+20
-16
packages/browser/src/index.ts
+20
-16
packages/browser/src/index.ts
···
4
4
import { getExtensions } from "@moonlight-mod/core/extension";
5
5
import { loadExtensions } from "@moonlight-mod/core/extension/loader";
6
6
import { MoonlightBranch, MoonlightNode } from "@moonlight-mod/types";
7
+
import { getConfig, getConfigOption, getManifest, setConfigOption } from "@moonlight-mod/core/util/config";
7
8
import { IndexedDB } from "@zenfs/dom";
8
9
import { configure } from "@zenfs/core";
9
10
import * as fs from "@zenfs/core/promises";
···
99
100
};
100
101
101
102
// Actual loading begins here
102
-
const config = await readConfig();
103
+
let config = await readConfig();
103
104
initLogger(config);
104
105
105
106
const extensions = await getExtensions();
106
107
const processedExtensions = await loadExtensions(extensions);
107
108
108
-
function getConfig(ext: string) {
109
-
const val = config.extensions[ext];
110
-
if (val == null || typeof val === "boolean") return undefined;
111
-
return val.config;
112
-
}
113
-
114
109
const moonlightNode: MoonlightNode = {
115
-
config,
110
+
get config() {
111
+
return config;
112
+
},
116
113
extensions,
117
114
processedExtensions,
118
115
nativesCache: {},
···
121
118
version: MOONLIGHT_VERSION,
122
119
branch: MOONLIGHT_BRANCH as MoonlightBranch,
123
120
124
-
getConfig,
125
-
getConfigOption: <T>(ext: string, name: string) => {
126
-
const config = getConfig(ext);
127
-
if (config == null) return undefined;
128
-
const option = config[name];
129
-
if (option == null) return undefined;
130
-
return option as T;
121
+
getConfig(ext) {
122
+
return getConfig(ext, config);
123
+
},
124
+
getConfigOption(ext, name) {
125
+
const manifest = getManifest(extensions, ext);
126
+
return getConfigOption(ext, name, config, manifest);
131
127
},
128
+
setConfigOption(ext, name, value) {
129
+
setConfigOption(config, ext, name, value);
130
+
this.writeConfig(config);
131
+
},
132
+
132
133
getNatives: () => {},
133
134
getLogger: (id: string) => {
134
135
return new Logger(id);
···
141
142
return `/extensions/${ext}`;
142
143
},
143
144
144
-
writeConfig
145
+
async writeConfig(newConfig) {
146
+
await writeConfig(newConfig);
147
+
config = newConfig;
148
+
}
145
149
};
146
150
147
151
Object.assign(window, {
-9
packages/core-extensions/src/moonbase/native.ts
-9
packages/core-extensions/src/moonbase/native.ts
···
178
178
async deleteExtension(id) {
179
179
const dir = moonlightNode.getExtensionDir(id);
180
180
await moonlightNodeSandboxed.fs.rmdir(dir);
181
-
},
182
-
183
-
getExtensionConfig(id, key) {
184
-
const config = moonlightNode.config.extensions[id];
185
-
if (typeof config === "object") {
186
-
return config.config?.[key];
187
-
}
188
-
189
-
return undefined;
190
181
}
191
182
};
192
183
}
-1
packages/core-extensions/src/moonbase/types.ts
-1
packages/core-extensions/src/moonbase/types.ts
···
8
8
fetchRepositories(repos: string[]): Promise<Record<string, RepositoryManifest[]>>;
9
9
installExtension(manifest: RepositoryManifest, url: string, repo: string): Promise<void>;
10
10
deleteExtension(id: string): Promise<void>;
11
-
getExtensionConfig(id: string, key: string): any;
12
11
};
13
12
14
13
export type RepositoryManifest = ExtensionManifest & {
+3
-20
packages/core-extensions/src/moonbase/webpackModules/stores.ts
+3
-20
packages/core-extensions/src/moonbase/webpackModules/stores.ts
···
6
6
import { mainRepo } from "@moonlight-mod/types/constants";
7
7
import { checkExtensionCompat, ExtensionCompat } from "@moonlight-mod/core/extension/loader";
8
8
import { CustomComponent } from "@moonlight-mod/types/coreExtensions/moonbase";
9
+
import { getConfigOption, setConfigOption } from "@moonlight-mod/core/util/config";
9
10
10
11
const logger = moonlight.getLogger("moonbase");
11
12
···
191
192
192
193
getExtensionConfig<T>(uniqueId: number, key: string): T | undefined {
193
194
const ext = this.getExtension(uniqueId);
194
-
const defaultValue = ext.manifest.settings?.[key]?.default;
195
-
const clonedDefaultValue = this.clone(defaultValue);
196
-
const cfg = this.config.extensions[ext.id];
197
-
198
-
if (cfg == null || typeof cfg === "boolean") return clonedDefaultValue;
199
-
return cfg.config?.[key] ?? clonedDefaultValue;
195
+
return getConfigOption(ext.id, key, this.config, ext.manifest);
200
196
}
201
197
202
198
getExtensionConfigRaw<T>(id: string, key: string, defaultValue: T | undefined): T | undefined {
203
199
const cfg = this.config.extensions[id];
204
-
205
200
if (cfg == null || typeof cfg === "boolean") return defaultValue;
206
201
return cfg.config?.[key] ?? defaultValue;
207
202
}
···
217
212
}
218
213
219
214
setExtensionConfig(id: string, key: string, value: any) {
220
-
const oldConfig = this.config.extensions[id];
221
-
const newConfig =
222
-
typeof oldConfig === "boolean"
223
-
? {
224
-
enabled: oldConfig,
225
-
config: { [key]: value }
226
-
}
227
-
: {
228
-
...oldConfig,
229
-
config: { ...(oldConfig?.config ?? {}), [key]: value }
230
-
};
231
-
232
-
this.config.extensions[id] = newConfig;
215
+
setConfigOption(this.config, id, key, value);
233
216
this.modified = this.isModified();
234
217
this.emitChange();
235
218
}
+39
packages/core/src/util/config.ts
+39
packages/core/src/util/config.ts
···
1
+
import type { Config, DetectedExtension, ExtensionManifest } from "@moonlight-mod/types";
2
+
3
+
export function getManifest(extensions: DetectedExtension[], ext: string) {
4
+
return extensions.find((x) => x.id === ext)?.manifest;
5
+
}
6
+
7
+
export function getConfig(ext: string, config: Config) {
8
+
const val = config.extensions[ext];
9
+
if (val == null || typeof val === "boolean") return undefined;
10
+
return val.config;
11
+
}
12
+
13
+
export function getConfigOption<T>(
14
+
ext: string,
15
+
key: string,
16
+
config: Config,
17
+
manifest?: ExtensionManifest
18
+
): T | undefined {
19
+
const defaultValue: T | undefined = structuredClone(manifest?.settings?.[key]?.default);
20
+
const cfg = getConfig(ext, config);
21
+
if (cfg == null || typeof cfg === "boolean") return defaultValue;
22
+
return cfg?.[key] ?? defaultValue;
23
+
}
24
+
25
+
export function setConfigOption<T>(config: Config, ext: string, key: string, value: T) {
26
+
const oldConfig = config.extensions[ext];
27
+
const newConfig =
28
+
typeof oldConfig === "boolean"
29
+
? {
30
+
enabled: oldConfig,
31
+
config: { [key]: value }
32
+
}
33
+
: {
34
+
...oldConfig,
35
+
config: { ...(oldConfig?.config ?? {}), [key]: value }
36
+
};
37
+
38
+
config.extensions[ext] = newConfig;
39
+
}
+20
-16
packages/node-preload/src/index.ts
+20
-16
packages/node-preload/src/index.ts
···
10
10
import { loadExtensions, loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
11
11
import createFS from "@moonlight-mod/core/fs";
12
12
import { registerCors, registerBlocked, getDynamicCors } from "@moonlight-mod/core/cors";
13
+
import { getConfig, getConfigOption, getManifest, setConfigOption } from "@moonlight-mod/core/util/config";
13
14
14
15
let initialized = false;
15
16
···
32
33
}
33
34
};
34
35
35
-
const config = await readConfig();
36
+
let config = await readConfig();
36
37
initLogger(config);
37
38
const extensions = await getExtensions();
38
39
const processedExtensions = await loadExtensions(extensions);
39
40
const moonlightDir = await getMoonlightDir();
40
41
const extensionsPath = await getExtensionsPath();
41
-
42
-
function getConfig(ext: string) {
43
-
const val = config.extensions[ext];
44
-
if (val == null || typeof val === "boolean") return undefined;
45
-
return val.config;
46
-
}
47
42
48
43
global.moonlightNode = {
49
-
config,
44
+
get config() {
45
+
return config;
46
+
},
50
47
extensions,
51
48
processedExtensions,
52
49
nativesCache: {},
···
55
52
version: MOONLIGHT_VERSION,
56
53
branch: MOONLIGHT_BRANCH as MoonlightBranch,
57
54
58
-
getConfig,
59
-
getConfigOption: <T>(ext: string, name: string) => {
60
-
const config = getConfig(ext);
61
-
if (config == null) return undefined;
62
-
const option = config[name];
63
-
if (option == null) return undefined;
64
-
return option as T;
55
+
getConfig(ext) {
56
+
return getConfig(ext, config);
57
+
},
58
+
getConfigOption(ext, name) {
59
+
const manifest = getManifest(extensions, ext);
60
+
return getConfigOption(ext, name, config, manifest);
65
61
},
62
+
setConfigOption(ext, name, value) {
63
+
setConfigOption(config, ext, name, value);
64
+
this.writeConfig(config);
65
+
},
66
+
66
67
getNatives: (ext: string) => global.moonlightNode.nativesCache[ext],
67
68
getLogger: (id: string) => {
68
69
return new Logger(id);
···
74
75
getExtensionDir: (ext: string) => {
75
76
return path.join(extensionsPath, ext);
76
77
},
77
-
writeConfig
78
+
async writeConfig(newConfig) {
79
+
await writeConfig(newConfig);
80
+
config = newConfig;
81
+
}
78
82
};
79
83
80
84
await loadProcessedExtensions(processedExtensions);
+7
-2
packages/types/src/globals.ts
+7
-2
packages/types/src/globals.ts
···
34
34
35
35
getConfig: (ext: string) => ConfigExtension["config"];
36
36
getConfigOption: <T>(ext: string, name: string) => T | undefined;
37
+
setConfigOption: <T>(ext: string, name: string, value: T) => void;
38
+
37
39
getNatives: (ext: string) => any | undefined;
38
40
getLogger: (id: string) => Logger;
39
41
···
63
65
version: string;
64
66
branch: MoonlightBranch;
65
67
66
-
getConfig: (ext: string) => ConfigExtension["config"];
67
-
getConfigOption: <T>(ext: string, name: string) => T | undefined;
68
+
// Re-exports for ease of use
69
+
getConfig: MoonlightNode["getConfig"];
70
+
getConfigOption: MoonlightNode["getConfigOption"];
71
+
setConfigOption: MoonlightNode["setConfigOption"];
72
+
68
73
getNatives: (ext: string) => any | undefined;
69
74
getLogger: (id: string) => Logger;
70
75
lunast: LunAST;
+2
packages/web-preload/src/index.ts
+2
packages/web-preload/src/index.ts
···
30
30
31
31
getConfig: moonlightNode.getConfig.bind(moonlightNode),
32
32
getConfigOption: moonlightNode.getConfigOption.bind(moonlightNode),
33
+
setConfigOption: moonlightNode.setConfigOption.bind(moonlightNode),
34
+
33
35
getNatives: moonlightNode.getNatives.bind(moonlightNode),
34
36
getLogger(id) {
35
37
return new Logger(id);