-75
.eslintrc.json
-75
.eslintrc.json
···
1
-
{
2
-
"root": true,
3
-
"extends": [
4
-
"eslint:recommended",
5
-
"plugin:@typescript-eslint/recommended",
6
-
"plugin:prettier/recommended",
7
-
"plugin:react/recommended"
8
-
],
9
-
"plugins": ["@typescript-eslint", "prettier", "react"],
10
-
"parser": "@typescript-eslint/parser",
11
-
"env": {
12
-
"browser": true,
13
-
"node": true
14
-
},
15
-
"parserOptions": {
16
-
"ecmaFeatures": {
17
-
"jsx": true
18
-
},
19
-
"ecmaVersion": "latest",
20
-
"sourceType": "module"
21
-
},
22
-
"rules": {
23
-
"indent": "off",
24
-
"eqeqeq": [
25
-
"error",
26
-
"always",
27
-
{
28
-
"null": "ignore"
29
-
}
30
-
],
31
-
"quotes": [
32
-
"error",
33
-
"double",
34
-
{ "avoidEscape": true, "allowTemplateLiterals": true }
35
-
],
36
-
"@typescript-eslint/no-unused-vars": [
37
-
"error",
38
-
{ "args": "none", "varsIgnorePattern": "^_" }
39
-
],
40
-
// Mostly so we don't forget to leave these in when committing
41
-
"no-console": "error",
42
-
"no-debugger": "error",
43
-
44
-
// Quite honestly we're interacting with so much unknown within Discord that
45
-
// this being enabled is a hinderance
46
-
"@typescript-eslint/no-explicit-any": "off",
47
-
48
-
"@typescript-eslint/no-var-requires": "off",
49
-
50
-
// https://canary.discord.com/channels/1154257010532032512/1154275441788583996/1181760413231230976
51
-
"no-unused-labels": "off",
52
-
53
-
// baseUrl being set to ./packages/ makes language server suggest "types/src" instead of "@moonlight-mod/types"
54
-
"no-restricted-imports": [
55
-
"error",
56
-
{
57
-
"patterns": [
58
-
{
59
-
"group": ["types/*"],
60
-
"message": "Use @moonlight-mod/types instead"
61
-
},
62
-
{
63
-
"group": ["core/*"],
64
-
"message": "Use @moonlight-mod/core instead"
65
-
}
66
-
]
67
-
}
68
-
]
69
-
},
70
-
"settings": {
71
-
"react": {
72
-
"version": "18.2"
73
-
}
74
-
}
75
-
}
+4
-8
.github/workflows/browser.yml
+4
-8
.github/workflows/browser.yml
···
10
10
name: Browser extension builds
11
11
runs-on: ubuntu-latest
12
12
steps:
13
-
- uses: actions/checkout@v3
14
-
15
-
- uses: pnpm/action-setup@v2
16
-
with:
17
-
version: 9
18
-
run_install: false
19
-
- uses: actions/setup-node@v3
13
+
- uses: actions/checkout@v4
14
+
- uses: pnpm/action-setup@v4
15
+
- uses: actions/setup-node@v4
20
16
with:
21
-
node-version: 18
17
+
node-version: 22
22
18
cache: pnpm
23
19
24
20
- name: Install dependencies
+4
-8
.github/workflows/lint.yml
+4
-8
.github/workflows/lint.yml
···
9
9
name: Lint commits
10
10
runs-on: ubuntu-latest
11
11
steps:
12
-
- uses: actions/checkout@v3
13
-
14
-
- uses: pnpm/action-setup@v2
15
-
with:
16
-
version: 9
17
-
run_install: false
18
-
- uses: actions/setup-node@v3
12
+
- uses: actions/checkout@v4
13
+
- uses: pnpm/action-setup@v4
14
+
- uses: actions/setup-node@v4
19
15
with:
20
-
node-version: 18
16
+
node-version: 22
21
17
cache: pnpm
22
18
23
19
- name: Install dependencies
+7
-11
.github/workflows/nightly.yml
+7
-11
.github/workflows/nightly.yml
···
15
15
name: Nightly builds on GitHub Pages
16
16
runs-on: ubuntu-latest
17
17
steps:
18
-
- uses: actions/checkout@v3
19
-
20
-
- uses: pnpm/action-setup@v2
21
-
with:
22
-
version: 9
23
-
run_install: false
24
-
- uses: actions/setup-node@v3
18
+
- uses: actions/checkout@v4
19
+
- uses: pnpm/action-setup@v4
20
+
- uses: actions/setup-node@v4
25
21
with:
26
-
node-version: 18
22
+
node-version: 22
27
23
cache: pnpm
28
24
29
25
- name: Install dependencies
···
47
43
echo "$(date +%s)" >> ./dist/ref
48
44
49
45
- name: Setup GitHub Pages
50
-
uses: actions/configure-pages@v3
46
+
uses: actions/configure-pages@v5
51
47
- name: Upload artifact
52
-
uses: actions/upload-pages-artifact@v1
48
+
uses: actions/upload-pages-artifact@v3
53
49
with:
54
50
path: ./dist
55
51
- name: Deploy to GitHub Pages
56
-
uses: actions/deploy-pages@v2
52
+
uses: actions/deploy-pages@v4
+16
.github/workflows/nix.yml
+16
.github/workflows/nix.yml
···
1
+
name: Check Nix flake
2
+
on: [push, pull_request]
3
+
4
+
permissions:
5
+
checks: write
6
+
7
+
jobs:
8
+
nix:
9
+
name: Check Nix flake
10
+
runs-on: ubuntu-latest
11
+
steps:
12
+
- uses: actions/checkout@v4
13
+
- uses: DeterminateSystems/nix-installer-action@main
14
+
15
+
- name: Build default flake output
16
+
run: nix build
+4
-8
.github/workflows/release.yml
+4
-8
.github/workflows/release.yml
···
13
13
name: Release builds to GitHub Releases
14
14
runs-on: ubuntu-latest
15
15
steps:
16
-
- uses: actions/checkout@v3
17
-
18
-
- uses: pnpm/action-setup@v2
19
-
with:
20
-
version: 9
21
-
run_install: false
22
-
- uses: actions/setup-node@v3
16
+
- uses: actions/checkout@v4
17
+
- uses: pnpm/action-setup@v4
18
+
- uses: actions/setup-node@v4
23
19
with:
24
-
node-version: 18
20
+
node-version: 22
25
21
cache: pnpm
26
22
27
23
- name: Install dependencies
+32
.github/workflows/types.yml
+32
.github/workflows/types.yml
···
1
+
name: Publish types on npm
2
+
on: workflow_dispatch
3
+
4
+
permissions:
5
+
contents: read
6
+
pages: write
7
+
id-token: write
8
+
9
+
jobs:
10
+
types:
11
+
name: Publish types on npm
12
+
runs-on: ubuntu-latest
13
+
steps:
14
+
- uses: actions/checkout@v4
15
+
- uses: pnpm/action-setup@v4
16
+
- uses: actions/setup-node@v4
17
+
with:
18
+
node-version: 22
19
+
cache: pnpm
20
+
registry-url: https://registry.npmjs.org
21
+
22
+
- name: Install dependencies
23
+
run: pnpm install --frozen-lockfile
24
+
- name: Build moonlight
25
+
env:
26
+
NODE_ENV: production
27
+
run: pnpm run build
28
+
29
+
- name: Publish types
30
+
run: pnpm publish --filter=./packages/types --access public --no-git-checks
31
+
env:
32
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+5
-1
.gitignore
+5
-1
.gitignore
+4
-4
.prettierrc
+4
-4
.prettierrc
-14
.vscode/tasks.json
-14
.vscode/tasks.json
+4
-1
CHANGELOG.md
+4
-1
CHANGELOG.md
+10
-3
README.md
+10
-3
README.md
···
5
5
<img src="./img/wordmark.png" alt="moonlight" />
6
6
</picture>
7
7
8
-
<a href="https://discord.gg/FdZBTFCP6F">Discord server</a>
8
+
<a href="https://moonlight-mod.github.io/using/install">Install</a>
9
+
\- <a href="https://moonlight-mod.github.io/ext-dev/getting-started">Docs</a>
10
+
\- <a href="https://discord.gg/FdZBTFCP6F">Discord server</a>
9
11
\- <a href="https://github.com/moonlight-mod/moonlight">GitHub</a>
10
-
\- <a href="https://moonlight-mod.github.io/">Docs</a>
11
12
12
13
<hr />
14
+
15
+
<picture>
16
+
<source media="(prefers-color-scheme: dark)" srcset="https://moonlight-mod.github.io/moonbase.png">
17
+
<source media="(prefers-color-scheme: light)" srcset="https://moonlight-mod.github.io/moonbase-light.png">
18
+
<img src="https://moonlight-mod.github.io/moonbase.png" alt="A screenshot of Moonbase, the moonlight UI" />
19
+
</picture>
13
20
</h3>
14
21
15
22
**moonlight** is yet another Discord client mod, focused on providing a decent user and developer experience.
16
23
17
24
moonlight is heavily inspired by hh3 (a private client mod) and the projects before it that it is inspired by, namely EndPwn. All core code is original or used with permission from their respective authors where not copyleft.
18
25
19
-
**_This is an experimental passion project._** Anything and everything is subject to change, but it is stable enough for developers to experiment with.
26
+
moonlight is a **_passion project_** - things may break from time to time, but we try our best to keep things working in a timely manner.
20
27
21
28
moonlight is licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.html) (`LGPL-3.0-or-later`). See [the documentation](https://moonlight-mod.github.io/) for more information.
+34
-44
build.mjs
+34
-44
build.mjs
···
15
15
const watch = process.argv.includes("--watch");
16
16
const browser = process.argv.includes("--browser");
17
17
const mv2 = process.argv.includes("--mv2");
18
+
const clean = process.argv.includes("--clean");
18
19
19
20
const buildBranch = process.env.MOONLIGHT_BRANCH ?? "dev";
20
21
const buildVersion = process.env.MOONLIGHT_VERSION ?? "dev";
···
69
70
name: "build-log",
70
71
setup(build) {
71
72
build.onEnd((result) => {
72
-
console.log(
73
-
`[${timeFormatter.format(new Date())}] [${tag}] build finished`
74
-
);
73
+
console.log(`[${timeFormatter.format(new Date())}] [${tag}] build finished`);
75
74
});
76
75
}
77
76
});
···
104
103
MOONLIGHT_VERSION: `"${buildVersion}"`
105
104
};
106
105
107
-
for (const iterName of [
108
-
"injector",
109
-
"node-preload",
110
-
"web-preload",
111
-
"browser"
112
-
]) {
106
+
for (const iterName of ["injector", "node-preload", "web-preload", "browser"]) {
113
107
const snake = iterName.replace(/-/g, "_").toUpperCase();
114
108
define[`MOONLIGHT_${snake}`] = (name === iterName).toString();
115
109
}
···
121
115
if (name === "browser") {
122
116
plugins.push(
123
117
copyStaticFiles({
124
-
src: mv2
125
-
? "./packages/browser/manifestv2.json"
126
-
: "./packages/browser/manifest.json",
118
+
src: mv2 ? "./packages/browser/manifestv2.json" : "./packages/browser/manifest.json",
127
119
dest: `./dist/${browserDir}/manifest.json`
128
120
})
129
121
);
···
145
137
146
138
plugins.push(
147
139
copyStaticFiles({
148
-
src: mv2
149
-
? "./packages/browser/src/background-mv2.js"
150
-
: "./packages/browser/src/background.js",
140
+
src: mv2 ? "./packages/browser/src/background-mv2.js" : "./packages/browser/src/background.js",
151
141
dest: `./dist/${browserDir}/background.js`
152
142
})
153
143
);
···
174
164
dropLabels,
175
165
176
166
logLevel: "silent",
177
-
plugins
167
+
plugins,
168
+
169
+
// https://github.com/evanw/esbuild/issues/3944
170
+
footer:
171
+
name === "web-preload"
172
+
? {
173
+
js: `\n//# sourceURL=${name}.js`
174
+
}
175
+
: undefined
178
176
};
179
177
180
178
if (name === "browser") {
181
179
const coreExtensionsJson = {};
182
180
183
-
// eslint-disable-next-line no-inner-declarations
184
181
function readDir(dir) {
185
182
const files = fs.readdirSync(dir);
186
183
for (const file of files) {
···
189
186
if (fs.statSync(filePath).isDirectory()) {
190
187
readDir(filePath);
191
188
} else {
192
-
coreExtensionsJson[normalizedPath] = fs.readFileSync(
193
-
filePath,
194
-
"utf8"
195
-
);
189
+
coreExtensionsJson[normalizedPath] = fs.readFileSync(filePath, "utf8");
196
190
}
197
191
}
198
192
}
···
200
194
readDir("./dist/core-extensions");
201
195
202
196
esbuildConfig.banner = {
203
-
js: `window._moonlight_coreExtensionsStr = ${JSON.stringify(
204
-
JSON.stringify(coreExtensionsJson)
205
-
)};`
197
+
js: `window._moonlight_coreExtensionsStr = ${JSON.stringify(JSON.stringify(coreExtensionsJson))};`
206
198
};
207
199
}
208
200
···
214
206
}
215
207
}
216
208
217
-
async function buildExt(ext, side, copyManifest, fileExt) {
209
+
async function buildExt(ext, side, fileExt) {
218
210
const outdir = path.join("./dist", "core-extensions", ext);
219
211
if (!fs.existsSync(outdir)) {
220
212
fs.mkdirSync(outdir, { recursive: true });
221
213
}
222
214
223
-
const entryPoints = [
224
-
`packages/core-extensions/src/${ext}/${side}.${fileExt}`
225
-
];
215
+
const entryPoints = [`packages/core-extensions/src/${ext}/${side}.${fileExt}`];
226
216
227
217
const wpModulesDir = `packages/core-extensions/src/${ext}/webpackModules`;
228
218
if (fs.existsSync(wpModulesDir) && side === "index") {
229
219
const wpModules = fs.opendirSync(wpModulesDir);
230
220
for await (const wpModule of wpModules) {
231
221
if (wpModule.isFile()) {
232
-
entryPoints.push(
233
-
`packages/core-extensions/src/${ext}/webpackModules/${wpModule.name}`
234
-
);
222
+
entryPoints.push(`packages/core-extensions/src/${ext}/webpackModules/${wpModule.name}`);
235
223
} else {
236
224
for (const fileExt of ["ts", "tsx"]) {
237
225
const path = `packages/core-extensions/src/${ext}/webpackModules/${wpModule.name}/index.${fileExt}`;
···
259
247
}
260
248
};
261
249
250
+
const styleInput = `packages/core-extensions/src/${ext}/style.css`;
251
+
const styleOutput = `dist/core-extensions/${ext}/style.css`;
252
+
262
253
const esbuildConfig = {
263
254
entryPoints,
264
255
outdir,
···
278
269
},
279
270
logLevel: "silent",
280
271
plugins: [
281
-
...(copyManifest
272
+
copyStaticFiles({
273
+
src: `./packages/core-extensions/src/${ext}/manifest.json`,
274
+
dest: `./dist/core-extensions/${ext}/manifest.json`
275
+
}),
276
+
...(fs.existsSync(styleInput)
282
277
? [
283
278
copyStaticFiles({
284
-
src: `./packages/core-extensions/src/${ext}/manifest.json`,
285
-
dest: `./dist/core-extensions/${ext}/manifest.json`
279
+
src: styleInput,
280
+
dest: styleOutput
286
281
})
287
282
]
288
283
: []),
···
302
297
303
298
const promises = [];
304
299
305
-
if (browser) {
300
+
if (clean) {
301
+
fs.rmSync("./dist", { recursive: true, force: true });
302
+
} else if (browser) {
306
303
build("browser", "packages/browser/src/index.ts");
307
304
} else {
308
305
for (const [name, entry] of Object.entries(config)) {
···
311
308
312
309
const coreExtensions = fs.readdirSync("./packages/core-extensions/src");
313
310
for (const ext of coreExtensions) {
314
-
let copiedManifest = false;
315
-
316
311
for (const fileExt of ["ts", "tsx"]) {
317
312
for (const type of ["index", "node", "host"]) {
318
-
if (
319
-
fs.existsSync(
320
-
`./packages/core-extensions/src/${ext}/${type}.${fileExt}`
321
-
)
322
-
) {
323
-
promises.push(buildExt(ext, type, !copiedManifest, fileExt));
324
-
copiedManifest = true;
313
+
if (fs.existsSync(`./packages/core-extensions/src/${ext}/${type}.${fileExt}`)) {
314
+
promises.push(buildExt(ext, type, fileExt));
325
315
}
326
316
}
327
317
}
+25
eslint.config.mjs
+25
eslint.config.mjs
···
1
+
import config from "@moonlight-mod/eslint-config";
2
+
3
+
export default [
4
+
...config,
5
+
{
6
+
rules: {
7
+
// baseUrl being set to ./packages/ makes language server suggest "types/src" instead of "@moonlight-mod/types"
8
+
"no-restricted-imports": [
9
+
"error",
10
+
{
11
+
patterns: [
12
+
{
13
+
group: ["types/*"],
14
+
message: "Use @moonlight-mod/types instead"
15
+
},
16
+
{
17
+
group: ["core/*"],
18
+
message: "Use @moonlight-mod/core instead"
19
+
}
20
+
]
21
+
}
22
+
]
23
+
}
24
+
}
25
+
];
+4
-73
flake.lock
+4
-73
flake.lock
···
18
18
"type": "github"
19
19
}
20
20
},
21
-
"flake-utils_2": {
22
-
"inputs": {
23
-
"systems": "systems_2"
24
-
},
25
-
"locked": {
26
-
"lastModified": 1701680307,
27
-
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
28
-
"owner": "numtide",
29
-
"repo": "flake-utils",
30
-
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
31
-
"type": "github"
32
-
},
33
-
"original": {
34
-
"owner": "numtide",
35
-
"repo": "flake-utils",
36
-
"type": "github"
37
-
}
38
-
},
39
21
"nixpkgs": {
40
22
"locked": {
41
-
"lastModified": 1728067476,
42
-
"narHash": "sha256-/uJcVXuBt+VFCPQIX+4YnYrHaubJSx4HoNsJVNRgANM=",
23
+
"lastModified": 1744232761,
24
+
"narHash": "sha256-gbl9hE39nQRpZaLjhWKmEu5ejtQsgI5TWYrIVVJn30U=",
43
25
"owner": "NixOS",
44
26
"repo": "nixpkgs",
45
-
"rev": "6e6b3dd395c3b1eb9be9f2d096383a8d05add030",
27
+
"rev": "f675531bc7e6657c10a18b565cfebd8aa9e24c14",
46
28
"type": "github"
47
29
},
48
30
"original": {
49
31
"owner": "NixOS",
50
-
"ref": "nixos-24.05",
51
-
"repo": "nixpkgs",
52
-
"type": "github"
53
-
}
54
-
},
55
-
"nixpkgs_2": {
56
-
"locked": {
57
-
"lastModified": 1727802920,
58
-
"narHash": "sha256-HP89HZOT0ReIbI7IJZJQoJgxvB2Tn28V6XS3MNKnfLs=",
59
-
"owner": "nixos",
60
-
"repo": "nixpkgs",
61
-
"rev": "27e30d177e57d912d614c88c622dcfdb2e6e6515",
62
-
"type": "github"
63
-
},
64
-
"original": {
65
-
"owner": "nixos",
66
32
"ref": "nixos-unstable",
67
33
"repo": "nixpkgs",
68
34
"type": "github"
69
35
}
70
36
},
71
-
"pnpm2nix": {
72
-
"inputs": {
73
-
"flake-utils": "flake-utils_2",
74
-
"nixpkgs": "nixpkgs_2"
75
-
},
76
-
"locked": {
77
-
"lastModified": 1728137762,
78
-
"narHash": "sha256-iEFvPR3BopGyI5KjQ1DK+gEZ1dKDugq838tKdet2moQ=",
79
-
"owner": "NotNite",
80
-
"repo": "pnpm2nix-nzbr",
81
-
"rev": "b7a60d3c7d106b601665e3f05dba6cdc6f59f959",
82
-
"type": "github"
83
-
},
84
-
"original": {
85
-
"owner": "NotNite",
86
-
"repo": "pnpm2nix-nzbr",
87
-
"type": "github"
88
-
}
89
-
},
90
37
"root": {
91
38
"inputs": {
92
39
"flake-utils": "flake-utils",
93
-
"nixpkgs": "nixpkgs",
94
-
"pnpm2nix": "pnpm2nix"
40
+
"nixpkgs": "nixpkgs"
95
41
}
96
42
},
97
43
"systems": {
98
-
"locked": {
99
-
"lastModified": 1681028828,
100
-
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
101
-
"owner": "nix-systems",
102
-
"repo": "default",
103
-
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
104
-
"type": "github"
105
-
},
106
-
"original": {
107
-
"owner": "nix-systems",
108
-
"repo": "default",
109
-
"type": "github"
110
-
}
111
-
},
112
-
"systems_2": {
113
44
"locked": {
114
45
"lastModified": 1681028828,
115
46
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+3
-4
flake.nix
+3
-4
flake.nix
···
2
2
description = "Yet another Discord mod";
3
3
4
4
inputs = {
5
-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
5
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6
6
flake-utils.url = "github:numtide/flake-utils";
7
-
pnpm2nix.url = "github:NotNite/pnpm2nix-nzbr";
8
7
};
9
8
10
-
outputs = { self, nixpkgs, flake-utils, pnpm2nix }:
11
-
let overlay = import ./nix/overlay.nix { inherit pnpm2nix; };
9
+
outputs = { self, nixpkgs, flake-utils }:
10
+
let overlay = import ./nix/overlay.nix { };
12
11
in flake-utils.lib.eachDefaultSystem (system:
13
12
let
14
13
pkgs = import nixpkgs {
+46
-17
nix/default.nix
+46
-17
nix/default.nix
···
1
-
{ pkgs, mkPnpmPackage }:
1
+
{
2
+
lib,
3
+
stdenv,
4
+
nodejs_22,
5
+
pnpm_10,
6
+
}:
2
7
3
-
mkPnpmPackage rec {
4
-
workspace = ./..;
8
+
stdenv.mkDerivation (finalAttrs: {
9
+
pname = "moonlight";
10
+
version = (builtins.fromJSON (builtins.readFile ./../package.json)).version;
11
+
5
12
src = ./..;
6
13
7
-
# Work around a bug with how it expects dist
8
-
components = [
9
-
"packages/core"
10
-
"packages/core-extensions"
11
-
"packages/injector"
12
-
"packages/node-preload"
13
-
"packages/types"
14
-
"packages/web-preload"
14
+
outputs = [ "out" "firefox" ];
15
+
16
+
nativeBuildInputs = [
17
+
nodejs_22
18
+
pnpm_10.configHook
15
19
];
16
-
distDirs = [ "dist" ];
20
+
21
+
pnpmDeps = pnpm_10.fetchDeps {
22
+
inherit (finalAttrs) pname version src;
23
+
hash = "sha256-I+zRCUqJabpGJRFBGW0NrM9xzyzeCjioF54zlCpynBU=";
24
+
};
25
+
26
+
env = {
27
+
NODE_ENV = "production";
28
+
MOONLIGHT_VERSION = "v${finalAttrs.version}";
29
+
};
30
+
31
+
buildPhase = ''
32
+
runHook preBuild
33
+
34
+
pnpm run build
35
+
pnpm run browser-mv2
36
+
37
+
runHook postBuild
38
+
'';
39
+
40
+
installPhase = ''
41
+
runHook preInstall
17
42
18
-
copyNodeModules = true;
19
-
buildPhase = "pnpm run build";
20
-
installPhase = "cp -r dist $out";
43
+
cp -r dist $out
44
+
45
+
mkdir -p $firefox/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/
46
+
mv $out/browser-mv2 $firefox/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/{0fb6d66f-f22d-4555-a87b-34ef4bea5e2a}
47
+
48
+
runHook postInstall
49
+
'';
21
50
22
-
meta = with pkgs.lib; {
51
+
meta = with lib; {
23
52
description = "Yet another Discord mod";
24
53
homepage = "https://moonlight-mod.github.io/";
25
54
license = licenses.lgpl3;
26
55
maintainers = with maintainers; [ notnite ];
27
56
};
28
-
}
57
+
})
+3
-6
nix/overlay.nix
+3
-6
nix/overlay.nix
···
1
-
{ pnpm2nix }:
1
+
{ ... }:
2
2
3
3
let
4
4
nameTable = {
···
29
29
'';
30
30
31
31
packageJson = ''
32
-
{"name":"discord","main":"./injector.js","private":true}
32
+
{"name":"${name}","main":"./injector.js","private":true}
33
33
'';
34
34
35
35
in old.installPhase + "\n" + ''
···
49
49
'';
50
50
});
51
51
in final: prev: rec {
52
-
moonlight-mod = final.callPackage ./default.nix {
53
-
pkgs = final;
54
-
mkPnpmPackage = pnpm2nix.packages.${final.system}.mkPnpmPackage;
55
-
};
52
+
moonlight-mod = final.callPackage ./default.nix { };
56
53
discord = mkOverride prev moonlight-mod "discord";
57
54
discord-ptb = mkOverride prev moonlight-mod "discord-ptb";
58
55
discord-canary = mkOverride prev moonlight-mod "discord-canary";
+24
-16
package.json
+24
-16
package.json
···
1
1
{
2
2
"name": "moonlight",
3
-
"version": "1.2.1",
3
+
"version": "1.3.14",
4
+
"packageManager": "pnpm@10.7.1",
4
5
"description": "Yet another Discord mod",
5
-
"homepage": "https://moonlight-mod.github.io/",
6
6
"license": "LGPL-3.0-or-later",
7
+
"homepage": "https://moonlight-mod.github.io/",
7
8
"repository": {
8
9
"type": "git",
9
10
"url": "git+https://github.com/moonlight-mod/moonlight.git"
···
11
12
"bugs": {
12
13
"url": "https://github.com/moonlight-mod/moonlight/issues"
13
14
},
15
+
"engineStrict": true,
16
+
"engines": {
17
+
"node": ">=22",
18
+
"pnpm": ">=10",
19
+
"npm": "pnpm",
20
+
"yarn": "pnpm"
21
+
},
14
22
"scripts": {
15
23
"build": "node build.mjs",
16
24
"dev": "node build.mjs --watch",
25
+
"clean": "node build.mjs --clean",
17
26
"browser": "node build.mjs --browser",
18
27
"browser-mv2": "node build.mjs --browser --mv2",
19
28
"lint": "eslint packages",
20
-
"lint:fix": "eslint packages",
21
-
"lint:report": "eslint --output-file eslint_report.json --format json packages",
29
+
"lint:fix": "pnpm lint --fix",
30
+
"lint:report": "pnpm lint --output-file eslint_report.json --format json",
22
31
"typecheck": "tsc --noEmit",
23
32
"check": "pnpm run lint && pnpm run typecheck",
24
-
"prepare": "husky install"
33
+
"prepare": "husky install",
34
+
"updates": "pnpm taze -r"
25
35
},
26
36
"devDependencies": {
27
-
"@typescript-eslint/eslint-plugin": "^6.13.2",
28
-
"@typescript-eslint/parser": "^6.13.2",
29
-
"esbuild": "^0.19.3",
30
-
"esbuild-copy-static-files": "^0.1.0",
31
-
"eslint": "^8.55.0",
32
-
"eslint-config-prettier": "^9.1.0",
33
-
"eslint-plugin-prettier": "^5.0.1",
34
-
"eslint-plugin-react": "^7.33.2",
35
-
"husky": "^8.0.3",
36
-
"prettier": "^3.1.0",
37
-
"typescript": "^5.3.2"
37
+
"@moonlight-mod/eslint-config": "catalog:dev",
38
+
"@types/node": "catalog:dev",
39
+
"esbuild": "catalog:dev",
40
+
"esbuild-copy-static-files": "catalog:dev",
41
+
"eslint": "catalog:dev",
42
+
"husky": "catalog:dev",
43
+
"prettier": "catalog:dev",
44
+
"taze": "catalog:dev",
45
+
"typescript": "catalog:dev"
38
46
}
39
47
}
+2
-1
packages/browser/blockLoading.json
+2
-1
packages/browser/blockLoading.json
+7
-10
packages/browser/manifest.json
+7
-10
packages/browser/manifest.json
···
1
1
{
2
+
"$schema": "https://json.schemastore.org/chrome-manifest",
2
3
"manifest_version": 3,
3
4
"name": "moonlight",
4
5
"description": "Yet another Discord mod",
5
-
"version": "1.1.0",
6
-
"permissions": [
7
-
"declarativeNetRequestWithHostAccess",
8
-
"webRequest",
9
-
"scripting",
10
-
"webNavigation"
11
-
],
6
+
"version": "1.3.14",
7
+
"permissions": ["declarativeNetRequestWithHostAccess", "webRequest", "scripting", "webNavigation"],
12
8
"host_permissions": [
13
9
"https://moonlight-mod.github.io/*",
14
10
"https://api.github.com/*",
15
-
"https://*.discord.com/*"
11
+
"https://*.discord.com/*",
12
+
"https://*.discordapp.com/*"
16
13
],
17
14
"content_scripts": [
18
15
{
19
16
"js": ["index.js"],
20
-
"matches": ["https://*.discord.com/*"],
17
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"],
21
18
"run_at": "document_start",
22
19
"world": "MAIN"
23
20
}
···
43
40
"web_accessible_resources": [
44
41
{
45
42
"resources": ["index.js"],
46
-
"matches": ["https://*.discord.com/*"]
43
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"]
47
44
}
48
45
]
49
46
}
+12
-6
packages/browser/manifestv2.json
+12
-6
packages/browser/manifestv2.json
···
1
1
{
2
+
"$schema": "https://json.schemastore.org/chrome-manifest",
2
3
"manifest_version": 2,
3
4
"name": "moonlight",
4
5
"description": "Yet another Discord mod",
5
-
"version": "1.1.0",
6
+
"version": "1.3.14",
6
7
"permissions": [
7
8
"webRequest",
8
9
"webRequestBlocking",
9
10
"scripting",
10
11
"webNavigation",
11
-
"https://*.discord.com/assets/*.js",
12
+
"https://*.discord.com/*",
13
+
"https://*.discordapp.com/*",
12
14
"https://moonlight-mod.github.io/*",
13
-
"https://api.github.com/*",
14
-
"https://*.discord.com/*"
15
+
"https://api.github.com/*"
15
16
],
16
17
"background": {
17
18
"scripts": ["background.js"]
···
19
20
"content_scripts": [
20
21
{
21
22
"js": ["index.js"],
22
-
"matches": ["https://*.discord.com/*"],
23
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"],
23
24
"run_at": "document_start",
24
25
"world": "MAIN"
25
26
}
26
-
]
27
+
],
28
+
"browser_specific_settings": {
29
+
"gecko": {
30
+
"id": "{0fb6d66f-f22d-4555-a87b-34ef4bea5e2a}"
31
+
}
32
+
}
27
33
}
+1
-1
packages/browser/modifyResponseHeaders.json
+1
-1
packages/browser/modifyResponseHeaders.json
+12
-2
packages/browser/package.json
+12
-2
packages/browser/package.json
···
1
1
{
2
2
"name": "@moonlight-mod/browser",
3
3
"private": true,
4
+
"engines": {
5
+
"node": ">=22",
6
+
"pnpm": ">=10",
7
+
"npm": "pnpm",
8
+
"yarn": "pnpm"
9
+
},
4
10
"dependencies": {
5
11
"@moonlight-mod/core": "workspace:*",
6
12
"@moonlight-mod/types": "workspace:*",
7
13
"@moonlight-mod/web-preload": "workspace:*",
8
-
"@zenfs/core": "^1.0.2",
9
-
"@zenfs/dom": "^0.2.16"
14
+
"@zenfs/core": "catalog:prod",
15
+
"@zenfs/dom": "catalog:prod"
16
+
},
17
+
"engineStrict": true,
18
+
"devDependencies": {
19
+
"@types/chrome": "catalog:dev"
10
20
}
11
21
}
+55
-70
packages/browser/src/background-mv2.js
+55
-70
packages/browser/src/background-mv2.js
···
1
1
/* eslint-disable no-console */
2
2
/* eslint-disable no-undef */
3
3
4
-
const starterUrls = ["web.", "sentry."];
5
-
let blockLoading = true;
6
-
let doing = false;
7
-
let collectedUrls = new Set();
4
+
const scriptUrls = ["web.", "sentry."];
5
+
let blockedScripts = new Set();
8
6
9
-
chrome.webNavigation.onBeforeNavigate.addListener(async (details) => {
10
-
const url = new URL(details.url);
11
-
if (!blockLoading && url.hostname.endsWith("discord.com")) {
12
-
console.log("Blocking", details.url);
13
-
blockLoading = true;
14
-
collectedUrls.clear();
15
-
}
16
-
});
7
+
chrome.webRequest.onBeforeRequest.addListener(
8
+
async (details) => {
9
+
if (details.tabId === -1) return;
17
10
18
-
async function doTheThing(urls, tabId) {
19
-
console.log("Doing", urls, tabId);
11
+
const url = new URL(details.url);
12
+
const hasUrl = scriptUrls.some((scriptUrl) => {
13
+
return (
14
+
details.url.includes(scriptUrl) &&
15
+
!url.searchParams.has("inj") &&
16
+
(url.host.endsWith("discord.com") || url.host.endsWith("discordapp.com"))
17
+
);
18
+
});
19
+
if (hasUrl) blockedScripts.add(details.url);
20
20
21
-
blockLoading = false;
21
+
if (blockedScripts.size === scriptUrls.length) {
22
+
const blockedScriptsCopy = Array.from(blockedScripts);
23
+
blockedScripts.clear();
22
24
23
-
try {
24
-
await chrome.scripting.executeScript({
25
-
target: { tabId },
26
-
world: "MAIN",
27
-
args: [urls],
28
-
func: async (urls) => {
29
-
try {
30
-
await window._moonlightBrowserInit();
31
-
} catch (e) {
32
-
console.log(e);
33
-
}
25
+
setTimeout(async () => {
26
+
console.log("Starting moonlight");
27
+
await chrome.scripting.executeScript({
28
+
target: { tabId: details.tabId },
29
+
world: "MAIN",
30
+
args: [blockedScriptsCopy],
31
+
func: async (blockedScripts) => {
32
+
console.log("Initializing moonlight");
33
+
try {
34
+
await window._moonlightBrowserInit();
35
+
} catch (e) {
36
+
console.error(e);
37
+
}
34
38
35
-
const scripts = [...document.querySelectorAll("script")].filter(
36
-
(script) => script.src && urls.some((url) => url.includes(script.src))
37
-
);
39
+
console.log("Readding scripts");
40
+
try {
41
+
const scripts = [...document.querySelectorAll("script")].filter(
42
+
(script) => script.src && blockedScripts.some((url) => url.includes(script.src))
43
+
);
38
44
39
-
// backwards
40
-
urls.reverse();
41
-
for (const url of urls) {
42
-
const script = scripts.find((script) => url.includes(script.src));
43
-
console.log("adding new script", script);
45
+
blockedScripts.reverse();
46
+
for (const url of blockedScripts) {
47
+
if (url.includes("/sentry.")) continue;
44
48
45
-
const newScript = document.createElement("script");
46
-
for (const { name, value } of script.attributes) {
47
-
newScript.setAttribute(name, value);
49
+
const script = scripts.find((script) => url.includes(script.src));
50
+
const newScript = document.createElement("script");
51
+
for (const attr of script.attributes) {
52
+
if (attr.name === "src") attr.value += "?inj";
53
+
newScript.setAttribute(attr.name, attr.value);
54
+
}
55
+
script.remove();
56
+
document.documentElement.appendChild(newScript);
57
+
}
58
+
} catch (e) {
59
+
console.error(e);
60
+
}
48
61
}
49
-
50
-
script.remove();
51
-
document.documentElement.appendChild(newScript);
52
-
}
53
-
}
54
-
});
55
-
} catch (e) {
56
-
console.log(e);
57
-
}
58
-
59
-
doing = false;
60
-
collectedUrls.clear();
61
-
}
62
-
63
-
chrome.webRequest.onBeforeRequest.addListener(
64
-
async (details) => {
65
-
if (starterUrls.some((url) => details.url.includes(url))) {
66
-
console.log("Adding", details.url);
67
-
collectedUrls.add(details.url);
62
+
});
63
+
}, 0);
68
64
}
69
65
70
-
if (collectedUrls.size === starterUrls.length) {
71
-
if (doing) return;
72
-
if (!blockLoading) return;
73
-
doing = true;
74
-
const urls = [...collectedUrls];
75
-
const tabId = details.tabId;
76
-
77
-
// yes this is a load-bearing sleep
78
-
setTimeout(() => doTheThing(urls, tabId), 0);
79
-
}
80
-
81
-
if (blockLoading) return { cancel: true };
66
+
if (hasUrl) return { cancel: true };
82
67
},
83
68
{
84
-
urls: ["https://*.discord.com/assets/*.js"]
69
+
urls: ["https://*.discord.com/assets/*.js", "https://*.discordapp.com/assets/*.js"]
85
70
},
86
71
["blocking"]
87
72
);
···
94
79
)
95
80
};
96
81
},
97
-
{ urls: ["https://*.discord.com/*"] },
82
+
{ urls: ["https://*.discord.com/*", "https://*.discordapp.com/*"] },
98
83
["blocking", "responseHeaders"]
99
84
);
+37
-40
packages/browser/src/background.js
+37
-40
packages/browser/src/background.js
···
1
1
/* eslint-disable no-console */
2
2
/* eslint-disable no-undef */
3
3
4
-
const starterUrls = ["web.", "sentry."];
5
-
let blockLoading = true;
6
-
let doing = false;
7
-
let collectedUrls = new Set();
4
+
const scriptUrls = ["web.", "sentry."];
5
+
let blockedScripts = new Set();
8
6
9
7
chrome.webNavigation.onBeforeNavigate.addListener(async (details) => {
10
8
const url = new URL(details.url);
11
-
if (!blockLoading && url.hostname.endsWith("discord.com")) {
9
+
if (
10
+
!url.searchParams.has("inj") &&
11
+
(url.hostname.endsWith("discord.com") || url.hostname.endsWith("discordapp.com"))
12
+
) {
13
+
console.log("Enabling block ruleset");
12
14
await chrome.declarativeNetRequest.updateEnabledRulesets({
13
15
enableRulesetIds: ["modifyResponseHeaders", "blockLoading"]
14
16
});
15
-
blockLoading = true;
16
-
collectedUrls.clear();
17
17
}
18
18
});
19
19
20
20
chrome.webRequest.onBeforeRequest.addListener(
21
21
async (details) => {
22
22
if (details.tabId === -1) return;
23
-
if (starterUrls.some((url) => details.url.includes(url))) {
24
-
console.log("Adding", details.url);
25
-
collectedUrls.add(details.url);
26
-
}
23
+
24
+
const url = new URL(details.url);
25
+
const hasUrl = scriptUrls.some((scriptUrl) => {
26
+
return (
27
+
details.url.includes(scriptUrl) &&
28
+
!url.searchParams.has("inj") &&
29
+
(url.hostname.endsWith("discord.com") || url.hostname.endsWith("discordapp.com"))
30
+
);
31
+
});
27
32
28
-
if (collectedUrls.size === starterUrls.length) {
29
-
if (doing) return;
30
-
if (!blockLoading) return;
31
-
doing = true;
32
-
const urls = [...collectedUrls];
33
-
console.log("Doing", urls);
33
+
if (hasUrl) blockedScripts.add(details.url);
34
+
35
+
if (blockedScripts.size === scriptUrls.length) {
36
+
const blockedScriptsCopy = Array.from(blockedScripts);
37
+
blockedScripts.clear();
34
38
35
39
console.log("Running moonlight script");
36
40
try {
···
40
44
files: ["index.js"]
41
45
});
42
46
} catch (e) {
43
-
console.log(e);
47
+
console.error(e);
44
48
}
45
49
46
50
console.log("Initializing moonlight");
···
52
56
try {
53
57
await window._moonlightBrowserInit();
54
58
} catch (e) {
55
-
console.log(e);
59
+
console.error(e);
56
60
}
57
61
}
58
62
});
···
60
64
console.log(e);
61
65
}
62
66
63
-
console.log("Updating rulesets");
67
+
console.log("Disabling block ruleset");
64
68
try {
65
-
blockLoading = false;
66
69
await chrome.declarativeNetRequest.updateEnabledRulesets({
67
70
disableRulesetIds: ["blockLoading"],
68
71
enableRulesetIds: ["modifyResponseHeaders"]
69
72
});
70
73
} catch (e) {
71
-
console.log(e);
74
+
console.error(e);
72
75
}
73
76
74
77
console.log("Readding scripts");
···
76
79
await chrome.scripting.executeScript({
77
80
target: { tabId: details.tabId },
78
81
world: "MAIN",
79
-
args: [urls],
80
-
func: async (urls) => {
82
+
args: [blockedScriptsCopy],
83
+
func: async (blockedScripts) => {
81
84
const scripts = [...document.querySelectorAll("script")].filter(
82
-
(script) =>
83
-
script.src && urls.some((url) => url.includes(script.src))
85
+
(script) => script.src && blockedScripts.some((url) => url.includes(script.src))
84
86
);
85
87
86
-
// backwards
87
-
urls.reverse();
88
-
for (const url of urls) {
89
-
const script = scripts.find((script) => url.includes(script.src));
90
-
console.log("adding new script", script);
88
+
blockedScripts.reverse();
89
+
for (const url of blockedScripts) {
90
+
if (url.includes("/sentry.")) continue;
91
91
92
+
const script = scripts.find((script) => url.includes(script.src));
92
93
const newScript = document.createElement("script");
93
-
for (const { name, value } of script.attributes) {
94
-
newScript.setAttribute(name, value);
94
+
for (const attr of script.attributes) {
95
+
if (attr.name === "src") attr.value += "?inj";
96
+
newScript.setAttribute(attr.name, attr.value);
95
97
}
96
-
97
98
script.remove();
98
99
document.documentElement.appendChild(newScript);
99
100
}
100
101
}
101
102
});
102
103
} catch (e) {
103
-
console.log(e);
104
+
console.error(e);
104
105
}
105
-
106
-
console.log("Done");
107
-
doing = false;
108
-
collectedUrls.clear();
109
106
}
110
107
},
111
108
{
112
-
urls: ["*://*.discord.com/assets/*.js"]
109
+
urls: ["*://*.discord.com/assets/*.js", "*://*.discordapp.com/assets/*.js"]
113
110
}
114
111
);
+97
-81
packages/browser/src/index.ts
+97
-81
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
-
import { configure } from "@zenfs/core";
9
+
import { configureSingle } from "@zenfs/core";
9
10
import * as fs from "@zenfs/core/promises";
11
+
import { NodeEventPayloads, NodeEventType } from "@moonlight-mod/types/core/event";
12
+
import { createEventEmitter } from "@moonlight-mod/core/util/event";
10
13
11
14
function getParts(path: string) {
12
15
if (path.startsWith("/")) path = path.substring(1);
···
14
17
}
15
18
16
19
window._moonlightBrowserInit = async () => {
20
+
delete window._moonlightBrowserInit;
21
+
17
22
// Set up a virtual filesystem with IndexedDB
18
-
await configure({
19
-
mounts: {
20
-
"/": {
21
-
backend: IndexedDB,
22
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
23
-
// @ts-ignore tsc tweaking
24
-
storeName: "moonlight-fs"
25
-
}
26
-
}
23
+
await configureSingle({
24
+
backend: IndexedDB,
25
+
storeName: "moonlight-fs"
27
26
});
28
27
29
-
window.moonlightFS = {
30
-
async readFile(path) {
31
-
return new Uint8Array(await fs.readFile(path));
32
-
},
33
-
async readFileString(path) {
34
-
const file = await this.readFile(path);
35
-
return new TextDecoder().decode(file);
36
-
},
37
-
async writeFile(path, data) {
38
-
await fs.writeFile(path, data);
39
-
},
40
-
async writeFileString(path, data) {
41
-
const file = new TextEncoder().encode(data);
42
-
await this.writeFile(path, file);
43
-
},
44
-
async unlink(path) {
45
-
await fs.unlink(path);
46
-
},
28
+
window.moonlightNodeSandboxed = {
29
+
fs: {
30
+
async readFile(path) {
31
+
return new Uint8Array(await fs.readFile(path));
32
+
},
33
+
async readFileString(path) {
34
+
const file = await this.readFile(path);
35
+
return new TextDecoder().decode(file);
36
+
},
37
+
async writeFile(path, data) {
38
+
await fs.writeFile(path, data);
39
+
},
40
+
async writeFileString(path, data) {
41
+
const file = new TextEncoder().encode(data);
42
+
await this.writeFile(path, file);
43
+
},
44
+
async unlink(path) {
45
+
await fs.unlink(path);
46
+
},
47
47
48
-
async readdir(path) {
49
-
return await fs.readdir(path);
50
-
},
51
-
async mkdir(path) {
52
-
const parts = getParts(path);
53
-
for (let i = 0; i < parts.length; i++) {
54
-
const path = this.join(...parts.slice(0, i + 1));
55
-
if (!(await this.exists(path))) await fs.mkdir(path);
56
-
}
57
-
},
48
+
async readdir(path) {
49
+
return await fs.readdir(path);
50
+
},
51
+
async mkdir(path) {
52
+
const parts = getParts(path);
53
+
for (let i = 0; i < parts.length; i++) {
54
+
const path = this.join(...parts.slice(0, i + 1));
55
+
if (!(await this.exists(path))) await fs.mkdir(path);
56
+
}
57
+
},
58
58
59
-
async rmdir(path) {
60
-
const entries = await this.readdir(path);
59
+
async rmdir(path) {
60
+
const entries = await this.readdir(path);
61
61
62
-
for (const entry of entries) {
63
-
const fullPath = this.join(path, entry);
64
-
const isFile = await this.isFile(fullPath);
65
-
if (isFile) {
66
-
await this.unlink(fullPath);
67
-
} else {
68
-
await this.rmdir(fullPath);
62
+
for (const entry of entries) {
63
+
const fullPath = this.join(path, entry);
64
+
const isFile = await this.isFile(fullPath);
65
+
if (isFile) {
66
+
await this.unlink(fullPath);
67
+
} else {
68
+
await this.rmdir(fullPath);
69
+
}
69
70
}
70
-
}
71
71
72
-
await fs.rmdir(path);
73
-
},
72
+
await fs.rmdir(path);
73
+
},
74
74
75
-
async exists(path) {
76
-
return await fs.exists(path);
77
-
},
78
-
async isFile(path) {
79
-
return (await fs.stat(path)).isFile();
80
-
},
75
+
async exists(path) {
76
+
return await fs.exists(path);
77
+
},
78
+
async isFile(path) {
79
+
return (await fs.stat(path)).isFile();
80
+
},
81
+
async isDir(path) {
82
+
return (await fs.stat(path)).isDirectory();
83
+
},
81
84
82
-
join(...parts) {
83
-
let str = parts.join("/");
84
-
if (!str.startsWith("/")) str = "/" + str;
85
-
return str;
85
+
join(...parts) {
86
+
let str = parts.join("/");
87
+
if (!str.startsWith("/")) str = "/" + str;
88
+
return str;
89
+
},
90
+
dirname(path) {
91
+
const parts = getParts(path);
92
+
return "/" + parts.slice(0, parts.length - 1).join("/");
93
+
},
94
+
basename(path) {
95
+
const parts = getParts(path);
96
+
return parts[parts.length - 1];
97
+
}
86
98
},
87
-
dirname(path) {
88
-
const parts = getParts(path);
89
-
return "/" + parts.slice(0, parts.length - 1).join("/");
90
-
}
99
+
// TODO
100
+
addCors(url) {},
101
+
addBlocked(url) {}
91
102
};
92
103
93
104
// Actual loading begins here
94
-
const config = await readConfig();
105
+
let config = await readConfig();
95
106
initLogger(config);
96
107
97
108
const extensions = await getExtensions();
98
109
const processedExtensions = await loadExtensions(extensions);
99
110
100
-
function getConfig(ext: string) {
101
-
const val = config.extensions[ext];
102
-
if (val == null || typeof val === "boolean") return undefined;
103
-
return val.config;
104
-
}
105
-
106
111
const moonlightNode: MoonlightNode = {
107
-
config,
112
+
get config() {
113
+
return config;
114
+
},
108
115
extensions,
109
116
processedExtensions,
110
117
nativesCache: {},
111
118
isBrowser: true,
119
+
events: createEventEmitter<NodeEventType, NodeEventPayloads>(),
112
120
113
121
version: MOONLIGHT_VERSION,
114
122
branch: MOONLIGHT_BRANCH as MoonlightBranch,
115
123
116
-
getConfig,
117
-
getConfigOption: <T>(ext: string, name: string) => {
118
-
const config = getConfig(ext);
119
-
if (config == null) return undefined;
120
-
const option = config[name];
121
-
if (option == null) return undefined;
122
-
return option as T;
124
+
getConfig(ext) {
125
+
return getConfig(ext, config);
126
+
},
127
+
getConfigOption(ext, name) {
128
+
const manifest = getManifest(extensions, ext);
129
+
return getConfigOption(ext, name, config, manifest?.settings);
123
130
},
131
+
async setConfigOption(ext, name, value) {
132
+
setConfigOption(config, ext, name, value);
133
+
await this.writeConfig(config);
134
+
},
135
+
124
136
getNatives: () => {},
125
137
getLogger: (id: string) => {
126
138
return new Logger(id);
···
133
145
return `/extensions/${ext}`;
134
146
},
135
147
136
-
writeConfig
148
+
async writeConfig(newConfig) {
149
+
await writeConfig(newConfig);
150
+
config = newConfig;
151
+
this.events.dispatchEvent(NodeEventType.ConfigSaved, newConfig);
152
+
}
137
153
};
138
154
139
155
Object.assign(window, {
···
141
157
});
142
158
143
159
// This is set by web-preload for us
144
-
await window._moonlightBrowserLoad();
160
+
await window._moonlightWebLoad!();
145
161
};
+1
packages/browser/tsconfig.json
+1
packages/browser/tsconfig.json
+7
packages/core/package.json
+7
packages/core/package.json
+4
-8
packages/core/src/config.ts
+4
-8
packages/core/src/config.ts
···
6
6
const logger = new Logger("core/config");
7
7
8
8
const defaultConfig: Config = {
9
+
// If you're updating this, update `builtinExtensions` in constants as well
9
10
extensions: {
10
11
moonbase: true,
11
12
disableSentry: true,
···
18
19
export async function writeConfig(config: Config) {
19
20
try {
20
21
const configPath = await getConfigPath();
21
-
await moonlightFS.writeFileString(
22
-
configPath,
23
-
JSON.stringify(config, null, 2)
24
-
);
22
+
await moonlightNodeSandboxed.fs.writeFileString(configPath, JSON.stringify(config, null, 2));
25
23
} catch (e) {
26
24
logger.error("Failed to write config", e);
27
25
}
···
33
31
}
34
32
35
33
const configPath = await getConfigPath();
36
-
if (!(await moonlightFS.exists(configPath))) {
34
+
if (!(await moonlightNodeSandboxed.fs.exists(configPath))) {
37
35
await writeConfig(defaultConfig);
38
36
return defaultConfig;
39
37
} else {
40
38
try {
41
-
let config: Config = JSON.parse(
42
-
await moonlightFS.readFileString(configPath)
43
-
);
39
+
let config: Config = JSON.parse(await moonlightNodeSandboxed.fs.readFileString(configPath));
44
40
// Assign the default values if they don't exist (newly added)
45
41
config = { ...defaultConfig, ...config };
46
42
await writeConfig(config);
+17
packages/core/src/cors.ts
+17
packages/core/src/cors.ts
···
1
+
const cors: string[] = [];
2
+
const blocked: string[] = [];
3
+
4
+
export function registerCors(url: string) {
5
+
cors.push(url);
6
+
}
7
+
8
+
export function registerBlocked(url: string) {
9
+
blocked.push(url);
10
+
}
11
+
12
+
export function getDynamicCors() {
13
+
return {
14
+
cors,
15
+
blocked
16
+
};
17
+
}
+62
-59
packages/core/src/extension/loader.ts
+62
-59
packages/core/src/extension/loader.ts
···
13
13
import calculateDependencies from "../util/dependency";
14
14
import { createEventEmitter } from "../util/event";
15
15
import { registerStyles } from "../styles";
16
-
import { EventPayloads, EventType } from "@moonlight-mod/types/core/event";
16
+
import { WebEventPayloads, WebEventType } from "@moonlight-mod/types/core/event";
17
17
18
18
const logger = new Logger("core/extension/loader");
19
19
20
-
function loadExtWeb(ext: DetectedExtension) {
20
+
function evalIIFE(id: string, source: string): ExtensionWebExports {
21
+
const fn = new Function("require", "module", "exports", source);
22
+
23
+
const module = { id, exports: {} };
24
+
fn.apply(window, [
25
+
() => {
26
+
logger.warn("Attempted to require() from web");
27
+
},
28
+
module,
29
+
module.exports
30
+
]);
31
+
32
+
return module.exports;
33
+
}
34
+
35
+
async function evalEsm(source: string): Promise<ExtensionWebExports> {
36
+
// Data URLs (`data:`) don't seem to work under the CSP, but object URLs do
37
+
const url = URL.createObjectURL(new Blob([source], { type: "text/javascript" }));
38
+
39
+
const module = await import(url);
40
+
41
+
URL.revokeObjectURL(url);
42
+
43
+
return module;
44
+
}
45
+
46
+
async function loadExtWeb(ext: DetectedExtension) {
21
47
if (ext.scripts.web != null) {
22
-
const source = ext.scripts.web;
23
-
const fn = new Function("require", "module", "exports", source);
48
+
const source = ext.scripts.web + `\n//# sourceURL=${ext.id}/web.js`;
24
49
25
-
const module = { id: ext.id, exports: {} };
26
-
fn.apply(window, [
27
-
() => {
28
-
logger.warn("Attempted to require() from web");
29
-
},
30
-
module,
31
-
module.exports
32
-
]);
50
+
let exports: ExtensionWebExports;
33
51
34
-
const exports: ExtensionWebExports = module.exports;
52
+
try {
53
+
exports = evalIIFE(ext.id, source);
54
+
} catch {
55
+
logger.trace(`Failed to load IIFE for extension ${ext.id}, trying ESM loading`);
56
+
exports = await evalEsm(source);
57
+
}
58
+
35
59
if (exports.patches != null) {
36
60
let idx = 0;
37
61
for (const patch of exports.patches) {
38
62
if (Array.isArray(patch.replace)) {
39
-
for (const replacement of patch.replace) {
40
-
const newPatch = Object.assign({}, patch, {
41
-
replace: replacement
42
-
});
43
-
44
-
registerPatch({ ...newPatch, ext: ext.id, id: idx });
45
-
idx++;
46
-
}
63
+
registerPatch({ ...patch, ext: ext.id, id: idx });
47
64
} else {
48
-
registerPatch({ ...patch, ext: ext.id, id: idx });
49
-
idx++;
65
+
registerPatch({ ...patch, replace: [patch.replace], ext: ext.id, id: idx });
50
66
}
67
+
idx++;
51
68
}
52
69
}
53
70
54
71
if (exports.webpackModules != null) {
55
72
for (const [name, wp] of Object.entries(exports.webpackModules)) {
56
73
if (wp.run == null && ext.scripts.webpackModules?.[name] != null) {
57
-
const func = new Function(
58
-
"module",
59
-
"exports",
60
-
"require",
61
-
ext.scripts.webpackModules[name]!
62
-
) as WebpackModuleFunc;
74
+
const source = ext.scripts.webpackModules[name]! + `\n//# sourceURL=${ext.id}/webpackModules/${name}.js`;
75
+
const func = new Function("module", "exports", "require", source) as WebpackModuleFunc;
63
76
registerWebpackModule({
64
77
...wp,
65
78
ext: ext.id,
···
73
86
}
74
87
75
88
if (exports.styles != null) {
76
-
registerStyles(
77
-
exports.styles.map((style, i) => `/* ${ext.id}#${i} */ ${style}`)
78
-
);
89
+
registerStyles(exports.styles.map((style, i) => `/* ${ext.id}#${i} */ ${style}`));
90
+
}
91
+
if (ext.scripts.style != null) {
92
+
registerStyles([`/* ${ext.id}#style.css */ ${ext.scripts.style}`]);
79
93
}
80
94
}
81
95
}
82
96
83
97
async function loadExt(ext: DetectedExtension) {
84
98
webTarget: {
85
-
loadExtWeb(ext);
99
+
try {
100
+
await loadExtWeb(ext);
101
+
} catch (e) {
102
+
logger.error(`Failed to load extension "${ext.id}"`, e);
103
+
}
86
104
}
87
105
88
106
nodePreload: {
···
113
131
InvalidEnvironment
114
132
}
115
133
116
-
export function checkExtensionCompat(
117
-
manifest: ExtensionManifest
118
-
): ExtensionCompat {
134
+
export function checkExtensionCompat(manifest: ExtensionManifest): ExtensionCompat {
119
135
let environment;
120
136
webTarget: {
121
137
environment = ExtensionEnvironment.Web;
···
124
140
environment = ExtensionEnvironment.Desktop;
125
141
}
126
142
127
-
if (manifest.apiLevel !== constants.apiLevel)
128
-
return ExtensionCompat.InvalidApiLevel;
129
-
if (
130
-
(manifest.environment ?? "both") !== "both" &&
131
-
manifest.environment !== environment
132
-
)
143
+
if (manifest.apiLevel !== constants.apiLevel) return ExtensionCompat.InvalidApiLevel;
144
+
if ((manifest.environment ?? "both") !== "both" && manifest.environment !== environment)
133
145
return ExtensionCompat.InvalidEnvironment;
134
146
return ExtensionCompat.Compatible;
135
147
}
···
148
160
extensions fires an event on completion, which allows us to await the loading
149
161
of another extension, resolving dependencies & load order effectively.
150
162
*/
151
-
export async function loadExtensions(
152
-
exts: DetectedExtension[]
153
-
): Promise<ProcessedExtensions> {
154
-
exts = exts.filter(
155
-
(ext) => checkExtensionCompat(ext.manifest) === ExtensionCompat.Compatible
156
-
);
163
+
export async function loadExtensions(exts: DetectedExtension[]): Promise<ProcessedExtensions> {
164
+
exts = exts.filter((ext) => checkExtensionCompat(ext.manifest) === ExtensionCompat.Compatible);
157
165
158
166
const config = await readConfig();
159
167
const items = exts
···
193
201
};
194
202
}
195
203
196
-
export async function loadProcessedExtensions({
197
-
extensions,
198
-
dependencyGraph
199
-
}: ProcessedExtensions) {
200
-
const eventEmitter = createEventEmitter<EventType, EventPayloads>();
204
+
export async function loadProcessedExtensions({ extensions, dependencyGraph }: ProcessedExtensions) {
205
+
const eventEmitter = createEventEmitter<WebEventType, WebEventPayloads>();
201
206
const finished: Set<string> = new Set();
202
207
203
208
logger.trace(
···
219
224
}
220
225
221
226
function done() {
222
-
eventEmitter.removeEventListener(EventType.ExtensionLoad, cb);
227
+
eventEmitter.removeEventListener(WebEventType.ExtensionLoad, cb);
223
228
r();
224
229
}
225
230
226
-
eventEmitter.addEventListener(EventType.ExtensionLoad, cb);
231
+
eventEmitter.addEventListener(WebEventType.ExtensionLoad, cb);
227
232
if (finished.has(dep)) done();
228
233
})
229
234
);
230
235
231
236
if (waitPromises.length > 0) {
232
-
logger.debug(
233
-
`Waiting on ${waitPromises.length} dependencies for "${ext.id}"`
234
-
);
237
+
logger.debug(`Waiting on ${waitPromises.length} dependencies for "${ext.id}"`);
235
238
await Promise.all(waitPromises);
236
239
}
237
240
···
239
242
await loadExt(ext);
240
243
241
244
finished.add(ext.id);
242
-
eventEmitter.dispatchEvent(EventType.ExtensionLoad, ext.id);
245
+
eventEmitter.dispatchEvent(WebEventType.ExtensionLoad, ext.id);
243
246
logger.debug(`Loaded "${ext.id}"`);
244
247
}
245
248
+55
-78
packages/core/src/extension.ts
+55
-78
packages/core/src/extension.ts
···
1
-
import {
2
-
ExtensionManifest,
3
-
DetectedExtension,
4
-
ExtensionLoadSource,
5
-
constants
6
-
} from "@moonlight-mod/types";
1
+
import { ExtensionManifest, DetectedExtension, ExtensionLoadSource, constants } from "@moonlight-mod/types";
7
2
import { readConfig } from "./config";
8
3
import { getCoreExtensionsPath, getExtensionsPath } from "./util/data";
9
4
import Logger from "./util/logger";
···
13
8
async function findManifests(dir: string): Promise<string[]> {
14
9
const ret = [];
15
10
16
-
if (await moonlightFS.exists(dir)) {
17
-
for (const file of await moonlightFS.readdir(dir)) {
18
-
const path = moonlightFS.join(dir, file);
11
+
if (await moonlightNodeSandboxed.fs.exists(dir)) {
12
+
for (const file of await moonlightNodeSandboxed.fs.readdir(dir)) {
13
+
const path = moonlightNodeSandboxed.fs.join(dir, file);
19
14
if (file === "manifest.json") {
20
15
ret.push(path);
21
16
}
22
17
23
-
if (!(await moonlightFS.isFile(path))) {
18
+
if (!(await moonlightNodeSandboxed.fs.isFile(path))) {
24
19
ret.push(...(await findManifests(path)));
25
20
}
26
21
}
···
31
26
32
27
async function loadDetectedExtensions(
33
28
dir: string,
34
-
type: ExtensionLoadSource
29
+
type: ExtensionLoadSource,
30
+
seen: Set<string>
35
31
): Promise<DetectedExtension[]> {
36
32
const ret: DetectedExtension[] = [];
37
33
38
34
const manifests = await findManifests(dir);
39
35
for (const manifestPath of manifests) {
40
36
try {
41
-
if (!(await moonlightFS.exists(manifestPath))) continue;
42
-
const dir = moonlightFS.dirname(manifestPath);
37
+
if (!(await moonlightNodeSandboxed.fs.exists(manifestPath))) continue;
38
+
const dir = moonlightNodeSandboxed.fs.dirname(manifestPath);
43
39
44
-
const manifest: ExtensionManifest = JSON.parse(
45
-
await moonlightFS.readFileString(manifestPath)
46
-
);
40
+
const manifest: ExtensionManifest = JSON.parse(await moonlightNodeSandboxed.fs.readFileString(manifestPath));
41
+
if (seen.has(manifest.id)) {
42
+
logger.warn(`Duplicate extension found, skipping: ${manifest.id}`);
43
+
continue;
44
+
}
45
+
seen.add(manifest.id);
47
46
48
-
const webPath = moonlightFS.join(dir, "index.js");
49
-
const nodePath = moonlightFS.join(dir, "node.js");
50
-
const hostPath = moonlightFS.join(dir, "host.js");
47
+
const webPath = moonlightNodeSandboxed.fs.join(dir, "index.js");
48
+
const nodePath = moonlightNodeSandboxed.fs.join(dir, "node.js");
49
+
const hostPath = moonlightNodeSandboxed.fs.join(dir, "host.js");
51
50
52
51
// if none exist (empty manifest) don't give a shit
53
52
if (
54
-
!moonlightFS.exists(webPath) &&
55
-
!moonlightFS.exists(nodePath) &&
56
-
!moonlightFS.exists(hostPath)
53
+
!moonlightNodeSandboxed.fs.exists(webPath) &&
54
+
!moonlightNodeSandboxed.fs.exists(nodePath) &&
55
+
!moonlightNodeSandboxed.fs.exists(hostPath)
57
56
) {
58
57
continue;
59
58
}
60
59
61
-
const web = (await moonlightFS.exists(webPath))
62
-
? await moonlightFS.readFileString(webPath)
60
+
const web = (await moonlightNodeSandboxed.fs.exists(webPath))
61
+
? await moonlightNodeSandboxed.fs.readFileString(webPath)
63
62
: undefined;
64
63
65
64
let url: string | undefined = undefined;
66
-
const urlPath = moonlightFS.join(dir, constants.repoUrlFile);
67
-
if (
68
-
type === ExtensionLoadSource.Normal &&
69
-
(await moonlightFS.exists(urlPath))
70
-
) {
71
-
url = await moonlightFS.readFileString(urlPath);
65
+
const urlPath = moonlightNodeSandboxed.fs.join(dir, constants.repoUrlFile);
66
+
if (type === ExtensionLoadSource.Normal && (await moonlightNodeSandboxed.fs.exists(urlPath))) {
67
+
url = await moonlightNodeSandboxed.fs.readFileString(urlPath);
72
68
}
73
69
74
70
const wpModules: Record<string, string> = {};
75
-
const wpModulesPath = moonlightFS.join(dir, "webpackModules");
76
-
if (await moonlightFS.exists(wpModulesPath)) {
77
-
const wpModulesFile = await moonlightFS.readdir(wpModulesPath);
71
+
const wpModulesPath = moonlightNodeSandboxed.fs.join(dir, "webpackModules");
72
+
if (await moonlightNodeSandboxed.fs.exists(wpModulesPath)) {
73
+
const wpModulesFile = await moonlightNodeSandboxed.fs.readdir(wpModulesPath);
78
74
79
75
for (const wpModuleFile of wpModulesFile) {
80
76
if (wpModuleFile.endsWith(".js")) {
81
-
wpModules[wpModuleFile.replace(".js", "")] =
82
-
await moonlightFS.readFileString(
83
-
moonlightFS.join(wpModulesPath, wpModuleFile)
84
-
);
77
+
wpModules[wpModuleFile.replace(".js", "")] = await moonlightNodeSandboxed.fs.readFileString(
78
+
moonlightNodeSandboxed.fs.join(wpModulesPath, wpModuleFile)
79
+
);
85
80
}
86
81
}
87
82
}
83
+
84
+
const stylePath = moonlightNodeSandboxed.fs.join(dir, "style.css");
88
85
89
86
ret.push({
90
87
id: manifest.id,
···
97
94
web,
98
95
webPath: web != null ? webPath : undefined,
99
96
webpackModules: wpModules,
100
-
nodePath: (await moonlightFS.exists(nodePath)) ? nodePath : undefined,
101
-
hostPath: (await moonlightFS.exists(hostPath)) ? hostPath : undefined
97
+
nodePath: (await moonlightNodeSandboxed.fs.exists(nodePath)) ? nodePath : undefined,
98
+
hostPath: (await moonlightNodeSandboxed.fs.exists(hostPath)) ? hostPath : undefined,
99
+
style: (await moonlightNodeSandboxed.fs.exists(stylePath))
100
+
? await moonlightNodeSandboxed.fs.readFileString(stylePath)
101
+
: undefined
102
102
}
103
103
});
104
-
} catch (e) {
105
-
logger.error(e, "Failed to load extension");
104
+
} catch (err) {
105
+
logger.error(`Failed to load extension from "${manifestPath}":`, err);
106
106
}
107
107
}
108
108
···
112
112
async function getExtensionsNative(): Promise<DetectedExtension[]> {
113
113
const config = await readConfig();
114
114
const res = [];
115
+
const seen = new Set<string>();
115
116
116
-
res.push(
117
-
...(await loadDetectedExtensions(
118
-
getCoreExtensionsPath(),
119
-
ExtensionLoadSource.Core
120
-
))
121
-
);
122
-
123
-
res.push(
124
-
...(await loadDetectedExtensions(
125
-
await getExtensionsPath(),
126
-
ExtensionLoadSource.Normal
127
-
))
128
-
);
117
+
res.push(...(await loadDetectedExtensions(getCoreExtensionsPath(), ExtensionLoadSource.Core, seen)));
129
118
130
119
for (const devSearchPath of config.devSearchPaths ?? []) {
131
-
res.push(
132
-
...(await loadDetectedExtensions(
133
-
devSearchPath,
134
-
ExtensionLoadSource.Developer
135
-
))
136
-
);
120
+
res.push(...(await loadDetectedExtensions(devSearchPath, ExtensionLoadSource.Developer, seen)));
137
121
}
138
122
123
+
res.push(...(await loadDetectedExtensions(await getExtensionsPath(), ExtensionLoadSource.Normal, seen)));
124
+
139
125
return res;
140
126
}
141
127
142
128
async function getExtensionsBrowser(): Promise<DetectedExtension[]> {
143
129
const ret: DetectedExtension[] = [];
130
+
const seen = new Set<string>();
144
131
145
-
const coreExtensionsFs: Record<string, string> = JSON.parse(
146
-
// @ts-expect-error shut up
147
-
_moonlight_coreExtensionsStr
148
-
);
149
-
const coreExtensions = Array.from(
150
-
new Set(Object.keys(coreExtensionsFs).map((x) => x.split("/")[0]))
151
-
);
132
+
const coreExtensionsFs: Record<string, string> = JSON.parse(_moonlight_coreExtensionsStr);
133
+
const coreExtensions = Array.from(new Set(Object.keys(coreExtensionsFs).map((x) => x.split("/")[0])));
152
134
153
135
for (const ext of coreExtensions) {
154
136
if (!coreExtensionsFs[`${ext}/index.js`]) continue;
···
159
141
const wpModulesPath = `${ext}/webpackModules`;
160
142
for (const wpModuleFile of Object.keys(coreExtensionsFs)) {
161
143
if (wpModuleFile.startsWith(wpModulesPath)) {
162
-
wpModules[
163
-
wpModuleFile.replace(wpModulesPath + "/", "").replace(".js", "")
164
-
] = coreExtensionsFs[wpModuleFile];
144
+
wpModules[wpModuleFile.replace(wpModulesPath + "/", "").replace(".js", "")] = coreExtensionsFs[wpModuleFile];
165
145
}
166
146
}
167
147
···
173
153
},
174
154
scripts: {
175
155
web,
176
-
webpackModules: wpModules
156
+
webpackModules: wpModules,
157
+
style: coreExtensionsFs[`${ext}/style.css`]
177
158
}
178
159
});
160
+
seen.add(manifest.id);
179
161
}
180
162
181
-
if (await moonlightFS.exists("/extensions")) {
182
-
ret.push(
183
-
...(await loadDetectedExtensions(
184
-
"/extensions",
185
-
ExtensionLoadSource.Normal
186
-
))
187
-
);
163
+
if (await moonlightNodeSandboxed.fs.exists("/extensions")) {
164
+
ret.push(...(await loadDetectedExtensions("/extensions", ExtensionLoadSource.Normal, seen)));
188
165
}
189
166
190
167
return ret;
+6
packages/core/src/fs.ts
+6
packages/core/src/fs.ts
···
39
39
async isFile(path) {
40
40
return fs.statSync(path).isFile();
41
41
},
42
+
async isDir(path) {
43
+
return fs.statSync(path).isDirectory();
44
+
},
42
45
43
46
join(...parts) {
44
47
return path.join(...parts);
45
48
},
46
49
dirname(dir) {
47
50
return path.dirname(dir);
51
+
},
52
+
basename(dir) {
53
+
return path.basename(dir);
48
54
}
49
55
};
50
56
}
+138
-122
packages/core/src/patch.ts
+138
-122
packages/core/src/patch.ts
···
11
11
} from "@moonlight-mod/types";
12
12
import Logger from "./util/logger";
13
13
import calculateDependencies, { Dependency } from "./util/dependency";
14
-
import WebpackRequire from "@moonlight-mod/types/discord/require";
15
-
import { EventType } from "@moonlight-mod/types/core/event";
14
+
import { WebEventType } from "@moonlight-mod/types/core/event";
15
+
import { processFind, processReplace, testFind } from "./util/patch";
16
16
17
17
const logger = new Logger("core/patch");
18
18
···
21
21
let webpackModules: Set<IdentifiedWebpackModule> = new Set();
22
22
let webpackRequire: WebpackRequireType | null = null;
23
23
24
-
const moduleLoadSubscriptions: Map<string, ((moduleId: string) => void)[]> =
25
-
new Map();
24
+
const moduleLoadSubscriptions: Map<string, ((moduleId: string) => void)[]> = new Map();
26
25
27
26
export function registerPatch(patch: IdentifiedPatch) {
27
+
patch.find = processFind(patch.find);
28
+
processReplace(patch.replace);
29
+
28
30
patches.push(patch);
29
31
moonlight.unpatched.add(patch);
30
32
}
···
36
38
}
37
39
}
38
40
39
-
export function onModuleLoad(
40
-
module: string | string[],
41
-
callback: (moduleId: string) => void
42
-
): void {
41
+
export function onModuleLoad(module: string | string[], callback: (moduleId: string) => void): void {
43
42
let moduleIds = module;
44
43
45
44
if (typeof module === "string") {
···
67
66
const moduleCache: Record<string, string> = {};
68
67
const patched: Record<string, Array<string>> = {};
69
68
70
-
function patchModules(entry: WebpackJsonpEntry[1]) {
71
-
function patchModule(id: string, patchId: string, replaced: string) {
72
-
// Store what extensions patched what modules for easier debugging
73
-
patched[id] = patched[id] || [];
74
-
patched[id].push(patchId);
69
+
function createSourceURL(id: string) {
70
+
const remapped = Object.entries(moonlight.moonmap.modules).find((m) => m[1] === id)?.[0];
71
+
72
+
if (remapped) {
73
+
return `// Webpack Module: ${id}\n//# sourceURL=${remapped}`;
74
+
}
75
+
76
+
return `//# sourceURL=Webpack-Module/${id.slice(0, 3)}/${id}`;
77
+
}
78
+
79
+
function patchModule(id: string, patchId: string, replaced: string, entry: WebpackJsonpEntry[1]) {
80
+
// Store what extensions patched what modules for easier debugging
81
+
patched[id] = patched[id] ?? [];
82
+
patched[id].push(patchId);
75
83
76
-
// Webpack module arguments are minified, so we replace them with consistent names
77
-
// We have to wrap it so things don't break, though
78
-
const patchedStr = patched[id].sort().join(", ");
84
+
// Webpack module arguments are minified, so we replace them with consistent names
85
+
// We have to wrap it so things don't break, though
86
+
const patchedStr = patched[id].sort().join(", ");
79
87
80
-
const wrapped =
81
-
`(${replaced}).apply(this, arguments)\n` +
82
-
`// Patched by moonlight: ${patchedStr}\n` +
83
-
`//# sourceURL=Webpack-Module-${id}`;
88
+
const wrapped =
89
+
`(${replaced}).apply(this, arguments)\n` + `// Patched by moonlight: ${patchedStr}\n` + createSourceURL(id);
84
90
85
-
try {
86
-
const func = new Function(
87
-
"module",
88
-
"exports",
89
-
"require",
90
-
wrapped
91
-
) as WebpackModuleFunc;
92
-
entry[id] = func;
93
-
entry[id].__moonlight = true;
94
-
return true;
95
-
} catch (e) {
96
-
logger.warn("Error constructing function for patch", patchId, e);
97
-
patched[id].pop();
98
-
return false;
99
-
}
91
+
try {
92
+
const func = new Function("module", "exports", "require", wrapped) as WebpackModuleFunc;
93
+
entry[id] = func;
94
+
entry[id].__moonlight = true;
95
+
return true;
96
+
} catch (e) {
97
+
logger.warn("Error constructing function for patch", patchId, e);
98
+
patched[id].pop();
99
+
return false;
100
100
}
101
+
}
101
102
103
+
function patchModules(entry: WebpackJsonpEntry[1]) {
102
104
// Populate the module cache
103
105
for (const [id, func] of Object.entries(entry)) {
104
106
if (!Object.hasOwn(moduleCache, id) && func.__moonlight !== true) {
···
109
111
110
112
for (const [id, func] of Object.entries(entry)) {
111
113
if (func.__moonlight === true) continue;
112
-
let moduleString = moduleCache[id];
114
+
115
+
// Clone the module string so finds don't get messed up by other extensions
116
+
const origModuleString = moduleCache[id];
117
+
let moduleString = origModuleString;
118
+
const patchedStr = [];
119
+
const mappedName = Object.entries(moonlight.moonmap.modules).find((m) => m[1] === id)?.[0];
120
+
let modified = false;
121
+
let swappedModule = false;
122
+
123
+
const exts = new Set<string>();
113
124
114
125
for (let i = 0; i < patches.length; i++) {
115
126
const patch = patches[i];
116
127
if (patch.prerequisite != null && !patch.prerequisite()) {
128
+
moonlight.unpatched.delete(patch);
117
129
continue;
118
130
}
119
131
···
122
134
patch.find.lastIndex = 0;
123
135
}
124
136
125
-
// indexOf is faster than includes by 0.25% lmao
126
-
const match =
127
-
typeof patch.find === "string"
128
-
? moduleString.indexOf(patch.find) !== -1
129
-
: patch.find.test(moduleString);
137
+
const match = testFind(origModuleString, patch.find) || patch.find === mappedName;
130
138
131
139
// Global regexes apply to all modules
132
-
const shouldRemove =
133
-
typeof patch.find === "string" ? true : !patch.find.global;
140
+
const shouldRemove = typeof patch.find === "string" ? true : !patch.find.global;
134
141
142
+
let replaced = moduleString;
143
+
let hardFailed = false;
135
144
if (match) {
136
-
moonlight.unpatched.delete(patch);
145
+
// We ensured normal PatchReplace objects get turned into arrays on register
146
+
const replaces = patch.replace as PatchReplace[];
137
147
138
-
// We ensured all arrays get turned into normal PatchReplace objects on register
139
-
const replace = patch.replace as PatchReplace;
140
-
141
-
if (
142
-
replace.type === undefined ||
143
-
replace.type === PatchReplaceType.Normal
144
-
) {
145
-
// Add support for \i to match rspack's minified names
146
-
if (typeof replace.match !== "string") {
147
-
replace.match = new RegExp(
148
-
replace.match.source.replace(/\\i/g, "[A-Za-z_$][\\w$]*"),
149
-
replace.match.flags
150
-
);
151
-
}
152
-
// tsc fails to detect the overloads for this, so I'll just do this
153
-
// Verbose, but it works
154
-
let replaced;
155
-
if (typeof replace.replacement === "string") {
156
-
replaced = moduleString.replace(replace.match, replace.replacement);
157
-
} else {
158
-
replaced = moduleString.replace(replace.match, replace.replacement);
159
-
}
148
+
let isPatched = true;
149
+
for (let i = 0; i < replaces.length; i++) {
150
+
const replace = replaces[i];
151
+
let patchId = `${patch.ext}#${patch.id}`;
152
+
if (replaces.length > 1) patchId += `#${i}`;
153
+
patchedStr.push(patchId);
160
154
161
-
if (replaced === moduleString) {
162
-
logger.warn("Patch replacement failed", id, patch);
163
-
continue;
164
-
}
155
+
if (replace.type === undefined || replace.type === PatchReplaceType.Normal) {
156
+
// tsc fails to detect the overloads for this, so I'll just do this
157
+
// Verbose, but it works
158
+
if (typeof replace.replacement === "string") {
159
+
replaced = replaced.replace(replace.match, replace.replacement);
160
+
} else {
161
+
replaced = replaced.replace(replace.match, replace.replacement);
162
+
}
165
163
166
-
if (patchModule(id, `${patch.ext}#${patch.id}`, replaced)) {
167
-
moduleString = replaced;
164
+
if (replaced === moduleString) {
165
+
logger.warn("Patch replacement failed", id, patchId, patch);
166
+
isPatched = false;
167
+
if (patch.hardFail) {
168
+
hardFailed = true;
169
+
break;
170
+
} else {
171
+
continue;
172
+
}
173
+
}
174
+
} else if (replace.type === PatchReplaceType.Module) {
175
+
// Directly replace the module with a new one
176
+
const newModule = replace.replacement(replaced);
177
+
entry[id] = newModule;
178
+
entry[id].__moonlight = true;
179
+
replaced = newModule.toString().replace(/\n/g, "");
180
+
swappedModule = true;
168
181
}
169
-
} else if (replace.type === PatchReplaceType.Module) {
170
-
// Directly replace the module with a new one
171
-
const newModule = replace.replacement(moduleString);
172
-
entry[id] = newModule;
173
-
entry[id].__moonlight = true;
174
-
moduleString =
175
-
newModule.toString().replace(/\n/g, "") +
176
-
`//# sourceURL=Webpack-Module-${id}`;
177
182
}
178
183
179
-
if (shouldRemove) {
180
-
patches.splice(i--, 1);
184
+
if (!hardFailed) {
185
+
moduleString = replaced;
186
+
modified = true;
187
+
exts.add(patch.ext);
181
188
}
189
+
190
+
if (isPatched) moonlight.unpatched.delete(patch);
191
+
if (shouldRemove) patches.splice(i--, 1);
182
192
}
183
193
}
184
194
185
-
moduleCache[id] = moduleString;
195
+
if (modified) {
196
+
let shouldCache = true;
197
+
if (!swappedModule) shouldCache = patchModule(id, patchedStr.join(", "), moduleString, entry);
198
+
if (shouldCache) moduleCache[id] = moduleString;
199
+
moonlight.patched.set(id, exts);
200
+
}
186
201
187
202
try {
188
203
const parsed = moonlight.lunast.parseScript(id, moduleString);
189
204
if (parsed != null) {
190
205
for (const [parsedId, parsedScript] of Object.entries(parsed)) {
191
-
if (patchModule(parsedId, "lunast", parsedScript)) {
206
+
if (patchModule(parsedId, "lunast", parsedScript, entry)) {
192
207
moduleCache[parsedId] = parsedScript;
193
208
}
194
209
}
···
198
213
}
199
214
200
215
if (moonlightNode.config.patchAll === true) {
201
-
if (
202
-
(typeof id !== "string" || !id.includes("_")) &&
203
-
!entry[id].__moonlight
204
-
) {
205
-
const wrapped =
206
-
`(${moduleCache[id]}).apply(this, arguments)\n` +
207
-
`//# sourceURL=Webpack-Module-${id}`;
208
-
entry[id] = new Function(
209
-
"module",
210
-
"exports",
211
-
"require",
212
-
wrapped
213
-
) as WebpackModuleFunc;
216
+
if ((typeof id !== "string" || !id.includes("_")) && !entry[id].__moonlight) {
217
+
const wrapped = `(${moduleCache[id]}).apply(this, arguments)\n` + createSourceURL(id);
218
+
entry[id] = new Function("module", "exports", "require", wrapped) as WebpackModuleFunc;
214
219
entry[id].__moonlight = true;
215
220
}
216
221
}
···
246
251
function handleModuleDependencies() {
247
252
const modules = Array.from(webpackModules.values());
248
253
249
-
const dependencies: Dependency<string, IdentifiedWebpackModule>[] =
250
-
modules.map((wp) => {
251
-
return {
252
-
id: depToString(wp),
253
-
data: wp
254
-
};
255
-
});
254
+
const dependencies: Dependency<string, IdentifiedWebpackModule>[] = modules.map((wp) => {
255
+
return {
256
+
id: depToString(wp),
257
+
data: wp
258
+
};
259
+
});
256
260
257
261
const [sorted, _] = calculateDependencies(dependencies, {
258
262
fetchDep: (id) => {
···
263
267
const deps = item.data?.dependencies ?? [];
264
268
return (
265
269
deps.filter(
266
-
(dep) =>
267
-
!(dep instanceof RegExp || typeof dep === "string") &&
268
-
dep.ext != null
270
+
(dep) => !(dep instanceof RegExp || typeof dep === "string") && dep.ext != null
269
271
) as ExplicitExtensionDependency[]
270
272
).map(depToString);
271
273
}
···
297
299
if (dep.test(modStr)) deps.delete(dep);
298
300
} else if (
299
301
dep.ext != null
300
-
? injectedWpModules.find(
301
-
(x) => x.ext === dep.ext && x.id === dep.id
302
-
)
302
+
? injectedWpModules.find((x) => x.ext === dep.ext && x.id === dep.id)
303
303
: injectedWpModules.find((x) => x.id === dep.id)
304
304
) {
305
305
deps.delete(dep);
306
306
}
307
307
}
308
308
309
+
wpModule.dependencies = Array.from(deps);
309
310
if (deps.size !== 0) {
310
-
wpModule.dependencies = Array.from(deps);
311
311
continue;
312
312
}
313
-
314
-
wpModule.dependencies = Array.from(deps);
315
313
}
316
314
}
317
315
···
324
322
if (wpModule.run) {
325
323
modules[id] = wpModule.run;
326
324
wpModule.run.__moonlight = true;
325
+
// @ts-expect-error hacks
326
+
wpModule.run.call = function (self, module, exports, require) {
327
+
try {
328
+
wpModule.run!.apply(self, [module, exports, require]);
329
+
} catch (err) {
330
+
logger.error(`Failed to run module "${id}":`, err);
331
+
}
332
+
};
333
+
if (wpModule.entrypoint) entrypoints.push(id);
327
334
}
328
-
if (wpModule.entrypoint) entrypoints.push(id);
329
335
}
330
336
if (!webpackModules.size) break;
331
337
}
332
338
333
-
for (const [name, func] of Object.entries(
334
-
moonlight.moonmap.getWebpackModules("window.moonlight.moonmap")
335
-
)) {
339
+
for (const [name, func] of Object.entries(moonlight.moonmap.getWebpackModules("window.moonlight.moonmap"))) {
340
+
// @ts-expect-error probably should fix the type on this idk
341
+
func.__moonlight = true;
336
342
injectedWpModules.push({ id: name, run: func });
337
343
modules[name] = func;
338
344
inject = true;
···
349
355
window.webpackChunkdiscord_app.push([
350
356
[--chunkId],
351
357
modules,
352
-
(require: typeof WebpackRequire) => entrypoints.map(require)
358
+
(require: WebpackRequireType) =>
359
+
entrypoints.map((id) => {
360
+
try {
361
+
if (require.m[id] == null) {
362
+
logger.error(`Failing to load entrypoint module "${id}" because it's not found in Webpack.`);
363
+
} else {
364
+
require(id);
365
+
}
366
+
} catch (err) {
367
+
logger.error(`Failed to load entrypoint module "${id}":`, err);
368
+
}
369
+
})
353
370
]);
354
371
}
355
372
}
···
399
416
const realPush = jsonp.push;
400
417
if (jsonp.push.__moonlight !== true) {
401
418
jsonp.push = (items) => {
402
-
moonlight.events.dispatchEvent(EventType.ChunkLoad, {
419
+
moonlight.events.dispatchEvent(WebEventType.ChunkLoad, {
403
420
chunkId: items[0],
404
421
modules: items[1],
405
422
require: items[2]
···
447
464
set(modules: any) {
448
465
const { stack } = new Error();
449
466
if (stack!.includes("/assets/") && !Array.isArray(modules)) {
450
-
moonlight.events.dispatchEvent(EventType.ChunkLoad, {
467
+
moonlight.events.dispatchEvent(WebEventType.ChunkLoad, {
451
468
modules: modules
452
469
});
453
470
patchModules(modules);
454
471
455
-
if (!window.webpackChunkdiscord_app)
456
-
window.webpackChunkdiscord_app = [];
472
+
if (!window.webpackChunkdiscord_app) window.webpackChunkdiscord_app = [];
457
473
injectModules(modules);
458
474
}
459
475
+2
-12
packages/core/src/persist.ts
+2
-12
packages/core/src/persist.ts
···
1
1
import { join, dirname } from "node:path";
2
-
import {
3
-
mkdirSync,
4
-
renameSync,
5
-
existsSync,
6
-
copyFileSync,
7
-
readdirSync
8
-
} from "node:fs";
2
+
import { mkdirSync, renameSync, existsSync, copyFileSync, readdirSync } from "node:fs";
9
3
import Logger from "./util/logger";
10
4
11
5
const logger = new Logger("core/persist");
···
31
25
if (event === "host-updated") {
32
26
const versions = this.queryCurrentVersionsSync();
33
27
34
-
const newRootDir = join(
35
-
this.rootPath,
36
-
"app-" +
37
-
versions.current_host.map((v: number) => v.toString()).join(".")
38
-
);
28
+
const newRootDir = join(this.rootPath, "app-" + versions.current_host.map((v: number) => v.toString()).join("."));
39
29
logger.info(`Persisting moonlight - new root dir: ${newRootDir}`);
40
30
41
31
const newResources = join(newRootDir, "resources");
+1
-4
packages/core/src/util/binary.ts
+1
-4
packages/core/src/util/binary.ts
···
55
55
return data;
56
56
}
57
57
58
-
private _read<T>(
59
-
func: (position: number, littleEndian?: boolean) => T,
60
-
length: number
61
-
): T {
58
+
private _read<T>(func: (position: number, littleEndian?: boolean) => T, length: number): T {
62
59
const result = func.call(this.view, this.position, true);
63
60
this.position += length;
64
61
return result;
+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
+
settings?: ExtensionManifest["settings"]
18
+
): T | undefined {
19
+
const defaultValue: T | undefined = structuredClone(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
+
}
+10
-15
packages/core/src/util/data.ts
+10
-15
packages/core/src/util/data.ts
···
16
16
appData = electron.ipcRenderer.sendSync(constants.ipcGetAppData);
17
17
}
18
18
19
-
const dir = moonlightFS.join(appData, "moonlight-mod");
20
-
if (!(await moonlightFS.exists(dir))) await moonlightFS.mkdir(dir);
19
+
const dir = moonlightNodeSandboxed.fs.join(appData, "moonlight-mod");
20
+
if (!(await moonlightNodeSandboxed.fs.exists(dir))) await moonlightNodeSandboxed.fs.mkdir(dir);
21
21
22
22
return dir;
23
23
}
···
36
36
37
37
let configPath = "";
38
38
39
-
const buildInfoPath = moonlightFS.join(
40
-
process.resourcesPath,
41
-
"build_info.json"
42
-
);
43
-
if (!(await moonlightFS.exists(buildInfoPath))) {
44
-
configPath = moonlightFS.join(dir, "desktop.json");
39
+
const buildInfoPath = moonlightNodeSandboxed.fs.join(process.resourcesPath, "build_info.json");
40
+
if (!(await moonlightNodeSandboxed.fs.exists(buildInfoPath))) {
41
+
configPath = moonlightNodeSandboxed.fs.join(dir, "desktop.json");
45
42
} else {
46
-
const buildInfo: BuildInfo = JSON.parse(
47
-
await moonlightFS.readFileString(buildInfoPath)
48
-
);
49
-
configPath = moonlightFS.join(dir, buildInfo.releaseChannel + ".json");
43
+
const buildInfo: BuildInfo = JSON.parse(await moonlightNodeSandboxed.fs.readFileString(buildInfoPath));
44
+
configPath = moonlightNodeSandboxed.fs.join(dir, buildInfo.releaseChannel + ".json");
50
45
}
51
46
52
47
return configPath;
···
55
50
async function getPathFromMoonlight(...names: string[]) {
56
51
const dir = await getMoonlightDir();
57
52
58
-
const target = moonlightFS.join(dir, ...names);
59
-
if (!(await moonlightFS.exists(target))) await moonlightFS.mkdir(target);
53
+
const target = moonlightNodeSandboxed.fs.join(dir, ...names);
54
+
if (!(await moonlightNodeSandboxed.fs.exists(target))) await moonlightNodeSandboxed.fs.mkdir(target);
60
55
61
56
return target;
62
57
}
···
66
61
}
67
62
68
63
export function getCoreExtensionsPath(): string {
69
-
return moonlightFS.join(__dirname, constants.coreExtensionsDir);
64
+
return moonlightNodeSandboxed.fs.join(__dirname, constants.coreExtensionsDir);
70
65
}
+4
-14
packages/core/src/util/dependency.ts
+4
-14
packages/core/src/util/dependency.ts
···
35
35
const fullDeps: Set<T> = new Set();
36
36
let failed = false;
37
37
38
-
// eslint-disable-next-line no-inner-declarations
39
38
function resolveDeps(id: T, root: boolean) {
40
39
if (id === item.id && !root) {
41
40
logger.warn(`Circular dependency detected: "${item.id}"`);
···
113
112
logger.trace("Enabled stage", itemsOrig);
114
113
const implicitlyEnabled: T[] = [];
115
114
116
-
// eslint-disable-next-line no-inner-declarations
117
115
function validateDeps(dep: Dependency<T, D>) {
118
116
if (getEnabled!(dep)) {
119
117
const deps = dependencyGraphOrig.get(dep.id)!;
···
122
120
validateDeps({ id, data });
123
121
}
124
122
} else {
125
-
const dependsOnMe = Array.from(dependencyGraphOrig.entries()).filter(
126
-
([, v]) => v?.has(dep.id)
127
-
);
123
+
const dependsOnMe = Array.from(dependencyGraphOrig.entries()).filter(([, v]) => v?.has(dep.id));
128
124
129
125
if (dependsOnMe.length > 0) {
130
126
logger.debug("Implicitly enabling dependency", dep.id);
···
134
130
}
135
131
136
132
for (const dep of itemsOrig) validateDeps(dep);
137
-
itemsOrig = itemsOrig.filter(
138
-
(x) => getEnabled(x) || implicitlyEnabled.includes(x.id)
139
-
);
133
+
itemsOrig = itemsOrig.filter((x) => getEnabled(x) || implicitlyEnabled.includes(x.id));
140
134
}
141
135
142
136
if (getIncompatible != null) {
···
176
170
dependencyGraph.set(item.id, new Set(dependencyGraph.get(item.id)));
177
171
}
178
172
179
-
while (
180
-
Array.from(dependencyGraph.values()).filter((x) => x != null).length > 0
181
-
) {
182
-
const noDependents = items.filter(
183
-
(e) => dependencyGraph.get(e.id)?.size === 0
184
-
);
173
+
while (Array.from(dependencyGraph.values()).filter((x) => x != null).length > 0) {
174
+
const noDependents = items.filter((e) => dependencyGraph.get(e.id)?.size === 0);
185
175
186
176
if (noDependents.length === 0) {
187
177
logger.warn("Stuck dependency graph detected", dependencyGraph);
+7
-27
packages/core/src/util/event.ts
+7
-27
packages/core/src/util/event.ts
···
9
9
const listeners = new Map<(data: EventData) => void, (e: Event) => void>();
10
10
11
11
return {
12
-
dispatchEvent: <Id extends keyof EventData>(
13
-
id: Id,
14
-
data: EventData[Id]
15
-
) => {
16
-
eventEmitter.dispatchEvent(
17
-
new CustomEvent(id as string, { detail: data })
18
-
);
12
+
dispatchEvent: <Id extends keyof EventData>(id: Id, data: EventData[Id]) => {
13
+
eventEmitter.dispatchEvent(new CustomEvent(id as string, { detail: data }));
19
14
},
20
15
21
-
addEventListener: <Id extends keyof EventData>(
22
-
id: Id,
23
-
cb: (data: EventData[Id]) => void
24
-
) => {
16
+
addEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
25
17
const untyped = cb as (data: EventData) => void;
26
18
if (listeners.has(untyped)) return;
27
19
···
34
26
eventEmitter.addEventListener(id as string, listener);
35
27
},
36
28
37
-
removeEventListener: <Id extends keyof EventData>(
38
-
id: Id,
39
-
cb: (data: EventData[Id]) => void
40
-
) => {
29
+
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
41
30
const untyped = cb as (data: EventData) => void;
42
31
const listener = listeners.get(untyped);
43
32
if (listener == null) return;
···
53
42
const listeners = new Map<(data: EventData) => void, (e: Event) => void>();
54
43
55
44
return {
56
-
dispatchEvent: <Id extends keyof EventData>(
57
-
id: Id,
58
-
data: EventData[Id]
59
-
) => {
45
+
dispatchEvent: <Id extends keyof EventData>(id: Id, data: EventData[Id]) => {
60
46
eventEmitter.emit(id as string, data);
61
47
},
62
48
63
-
addEventListener: <Id extends keyof EventData>(
64
-
id: Id,
65
-
cb: (data: EventData[Id]) => void
66
-
) => {
49
+
addEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
67
50
const untyped = cb as (data: EventData) => void;
68
51
if (listeners.has(untyped)) return;
69
52
···
76
59
eventEmitter.on(id as string, listener);
77
60
},
78
61
79
-
removeEventListener: <Id extends keyof EventData>(
80
-
id: Id,
81
-
cb: (data: EventData[Id]) => void
82
-
) => {
62
+
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
83
63
const untyped = cb as (data: EventData) => void;
84
64
const listener = listeners.get(untyped);
85
65
if (listener == null) return;
+3
-5
packages/core/src/util/import.ts
+3
-5
packages/core/src/util/import.ts
···
9
9
cemented if import is passed a string literal.
10
10
*/
11
11
12
-
const canRequire = ["path", "fs"] as const;
13
-
type CanRequire = (typeof canRequire)[number];
12
+
const _canRequire = ["path", "fs"] as const;
13
+
type CanRequire = (typeof _canRequire)[number];
14
14
15
15
type ImportTypes = {
16
16
path: typeof import("path");
17
17
fs: typeof import("fs");
18
18
};
19
19
20
-
export default function requireImport<T extends CanRequire>(
21
-
type: T
22
-
): Awaited<ImportTypes[T]> {
20
+
export default function requireImport<T extends CanRequire>(type: T): Awaited<ImportTypes[T]> {
23
21
return require(type);
24
22
}
+2
-8
packages/core/src/util/logger.ts
+2
-8
packages/core/src/util/logger.ts
···
50
50
if (maxLevel > level) return;
51
51
52
52
if (MOONLIGHT_WEB_PRELOAD || MOONLIGHT_BROWSER) {
53
-
args = [
54
-
`%c[${logLevel}]`,
55
-
`background-color: ${colors[level]}; color: #FFFFFF;`,
56
-
`[${this.name}]`,
57
-
...obj
58
-
];
53
+
args = [`%c[${logLevel}]`, `background-color: ${colors[level]}; color: #FFFFFF;`, `[${this.name}]`, ...obj];
59
54
} else {
60
55
args = [`[${logLevel}]`, `[${this.name}]`, ...obj];
61
56
}
···
87
82
88
83
export function initLogger(config: Config) {
89
84
if (config.loggerLevel != null) {
90
-
const enumValue =
91
-
LogLevel[config.loggerLevel.toUpperCase() as keyof typeof LogLevel];
85
+
const enumValue = LogLevel[config.loggerLevel.toUpperCase() as keyof typeof LogLevel];
92
86
if (enumValue != null) {
93
87
maxLevel = enumValue;
94
88
}
+30
packages/core/src/util/patch.ts
+30
packages/core/src/util/patch.ts
···
1
+
import { PatchReplace, PatchReplaceType } from "@moonlight-mod/types";
2
+
3
+
type SingleFind = string | RegExp;
4
+
type Find = SingleFind | SingleFind[];
5
+
6
+
export function processFind<T extends Find>(find: T): T {
7
+
if (Array.isArray(find)) {
8
+
return find.map(processFind) as T;
9
+
} else if (find instanceof RegExp) {
10
+
// Add support for \i to match rspack's minified names
11
+
return new RegExp(find.source.replace(/\\i/g, "[A-Za-z_$][\\w$]*"), find.flags) as T;
12
+
} else {
13
+
return find;
14
+
}
15
+
}
16
+
17
+
export function processReplace(replace: PatchReplace | PatchReplace[]) {
18
+
if (Array.isArray(replace)) {
19
+
replace.forEach(processReplace);
20
+
} else {
21
+
if (replace.type === undefined || replace.type === PatchReplaceType.Normal) {
22
+
replace.match = processFind(replace.match);
23
+
}
24
+
}
25
+
}
26
+
27
+
export function testFind(src: string, find: SingleFind) {
28
+
// indexOf is faster than includes by 0.25% lmao
29
+
return typeof find === "string" ? src.indexOf(find) !== -1 : find.test(src);
30
+
}
+4
-1
packages/core/tsconfig.json
+4
-1
packages/core/tsconfig.json
+9
-1
packages/core-extensions/package.json
+9
-1
packages/core-extensions/package.json
···
1
1
{
2
2
"name": "@moonlight-mod/core-extensions",
3
3
"private": true,
4
+
"engineStrict": true,
5
+
"engines": {
6
+
"node": ">=22",
7
+
"pnpm": ">=10",
8
+
"npm": "pnpm",
9
+
"yarn": "pnpm"
10
+
},
4
11
"dependencies": {
5
12
"@moonlight-mod/core": "workspace:*",
6
13
"@moonlight-mod/types": "workspace:*",
7
-
"nanotar": "^0.1.1"
14
+
"microdiff": "catalog:prod",
15
+
"nanotar": "catalog:prod"
8
16
}
9
17
}
+19
packages/core-extensions/src/appPanels/index.ts
+19
packages/core-extensions/src/appPanels/index.ts
···
1
+
import type { ExtensionWebpackModule, Patch } from "@moonlight-mod/types";
2
+
3
+
export const patches: Patch[] = [
4
+
{
5
+
find: 'setProperty("--custom-app-panels-height"',
6
+
replace: [
7
+
{
8
+
match: /\(0,.\.jsx\)\((.\..),{section:/,
9
+
replacement: (prev, el) => `...require("appPanels_appPanels").default.getPanels(${el}),${prev}`
10
+
}
11
+
]
12
+
}
13
+
];
14
+
15
+
export const webpackModules: Record<string, ExtensionWebpackModule> = {
16
+
appPanels: {
17
+
dependencies: [{ id: "react" }]
18
+
}
19
+
};
+11
packages/core-extensions/src/appPanels/manifest.json
+11
packages/core-extensions/src/appPanels/manifest.json
···
1
+
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
3
+
"id": "appPanels",
4
+
"apiLevel": 2,
5
+
"meta": {
6
+
"name": "App Panels",
7
+
"tagline": "An API for adding panels around the user/voice controls",
8
+
"authors": ["NotNite"],
9
+
"tags": ["library"]
10
+
}
11
+
}
+23
packages/core-extensions/src/appPanels/webpackModules/appPanels.ts
+23
packages/core-extensions/src/appPanels/webpackModules/appPanels.ts
···
1
+
import type { AppPanels as AppPanelsType } from "@moonlight-mod/types/coreExtensions/appPanels";
2
+
import React from "@moonlight-mod/wp/react";
3
+
4
+
const panels: Record<string, React.FC<any>> = {};
5
+
6
+
export const AppPanels: AppPanelsType = {
7
+
addPanel(section, element) {
8
+
panels[section] = element;
9
+
},
10
+
getPanels(panel) {
11
+
return Object.entries(panels).map(([section, element]) =>
12
+
React.createElement(
13
+
panel,
14
+
{
15
+
section
16
+
},
17
+
React.createElement(element)
18
+
)
19
+
);
20
+
}
21
+
};
22
+
23
+
export default AppPanels;
+85
packages/core-extensions/src/commands/index.ts
+85
packages/core-extensions/src/commands/index.ts
···
1
+
import { Patch, ExtensionWebpackModule } from "@moonlight-mod/types";
2
+
import { APPLICATION_ID } from "@moonlight-mod/types/coreExtensions/commands";
3
+
4
+
export const patches: Patch[] = [
5
+
{
6
+
find: ".fI5MTU)", // COMMAND_SECTION_BUILT_IN_NAME
7
+
replace: [
8
+
// inject commands
9
+
{
10
+
match: /return (\i)\.filter/,
11
+
replacement: (orig, commands) =>
12
+
`return [...${commands},...require("commands_commands").default._getCommands()].filter`
13
+
},
14
+
15
+
// section
16
+
{
17
+
match: /(?<=\i={)(?=\[\i\.\i\.BUILT_IN]:{id:\i\.\i\.BUILT_IN,type:(\i.\i\.BUILT_IN))/,
18
+
replacement: (_, type) =>
19
+
`"${APPLICATION_ID}":{id:"${APPLICATION_ID}",type:${type},get name(){return "moonlight"}},`
20
+
}
21
+
]
22
+
},
23
+
24
+
// index our section
25
+
{
26
+
find: '"ApplicationCommandIndexStore"',
27
+
replace: {
28
+
match: /(?<=let \i=(\i)\((\i\.\i)\[\i\.\i\.BUILT_IN\],(\i),!0,!0,(\i)\);)null!=(\i)&&(\i)\.push\(\i\)/,
29
+
replacement: (_, createSection, sections, deny, props, section, commands) =>
30
+
`null!=${section}&&(${section}.data=${section}.data.filter(c=>c.applicationId=="-1"));
31
+
null!=${section}&&${commands}.push(${section});
32
+
const moonlightCommands=${createSection}(${sections}["${APPLICATION_ID}"],${deny},!0,!0,${props});
33
+
null!=moonlightCommands&&(moonlightCommands.data=moonlightCommands.data.filter(c=>c.applicationId=="${APPLICATION_ID}"));
34
+
null!=moonlightCommands&&${commands}.push(moonlightCommands)`
35
+
}
36
+
},
37
+
38
+
// grab legacy commands (needed for adding actions that act like sed/plus reacting)
39
+
{
40
+
find: "={tts:{action:",
41
+
replace: {
42
+
match: /Object\.setPrototypeOf\((\i),null\)/,
43
+
replacement: (_, legacyCommands) => `require("commands_commands")._getLegacyCommands(${legacyCommands})`
44
+
}
45
+
},
46
+
47
+
// add icon
48
+
{
49
+
find: ",hasSpaceTerminator:",
50
+
replace: {
51
+
match: /(\i)\.type===/,
52
+
replacement: (orig, section) => `${section}.id!=="${APPLICATION_ID}"&&${orig}`
53
+
}
54
+
},
55
+
{
56
+
find: ".icon,bot:null==",
57
+
replace: {
58
+
match: /(\.useMemo\(\(\)=>{(var \i;)?)((return |if\()(\i)\.type)/,
59
+
replacement: (_, before, beforeVar, after, afterIf, section) => `${before}
60
+
if (${section}.id==="${APPLICATION_ID}") return "https://moonlight-mod.github.io/favicon.png";
61
+
${after}`
62
+
}
63
+
},
64
+
// fix icon sizing because they expect built in to be 24 and others to be 32
65
+
{
66
+
find: ".builtInSeparator}):null]",
67
+
replace: {
68
+
match: /(\i)\.type===\i\.\i\.BUILT_IN/,
69
+
replacement: (orig, section) => `${section}.id!=="${APPLICATION_ID}"&&${orig}`
70
+
}
71
+
},
72
+
73
+
// tell it this app id is authorized
74
+
{
75
+
find: /let{customInstallUrl:\i,installParams:\i,integrationTypesConfig:\i}/,
76
+
replace: {
77
+
match: /\|\|(\i)===\i\.\i\.BUILT_IN/,
78
+
replacement: (orig, id) => `${orig}||${id}==="${APPLICATION_ID}"`
79
+
}
80
+
}
81
+
];
82
+
83
+
export const webpackModules: Record<string, ExtensionWebpackModule> = {
84
+
commands: {}
85
+
};
+11
packages/core-extensions/src/commands/manifest.json
+11
packages/core-extensions/src/commands/manifest.json
+71
packages/core-extensions/src/commands/webpackModules/commands.ts
+71
packages/core-extensions/src/commands/webpackModules/commands.ts
···
1
+
import {
2
+
APPLICATION_ID,
3
+
Commands,
4
+
LegacyCommand,
5
+
RegisteredCommand
6
+
} from "@moonlight-mod/types/coreExtensions/commands";
7
+
8
+
type LegacyCommands = Record<string, LegacyCommand>;
9
+
let legacyCommands: LegacyCommands | undefined;
10
+
let queuedLegacyCommands: Record<string, LegacyCommand> | null = {};
11
+
12
+
const registeredCommands: RegisteredCommand[] = [];
13
+
14
+
export function _getLegacyCommands(commands: LegacyCommands) {
15
+
legacyCommands = commands;
16
+
if (queuedLegacyCommands != null) {
17
+
for (const [key, value] of Object.entries(queuedLegacyCommands)) {
18
+
legacyCommands[key] = value;
19
+
}
20
+
queuedLegacyCommands = null;
21
+
}
22
+
}
23
+
24
+
export const commands: Commands = {
25
+
registerCommand(command) {
26
+
const registered: RegisteredCommand = {
27
+
...command,
28
+
untranslatedName: command.id,
29
+
displayName: command.id,
30
+
applicationId: APPLICATION_ID,
31
+
untranslatedDescription: command.description,
32
+
displayDescription: command.description,
33
+
options: command.options?.map((o) => ({
34
+
...o,
35
+
displayName: o.name,
36
+
displayDescription: o.description
37
+
}))
38
+
};
39
+
registeredCommands.push(registered);
40
+
},
41
+
42
+
registerLegacyCommand(id, command) {
43
+
if (command.match) {
44
+
if (command.match instanceof RegExp) {
45
+
command.match = this.anyScopeRegex(command.match);
46
+
} else if (command.match.regex && typeof command.match !== "function") {
47
+
command.match = this.anyScopeRegex(command.match.regex);
48
+
}
49
+
}
50
+
51
+
if (!legacyCommands) {
52
+
queuedLegacyCommands![id] = command;
53
+
} else {
54
+
legacyCommands[id] = command;
55
+
}
56
+
},
57
+
58
+
anyScopeRegex(regex) {
59
+
const out = function (str: string) {
60
+
return regex.exec(str);
61
+
};
62
+
out.regex = regex;
63
+
return out;
64
+
},
65
+
66
+
_getCommands() {
67
+
return [...registeredCommands];
68
+
}
69
+
};
70
+
71
+
export default commands;
+7
-5
packages/core-extensions/src/common/index.ts
+7
-5
packages/core-extensions/src/common/index.ts
···
2
2
3
3
export const webpackModules: ExtensionWebExports["webpackModules"] = {
4
4
stores: {
5
-
dependencies: [
6
-
{
7
-
id: "discord/packages/flux"
8
-
}
9
-
]
5
+
dependencies: [{ id: "discord/packages/flux" }]
6
+
},
7
+
ErrorBoundary: {
8
+
dependencies: [{ id: "react" }]
9
+
},
10
+
icons: {
11
+
dependencies: [{ id: "react" }, { id: "discord/components/common/index" }]
10
12
}
11
13
};
+2
-1
packages/core-extensions/src/common/manifest.json
+2
-1
packages/core-extensions/src/common/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "common",
3
4
"apiLevel": 2,
4
5
"meta": {
5
6
"name": "Common",
6
-
"tagline": "A *lot* of common clientmodding utilities from the Discord client",
7
+
"tagline": "Common client modding utilities for the Discord client",
7
8
"authors": ["Cynosphere", "NotNite"],
8
9
"tags": ["library"]
9
10
},
+27
packages/core-extensions/src/common/style.css
+27
packages/core-extensions/src/common/style.css
···
1
+
.moonlight-error-boundary {
2
+
margin: 0 0 15px;
3
+
padding: 10px;
4
+
border-radius: 5px;
5
+
font-size: 1rem;
6
+
font-weight: 300;
7
+
line-height: 22px;
8
+
color: var(--text-normal, white);
9
+
background: hsl(var(--red-400-hsl) / 0.1);
10
+
border: 2px solid hsl(var(--red-400-hsl) / 0.5);
11
+
12
+
.theme-light & {
13
+
color: var(--text-normal, black) !important;
14
+
}
15
+
16
+
& > h3 {
17
+
margin-bottom: 0.25rem;
18
+
}
19
+
20
+
& > .hljs {
21
+
background: var(--background-secondary);
22
+
border: 1px solid var(--background-tertiary);
23
+
white-space: pre-wrap;
24
+
font-family: var(--font-code);
25
+
user-select: text;
26
+
}
27
+
}
+47
packages/core-extensions/src/common/webpackModules/ErrorBoundary.tsx
+47
packages/core-extensions/src/common/webpackModules/ErrorBoundary.tsx
···
1
+
import React from "@moonlight-mod/wp/react";
2
+
import { ErrorBoundaryProps, ErrorBoundaryState } from "@moonlight-mod/types/coreExtensions/common";
3
+
4
+
const logger = moonlight.getLogger("ErrorBoundary");
5
+
6
+
class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
7
+
constructor(props: ErrorBoundaryProps) {
8
+
super(props);
9
+
this.state = {
10
+
errored: false,
11
+
error: undefined,
12
+
componentStack: undefined
13
+
};
14
+
}
15
+
16
+
static getDerivedStateFromError(error: Error) {
17
+
return {
18
+
errored: true,
19
+
error
20
+
};
21
+
}
22
+
23
+
componentDidCatch(error: Error, { componentStack }: { componentStack: string }) {
24
+
logger.error(`${error}\n\nComponent stack:\n${componentStack}`);
25
+
this.setState({ error, componentStack });
26
+
}
27
+
28
+
render() {
29
+
const { noop, fallback: FallbackComponent, children, message } = this.props;
30
+
const { errored, error, componentStack } = this.state;
31
+
32
+
if (FallbackComponent) return <FallbackComponent children={children} {...this.state} />;
33
+
34
+
if (errored) {
35
+
return noop ? null : (
36
+
<div className={`moonlight-error-boundary`}>
37
+
<h3>{message ?? "An error occurred rendering this component:"}</h3>
38
+
<code className="hljs">{`${error}\n\nComponent stack:\n${componentStack}`}</code>
39
+
</div>
40
+
);
41
+
}
42
+
43
+
return children;
44
+
}
45
+
}
46
+
47
+
export default ErrorBoundary;
+31
packages/core-extensions/src/common/webpackModules/icons.ts
+31
packages/core-extensions/src/common/webpackModules/icons.ts
···
1
+
import { Icons, IconSize } from "@moonlight-mod/types/coreExtensions/common";
2
+
import { tokens } from "@moonlight-mod/wp/discord/components/common/index";
3
+
4
+
// This is defined in a Webpack module but we copy it here to be less breakage-prone
5
+
const sizes: Partial<Record<IconSize, number>> = {
6
+
xxs: 12,
7
+
xs: 16,
8
+
sm: 18,
9
+
md: 24,
10
+
lg: 32,
11
+
refresh_sm: 20
12
+
};
13
+
14
+
export const icons: Icons = {
15
+
parseProps(props) {
16
+
// NOTE: var() fallback is non-standard behavior, just for safety reasons
17
+
const color = props?.color ?? tokens?.colors?.["INTERACTIVE_NORMAL"] ?? "var(--interactive-normal)";
18
+
19
+
const size = sizes[props?.size ?? "md"];
20
+
21
+
return {
22
+
// note: this default size is also non-standard behavior, just for safety
23
+
width: size ?? props?.width ?? sizes.md!,
24
+
height: size ?? props?.width ?? sizes.md!,
25
+
26
+
fill: typeof color === "string" ? color : color.css,
27
+
className: props?.colorClass ?? ""
28
+
};
29
+
}
30
+
};
31
+
export default icons;
+84
packages/core-extensions/src/componentEditor/index.ts
+84
packages/core-extensions/src/componentEditor/index.ts
···
1
+
import { ExtensionWebpackModule, Patch } from "@moonlight-mod/types";
2
+
3
+
export const patches: Patch[] = [
4
+
// dm list
5
+
{
6
+
find: ".interactiveSystemDM]:",
7
+
replace: [
8
+
{
9
+
match: /decorators:(\i\.isSystemDM\(\)\?\(0,\i\.jsx\)\(.+?verified:!0}\):null)/,
10
+
replacement: (_, decorators) =>
11
+
`decorators:require("componentEditor_dmList").default._patchDecorators([${decorators}],arguments[0])`
12
+
},
13
+
{
14
+
match: /(?<=selected:\i,)children:\[/,
15
+
replacement: 'children:require("componentEditor_dmList").default._patchItems(['
16
+
},
17
+
{
18
+
match: /(?<=(onMouseDown|nameplate):\i}\))]/,
19
+
replacement: "],arguments[0])"
20
+
}
21
+
],
22
+
hardFail: true
23
+
},
24
+
25
+
// member list
26
+
{
27
+
find: ".lostPermission",
28
+
replace: [
29
+
{
30
+
match:
31
+
/(?<=\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[\(0,\i\.jsx\)\(\i,{user:\i}\),.+?onClickPremiumGuildIcon:\i}\)])/,
32
+
replacement: (_, decorators) =>
33
+
`children:require("componentEditor_memberList").default._patchDecorators(${decorators},arguments[0])`
34
+
},
35
+
{
36
+
match: /name:null==\i\?\(0,\i\.jsx\)\("span"/,
37
+
replacement: (orig: string) =>
38
+
`children:require("componentEditor_memberList").default._patchItems([],arguments[0]),${orig}`
39
+
}
40
+
]
41
+
},
42
+
43
+
// messages
44
+
{
45
+
find: '},"new-member")),',
46
+
replace: [
47
+
{
48
+
match: /(?<=\.BADGES](=|:))(\i)(;|})/,
49
+
replacement: (_, leading, badges, trailing) =>
50
+
`require("componentEditor_messages").default._patchUsernameBadges(${badges},arguments[0])${trailing}`
51
+
},
52
+
{
53
+
match: /(?<=className:\i,)badges:(\i)/,
54
+
replacement: (_, badges) =>
55
+
`badges:require("componentEditor_messages").default._patchBadges(${badges},arguments[0])`
56
+
},
57
+
{
58
+
match: /(?<=username:\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[.+?])}\),usernameSpanId:/,
59
+
replacement: (_, elements) =>
60
+
`children:require("componentEditor_messages").default._patchUsername(${elements},arguments[0])}),usernameSpanId:`
61
+
}
62
+
]
63
+
},
64
+
{
65
+
find: '.provider&&"Discord"===',
66
+
replace: {
67
+
match: /(?<=\.container\),)children:(\[.+?this\.renderSuppressConfirmModal\(\),.+?\])}\)/,
68
+
replacement: (_, elements) =>
69
+
`children:require("componentEditor_messages").default._patchAccessories(${elements},this.props)})`
70
+
}
71
+
}
72
+
];
73
+
74
+
export const webpackModules: Record<string, ExtensionWebpackModule> = {
75
+
dmList: {
76
+
dependencies: [{ id: "react" }]
77
+
},
78
+
memberList: {
79
+
dependencies: [{ id: "react" }]
80
+
},
81
+
messages: {
82
+
dependencies: [{ id: "react" }]
83
+
}
84
+
};
+11
packages/core-extensions/src/componentEditor/manifest.json
+11
packages/core-extensions/src/componentEditor/manifest.json
···
1
+
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
3
+
"id": "componentEditor",
4
+
"apiLevel": 2,
5
+
"meta": {
6
+
"name": "Component Editor",
7
+
"tagline": "A library to add to commonly patched components",
8
+
"authors": ["Cynosphere"],
9
+
"tags": ["library"]
10
+
}
11
+
}
+61
packages/core-extensions/src/componentEditor/webpackModules/dmList.tsx
+61
packages/core-extensions/src/componentEditor/webpackModules/dmList.tsx
···
1
+
import {
2
+
DMList,
3
+
DMListItem,
4
+
DMListDecorator,
5
+
DMListAnchorIndicies,
6
+
DMListDecoratorAnchorIndicies
7
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
8
+
import React from "@moonlight-mod/wp/react";
9
+
10
+
const items: Record<string, DMListItem> = {};
11
+
const decorators: Record<string, DMListDecorator> = {};
12
+
13
+
function addEntries(
14
+
elements: React.ReactNode[],
15
+
entries: Record<string, DMListItem | DMListDecorator>,
16
+
indicies: Partial<Record<keyof typeof DMListAnchorIndicies | keyof typeof DMListDecoratorAnchorIndicies, number>>,
17
+
props: any
18
+
) {
19
+
const originalElements = [...elements];
20
+
for (const [id, entry] of Object.entries(entries)) {
21
+
const component = <entry.component {...props} key={id} />;
22
+
23
+
if (entry.anchor === undefined) {
24
+
if (entry.before) {
25
+
elements.splice(0, 0, component);
26
+
} else {
27
+
elements.push(component);
28
+
}
29
+
} else {
30
+
const index = elements.indexOf(originalElements[indicies[entry.anchor]!]);
31
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
32
+
}
33
+
}
34
+
}
35
+
36
+
export const dmList: DMList = {
37
+
addItem(id, component, anchor, before = false) {
38
+
items[id] = {
39
+
component,
40
+
anchor,
41
+
before
42
+
};
43
+
},
44
+
addDecorator(id, component, anchor, before = false) {
45
+
decorators[id] = {
46
+
component,
47
+
anchor,
48
+
before
49
+
};
50
+
},
51
+
_patchItems(elements, props) {
52
+
addEntries(elements, items, DMListAnchorIndicies, props);
53
+
return elements;
54
+
},
55
+
_patchDecorators(elements, props) {
56
+
addEntries(elements, decorators, DMListDecoratorAnchorIndicies, props);
57
+
return elements;
58
+
}
59
+
};
60
+
61
+
export default dmList;
+50
packages/core-extensions/src/componentEditor/webpackModules/memberList.tsx
+50
packages/core-extensions/src/componentEditor/webpackModules/memberList.tsx
···
1
+
import {
2
+
MemberList,
3
+
MemberListDecorator,
4
+
MemberListDecoratorAnchorIndicies
5
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
6
+
import React from "@moonlight-mod/wp/react";
7
+
8
+
const items: Record<string, React.FC<any>> = {};
9
+
const decorators: Record<string, MemberListDecorator> = {};
10
+
11
+
export const memberList: MemberList = {
12
+
addItem(id, component) {
13
+
items[id] = component;
14
+
},
15
+
addDecorator(id, component, anchor, before = false) {
16
+
decorators[id] = {
17
+
component,
18
+
anchor,
19
+
before
20
+
};
21
+
},
22
+
_patchItems(elements, props) {
23
+
for (const [id, Component] of Object.entries(items)) {
24
+
elements.push(<Component {...props} key={id} />);
25
+
}
26
+
27
+
return elements;
28
+
},
29
+
_patchDecorators(elements, props) {
30
+
const originalElements = [...elements];
31
+
for (const [id, entry] of Object.entries(decorators)) {
32
+
const component = <entry.component {...props} key={id} />;
33
+
34
+
if (entry.anchor === undefined) {
35
+
if (entry.before) {
36
+
elements.splice(0, 0, component);
37
+
} else {
38
+
elements.push(component);
39
+
}
40
+
} else {
41
+
const index = elements.indexOf(originalElements[MemberListDecoratorAnchorIndicies[entry.anchor]!]);
42
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
43
+
}
44
+
}
45
+
46
+
return elements;
47
+
}
48
+
};
49
+
50
+
export default memberList;
+97
packages/core-extensions/src/componentEditor/webpackModules/messages.tsx
+97
packages/core-extensions/src/componentEditor/webpackModules/messages.tsx
···
1
+
import {
2
+
MessageBadge,
3
+
MessageBadgeIndicies,
4
+
Messages,
5
+
MessageUsername,
6
+
MessageUsernameBadge,
7
+
MessageUsernameBadgeIndicies,
8
+
MessageUsernameIndicies
9
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
10
+
import React from "@moonlight-mod/wp/react";
11
+
12
+
const username: Record<string, MessageUsername> = {};
13
+
const usernameBadges: Record<string, MessageUsernameBadge> = {};
14
+
const badges: Record<string, MessageBadge> = {};
15
+
const accessories: Record<string, React.FC<any>> = {};
16
+
17
+
function addEntries(
18
+
elements: React.ReactNode[],
19
+
entries: Record<string, MessageUsername | MessageUsernameBadge | MessageBadge>,
20
+
indicies: Partial<
21
+
Record<
22
+
| keyof typeof MessageUsernameIndicies
23
+
| keyof typeof MessageUsernameBadgeIndicies
24
+
| keyof typeof MessageBadgeIndicies,
25
+
number
26
+
>
27
+
>,
28
+
props: any
29
+
) {
30
+
const originalElements = [...elements];
31
+
for (const [id, entry] of Object.entries(entries)) {
32
+
const component = <entry.component {...props} key={id} />;
33
+
34
+
if (entry.anchor === undefined) {
35
+
if (entry.before) {
36
+
elements.splice(0, 0, component);
37
+
} else {
38
+
elements.push(component);
39
+
}
40
+
} else {
41
+
const index = elements.indexOf(originalElements[indicies[entry.anchor]!]);
42
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
43
+
}
44
+
}
45
+
}
46
+
47
+
function addComponents(elements: React.ReactNode[], components: Record<string, React.FC<any>>, props: any) {
48
+
for (const [id, Component] of Object.entries(components)) {
49
+
const component = <Component {...props} key={id} />;
50
+
elements.push(component);
51
+
}
52
+
}
53
+
54
+
export const messages: Messages = {
55
+
addToUsername(id, component, anchor, before = false) {
56
+
username[id] = {
57
+
component,
58
+
anchor,
59
+
before
60
+
};
61
+
},
62
+
addUsernameBadge(id, component, anchor, before = false) {
63
+
usernameBadges[id] = {
64
+
component,
65
+
anchor,
66
+
before
67
+
};
68
+
},
69
+
addBadge(id, component, anchor, before = false) {
70
+
badges[id] = {
71
+
component,
72
+
anchor,
73
+
before
74
+
};
75
+
},
76
+
addAccessory(id, component) {
77
+
accessories[id] = component;
78
+
},
79
+
_patchUsername(elements, props) {
80
+
addEntries(elements, username, MessageUsernameIndicies, props);
81
+
return elements;
82
+
},
83
+
_patchUsernameBadges(elements, props) {
84
+
addEntries(elements, usernameBadges, MessageUsernameBadgeIndicies, props);
85
+
return elements;
86
+
},
87
+
_patchBadges(elements, props) {
88
+
addEntries(elements, badges, MessageBadgeIndicies, props);
89
+
return elements;
90
+
},
91
+
_patchAccessories(elements, props) {
92
+
addComponents(elements, accessories, props);
93
+
return elements;
94
+
}
95
+
};
96
+
97
+
export default messages;
+5
-14
packages/core-extensions/src/contextMenu/index.tsx
+5
-14
packages/core-extensions/src/contextMenu/index.tsx
···
5
5
find: "Menu API only allows Items and groups of Items as children.",
6
6
replace: [
7
7
{
8
-
match:
9
-
/(?<=let{navId[^}]+?}=(.),(.)=function .\(.\){.+(?=,.=function))/,
10
-
replacement: (_, props, items) =>
11
-
`,__contextMenu=!${props}.__contextMenu_evilMenu&&require("contextMenu_contextMenu")._patchMenu(${props}, ${items})`
8
+
match: /(?<=let{navId[^}]+?}=(.),.=).+?(?=,)/,
9
+
replacement: (items, props) => `require("contextMenu_contextMenu")._patchMenu(${props},${items})`
12
10
}
13
11
]
14
12
},
···
17
15
replace: [
18
16
{
19
17
match: /(?<=let\{[^}]+?\}=.;return ).\({[^}]+?}\)/,
20
-
replacement: (render) =>
21
-
`require("contextMenu_contextMenu")._saveProps(this,${render})`
18
+
replacement: (render) => `require("contextMenu_contextMenu")._saveProps(this,${render})`
22
19
}
23
20
]
24
21
}
···
26
23
27
24
export const webpackModules: Record<string, ExtensionWebpackModule> = {
28
25
contextMenu: {
29
-
dependencies: [
30
-
{ ext: "spacepack", id: "spacepack" },
31
-
"Menu API only allows Items and groups of Items as children."
32
-
]
26
+
dependencies: [{ ext: "spacepack", id: "spacepack" }, "Menu API only allows Items and groups of Items as children."]
33
27
},
34
28
evilMenu: {
35
-
dependencies: [
36
-
{ ext: "spacepack", id: "spacepack" },
37
-
"Menu API only allows Items and groups of Items as children."
38
-
]
29
+
dependencies: [{ ext: "spacepack", id: "spacepack" }, "Menu API only allows Items and groups of Items as children."]
39
30
}
40
31
};
+1
packages/core-extensions/src/contextMenu/manifest.json
+1
packages/core-extensions/src/contextMenu/manifest.json
+32
-31
packages/core-extensions/src/contextMenu/webpackModules/contextMenu.ts
+32
-31
packages/core-extensions/src/contextMenu/webpackModules/contextMenu.ts
···
1
-
import {
2
-
InternalItem,
3
-
MenuElement,
4
-
MenuProps
5
-
} from "@moonlight-mod/types/coreExtensions/contextMenu";
1
+
import { InternalItem, Menu, MenuElement } from "@moonlight-mod/types/coreExtensions/contextMenu";
6
2
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
7
3
import parser from "@moonlight-mod/wp/contextMenu_evilMenu";
8
4
5
+
// NOTE: We originally had item as a function that returned this, but it didn't
6
+
// quite know how to work out the type and thought it was a JSX element (it
7
+
// *technically* was). This has less type safety, but a @ts-expect-error has
8
+
// zero, so it's better than nothing.
9
+
type ReturnType = MenuElement | MenuElement[];
10
+
9
11
type Patch = {
10
12
navId: string;
11
-
item: (
12
-
props: any
13
-
) =>
14
-
| React.ReactComponentElement<MenuElement>
15
-
| React.ReactComponentElement<MenuElement>[];
16
-
anchorId: string;
13
+
item: React.FC<any>;
14
+
anchor: string | RegExp;
17
15
before: boolean;
18
16
};
19
17
20
-
export function addItem<T>(
21
-
navId: string,
22
-
item: (
23
-
props: T
24
-
) =>
25
-
| React.ReactComponentElement<MenuElement>
26
-
| React.ReactComponentElement<MenuElement>[],
27
-
anchorId: string,
28
-
before = false
29
-
) {
30
-
patches.push({ navId, item, anchorId, before });
18
+
function addItem<T = any>(navId: string, item: React.FC<T>, anchor: string | RegExp, before = false) {
19
+
if (anchor instanceof RegExp && anchor.flags.includes("g"))
20
+
throw new Error("anchor regular expression should not be global");
21
+
patches.push({ navId, item, anchor, before });
31
22
}
32
23
33
-
export const patches: Patch[] = [];
34
-
export function _patchMenu(props: MenuProps, items: InternalItem[]) {
24
+
const patches: Patch[] = [];
25
+
function _patchMenu(props: React.ComponentProps<Menu>, items: InternalItem[]) {
35
26
const matches = patches.filter((p) => p.navId === props.navId);
36
-
if (!matches.length) return;
27
+
if (!matches.length) return items;
37
28
38
29
for (const patch of matches) {
39
-
const idx = items.findIndex((i) => i.key === patch.anchorId);
30
+
const idx = items.findIndex((i) =>
31
+
typeof patch.anchor === "string" ? i.key === patch.anchor : patch.anchor.test(i.key!)
32
+
);
40
33
if (idx === -1) continue;
41
-
items.splice(idx + 1 - +patch.before, 0, ...parser(patch.item(menuProps)));
34
+
items.splice(idx + 1 - +patch.before, 0, ...parser(patch.item(menuProps) as ReturnType));
42
35
}
36
+
37
+
return items;
43
38
}
44
39
45
40
let menuProps: any;
46
-
export function _saveProps(self: any, el: any) {
41
+
function _saveProps(self: any, el: any) {
47
42
menuProps = el.props;
48
43
49
44
const original = self.props.closeContextMenu;
···
55
50
return el;
56
51
}
57
52
53
+
module.exports = {
54
+
patches,
55
+
addItem,
56
+
_patchMenu,
57
+
_saveProps
58
+
};
59
+
58
60
// Unmangle Menu elements
61
+
// spacepack.require.m[moonlight.moonmap.modules["discord/modules/menus/web/Menu"]].toString();
59
62
const code =
60
63
spacepack.require.m[
61
-
spacepack.findByCode(
62
-
"Menu API only allows Items and groups of Items as children."
63
-
)[0].id
64
+
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
64
65
].toString();
65
66
66
67
let MangledMenu;
+11
-21
packages/core-extensions/src/contextMenu/webpackModules/evilMenu.ts
+11
-21
packages/core-extensions/src/contextMenu/webpackModules/evilMenu.ts
···
1
1
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
2
2
3
+
// spacepack.require.m[moonlight.moonmap.modules["discord/modules/menus/web/Menu"]].toString();
3
4
let code =
4
5
spacepack.require.m[
5
-
spacepack.findByCode(
6
-
"Menu API only allows Items and groups of Items as children."
7
-
)[0].id
6
+
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
8
7
].toString();
9
-
code = code.replace(/,.=(?=function .\(.\){.+?,.=function)/, ";return ");
10
-
code = code.replace(/,(?=__contextMenu)/, ";let ");
11
-
const mod = new Function(
12
-
"module",
13
-
"exports",
14
-
"require",
15
-
`(${code}).apply(this, arguments)`
16
-
);
8
+
9
+
const parserSym = code.match(/(?<=_patchMenu\(.,).+?(?=\()/)![0];
10
+
11
+
code = code.replace(/{(.):\(\)=>./, (orig, e) => `{${e}:()=>${parserSym}`);
12
+
const mod = new Function("module", "exports", "require", `(${code}).apply(this, arguments)`);
13
+
17
14
const exp: any = {};
18
15
mod({}, exp, require);
19
-
const Menu = spacepack.findFunctionByStrings(
20
-
exp,
21
-
"Menu API only allows Items and groups of Items as children."
22
-
)!;
23
-
module.exports = (el: any) => {
24
-
return Menu({
25
-
children: el,
26
-
__contextMenu_evilMenu: true
27
-
});
28
-
};
16
+
17
+
const parser = spacepack.findFunctionByStrings(exp, "Menu API only allows Items and groups of Items as children.")!;
18
+
module.exports = parser;
+19
packages/core-extensions/src/devToolsExtensions/host.ts
+19
packages/core-extensions/src/devToolsExtensions/host.ts
···
1
+
import { app, session } from "electron";
2
+
import { resolve } from "node:path";
3
+
import Logger from "@moonlight-mod/core/util/logger";
4
+
5
+
const logger = new Logger("DevTools Extensions");
6
+
7
+
app.whenReady().then(async () => {
8
+
const paths = moonlightHost.getConfigOption<string[]>("devToolsExtensions", "paths") ?? [];
9
+
10
+
for (const path of paths) {
11
+
const resolved = resolve(path);
12
+
13
+
try {
14
+
await session.defaultSession.loadExtension(resolved);
15
+
} catch (err) {
16
+
logger.error(`Failed to load an extension in "${resolved}":`, err);
17
+
}
18
+
}
19
+
});
+22
packages/core-extensions/src/devToolsExtensions/manifest.json
+22
packages/core-extensions/src/devToolsExtensions/manifest.json
···
1
+
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
3
+
"id": "devToolsExtensions",
4
+
"meta": {
5
+
"name": "DevTools Extensions",
6
+
"tagline": "Loads Chrome extensions into Electron DevTools",
7
+
"authors": [
8
+
"Cynosphere"
9
+
],
10
+
"tags": [
11
+
"development"
12
+
]
13
+
},
14
+
"settings": {
15
+
"paths": {
16
+
"advice": "restart",
17
+
"displayName": "Extension Paths",
18
+
"type": "list"
19
+
}
20
+
},
21
+
"apiLevel": 2
22
+
}
+4
-8
packages/core-extensions/src/disableSentry/host.ts
+4
-8
packages/core-extensions/src/disableSentry/host.ts
···
5
5
6
6
if (moonlightHost.asarPath !== "moonlightDesktop") {
7
7
try {
8
-
const hostSentryPath = require.resolve(
9
-
join(moonlightHost.asarPath, "node_modules", "@sentry", "electron")
10
-
);
11
-
require.cache[hostSentryPath] = new Module(
12
-
hostSentryPath,
13
-
require.cache[require.resolve(moonlightHost.asarPath)]
14
-
);
8
+
const hostSentryPath = require.resolve(join(moonlightHost.asarPath, "node_modules", "@sentry", "electron"));
9
+
require.cache[hostSentryPath] = new Module(hostSentryPath, require.cache[require.resolve(moonlightHost.asarPath)]);
15
10
require.cache[hostSentryPath]!.exports = {
16
11
init: () => {},
17
12
captureException: () => {},
18
13
setTag: () => {},
19
-
setUser: () => {}
14
+
setUser: () => {},
15
+
captureMessage: () => {}
20
16
};
21
17
logger.debug("Stubbed Sentry host side!");
22
18
} catch (err) {
+2
-2
packages/core-extensions/src/disableSentry/index.ts
+2
-2
packages/core-extensions/src/disableSentry/index.ts
+5
-1
packages/core-extensions/src/disableSentry/manifest.json
+5
-1
packages/core-extensions/src/disableSentry/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "disableSentry",
3
4
"apiLevel": 2,
4
5
"meta": {
···
11
12
"https://*.sentry.io/*",
12
13
"https://*.discord.com/error-reporting-proxy/*",
13
14
"https://discord.com/assets/sentry.*.js",
14
-
"https://*.discord.com/assets/sentry.*.js"
15
+
"https://*.discord.com/assets/sentry.*.js",
16
+
"https://*.discordapp.com/error-reporting-proxy/*",
17
+
"https://discordapp.com/assets/sentry.*.js",
18
+
"https://*.discordapp.com/assets/sentry.*.js"
15
19
]
16
20
}
+13
-19
packages/core-extensions/src/disableSentry/node.ts
+13
-19
packages/core-extensions/src/disableSentry/node.ts
···
5
5
6
6
const logger = moonlightNode.getLogger("disableSentry");
7
7
8
-
if (!ipcRenderer.sendSync(constants.ipcGetIsMoonlightDesktop)) {
9
-
const preloadPath = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
10
-
try {
11
-
const sentryPath = require.resolve(
12
-
resolve(preloadPath, "..", "node_modules", "@sentry", "electron")
13
-
);
14
-
require.cache[sentryPath] = new Module(
15
-
sentryPath,
16
-
require.cache[require.resolve(preloadPath)]
17
-
);
18
-
require.cache[sentryPath]!.exports = {
19
-
init: () => {},
20
-
setTag: () => {},
21
-
setUser: () => {}
22
-
};
23
-
logger.debug("Stubbed Sentry node side!");
24
-
} catch (err) {
25
-
logger.error("Failed to stub Sentry:", err);
26
-
}
8
+
const preloadPath = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
9
+
try {
10
+
const sentryPath = require.resolve(resolve(preloadPath, "..", "node_modules", "@sentry", "electron"));
11
+
require.cache[sentryPath] = new Module(sentryPath, require.cache[require.resolve(preloadPath)]);
12
+
require.cache[sentryPath]!.exports = {
13
+
init: () => {},
14
+
setTag: () => {},
15
+
setUser: () => {},
16
+
captureMessage: () => {}
17
+
};
18
+
logger.debug("Stubbed Sentry node side!");
19
+
} catch (err) {
20
+
logger.error("Failed to stub Sentry:", err);
27
21
}
+1
-2
packages/core-extensions/src/disableSentry/webpackModules/stub.ts
+1
-2
packages/core-extensions/src/disableSentry/webpackModules/stub.ts
···
23
23
throw Error("crash");
24
24
};
25
25
} else if (keys.includes(prop.toString())) {
26
-
return (...args: any[]) =>
27
-
logger.debug(`Sentry calling "${prop.toString()}":`, ...args);
26
+
return (...args: any[]) => logger.debug(`Sentry calling "${prop.toString()}":`, ...args);
28
27
} else {
29
28
return undefined;
30
29
}
+39
-2
packages/core-extensions/src/experiments/index.ts
+39
-2
packages/core-extensions/src/experiments/index.ts
···
11
11
{
12
12
find: '"scientist:triggered"', // Scientist? Triggered.
13
13
replace: {
14
-
match: /(?<=personal_connection_id\|\|)!1/,
15
-
replacement: "!0"
14
+
match: ".personal_connection_id",
15
+
replacement: ".personal_connection_id || true"
16
+
}
17
+
},
18
+
19
+
// Enable staff help menu
20
+
{
21
+
find: ".HEADER_BAR)",
22
+
replace: {
23
+
match: /&&\((\i)\?\(0,/,
24
+
replacement: (_, isStaff) =>
25
+
`&&(((moonlight.getConfigOption("experiments","devtools")??false)?true:${isStaff})?(0,`
26
+
}
27
+
},
28
+
// staff help menu - visual refresh
29
+
{
30
+
find: '("AppTitleBar")',
31
+
replace: {
32
+
match: /{hasBugReporterAccess:(\i)}=\i\.\i\.useExperiment\({location:"HeaderBar"},{autoTrackExposure:!1}\);/,
33
+
replacement: (orig, isStaff) =>
34
+
`${orig}if(moonlight.getConfigOption("experiments","devtools")??false)${isStaff}=true;`
35
+
}
36
+
},
37
+
{
38
+
find: 'navId:"staff-help-popout",',
39
+
replace: {
40
+
match: /isDiscordDeveloper:(\i)}\),/,
41
+
replacement: (_, isStaff) =>
42
+
`isDiscordDeveloper:(moonlight.getConfigOption("experiments","devtools")??false)||${isStaff}}),`
43
+
}
44
+
},
45
+
46
+
// Enable further staff-locked options
47
+
{
48
+
find: "shouldShowLurkerModeUpsellPopout:",
49
+
replace: {
50
+
match: /\.useReducedMotion,isStaff:(\i)(,|})/,
51
+
replacement: (_, isStaff, trail) =>
52
+
`.useReducedMotion,isStaff:(moonlight.getConfigOption("experiments","staffSettings")??false)?true:${isStaff}${trail}`
16
53
}
17
54
}
18
55
];
+11
-2
packages/core-extensions/src/experiments/manifest.json
+11
-2
packages/core-extensions/src/experiments/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "experiments",
3
4
"apiLevel": 2,
4
5
"meta": {
···
8
9
"tags": ["dangerZone"]
9
10
},
10
11
"settings": {
11
-
"sections": {
12
+
"devtools": {
13
+
"advice": "reload",
14
+
"displayName": "Enable staff help menu (DevTools)",
15
+
"type": "boolean",
16
+
"default": false
17
+
},
18
+
"staffSettings": {
19
+
"advice": "reload",
12
20
"displayName": "Allow access to other staff settings elsewhere",
13
-
"type": "boolean"
21
+
"type": "boolean",
22
+
"default": false
14
23
}
15
24
}
16
25
}
+6
-18
packages/core-extensions/src/markdown/index.ts
+6
-18
packages/core-extensions/src/markdown/index.ts
···
6
6
replace: [
7
7
{
8
8
match: /={newline:(.+?)},(.{1,2})=\(0,/,
9
-
replacement: (_, rules, RULES) =>
10
-
`=require("markdown_markdown")._addRules({newline:${rules}}),${RULES}=(0,`
9
+
replacement: (_, rules, RULES) => `=require("markdown_markdown")._addRules({newline:${rules}}),${RULES}=(0,`
11
10
},
12
11
{
13
12
match: /(?<=;(.{1,2}\.Z)={RULES:.+?})/,
14
-
replacement: (_, rulesets) =>
15
-
`;require("markdown_markdown")._applyRulesetBlacklist(${rulesets});`
13
+
replacement: (_, rulesets) => `;require("markdown_markdown")._applyRulesetBlacklist(${rulesets});`
16
14
}
17
15
]
18
16
},
···
25
23
`__slateRules,${rulesDef}=__slateRules=require("markdown_markdown")._addSlateRules({link:{${rules}}),${syntaxBefore}=new Set`
26
24
},
27
25
{
28
-
match:
29
-
/(originalMatch:.}=(.);)(.+?)case"emoticon":(return .+?;)(.+?)case"subtext":{(.+?)}default:/,
30
-
replacement: (
31
-
_,
32
-
start,
33
-
rule,
34
-
body,
35
-
plaintextReturn,
36
-
otherRules,
37
-
inlineStyleBody
38
-
) =>
39
-
`${start}if(${rule}.type.startsWith("__moonlight_")){if(__slateRules[${rule}.type].type=="inlineStyle"){${inlineStyleBody}}else{${plaintextReturn}}}${body}case"emoticon":${plaintextReturn}${otherRules}case"link":{${inlineStyleBody}}default:`
26
+
match: /(originalMatch:.}=(.);)(.+?)case"emoticon":(return .+?;)(.+?)case"subtext":{(.+?)}default:/,
27
+
replacement: (_, start, rule, body, plaintextReturn, otherRules, inlineStyleBody) =>
28
+
`${start}if(${rule}.type.startsWith("__moonlight_")){if(__slateRules[${rule}.type].type=="inlineStyle"){${inlineStyleBody}}else{${plaintextReturn}}}${body}case"emoticon":${plaintextReturn}${otherRules}case"subtext":{${inlineStyleBody}}default:`
40
29
}
41
30
]
42
31
},
···
44
33
find: '"Slate: Unknown decoration attribute: "',
45
34
replace: {
46
35
match: /=({strong:.+?});/,
47
-
replacement: (_, rules) =>
48
-
`=require("markdown_markdown")._addSlateDecorators(${rules});`
36
+
replacement: (_, rules) => `=require("markdown_markdown")._addSlateDecorators(${rules});`
49
37
}
50
38
}
51
39
];
+1
packages/core-extensions/src/markdown/manifest.json
+1
packages/core-extensions/src/markdown/manifest.json
+4
-17
packages/core-extensions/src/markdown/webpackModules/markdown.ts
+4
-17
packages/core-extensions/src/markdown/webpackModules/markdown.ts
···
1
-
/* eslint-disable no-console */
2
-
import {
3
-
MarkdownRule,
4
-
Ruleset,
5
-
SlateRule
6
-
} from "@moonlight-mod/types/coreExtensions/markdown";
1
+
import { MarkdownRule, Ruleset, SlateRule } from "@moonlight-mod/types/coreExtensions/markdown";
7
2
8
-
export const rules: Record<
9
-
string,
10
-
(rules: Record<string, MarkdownRule>) => MarkdownRule
11
-
> = {};
12
-
export const slateRules: Record<
13
-
string,
14
-
(rules: Record<string, SlateRule>) => SlateRule
15
-
> = {};
3
+
export const rules: Record<string, (rules: Record<string, MarkdownRule>) => MarkdownRule> = {};
4
+
export const slateRules: Record<string, (rules: Record<string, SlateRule>) => SlateRule> = {};
16
5
export const slateDecorators: Record<string, string> = {};
17
6
export const ruleBlacklists: Record<Ruleset, Record<string, boolean>> = {
18
7
RULES: {},
···
67
56
return originalRules;
68
57
}
69
58
70
-
export function _applyRulesetBlacklist(
71
-
rulesets: Record<Ruleset, Record<string, MarkdownRule>>
72
-
) {
59
+
export function _applyRulesetBlacklist(rulesets: Record<Ruleset, Record<string, MarkdownRule>>) {
73
60
for (const ruleset of Object.keys(rulesets) as Ruleset[]) {
74
61
if (ruleset === "RULES") continue;
75
62
+108
packages/core-extensions/src/moonbase/host.ts
+108
packages/core-extensions/src/moonbase/host.ts
···
1
+
import * as electron from "electron";
2
+
import * as fs from "node:fs/promises";
3
+
import * as path from "node:path";
4
+
import getNatives from "./native";
5
+
import { MoonlightBranch } from "@moonlight-mod/types";
6
+
7
+
const natives = getNatives();
8
+
9
+
const confirm = (action: string) =>
10
+
electron.dialog
11
+
.showMessageBox({
12
+
title: "Are you sure?",
13
+
message: `Are you sure? This will ${action} and restart Discord.`,
14
+
type: "warning",
15
+
buttons: ["OK", "Cancel"]
16
+
})
17
+
.then((r) => r.response === 0);
18
+
19
+
async function updateAndRestart() {
20
+
if (!(await confirm("update moonlight"))) return;
21
+
const newVersion = await natives.checkForMoonlightUpdate();
22
+
23
+
if (newVersion === null) {
24
+
electron.dialog.showMessageBox({ message: "You are already on the latest version of moonlight." });
25
+
return;
26
+
}
27
+
28
+
try {
29
+
await natives.updateMoonlight();
30
+
await electron.dialog.showMessageBox({ message: "Update successful, restarting Discord." });
31
+
electron.app.relaunch();
32
+
electron.app.exit(0);
33
+
} catch {
34
+
await electron.dialog.showMessageBox({
35
+
message: "Failed to update moonlight. Please use the installer instead.",
36
+
type: "error"
37
+
});
38
+
}
39
+
}
40
+
41
+
async function resetConfig() {
42
+
if (!(await confirm("reset your configuration"))) return;
43
+
44
+
const config = await moonlightHost.getConfigPath();
45
+
const dir = path.dirname(config);
46
+
const branch = path.basename(config, ".json");
47
+
await fs.rename(config, path.join(dir, `${branch}-backup-${Math.floor(Date.now() / 1000)}.json`));
48
+
49
+
await electron.dialog.showMessageBox({ message: "Configuration reset, restarting Discord." });
50
+
electron.app.relaunch();
51
+
electron.app.exit(0);
52
+
}
53
+
54
+
async function changeBranch(branch: MoonlightBranch) {
55
+
if (moonlightHost.branch === branch) return;
56
+
if (!(await confirm("switch branches"))) return;
57
+
try {
58
+
await natives.updateMoonlight(branch);
59
+
await electron.dialog.showMessageBox({ message: "Branch switch successful, restarting Discord." });
60
+
electron.app.relaunch();
61
+
electron.app.exit(0);
62
+
} catch (e) {
63
+
await electron.dialog.showMessageBox({ message: "Failed to switch branches:\n" + e, type: "error" });
64
+
}
65
+
}
66
+
67
+
function showAbout() {
68
+
electron.dialog.showMessageBox({
69
+
title: "About moonlight",
70
+
message: `moonlight ${moonlightHost.branch} ${moonlightHost.version}`
71
+
});
72
+
}
73
+
74
+
electron.app.whenReady().then(() => {
75
+
const original = electron.Menu.buildFromTemplate;
76
+
electron.Menu.buildFromTemplate = function (entries) {
77
+
const i = entries.findIndex((e) => e.label === "Check for Updates...");
78
+
if (i === -1) return original.call(this, entries);
79
+
80
+
if (!entries.find((e) => e.label === "moonlight")) {
81
+
const options: Electron.MenuItemConstructorOptions[] = [
82
+
{ label: "Update and restart", click: updateAndRestart },
83
+
{ label: "Reset config", click: resetConfig }
84
+
];
85
+
86
+
if (moonlightHost.branch !== MoonlightBranch.DEV) {
87
+
options.push({
88
+
label: "Switch branch",
89
+
submenu: [MoonlightBranch.STABLE, MoonlightBranch.NIGHTLY].map((branch) => ({
90
+
label: branch,
91
+
type: "radio",
92
+
checked: moonlightHost.branch === branch,
93
+
click: () => changeBranch(branch)
94
+
}))
95
+
});
96
+
}
97
+
98
+
options.push({ label: "About", click: showAbout });
99
+
100
+
entries.splice(i + 1, 0, {
101
+
label: "moonlight",
102
+
submenu: options
103
+
});
104
+
}
105
+
106
+
return original.call(this, entries);
107
+
};
108
+
});
+59
-59
packages/core-extensions/src/moonbase/index.tsx
+59
-59
packages/core-extensions/src/moonbase/index.tsx
···
1
-
import { ExtensionWebpackModule } from "@moonlight-mod/types";
1
+
import { ExtensionWebpackModule, Patch } from "@moonlight-mod/types";
2
+
3
+
export const patches: Patch[] = [
4
+
{
5
+
find: "window.DiscordErrors=",
6
+
replace: [
7
+
// replace reporting line with update status
8
+
{
9
+
// CvQlAA mapped to ERRORS_ACTION_TO_TAKE
10
+
// FIXME: Better patch find?
11
+
match: /,(\(0,(\i)\.jsx\))\("p",{children:\i\.\i\.string\(\i\.\i\.CvQlAA\)}\)/,
12
+
replacement: (_, createElement, ReactJSX) =>
13
+
`,${createElement}(require("moonbase_crashScreen")?.UpdateText??${ReactJSX}.Fragment,{state:this.state,setState:this.setState.bind(this)})`
14
+
},
15
+
16
+
// wrap actions field to display error details
17
+
{
18
+
match: /(?<=return(\(0,(\i)\.jsx\))\(.+?,)action:(\i),className:/,
19
+
replacement: (_, createElement, ReactJSX, action) =>
20
+
`action:require("moonbase_crashScreen")?.wrapAction?${createElement}(require("moonbase_crashScreen").wrapAction,{action:${action},state:this.state}):${action},className:`
21
+
},
22
+
23
+
// add update button
24
+
// +hivLS -> ERRORS_RELOAD
25
+
{
26
+
match: /(?<=\["\+hivLS"\]\)}\),(\(0,(\i)\.jsx\))\(\i,{}\))/,
27
+
replacement: (_, createElement, ReactJSX) =>
28
+
`,${createElement}(require("moonbase_crashScreen")?.UpdateButton??${ReactJSX}.Fragment,{state:this.state,setState:this.setState.bind(this)})`
29
+
}
30
+
]
31
+
}
32
+
];
2
33
3
34
export const webpackModules: Record<string, ExtensionWebpackModule> = {
4
35
stores: {
5
-
dependencies: [
6
-
{ id: "discord/packages/flux" },
7
-
{ id: "discord/Dispatcher" }
8
-
]
36
+
dependencies: [{ id: "discord/packages/flux" }, { id: "discord/Dispatcher" }]
9
37
},
10
38
11
39
ui: {
···
14
42
{ id: "react" },
15
43
{ id: "discord/components/common/index" },
16
44
{ ext: "moonbase", id: "stores" },
17
-
{ id: "discord/modules/guild_settings/IntegrationCard.css" },
45
+
{ ext: "moonbase", id: "ThemeDarkIcon" },
46
+
{ id: "discord/modules/guild_settings/web/AppCard.css" },
47
+
{ ext: "contextMenu", id: "contextMenu" },
48
+
{ id: "discord/modules/modals/Modals" },
18
49
"Masks.PANEL_BUTTON",
19
50
'"Missing channel in Channel.openChannelContextMenu"',
20
51
".forumOrHome]:"
21
52
]
22
53
},
23
54
55
+
ThemeDarkIcon: {
56
+
dependencies: [{ ext: "common", id: "icons" }, { id: "react" }]
57
+
},
58
+
24
59
settings: {
25
60
dependencies: [
26
61
{ ext: "spacepack", id: "spacepack" },
27
62
{ ext: "settings", id: "settings" },
28
63
{ id: "react" },
29
-
{ ext: "moonbase", id: "ui" }
64
+
{ ext: "moonbase", id: "ui" },
65
+
{ ext: "contextMenu", id: "contextMenu" },
66
+
':"USER_SETTINGS_MODAL_SET_SECTION"'
30
67
],
31
68
entrypoint: true
32
69
},
···
35
72
dependencies: [
36
73
{ id: "react" },
37
74
{ ext: "moonbase", id: "stores" },
75
+
{ ext: "moonbase", id: "ThemeDarkIcon" },
38
76
{ ext: "notices", id: "notices" },
39
77
{
40
78
ext: "spacepack",
41
79
id: "spacepack"
42
-
}
80
+
},
81
+
{ id: "discord/Constants" },
82
+
{ id: "discord/components/common/index" }
43
83
],
44
84
entrypoint: true
45
85
},
46
86
47
87
moonbase: {
48
88
dependencies: [{ ext: "moonbase", id: "stores" }]
89
+
},
90
+
91
+
crashScreen: {
92
+
dependencies: [
93
+
{ ext: "spacepack", id: "spacepack" },
94
+
{ id: "react" },
95
+
{ ext: "moonbase", id: "stores" },
96
+
{ id: "discord/packages/flux" },
97
+
{ id: "discord/components/common/index" },
98
+
/tabBar:"tabBar_[a-z0-9]+",tabBarItem:"tabBarItem_[a-z0-9]+"/
99
+
]
49
100
}
50
101
};
51
-
52
-
const bg = "#222034";
53
-
const fg = "#FFFBA6";
54
-
55
-
export const styles = [
56
-
`
57
-
.moonbase-settings > :first-child {
58
-
margin-top: 0px;
59
-
}
60
-
61
-
textarea.moonbase-resizeable {
62
-
resize: vertical
63
-
}
64
-
65
-
.moonbase-updates-notice {
66
-
background-color: ${bg};
67
-
color: ${fg};
68
-
line-height: unset;
69
-
height: 36px;
70
-
}
71
-
72
-
.moonbase-updates-notice button {
73
-
color: ${fg};
74
-
border-color: ${fg};
75
-
}
76
-
77
-
.moonbase-updates-notice_text-wrapper {
78
-
display: inline-flex;
79
-
align-items: center;
80
-
line-height: 36px;
81
-
gap: 2px;
82
-
}
83
-
84
-
.moonbase-update-section {
85
-
background-color: ${bg};
86
-
--info-help-foreground: ${fg};
87
-
border: none !important;
88
-
color: ${fg};
89
-
90
-
display: flex;
91
-
flex-direction: row;
92
-
justify-content: space-between;
93
-
}
94
-
95
-
.moonbase-update-section > button {
96
-
color: ${fg};
97
-
background-color: transparent;
98
-
border-color: ${fg};
99
-
}
100
-
`.trim()
101
-
];
+18
-5
packages/core-extensions/src/moonbase/manifest.json
+18
-5
packages/core-extensions/src/moonbase/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "moonbase",
3
4
"apiLevel": 2,
4
5
"meta": {
···
6
7
"tagline": "The official settings UI for moonlight",
7
8
"authors": ["Cynosphere", "NotNite", "redstonekasi"]
8
9
},
9
-
"dependencies": ["spacepack", "settings", "common", "notices"],
10
+
"dependencies": ["spacepack", "settings", "common", "notices", "contextMenu"],
10
11
"settings": {
11
12
"sections": {
13
+
"advice": "reload",
12
14
"displayName": "Split into sections",
13
15
"description": "Show the Moonbase tabs as separate sections",
14
-
"type": "boolean"
16
+
"type": "boolean",
17
+
"default": false
18
+
},
19
+
"oldLocation": {
20
+
"advice": "reload",
21
+
"displayName": "Put Moonbase back at the bottom",
22
+
"type": "boolean",
23
+
"default": false
15
24
},
16
25
"saveFilter": {
26
+
"advice": "none",
17
27
"displayName": "Persist filter",
18
28
"description": "Save extension filter in config",
19
-
"type": "boolean"
29
+
"type": "boolean",
30
+
"default": false
20
31
},
21
32
"updateChecking": {
33
+
"advice": "none",
22
34
"displayName": "Automatic update checking",
23
35
"description": "Checks for updates to moonlight",
24
36
"type": "boolean",
25
-
"default": "true"
37
+
"default": true
26
38
},
27
39
"updateBanner": {
40
+
"advice": "none",
28
41
"displayName": "Show update banner",
29
42
"description": "Shows a banner for moonlight and extension updates",
30
43
"type": "boolean",
31
-
"default": "true"
44
+
"default": true
32
45
}
33
46
},
34
47
"cors": [
+46
-71
packages/core-extensions/src/moonbase/native.ts
+46
-71
packages/core-extensions/src/moonbase/native.ts
···
1
1
import { MoonlightBranch } from "@moonlight-mod/types";
2
2
import type { MoonbaseNatives, RepositoryManifest } from "./types";
3
3
import extractAsar from "@moonlight-mod/core/asar";
4
-
import {
5
-
distDir,
6
-
repoUrlFile,
7
-
installedVersionFile
8
-
} from "@moonlight-mod/types/constants";
4
+
import { distDir, repoUrlFile, installedVersionFile } from "@moonlight-mod/types/constants";
9
5
import { parseTarGzip } from "nanotar";
6
+
7
+
const moonlightGlobal = globalThis.moonlightHost ?? globalThis.moonlightNode;
10
8
11
9
const githubRepo = "moonlight-mod/moonlight";
12
10
const githubApiUrl = `https://api.github.com/repos/${githubRepo}/releases/latest`;
···
15
13
const nightlyRefUrl = "https://moonlight-mod.github.io/moonlight/ref";
16
14
const nightlyZipUrl = "https://moonlight-mod.github.io/moonlight/dist.tar.gz";
17
15
18
-
export const userAgent = `moonlight/${moonlightNode.version} (https://github.com/moonlight-mod/moonlight)`;
16
+
export const userAgent = `moonlight/${moonlightGlobal.version} (https://github.com/moonlight-mod/moonlight)`;
17
+
18
+
// User-Agent header causes trouble on Firefox
19
+
const isBrowser = globalThis.moonlightNode != null && globalThis.moonlightNode.isBrowser;
20
+
const sharedHeaders: Record<string, string> = {};
21
+
if (!isBrowser) sharedHeaders["User-Agent"] = userAgent;
19
22
20
23
async function getStableRelease(): Promise<{
21
24
name: string;
···
26
29
}> {
27
30
const req = await fetch(githubApiUrl, {
28
31
cache: "no-store",
29
-
headers: {
30
-
"User-Agent": userAgent
31
-
}
32
+
headers: sharedHeaders
32
33
});
33
34
return await req.json();
34
35
}
35
36
36
37
export default function getNatives(): MoonbaseNatives {
37
-
const logger = moonlightNode.getLogger("moonbase/natives");
38
+
const logger = moonlightGlobal.getLogger("moonbase/natives");
38
39
39
40
return {
40
41
async checkForMoonlightUpdate() {
41
42
try {
42
-
if (moonlightNode.branch === MoonlightBranch.STABLE) {
43
+
if (moonlightGlobal.branch === MoonlightBranch.STABLE) {
43
44
const json = await getStableRelease();
44
-
return json.name !== moonlightNode.version ? json.name : null;
45
-
} else if (moonlightNode.branch === MoonlightBranch.NIGHTLY) {
45
+
return json.name !== moonlightGlobal.version ? json.name : null;
46
+
} else if (moonlightGlobal.branch === MoonlightBranch.NIGHTLY) {
46
47
const req = await fetch(nightlyRefUrl, {
47
48
cache: "no-store",
48
-
headers: {
49
-
"User-Agent": userAgent
50
-
}
49
+
headers: sharedHeaders
51
50
});
52
51
const ref = (await req.text()).split("\n")[0];
53
-
return ref !== moonlightNode.version ? ref : null;
52
+
return ref !== moonlightGlobal.version ? ref : null;
54
53
}
55
54
56
55
return null;
···
60
59
}
61
60
},
62
61
63
-
async updateMoonlight() {
62
+
async updateMoonlight(overrideBranch?: MoonlightBranch) {
63
+
const branch = overrideBranch ?? moonlightGlobal.branch;
64
+
64
65
// Note: this won't do anything on browser, we should probably disable it
65
66
// entirely when running in browser.
66
67
async function downloadStable(): Promise<[ArrayBuffer, string]> {
···
71
72
logger.debug(`Downloading ${asset.browser_download_url}`);
72
73
const req = await fetch(asset.browser_download_url, {
73
74
cache: "no-store",
74
-
headers: {
75
-
"User-Agent": userAgent
76
-
}
75
+
headers: sharedHeaders
77
76
});
78
77
79
78
return [await req.arrayBuffer(), json.name];
···
83
82
logger.debug(`Downloading ${nightlyZipUrl}`);
84
83
const zipReq = await fetch(nightlyZipUrl, {
85
84
cache: "no-store",
86
-
headers: {
87
-
"User-Agent": userAgent
88
-
}
85
+
headers: sharedHeaders
89
86
});
90
87
91
88
const refReq = await fetch(nightlyRefUrl, {
92
89
cache: "no-store",
93
-
headers: {
94
-
"User-Agent": userAgent
95
-
}
90
+
headers: sharedHeaders
96
91
});
97
92
const ref = (await refReq.text()).split("\n")[0];
98
93
···
100
95
}
101
96
102
97
const [tar, ref] =
103
-
moonlightNode.branch === MoonlightBranch.STABLE
98
+
branch === MoonlightBranch.STABLE
104
99
? await downloadStable()
105
-
: moonlightNode.branch === MoonlightBranch.NIGHTLY
100
+
: branch === MoonlightBranch.NIGHTLY
106
101
? await downloadNightly()
107
102
: [null, null];
108
103
109
104
if (!tar || !ref) return;
110
105
111
-
const dist = moonlightFS.join(moonlightNode.getMoonlightDir(), distDir);
112
-
if (await moonlightFS.exists(dist)) await moonlightFS.rmdir(dist);
113
-
await moonlightFS.mkdir(dist);
106
+
const dist = moonlightNodeSandboxed.fs.join(moonlightGlobal.getMoonlightDir(), distDir);
107
+
if (await moonlightNodeSandboxed.fs.exists(dist)) await moonlightNodeSandboxed.fs.rmdir(dist);
108
+
await moonlightNodeSandboxed.fs.mkdir(dist);
114
109
115
110
logger.debug("Extracting update");
116
111
const files = await parseTarGzip(tar);
···
119
114
// @ts-expect-error What do you mean their own types are wrong
120
115
if (file.type !== "file") continue;
121
116
122
-
const fullFile = moonlightFS.join(dist, file.name);
123
-
const fullDir = moonlightFS.dirname(fullFile);
124
-
if (!(await moonlightFS.exists(fullDir)))
125
-
await moonlightFS.mkdir(fullDir);
126
-
await moonlightFS.writeFile(fullFile, file.data);
117
+
const fullFile = moonlightNodeSandboxed.fs.join(dist, file.name);
118
+
const fullDir = moonlightNodeSandboxed.fs.dirname(fullFile);
119
+
if (!(await moonlightNodeSandboxed.fs.exists(fullDir))) await moonlightNodeSandboxed.fs.mkdir(fullDir);
120
+
await moonlightNodeSandboxed.fs.writeFile(fullFile, file.data);
127
121
}
128
122
129
123
logger.debug("Writing version file:", ref);
130
-
const versionFile = moonlightFS.join(
131
-
moonlightNode.getMoonlightDir(),
132
-
installedVersionFile
133
-
);
134
-
await moonlightFS.writeFileString(versionFile, ref.trim());
124
+
const versionFile = moonlightNodeSandboxed.fs.join(moonlightGlobal.getMoonlightDir(), installedVersionFile);
125
+
await moonlightNodeSandboxed.fs.writeFileString(versionFile, ref.trim());
135
126
136
127
logger.debug("Update extracted");
137
128
},
···
143
134
try {
144
135
const req = await fetch(repo, {
145
136
cache: "no-store",
146
-
headers: {
147
-
"User-Agent": userAgent
148
-
}
137
+
headers: sharedHeaders
149
138
});
150
139
const json = await req.json();
151
140
ret[repo] = json;
···
159
148
160
149
async installExtension(manifest, url, repo) {
161
150
const req = await fetch(url, {
162
-
headers: {
163
-
"User-Agent": userAgent
164
-
}
151
+
cache: "no-store",
152
+
headers: sharedHeaders
165
153
});
166
154
167
-
const dir = moonlightNode.getExtensionDir(manifest.id);
155
+
const dir = moonlightGlobal.getExtensionDir(manifest.id);
168
156
// remake it in case of updates
169
-
if (await moonlightFS.exists(dir)) await moonlightFS.rmdir(dir);
170
-
await moonlightFS.mkdir(dir);
157
+
if (await moonlightNodeSandboxed.fs.exists(dir)) await moonlightNodeSandboxed.fs.rmdir(dir);
158
+
await moonlightNodeSandboxed.fs.mkdir(dir);
171
159
172
160
const buffer = await req.arrayBuffer();
173
161
const files = extractAsar(buffer);
174
162
for (const [file, buf] of Object.entries(files)) {
175
-
const fullFile = moonlightFS.join(dir, file);
176
-
const fullDir = moonlightFS.dirname(fullFile);
163
+
const fullFile = moonlightNodeSandboxed.fs.join(dir, file);
164
+
const fullDir = moonlightNodeSandboxed.fs.dirname(fullFile);
177
165
178
-
if (!(await moonlightFS.exists(fullDir)))
179
-
await moonlightFS.mkdir(fullDir);
180
-
await moonlightFS.writeFile(moonlightFS.join(dir, file), buf);
166
+
if (!(await moonlightNodeSandboxed.fs.exists(fullDir))) await moonlightNodeSandboxed.fs.mkdir(fullDir);
167
+
await moonlightNodeSandboxed.fs.writeFile(moonlightNodeSandboxed.fs.join(dir, file), buf);
181
168
}
182
169
183
-
await moonlightFS.writeFileString(
184
-
moonlightFS.join(dir, repoUrlFile),
185
-
repo
186
-
);
170
+
await moonlightNodeSandboxed.fs.writeFileString(moonlightNodeSandboxed.fs.join(dir, repoUrlFile), repo);
187
171
},
188
172
189
173
async deleteExtension(id) {
190
-
const dir = moonlightNode.getExtensionDir(id);
191
-
await moonlightFS.rmdir(dir);
192
-
},
193
-
194
-
getExtensionConfig(id, key) {
195
-
const config = moonlightNode.config.extensions[id];
196
-
if (typeof config === "object") {
197
-
return config.config?.[key];
198
-
}
199
-
200
-
return undefined;
174
+
const dir = moonlightGlobal.getExtensionDir(id);
175
+
await moonlightNodeSandboxed.fs.rmdir(dir);
201
176
}
202
177
};
203
178
}
+269
packages/core-extensions/src/moonbase/style.css
+269
packages/core-extensions/src/moonbase/style.css
···
1
+
:root {
2
+
--moonbase-bg: #222034;
3
+
--moonbase-fg: #fffba6;
4
+
}
5
+
6
+
.moonbase-settings > :first-child {
7
+
margin-top: 0px;
8
+
}
9
+
10
+
.moonbase-retry-button {
11
+
padding: 8px;
12
+
margin-right: 8px;
13
+
}
14
+
15
+
textarea.moonbase-resizeable {
16
+
resize: vertical;
17
+
}
18
+
19
+
.moonbase-link-buttons {
20
+
border-bottom: 2px solid var(--background-modifier-accent);
21
+
margin-bottom: -2px;
22
+
margin-left: 0 !important;
23
+
padding-right: 20px;
24
+
gap: 1rem;
25
+
}
26
+
27
+
.moonbase-speen {
28
+
animation: moonbase-speen-animation 0.25s linear infinite;
29
+
}
30
+
31
+
@keyframes moonbase-speen-animation {
32
+
from {
33
+
transform: rotate(0deg);
34
+
}
35
+
to {
36
+
transform: rotate(360deg);
37
+
}
38
+
}
39
+
40
+
/* Update notice at the top of the client */
41
+
.moonbase-updates-notice {
42
+
background-color: var(--moonbase-bg);
43
+
color: var(--moonbase-fg);
44
+
--custom-notice-text: var(--moonbase-fg);
45
+
line-height: unset;
46
+
height: 36px;
47
+
}
48
+
49
+
.moonbase-updates-notice button {
50
+
color: var(--moonbase-fg);
51
+
border-color: var(--moonbase-fg);
52
+
}
53
+
54
+
.moonbase-updates-notice_text-wrapper {
55
+
display: inline-flex;
56
+
align-items: center;
57
+
line-height: 36px;
58
+
gap: 2px;
59
+
}
60
+
61
+
/* Help messages in Moonbase UI */
62
+
.moonbase-help-message {
63
+
display: flex;
64
+
flex-direction: row;
65
+
justify-content: space-between;
66
+
}
67
+
68
+
.moonbase-help-message-sticky {
69
+
position: sticky;
70
+
top: 24px;
71
+
z-index: 10;
72
+
background-color: var(--background-primary);
73
+
}
74
+
75
+
.moonbase-extension-update-section {
76
+
margin-top: 15px;
77
+
}
78
+
79
+
.moonbase-update-section {
80
+
background-color: var(--moonbase-bg);
81
+
--info-help-foreground: var(--moonbase-fg);
82
+
border: none !important;
83
+
color: var(--moonbase-fg);
84
+
}
85
+
86
+
.moonbase-update-section button {
87
+
--info-help-foreground: var(--moonbase-fg);
88
+
color: var(--moonbase-fg);
89
+
background-color: transparent;
90
+
border-color: var(--moonbase-fg);
91
+
}
92
+
93
+
.moonbase-help-message-buttons {
94
+
display: flex;
95
+
flex-direction: row;
96
+
gap: 8px;
97
+
align-items: center;
98
+
}
99
+
100
+
.moonbase-update-divider {
101
+
margin: 32px 0;
102
+
}
103
+
104
+
.moonlight-card-info-header {
105
+
margin-bottom: 0.25rem;
106
+
}
107
+
108
+
.moonlight-card-badge {
109
+
border-radius: 0.1875rem;
110
+
padding: 0 0.275rem;
111
+
margin-right: 0.4em;
112
+
background-color: var(--badge-color, var(--bg-mod-strong));
113
+
}
114
+
115
+
/* Crash screen */
116
+
.moonbase-crash-wrapper > [class^="buttons_"] {
117
+
gap: 1rem;
118
+
}
119
+
120
+
.moonbase-crash-wrapper {
121
+
display: flex;
122
+
flex-direction: column;
123
+
align-items: center;
124
+
gap: 1rem;
125
+
height: 50%;
126
+
width: 50vw;
127
+
max-height: 50%;
128
+
max-width: 50vw;
129
+
}
130
+
131
+
.moonbase-crash-tabs {
132
+
width: 100%;
133
+
}
134
+
135
+
.moonbase-crash-details-wrapper {
136
+
overflow-y: scroll;
137
+
color: var(--text-normal);
138
+
background: var(--background-secondary);
139
+
border: 1px solid var(--background-tertiary);
140
+
border-radius: 4px;
141
+
padding: 0.5em;
142
+
143
+
&::-webkit-scrollbar {
144
+
width: 8px;
145
+
height: 8px;
146
+
}
147
+
148
+
&::-webkit-scrollbar-thumb {
149
+
background-clip: padding-box;
150
+
border: 2px solid transparent;
151
+
border-radius: 4px;
152
+
background-color: var(--scrollbar-thin-thumb);
153
+
min-height: 40px;
154
+
}
155
+
156
+
&::-webkit-scrollbar-track {
157
+
border: 2px solid var(--scrollbar-thin-track);
158
+
background-color: var(--scrollbar-thin-track);
159
+
border-color: var(--scrollbar-thin-track);
160
+
}
161
+
}
162
+
163
+
.moonbase-crash-details {
164
+
box-sizing: border-box;
165
+
padding: 0;
166
+
font-family: var(--font-code);
167
+
font-size: 0.75rem;
168
+
line-height: 1rem;
169
+
margin: 6px;
170
+
white-space: pre-wrap;
171
+
background-clip: border-box;
172
+
173
+
& > code {
174
+
font-size: 0.875rem;
175
+
line-height: 1.125rem;
176
+
text-indent: 0;
177
+
white-space: pre-wrap;
178
+
text-size-adjust: none;
179
+
display: block;
180
+
user-select: text;
181
+
}
182
+
}
183
+
184
+
.moonbase-crash-extensions {
185
+
overflow-y: scroll;
186
+
display: grid;
187
+
grid-auto-columns: 25vw;
188
+
gap: 8px;
189
+
190
+
&::-webkit-scrollbar {
191
+
width: 8px;
192
+
height: 8px;
193
+
}
194
+
195
+
&::-webkit-scrollbar-thumb {
196
+
background-clip: padding-box;
197
+
border: 2px solid transparent;
198
+
border-radius: 4px;
199
+
background-color: var(--scrollbar-thin-thumb);
200
+
min-height: 40px;
201
+
}
202
+
203
+
&::-webkit-scrollbar-track {
204
+
border: 2px solid var(--scrollbar-thin-track);
205
+
background-color: var(--scrollbar-thin-track);
206
+
border-color: var(--scrollbar-thin-track);
207
+
}
208
+
}
209
+
210
+
.moonbase-crash-extensionCard {
211
+
color: var(--text-normal);
212
+
background: var(--background-secondary);
213
+
border: 1px solid var(--background-tertiary);
214
+
border-radius: 4px;
215
+
padding: 0.5em;
216
+
display: flex;
217
+
}
218
+
219
+
.moonbase-crash-extensionCard-meta {
220
+
display: flex;
221
+
flex-direction: column;
222
+
flex-grow: 1;
223
+
}
224
+
225
+
.moonbase-crash-extensionCard-title {
226
+
color: var(--text-normal);
227
+
font-family: var(--font-primary);
228
+
font-size: 16px;
229
+
line-height: 1.25;
230
+
font-weight: 600;
231
+
}
232
+
233
+
.moonbase-crash-extensionCard-version {
234
+
color: var(--text-muted);
235
+
font-family: var(--font-primary);
236
+
font-size: 14px;
237
+
line-height: 1.286;
238
+
font-weight: 400;
239
+
}
240
+
241
+
/* About page */
242
+
.moonbase-wordmark {
243
+
width: 100%;
244
+
}
245
+
246
+
.moonbase-devs {
247
+
width: 100%;
248
+
display: flex;
249
+
justify-content: center;
250
+
gap: 0rem 0.5rem;
251
+
padding-top: 0.5rem;
252
+
}
253
+
254
+
.moonbase-dev {
255
+
height: 4rem;
256
+
}
257
+
258
+
.moonbase-dev-avatar {
259
+
width: 2rem;
260
+
border-radius: 50%;
261
+
}
262
+
263
+
.moonbase-gap {
264
+
gap: 0.5rem;
265
+
}
266
+
267
+
.moonbase-about-page {
268
+
gap: 1rem;
269
+
}
+21
-11
packages/core-extensions/src/moonbase/types.ts
+21
-11
packages/core-extensions/src/moonbase/types.ts
···
1
1
import { ExtensionCompat } from "@moonlight-mod/core/extension/loader";
2
-
import { DetectedExtension, ExtensionManifest } from "@moonlight-mod/types";
2
+
import { DetectedExtension, ExtensionManifest, MoonlightBranch } from "@moonlight-mod/types";
3
3
4
4
export type MoonbaseNatives = {
5
5
checkForMoonlightUpdate(): Promise<string | null>;
6
-
updateMoonlight(): Promise<void>;
6
+
updateMoonlight(overrideBranch?: MoonlightBranch): Promise<void>;
7
7
8
-
fetchRepositories(
9
-
repos: string[]
10
-
): Promise<Record<string, RepositoryManifest[]>>;
11
-
installExtension(
12
-
manifest: RepositoryManifest,
13
-
url: string,
14
-
repo: string
15
-
): Promise<void>;
8
+
fetchRepositories(repos: string[]): Promise<Record<string, RepositoryManifest[]>>;
9
+
installExtension(manifest: RepositoryManifest, url: string, repo: string): Promise<void>;
16
10
deleteExtension(id: string): Promise<void>;
17
-
getExtensionConfig(id: string, key: string): any;
18
11
};
19
12
20
13
export type RepositoryManifest = ExtensionManifest & {
···
35
28
state: ExtensionState;
36
29
compat: ExtensionCompat;
37
30
hasUpdate: boolean;
31
+
changelog?: string;
32
+
settingsOverride?: ExtensionManifest["settings"];
38
33
};
34
+
35
+
export enum UpdateState {
36
+
Ready,
37
+
Working,
38
+
Installed,
39
+
Failed
40
+
}
41
+
42
+
// Ordered in terms of priority
43
+
export enum RestartAdvice {
44
+
NotNeeded, // No action is needed
45
+
ReloadSuggested, // A reload might be needed
46
+
ReloadNeeded, // A reload is needed
47
+
RestartNeeded // A restart is needed
48
+
}
+36
packages/core-extensions/src/moonbase/webpackModules/ThemeDarkIcon.tsx
+36
packages/core-extensions/src/moonbase/webpackModules/ThemeDarkIcon.tsx
···
1
+
// RIP to ThemeDarkIcon ????-2025
2
+
// <Cynthia> Failed to remap "ThemeDarkIcon" in "discord/components/common/index"
3
+
// <NotNite> bro are you fucking kidding me
4
+
// <NotNite> that's literally the icon we use for the update banner
5
+
6
+
import React from "@moonlight-mod/wp/react";
7
+
import icons from "@moonlight-mod/wp/common_icons";
8
+
import type { IconProps } from "@moonlight-mod/types/coreExtensions/common";
9
+
10
+
export default function ThemeDarkIcon(props?: IconProps) {
11
+
const parsed = icons.parseProps(props);
12
+
13
+
return (
14
+
<svg
15
+
aria-hidden="true"
16
+
role="img"
17
+
xmlns="http://www.w3.org/2000/svg"
18
+
width={parsed.width}
19
+
height={parsed.height}
20
+
fill="none"
21
+
viewBox="0 0 24 24"
22
+
>
23
+
<path
24
+
fill={parsed.fill}
25
+
className={parsed.className}
26
+
d="M20.52 18.96c.32-.4-.01-.96-.52-.96A11 11 0 0 1 9.77 2.94c.31-.78-.3-1.68-1.1-1.43a11 11 0 1 0 11.85 17.45Z"
27
+
/>
28
+
29
+
<path
30
+
fill={parsed.fill}
31
+
className={parsed.className}
32
+
d="m17.73 9.27-.76-2.02a.5.5 0 0 0-.94 0l-.76 2.02-2.02.76a.5.5 0 0 0 0 .94l2.02.76.76 2.02a.5.5 0 0 0 .94 0l.76-2.02 2.02-.76a.5.5 0 0 0 0-.94l-2.02-.76ZM19.73 2.62l.45 1.2 1.2.45c.21.08.21.38 0 .46l-1.2.45-.45 1.2a.25.25 0 0 1-.46 0l-.45-1.2-1.2-.45a.25.25 0 0 1 0-.46l1.2-.45.45-1.2a.25.25 0 0 1 .46 0Z"
33
+
/>
34
+
</svg>
35
+
);
36
+
}
+263
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
+263
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
···
1
+
import React from "@moonlight-mod/wp/react";
2
+
import { Button, TabBar } from "@moonlight-mod/wp/discord/components/common/index";
3
+
import { useStateFromStores, useStateFromStoresObject } from "@moonlight-mod/wp/discord/packages/flux";
4
+
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
5
+
import { RepositoryManifest, UpdateState } from "../types";
6
+
import { ConfigExtension, DetectedExtension } from "@moonlight-mod/types";
7
+
import DiscoveryClasses from "@moonlight-mod/wp/discord/modules/discovery/web/Discovery.css";
8
+
9
+
const MODULE_REGEX = /Webpack-Module\/(\d+)\/(\d+)/g;
10
+
11
+
const logger = moonlight.getLogger("moonbase/crashScreen");
12
+
13
+
type ErrorState = {
14
+
error: Error;
15
+
info: {
16
+
componentStack: string;
17
+
};
18
+
__moonlight_update?: UpdateState;
19
+
};
20
+
21
+
type WrapperProps = {
22
+
action: React.ReactNode;
23
+
state: ErrorState;
24
+
};
25
+
26
+
type UpdateCardProps = {
27
+
id: number;
28
+
ext: {
29
+
version: string;
30
+
download: string;
31
+
updateManifest: RepositoryManifest;
32
+
};
33
+
};
34
+
35
+
const updateStrings: Record<UpdateState, string> = {
36
+
[UpdateState.Ready]: "A new version of moonlight is available.",
37
+
[UpdateState.Working]: "Updating moonlight...",
38
+
[UpdateState.Installed]: "Updated moonlight. Click Reload to apply changes.",
39
+
[UpdateState.Failed]: "Failed to update moonlight. Please use the installer."
40
+
};
41
+
const buttonStrings: Record<UpdateState, string> = {
42
+
[UpdateState.Ready]: "Update moonlight",
43
+
[UpdateState.Working]: "Updating moonlight...",
44
+
[UpdateState.Installed]: "",
45
+
[UpdateState.Failed]: "Update failed"
46
+
};
47
+
const extensionButtonStrings: Record<UpdateState, string> = {
48
+
[UpdateState.Ready]: "Update",
49
+
[UpdateState.Working]: "Updating...",
50
+
[UpdateState.Installed]: "Updated",
51
+
[UpdateState.Failed]: "Update failed"
52
+
};
53
+
54
+
function ExtensionUpdateCard({ id, ext }: UpdateCardProps) {
55
+
const [state, setState] = React.useState(UpdateState.Ready);
56
+
const installed = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.getExtension(id), [id]);
57
+
58
+
return (
59
+
<div className="moonbase-crash-extensionCard">
60
+
<div className="moonbase-crash-extensionCard-meta">
61
+
<div className="moonbase-crash-extensionCard-title">
62
+
{ext.updateManifest.meta?.name ?? ext.updateManifest.id}
63
+
</div>
64
+
<div className="moonbase-crash-extensionCard-version">{`v${installed?.manifest?.version ?? "???"} -> v${
65
+
ext.version
66
+
}`}</div>
67
+
</div>
68
+
<div className="moonbase-crash-extensionCard-button">
69
+
<Button
70
+
color={Button.Colors.GREEN}
71
+
disabled={state !== UpdateState.Ready}
72
+
onClick={() => {
73
+
setState(UpdateState.Working);
74
+
MoonbaseSettingsStore.installExtension(id)
75
+
.then(() => setState(UpdateState.Installed))
76
+
.catch(() => setState(UpdateState.Failed));
77
+
}}
78
+
>
79
+
{extensionButtonStrings[state]}
80
+
</Button>
81
+
</div>
82
+
</div>
83
+
);
84
+
}
85
+
86
+
function ExtensionDisableCard({ ext }: { ext: DetectedExtension }) {
87
+
async function disableWithDependents() {
88
+
const disable = new Set<string>();
89
+
disable.add(ext.id);
90
+
for (const [id, dependencies] of moonlightNode.processedExtensions.dependencyGraph) {
91
+
if (dependencies?.has(ext.id)) disable.add(id);
92
+
}
93
+
94
+
const config = structuredClone(moonlightNode.config);
95
+
for (const id in config.extensions) {
96
+
if (!disable.has(id)) continue;
97
+
if (typeof config.extensions[id] === "boolean") config.extensions[id] = false;
98
+
else (config.extensions[id] as ConfigExtension).enabled = false;
99
+
}
100
+
101
+
let msg = `Are you sure you want to disable "${ext.manifest.meta?.name ?? ext.id}"`;
102
+
if (disable.size > 1) {
103
+
msg += ` and its ${disable.size - 1} dependent${disable.size - 1 === 1 ? "" : "s"}`;
104
+
}
105
+
msg += "?";
106
+
107
+
if (confirm(msg)) {
108
+
await moonlightNode.writeConfig(config);
109
+
window.location.reload();
110
+
}
111
+
}
112
+
113
+
return (
114
+
<div className="moonbase-crash-extensionCard">
115
+
<div className="moonbase-crash-extensionCard-meta">
116
+
<div className="moonbase-crash-extensionCard-title">{ext.manifest.meta?.name ?? ext.id}</div>
117
+
<div className="moonbase-crash-extensionCard-version">{`v${ext.manifest.version ?? "???"}`}</div>
118
+
</div>
119
+
<div className="moonbase-crash-extensionCard-button">
120
+
<Button color={Button.Colors.RED} onClick={disableWithDependents}>
121
+
Disable
122
+
</Button>
123
+
</div>
124
+
</div>
125
+
);
126
+
}
127
+
128
+
export function wrapAction({ action, state }: WrapperProps) {
129
+
const [tab, setTab] = React.useState("crash");
130
+
131
+
const { updates, updateCount } = useStateFromStoresObject([MoonbaseSettingsStore], () => {
132
+
const { updates } = MoonbaseSettingsStore;
133
+
return {
134
+
updates: Object.entries(updates),
135
+
updateCount: Object.keys(updates).length
136
+
};
137
+
});
138
+
139
+
const causes = React.useMemo(() => {
140
+
const causes = new Set<string>();
141
+
if (state.error.stack) {
142
+
for (const [, , id] of state.error.stack.matchAll(MODULE_REGEX))
143
+
for (const ext of moonlight.patched.get(id) ?? []) causes.add(ext);
144
+
}
145
+
for (const [, , id] of state.info.componentStack.matchAll(MODULE_REGEX))
146
+
for (const ext of moonlight.patched.get(id) ?? []) causes.add(ext);
147
+
148
+
for (const [path, id] of Object.entries(moonlight.moonmap.modules)) {
149
+
const MAPPING_REGEX = new RegExp(
150
+
// @ts-expect-error Only Firefox has RegExp.escape
151
+
`(${RegExp.escape ? RegExp.escape(path) : path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`,
152
+
"g"
153
+
);
154
+
155
+
if (state.error.stack) {
156
+
for (const match of state.error.stack.matchAll(MAPPING_REGEX))
157
+
if (match) for (const ext of moonlight.patched.get(id) ?? []) causes.add(ext);
158
+
}
159
+
for (const match of state.info.componentStack.matchAll(MAPPING_REGEX))
160
+
if (match) for (const ext of moonlight.patched.get(id) ?? []) causes.add(ext);
161
+
}
162
+
163
+
return [...causes];
164
+
}, []);
165
+
166
+
return (
167
+
<div className="moonbase-crash-wrapper">
168
+
{action}
169
+
<TabBar
170
+
className={`${DiscoveryClasses.tabBar} moonbase-crash-tabs`}
171
+
type="top"
172
+
selectedItem={tab}
173
+
onItemSelect={(v) => setTab(v)}
174
+
>
175
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id="crash">
176
+
Crash details
177
+
</TabBar.Item>
178
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id="extensions" disabled={updateCount === 0}>
179
+
{`Extension updates (${updateCount})`}
180
+
</TabBar.Item>
181
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id="causes" disabled={causes.length === 0}>
182
+
{`Possible causes (${causes.length})`}
183
+
</TabBar.Item>
184
+
</TabBar>
185
+
{tab === "crash" ? (
186
+
<div className="moonbase-crash-details-wrapper">
187
+
<pre className="moonbase-crash-details">
188
+
<code>
189
+
{state.error.stack}
190
+
{"\n\nComponent stack:"}
191
+
{state.info.componentStack}
192
+
</code>
193
+
</pre>
194
+
</div>
195
+
) : null}
196
+
{tab === "extensions" ? (
197
+
<div className="moonbase-crash-extensions">
198
+
{updates.map(([id, ext]) => (
199
+
<ExtensionUpdateCard id={Number(id)} ext={ext} />
200
+
))}
201
+
</div>
202
+
) : null}
203
+
{tab === "causes" ? (
204
+
<div className="moonbase-crash-extensions">
205
+
{causes
206
+
.map((ext) => moonlightNode.extensions.find((e) => e.id === ext)!)
207
+
.map((ext) => (
208
+
<ExtensionDisableCard ext={ext} />
209
+
))}
210
+
</div>
211
+
) : null}
212
+
</div>
213
+
);
214
+
}
215
+
216
+
export function UpdateText({ state, setState }: { state: ErrorState; setState: (state: ErrorState) => void }) {
217
+
if (!state.__moonlight_update) {
218
+
setState({
219
+
...state,
220
+
__moonlight_update: UpdateState.Ready
221
+
});
222
+
}
223
+
const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion);
224
+
225
+
return newVersion == null ? null : (
226
+
<p>{state.__moonlight_update !== undefined ? updateStrings[state.__moonlight_update] : ""}</p>
227
+
);
228
+
}
229
+
230
+
export function UpdateButton({ state, setState }: { state: ErrorState; setState: (state: ErrorState) => void }) {
231
+
const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion);
232
+
return newVersion == null ||
233
+
state.__moonlight_update === UpdateState.Installed ||
234
+
state.__moonlight_update === undefined ? null : (
235
+
<Button
236
+
size={Button.Sizes.LARGE}
237
+
disabled={state.__moonlight_update !== UpdateState.Ready}
238
+
onClick={() => {
239
+
setState({
240
+
...state,
241
+
__moonlight_update: UpdateState.Working
242
+
});
243
+
244
+
MoonbaseSettingsStore.updateMoonlight()
245
+
.then(() => {
246
+
setState({
247
+
...state,
248
+
__moonlight_update: UpdateState.Installed
249
+
});
250
+
})
251
+
.catch((e) => {
252
+
logger.error(e);
253
+
setState({
254
+
...state,
255
+
__moonlight_update: UpdateState.Failed
256
+
});
257
+
});
258
+
}}
259
+
>
260
+
{state.__moonlight_update !== undefined ? buttonStrings[state.__moonlight_update] : ""}
261
+
</Button>
262
+
);
263
+
}
+27
-40
packages/core-extensions/src/moonbase/webpackModules/settings.tsx
+27
-40
packages/core-extensions/src/moonbase/webpackModules/settings.tsx
···
1
1
import settings from "@moonlight-mod/wp/settings_settings";
2
2
import React from "@moonlight-mod/wp/react";
3
3
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
4
-
import { Moonbase, pages } from "@moonlight-mod/wp/moonbase_ui";
5
-
4
+
import { Moonbase, pages, RestartAdviceMessage, Update } from "@moonlight-mod/wp/moonbase_ui";
5
+
import UserSettingsModalActionCreators from "@moonlight-mod/wp/discord/actions/UserSettingsModalActionCreators";
6
+
import Margins from "@moonlight-mod/wp/discord/styles/shared/Margins.css";
6
7
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
7
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
8
-
9
-
import Update from "./ui/update";
10
-
11
-
const { MenuItem, Text, Breadcrumbs } = Components;
12
-
13
-
const Margins = spacepack.require("discord/styles/shared/Margins.css");
14
-
15
-
const { open } = spacepack.findByExports("setSection", "clearSubsection")[0]
16
-
.exports.Z;
8
+
import { Text, Breadcrumbs } from "@moonlight-mod/wp/discord/components/common/index";
9
+
import { MenuItem } from "@moonlight-mod/wp/contextMenu_contextMenu";
17
10
18
11
const notice = {
19
12
stores: [MoonbaseSettingsStore],
20
13
element: () => {
21
14
// Require it here because lazy loading SUX
22
-
const SettingsNotice = spacepack.findByCode(
23
-
"onSaveButtonColor",
24
-
"FocusRingScope"
25
-
)[0].exports.Z;
15
+
const SettingsNotice = spacepack.require("discord/components/common/SettingsNotice").default;
26
16
return (
27
17
<SettingsNotice
28
18
submitting={MoonbaseSettingsStore.submitting}
29
19
onReset={() => {
30
20
MoonbaseSettingsStore.reset();
31
21
}}
32
-
onSave={() => {
33
-
MoonbaseSettingsStore.writeConfig();
22
+
onSave={async () => {
23
+
await MoonbaseSettingsStore.writeConfig();
34
24
}}
35
25
/>
36
26
);
37
27
}
38
28
};
39
29
40
-
function addSection(
41
-
id: string,
42
-
name: string,
43
-
element: React.FunctionComponent
44
-
) {
45
-
settings.addSection(`moonbase-${id}`, name, element, null, -2, notice);
30
+
const oldLocation = MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "oldLocation", false);
31
+
const position = oldLocation ? -2 : -9999;
32
+
33
+
function addSection(id: string, name: string, element: React.FunctionComponent) {
34
+
settings.addSection(`moonbase-${id}`, name, element, null, position, notice);
46
35
}
47
36
48
37
// FIXME: move to component types
···
53
42
54
43
function renderBreadcrumb(crumb: Breadcrumb, last: boolean) {
55
44
return (
56
-
<Text
57
-
variant="heading-lg/semibold"
58
-
tag="h2"
59
-
color={last ? "header-primary" : "header-secondary"}
60
-
>
45
+
<Text variant="heading-lg/semibold" tag="h2" color={last ? "header-primary" : "header-secondary"}>
61
46
{crumb.label}
62
47
</Text>
63
48
);
64
49
}
65
50
66
-
if (
67
-
MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
68
-
"moonbase",
69
-
"sections",
70
-
false
71
-
)
72
-
) {
73
-
settings.addHeader("Moonbase", -2);
51
+
if (!oldLocation) {
52
+
settings.addDivider(position);
53
+
}
54
+
55
+
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "sections", false)) {
56
+
if (oldLocation) settings.addHeader("Moonbase", position);
74
57
75
-
for (const page of pages) {
58
+
const _pages = oldLocation ? pages : pages.reverse();
59
+
for (const page of _pages) {
76
60
addSection(page.id, page.name, () => {
77
61
const breadcrumbs = [
78
62
{ id: "moonbase", label: "Moonbase" },
···
89
73
{page.name}
90
74
</Breadcrumbs>
91
75
76
+
<RestartAdviceMessage />
92
77
<Update />
93
78
94
79
<page.element />
···
96
81
);
97
82
});
98
83
}
84
+
85
+
if (!oldLocation) settings.addHeader("Moonbase", position);
99
86
} else {
100
-
settings.addSection("moonbase", "Moonbase", Moonbase, null, -2, notice);
87
+
settings.addSection("moonbase", "Moonbase", Moonbase, null, position, notice);
101
88
102
89
settings.addSectionMenuItems(
103
90
"moonbase",
···
106
93
key={page.id}
107
94
id={`moonbase-${page.id}`}
108
95
label={page.name}
109
-
action={() => open("moonbase", i)}
96
+
action={() => UserSettingsModalActionCreators.open("moonbase", i.toString())}
110
97
/>
111
98
))
112
99
);
+270
-143
packages/core-extensions/src/moonbase/webpackModules/stores.ts
+270
-143
packages/core-extensions/src/moonbase/webpackModules/stores.ts
···
1
-
import { Config, ExtensionLoadSource } from "@moonlight-mod/types";
1
+
import { Config, ExtensionEnvironment, ExtensionLoadSource, ExtensionSettingsAdvice } from "@moonlight-mod/types";
2
2
import {
3
3
ExtensionState,
4
4
MoonbaseExtension,
5
5
MoonbaseNatives,
6
-
RepositoryManifest
6
+
RepositoryManifest,
7
+
RestartAdvice,
8
+
UpdateState
7
9
} from "../types";
8
10
import { Store } from "@moonlight-mod/wp/discord/packages/flux";
9
11
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
10
12
import getNatives from "../native";
11
13
import { mainRepo } from "@moonlight-mod/types/constants";
12
-
import {
13
-
checkExtensionCompat,
14
-
ExtensionCompat
15
-
} from "@moonlight-mod/core/extension/loader";
14
+
import { checkExtensionCompat, ExtensionCompat } from "@moonlight-mod/core/extension/loader";
16
15
import { CustomComponent } from "@moonlight-mod/types/coreExtensions/moonbase";
16
+
import { NodeEventType } from "@moonlight-mod/types/core/event";
17
+
import { getConfigOption, setConfigOption } from "@moonlight-mod/core/util/config";
18
+
import diff from "microdiff";
17
19
18
20
const logger = moonlight.getLogger("moonbase");
19
21
···
21
23
if (moonlightNode.isBrowser) natives = getNatives();
22
24
23
25
class MoonbaseSettingsStore extends Store<any> {
24
-
private origConfig: Config;
26
+
private initialConfig: Config;
27
+
private savedConfig: Config;
25
28
private config: Config;
26
29
private extensionIndex: number;
27
-
private configComponents: Record<string, Record<string, CustomComponent>> =
28
-
{};
30
+
private configComponents: Record<string, Record<string, CustomComponent>> = {};
29
31
30
32
modified: boolean;
31
33
submitting: boolean;
32
34
installing: boolean;
33
35
36
+
#updateState = UpdateState.Ready;
37
+
get updateState() {
38
+
return this.#updateState;
39
+
}
34
40
newVersion: string | null;
35
41
shouldShowNotice: boolean;
42
+
43
+
restartAdvice = RestartAdvice.NotNeeded;
36
44
37
45
extensions: { [id: number]: MoonbaseExtension };
38
46
updates: {
···
46
54
constructor() {
47
55
super(Dispatcher);
48
56
49
-
this.origConfig = moonlightNode.config;
50
-
this.config = this.clone(this.origConfig);
57
+
this.initialConfig = moonlightNode.config;
58
+
this.savedConfig = moonlightNode.config;
59
+
this.config = this.clone(this.savedConfig);
51
60
this.extensionIndex = 0;
52
61
53
62
this.modified = false;
···
64
73
this.extensions[uniqueId] = {
65
74
...ext,
66
75
uniqueId,
67
-
state: moonlight.enabledExtensions.has(ext.id)
68
-
? ExtensionState.Enabled
69
-
: ExtensionState.Disabled,
76
+
state: moonlight.enabledExtensions.has(ext.id) ? ExtensionState.Enabled : ExtensionState.Disabled,
70
77
compat: checkExtensionCompat(ext.manifest),
71
78
hasUpdate: false
72
79
};
73
80
}
74
81
75
-
natives!
76
-
.fetchRepositories(this.config.repositories)
77
-
.then((ret) => {
78
-
for (const [repo, exts] of Object.entries(ret)) {
79
-
try {
80
-
for (const ext of exts) {
81
-
const uniqueId = this.extensionIndex++;
82
-
const extensionData = {
83
-
id: ext.id,
84
-
uniqueId,
85
-
manifest: ext,
86
-
source: { type: ExtensionLoadSource.Normal, url: repo },
87
-
state: ExtensionState.NotDownloaded,
88
-
compat: ExtensionCompat.Compatible,
89
-
hasUpdate: false
90
-
};
82
+
// This is async but we're calling it without
83
+
this.checkUpdates();
91
84
92
-
// Don't present incompatible updates
93
-
if (checkExtensionCompat(ext) !== ExtensionCompat.Compatible)
94
-
continue;
85
+
// Update our state if another extension edited the config programatically
86
+
moonlightNode.events.addEventListener(NodeEventType.ConfigSaved, (config) => {
87
+
if (!this.submitting) {
88
+
this.config = this.clone(config);
89
+
// NOTE: This is also async but we're calling it without
90
+
this.processConfigChanged();
91
+
}
92
+
});
93
+
}
95
94
96
-
const existing = this.getExisting(extensionData);
97
-
if (existing != null) {
98
-
// Make sure the download URL is properly updated
99
-
for (const [id, e] of Object.entries(this.extensions)) {
100
-
if (e.id === ext.id && e.source.url === repo) {
101
-
this.extensions[parseInt(id)].manifest = {
102
-
...e.manifest,
103
-
download: ext.download
104
-
};
105
-
break;
106
-
}
107
-
}
95
+
async checkUpdates() {
96
+
await Promise.all([this.checkExtensionUpdates(), this.checkMoonlightUpdates()]);
97
+
this.shouldShowNotice = this.newVersion != null || Object.keys(this.updates).length > 0;
98
+
this.emitChange();
99
+
}
100
+
101
+
private async checkExtensionUpdates() {
102
+
const repositories = await natives!.fetchRepositories(this.savedConfig.repositories);
103
+
104
+
// Reset update state
105
+
for (const id in this.extensions) {
106
+
const ext = this.extensions[id];
107
+
ext.hasUpdate = false;
108
+
ext.changelog = undefined;
109
+
}
110
+
this.updates = {};
111
+
112
+
for (const [repo, exts] of Object.entries(repositories)) {
113
+
for (const ext of exts) {
114
+
const uniqueId = this.extensionIndex++;
115
+
const extensionData = {
116
+
id: ext.id,
117
+
uniqueId,
118
+
manifest: ext,
119
+
source: { type: ExtensionLoadSource.Normal, url: repo },
120
+
state: ExtensionState.NotDownloaded,
121
+
compat: ExtensionCompat.Compatible,
122
+
hasUpdate: false
123
+
};
108
124
109
-
if (this.hasUpdate(extensionData)) {
110
-
this.updates[existing.uniqueId] = {
111
-
version: ext.version!,
112
-
download: ext.download,
113
-
updateManifest: ext
114
-
};
115
-
existing.hasUpdate = true;
116
-
}
125
+
// Don't present incompatible updates
126
+
if (checkExtensionCompat(ext) !== ExtensionCompat.Compatible) continue;
117
127
118
-
continue;
119
-
}
128
+
const existing = this.getExisting(extensionData);
129
+
if (existing != null) {
130
+
// Make sure the download URL is properly updated
131
+
existing.manifest = {
132
+
...existing.manifest,
133
+
download: ext.download
134
+
};
120
135
121
-
this.extensions[uniqueId] = extensionData;
122
-
}
123
-
} catch (e) {
124
-
logger.error(`Error processing repository ${repo}`, e);
136
+
if (this.hasUpdate(extensionData)) {
137
+
this.updates[existing.uniqueId] = {
138
+
version: ext.version!,
139
+
download: ext.download,
140
+
updateManifest: ext
141
+
};
142
+
existing.hasUpdate = true;
143
+
existing.changelog = ext.meta?.changelog;
125
144
}
145
+
} else {
146
+
this.extensions[uniqueId] = extensionData;
126
147
}
148
+
}
149
+
}
150
+
}
127
151
128
-
this.emitChange();
129
-
})
130
-
.then(() =>
131
-
this.getExtensionConfigRaw("moonbase", "updateChecking", true)
132
-
? natives!.checkForMoonlightUpdate()
133
-
: new Promise<null>((resolve) => resolve(null))
134
-
)
135
-
.then((version) => {
136
-
this.newVersion = version;
137
-
this.emitChange();
138
-
})
139
-
.then(() => {
140
-
this.shouldShowNotice =
141
-
this.newVersion != null || Object.keys(this.updates).length > 0;
142
-
this.emitChange();
143
-
});
152
+
private async checkMoonlightUpdates() {
153
+
this.newVersion = this.getExtensionConfigRaw("moonbase", "updateChecking", true)
154
+
? await natives!.checkForMoonlightUpdate()
155
+
: null;
144
156
}
145
157
146
158
private getExisting(ext: MoonbaseExtension) {
147
-
return Object.values(this.extensions).find(
148
-
(e) => e.id === ext.id && e.source.url === ext.source.url
149
-
);
159
+
return Object.values(this.extensions).find((e) => e.id === ext.id && e.source.url === ext.source.url);
150
160
}
151
161
152
162
private hasUpdate(ext: MoonbaseExtension) {
153
-
const existing = Object.values(this.extensions).find(
154
-
(e) => e.id === ext.id && e.source.url === ext.source.url
155
-
);
163
+
const existing = Object.values(this.extensions).find((e) => e.id === ext.id && e.source.url === ext.source.url);
156
164
if (existing == null) return false;
157
165
158
-
return (
159
-
existing.manifest.version !== ext.manifest.version &&
160
-
existing.state !== ExtensionState.NotDownloaded
161
-
);
166
+
return existing.manifest.version !== ext.manifest.version && existing.state !== ExtensionState.NotDownloaded;
162
167
}
163
168
164
169
// Jank
165
170
private isModified() {
166
-
const orig = JSON.stringify(this.origConfig);
171
+
const orig = JSON.stringify(this.savedConfig);
167
172
const curr = JSON.stringify(this.config);
168
173
return orig !== curr;
169
174
}
···
172
177
return this.submitting || this.installing;
173
178
}
174
179
180
+
// Required for the settings store contract
175
181
showNotice() {
176
182
return this.modified;
177
183
}
···
181
187
}
182
188
183
189
getExtensionUniqueId(id: string) {
184
-
return Object.values(this.extensions).find((ext) => ext.id === id)
185
-
?.uniqueId;
190
+
return Object.values(this.extensions).find((ext) => ext.id === id)?.uniqueId;
186
191
}
187
192
188
193
getExtensionConflicting(uniqueId: number) {
189
194
const ext = this.getExtension(uniqueId);
190
195
if (ext.state !== ExtensionState.NotDownloaded) return false;
191
196
return Object.values(this.extensions).some(
192
-
(e) =>
193
-
e.id === ext.id &&
194
-
e.uniqueId !== uniqueId &&
195
-
e.state !== ExtensionState.NotDownloaded
197
+
(e) => e.id === ext.id && e.uniqueId !== uniqueId && e.state !== ExtensionState.NotDownloaded
196
198
);
197
199
}
198
200
···
215
217
216
218
getExtensionConfig<T>(uniqueId: number, key: string): T | undefined {
217
219
const ext = this.getExtension(uniqueId);
218
-
const defaultValue = ext.manifest.settings?.[key]?.default;
219
-
const clonedDefaultValue = this.clone(defaultValue);
220
-
const cfg = this.config.extensions[ext.id];
221
-
222
-
if (cfg == null || typeof cfg === "boolean") return clonedDefaultValue;
223
-
return cfg.config?.[key] ?? clonedDefaultValue;
220
+
const settings = ext.settingsOverride ?? ext.manifest.settings;
221
+
return getConfigOption(ext.id, key, this.config, settings);
224
222
}
225
223
226
-
getExtensionConfigRaw<T>(
227
-
id: string,
228
-
key: string,
229
-
defaultValue: T | undefined
230
-
): T | undefined {
224
+
getExtensionConfigRaw<T>(id: string, key: string, defaultValue: T | undefined): T | undefined {
231
225
const cfg = this.config.extensions[id];
232
-
233
226
if (cfg == null || typeof cfg === "boolean") return defaultValue;
234
227
return cfg.config?.[key] ?? defaultValue;
235
228
}
236
229
237
230
getExtensionConfigName(uniqueId: number, key: string) {
238
231
const ext = this.getExtension(uniqueId);
239
-
return ext.manifest.settings?.[key]?.displayName ?? key;
232
+
const settings = ext.settingsOverride ?? ext.manifest.settings;
233
+
return settings?.[key]?.displayName ?? key;
240
234
}
241
235
242
236
getExtensionConfigDescription(uniqueId: number, key: string) {
243
237
const ext = this.getExtension(uniqueId);
244
-
return ext.manifest.settings?.[key]?.description;
238
+
const settings = ext.settingsOverride ?? ext.manifest.settings;
239
+
return settings?.[key]?.description;
245
240
}
246
241
247
242
setExtensionConfig(id: string, key: string, value: any) {
248
-
const oldConfig = this.config.extensions[id];
249
-
const newConfig =
250
-
typeof oldConfig === "boolean"
251
-
? {
252
-
enabled: oldConfig,
253
-
config: { [key]: value }
254
-
}
255
-
: {
256
-
...oldConfig,
257
-
config: { ...(oldConfig?.config ?? {}), [key]: value }
258
-
};
259
-
260
-
this.config.extensions[id] = newConfig;
243
+
setConfigOption(this.config, id, key, value);
261
244
this.modified = this.isModified();
262
245
this.emitChange();
263
246
}
···
267
250
let val = this.config.extensions[ext.id];
268
251
269
252
if (val == null) {
270
-
this.config.extensions[ext.id] = { enabled };
253
+
this.config.extensions[ext.id] = enabled;
271
254
this.modified = this.isModified();
272
255
this.emitChange();
273
256
return;
···
284
267
this.emitChange();
285
268
}
286
269
270
+
dismissAllExtensionUpdates() {
271
+
for (const id in this.extensions) {
272
+
this.extensions[id].hasUpdate = false;
273
+
}
274
+
this.emitChange();
275
+
}
276
+
277
+
async updateAllExtensions() {
278
+
for (const id of Object.keys(this.updates)) {
279
+
try {
280
+
await this.installExtension(parseInt(id));
281
+
} catch (e) {
282
+
logger.error("Error bulk updating extension", id, e);
283
+
}
284
+
}
285
+
}
286
+
287
287
async installExtension(uniqueId: number) {
288
288
const ext = this.getExtension(uniqueId);
289
289
if (!("download" in ext.manifest)) {
···
299
299
this.extensions[uniqueId].state = ExtensionState.Disabled;
300
300
}
301
301
302
-
if (update != null)
303
-
this.extensions[uniqueId].compat = checkExtensionCompat(
304
-
update.updateManifest
305
-
);
302
+
if (update != null) {
303
+
const existing = this.extensions[uniqueId];
304
+
existing.settingsOverride = update.updateManifest.settings;
305
+
existing.compat = checkExtensionCompat(update.updateManifest);
306
+
existing.manifest = update.updateManifest;
307
+
existing.changelog = update.updateManifest.meta?.changelog;
308
+
}
306
309
307
310
delete this.updates[uniqueId];
308
311
} catch (e) {
···
310
313
}
311
314
312
315
this.installing = false;
316
+
this.restartAdvice = this.#computeRestartAdvice();
313
317
this.emitChange();
314
318
}
315
319
···
335
339
336
340
const deps: Record<string, MoonbaseExtension[]> = {};
337
341
for (const dep of missingDeps) {
338
-
const candidates = Object.values(this.extensions).filter(
339
-
(e) => e.id === dep
340
-
);
342
+
const candidates = Object.values(this.extensions).filter((e) => e.id === dep);
341
343
342
344
deps[dep] = candidates.sort((a, b) => {
343
345
const aRank = this.getRank(a);
344
346
const bRank = this.getRank(b);
345
347
if (aRank === bRank) {
346
-
const repoIndex = this.config.repositories.indexOf(a.source.url!);
347
-
const otherRepoIndex = this.config.repositories.indexOf(
348
-
b.source.url!
349
-
);
348
+
const repoIndex = this.savedConfig.repositories.indexOf(a.source.url!);
349
+
const otherRepoIndex = this.savedConfig.repositories.indexOf(b.source.url!);
350
350
return repoIndex - otherRepoIndex;
351
351
} else {
352
352
return bRank - aRank;
···
370
370
}
371
371
372
372
this.installing = false;
373
+
this.restartAdvice = this.#computeRestartAdvice();
373
374
this.emitChange();
374
375
}
375
376
376
377
async updateMoonlight() {
377
-
await natives.updateMoonlight();
378
+
this.#updateState = UpdateState.Working;
379
+
this.emitChange();
380
+
381
+
await natives
382
+
.updateMoonlight()
383
+
.then(() => (this.#updateState = UpdateState.Installed))
384
+
.catch((e) => {
385
+
logger.error(e);
386
+
this.#updateState = UpdateState.Failed;
387
+
});
388
+
389
+
this.emitChange();
378
390
}
379
391
380
392
getConfigOption<K extends keyof Config>(key: K): Config[K] {
···
392
404
return (uniqueId != null ? this.getExtensionName(uniqueId) : null) ?? id;
393
405
}
394
406
395
-
registerConfigComponent(
396
-
ext: string,
397
-
name: string,
398
-
component: CustomComponent
399
-
) {
407
+
registerConfigComponent(ext: string, name: string, component: CustomComponent) {
400
408
if (!(ext in this.configComponents)) this.configComponents[ext] = {};
401
409
this.configComponents[ext][name] = component;
402
410
}
···
405
413
return this.configComponents[ext]?.[name];
406
414
}
407
415
408
-
writeConfig() {
409
-
this.submitting = true;
416
+
#computeRestartAdvice() {
417
+
// If moonlight update needs a restart, always hide advice.
418
+
if (this.#updateState === UpdateState.Installed) return RestartAdvice.NotNeeded;
419
+
420
+
const i = this.initialConfig; // Initial config, from startup
421
+
const n = this.config; // New config about to be saved
422
+
423
+
let returnedAdvice = RestartAdvice.NotNeeded;
424
+
const updateAdvice = (r: RestartAdvice) => (returnedAdvice < r ? (returnedAdvice = r) : returnedAdvice);
425
+
426
+
// Top-level keys, repositories is not needed here because Moonbase handles it.
427
+
if (i.patchAll !== n.patchAll) updateAdvice(RestartAdvice.ReloadNeeded);
428
+
if (i.loggerLevel !== n.loggerLevel) updateAdvice(RestartAdvice.ReloadNeeded);
429
+
if (diff(i.devSearchPaths ?? [], n.devSearchPaths ?? [], { cyclesFix: false }).length !== 0)
430
+
return updateAdvice(RestartAdvice.RestartNeeded);
410
431
411
-
moonlightNode.writeConfig(this.config);
412
-
this.origConfig = this.clone(this.config);
432
+
// Extension specific logic
433
+
for (const id in n.extensions) {
434
+
// Installed extension (might not be detected yet)
435
+
const ext = Object.values(this.extensions).find((e) => e.id === id && e.state !== ExtensionState.NotDownloaded);
436
+
// Installed and detected extension
437
+
const detected = moonlightNode.extensions.find((e) => e.id === id);
413
438
414
-
this.submitting = false;
439
+
// If it's not installed at all, we don't care
440
+
if (!ext) continue;
441
+
442
+
const initState = i.extensions[id];
443
+
const newState = n.extensions[id];
444
+
445
+
const newEnabled = typeof newState === "boolean" ? newState : newState.enabled;
446
+
// If it's enabled but not detected yet, restart.
447
+
if (newEnabled && !detected) {
448
+
return updateAdvice(RestartAdvice.RestartNeeded);
449
+
}
450
+
451
+
// Toggling extensions specifically wants to rely on the initial state,
452
+
// that's what was considered when loading extensions.
453
+
const initEnabled = initState && (typeof initState === "boolean" ? initState : initState.enabled);
454
+
if (initEnabled !== newEnabled || detected?.manifest.version !== ext.manifest.version) {
455
+
// If we have the extension locally, we confidently know if it has host/preload scripts.
456
+
// If not, we have to respect the environment specified in the manifest.
457
+
// If that is the default, we can't know what's needed.
458
+
459
+
if (detected?.scripts.hostPath || detected?.scripts.nodePath) {
460
+
return updateAdvice(RestartAdvice.RestartNeeded);
461
+
}
462
+
463
+
switch (ext.manifest.environment) {
464
+
case ExtensionEnvironment.Both:
465
+
case ExtensionEnvironment.Web:
466
+
updateAdvice(RestartAdvice.ReloadNeeded);
467
+
continue;
468
+
case ExtensionEnvironment.Desktop:
469
+
return updateAdvice(RestartAdvice.RestartNeeded);
470
+
default:
471
+
updateAdvice(RestartAdvice.ReloadNeeded);
472
+
continue;
473
+
}
474
+
}
475
+
476
+
const initConfig = typeof initState === "boolean" ? {} : { ...initState?.config };
477
+
const newConfig = typeof newState === "boolean" ? {} : { ...newState?.config };
478
+
479
+
const def = ext.manifest.settings;
480
+
if (!def) continue;
481
+
482
+
for (const key in def) {
483
+
const defaultValue = def[key].default;
484
+
485
+
initConfig[key] ??= defaultValue;
486
+
newConfig[key] ??= defaultValue;
487
+
}
488
+
489
+
const changedKeys = diff(initConfig, newConfig, { cyclesFix: false }).map((c) => c.path[0]);
490
+
for (const key in def) {
491
+
if (!changedKeys.includes(key)) continue;
492
+
493
+
const advice = def[key].advice;
494
+
switch (advice) {
495
+
case ExtensionSettingsAdvice.None:
496
+
updateAdvice(RestartAdvice.NotNeeded);
497
+
continue;
498
+
case ExtensionSettingsAdvice.Reload:
499
+
updateAdvice(RestartAdvice.ReloadNeeded);
500
+
continue;
501
+
case ExtensionSettingsAdvice.Restart:
502
+
updateAdvice(RestartAdvice.RestartNeeded);
503
+
continue;
504
+
default:
505
+
updateAdvice(RestartAdvice.ReloadSuggested);
506
+
}
507
+
}
508
+
}
509
+
510
+
return returnedAdvice;
511
+
}
512
+
513
+
async writeConfig() {
514
+
try {
515
+
this.submitting = true;
516
+
this.emitChange();
517
+
518
+
await moonlightNode.writeConfig(this.config);
519
+
await this.processConfigChanged();
520
+
} finally {
521
+
this.submitting = false;
522
+
this.emitChange();
523
+
}
524
+
}
525
+
526
+
private async processConfigChanged() {
527
+
this.savedConfig = this.clone(this.config);
528
+
this.restartAdvice = this.#computeRestartAdvice();
415
529
this.modified = false;
530
+
531
+
const modifiedRepos = diff(this.savedConfig.repositories, this.config.repositories);
532
+
if (modifiedRepos.length !== 0) await this.checkUpdates();
533
+
416
534
this.emitChange();
417
535
}
418
536
419
537
reset() {
420
538
this.submitting = false;
421
539
this.modified = false;
422
-
this.config = this.clone(this.origConfig);
540
+
this.config = this.clone(this.savedConfig);
423
541
this.emitChange();
542
+
}
543
+
544
+
restartDiscord() {
545
+
if (moonlightNode.isBrowser) {
546
+
window.location.reload();
547
+
} else {
548
+
// @ts-expect-error TODO: DiscordNative
549
+
window.DiscordNative.app.relaunch();
550
+
}
424
551
}
425
552
426
553
// Required because electron likes to make it immutable sometimes.
+47
packages/core-extensions/src/moonbase/webpackModules/ui/HelpMessage.tsx
+47
packages/core-extensions/src/moonbase/webpackModules/ui/HelpMessage.tsx
···
1
+
import React from "@moonlight-mod/wp/react";
2
+
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
3
+
import { Text } from "@moonlight-mod/wp/discord/components/common/index";
4
+
import HelpMessageClasses from "@moonlight-mod/wp/discord/components/common/HelpMessage.css";
5
+
import Margins from "@moonlight-mod/wp/discord/styles/shared/Margins.css";
6
+
7
+
// reimpl of HelpMessage but with a custom icon
8
+
export default function HelpMessage({
9
+
className,
10
+
text,
11
+
icon,
12
+
children,
13
+
type = "info"
14
+
}: {
15
+
className?: string;
16
+
text: string;
17
+
icon: React.ComponentType<any>;
18
+
type?: "warning" | "positive" | "error" | "info";
19
+
children?: React.ReactNode;
20
+
}) {
21
+
return (
22
+
<div
23
+
className={`${Margins.marginBottom20} ${HelpMessageClasses[type]} ${HelpMessageClasses.container} moonbase-help-message ${className}`}
24
+
>
25
+
<Flex direction={Flex.Direction.HORIZONTAL}>
26
+
<div
27
+
className={HelpMessageClasses.iconDiv}
28
+
style={{
29
+
alignItems: "center"
30
+
}}
31
+
>
32
+
{React.createElement(icon, {
33
+
size: "sm",
34
+
color: "currentColor",
35
+
className: HelpMessageClasses.icon
36
+
})}
37
+
</div>
38
+
39
+
<Text variant="text-sm/medium" color="currentColor" className={HelpMessageClasses.text}>
40
+
{text}
41
+
</Text>
42
+
43
+
{children}
44
+
</Flex>
45
+
</div>
46
+
);
47
+
}
+43
packages/core-extensions/src/moonbase/webpackModules/ui/RestartAdvice.tsx
+43
packages/core-extensions/src/moonbase/webpackModules/ui/RestartAdvice.tsx
···
1
+
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
2
+
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
3
+
import { Button, CircleWarningIcon } from "@moonlight-mod/wp/discord/components/common/index";
4
+
import React from "@moonlight-mod/wp/react";
5
+
import { RestartAdvice } from "../../types";
6
+
import HelpMessage from "./HelpMessage";
7
+
8
+
const strings: Record<RestartAdvice, string> = {
9
+
[RestartAdvice.NotNeeded]: "how did you even",
10
+
[RestartAdvice.ReloadSuggested]: "A reload might be needed to apply some of the changed options.",
11
+
[RestartAdvice.ReloadNeeded]: "A reload is needed to apply some of the changed options.",
12
+
[RestartAdvice.RestartNeeded]: "A restart is needed to apply some of the changed options."
13
+
};
14
+
15
+
const buttonStrings: Record<RestartAdvice, string> = {
16
+
[RestartAdvice.NotNeeded]: "huh?",
17
+
[RestartAdvice.ReloadSuggested]: "Reload",
18
+
[RestartAdvice.ReloadNeeded]: "Reload",
19
+
[RestartAdvice.RestartNeeded]: "Restart"
20
+
};
21
+
22
+
const actions: Record<RestartAdvice, () => void> = {
23
+
[RestartAdvice.NotNeeded]: () => {},
24
+
[RestartAdvice.ReloadSuggested]: () => window.location.reload(),
25
+
[RestartAdvice.ReloadNeeded]: () => window.location.reload(),
26
+
[RestartAdvice.RestartNeeded]: () => MoonbaseSettingsStore.restartDiscord()
27
+
};
28
+
29
+
export default function RestartAdviceMessage() {
30
+
const restartAdvice = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.restartAdvice);
31
+
32
+
if (restartAdvice === RestartAdvice.NotNeeded) return null;
33
+
34
+
return (
35
+
<div className="moonbase-help-message-sticky">
36
+
<HelpMessage text={strings[restartAdvice]} icon={CircleWarningIcon} type="warning">
37
+
<Button color={Button.Colors.YELLOW} size={Button.Sizes.TINY} onClick={actions[restartAdvice]}>
38
+
{buttonStrings[restartAdvice]}
39
+
</Button>
40
+
</HelpMessage>
41
+
</div>
42
+
);
43
+
}
+110
packages/core-extensions/src/moonbase/webpackModules/ui/about.tsx
+110
packages/core-extensions/src/moonbase/webpackModules/ui/about.tsx
···
1
+
import {
2
+
Text,
3
+
useThemeContext,
4
+
Button,
5
+
AngleBracketsIcon,
6
+
BookCheckIcon,
7
+
ClydeIcon
8
+
} from "@moonlight-mod/wp/discord/components/common/index";
9
+
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
10
+
import React from "@moonlight-mod/wp/react";
11
+
import MarkupUtils from "@moonlight-mod/wp/discord/modules/markup/MarkupUtils";
12
+
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
13
+
14
+
const wordmark = "https://raw.githubusercontent.com/moonlight-mod/moonlight/refs/heads/main/img/wordmark.png";
15
+
const wordmarkLight =
16
+
"https://raw.githubusercontent.com/moonlight-mod/moonlight/refs/heads/main/img/wordmark-light.png";
17
+
18
+
function parse(str: string) {
19
+
return MarkupUtils.parse(str, true, {
20
+
allowHeading: true,
21
+
allowLinks: true,
22
+
allowList: true
23
+
});
24
+
}
25
+
26
+
function Dev({ name, picture, link }: { name: string; picture: string; link: string }) {
27
+
return (
28
+
<Button onClick={() => window.open(link)} color={Button.Colors.PRIMARY} className="moonbase-dev">
29
+
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.CENTER} className="moonbase-gap">
30
+
<img src={picture} alt={name} className="moonbase-dev-avatar" />
31
+
32
+
<Text variant="text-md/semibold">{name}</Text>
33
+
</Flex>
34
+
</Button>
35
+
);
36
+
}
37
+
38
+
function IconButton({
39
+
text,
40
+
link,
41
+
icon,
42
+
openInClient
43
+
}: {
44
+
text: string;
45
+
link: string;
46
+
icon: React.FC<any>;
47
+
openInClient?: boolean;
48
+
}) {
49
+
return (
50
+
<Button
51
+
onClick={() => {
52
+
if (openInClient) {
53
+
try {
54
+
const { handleClick } = spacepack.require("discord/utils/MaskedLinkUtils");
55
+
handleClick({ href: link });
56
+
} catch {
57
+
window.open(link);
58
+
}
59
+
} else {
60
+
// Will open externally in the user's browser
61
+
window.open(link);
62
+
}
63
+
}}
64
+
>
65
+
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.CENTER} className="moonbase-gap">
66
+
{React.createElement(icon, {
67
+
size: "sm",
68
+
color: "currentColor"
69
+
})}
70
+
{text}
71
+
</Flex>
72
+
</Button>
73
+
);
74
+
}
75
+
76
+
export default function AboutPage() {
77
+
const darkTheme = useThemeContext()?.theme !== "light";
78
+
79
+
return (
80
+
<Flex direction={Flex.Direction.VERTICAL} align={Flex.Align.CENTER} className="moonbase-about-page">
81
+
<img src={darkTheme ? wordmarkLight : wordmark} alt="moonlight wordmark" className="moonbase-wordmark" />
82
+
83
+
<Text variant="heading-lg/medium">created by:</Text>
84
+
<div className="moonbase-devs">
85
+
<Dev name="Cynosphere" picture="https://github.com/Cynosphere.png" link="https://github.com/Cynosphere" />
86
+
<Dev name="NotNite" picture="https://github.com/NotNite.png" link="https://github.com/NotNite" />
87
+
<Dev name="adryd" picture="https://github.com/adryd325.png" link="https://github.com/adryd325" />
88
+
<Dev name="redstonekasi" picture="https://github.com/redstonekasi.png" link="https://github.com/redstonekasi" />
89
+
</div>
90
+
91
+
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.CENTER} className="moonbase-gap">
92
+
<IconButton text="View source" icon={AngleBracketsIcon} link="https://github.com/moonlight-mod/moonlight" />
93
+
<IconButton text="Open the docs" icon={BookCheckIcon} link="https://moonlight-mod.github.io/" />
94
+
<IconButton text="Join the server" icon={ClydeIcon} link="https://discord.gg/FdZBTFCP6F" openInClient={true} />
95
+
</Flex>
96
+
97
+
<Flex direction={Flex.Direction.VERTICAL} align={Flex.Align.START}>
98
+
<Text variant="text-sm/normal">
99
+
{parse(`moonlight \`${window.moonlight.version}\` on \`${window.moonlight.branch}\``)}
100
+
</Text>
101
+
102
+
<Text variant="text-sm/normal">
103
+
{parse(
104
+
"moonlight is licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.html) (`LGPL-3.0-or-later`)."
105
+
)}
106
+
</Text>
107
+
</Flex>
108
+
</Flex>
109
+
);
110
+
}
+18
-43
packages/core-extensions/src/moonbase/webpackModules/ui/config/index.tsx
+18
-43
packages/core-extensions/src/moonbase/webpackModules/ui/config/index.tsx
···
1
1
import { LogLevel } from "@moonlight-mod/types";
2
2
3
-
const logLevels = Object.values(LogLevel).filter(
4
-
(v) => typeof v === "string"
5
-
) as string[];
3
+
const logLevels = Object.values(LogLevel).filter((v) => typeof v === "string") as string[];
6
4
7
5
import React from "@moonlight-mod/wp/react";
8
6
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
···
18
16
Clickable
19
17
} from "@moonlight-mod/wp/discord/components/common/index";
20
18
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
21
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
19
+
import { CircleXIcon } from "@moonlight-mod/wp/discord/components/common/index";
20
+
import Margins from "@moonlight-mod/wp/discord/styles/shared/Margins.css";
21
+
import FormSwitchClasses from "@moonlight-mod/wp/discord/components/common/FormSwitch.css";
22
22
23
23
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
24
24
25
-
const FormClasses = spacepack.findByCode("dividerDefault:")[0].exports;
26
-
const Margins = spacepack.findByCode("marginCenterHorz:")[0].exports;
27
-
28
-
let RemoveButtonClasses: any;
25
+
let GuildSettingsRoleEditClasses: any;
29
26
spacepack
30
27
.lazyLoad(
31
28
"renderArtisanalHack",
···
34
31
)
35
32
.then(
36
33
() =>
37
-
(RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0]
38
-
.exports)
34
+
(GuildSettingsRoleEditClasses = spacepack.require(
35
+
"discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"
36
+
))
39
37
);
40
38
41
-
// FIXME: type component keys
42
-
const { CircleXIcon } = Components;
43
-
44
39
function RemoveEntryButton({ onClick }: { onClick: () => void }) {
45
40
return (
46
-
<div className={RemoveButtonClasses.removeButtonContainer}>
41
+
<div className={GuildSettingsRoleEditClasses.removeButtonContainer}>
47
42
<Tooltip text="Remove entry" position="top">
48
43
{(props: any) => (
49
-
<Clickable
50
-
{...props}
51
-
className={RemoveButtonClasses.removeButton}
52
-
onClick={onClick}
53
-
>
44
+
<Clickable {...props} className={GuildSettingsRoleEditClasses.removeButton} onClick={onClick}>
54
45
<CircleXIcon width={24} height={24} />
55
46
</Clickable>
56
47
)}
···
59
50
);
60
51
}
61
52
62
-
function ArrayFormItem({
63
-
config
64
-
}: {
65
-
config: "repositories" | "devSearchPaths";
66
-
}) {
53
+
function ArrayFormItem({ config }: { config: "repositories" | "devSearchPaths" }) {
67
54
const items = MoonbaseSettingsStore.getConfigOption(config) ?? [];
68
55
return (
69
56
<Flex
···
123
110
<>
124
111
<FormSwitch
125
112
className={Margins.marginTop20}
126
-
value={MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
127
-
"moonbase",
128
-
"updateChecking",
129
-
true
130
-
)}
113
+
value={MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "updateChecking", true) ?? true}
131
114
onChange={(value: boolean) => {
132
-
MoonbaseSettingsStore.setExtensionConfig(
133
-
"moonbase",
134
-
"updateChecking",
135
-
value
136
-
);
115
+
MoonbaseSettingsStore.setExtensionConfig("moonbase", "updateChecking", value);
137
116
}}
138
117
note="Checks for updates to moonlight"
139
118
>
140
119
Automatic update checking
141
120
</FormSwitch>
142
121
<FormItem title="Repositories">
143
-
<FormText className={Margins.marginBottom4}>
144
-
A list of remote repositories to display extensions from
145
-
</FormText>
122
+
<FormText className={Margins.marginBottom4}>A list of remote repositories to display extensions from</FormText>
146
123
<ArrayFormItem config="repositories" />
147
124
</FormItem>
148
-
<FormDivider className={FormClasses.dividerDefault} />
125
+
<FormDivider className={FormSwitchClasses.dividerDefault} />
149
126
<FormItem title="Extension search paths" className={Margins.marginTop20}>
150
127
<FormText className={Margins.marginBottom4}>
151
128
A list of local directories to search for built extensions
152
129
</FormText>
153
130
<ArrayFormItem config="devSearchPaths" />
154
131
</FormItem>
155
-
<FormDivider className={FormClasses.dividerDefault} />
132
+
<FormDivider className={FormSwitchClasses.dividerDefault} />
156
133
<FormSwitch
157
134
className={Margins.marginTop20}
158
-
value={MoonbaseSettingsStore.getConfigOption("patchAll")}
135
+
value={MoonbaseSettingsStore.getConfigOption("patchAll") ?? false}
159
136
onChange={(value: boolean) => {
160
137
MoonbaseSettingsStore.setConfigOption("patchAll", value);
161
138
}}
···
172
149
value: o.toLowerCase(),
173
150
label: o[0] + o.slice(1).toLowerCase()
174
151
}))}
175
-
onChange={(v) =>
176
-
MoonbaseSettingsStore.setConfigOption("loggerLevel", v)
177
-
}
152
+
onChange={(v) => MoonbaseSettingsStore.setConfigOption("loggerLevel", v)}
178
153
/>
179
154
</FormItem>
180
155
</>
+253
-194
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/card.tsx
+253
-194
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/card.tsx
···
1
1
import { ExtensionState } from "../../../types";
2
-
import { ExtensionLoadSource } from "@moonlight-mod/types";
2
+
import { constants, ExtensionLoadSource, ExtensionTag } from "@moonlight-mod/types";
3
+
3
4
import { ExtensionCompat } from "@moonlight-mod/core/extension/loader";
4
-
5
-
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
6
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
5
+
import {
6
+
ScienceIcon,
7
+
DownloadIcon,
8
+
TrashIcon,
9
+
AngleBracketsIcon,
10
+
Tooltip,
11
+
Card,
12
+
Text,
13
+
FormSwitch,
14
+
TabBar,
15
+
Button,
16
+
ChannelListIcon,
17
+
HeartIcon,
18
+
WindowTopOutlineIcon,
19
+
WarningIcon
20
+
} from "@moonlight-mod/wp/discord/components/common/index";
7
21
import React from "@moonlight-mod/wp/react";
8
22
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
9
23
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
10
24
import MarkupUtils from "@moonlight-mod/wp/discord/modules/markup/MarkupUtils";
11
-
import IntegrationCard from "@moonlight-mod/wp/discord/modules/guild_settings/IntegrationCard.css";
12
-
25
+
import AppCardClasses from "@moonlight-mod/wp/discord/modules/guild_settings/web/AppCard.css";
26
+
import PanelButton from "@moonlight-mod/wp/discord/components/common/PanelButton";
27
+
import DiscoveryClasses from "@moonlight-mod/wp/discord/modules/discovery/web/Discovery.css";
28
+
import MarkupClasses from "@moonlight-mod/wp/discord/modules/messages/web/Markup.css";
29
+
import BuildOverrideClasses from "@moonlight-mod/wp/discord/modules/build_overrides/web/BuildOverride.css";
30
+
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
31
+
import ErrorBoundary from "@moonlight-mod/wp/common_ErrorBoundary";
13
32
import ExtensionInfo from "./info";
14
33
import Settings from "./settings";
15
-
import installWithDependencyPopup from "./popup";
34
+
import { doGenericExtensionPopup, doMissingExtensionPopup } from "./popup";
16
35
17
36
export enum ExtensionPage {
18
37
Info,
19
38
Description,
39
+
Changelog,
20
40
Settings
21
41
}
22
42
23
-
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
24
-
25
-
const { BeakerIcon, DownloadIcon, TrashIcon, CircleWarningIcon, Tooltip } =
26
-
Components;
27
-
28
-
const PanelButton = spacepack.findByCode("Masks.PANEL_BUTTON")[0].exports.Z;
29
-
const TabBarClasses = spacepack.findByExports(
30
-
"tabBar",
31
-
"tabBarItem",
32
-
"headerContentWrapper"
33
-
)[0].exports;
34
-
const MarkupClasses = spacepack.findByExports("markup", "inlineFormat")[0]
35
-
.exports;
36
-
37
-
const BuildOverrideClasses = spacepack.findByExports(
38
-
"disabledButtonOverride"
39
-
)[0].exports;
40
-
41
43
const COMPAT_TEXT_MAP: Record<ExtensionCompat, string> = {
42
44
[ExtensionCompat.Compatible]: "huh?",
43
45
[ExtensionCompat.InvalidApiLevel]: "Incompatible API level",
44
46
[ExtensionCompat.InvalidEnvironment]: "Incompatible platform"
45
47
};
46
-
47
-
export default function ExtensionCard({ uniqueId }: { uniqueId: number }) {
48
-
const [tab, setTab] = React.useState(ExtensionPage.Info);
49
-
const [restartNeeded, setRestartNeeded] = React.useState(false);
48
+
const CONFLICTING_TEXT = "This extension is already installed from another source.";
50
49
51
-
const { ext, enabled, busy, update, conflicting } = useStateFromStores(
52
-
[MoonbaseSettingsStore],
53
-
() => {
54
-
return {
55
-
ext: MoonbaseSettingsStore.getExtension(uniqueId),
56
-
enabled: MoonbaseSettingsStore.getExtensionEnabled(uniqueId),
57
-
busy: MoonbaseSettingsStore.busy,
58
-
update: MoonbaseSettingsStore.getExtensionUpdate(uniqueId),
59
-
conflicting: MoonbaseSettingsStore.getExtensionConflicting(uniqueId)
60
-
};
61
-
}
50
+
function PanelLinkButton({ icon, tooltip, link }: { icon: React.ReactNode; tooltip: string; link: string }) {
51
+
return (
52
+
<PanelButton
53
+
icon={icon}
54
+
tooltipText={tooltip}
55
+
onClick={() => {
56
+
window.open(link);
57
+
}}
58
+
/>
62
59
);
60
+
}
63
61
64
-
// Why it work like that :sob:
65
-
if (ext == null) return <></>;
62
+
export default function ExtensionCard({ uniqueId, selectTag }: { uniqueId: number; selectTag: (tag: string) => void }) {
63
+
const { ext, enabled, busy, update, conflicting } = useStateFromStores([MoonbaseSettingsStore], () => {
64
+
return {
65
+
ext: MoonbaseSettingsStore.getExtension(uniqueId),
66
+
enabled: MoonbaseSettingsStore.getExtensionEnabled(uniqueId),
67
+
busy: MoonbaseSettingsStore.busy,
68
+
update: MoonbaseSettingsStore.getExtensionUpdate(uniqueId),
69
+
conflicting: MoonbaseSettingsStore.getExtensionConflicting(uniqueId)
70
+
};
71
+
});
66
72
67
-
const { Card, Text, FormSwitch, TabBar, Button } = Components;
73
+
const [tab, setTab] = React.useState(
74
+
update != null && ext?.changelog != null ? ExtensionPage.Changelog : ExtensionPage.Info
75
+
);
68
76
69
77
const tagline = ext.manifest?.meta?.tagline;
70
-
const settings = ext.manifest?.settings;
78
+
const settings = ext.settingsOverride ?? ext.manifest?.settings;
71
79
const description = ext.manifest?.meta?.description;
80
+
const changelog = ext.changelog;
81
+
const linkButtons = [
82
+
ext?.manifest?.meta?.source && (
83
+
<PanelLinkButton icon={<AngleBracketsIcon />} tooltip="View source" link={ext.manifest.meta.source} />
84
+
),
85
+
ext?.source?.url && <PanelLinkButton icon={<ChannelListIcon />} tooltip="View repository" link={ext.source.url} />,
86
+
ext?.manifest?.meta?.donate && (
87
+
<PanelLinkButton icon={<HeartIcon />} tooltip="Donate" link={ext.manifest.meta.donate} />
88
+
)
89
+
].filter((x) => x != null);
90
+
72
91
const enabledDependants = useStateFromStores([MoonbaseSettingsStore], () =>
73
92
Object.keys(MoonbaseSettingsStore.extensions)
74
93
.filter((uniqueId) => {
75
-
const potentialDependant = MoonbaseSettingsStore.getExtension(
76
-
parseInt(uniqueId)
77
-
);
94
+
const potentialDependant = MoonbaseSettingsStore.getExtension(parseInt(uniqueId));
78
95
79
96
return (
80
-
potentialDependant.manifest.dependencies?.includes(ext.id) &&
97
+
potentialDependant.manifest.dependencies?.includes(ext?.id) &&
81
98
MoonbaseSettingsStore.getExtensionEnabled(parseInt(uniqueId))
82
99
);
83
100
})
···
85
102
);
86
103
const implicitlyEnabled = enabledDependants.length > 0;
87
104
88
-
return (
89
-
<Card editable={true} className={IntegrationCard.card}>
90
-
<div className={IntegrationCard.cardHeader}>
105
+
const hasDuplicateEntry = useStateFromStores([MoonbaseSettingsStore], () =>
106
+
Object.entries(MoonbaseSettingsStore.extensions).some(
107
+
([otherUniqueId, otherExt]) =>
108
+
otherExt != null && otherExt?.id === ext?.id && parseInt(otherUniqueId) !== uniqueId
109
+
)
110
+
);
111
+
112
+
return ext == null ? (
113
+
<></>
114
+
) : (
115
+
<Card editable={true} className={AppCardClasses.card}>
116
+
<div className={AppCardClasses.cardHeader}>
91
117
<Flex direction={Flex.Direction.VERTICAL}>
92
118
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.CENTER}>
93
-
<Text variant="text-md/semibold">
94
-
{ext.manifest?.meta?.name ?? ext.id}
95
-
</Text>
119
+
<Text variant="text-md/semibold">{ext.manifest?.meta?.name ?? ext.id}</Text>
96
120
{ext.source.type === ExtensionLoadSource.Developer && (
97
121
<Tooltip text="This is a local extension" position="top">
98
-
{(props: any) => (
99
-
<BeakerIcon
100
-
{...props}
101
-
class={BuildOverrideClasses.infoIcon}
102
-
size="xs"
103
-
/>
104
-
)}
122
+
{(props: any) => <ScienceIcon {...props} class={BuildOverrideClasses.infoIcon} size="xs" />}
123
+
</Tooltip>
124
+
)}
125
+
126
+
{hasDuplicateEntry && ext?.source?.url && (
127
+
<Tooltip text={`This extension is from the following repository: ${ext.source.url}`} position="top">
128
+
{(props: any) => <WindowTopOutlineIcon {...props} class={BuildOverrideClasses.infoIcon} size="xs" />}
129
+
</Tooltip>
130
+
)}
131
+
132
+
{ext.manifest?.meta?.deprecated && (
133
+
<Tooltip text="This extension is deprecated" position="top">
134
+
{(props: any) => <WarningIcon {...props} class={BuildOverrideClasses.infoIcon} size="xs" />}
105
135
</Tooltip>
106
136
)}
107
137
</Flex>
108
138
109
-
{tagline != null && (
110
-
<Text variant="text-sm/normal">{MarkupUtils.parse(tagline)}</Text>
111
-
)}
139
+
{tagline != null && <Text variant="text-sm/normal">{MarkupUtils.parse(tagline)}</Text>}
112
140
</Flex>
113
141
114
-
<Flex
115
-
direction={Flex.Direction.HORIZONTAL}
116
-
align={Flex.Align.END}
117
-
justify={Flex.Justify.END}
118
-
>
119
-
{ext.state === ExtensionState.NotDownloaded ? (
120
-
<Tooltip
121
-
text={COMPAT_TEXT_MAP[ext.compat]}
122
-
shouldShow={ext.compat !== ExtensionCompat.Compatible}
123
-
>
124
-
{(props: any) => (
125
-
<Button
126
-
{...props}
127
-
color={Button.Colors.BRAND}
128
-
submitting={busy}
129
-
disabled={
130
-
ext.compat !== ExtensionCompat.Compatible || conflicting
142
+
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.END} justify={Flex.Justify.END}>
143
+
<div
144
+
// too lazy to learn how <Flex /> works lmao
145
+
style={{
146
+
display: "flex",
147
+
alignItems: "center",
148
+
gap: "1rem"
149
+
}}
150
+
>
151
+
{ext.state === ExtensionState.NotDownloaded ? (
152
+
<Tooltip
153
+
text={conflicting ? CONFLICTING_TEXT : COMPAT_TEXT_MAP[ext.compat]}
154
+
shouldShow={conflicting || ext.compat !== ExtensionCompat.Compatible}
155
+
>
156
+
{(props: any) => (
157
+
<Button
158
+
{...props}
159
+
color={Button.Colors.BRAND}
160
+
submitting={busy}
161
+
disabled={ext.compat !== ExtensionCompat.Compatible || conflicting}
162
+
onClick={async () => {
163
+
await MoonbaseSettingsStore.installExtension(uniqueId);
164
+
const deps = await MoonbaseSettingsStore.getDependencies(uniqueId);
165
+
if (deps != null) {
166
+
await doMissingExtensionPopup(deps);
167
+
}
168
+
169
+
// Don't auto enable dangerous extensions
170
+
if (!ext.manifest?.meta?.tags?.includes(ExtensionTag.DangerZone)) {
171
+
MoonbaseSettingsStore.setExtensionEnabled(uniqueId, true);
172
+
}
173
+
}}
174
+
>
175
+
Install
176
+
</Button>
177
+
)}
178
+
</Tooltip>
179
+
) : (
180
+
<>
181
+
{ext.source.type === ExtensionLoadSource.Normal && (
182
+
<PanelButton
183
+
icon={TrashIcon}
184
+
tooltipText="Delete"
185
+
onClick={() => {
186
+
MoonbaseSettingsStore.deleteExtension(uniqueId);
187
+
}}
188
+
/>
189
+
)}
190
+
191
+
{update != null && (
192
+
<PanelButton
193
+
icon={DownloadIcon}
194
+
tooltipText="Update"
195
+
onClick={() => {
196
+
MoonbaseSettingsStore.installExtension(uniqueId);
197
+
}}
198
+
/>
199
+
)}
200
+
201
+
<FormSwitch
202
+
value={ext.compat === ExtensionCompat.Compatible && (enabled || implicitlyEnabled)}
203
+
disabled={implicitlyEnabled || ext.compat !== ExtensionCompat.Compatible}
204
+
hideBorder={true}
205
+
style={{ marginBottom: "0px" }}
206
+
// @ts-expect-error fix type later
207
+
tooltipNote={
208
+
ext.compat !== ExtensionCompat.Compatible ? (
209
+
COMPAT_TEXT_MAP[ext.compat]
210
+
) : implicitlyEnabled ? (
211
+
<div style={{ display: "flex", flexDirection: "column" }}>
212
+
<div>{`This extension is a dependency of the following enabled extension${
213
+
enabledDependants.length > 1 ? "s" : ""
214
+
}:`}</div>
215
+
{enabledDependants.map((dep) => (
216
+
<div>{"โข " + (dep.manifest.meta?.name ?? dep.id)}</div>
217
+
))}
218
+
</div>
219
+
) : undefined
131
220
}
132
-
onClick={async () => {
133
-
await installWithDependencyPopup(uniqueId);
221
+
onChange={() => {
222
+
const toggle = () => {
223
+
MoonbaseSettingsStore.setExtensionEnabled(uniqueId, !enabled);
224
+
};
225
+
226
+
if (enabled && constants.builtinExtensions.includes(ext.id)) {
227
+
doGenericExtensionPopup(
228
+
"Built in extension",
229
+
"This extension is enabled by default. Disabling it might have consequences. Are you sure you want to disable it?",
230
+
uniqueId,
231
+
toggle
232
+
);
233
+
} else if (!enabled && ext.manifest?.meta?.tags?.includes(ExtensionTag.DangerZone)) {
234
+
doGenericExtensionPopup(
235
+
"Dangerous extension",
236
+
"This extension is marked as dangerous. Enabling it might have consequences. Are you sure you want to enable it?",
237
+
uniqueId,
238
+
toggle
239
+
);
240
+
} else {
241
+
toggle();
242
+
}
134
243
}}
135
-
>
136
-
Install
137
-
</Button>
138
-
)}
139
-
</Tooltip>
140
-
) : (
141
-
<div
142
-
// too lazy to learn how <Flex /> works lmao
244
+
/>
245
+
</>
246
+
)}
247
+
</div>
248
+
</Flex>
249
+
</div>
250
+
251
+
<div>
252
+
{(description != null || changelog != null || settings != null || linkButtons.length > 0) && (
253
+
<Flex>
254
+
<TabBar
255
+
selectedItem={tab}
256
+
type="top"
257
+
onItemSelect={setTab}
258
+
className={DiscoveryClasses.tabBar}
143
259
style={{
144
-
display: "flex",
145
-
alignItems: "center",
146
-
gap: "1rem"
260
+
padding: "0 20px"
147
261
}}
148
262
>
149
-
{ext.source.type === ExtensionLoadSource.Normal && (
150
-
<PanelButton
151
-
icon={TrashIcon}
152
-
tooltipText="Delete"
153
-
onClick={() => {
154
-
MoonbaseSettingsStore.deleteExtension(uniqueId);
155
-
}}
156
-
/>
263
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id={ExtensionPage.Info}>
264
+
Info
265
+
</TabBar.Item>
266
+
267
+
{description != null && (
268
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id={ExtensionPage.Description}>
269
+
Description
270
+
</TabBar.Item>
157
271
)}
158
272
159
-
{update != null && (
160
-
<PanelButton
161
-
icon={DownloadIcon}
162
-
tooltipText="Update"
163
-
onClick={() => {
164
-
MoonbaseSettingsStore.installExtension(uniqueId);
165
-
}}
166
-
/>
273
+
{changelog != null && (
274
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id={ExtensionPage.Changelog}>
275
+
Changelog
276
+
</TabBar.Item>
167
277
)}
168
278
169
-
{restartNeeded && (
170
-
<PanelButton
171
-
icon={() => (
172
-
<CircleWarningIcon
173
-
color={Components.tokens.colors.STATUS_DANGER}
174
-
/>
175
-
)}
176
-
onClick={() => window.location.reload()}
177
-
tooltipText="You will need to reload/restart your client for this extension to work properly."
178
-
/>
279
+
{settings != null && (
280
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id={ExtensionPage.Settings}>
281
+
Settings
282
+
</TabBar.Item>
179
283
)}
180
-
181
-
<FormSwitch
182
-
value={
183
-
ext.compat === ExtensionCompat.Compatible &&
184
-
(enabled || implicitlyEnabled)
185
-
}
186
-
disabled={
187
-
implicitlyEnabled || ext.compat !== ExtensionCompat.Compatible
188
-
}
189
-
hideBorder={true}
190
-
style={{ marginBottom: "0px" }}
191
-
tooltipNote={
192
-
ext.compat !== ExtensionCompat.Compatible
193
-
? COMPAT_TEXT_MAP[ext.compat]
194
-
: implicitlyEnabled
195
-
? `This extension is a dependency of the following enabled extension${
196
-
enabledDependants.length > 1 ? "s" : ""
197
-
}: ${enabledDependants
198
-
.map((a) => a.manifest.meta?.name ?? a.id)
199
-
.join(", ")}`
200
-
: undefined
201
-
}
202
-
onChange={() => {
203
-
setRestartNeeded(true);
204
-
MoonbaseSettingsStore.setExtensionEnabled(uniqueId, !enabled);
205
-
}}
206
-
/>
207
-
</div>
208
-
)}
209
-
</Flex>
210
-
</div>
284
+
</TabBar>
211
285
212
-
<div>
213
-
{(description != null || settings != null) && (
214
-
<TabBar
215
-
selectedItem={tab}
216
-
type="top"
217
-
onItemSelect={setTab}
218
-
className={TabBarClasses.tabBar}
219
-
style={{
220
-
padding: "0 20px"
221
-
}}
222
-
>
223
-
<TabBar.Item
224
-
className={TabBarClasses.tabBarItem}
225
-
id={ExtensionPage.Info}
286
+
<Flex
287
+
align={Flex.Align.CENTER}
288
+
justify={Flex.Justify.END}
289
+
direction={Flex.Direction.HORIZONTAL}
290
+
grow={1}
291
+
className="moonbase-link-buttons"
226
292
>
227
-
Info
228
-
</TabBar.Item>
229
-
230
-
{description != null && (
231
-
<TabBar.Item
232
-
className={TabBarClasses.tabBarItem}
233
-
id={ExtensionPage.Description}
234
-
>
235
-
Description
236
-
</TabBar.Item>
237
-
)}
238
-
239
-
{settings != null && (
240
-
<TabBar.Item
241
-
className={TabBarClasses.tabBarItem}
242
-
id={ExtensionPage.Settings}
243
-
>
244
-
Settings
245
-
</TabBar.Item>
246
-
)}
247
-
</TabBar>
293
+
{linkButtons.length > 0 && linkButtons}
294
+
</Flex>
295
+
</Flex>
248
296
)}
249
297
250
298
<Flex
251
299
justify={Flex.Justify.START}
252
300
wrap={Flex.Wrap.WRAP}
253
301
style={{
254
-
padding: "16px 16px"
302
+
padding: "16px 16px",
303
+
// This looks wonky in the settings tab
304
+
rowGap: tab === ExtensionPage.Info ? "16px" : undefined
255
305
}}
256
306
>
257
-
{tab === ExtensionPage.Info && <ExtensionInfo ext={ext} />}
307
+
{tab === ExtensionPage.Info && <ExtensionInfo ext={ext} selectTag={selectTag} />}
258
308
{tab === ExtensionPage.Description && (
259
-
<Text
260
-
variant="text-md/normal"
261
-
class={MarkupClasses.markup}
262
-
style={{ width: "100%" }}
263
-
>
309
+
<Text variant="text-md/normal" className={MarkupClasses.markup} style={{ width: "100%" }}>
264
310
{MarkupUtils.parse(description ?? "*No description*", true, {
265
311
allowHeading: true,
266
312
allowLinks: true,
···
268
314
})}
269
315
</Text>
270
316
)}
271
-
{tab === ExtensionPage.Settings && <Settings ext={ext} />}
317
+
{tab === ExtensionPage.Changelog && (
318
+
<Text variant="text-md/normal" className={MarkupClasses.markup} style={{ width: "100%" }}>
319
+
{MarkupUtils.parse(changelog ?? "*No changelog*", true, {
320
+
allowHeading: true,
321
+
allowLinks: true,
322
+
allowList: true
323
+
})}
324
+
</Text>
325
+
)}
326
+
{tab === ExtensionPage.Settings && (
327
+
<ErrorBoundary>
328
+
<Settings ext={ext} />
329
+
</ErrorBoundary>
330
+
)}
272
331
</Flex>
273
332
</div>
274
333
</Card>
+109
-117
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/filterBar.tsx
+109
-117
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/filterBar.tsx
···
1
1
import { tagNames } from "./info";
2
-
3
2
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
4
3
import * as React from "@moonlight-mod/wp/react";
5
4
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
···
11
10
Popout,
12
11
Dialog,
13
12
Menu,
14
-
MenuGroup,
15
-
MenuCheckboxItem,
16
-
MenuItem
13
+
ChevronSmallDownIcon,
14
+
ChevronSmallUpIcon,
15
+
ArrowsUpDownIcon,
16
+
RetryIcon,
17
+
Tooltip
17
18
} from "@moonlight-mod/wp/discord/components/common/index";
18
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
19
+
import { MenuGroup, MenuCheckboxItem, MenuItem } from "@moonlight-mod/wp/contextMenu_contextMenu";
20
+
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
21
+
import Margins from "@moonlight-mod/wp/discord/styles/shared/Margins.css";
22
+
import TagItem from "@moonlight-mod/wp/discord/modules/forums/web/Tag";
19
23
20
24
export enum Filter {
21
25
Core = 1 << 0,
···
25
29
Disabled = 1 << 4,
26
30
Installed = 1 << 5,
27
31
Repository = 1 << 6,
28
-
Incompatible = 1 << 7
32
+
Incompatible = 1 << 7,
33
+
Deprecated = 1 << 8
29
34
}
30
35
export const defaultFilter = 127 as Filter;
31
36
32
-
const Margins = spacepack.findByCode("marginCenterHorz:")[0].exports;
33
-
const SortMenuClasses = spacepack.findByCode("container:", "clearText:")[0]
34
-
.exports;
35
-
36
-
let FilterDialogClasses: any;
37
-
let FilterBarClasses: any;
37
+
let HeaderClasses: any;
38
+
let ForumsClasses: any;
39
+
let SortMenuClasses: any;
38
40
spacepack
39
-
.lazyLoad(
40
-
'"Missing channel in Channel.openChannelContextMenu"',
41
-
/e\("(\d+)"\)/g,
42
-
/webpackId:(\d+?),/
43
-
)
41
+
.lazyLoad('"Missing channel in Channel.openChannelContextMenu"', /e\("(\d+)"\)/g, /webpackId:(\d+?),/)
44
42
.then(() => {
45
-
FilterBarClasses = spacepack.findByCode("tagsButtonWithCount:")[0].exports;
46
-
FilterDialogClasses = spacepack.findByCode(
47
-
"countContainer:",
48
-
"tagContainer:"
49
-
)[0].exports;
43
+
ForumsClasses = spacepack.require("discord/modules/forums/web/Forums.css");
44
+
HeaderClasses = spacepack.require("discord/modules/forums/web/Header.css");
45
+
SortMenuClasses = spacepack.require("discord/modules/forums/web/SortMenu.css");
50
46
});
51
47
52
-
const TagItem = spacepack.findByCode(".FORUM_TAG_A11Y_FILTER_BY_TAG")[0].exports
53
-
.Z;
54
-
55
-
// FIXME: type component keys
56
-
const { ChevronSmallDownIcon, ChevronSmallUpIcon, ArrowsUpDownIcon } =
57
-
Components;
58
-
59
-
function toggleTag(
60
-
selectedTags: Set<string>,
61
-
setSelectedTags: (tags: Set<string>) => void,
62
-
tag: string
63
-
) {
48
+
function toggleTag(selectedTags: Set<string>, setSelectedTags: (tags: Set<string>) => void, tag: string) {
64
49
const newState = new Set(selectedTags);
65
50
if (newState.has(tag)) newState.delete(tag);
66
51
else newState.add(tag);
···
76
61
setFilter: (filter: Filter) => void;
77
62
closePopout: () => void;
78
63
}) {
79
-
const toggleFilter = (set: Filter) =>
80
-
setFilter(filter & set ? filter & ~set : filter | set);
64
+
const toggleFilter = (set: Filter) => setFilter(filter & set ? filter & ~set : filter | set);
81
65
82
66
return (
83
67
<div className={SortMenuClasses.container}>
84
-
<Menu navId="sort-filter" hideScrollbar={true} onClose={closePopout}>
68
+
<Menu navId="sort-filter" hideScroller={true} onClose={closePopout}>
85
69
<MenuGroup label="Type">
86
70
<MenuCheckboxItem
87
71
id="t-core"
88
72
label="Core"
89
-
checked={filter & Filter.Core}
73
+
checked={(filter & Filter.Core) === Filter.Core}
90
74
action={() => toggleFilter(Filter.Core)}
91
75
/>
92
76
<MenuCheckboxItem
93
77
id="t-normal"
94
78
label="Normal"
95
-
checked={filter & Filter.Normal}
79
+
checked={(filter & Filter.Normal) === Filter.Normal}
96
80
action={() => toggleFilter(Filter.Normal)}
97
81
/>
98
82
<MenuCheckboxItem
99
83
id="t-developer"
100
84
label="Developer"
101
-
checked={filter & Filter.Developer}
85
+
checked={(filter & Filter.Developer) === Filter.Developer}
102
86
action={() => toggleFilter(Filter.Developer)}
103
87
/>
104
88
</MenuGroup>
···
106
90
<MenuCheckboxItem
107
91
id="s-enabled"
108
92
label="Enabled"
109
-
checked={filter & Filter.Enabled}
93
+
checked={(filter & Filter.Enabled) === Filter.Enabled}
110
94
action={() => toggleFilter(Filter.Enabled)}
111
95
/>
112
96
<MenuCheckboxItem
113
97
id="s-disabled"
114
98
label="Disabled"
115
-
checked={filter & Filter.Disabled}
99
+
checked={(filter & Filter.Disabled) === Filter.Disabled}
116
100
action={() => toggleFilter(Filter.Disabled)}
117
101
/>
118
102
</MenuGroup>
···
120
104
<MenuCheckboxItem
121
105
id="l-installed"
122
106
label="Installed"
123
-
checked={filter & Filter.Installed}
107
+
checked={(filter & Filter.Installed) === Filter.Installed}
124
108
action={() => toggleFilter(Filter.Installed)}
125
109
/>
126
110
<MenuCheckboxItem
127
111
id="l-repository"
128
112
label="Repository"
129
-
checked={filter & Filter.Repository}
113
+
checked={(filter & Filter.Repository) === Filter.Repository}
130
114
action={() => toggleFilter(Filter.Repository)}
131
115
/>
132
116
</MenuGroup>
···
134
118
<MenuCheckboxItem
135
119
id="l-incompatible"
136
120
label="Show incompatible"
137
-
checked={filter & Filter.Incompatible}
121
+
checked={(filter & Filter.Incompatible) === Filter.Incompatible}
138
122
action={() => toggleFilter(Filter.Incompatible)}
139
123
/>
124
+
<MenuCheckboxItem
125
+
id="l-deprecated"
126
+
label="Show deprecated"
127
+
checked={(filter & Filter.Deprecated) === Filter.Deprecated}
128
+
action={() => toggleFilter(Filter.Deprecated)}
129
+
/>
140
130
<MenuItem
141
131
id="reset-all"
142
132
className={SortMenuClasses.clearText}
143
-
label={
144
-
<Text variant="text-sm/medium" color="none">
145
-
Reset to default
146
-
</Text>
147
-
}
133
+
label="Reset to default"
148
134
action={() => {
149
135
setFilter(defaultFilter);
150
136
closePopout();
···
156
142
);
157
143
}
158
144
159
-
function TagButtonPopout({
160
-
selectedTags,
161
-
setSelectedTags,
162
-
setPopoutRef,
163
-
closePopout
164
-
}: any) {
145
+
function TagButtonPopout({ selectedTags, setSelectedTags, setPopoutRef, closePopout }: any) {
165
146
return (
166
-
<Dialog ref={setPopoutRef} className={FilterDialogClasses.container}>
167
-
<div className={FilterDialogClasses.header}>
168
-
<div className={FilterDialogClasses.headerLeft}>
169
-
<Heading
170
-
color="interactive-normal"
171
-
variant="text-xs/bold"
172
-
className={FilterDialogClasses.headerText}
173
-
>
147
+
<Dialog ref={setPopoutRef} className={HeaderClasses.container}>
148
+
<div className={HeaderClasses.header}>
149
+
<div className={HeaderClasses.headerLeft}>
150
+
<Heading color="interactive-normal" variant="text-xs/bold" className={HeaderClasses.headerText}>
174
151
Select tags
175
152
</Heading>
176
-
<div className={FilterDialogClasses.countContainer}>
177
-
<Text
178
-
className={FilterDialogClasses.countText}
179
-
color="none"
180
-
variant="text-xs/medium"
181
-
>
153
+
<div className={HeaderClasses.countContainer}>
154
+
<Text className={HeaderClasses.countText} color="none" variant="text-xs/medium">
182
155
{selectedTags.size}
183
156
</Text>
184
157
</div>
185
158
</div>
186
159
</div>
187
-
<div className={FilterDialogClasses.tagContainer}>
160
+
<div className={HeaderClasses.tagContainer}>
188
161
{Object.keys(tagNames).map((tag) => (
189
162
<TagItem
190
163
key={tag}
191
-
className={FilterDialogClasses.tag}
192
-
tag={{ name: tagNames[tag as keyof typeof tagNames] }}
164
+
className={HeaderClasses.tag}
165
+
tag={{ name: tagNames[tag as keyof typeof tagNames], id: tagNames[tag as keyof typeof tagNames] }}
193
166
onClick={() => toggleTag(selectedTags, setSelectedTags, tag)}
194
167
selected={selectedTags.has(tag)}
195
168
/>
196
169
))}
197
170
</div>
198
-
<div className={FilterDialogClasses.separator} />
171
+
<div className={HeaderClasses.separator} />
199
172
<Button
200
173
look={Button.Looks.LINK}
201
174
size={Button.Sizes.MIN}
202
175
color={Button.Colors.CUSTOM}
203
-
className={FilterDialogClasses.clear}
176
+
className={HeaderClasses.clear}
204
177
onClick={() => {
205
178
setSelectedTags(new Set());
206
179
closePopout();
···
225
198
selectedTags: Set<string>;
226
199
setSelectedTags: (tags: Set<string>) => void;
227
200
}) {
228
-
const windowSize = useStateFromStores([WindowStore], () =>
229
-
WindowStore.windowSize()
230
-
);
201
+
const windowSize = useStateFromStores([WindowStore], () => WindowStore.windowSize());
231
202
232
203
const tagsContainer = React.useRef<HTMLDivElement>(null);
233
204
const tagListInner = React.useRef<HTMLDivElement>(null);
234
205
const [tagsButtonOffset, setTagsButtonOffset] = React.useState(0);
206
+
const [checkingUpdates, setCheckingUpdates] = React.useState(false);
207
+
235
208
React.useLayoutEffect(() => {
236
209
if (tagsContainer.current === null || tagListInner.current === null) return;
237
-
const { left: containerX, top: containerY } =
238
-
tagsContainer.current.getBoundingClientRect();
210
+
const { left: containerX, top: containerY } = tagsContainer.current.getBoundingClientRect();
239
211
let offset = 0;
240
212
for (const child of tagListInner.current.children) {
241
-
const {
242
-
right: childX,
243
-
top: childY,
244
-
height
245
-
} = child.getBoundingClientRect();
213
+
const { right: childX, top: childY, height } = child.getBoundingClientRect();
246
214
if (childY - containerY > height) break;
247
215
const newOffset = childX - containerX;
248
216
if (newOffset > offset) {
···
250
218
}
251
219
}
252
220
setTagsButtonOffset(offset);
253
-
}, [windowSize]);
221
+
}, [windowSize, tagsContainer.current, tagListInner.current, tagListInner.current?.getBoundingClientRect()?.width]);
254
222
255
223
return (
256
224
<div
···
258
226
style={{
259
227
paddingTop: "12px"
260
228
}}
261
-
className={`${FilterBarClasses.tagsContainer} ${Margins.marginBottom8}`}
229
+
className={`${ForumsClasses.tagsContainer} ${Margins.marginBottom8}`}
262
230
>
231
+
<Tooltip text="Refresh updates" position="top">
232
+
{(props: any) => (
233
+
<Button
234
+
{...props}
235
+
size={Button.Sizes.MIN}
236
+
color={Button.Colors.CUSTOM}
237
+
className={`${ForumsClasses.sortDropdown} moonbase-retry-button`}
238
+
innerClassName={ForumsClasses.sortDropdownInner}
239
+
onClick={() => {
240
+
(async () => {
241
+
try {
242
+
setCheckingUpdates(true);
243
+
await MoonbaseSettingsStore.checkUpdates();
244
+
} finally {
245
+
// artificial delay because the spin is fun
246
+
await new Promise((r) => setTimeout(r, 500));
247
+
setCheckingUpdates(false);
248
+
}
249
+
})();
250
+
}}
251
+
>
252
+
<RetryIcon size={"custom"} width={16} className={checkingUpdates ? "moonbase-speen" : ""} />
253
+
</Button>
254
+
)}
255
+
</Tooltip>
263
256
<Popout
264
257
renderPopout={({ closePopout }: any) => (
265
-
<FilterButtonPopout
266
-
filter={filter}
267
-
setFilter={setFilter}
268
-
closePopout={closePopout}
269
-
/>
258
+
<FilterButtonPopout filter={filter} setFilter={setFilter} closePopout={closePopout} />
270
259
)}
271
260
position="bottom"
272
261
align="left"
···
276
265
{...props}
277
266
size={Button.Sizes.MIN}
278
267
color={Button.Colors.CUSTOM}
279
-
className={FilterBarClasses.sortDropdown}
280
-
innerClassName={FilterBarClasses.sortDropdownInner}
268
+
className={ForumsClasses.sortDropdown}
269
+
innerClassName={ForumsClasses.sortDropdownInner}
281
270
>
282
271
<ArrowsUpDownIcon size="xs" />
283
-
<Text
284
-
className={FilterBarClasses.sortDropdownText}
285
-
variant="text-sm/medium"
286
-
color="interactive-normal"
287
-
>
272
+
<Text className={ForumsClasses.sortDropdownText} variant="text-sm/medium" color="interactive-normal">
288
273
Sort & filter
289
274
</Text>
290
275
{isShown ? (
···
295
280
</Button>
296
281
)}
297
282
</Popout>
298
-
<div className={FilterBarClasses.divider} />
299
-
<div className={FilterBarClasses.tagList}>
300
-
<div ref={tagListInner} className={FilterBarClasses.tagListInner}>
283
+
<div className={ForumsClasses.divider} />
284
+
<div className={ForumsClasses.tagList}>
285
+
<div ref={tagListInner} className={ForumsClasses.tagListInner}>
301
286
{Object.keys(tagNames).map((tag) => (
302
287
<TagItem
303
288
key={tag}
304
-
className={FilterBarClasses.tag}
305
-
tag={{ name: tagNames[tag as keyof typeof tagNames] }}
289
+
className={ForumsClasses.tag}
290
+
tag={{ name: tagNames[tag as keyof typeof tagNames], id: tag }}
306
291
onClick={() => toggleTag(selectedTags, setSelectedTags, tag)}
307
292
selected={selectedTags.has(tag)}
308
293
/>
···
330
315
left: tagsButtonOffset
331
316
}}
332
317
// TODO: Use Discord's class name utility
333
-
className={`${FilterBarClasses.tagsButton} ${
334
-
selectedTags.size > 0 ? FilterBarClasses.tagsButtonWithCount : ""
335
-
}`}
336
-
innerClassName={FilterBarClasses.tagsButtonInner}
318
+
className={`${ForumsClasses.tagsButton} ${selectedTags.size > 0 ? ForumsClasses.tagsButtonWithCount : ""}`}
319
+
innerClassName={ForumsClasses.tagsButtonInner}
337
320
>
338
321
{selectedTags.size > 0 ? (
339
-
<div
340
-
style={{ boxSizing: "content-box" }}
341
-
className={FilterBarClasses.countContainer}
342
-
>
343
-
<Text
344
-
className={FilterBarClasses.countText}
345
-
color="none"
346
-
variant="text-xs/medium"
347
-
>
322
+
<div style={{ boxSizing: "content-box" }} className={ForumsClasses.countContainer}>
323
+
<Text className={ForumsClasses.countText} color="none" variant="text-xs/medium">
348
324
{selectedTags.size}
349
325
</Text>
350
326
</div>
···
359
335
</Button>
360
336
)}
361
337
</Popout>
338
+
<Button
339
+
size={Button.Sizes.MIN}
340
+
color={Button.Colors.CUSTOM}
341
+
className={`${ForumsClasses.tagsButton} ${ForumsClasses.tagsButtonPlaceholder}`}
342
+
innerClassName={ForumsClasses.tagsButtonInner}
343
+
>
344
+
{selectedTags.size > 0 ? (
345
+
<div style={{ boxSizing: "content-box" }} className={ForumsClasses.countContainer}>
346
+
<Text className={ForumsClasses.countText} color="none" variant="text-xs/medium">
347
+
{selectedTags.size}
348
+
</Text>
349
+
</div>
350
+
) : null}
351
+
352
+
<ChevronSmallUpIcon size={"custom"} width={20} />
353
+
</Button>
362
354
</div>
363
355
);
364
356
}
+101
-54
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/index.tsx
+101
-54
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/index.tsx
···
6
6
import React from "@moonlight-mod/wp/react";
7
7
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
8
8
import { useStateFromStoresObject } from "@moonlight-mod/wp/discord/packages/flux";
9
+
import {
10
+
FormDivider,
11
+
CircleInformationIcon,
12
+
XSmallIcon,
13
+
Button
14
+
} from "@moonlight-mod/wp/discord/components/common/index";
15
+
import PanelButton from "@moonlight-mod/wp/discord/components/common/PanelButton";
9
16
10
17
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
18
+
import ErrorBoundary from "@moonlight-mod/wp/common_ErrorBoundary";
11
19
import { ExtensionCompat } from "@moonlight-mod/core/extension/loader";
20
+
import HelpMessage from "../HelpMessage";
12
21
13
-
const SearchBar: any = Object.values(
14
-
spacepack.findByCode("Messages.SEARCH", "hideSearchIcon")[0].exports
15
-
)[0];
22
+
const SearchBar = spacepack.require("discord/uikit/search/SearchBar").default;
23
+
24
+
const validTags: string[] = Object.values(ExtensionTag);
16
25
17
26
export default function ExtensionsPage() {
18
-
const { extensions, savedFilter } = useStateFromStoresObject(
19
-
[MoonbaseSettingsStore],
20
-
() => {
21
-
return {
22
-
extensions: MoonbaseSettingsStore.extensions,
23
-
savedFilter: MoonbaseSettingsStore.getExtensionConfigRaw<number>(
24
-
"moonbase",
25
-
"filter",
26
-
defaultFilter
27
-
)
28
-
};
29
-
}
30
-
);
27
+
const { extensions, savedFilter } = useStateFromStoresObject([MoonbaseSettingsStore], () => {
28
+
return {
29
+
extensions: MoonbaseSettingsStore.extensions,
30
+
savedFilter: MoonbaseSettingsStore.getExtensionConfigRaw<number>("moonbase", "filter", defaultFilter)
31
+
};
32
+
});
31
33
32
34
const [query, setQuery] = React.useState("");
35
+
const [hitUpdateAll, setHitUpdateAll] = React.useState(false);
36
+
37
+
const filterState = React.useState(defaultFilter);
33
38
34
39
let filter: Filter, setFilter: (filter: Filter) => void;
35
-
if (
36
-
MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
37
-
"moonbase",
38
-
"saveFilter",
39
-
false
40
-
)
41
-
) {
40
+
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "saveFilter", false)) {
42
41
filter = savedFilter ?? defaultFilter;
43
-
setFilter = (filter) =>
44
-
MoonbaseSettingsStore.setExtensionConfig("moonbase", "filter", filter);
42
+
setFilter = (filter) => MoonbaseSettingsStore.setExtensionConfig("moonbase", "filter", filter);
45
43
} else {
46
-
const state = React.useState(defaultFilter);
47
-
filter = state[0];
48
-
setFilter = state[1];
44
+
filter = filterState[0];
45
+
setFilter = filterState[1];
49
46
}
47
+
50
48
const [selectedTags, setSelectedTags] = React.useState(new Set<string>());
49
+
const selectTag = React.useCallback(
50
+
(tag: string) => {
51
+
const newState = new Set(selectedTags);
52
+
if (validTags.includes(tag)) newState.add(tag);
53
+
setSelectedTags(newState);
54
+
},
55
+
[selectedTags]
56
+
);
57
+
51
58
const sorted = Object.values(extensions).sort((a, b) => {
52
59
const aName = a.manifest.meta?.name ?? a.id;
53
60
const bName = b.manifest.meta?.name ?? b.id;
···
60
67
ext.manifest.id?.toLowerCase().includes(query) ||
61
68
ext.manifest.meta?.name?.toLowerCase().includes(query) ||
62
69
ext.manifest.meta?.tagline?.toLowerCase().includes(query) ||
70
+
(ext.manifest?.settings != null &&
71
+
Object.entries(ext.manifest.settings).some(([key, setting]) =>
72
+
(setting.displayName ?? key).toLowerCase().includes(query)
73
+
)) ||
74
+
(ext.manifest?.meta?.authors != null &&
75
+
ext.manifest.meta.authors.some((author) =>
76
+
(typeof author === "string" ? author : author.name).toLowerCase().includes(query)
77
+
)) ||
63
78
ext.manifest.meta?.description?.toLowerCase().includes(query)) &&
64
-
[...selectedTags.values()].every(
65
-
(tag) => ext.manifest.meta?.tags?.includes(tag as ExtensionTag)
66
-
) &&
79
+
[...selectedTags.values()].every((tag) => ext.manifest.meta?.tags?.includes(tag as ExtensionTag)) &&
67
80
// This seems very bad, sorry
68
81
!(
69
-
(!(filter & Filter.Core) &&
70
-
ext.source.type === ExtensionLoadSource.Core) ||
71
-
(!(filter & Filter.Normal) &&
72
-
ext.source.type === ExtensionLoadSource.Normal) ||
73
-
(!(filter & Filter.Developer) &&
74
-
ext.source.type === ExtensionLoadSource.Developer) ||
75
-
(!(filter & Filter.Enabled) &&
76
-
MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
77
-
(!(filter & Filter.Disabled) &&
78
-
!MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
79
-
(!(filter & Filter.Installed) &&
80
-
ext.state !== ExtensionState.NotDownloaded) ||
81
-
(!(filter & Filter.Repository) &&
82
-
ext.state === ExtensionState.NotDownloaded)
82
+
(!(filter & Filter.Core) && ext.source.type === ExtensionLoadSource.Core) ||
83
+
(!(filter & Filter.Normal) && ext.source.type === ExtensionLoadSource.Normal) ||
84
+
(!(filter & Filter.Developer) && ext.source.type === ExtensionLoadSource.Developer) ||
85
+
(!(filter & Filter.Enabled) && MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
86
+
(!(filter & Filter.Disabled) && !MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
87
+
(!(filter & Filter.Installed) && ext.state !== ExtensionState.NotDownloaded) ||
88
+
(!(filter & Filter.Repository) && ext.state === ExtensionState.NotDownloaded)
83
89
) &&
84
90
(filter & Filter.Incompatible ||
85
91
ext.compat === ExtensionCompat.Compatible ||
86
-
(ext.compat === ExtensionCompat.InvalidApiLevel && ext.hasUpdate))
92
+
(ext.compat === ExtensionCompat.InvalidApiLevel && ext.hasUpdate)) &&
93
+
(filter & Filter.Deprecated ||
94
+
ext.manifest?.meta?.deprecated !== true ||
95
+
ext.state !== ExtensionState.NotDownloaded)
87
96
);
97
+
98
+
// Prioritize extensions with updates
99
+
const filteredWithUpdates = filtered.filter((ext) => ext!.hasUpdate);
100
+
const filteredWithoutUpdates = filtered.filter((ext) => !ext!.hasUpdate);
88
101
89
102
return (
90
103
<>
···
101
114
spellCheck: "false"
102
115
}}
103
116
/>
104
-
<FilterBar
105
-
filter={filter}
106
-
setFilter={setFilter}
107
-
selectedTags={selectedTags}
108
-
setSelectedTags={setSelectedTags}
109
-
/>
110
-
{filtered.map((ext) => (
111
-
<ExtensionCard uniqueId={ext.uniqueId} key={ext.uniqueId} />
117
+
<FilterBar filter={filter} setFilter={setFilter} selectedTags={selectedTags} setSelectedTags={setSelectedTags} />
118
+
119
+
{filteredWithUpdates.length > 0 && (
120
+
<HelpMessage
121
+
icon={CircleInformationIcon}
122
+
text="Extension updates are available"
123
+
className="moonbase-extension-update-section"
124
+
>
125
+
<div className="moonbase-help-message-buttons">
126
+
<Button
127
+
color={Button.Colors.BRAND}
128
+
size={Button.Sizes.TINY}
129
+
disabled={hitUpdateAll}
130
+
onClick={() => {
131
+
setHitUpdateAll(true);
132
+
MoonbaseSettingsStore.updateAllExtensions();
133
+
}}
134
+
>
135
+
Update all
136
+
</Button>
137
+
<PanelButton
138
+
icon={XSmallIcon}
139
+
onClick={() => {
140
+
MoonbaseSettingsStore.dismissAllExtensionUpdates();
141
+
}}
142
+
/>
143
+
</div>
144
+
</HelpMessage>
145
+
)}
146
+
147
+
{filteredWithUpdates.map((ext) => (
148
+
<ErrorBoundary>
149
+
<ExtensionCard uniqueId={ext.uniqueId} key={ext.uniqueId} selectTag={selectTag} />
150
+
</ErrorBoundary>
151
+
))}
152
+
{filteredWithUpdates.length > 0 && filteredWithoutUpdates.length > 0 && (
153
+
<FormDivider className="moonbase-update-divider" />
154
+
)}
155
+
{filteredWithoutUpdates.map((ext) => (
156
+
<ErrorBoundary>
157
+
<ExtensionCard uniqueId={ext.uniqueId} key={ext.uniqueId} selectTag={selectTag} />
158
+
</ErrorBoundary>
112
159
))}
113
160
</>
114
161
);
+50
-44
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/info.tsx
+50
-44
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/info.tsx
···
2
2
import { MoonbaseExtension } from "../../../types";
3
3
4
4
import React from "@moonlight-mod/wp/react";
5
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
6
-
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
5
+
import { Text } from "@moonlight-mod/wp/discord/components/common/index";
7
6
8
7
type Dependency = {
9
8
id: string;
···
34
33
[ExtensionTag.Library]: "Library"
35
34
};
36
35
37
-
const UserInfoClasses = spacepack.findByCode(
38
-
"infoScroller",
39
-
"userInfoSection",
40
-
"userInfoSectionHeader"
41
-
)[0].exports;
42
-
43
36
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
44
37
45
-
// FIXME: type component keys
46
-
const { Text } = Components;
47
-
48
-
function InfoSection({
49
-
title,
50
-
children
51
-
}: {
52
-
title: string;
53
-
children: React.ReactNode;
54
-
}) {
38
+
function InfoSection({ title, children }: { title: string; children: React.ReactNode }) {
55
39
return (
56
40
<div
57
41
style={{
58
42
marginRight: "1em"
59
43
}}
60
44
>
61
-
<Text variant="eyebrow" className={UserInfoClasses.userInfoSectionHeader}>
45
+
<Text variant="eyebrow" className="moonlight-card-info-header">
62
46
{title}
63
47
</Text>
64
48
···
69
53
70
54
function Badge({
71
55
color,
72
-
children
56
+
children,
57
+
style = {},
58
+
onClick
73
59
}: {
74
60
color: string;
75
61
children: React.ReactNode;
62
+
style?: React.CSSProperties;
63
+
onClick?: () => void;
76
64
}) {
65
+
if (onClick) style.cursor ??= "pointer";
77
66
return (
78
67
<span
79
-
style={{
80
-
borderRadius: ".1875rem",
81
-
padding: "0 0.275rem",
82
-
marginRight: "0.4em",
83
-
backgroundColor: color,
84
-
color: "#fff"
85
-
}}
68
+
className="moonlight-card-badge"
69
+
style={
70
+
{
71
+
"--badge-color": color,
72
+
...style
73
+
} as React.CSSProperties
74
+
}
75
+
onClick={onClick}
86
76
>
87
77
{children}
88
78
</span>
89
79
);
90
80
}
91
81
92
-
export default function ExtensionInfo({ ext }: { ext: MoonbaseExtension }) {
82
+
export default function ExtensionInfo({
83
+
ext,
84
+
selectTag
85
+
}: {
86
+
ext: MoonbaseExtension;
87
+
selectTag: (tag: string) => void;
88
+
}) {
93
89
const authors = ext.manifest?.meta?.authors;
94
90
const tags = ext.manifest?.meta?.tags;
95
91
const version = ext.manifest?.version;
96
92
97
93
const dependencies: Dependency[] = [];
94
+
const incompatible: Dependency[] = [];
95
+
98
96
if (ext.manifest.dependencies != null) {
99
97
dependencies.push(
100
98
...ext.manifest.dependencies.map((dep) => ({
···
114
112
}
115
113
116
114
if (ext.manifest.incompatible != null) {
117
-
dependencies.push(
115
+
incompatible.push(
118
116
...ext.manifest.incompatible.map((dep) => ({
119
117
id: dep,
120
118
type: DependencyType.Incompatible
···
152
150
<InfoSection title="Tags">
153
151
{tags.map((tag, i) => {
154
152
const name = tagNames[tag];
153
+
let color = "var(--bg-mod-strong)";
154
+
let style;
155
+
if (tag === ExtensionTag.DangerZone) {
156
+
color = "var(--red-460)";
157
+
style = { color: "var(--primary-230)" };
158
+
}
155
159
156
160
return (
157
-
<Badge
158
-
key={i}
159
-
color={
160
-
tag === ExtensionTag.DangerZone
161
-
? "var(--red-400)"
162
-
: "var(--brand-500)"
163
-
}
164
-
>
161
+
<Badge key={i} color={color} style={style} onClick={() => selectTag(tag)}>
165
162
{name}
166
163
</Badge>
167
164
);
···
172
169
{dependencies.length > 0 && (
173
170
<InfoSection title="Dependencies">
174
171
{dependencies.map((dep) => {
175
-
const colors = {
176
-
[DependencyType.Dependency]: "var(--brand-500)",
177
-
[DependencyType.Optional]: "var(--orange-400)",
178
-
[DependencyType.Incompatible]: "var(--red-400)"
179
-
};
180
-
const color = colors[dep.type];
172
+
const name = MoonbaseSettingsStore.tryGetExtensionName(dep.id);
173
+
174
+
// TODO: figure out a decent way to distinguish suggested
175
+
return (
176
+
<Badge color="var(--bg-mod-strong)" key={dep.id}>
177
+
{name}
178
+
</Badge>
179
+
);
180
+
})}
181
+
</InfoSection>
182
+
)}
183
+
184
+
{incompatible.length > 0 && (
185
+
<InfoSection title="Incompatible">
186
+
{incompatible.map((dep) => {
181
187
const name = MoonbaseSettingsStore.tryGetExtensionName(dep.id);
182
188
183
189
return (
184
-
<Badge color={color} key={dep.id}>
190
+
<Badge color="var(--bg-mod-strong)" key={dep.id}>
185
191
{name}
186
192
</Badge>
187
193
);
+79
-46
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/popup.tsx
+79
-46
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/popup.tsx
···
1
1
// TODO: clean up the styling here
2
-
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
3
2
import React from "@moonlight-mod/wp/react";
4
3
import { MoonbaseExtension } from "core-extensions/src/moonbase/types";
5
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
4
+
import { openModalLazy, useModalsStore, closeModal } from "@moonlight-mod/wp/discord/modules/modals/Modals";
5
+
import { SingleSelect, Text } from "@moonlight-mod/wp/discord/components/common/index";
6
6
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
7
7
import { ExtensionLoadSource } from "@moonlight-mod/types";
8
8
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
9
+
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
9
10
10
-
const {
11
-
openModalLazy,
12
-
closeModal
13
-
} = require("@moonlight-mod/wp/discord/components/common/index");
14
-
const Popup = spacepack.findByCode(".minorContainer", "secondaryAction")[0]
15
-
.exports.default;
11
+
let ConfirmModal: typeof import("@moonlight-mod/wp/discord/components/modals/ConfirmModal").default;
12
+
13
+
function close() {
14
+
const ModalStore = useModalsStore.getState();
15
+
closeModal(ModalStore.default[0].key);
16
+
}
17
+
18
+
// do this to avoid a hard dependency
19
+
function lazyLoad() {
20
+
if (!ConfirmModal) {
21
+
ConfirmModal = spacepack.require("discord/components/modals/ConfirmModal").default;
22
+
}
23
+
}
16
24
17
25
const presentableLoadSources: Record<ExtensionLoadSource, string> = {
18
26
[ExtensionLoadSource.Developer]: "Local extension", // should never show up
···
31
39
option: string | undefined;
32
40
setOption: (pick: string | undefined) => void;
33
41
}) {
34
-
const { SingleSelect } = Components;
35
-
36
42
return (
37
43
<SingleSelect
38
44
key={id}
···
42
48
return {
43
49
value: candidate.uniqueId.toString(),
44
50
label:
45
-
candidate.source.url ??
46
-
presentableLoadSources[candidate.source.type] ??
47
-
candidate.manifest.version ??
48
-
""
51
+
candidate.source.url ?? presentableLoadSources[candidate.source.type] ?? candidate.manifest.version ?? ""
49
52
};
50
53
})}
51
54
onChange={(value: string) => {
52
55
setOption(value);
53
56
}}
54
-
// @ts-expect-error no thanks
55
57
placeholder="Missing extension"
56
58
/>
57
59
);
58
60
}
59
61
60
-
function OurPopup({
62
+
function MissingExtensionPopup({
61
63
deps,
62
-
transitionState,
63
-
id
64
+
transitionState
64
65
}: {
65
66
deps: Record<string, MoonbaseExtension[]>;
66
67
transitionState: number | null;
67
-
id: string;
68
68
}) {
69
-
const { Text } = Components;
70
-
71
-
const amountNotAvailable = Object.values(deps).filter(
72
-
(candidates) => candidates.length === 0
73
-
).length;
69
+
lazyLoad();
70
+
const amountNotAvailable = Object.values(deps).filter((candidates) => candidates.length === 0).length;
74
71
75
-
const [options, setOptions] = React.useState<
76
-
Record<string, string | undefined>
77
-
>(
72
+
const [options, setOptions] = React.useState<Record<string, string | undefined>>(
78
73
Object.fromEntries(
79
74
Object.entries(deps).map(([id, candidates]) => [
80
75
id,
···
84
79
);
85
80
86
81
return (
87
-
<Popup
82
+
<ConfirmModal
88
83
body={
89
84
<Flex
90
85
style={{
···
93
88
direction={Flex.Direction.VERTICAL}
94
89
>
95
90
<Text variant="text-md/normal">
96
-
This extension depends on other extensions which are not downloaded.
97
-
Choose which extensions to download.
91
+
This extension depends on other extensions which are not downloaded. Choose which extensions to download.
98
92
</Text>
99
93
100
94
{amountNotAvailable > 0 && (
101
95
<Text variant="text-md/normal">
102
96
{amountNotAvailable} extension
103
-
{amountNotAvailable > 1 ? "s" : ""} could not be found, and must
104
-
be installed manually.
97
+
{amountNotAvailable > 1 ? "s" : ""} could not be found, and must be installed manually.
105
98
</Text>
106
99
)}
107
100
···
142
135
}
143
136
cancelText="Cancel"
144
137
confirmText="Install"
145
-
onCancel={() => {
146
-
closeModal(id);
147
-
}}
138
+
onCancel={close}
148
139
onConfirm={() => {
149
-
closeModal(id);
140
+
close();
150
141
151
142
for (const pick of Object.values(options)) {
152
143
if (pick != null) {
···
160
151
);
161
152
}
162
153
163
-
export async function doPopup(deps: Record<string, MoonbaseExtension[]>) {
164
-
const id: string = await openModalLazy(async () => {
165
-
// eslint-disable-next-line react/display-name
154
+
export async function doMissingExtensionPopup(deps: Record<string, MoonbaseExtension[]>) {
155
+
await openModalLazy(async () => {
166
156
return ({ transitionState }: { transitionState: number | null }) => {
167
-
return <OurPopup transitionState={transitionState} deps={deps} id={id} />;
157
+
return <MissingExtensionPopup transitionState={transitionState} deps={deps} />;
168
158
};
169
159
});
170
160
}
171
161
172
-
export default async function installWithDependencyPopup(uniqueId: number) {
173
-
await MoonbaseSettingsStore.installExtension(uniqueId);
174
-
const deps = await MoonbaseSettingsStore.getDependencies(uniqueId);
175
-
if (deps != null) {
176
-
await doPopup(deps);
177
-
}
162
+
function GenericExtensionPopup({
163
+
title,
164
+
content,
165
+
transitionState,
166
+
uniqueId,
167
+
cb
168
+
}: {
169
+
title: string;
170
+
content: string;
171
+
transitionState: number | null;
172
+
uniqueId: number;
173
+
cb: () => void;
174
+
}) {
175
+
lazyLoad();
176
+
177
+
return (
178
+
<ConfirmModal
179
+
title={title}
180
+
body={
181
+
<Flex>
182
+
<Text variant="text-md/normal">{content}</Text>
183
+
</Flex>
184
+
}
185
+
confirmText="Yes"
186
+
cancelText="No"
187
+
onCancel={close}
188
+
onConfirm={() => {
189
+
close();
190
+
cb();
191
+
}}
192
+
transitionState={transitionState}
193
+
/>
194
+
);
195
+
}
196
+
197
+
export async function doGenericExtensionPopup(title: string, content: string, uniqueId: number, cb: () => void) {
198
+
await openModalLazy(async () => {
199
+
return ({ transitionState }: { transitionState: number | null }) => {
200
+
return (
201
+
<GenericExtensionPopup
202
+
title={title}
203
+
content={content}
204
+
transitionState={transitionState}
205
+
uniqueId={uniqueId}
206
+
cb={cb}
207
+
/>
208
+
);
209
+
};
210
+
});
178
211
}
+104
-145
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/settings.tsx
+104
-145
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/settings.tsx
···
11
11
12
12
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
13
13
import React from "@moonlight-mod/wp/react";
14
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
14
+
import {
15
+
FormSwitch,
16
+
FormItem,
17
+
FormText,
18
+
TextInput,
19
+
Slider,
20
+
TextArea,
21
+
Tooltip,
22
+
Clickable,
23
+
CircleXIcon,
24
+
Text,
25
+
SingleSelect,
26
+
Button,
27
+
useVariableSelect,
28
+
multiSelect,
29
+
Select as DiscordSelect,
30
+
NumberInputStepper
31
+
} from "@moonlight-mod/wp/discord/components/common/index";
15
32
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
16
33
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
34
+
import MarkupUtils from "@moonlight-mod/wp/discord/modules/markup/MarkupUtils";
35
+
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
36
+
import ErrorBoundary from "@moonlight-mod/wp/common_ErrorBoundary";
37
+
38
+
let GuildSettingsRoleEditClasses: any;
39
+
spacepack
40
+
.lazyLoad(
41
+
"renderArtisanalHack",
42
+
/\[(?:.\.e\("\d+?"\),?)+\][^}]+?webpackId:\d+,name:"GuildSettings"/,
43
+
/webpackId:(\d+),name:"GuildSettings"/
44
+
)
45
+
.then(
46
+
() =>
47
+
(GuildSettingsRoleEditClasses = spacepack.require(
48
+
"discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"
49
+
))
50
+
);
17
51
18
52
type SettingsProps = {
19
53
ext: MoonbaseExtension;
···
21
55
setting: ExtensionSettingsManifest;
22
56
disabled: boolean;
23
57
};
24
-
25
58
type SettingsComponent = React.ComponentType<SettingsProps>;
26
59
27
-
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
28
60
const Margins = spacepack.require("discord/styles/shared/Margins.css");
29
61
62
+
function markdownify(str: string) {
63
+
return MarkupUtils.parse(str, true, {
64
+
hideSimpleEmbedContent: true,
65
+
allowLinks: true
66
+
});
67
+
}
68
+
30
69
function useConfigEntry<T>(uniqueId: number, name: string) {
31
70
return useStateFromStores(
32
71
[MoonbaseSettingsStore],
33
72
() => {
34
73
return {
35
74
value: MoonbaseSettingsStore.getExtensionConfig<T>(uniqueId, name),
36
-
displayName: MoonbaseSettingsStore.getExtensionConfigName(
37
-
uniqueId,
38
-
name
39
-
),
40
-
description: MoonbaseSettingsStore.getExtensionConfigDescription(
41
-
uniqueId,
42
-
name
43
-
)
75
+
displayName: MoonbaseSettingsStore.getExtensionConfigName(uniqueId, name),
76
+
description: MoonbaseSettingsStore.getExtensionConfigDescription(uniqueId, name)
44
77
};
45
78
},
46
79
[uniqueId, name]
···
48
81
}
49
82
50
83
function Boolean({ ext, name, setting, disabled }: SettingsProps) {
51
-
const { FormSwitch } = Components;
52
-
const { value, displayName, description } = useConfigEntry<boolean>(
53
-
ext.uniqueId,
54
-
name
55
-
);
84
+
const { value, displayName, description } = useConfigEntry<boolean>(ext.uniqueId, name);
56
85
57
86
return (
58
87
<FormSwitch
···
62
91
onChange={(value: boolean) => {
63
92
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
64
93
}}
65
-
note={description}
94
+
note={description != null ? markdownify(description) : undefined}
66
95
className={`${Margins.marginReset} ${Margins.marginTop20}`}
67
96
>
68
97
{displayName}
···
71
100
}
72
101
73
102
function Number({ ext, name, setting, disabled }: SettingsProps) {
74
-
const { FormItem, FormText, Slider } = Components;
75
-
const { value, displayName, description } = useConfigEntry<number>(
76
-
ext.uniqueId,
77
-
name
78
-
);
103
+
const { value, displayName, description } = useConfigEntry<number>(ext.uniqueId, name);
79
104
80
105
const castedSetting = setting as NumberSettingType;
81
-
const min = castedSetting.min ?? 0;
82
-
const max = castedSetting.max ?? 100;
106
+
const min = castedSetting.min;
107
+
const max = castedSetting.max;
108
+
109
+
const onChange = (value: number) => {
110
+
const rounded = min == null || max == null ? Math.round(value) : Math.max(min, Math.min(max, Math.round(value)));
111
+
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, rounded);
112
+
};
83
113
84
114
return (
85
115
<FormItem className={Margins.marginTop20} title={displayName}>
86
-
{description && <FormText>{description}</FormText>}
87
-
<Slider
88
-
initialValue={value ?? 0}
89
-
disabled={disabled}
90
-
minValue={castedSetting.min ?? 0}
91
-
maxValue={castedSetting.max ?? 100}
92
-
onValueChange={(value: number) => {
93
-
const rounded = Math.max(min, Math.min(max, Math.round(value)));
94
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, rounded);
95
-
}}
96
-
/>
116
+
{min == null || max == null ? (
117
+
<Flex justify={Flex.Justify.BETWEEN} direction={Flex.Direction.HORIZONTAL}>
118
+
{description && <FormText>{markdownify(description)}</FormText>}
119
+
<NumberInputStepper value={value ?? 0} onChange={onChange} />
120
+
</Flex>
121
+
) : (
122
+
<>
123
+
{description && <FormText>{markdownify(description)}</FormText>}
124
+
<Slider
125
+
initialValue={value ?? 0}
126
+
disabled={disabled}
127
+
minValue={min}
128
+
maxValue={max}
129
+
onValueChange={onChange}
130
+
onValueRender={(value: number) => `${Math.round(value)}`}
131
+
/>
132
+
</>
133
+
)}
97
134
</FormItem>
98
135
);
99
136
}
100
137
101
138
function String({ ext, name, setting, disabled }: SettingsProps) {
102
-
const { FormItem, FormText, TextInput } = Components;
103
-
const { value, displayName, description } = useConfigEntry<string>(
104
-
ext.uniqueId,
105
-
name
106
-
);
139
+
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
107
140
108
141
return (
109
142
<FormItem className={Margins.marginTop20} title={displayName}>
110
-
{description && (
111
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
112
-
)}
143
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
113
144
<TextInput
114
145
value={value ?? ""}
115
-
onChange={(value: string) => {
116
-
if (disabled) return;
117
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
118
-
}}
146
+
disabled={disabled}
147
+
onChange={(value: string) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)}
119
148
/>
120
149
</FormItem>
121
150
);
122
151
}
123
152
124
153
function MultilineString({ ext, name, setting, disabled }: SettingsProps) {
125
-
const { FormItem, FormText, TextArea } = Components;
126
-
const { value, displayName, description } = useConfigEntry<string>(
127
-
ext.uniqueId,
128
-
name
129
-
);
154
+
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
130
155
131
156
return (
132
157
<FormItem className={Margins.marginTop20} title={displayName}>
133
-
{description && (
134
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
135
-
)}
158
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
136
159
<TextArea
137
160
rows={5}
138
161
value={value ?? ""}
162
+
disabled={disabled}
139
163
className={"moonbase-resizeable"}
140
-
onChange={(value: string) => {
141
-
if (disabled) return;
142
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
143
-
}}
164
+
onChange={(value: string) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)}
144
165
/>
145
166
</FormItem>
146
167
);
147
168
}
148
169
149
170
function Select({ ext, name, setting, disabled }: SettingsProps) {
150
-
const { FormItem, FormText, SingleSelect } = Components;
151
-
const { value, displayName, description } = useConfigEntry<string>(
152
-
ext.uniqueId,
153
-
name
154
-
);
171
+
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
155
172
156
173
const castedSetting = setting as SelectSettingType;
157
174
const options = castedSetting.options;
158
175
159
176
return (
160
177
<FormItem className={Margins.marginTop20} title={displayName}>
161
-
{description && (
162
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
163
-
)}
178
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
164
179
<SingleSelect
165
180
autofocus={false}
166
181
clearable={false}
167
182
value={value ?? ""}
168
-
options={options.map((o: SelectOption) =>
169
-
typeof o === "string" ? { value: o, label: o } : o
170
-
)}
183
+
options={options.map((o: SelectOption) => (typeof o === "string" ? { value: o, label: o } : o))}
171
184
onChange={(value: string) => {
172
185
if (disabled) return;
173
186
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
···
178
191
}
179
192
180
193
function MultiSelect({ ext, name, setting, disabled }: SettingsProps) {
181
-
const { FormItem, FormText, Select, useVariableSelect, multiSelect } =
182
-
Components;
183
-
const { value, displayName, description } = useConfigEntry<string | string[]>(
184
-
ext.uniqueId,
185
-
name
186
-
);
194
+
const { value, displayName, description } = useConfigEntry<string | string[]>(ext.uniqueId, name);
187
195
188
196
const castedSetting = setting as MultiSelectSettingType;
189
197
const options = castedSetting.options;
190
198
191
199
return (
192
200
<FormItem className={Margins.marginTop20} title={displayName}>
193
-
{description && (
194
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
195
-
)}
196
-
<Select
201
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
202
+
<DiscordSelect
197
203
autofocus={false}
198
204
clearable={false}
199
205
closeOnSelect={false}
200
-
options={options.map((o: SelectOption) =>
201
-
typeof o === "string" ? { value: o, label: o } : o
202
-
)}
206
+
options={options.map((o: SelectOption) => (typeof o === "string" ? { value: o, label: o } : o))}
203
207
{...useVariableSelect({
204
208
onSelectInteraction: multiSelect,
205
-
value: new Set(Array.isArray(value) ? value : [value]),
209
+
value: value == null ? new Set() : new Set(Array.isArray(value) ? value : [value]),
206
210
onChange: (value: string) => {
207
211
if (disabled) return;
208
-
MoonbaseSettingsStore.setExtensionConfig(
209
-
ext.id,
210
-
name,
211
-
Array.from(value)
212
-
);
212
+
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, Array.from(value));
213
213
}
214
214
})}
215
215
/>
···
217
217
);
218
218
}
219
219
220
-
const RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0]
221
-
.exports;
222
-
223
-
// FIXME: type component keys
224
-
const { CircleXIcon } = Components;
225
-
226
-
function RemoveEntryButton({
227
-
onClick,
228
-
disabled
229
-
}: {
230
-
onClick: () => void;
231
-
disabled: boolean;
232
-
}) {
233
-
const { Tooltip, Clickable } = Components;
220
+
function RemoveEntryButton({ onClick, disabled }: { onClick: () => void; disabled: boolean }) {
234
221
return (
235
-
<div className={RemoveButtonClasses.removeButtonContainer}>
222
+
<div className={GuildSettingsRoleEditClasses.removeButtonContainer}>
236
223
<Tooltip text="Remove entry" position="top">
237
224
{(props: any) => (
238
-
<Clickable
239
-
{...props}
240
-
className={RemoveButtonClasses.removeButton}
241
-
onClick={onClick}
242
-
>
225
+
<Clickable {...props} className={GuildSettingsRoleEditClasses.removeButton} onClick={onClick}>
243
226
<CircleXIcon width={16} height={16} />
244
227
</Clickable>
245
228
)}
···
249
232
}
250
233
251
234
function List({ ext, name, setting, disabled }: SettingsProps) {
252
-
const { FormItem, FormText, TextInput, Button } = Components;
253
-
const { value, displayName, description } = useConfigEntry<string[]>(
254
-
ext.uniqueId,
255
-
name
256
-
);
235
+
const { value, displayName, description } = useConfigEntry<string[]>(ext.uniqueId, name);
257
236
258
237
const entries = value ?? [];
259
-
const updateConfig = () =>
260
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, entries);
238
+
const updateConfig = () => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, entries);
261
239
262
240
return (
263
241
<FormItem className={Margins.marginTop20} title={displayName}>
264
-
{description && (
265
-
<FormText className={Margins.marginBottom4}>{description}</FormText>
266
-
)}
242
+
{description && <FormText className={Margins.marginBottom4}>{markdownify(description)}</FormText>}
267
243
<Flex direction={Flex.Direction.VERTICAL}>
268
244
{entries.map((val, i) => (
269
245
// FIXME: stylesheets
···
315
291
}
316
292
317
293
function Dictionary({ ext, name, setting, disabled }: SettingsProps) {
318
-
const { FormItem, FormText, TextInput, Button } = Components;
319
-
const { value, displayName, description } = useConfigEntry<
320
-
Record<string, string>
321
-
>(ext.uniqueId, name);
294
+
const { value, displayName, description } = useConfigEntry<Record<string, string>>(ext.uniqueId, name);
322
295
323
296
const entries = Object.entries(value ?? {});
324
-
const updateConfig = () =>
325
-
MoonbaseSettingsStore.setExtensionConfig(
326
-
ext.id,
327
-
name,
328
-
Object.fromEntries(entries)
329
-
);
297
+
const updateConfig = () => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, Object.fromEntries(entries));
330
298
331
299
return (
332
300
<FormItem className={Margins.marginTop20} title={displayName}>
333
-
{description && (
334
-
<FormText className={Margins.marginBottom4}>{description}</FormText>
335
-
)}
301
+
{description && <FormText className={Margins.marginBottom4}>{markdownify(description)}</FormText>}
336
302
<Flex direction={Flex.Direction.VERTICAL}>
337
303
{entries.map(([key, val], i) => (
338
304
// FIXME: stylesheets
···
399
365
[MoonbaseSettingsStore],
400
366
() => {
401
367
return {
402
-
component: MoonbaseSettingsStore.getExtensionConfigComponent(
403
-
ext.id,
404
-
name
405
-
)
368
+
component: MoonbaseSettingsStore.getExtensionConfigComponent(ext.id, name)
406
369
};
407
370
},
408
371
[ext.uniqueId, name]
409
372
);
410
373
411
374
if (Component == null) {
412
-
const { Text } = Components;
413
375
return (
414
-
<Text variant="text/md/normal">{`Custom setting "${displayName}" is missing a component. Perhaps the extension is not installed?`}</Text>
376
+
<Text variant="text-md/normal">{`Custom setting "${displayName}" is missing a component. Perhaps the extension is not installed?`}</Text>
415
377
);
416
378
}
417
379
418
380
return (
419
-
<Component
420
-
value={value}
421
-
setValue={(value) =>
422
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)
423
-
}
424
-
/>
381
+
<ErrorBoundary>
382
+
<Component value={value} setValue={(value) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)} />
383
+
</ErrorBoundary>
425
384
);
426
385
}
427
386
···
445
404
export default function Settings({ ext }: { ext: MoonbaseExtension }) {
446
405
return (
447
406
<Flex className="moonbase-settings" direction={Flex.Direction.VERTICAL}>
448
-
{Object.entries(ext.manifest.settings!).map(([name, setting]) => (
407
+
{Object.entries(ext.settingsOverride ?? ext.manifest.settings!).map(([name, setting]) => (
449
408
<Setting
450
409
ext={ext}
451
410
key={name}
+23
-29
packages/core-extensions/src/moonbase/webpackModules/ui/index.tsx
+23
-29
packages/core-extensions/src/moonbase/webpackModules/ui/index.tsx
···
1
1
import React from "@moonlight-mod/wp/react";
2
-
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
3
-
import {
4
-
Text,
5
-
TabBar
6
-
} from "@moonlight-mod/wp/discord/components/common/index";
2
+
import { Text, TabBar } from "@moonlight-mod/wp/discord/components/common/index";
7
3
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
8
4
import { UserSettingsModalStore } from "@moonlight-mod/wp/common_stores";
9
5
10
6
import ExtensionsPage from "./extensions";
11
7
import ConfigPage from "./config";
8
+
import AboutPage from "./about";
12
9
import Update from "./update";
13
-
14
-
const { Divider } = spacepack.findByCode(".forumOrHome]:")[0].exports.Z;
15
-
const TitleBarClasses = spacepack.findByCode("iconWrapper:", "children:")[0]
16
-
.exports;
17
-
const TabBarClasses = spacepack.findByCode("nowPlayingColumn:")[0].exports;
18
-
const { setSection, clearSubsection } = spacepack.findByExports(
19
-
"setSection",
20
-
"clearSubsection"
21
-
)[0].exports.Z;
22
-
const Margins = spacepack.require("discord/styles/shared/Margins.css");
10
+
import RestartAdviceMessage from "./RestartAdvice";
11
+
import { Divider } from "@moonlight-mod/wp/discord/components/common/BaseHeaderBar";
12
+
import HeaderBarClasses from "@moonlight-mod/wp/discord/components/common/HeaderBar.css";
13
+
import PeoplePageClasses from "@moonlight-mod/wp/discord/modules/people/web/PeoplePage.css";
14
+
import UserSettingsModalActionCreators from "@moonlight-mod/wp/discord/actions/UserSettingsModalActionCreators";
15
+
import Margins from "@moonlight-mod/wp/discord/styles/shared/Margins.css";
23
16
24
17
export const pages: {
25
18
id: string;
···
35
28
id: "config",
36
29
name: "Config",
37
30
element: ConfigPage
31
+
},
32
+
{
33
+
id: "about",
34
+
name: "About",
35
+
element: AboutPage
38
36
}
39
37
];
40
38
41
39
export function Moonbase(props: { initialTab?: number } = {}) {
42
-
const subsection = useStateFromStores(
43
-
[UserSettingsModalStore],
44
-
() => UserSettingsModalStore.getSubsection() ?? 0
45
-
);
40
+
const subsection = useStateFromStores([UserSettingsModalStore], () => UserSettingsModalStore.getSubsection() ?? 0);
46
41
const setSubsection = React.useCallback(
47
42
(to: string) => {
48
-
if (subsection !== to) setSection("moonbase", to);
43
+
if (subsection !== to) UserSettingsModalActionCreators.setSection("moonbase", to);
49
44
},
50
45
[subsection]
51
46
);
···
53
48
React.useEffect(
54
49
() => () => {
55
50
// Normally there's an onSettingsClose prop you can set but we don't expose it and I don't care enough to add support for it right now
56
-
clearSubsection("moonbase");
51
+
UserSettingsModalActionCreators.clearSubsection("moonbase");
57
52
},
58
53
[]
59
54
);
60
55
61
56
return (
62
57
<>
63
-
<div className={`${TitleBarClasses.children} ${Margins.marginBottom20}`}>
64
-
<Text
65
-
className={TitleBarClasses.titleWrapper}
66
-
variant="heading-lg/semibold"
67
-
tag="h2"
68
-
>
58
+
<div className={`${HeaderBarClasses.children} ${Margins.marginBottom20}`}>
59
+
<Text className={HeaderBarClasses.titleWrapper} variant="heading-lg/semibold" tag="h2">
69
60
Moonbase
70
61
</Text>
71
62
<Divider />
···
73
64
selectedItem={subsection}
74
65
onItemSelect={setSubsection}
75
66
type="top-pill"
76
-
className={TabBarClasses.tabBar}
67
+
className={PeoplePageClasses.tabBar}
77
68
>
78
69
{pages.map((page, i) => (
79
-
<TabBar.Item key={page.id} id={i} className={TabBarClasses.item}>
70
+
<TabBar.Item key={page.id} id={i} className={PeoplePageClasses.item}>
80
71
{page.name}
81
72
</TabBar.Item>
82
73
))}
83
74
</TabBar>
84
75
</div>
85
76
77
+
<RestartAdviceMessage />
86
78
<Update />
87
79
88
80
{React.createElement(pages[subsection].element)}
89
81
</>
90
82
);
91
83
}
84
+
85
+
export { RestartAdviceMessage, Update };
+104
-67
packages/core-extensions/src/moonbase/webpackModules/ui/update.tsx
+104
-67
packages/core-extensions/src/moonbase/webpackModules/ui/update.tsx
···
1
1
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
2
2
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
3
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
4
3
import React from "@moonlight-mod/wp/react";
5
-
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
4
+
import { UpdateState } from "../../types";
5
+
import HelpMessage from "./HelpMessage";
6
+
import { MoonlightBranch } from "@moonlight-mod/types";
7
+
import MarkupUtils from "@moonlight-mod/wp/discord/modules/markup/MarkupUtils";
6
8
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
7
-
8
-
enum UpdateState {
9
-
Ready,
10
-
Working,
11
-
Installed,
12
-
Failed
13
-
}
14
-
15
-
const { ThemeDarkIcon, Text, Button } = Components;
16
-
const Margins = spacepack.require("discord/styles/shared/Margins.css");
17
-
const HelpMessageClasses = spacepack.findByExports("positive", "iconDiv")[0]
18
-
.exports;
19
-
20
-
const logger = moonlight.getLogger("moonbase/ui/update");
9
+
import {
10
+
Button,
11
+
Text,
12
+
ModalRoot,
13
+
ModalSize,
14
+
ModalContent,
15
+
ModalHeader,
16
+
Heading,
17
+
ModalCloseButton,
18
+
openModal
19
+
} from "@moonlight-mod/wp/discord/components/common/index";
20
+
import MarkupClasses from "@moonlight-mod/wp/discord/modules/messages/web/Markup.css";
21
+
import ThemeDarkIcon from "@moonlight-mod/wp/moonbase_ThemeDarkIcon";
21
22
22
23
const strings: Record<UpdateState, string> = {
23
24
[UpdateState.Ready]: "A new version of moonlight is available.",
24
25
[UpdateState.Working]: "Updating moonlight...",
25
26
[UpdateState.Installed]: "Updated. Restart Discord to apply changes.",
26
-
[UpdateState.Failed]:
27
-
"Failed to update moonlight. Please use the installer instead."
27
+
[UpdateState.Failed]: "Failed to update moonlight. Please use the installer instead."
28
28
};
29
29
30
-
export default function Update() {
31
-
const [state, setState] = React.useState(UpdateState.Ready);
32
-
const newVersion = useStateFromStores(
33
-
[MoonbaseSettingsStore],
34
-
() => MoonbaseSettingsStore.newVersion
30
+
function MoonlightChangelog({
31
+
changelog,
32
+
version,
33
+
transitionState,
34
+
onClose
35
+
}: {
36
+
changelog: string;
37
+
version: string;
38
+
transitionState: number | null;
39
+
onClose: () => void;
40
+
}) {
41
+
return (
42
+
<ModalRoot transitionState={transitionState} size={ModalSize.DYNAMIC}>
43
+
<ModalHeader>
44
+
<Flex.Child grow={1} shrink={1}>
45
+
<Heading variant="heading-lg/semibold">moonlight</Heading>
46
+
<Text variant="text-xs/normal">{version}</Text>
47
+
</Flex.Child>
48
+
49
+
<Flex.Child grow={0}>
50
+
<ModalCloseButton onClick={onClose} />
51
+
</Flex.Child>
52
+
</ModalHeader>
53
+
54
+
<ModalContent>
55
+
<Text variant="text-md/normal" className={MarkupClasses.markup} style={{ padding: "1rem" }}>
56
+
{MarkupUtils.parse(changelog, true, {
57
+
allowHeading: true,
58
+
allowList: true,
59
+
allowLinks: true
60
+
})}
61
+
</Text>
62
+
</ModalContent>
63
+
</ModalRoot>
35
64
);
65
+
}
66
+
67
+
export default function Update() {
68
+
const [newVersion, state] = useStateFromStores([MoonbaseSettingsStore], () => [
69
+
MoonbaseSettingsStore.newVersion,
70
+
MoonbaseSettingsStore.updateState
71
+
]);
36
72
37
73
if (newVersion == null) return null;
38
74
39
-
// reimpl of HelpMessage but with a custom icon
40
75
return (
41
-
<div
42
-
className={`${Margins.marginBottom20} ${HelpMessageClasses.info} ${HelpMessageClasses.container} moonbase-update-section`}
43
-
>
44
-
<Flex direction={Flex.Direction.HORIZONTAL}>
45
-
<div
46
-
className={HelpMessageClasses.iconDiv}
47
-
style={{
48
-
alignItems: "center"
76
+
<HelpMessage text={strings[state]} className="moonbase-update-section" icon={ThemeDarkIcon}>
77
+
<div className="moonbase-help-message-buttons">
78
+
{moonlight.branch === MoonlightBranch.STABLE && (
79
+
<Button
80
+
look={Button.Looks.OUTLINED}
81
+
color={Button.Colors.CUSTOM}
82
+
size={Button.Sizes.TINY}
83
+
onClick={() => {
84
+
fetch(`https://raw.githubusercontent.com/moonlight-mod/moonlight/refs/tags/${newVersion}/CHANGELOG.md`)
85
+
.then((r) => r.text())
86
+
.then((changelog) =>
87
+
openModal((modalProps) => {
88
+
return <MoonlightChangelog {...modalProps} changelog={changelog} version={newVersion} />;
89
+
})
90
+
);
91
+
}}
92
+
>
93
+
View changelog
94
+
</Button>
95
+
)}
96
+
97
+
{state === UpdateState.Installed && (
98
+
<Button
99
+
look={Button.Looks.OUTLINED}
100
+
color={Button.Colors.CUSTOM}
101
+
size={Button.Sizes.TINY}
102
+
onClick={() => {
103
+
MoonbaseSettingsStore.restartDiscord();
104
+
}}
105
+
>
106
+
Restart Discord
107
+
</Button>
108
+
)}
109
+
110
+
<Button
111
+
look={Button.Looks.OUTLINED}
112
+
color={Button.Colors.CUSTOM}
113
+
size={Button.Sizes.TINY}
114
+
disabled={state !== UpdateState.Ready}
115
+
onClick={() => {
116
+
MoonbaseSettingsStore.updateMoonlight();
49
117
}}
50
118
>
51
-
<ThemeDarkIcon
52
-
size="sm"
53
-
color="currentColor"
54
-
className={HelpMessageClasses.icon}
55
-
/>
56
-
</div>
57
-
58
-
<Text
59
-
variant="text-sm/medium"
60
-
color="currentColor"
61
-
className={HelpMessageClasses.text}
62
-
>
63
-
{strings[state]}
64
-
</Text>
65
-
</Flex>
66
-
67
-
<Button
68
-
look={Button.Looks.OUTLINED}
69
-
color={Button.Colors.CUSTOM}
70
-
size={Button.Sizes.TINY}
71
-
disabled={state !== UpdateState.Ready}
72
-
onClick={() => {
73
-
setState(UpdateState.Working);
74
-
75
-
MoonbaseSettingsStore.updateMoonlight()
76
-
.then(() => setState(UpdateState.Installed))
77
-
.catch((e) => {
78
-
logger.error(e);
79
-
setState(UpdateState.Failed);
80
-
});
81
-
}}
82
-
>
83
-
Update
84
-
</Button>
85
-
</div>
119
+
Update
120
+
</Button>
121
+
</div>
122
+
</HelpMessage>
86
123
);
87
124
}
+9
-42
packages/core-extensions/src/moonbase/webpackModules/updates.tsx
+9
-42
packages/core-extensions/src/moonbase/webpackModules/updates.tsx
···
3
3
import Notices from "@moonlight-mod/wp/notices_notices";
4
4
import { MoonlightBranch } from "@moonlight-mod/types";
5
5
import React from "@moonlight-mod/wp/react";
6
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
7
-
8
-
// FIXME: not indexed as importable
9
-
const Constants = spacepack.require("discord/Constants");
10
-
const UserSettingsSections = spacepack.findObjectFromKey(
11
-
Constants,
12
-
"APPEARANCE_THEME_PICKER"
13
-
);
14
-
15
-
const { ThemeDarkIcon } = Components;
6
+
import ThemeDarkIcon from "@moonlight-mod/wp/moonbase_ThemeDarkIcon";
16
7
17
8
function plural(str: string, num: number) {
18
9
return `${str}${num > 1 ? "s" : ""}`;
···
21
12
function listener() {
22
13
if (
23
14
MoonbaseSettingsStore.shouldShowNotice &&
24
-
MoonbaseSettingsStore.getExtensionConfigRaw(
25
-
"moonbase",
26
-
"updateBanner",
27
-
true
28
-
)
15
+
MoonbaseSettingsStore.getExtensionConfigRaw("moonbase", "updateBanner", true)
29
16
) {
30
-
// @ts-expect-error epic type fail
31
17
MoonbaseSettingsStore.removeChangeListener(listener);
32
18
33
19
const version = MoonbaseSettingsStore.newVersion;
34
-
const extensionUpdateCount = Object.keys(
35
-
MoonbaseSettingsStore.updates
36
-
).length;
20
+
const extensionUpdateCount = Object.keys(MoonbaseSettingsStore.updates).length;
37
21
const hasExtensionUpdates = extensionUpdateCount > 0;
38
22
39
23
let message;
···
73
57
{
74
58
name: "Open Moonbase",
75
59
onClick: () => {
76
-
const { open } = spacepack.findByExports(
77
-
"setSection",
78
-
"clearSubsection"
79
-
)[0].exports.Z;
80
-
81
-
// settings is lazy loaded thus lazily patched
82
-
// FIXME: figure out a way to detect if settings has been opened
83
-
// alreadyjust so the transition isnt as jarring
84
-
open(UserSettingsSections.ACCOUNT);
85
-
setTimeout(() => {
86
-
if (
87
-
MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
88
-
"moonbase",
89
-
"sections",
90
-
false
91
-
)
92
-
) {
93
-
open("moonbase-extensions");
94
-
} else {
95
-
open("moonbase", 0);
96
-
}
97
-
}, 0);
60
+
const { open } = spacepack.require("discord/actions/UserSettingsModalActionCreators").default;
61
+
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "sections", false)) {
62
+
open("moonbase-extensions");
63
+
} else {
64
+
open("moonbase", "0");
65
+
}
98
66
return true;
99
67
}
100
68
}
···
103
71
}
104
72
}
105
73
106
-
// @ts-expect-error epic type fail
107
74
MoonbaseSettingsStore.addChangeListener(listener);
+5
packages/core-extensions/src/moonbase/wp.d.ts
+5
packages/core-extensions/src/moonbase/wp.d.ts
···
5
5
declare module "@moonlight-mod/wp/moonbase_stores" {
6
6
export * from "core-extensions/src/moonbase/webpackModules/stores";
7
7
}
8
+
9
+
declare module "@moonlight-mod/wp/moonbase_ThemeDarkIcon" {
10
+
import ThemeDarkIcon from "core-extensions/src/moonbase/webpackModules/ThemeDarkIcon";
11
+
export = ThemeDarkIcon;
12
+
}
+150
-43
packages/core-extensions/src/nativeFixes/host.ts
+150
-43
packages/core-extensions/src/nativeFixes/host.ts
···
1
1
import { app, nativeTheme } from "electron";
2
+
import * as path from "node:path";
3
+
import * as fs from "node:fs/promises";
4
+
import * as fsSync from "node:fs";
5
+
import { parseTarGzip } from "nanotar";
2
6
3
-
const enabledFeatures = app.commandLine
4
-
.getSwitchValue("enable-features")
5
-
.split(",");
7
+
const logger = moonlightHost.getLogger("nativeFixes/host");
8
+
const enabledFeatures = app.commandLine.getSwitchValue("enable-features").split(",");
6
9
7
10
moonlightHost.events.on("window-created", function (browserWindow) {
8
-
if (
9
-
moonlightHost.getConfigOption<boolean>("nativeFixes", "devtoolsThemeFix") ??
10
-
true
11
-
) {
11
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "devtoolsThemeFix") ?? true) {
12
12
browserWindow.webContents.on("devtools-opened", () => {
13
13
if (!nativeTheme.shouldUseDarkColors) return;
14
14
nativeTheme.themeSource = "light";
···
19
19
}
20
20
});
21
21
22
-
if (
23
-
moonlightHost.getConfigOption<boolean>(
24
-
"nativeFixes",
25
-
"disableRendererBackgrounding"
26
-
) ??
27
-
true
28
-
) {
22
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "disableRendererBackgrounding") ?? true) {
29
23
// Discord already disables UseEcoQoSForBackgroundProcess and some other
30
24
// related features
31
25
app.commandLine.appendSwitch("disable-renderer-backgrounding");
···
35
29
app.commandLine.appendSwitch("disable-background-timer-throttling");
36
30
}
37
31
32
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "vulkan") ?? false) {
33
+
enabledFeatures.push("Vulkan", "DefaultANGLEVulkan", "VulkanFromANGLE");
34
+
}
35
+
38
36
if (process.platform === "linux") {
39
-
if (
40
-
moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxAutoscroll") ??
41
-
false
42
-
) {
43
-
app.commandLine.appendSwitch(
44
-
"enable-blink-features",
45
-
"MiddleClickAutoscroll"
46
-
);
37
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxAutoscroll") ?? false) {
38
+
app.commandLine.appendSwitch("enable-blink-features", "MiddleClickAutoscroll");
47
39
}
48
40
49
-
if (
50
-
moonlightHost.getConfigOption<boolean>(
51
-
"nativeFixes",
52
-
"linuxSpeechDispatcher"
53
-
) ??
54
-
true
55
-
) {
41
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxSpeechDispatcher") ?? true) {
56
42
app.commandLine.appendSwitch("enable-speech-dispatcher");
57
43
}
44
+
45
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxHevcSupport") ?? true) {
46
+
enabledFeatures.push("PlatformHEVCDecoderSupport");
47
+
}
58
48
}
59
49
60
50
// NOTE: Only tested if this appears on Windows, it should appear on all when
61
51
// hardware acceleration is disabled
62
52
const noAccel = app.commandLine.hasSwitch("disable-gpu-compositing");
63
-
if (
64
-
(moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapi") ?? true) &&
65
-
!noAccel
66
-
) {
67
-
if (process.platform === "linux")
53
+
if ((moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapi") ?? true) && !noAccel) {
54
+
if (process.platform === "linux") {
68
55
// These will eventually be renamed https://source.chromium.org/chromium/chromium/src/+/5482210941a94d70406b8da962426e4faca7fce4
69
-
enabledFeatures.push(
70
-
"VaapiVideoEncoder",
71
-
"VaapiVideoDecoder",
72
-
"VaapiVideoDecodeLinuxGL"
73
-
);
56
+
enabledFeatures.push("VaapiVideoEncoder", "VaapiVideoDecoder", "VaapiVideoDecodeLinuxGL");
57
+
58
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapiIgnoreDriverChecks") ?? false)
59
+
enabledFeatures.push("VaapiIgnoreDriverChecks");
60
+
}
74
61
}
75
62
76
-
app.commandLine.appendSwitch(
77
-
"enable-features",
78
-
[...new Set(enabledFeatures)].join(",")
79
-
);
63
+
app.commandLine.appendSwitch("enable-features", [...new Set(enabledFeatures)].join(","));
64
+
65
+
if (process.platform === "linux" && moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxUpdater")) {
66
+
const exePath = app.getPath("exe");
67
+
const appName = path.basename(exePath);
68
+
const targetDir = path.dirname(exePath);
69
+
const { releaseChannel }: { releaseChannel: string } = JSON.parse(
70
+
fsSync.readFileSync(path.join(targetDir, "resources", "build_info.json"), "utf8")
71
+
);
72
+
73
+
const updaterModule = require(path.join(moonlightHost.asarPath, "app_bootstrap", "hostUpdater.js"));
74
+
const updater = updaterModule.constructor;
75
+
76
+
async function doUpdate(cb: (percent: number) => void) {
77
+
logger.debug("Extracting to", targetDir);
78
+
79
+
const exists = (path: string) =>
80
+
fs
81
+
.stat(path)
82
+
.then(() => true)
83
+
.catch(() => false);
84
+
85
+
const url = `https://discord.com/api/download/${releaseChannel}?platform=linux&format=tar.gz`;
86
+
const resp = await fetch(url, {
87
+
cache: "no-store"
88
+
});
89
+
90
+
const reader = resp.body!.getReader();
91
+
const contentLength = parseInt(resp.headers.get("Content-Length") ?? "0");
92
+
logger.info(`Expecting ${contentLength} bytes for the update`);
93
+
const bytes = new Uint8Array(contentLength);
94
+
let pos = 0;
95
+
let lastPercent = 0;
96
+
97
+
while (true) {
98
+
const { done, value } = await reader.read();
99
+
if (done) {
100
+
break;
101
+
} else {
102
+
bytes.set(value, pos);
103
+
pos += value.length;
104
+
105
+
const newPercent = Math.floor((pos / contentLength) * 100);
106
+
if (lastPercent !== newPercent) {
107
+
lastPercent = newPercent;
108
+
cb(newPercent);
109
+
}
110
+
}
111
+
}
112
+
113
+
const files = await parseTarGzip(bytes);
114
+
115
+
for (const file of files) {
116
+
if (!file.data) continue;
117
+
// @ts-expect-error What do you mean their own types are wrong
118
+
if (file.type !== "file") continue;
119
+
120
+
// Discord update files are inside of a main "Discord(PTB|Canary)" folder
121
+
const filePath = file.name.replace(`${appName}/`, "");
122
+
logger.info("Extracting", filePath);
123
+
124
+
let targetFilePath = path.join(targetDir, filePath);
125
+
if (filePath === "resources/app.asar") {
126
+
// You tried
127
+
targetFilePath = path.join(targetDir, "resources", "_app.asar");
128
+
} else if (filePath === appName || filePath === "chrome_crashpad_handler") {
129
+
// Can't write over the executable? Just move it! 4head
130
+
if (await exists(targetFilePath)) {
131
+
await fs.rename(targetFilePath, targetFilePath + ".bak");
132
+
await fs.unlink(targetFilePath + ".bak");
133
+
}
134
+
}
135
+
const targetFileDir = path.dirname(targetFilePath);
136
+
137
+
if (!(await exists(targetFileDir))) await fs.mkdir(targetFileDir, { recursive: true });
138
+
await fs.writeFile(targetFilePath, file.data);
139
+
140
+
const mode = file.attrs?.mode;
141
+
if (mode != null) {
142
+
// Not sure why this slice is needed
143
+
await fs.chmod(targetFilePath, mode.slice(-3));
144
+
}
145
+
}
146
+
147
+
logger.debug("Done updating");
148
+
}
149
+
150
+
const realEmit = updater.prototype.emit;
151
+
updater.prototype.emit = function (event: string, ...args: any[]) {
152
+
// Arrow functions don't bind `this` :D
153
+
const call = (event: string, ...args: any[]) => realEmit.call(this, event, ...args);
154
+
155
+
if (event === "update-manually") {
156
+
const latestVerStr: string = args[0];
157
+
logger.debug("update-manually called, intercepting", latestVerStr);
158
+
call("update-available");
159
+
160
+
(async () => {
161
+
try {
162
+
await doUpdate((progress) => {
163
+
call("update-progress", progress);
164
+
});
165
+
// Copied from the win32 updater
166
+
this.updateVersion = latestVerStr;
167
+
call(
168
+
"update-downloaded",
169
+
{},
170
+
releaseChannel,
171
+
latestVerStr,
172
+
new Date(),
173
+
this.updateUrl,
174
+
this.quitAndInstall.bind(this)
175
+
);
176
+
} catch (e) {
177
+
logger.error("Error updating", e);
178
+
}
179
+
})();
180
+
181
+
return this;
182
+
} else {
183
+
return realEmit.call(this, event, ...args);
184
+
}
185
+
};
186
+
}
+36
-1
packages/core-extensions/src/nativeFixes/manifest.json
+36
-1
packages/core-extensions/src/nativeFixes/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "nativeFixes",
3
4
"meta": {
4
5
"name": "Native Fixes",
5
6
"tagline": "Various configurable fixes for Discord and Electron",
6
-
"authors": ["Cynosphere", "adryd"],
7
+
"authors": ["Cynosphere", "adryd", "NotNite"],
7
8
"tags": ["fixes"]
8
9
},
10
+
"environment": "desktop",
9
11
"settings": {
10
12
"devtoolsThemeFix": {
13
+
"advice": "restart",
11
14
"displayName": "Devtools Theme Fix",
12
15
"description": "Temporary workaround for devtools defaulting to light theme on Electron 32",
13
16
"type": "boolean",
14
17
"default": true
15
18
},
16
19
"disableRendererBackgrounding": {
20
+
"advice": "restart",
17
21
"displayName": "Disable Renderer Backgrounding",
18
22
"description": "This is enabled by default as a power saving measure, but it breaks screensharing and websocket connections fairly often",
19
23
"type": "boolean",
20
24
"default": true
21
25
},
26
+
"vulkan": {
27
+
"advice": "restart",
28
+
"displayName": "Enable Vulkan renderer",
29
+
"description": "Uses the Vulkan backend for rendering",
30
+
"type": "boolean",
31
+
"default": false
32
+
},
22
33
"linuxAutoscroll": {
34
+
"advice": "restart",
23
35
"displayName": "Enable middle click autoscroll on Linux",
24
36
"description": "Requires manual configuration of your system to disable middle click paste, has no effect on other operating systems",
25
37
"type": "boolean",
26
38
"default": false
27
39
},
28
40
"linuxSpeechDispatcher": {
41
+
"advice": "restart",
29
42
"displayName": "Enable speech-dispatcher for TTS on Linux",
30
43
"description": "Fixes text-to-speech. Has no effect on other operating systems",
31
44
"type": "boolean",
32
45
"default": true
33
46
},
34
47
"vaapi": {
48
+
"advice": "restart",
35
49
"displayName": "Enable VAAPI features on Linux",
36
50
"description": "Provides hardware accelerated video encode and decode. Has no effect on other operating systems",
51
+
"type": "boolean",
52
+
"default": true
53
+
},
54
+
"vaapiIgnoreDriverChecks": {
55
+
"advice": "restart",
56
+
"displayName": "Ignore VAAPI driver checks on Linux",
57
+
"description": "Forces hardware video acceleration on some graphics drivers at the cost of stability. Has no effect on other operating systems",
58
+
"type": "boolean",
59
+
"default": false
60
+
},
61
+
"linuxUpdater": {
62
+
"advice": "restart",
63
+
"displayName": "Linux Updater",
64
+
"description": "Actually implements updating Discord on Linux. Has no effect on other operating systems",
65
+
"type": "boolean",
66
+
"default": false
67
+
},
68
+
"linuxHevcSupport": {
69
+
"advice": "restart",
70
+
"displayName": "HEVC support on Linux",
71
+
"description": "You might also need to enable Vulkan renderer. Has no effect on other operating systems",
37
72
"type": "boolean",
38
73
"default": true
39
74
}
+3
-3
packages/core-extensions/src/noHideToken/index.ts
+3
-3
packages/core-extensions/src/noHideToken/index.ts
+1
packages/core-extensions/src/noHideToken/manifest.json
+1
packages/core-extensions/src/noHideToken/manifest.json
+3
-3
packages/core-extensions/src/noTrack/index.ts
+3
-3
packages/core-extensions/src/noTrack/index.ts
···
2
2
3
3
export const patches: Patch[] = [
4
4
{
5
-
find: "analyticsTrackingStoreMaker:function",
5
+
find: "analyticsTrackingStoreMaker:()=>",
6
6
replace: {
7
-
match: /analyticsTrackingStoreMaker:function\(\){return .+?}/,
8
-
replacement: "analyticsTrackingStoreMaker:function(){return ()=>{}}"
7
+
match: /analyticsTrackingStoreMaker:\(\)=>.+?,/,
8
+
replacement: "analyticsTrackingStoreMaker:()=>()=>{},"
9
9
}
10
10
},
11
11
{
+4
-1
packages/core-extensions/src/noTrack/manifest.json
+4
-1
packages/core-extensions/src/noTrack/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "noTrack",
3
4
"apiLevel": 2,
4
5
"meta": {
···
9
10
},
10
11
"blocked": [
11
12
"https://*.discord.com/api/v*/science",
12
-
"https://*.discord.com/api/v*/metrics"
13
+
"https://*.discord.com/api/v*/metrics",
14
+
"https://*.discordapp.com/api/v*/science",
15
+
"https://*.discordapp.com/api/v*/metrics"
13
16
]
14
17
}
+2
-6
packages/core-extensions/src/notices/index.ts
+2
-6
packages/core-extensions/src/notices/index.ts
···
4
4
{
5
5
find: ".GUILD_RAID_NOTIFICATION:",
6
6
replace: {
7
-
match:
8
-
/(?<=return(\(0,.\.jsx\))\(.+?\);)case .{1,2}\..{1,3}\.GUILD_RAID_NOTIFICATION:/,
7
+
match: /(?<=return(\(0,.\.jsx\))\(.+?\);)case .{1,2}\..{1,3}\.GUILD_RAID_NOTIFICATION:/,
9
8
replacement: (orig, createElement) =>
10
9
`case "__moonlight_notice":return${createElement}(require("notices_component").default,{});${orig}`
11
10
}
···
28
27
29
28
export const webpackModules: Record<string, ExtensionWebpackModule> = {
30
29
notices: {
31
-
dependencies: [
32
-
{ id: "discord/packages/flux" },
33
-
{ id: "discord/Dispatcher" }
34
-
]
30
+
dependencies: [{ id: "discord/packages/flux" }, { id: "discord/Dispatcher" }]
35
31
},
36
32
37
33
component: {
+1
packages/core-extensions/src/notices/manifest.json
+1
packages/core-extensions/src/notices/manifest.json
+4
-10
packages/core-extensions/src/notices/webpackModules/component.tsx
+4
-10
packages/core-extensions/src/notices/webpackModules/component.tsx
···
1
1
import React from "@moonlight-mod/wp/react";
2
2
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
3
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
3
+
import { Notice, NoticeCloseButton, PrimaryCTANoticeButton } from "@moonlight-mod/wp/discord/components/common/index";
4
4
import { useStateFromStoresObject } from "@moonlight-mod/wp/discord/packages/flux";
5
5
import NoticesStore from "@moonlight-mod/wp/notices_notices";
6
-
import type { Notice } from "@moonlight-mod/types/coreExtensions/notices";
6
+
import type { Notice as NoticeType } from "@moonlight-mod/types/coreExtensions/notices";
7
7
8
-
// FIXME: types
9
-
const { Notice, NoticeCloseButton, PrimaryCTANoticeButton } = Components;
10
-
11
-
function popAndDismiss(notice: Notice) {
8
+
function popAndDismiss(notice: NoticeType) {
12
9
NoticesStore.popNotice();
13
10
if (notice?.onDismiss) {
14
11
notice.onDismiss();
···
32
29
{notice.element}
33
30
34
31
{(notice.showClose ?? true) && (
35
-
<NoticeCloseButton
36
-
onClick={() => popAndDismiss(notice)}
37
-
noticeType="__moonlight_notice"
38
-
/>
32
+
<NoticeCloseButton onClick={() => popAndDismiss(notice)} noticeType="__moonlight_notice" />
39
33
)}
40
34
41
35
{(notice.buttons ?? []).map((button) => (
+1
-4
packages/core-extensions/src/notices/webpackModules/notices.ts
+1
-4
packages/core-extensions/src/notices/webpackModules/notices.ts
···
1
1
import { Store } from "@moonlight-mod/wp/discord/packages/flux";
2
2
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
3
-
import type {
4
-
Notice,
5
-
Notices
6
-
} from "@moonlight-mod/types/coreExtensions/notices";
3
+
import type { Notice, Notices } from "@moonlight-mod/types/coreExtensions/notices";
7
4
8
5
// very lazy way of doing this, FIXME
9
6
let open = false;
+95
-37
packages/core-extensions/src/quietLoggers/index.ts
+95
-37
packages/core-extensions/src/quietLoggers/index.ts
···
1
1
import { Patch } from "@moonlight-mod/types";
2
2
3
3
const notXssDefensesOnly = () =>
4
-
(moonlight.getConfigOption<boolean>("quietLoggers", "xssDefensesOnly") ??
5
-
false) === false;
4
+
(moonlight.getConfigOption<boolean>("quietLoggers", "xssDefensesOnly") ?? false) === false;
5
+
6
+
const silenceDiscordLogger = moonlight.getConfigOption<boolean>("quietLoggers", "silenceDiscordLogger") ?? false;
6
7
7
8
// These patches MUST run before the simple patches, these are to remove loggers
8
9
// that end up causing syntax errors by the normal patch
···
17
18
{
18
19
find: '("GatewaySocket")',
19
20
replace: {
20
-
match: /.\.(info|log)(\(.+?\))(;|,)/g,
21
-
replacement: (_, type, body, trail) => `(()=>{})${body}${trail}`
21
+
match: /\i\.(log|info)\(/g,
22
+
replacement: "(()=>{})("
23
+
}
24
+
},
25
+
{
26
+
find: '"_connect called with already existing websocket"',
27
+
replace: {
28
+
match: /\i\.(log|info|verbose)\(/g,
29
+
replacement: "(()=>{})("
22
30
}
23
31
}
24
32
];
···
29
37
// Patches to simply remove a logger call
30
38
const stubPatches = [
31
39
// "sh" is not a valid locale.
32
-
[
33
-
"is not a valid locale",
34
-
/(.)\.error\(""\.concat\((.)," is not a valid locale\."\)\)/g
35
-
],
36
-
['="RunningGameStore"', /.\.info\("games",{.+?}\),/],
40
+
["is not a valid locale", /void \i\.error\(""\.concat\(\i," is not a valid locale\."\)\)/g],
41
+
['"[BUILD INFO] Release Channel: "', /new \i\.Z\(\)\.log\("\[BUILD INFO\] Release Channel: ".+?\)\),/],
42
+
['.APP_NATIVE_CRASH,"Storage"', /console\.log\("AppCrashedFatalReport lastCrash:",\i,\i\);/],
43
+
['.APP_NATIVE_CRASH,"Storage"', 'void console.log("AppCrashedFatalReport: getLastCrash not supported.")'],
44
+
['"[NATIVE INFO] ', /new \i\.Z\(\)\.log\("\[NATIVE INFO] .+?\)\);/],
45
+
['"Spellchecker"', /\i\.info\("Switching to ".+?"\(unavailable\)"\);?/g],
46
+
['throw Error("Messages are still loading.");', /console\.warn\("Unsupported Locale",\i\),/],
47
+
["}_dispatchWithDevtools(", /\i\.totalTime>\i&&\i\.verbose\(.+?\);/],
48
+
['"NativeDispatchUtils"', /null==\i&&\i\.warn\("Tried getting Dispatch instance before instantiated"\),/],
37
49
[
38
-
'"[BUILD INFO] Release Channel: "',
39
-
/new .{1,2}\.Z\(\)\.log\("\[BUILD INFO\] Release Channel: ".+?"\)\),/
50
+
'"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. Action: "',
51
+
/\i\.has\(\i\.type\)&&\i\.log\(.+?\.type\)\),/
40
52
],
53
+
['console.warn("Window state not initialized"', /console\.warn\("Window state not initialized",\i\),/],
54
+
['.name="MaxListenersExceededWarning",', /(?<=\.length),\i\(\i\)/],
41
55
[
42
-
'.APP_NATIVE_CRASH,"Storage"',
43
-
/console\.log\("AppCrashedFatalReport lastCrash:",.,.\);/
56
+
'"The answer for life the universe and everything is:"',
57
+
/\i\.info\("The answer for life the universe and everything is:",\i\),/
44
58
],
45
59
[
46
-
'.APP_NATIVE_CRASH,"Storage"',
47
-
'console.log("AppCrashedFatalReport: getLastCrash not supported.");'
60
+
'"isLibdiscoreBlockedDomainsEnabled called but libdiscore is not loaded"',
61
+
/,\i\.verbose\("isLibdiscoreBlockedDomainsEnabledThisSession: ".concat\(\i\)\)/
48
62
],
49
-
['"[NATIVE INFO] ', /new .{1,2}\.Z\(\)\.log\("\[NATIVE INFO] .+?\)\);/],
50
-
['"Spellchecker"', /.\.info\("Switching to ".+?"\(unavailable\)"\);?/g],
51
63
[
52
-
'throw Error("Messages are still loading.");',
53
-
/console\.warn\("Unsupported Locale",.\),/
64
+
'"Unable to determine render window for element"',
65
+
/console\.warn\("Unable to determine render window for element",\i\),/
54
66
],
55
-
["}_dispatchWithDevtools(", /.\.totalTime>100&&.\.verbose\(.+?\);/],
56
67
[
57
-
'"NativeDispatchUtils"',
58
-
/null==.&&.\.warn\("Tried getting Dispatch instance before instantiated"\),/
68
+
'"Unable to determine render window for element"',
69
+
/console\.warn\('Unable to find element constructor "'\.concat\(\i,'" in'\),\i\),/
59
70
],
60
-
['("DatabaseManager")', /.\.log\("removing database \(user: ".+?\)\),/],
61
71
[
62
-
'"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. Action: "',
63
-
/.\.has\(.\.type\)&&.\.log\(.+?\.type\)\),/
72
+
'"[PostMessageTransport] Protocol error: event data should be an Array!"',
73
+
/void console\.warn\("\[PostMessageTransport] Protocol error: event data should be an Array!"\)/
64
74
],
65
75
[
66
-
'console.warn("Window state not initialized"',
67
-
/console\.warn\("Window state not initialized",.\),/
76
+
'("ComponentDispatchUtils")',
77
+
/new \i\.Z\("ComponentDispatchUtils"\)\.warn\("ComponentDispatch\.resubscribe: Resubscribe without existing subscription",\i\),/
68
78
]
69
79
];
70
80
81
+
const stripLoggers = [
82
+
'("OverlayRenderStore")',
83
+
'("FetchBlockedDomain")',
84
+
'="UserSettingsProtoLastWriteTimes",',
85
+
'("MessageActionCreators")',
86
+
'("Routing/Utils")',
87
+
'("DatabaseManager")',
88
+
'("KeyboardLayoutMapUtils")',
89
+
'("ChannelMessages")',
90
+
'("MessageQueue")',
91
+
'("RTCLatencyTestManager")',
92
+
'("OverlayStoreV3")',
93
+
'("OverlayBridgeStore")',
94
+
'("AuthenticationStore")',
95
+
'("ConnectionStore")',
96
+
'"Dispatched INITIAL_GUILD "',
97
+
'"handleIdentify called"',
98
+
'("Spotify")'
99
+
];
100
+
71
101
const simplePatches = [
72
102
// Moment.js deprecation warnings
73
-
["suppressDeprecationWarnings=!1", "suppressDeprecationWarnings=!0"],
74
-
75
-
// Zustand related
76
-
[
77
-
/console\.warn\("\[DEPRECATED\] Please use `subscribeWithSelector` middleware"\)/g,
78
-
"/*$&*/"
79
-
],
80
-
["this.getDebugLogging()", "false"]
103
+
["suppressDeprecationWarnings=!1", "suppressDeprecationWarnings=!0"]
81
104
] as { [0]: string | RegExp; [1]: string }[];
82
105
83
106
export const patches: Patch[] = [
84
107
{
85
-
find: ".Messages.XSSDefenses",
108
+
find: ".Messages.SELF_XSS_HEADER",
86
109
replace: {
87
-
match: /\(null!=.{1,2}&&"0\.0\.0"===.{1,2}\.remoteApp\.getVersion\(\)\)/,
110
+
match: /\(null!=\i&&"0\.0\.0"===\i\.remoteApp\.getVersion\(\)\)/,
88
111
replacement: "(true)"
89
112
}
90
113
},
114
+
{
115
+
find: '("ComponentDispatchUtils")',
116
+
replace: {
117
+
match:
118
+
/new \i\.Z\("ComponentDispatchUtils"\)\.warn\("ComponentDispatch\.subscribe: Attempting to add a duplicate listener",\i\)/,
119
+
replacement: "void 0"
120
+
},
121
+
prerequisite: notXssDefensesOnly
122
+
},
123
+
// Highlight.js deprecation warnings
124
+
{
125
+
find: "Deprecated as of",
126
+
replace: {
127
+
match: /console\./g,
128
+
replacement: "false&&console."
129
+
},
130
+
prerequisite: notXssDefensesOnly
131
+
},
132
+
// Discord's logger
133
+
{
134
+
find: "ฮฃ:",
135
+
replace: {
136
+
match: "for",
137
+
replacement: "return;for"
138
+
},
139
+
prerequisite: () => silenceDiscordLogger && notXssDefensesOnly()
140
+
},
91
141
...loggerFixes,
92
142
...stubPatches.map((patch) => ({
93
143
find: patch[0],
···
102
152
replace: {
103
153
match: patch[0],
104
154
replacement: patch[1]
155
+
},
156
+
prerequisite: notXssDefensesOnly
157
+
})),
158
+
...stripLoggers.map((find) => ({
159
+
find,
160
+
replace: {
161
+
match: /(\i|this\.logger)\.(log|warn|error|info|verbose)\(/g,
162
+
replacement: "(()=>{})("
105
163
},
106
164
prerequisite: notXssDefensesOnly
107
165
}))
+9
packages/core-extensions/src/quietLoggers/manifest.json
+9
packages/core-extensions/src/quietLoggers/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "quietLoggers",
3
4
"apiLevel": 2,
4
5
"meta": {
···
9
10
},
10
11
"settings": {
11
12
"xssDefensesOnly": {
13
+
"advice": "reload",
12
14
"displayName": "Only hide self-XSS",
13
15
"description": "Only disable self XSS prevention log",
16
+
"type": "boolean",
17
+
"default": false
18
+
},
19
+
"silenceDiscordLogger": {
20
+
"advice": "reload",
21
+
"displayName": "Silence Discord logger",
22
+
"description": "Hides all messages from Discord's logger (the logs that start with purple text in brackets)",
14
23
"type": "boolean",
15
24
"default": false
16
25
}
+46
-67
packages/core-extensions/src/rocketship/host/permissions.ts
+46
-67
packages/core-extensions/src/rocketship/host/permissions.ts
···
14
14
details: Electron.PermissionCheckHandlerHandlerDetails
15
15
) => boolean;
16
16
17
-
moonlightHost.events.on(
18
-
"window-created",
19
-
(window: BrowserWindow, isMainWindow: boolean) => {
20
-
if (!isMainWindow) return;
21
-
const windowSession = window.webContents.session;
17
+
moonlightHost.events.on("window-created", (window: BrowserWindow, isMainWindow: boolean) => {
18
+
if (!isMainWindow) return;
19
+
const windowSession = window.webContents.session;
22
20
23
-
// setPermissionRequestHandler
24
-
windowSession.setPermissionRequestHandler(
25
-
(webcontents, permission, callback, details) => {
26
-
let cbResult = false;
27
-
function fakeCallback(result: boolean) {
28
-
cbResult = result;
29
-
}
21
+
// setPermissionRequestHandler
22
+
windowSession.setPermissionRequestHandler((webcontents, permission, callback, details) => {
23
+
let cbResult = false;
24
+
function fakeCallback(result: boolean) {
25
+
cbResult = result;
26
+
}
30
27
31
-
if (caughtPermissionRequestHandler) {
32
-
caughtPermissionRequestHandler(
33
-
webcontents,
34
-
permission,
35
-
fakeCallback,
36
-
details
37
-
);
38
-
}
28
+
if (caughtPermissionRequestHandler) {
29
+
caughtPermissionRequestHandler(webcontents, permission, fakeCallback, details);
30
+
}
39
31
40
-
if (permission === "media" || permission === "display-capture") {
41
-
cbResult = true;
42
-
}
32
+
if (permission === "media" || permission === "display-capture") {
33
+
cbResult = true;
34
+
}
43
35
44
-
callback(cbResult);
45
-
}
46
-
);
36
+
callback(cbResult);
37
+
});
47
38
48
-
let caughtPermissionRequestHandler: PermissionRequestHandler | undefined;
39
+
let caughtPermissionRequestHandler: PermissionRequestHandler | undefined;
49
40
50
-
windowSession.setPermissionRequestHandler =
51
-
function catchSetPermissionRequestHandler(
52
-
handler: (
53
-
webcontents: Electron.WebContents,
54
-
permission: string,
55
-
callback: (permissionGranted: boolean) => void
56
-
) => void
57
-
) {
58
-
caughtPermissionRequestHandler = handler;
59
-
};
41
+
windowSession.setPermissionRequestHandler = function catchSetPermissionRequestHandler(
42
+
handler: (
43
+
webcontents: Electron.WebContents,
44
+
permission: string,
45
+
callback: (permissionGranted: boolean) => void
46
+
) => void
47
+
) {
48
+
caughtPermissionRequestHandler = handler;
49
+
};
60
50
61
-
// setPermissionCheckHandler
62
-
windowSession.setPermissionCheckHandler(
63
-
(webcontents, permission, requestingOrigin, details) => {
64
-
return false;
65
-
}
66
-
);
51
+
// setPermissionCheckHandler
52
+
windowSession.setPermissionCheckHandler((webcontents, permission, requestingOrigin, details) => {
53
+
return false;
54
+
});
67
55
68
-
let caughtPermissionCheckHandler: PermissionCheckHandler | undefined;
56
+
let caughtPermissionCheckHandler: PermissionCheckHandler | undefined;
69
57
70
-
windowSession.setPermissionCheckHandler(
71
-
(webcontents, permission, requestingOrigin, details) => {
72
-
let result = false;
58
+
windowSession.setPermissionCheckHandler((webcontents, permission, requestingOrigin, details) => {
59
+
let result = false;
73
60
74
-
if (caughtPermissionCheckHandler) {
75
-
result = caughtPermissionCheckHandler(
76
-
webcontents,
77
-
permission,
78
-
requestingOrigin,
79
-
details
80
-
);
81
-
}
61
+
if (caughtPermissionCheckHandler) {
62
+
result = caughtPermissionCheckHandler(webcontents, permission, requestingOrigin, details);
63
+
}
82
64
83
-
if (permission === "media" || permission === "display-capture") {
84
-
result = true;
85
-
}
65
+
if (permission === "media" || permission === "display-capture") {
66
+
result = true;
67
+
}
86
68
87
-
return result;
88
-
}
89
-
);
69
+
return result;
70
+
});
90
71
91
-
windowSession.setPermissionCheckHandler =
92
-
function catchSetPermissionCheckHandler(handler: PermissionCheckHandler) {
93
-
caughtPermissionCheckHandler = handler;
94
-
};
95
-
}
96
-
);
72
+
windowSession.setPermissionCheckHandler = function catchSetPermissionCheckHandler(handler: PermissionCheckHandler) {
73
+
caughtPermissionCheckHandler = handler;
74
+
};
75
+
});
+4
-12
packages/core-extensions/src/rocketship/host/types.ts
+4
-12
packages/core-extensions/src/rocketship/host/types.ts
···
1
1
// https://github.com/Vencord/venmic/blob/d737ef33eaae7a73d03ec02673e008cf0243434d/lib/module.d.ts
2
2
type DefaultProps = "node.name" | "application.name";
3
3
4
-
type LiteralUnion<LiteralType, BaseType extends string> =
5
-
| LiteralType
6
-
| (BaseType & Record<never, never>);
4
+
type LiteralUnion<LiteralType, BaseType extends string> = LiteralType | (BaseType & Record<never, never>);
7
5
8
-
type Optional<Type, Key extends keyof Type> = Partial<Pick<Type, Key>> &
9
-
Omit<Type, Key>;
6
+
type Optional<Type, Key extends keyof Type> = Partial<Pick<Type, Key>> & Omit<Type, Key>;
10
7
11
-
export type Node<T extends string = never> = Record<
12
-
LiteralUnion<T, string>,
13
-
string
14
-
>;
8
+
export type Node<T extends string = never> = Record<LiteralUnion<T, string>, string>;
15
9
16
10
export interface LinkData {
17
11
include: Node[];
···
29
23
unlink(): void;
30
24
31
25
list<T extends string = DefaultProps>(props?: T[]): Node<T>[];
32
-
link(
33
-
data: Optional<LinkData, "exclude"> | Optional<LinkData, "include">
34
-
): boolean;
26
+
link(data: Optional<LinkData, "exclude"> | Optional<LinkData, "include">): boolean;
35
27
}
+23
-31
packages/core-extensions/src/rocketship/host/venmic.ts
+23
-31
packages/core-extensions/src/rocketship/host/venmic.ts
···
7
7
8
8
function getPatchbay() {
9
9
try {
10
-
const venmic = require(
11
-
path.join(path.dirname(moonlightHost.asarPath), "..", "venmic.node")
12
-
) as { PatchBay: new () => PatchBay };
10
+
const venmic = require(path.join(path.dirname(moonlightHost.asarPath), "..", "venmic.node")) as {
11
+
PatchBay: new () => PatchBay;
12
+
};
13
13
const patchbay = new venmic.PatchBay();
14
14
return patchbay;
15
15
} catch (error) {
···
35
35
36
36
patchbay.unlink();
37
37
return patchbay.link({
38
-
exclude: [
39
-
{ "application.process.id": pid },
40
-
{ "media.class": "Stream/Input/Audio" }
41
-
],
38
+
exclude: [{ "application.process.id": pid }, { "media.class": "Stream/Input/Audio" }],
42
39
ignore_devices: true,
43
40
only_speakers: true,
44
41
only_default_speakers: true
···
49
46
}
50
47
}
51
48
52
-
moonlightHost.events.on(
53
-
"window-created",
54
-
(window: BrowserWindow, isMainWindow: boolean) => {
55
-
if (!isMainWindow) return;
56
-
const windowSession = window.webContents.session;
49
+
moonlightHost.events.on("window-created", (window: BrowserWindow, isMainWindow: boolean) => {
50
+
if (!isMainWindow) return;
51
+
const windowSession = window.webContents.session;
57
52
58
-
// @ts-expect-error these types ancient
59
-
windowSession.setDisplayMediaRequestHandler(
60
-
(request: any, callback: any) => {
61
-
const linked = linkVenmic();
62
-
desktopCapturer
63
-
.getSources({ types: ["screen", "window"] })
64
-
.then((sources) => {
65
-
//logger.debug("desktopCapturer.getSources", sources);
66
-
logger.debug("Linked to venmic:", linked);
53
+
// @ts-expect-error these types ancient
54
+
windowSession.setDisplayMediaRequestHandler(
55
+
(request: any, callback: any) => {
56
+
const linked = linkVenmic();
57
+
desktopCapturer.getSources({ types: ["screen", "window"] }).then((sources) => {
58
+
//logger.debug("desktopCapturer.getSources", sources);
59
+
logger.debug("Linked to venmic:", linked);
67
60
68
-
callback({
69
-
video: sources[0],
70
-
audio: "loopback"
71
-
});
72
-
});
73
-
},
74
-
{ useSystemPicker: true }
75
-
);
76
-
}
77
-
);
61
+
callback({
62
+
video: sources[0],
63
+
audio: "loopback"
64
+
});
65
+
});
66
+
},
67
+
{ useSystemPicker: true }
68
+
);
69
+
});
+5
-11
packages/core-extensions/src/rocketship/index.ts
+5
-11
packages/core-extensions/src/rocketship/index.ts
···
9
9
logger.debug("Devices:", devices);
10
10
11
11
// This isn't vencord :(
12
-
const id = devices.find((device) => device.label === "vencord-screen-share")
13
-
?.deviceId;
12
+
const id = devices.find((device) => device.label === "vencord-screen-share")?.deviceId;
14
13
if (!id) return null;
15
14
logger.debug("Got venmic device ID:", id);
16
15
···
32
31
}
33
32
}
34
33
35
-
navigator.mediaDevices.getDisplayMedia = async function getDisplayMediaRedirect(
36
-
options
37
-
) {
34
+
navigator.mediaDevices.getDisplayMedia = async function getDisplayMediaRedirect(options) {
38
35
const orig = await getDisplayMediaOrig.call(this, options);
39
36
40
37
const venmic = await getVenmicStream();
···
114
111
replace: [
115
112
// Prevent loading of krisp native module by stubbing out desktop checks
116
113
{
117
-
match:
118
-
/\(\(0,.\.isWindows\)\(\)\|\|\(0,.\.isLinux\)\(\)\|\|.+?&&!__OVERLAY__/,
114
+
match: /\(\(0,.\.isWindows\)\(\)\|\|\(0,.\.isLinux\)\(\)\|\|.+?&&!__OVERLAY__/,
119
115
replacement: (orig, macosPlatformCheck) => `false&&!__OVERLAY__`
120
116
},
121
117
// Enable loading of web krisp equivelant by replacing isWeb with true
122
118
{
123
-
match:
124
-
/\(0,.\.isWeb\)\(\)&&(.{1,2}\.supports\(.{1,2}\..{1,2}.NOISE_CANCELLATION)/,
125
-
replacement: (orig, supportsNoiseCancellation) =>
126
-
`true&&${supportsNoiseCancellation}`
119
+
match: /\(0,.\.isWeb\)\(\)&&(.{1,2}\.supports\(.{1,2}\..{1,2}.NOISE_CANCELLATION)/,
120
+
replacement: (orig, supportsNoiseCancellation) => `true&&${supportsNoiseCancellation}`
127
121
}
128
122
]
129
123
}
+4
-1
packages/core-extensions/src/rocketship/manifest.json
+4
-1
packages/core-extensions/src/rocketship/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "rocketship",
3
4
"apiLevel": 2,
5
+
"environment": "desktop",
4
6
"meta": {
5
7
"name": "Rocketship",
6
8
"tagline": "Adds new features when using rocketship",
7
9
"description": "**This extension only works on Linux when using rocketship:**\nhttps://github.com/moonlight-mod/rocketship\n\nAdds new features to the Discord Linux client with rocketship, such as a better screensharing experience.",
8
-
"authors": ["NotNite", "Cynosphere", "adryd"]
10
+
"authors": ["NotNite", "Cynosphere", "adryd"],
11
+
"deprecated": true
9
12
}
10
13
}
+3
-5
packages/core-extensions/src/settings/index.ts
+3
-5
packages/core-extensions/src/settings/index.ts
···
6
6
find: '"useGenerateUserSettingsSections"',
7
7
replace: {
8
8
match: /(?<=\.push\(.+?\)}\)\)}\),)(.+?)}/,
9
-
replacement: (_, sections: string) =>
10
-
`require("settings_settings").Settings._mutateSections(${sections})}`
9
+
replacement: (_, sections: string) => `require("settings_settings").Settings._mutateSections(${sections})}`
11
10
}
12
11
},
13
12
{
14
13
find: 'navId:"user-settings-cog",',
15
14
replace: {
16
-
match: /children:\[(.)\.map\(.+?\),children:.\((.)\)/,
15
+
match: /children:\[(\i)\.map\(.+?\),.*?children:\i\((\i)\)/,
17
16
replacement: (orig, sections, section) =>
18
17
`${orig.replace(
19
18
/Object\.values\(.\..+?\)/,
20
-
(orig) =>
21
-
`[...require("settings_settings").Settings.sectionNames,...${orig}]`
19
+
(orig) => `[...require("settings_settings").Settings.sectionNames,...${orig}]`
22
20
)}??${sections}.find(x=>x.section==${section})?._moonlight_submenu?.()`
23
21
}
24
22
}
+1
packages/core-extensions/src/settings/manifest.json
+1
packages/core-extensions/src/settings/manifest.json
+11
-13
packages/core-extensions/src/settings/webpackModules/settings.ts
+11
-13
packages/core-extensions/src/settings/webpackModules/settings.ts
···
1
-
import {
2
-
SettingsSection,
3
-
Settings as SettingsType
4
-
} from "@moonlight-mod/types/coreExtensions/settings";
1
+
import { SettingsSection, Settings as SettingsType } from "@moonlight-mod/types/coreExtensions/settings";
2
+
import UserSettingsModalActionCreators from "@moonlight-mod/wp/discord/actions/UserSettingsModalActionCreators";
5
3
6
4
export const Settings: SettingsType = {
7
5
ourSections: [],
8
6
sectionNames: [],
9
7
sectionMenuItems: {},
10
8
11
-
addSection: (section, label, element, color = null, pos, notice) => {
9
+
addSection: (section, label, element, color = null, pos, notice, onClick) => {
12
10
const data: SettingsSection = {
13
11
section,
14
12
label,
15
13
color,
16
14
element,
17
15
pos: pos ?? -4,
18
-
notice: notice
16
+
notice: notice,
17
+
onClick: onClick ?? (() => UserSettingsModalActionCreators.open(section))
19
18
};
20
19
21
20
Settings.ourSections.push(data);
···
24
23
},
25
24
addSectionMenuItems(section, ...newItems) {
26
25
const data = Settings.ourSections.find((x) => x.section === section);
27
-
if (!data || !("element" in data))
28
-
throw new Error(`Could not find section "${section}"`);
26
+
if (!data || !("element" in data)) throw new Error(`Could not find section "${section}"`);
29
27
(Settings.sectionMenuItems[section] ??= []).push(...newItems);
30
28
data._moonlight_submenu ??= () => Settings.sectionMenuItems[section];
31
29
},
···
47
45
48
46
_mutateSections: (sections) => {
49
47
for (const section of Settings.ourSections) {
50
-
sections.splice(
51
-
section.pos < 0 ? sections.length + section.pos : section.pos,
52
-
0,
53
-
section
54
-
);
48
+
// Discord's `pos` only supports numbers, so lets call the function to get the position.
49
+
if (typeof section.pos === "function") {
50
+
section.pos = section.pos(sections);
51
+
}
52
+
sections.splice(section.pos < 0 ? sections.length + section.pos : section.pos, 0, section);
55
53
}
56
54
57
55
return sections;
+2
packages/core-extensions/src/spacepack/manifest.json
+2
packages/core-extensions/src/spacepack/manifest.json
···
1
1
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
2
3
"id": "spacepack",
3
4
"apiLevel": 2,
4
5
"meta": {
···
9
10
},
10
11
"settings": {
11
12
"addToGlobalScope": {
13
+
"advice": "reload",
12
14
"displayName": "Add to global scope",
13
15
"description": "Populates window.spacepack for easier usage in DevTools",
14
16
"type": "boolean",
+84
-67
packages/core-extensions/src/spacepack/webpackModules/spacepack.ts
+84
-67
packages/core-extensions/src/spacepack/webpackModules/spacepack.ts
···
1
-
import {
2
-
WebpackModule,
3
-
WebpackModuleFunc,
4
-
WebpackRequireType
5
-
} from "@moonlight-mod/types";
1
+
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "@moonlight-mod/types";
6
2
import { Spacepack } from "@moonlight-mod/types/coreExtensions/spacepack";
3
+
import { processFind, testFind } from "@moonlight-mod/core/util/patch";
7
4
8
5
const webpackRequire = require as unknown as WebpackRequireType;
9
6
const cache = webpackRequire.c;
···
40
37
"module",
41
38
"exports",
42
39
"require",
43
-
`(${funcStr}).apply(this, arguments)\n` +
44
-
`//# sourceURL=Webpack-Module-${module}`
40
+
`(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module/${module.slice(0, 3)}/${module}`
45
41
) as WebpackModuleFunc;
46
42
},
47
43
48
44
findByCode: (...args: (string | RegExp)[]) => {
49
-
return Object.entries(modules)
50
-
.filter(
51
-
([id, mod]) =>
52
-
!args.some(
53
-
(item) =>
54
-
!(item instanceof RegExp
55
-
? item.test(mod.toString())
56
-
: mod.toString().indexOf(item) !== -1)
57
-
)
58
-
)
45
+
const ret = Object.entries(modules)
46
+
.filter(([id, mod]) => !args.some((item) => !testFind(mod.toString(), processFind(item))))
59
47
.map(([id]) => {
60
48
//if (!(id in cache)) require(id);
61
49
//return cache[id];
···
64
52
try {
65
53
exports = require(id);
66
54
} catch (e) {
67
-
logger.error(`Error requiring module "${id}": `, e);
55
+
logger.error(`findByCode: Error requiring module "${id}": `, args, e);
68
56
}
69
57
70
58
return {
···
73
61
};
74
62
})
75
63
.filter((item) => item !== null);
64
+
65
+
if (ret.length === 0) {
66
+
logger.warn("findByCode: Got zero results for", args, new Error().stack!.substring(5));
67
+
}
68
+
69
+
return ret;
76
70
},
77
71
78
72
findByExports: (...args: string[]) => {
···
84
78
!(
85
79
exports !== undefined &&
86
80
exports !== window &&
87
-
(exports?.[item] ||
88
-
exports?.default?.[item] ||
89
-
exports?.Z?.[item] ||
90
-
exports?.ZP?.[item])
81
+
(exports?.[item] || exports?.default?.[item] || exports?.Z?.[item] || exports?.ZP?.[item])
91
82
)
92
83
)
93
84
)
···
99
90
},
100
91
101
92
findObjectFromKey: (exports: Record<string, any>, key: string) => {
93
+
let ret = null;
102
94
let subKey;
103
95
if (key.indexOf(".") > -1) {
104
96
const splitKey = key.split(".");
···
109
101
const obj = exports[exportKey];
110
102
if (obj && obj[key] !== undefined) {
111
103
if (subKey) {
112
-
if (obj[key][subKey]) return obj;
104
+
if (obj[key][subKey]) {
105
+
ret = obj;
106
+
break;
107
+
}
113
108
} else {
114
-
return obj;
109
+
ret = obj;
110
+
break;
115
111
}
116
112
}
117
113
}
118
-
return null;
114
+
115
+
if (ret == null) {
116
+
logger.warn("Failed to find object by key", key, "in", exports, new Error().stack!.substring(5));
117
+
}
118
+
119
+
return ret;
119
120
},
120
121
121
122
findObjectFromValue: (exports: Record<string, any>, value: any) => {
123
+
let ret = null;
122
124
for (const exportKey in exports) {
123
125
const obj = exports[exportKey];
124
126
// eslint-disable-next-line eqeqeq
125
-
if (obj == value) return obj;
127
+
if (obj == value) {
128
+
ret = obj;
129
+
break;
130
+
}
126
131
for (const subKey in obj) {
127
132
// eslint-disable-next-line eqeqeq
128
133
if (obj && obj[subKey] == value) {
129
-
return obj;
134
+
ret = obj;
135
+
break;
130
136
}
131
137
}
132
138
}
133
-
return null;
139
+
140
+
if (ret == null) {
141
+
logger.warn("Failed to find object by value", value, "in", exports, new Error().stack!.substring(5));
142
+
}
143
+
144
+
return ret;
134
145
},
135
146
136
-
findObjectFromKeyValuePair: (
137
-
exports: Record<string, any>,
138
-
key: string,
139
-
value: any
140
-
) => {
147
+
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => {
148
+
let ret = null;
141
149
for (const exportKey in exports) {
142
150
const obj = exports[exportKey];
143
151
// eslint-disable-next-line eqeqeq
144
152
if (obj && obj[key] == value) {
145
-
return obj;
153
+
ret = obj;
154
+
break;
146
155
}
147
156
}
157
+
158
+
if (ret == null) {
159
+
logger.warn(
160
+
"Failed to find object by key value pair",
161
+
key,
162
+
value,
163
+
"in",
164
+
exports,
165
+
new Error().stack!.substring(5)
166
+
);
167
+
}
168
+
148
169
return null;
149
170
},
150
171
151
-
findFunctionByStrings: (
152
-
exports: Record<string, any>,
153
-
...strings: (string | RegExp)[]
154
-
) => {
155
-
return (
172
+
findFunctionByStrings: (exports: Record<string, any>, ...strings: (string | RegExp)[]) => {
173
+
const ret =
156
174
Object.entries(exports).filter(
157
175
([index, func]) =>
158
-
typeof func === "function" &&
159
-
!strings.some(
160
-
(query) =>
161
-
!(query instanceof RegExp
162
-
? func.toString().match(query)
163
-
: func.toString().includes(query))
164
-
)
165
-
)?.[0]?.[1] ?? null
166
-
);
176
+
typeof func === "function" && !strings.some((query) => !testFind(func.toString(), processFind(query)))
177
+
)?.[0]?.[1] ?? null;
178
+
179
+
if (ret == null) {
180
+
logger.warn("Failed to find function by strings", strings, "in", exports, new Error().stack!.substring(5));
181
+
}
182
+
183
+
return ret;
167
184
},
168
185
169
-
lazyLoad: (
170
-
find: string | RegExp | (string | RegExp)[],
171
-
chunk: RegExp,
172
-
module: RegExp
173
-
) => {
174
-
const mod = Array.isArray(find)
175
-
? spacepack.findByCode(...find)
176
-
: spacepack.findByCode(find);
177
-
if (mod.length < 1) return Promise.reject("Module find failed");
186
+
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => {
187
+
chunk = processFind(chunk);
188
+
module = processFind(module);
189
+
190
+
const mod = Array.isArray(find) ? spacepack.findByCode(...find) : spacepack.findByCode(find);
191
+
if (mod.length < 1) {
192
+
logger.warn("lazyLoad: Module find failed", find, chunk, module, new Error().stack!.substring(5));
193
+
return Promise.reject("Module find failed");
194
+
}
178
195
179
196
const findId = mod[0].id;
180
197
const findCode = webpackRequire.m[findId].toString().replace(/\n/g, "");
···
184
201
chunkIds = [...findCode.matchAll(chunk)].map(([, id]) => id);
185
202
} else {
186
203
const match = findCode.match(chunk);
187
-
if (match)
188
-
chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
204
+
if (match) chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
189
205
}
190
206
191
-
if (!chunkIds || chunkIds.length === 0)
207
+
if (!chunkIds || chunkIds.length === 0) {
208
+
logger.warn("lazyLoad: Chunk ID match failed", find, chunk, module, new Error().stack!.substring(5));
192
209
return Promise.reject("Chunk ID match failed");
210
+
}
193
211
194
212
const moduleId = findCode.match(module)?.[1];
195
-
if (!moduleId) return Promise.reject("Module ID match failed");
213
+
if (!moduleId) {
214
+
logger.warn("lazyLoad: Module ID match failed", find, chunk, module, new Error().stack!.substring(5));
215
+
return Promise.reject("Module ID match failed");
216
+
}
196
217
197
-
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() =>
198
-
webpackRequire(moduleId)
199
-
);
218
+
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() => webpackRequire(moduleId));
200
219
},
201
220
202
221
filterReal: (modules: WebpackModule[]) => {
···
204
223
}
205
224
};
206
225
207
-
if (
208
-
moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true
209
-
) {
226
+
if (moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true) {
210
227
window.spacepack = spacepack;
211
228
}
212
229
+4
-1
packages/core-extensions/tsconfig.json
+4
-1
packages/core-extensions/tsconfig.json
+10
-3
packages/injector/package.json
+10
-3
packages/injector/package.json
···
1
1
{
2
2
"name": "@moonlight-mod/injector",
3
3
"private": true,
4
+
"engines": {
5
+
"node": ">=22",
6
+
"pnpm": ">=10",
7
+
"npm": "pnpm",
8
+
"yarn": "pnpm"
9
+
},
4
10
"dependencies": {
5
-
"@moonlight-mod/types": "workspace:*",
6
-
"@moonlight-mod/core": "workspace:*"
7
-
}
11
+
"@moonlight-mod/core": "workspace:*",
12
+
"@moonlight-mod/types": "workspace:*"
13
+
},
14
+
"engineStrict": true
8
15
}
+126
-119
packages/injector/src/index.ts
+126
-119
packages/injector/src/index.ts
···
6
6
} from "electron";
7
7
import Module from "node:module";
8
8
import { constants, MoonlightBranch } from "@moonlight-mod/types";
9
-
import { readConfig } from "@moonlight-mod/core/config";
9
+
import { readConfig, writeConfig } from "@moonlight-mod/core/config";
10
10
import { getExtensions } from "@moonlight-mod/core/extension";
11
11
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
12
-
import {
13
-
loadExtensions,
14
-
loadProcessedExtensions
15
-
} from "@moonlight-mod/core/extension/loader";
12
+
import { loadExtensions, loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
16
13
import EventEmitter from "node:events";
17
-
import { join, resolve } from "node:path";
14
+
import path from "node:path";
18
15
import persist from "@moonlight-mod/core/persist";
19
16
import createFS from "@moonlight-mod/core/fs";
17
+
import { getConfigOption, getManifest, setConfigOption } from "@moonlight-mod/core/util/config";
18
+
import { getConfigPath, getExtensionsPath, getMoonlightDir } from "@moonlight-mod/core/util/data";
20
19
21
20
const logger = new Logger("injector");
22
21
23
22
let oldPreloadPath: string | undefined;
24
23
let corsAllow: string[] = [];
25
24
let blockedUrls: RegExp[] = [];
26
-
let isMoonlightDesktop = false;
27
-
let hasOpenAsar = false;
28
-
let openAsarConfigPreload: string | undefined;
25
+
let injectorConfig: InjectorConfig | undefined;
26
+
27
+
const scriptUrls = ["web.", "sentry."];
28
+
const blockedScripts = new Set<string>();
29
29
30
30
ipcMain.on(constants.ipcGetOldPreloadPath, (e) => {
31
31
e.returnValue = oldPreloadPath;
32
32
});
33
+
33
34
ipcMain.on(constants.ipcGetAppData, (e) => {
34
35
e.returnValue = app.getPath("appData");
35
36
});
36
-
ipcMain.on(constants.ipcGetIsMoonlightDesktop, (e) => {
37
-
e.returnValue = isMoonlightDesktop;
37
+
ipcMain.on(constants.ipcGetInjectorConfig, (e) => {
38
+
e.returnValue = injectorConfig;
38
39
});
39
40
ipcMain.handle(constants.ipcMessageBox, (_, opts) => {
40
41
electron.dialog.showMessageBoxSync(opts);
···
44
45
});
45
46
46
47
const reEscapeRegExp = /[\\^$.*+?()[\]{}|]/g;
47
-
const reMatchPattern =
48
-
/^(?<scheme>\*|[a-z][a-z0-9+.-]*):\/\/(?<host>.+?)\/(?<path>.+)?$/;
48
+
const reMatchPattern = /^(?<scheme>\*|[a-z][a-z0-9+.-]*):\/\/(?<host>.+?)\/(?<path>.+)?$/;
49
49
50
50
const escapeRegExp = (s: string) => s.replace(reEscapeRegExp, "\\$&");
51
51
ipcMain.handle(constants.ipcSetBlockedList, (_, list: string[]) => {
···
76
76
blockedUrls = compiled;
77
77
});
78
78
79
-
function patchCsp(headers: Record<string, string[]>) {
80
-
const directives = [
81
-
"style-src",
82
-
"connect-src",
83
-
"img-src",
84
-
"font-src",
85
-
"media-src",
86
-
"worker-src",
87
-
"prefetch-src"
88
-
];
89
-
const values = ["*", "blob:", "data:", "'unsafe-inline'", "disclip:"];
79
+
function patchCsp(headers: Record<string, string[]>, extensionCspOverrides: Record<string, string[]>) {
80
+
const directives = ["script-src", "style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src"];
81
+
const values = ["*", "blob:", "data:", "'unsafe-inline'", "'unsafe-eval'", "disclip:"];
90
82
91
83
const csp = "content-security-policy";
92
84
if (headers[csp] == null) return;
···
105
97
parts[directive] = values;
106
98
}
107
99
100
+
for (const [directive, urls] of Object.entries(extensionCspOverrides)) {
101
+
parts[directive] ??= [];
102
+
parts[directive].push(...urls);
103
+
}
104
+
108
105
const stringified = Object.entries<string[]>(parts)
109
106
.map(([key, value]) => {
110
107
return `${key} ${value.join(" ")}`;
···
113
110
headers[csp] = [stringified];
114
111
}
115
112
116
-
function removeOpenAsarEventIfPresent(eventHandler: (...args: any[]) => void) {
117
-
const code = eventHandler.toString();
118
-
if (code.indexOf("bw.webContents.on('dom-ready'") > -1) {
119
-
electron.app.off("browser-window-created", eventHandler);
120
-
}
121
-
}
122
-
123
113
class BrowserWindow extends ElectronBrowserWindow {
124
114
constructor(opts: BrowserWindowConstructorOptions) {
125
-
oldPreloadPath = opts.webPreferences!.preload;
115
+
const isMainWindow = opts.webPreferences!.preload!.indexOf("discord_desktop_core") > -1;
126
116
127
-
const isMainWindow =
128
-
opts.webPreferences!.preload!.indexOf("discord_desktop_core") > -1;
129
-
130
-
if (isMainWindow)
117
+
if (isMainWindow) {
118
+
if (!oldPreloadPath) oldPreloadPath = opts.webPreferences!.preload;
131
119
opts.webPreferences!.preload = require.resolve("./node-preload.js");
120
+
}
132
121
133
122
// Event for modifying window options
134
123
moonlightHost.events.emit("window-options", opts, isMainWindow);
···
138
127
// Event for when a window is created
139
128
moonlightHost.events.emit("window-created", this, isMainWindow);
140
129
130
+
const extensionCspOverrides: Record<string, string[]> = {};
131
+
132
+
{
133
+
const extCsps = moonlightHost.processedExtensions.extensions.map((x) => x.manifest.csp ?? {});
134
+
for (const csp of extCsps) {
135
+
for (const [directive, urls] of Object.entries(csp)) {
136
+
extensionCspOverrides[directive] ??= [];
137
+
extensionCspOverrides[directive].push(...urls);
138
+
}
139
+
}
140
+
}
141
+
141
142
this.webContents.session.webRequest.onHeadersReceived((details, cb) => {
142
143
if (details.responseHeaders != null) {
143
144
// Patch CSP so things can use externally hosted assets
144
145
if (details.resourceType === "mainFrame") {
145
-
patchCsp(details.responseHeaders);
146
+
patchCsp(details.responseHeaders, extensionCspOverrides);
146
147
}
147
148
148
149
// Allow plugins to bypass CORS for specific URLs
149
150
if (corsAllow.some((x) => details.url.startsWith(x))) {
150
-
details.responseHeaders["access-control-allow-origin"] = ["*"];
151
+
if (!details.responseHeaders) details.responseHeaders = {};
152
+
153
+
// Work around HTTP header case sensitivity by reusing the header name if it exists
154
+
// https://github.com/moonlight-mod/moonlight/issues/201
155
+
const fallback = "access-control-allow-origin";
156
+
const key = Object.keys(details.responseHeaders).find((h) => h.toLowerCase() === fallback) ?? fallback;
157
+
details.responseHeaders[key] = ["*"];
151
158
}
159
+
160
+
moonlightHost.events.emit("headers-received", details, isMainWindow);
152
161
153
162
cb({ cancel: false, responseHeaders: details.responseHeaders });
154
163
}
155
164
});
156
165
157
-
// Allow plugins to block some URLs,
158
-
// this is needed because multiple webRequest handlers cannot be registered at once
159
166
this.webContents.session.webRequest.onBeforeRequest((details, cb) => {
160
-
cb({ cancel: blockedUrls.some((u) => u.test(details.url)) });
161
-
});
167
+
/*
168
+
In order to get moonlight loading to be truly async, we prevent Discord
169
+
from loading their scripts immediately. We block the requests, keep note
170
+
of their URLs, and then send them off to node-preload when we get all of
171
+
them. node-preload then loads node side, web side, and then recreates
172
+
the script elements to cause them to re-fetch.
162
173
163
-
if (hasOpenAsar) {
164
-
// Remove DOM injections
165
-
// Settings can still be opened via:
166
-
// `DiscordNative.ipc.send("DISCORD_UPDATED_QUOTES","o")`
167
-
// @ts-expect-error Electron internals
168
-
const events = electron.app._events["browser-window-created"];
169
-
if (Array.isArray(events)) {
170
-
for (const event of events) {
171
-
removeOpenAsarEventIfPresent(event);
174
+
The browser extension also does this, but in a background script (see
175
+
packages/browser/src/background.js - we should probably get this working
176
+
with esbuild someday).
177
+
*/
178
+
if (details.resourceType === "script" && isMainWindow) {
179
+
const url = new URL(details.url);
180
+
const hasUrl = scriptUrls.some((scriptUrl) => {
181
+
return (
182
+
details.url.includes(scriptUrl) &&
183
+
!url.searchParams.has("inj") &&
184
+
(url.host.endsWith("discord.com") || url.host.endsWith("discordapp.com"))
185
+
);
186
+
});
187
+
if (hasUrl) blockedScripts.add(details.url);
188
+
189
+
if (blockedScripts.size === scriptUrls.length) {
190
+
setTimeout(() => {
191
+
logger.debug("Kicking off node-preload");
192
+
this.webContents.send(constants.ipcNodePreloadKickoff, Array.from(blockedScripts));
193
+
blockedScripts.clear();
194
+
}, 0);
172
195
}
173
-
} else if (events != null) {
174
-
removeOpenAsarEventIfPresent(events);
175
-
}
176
196
177
-
// Config screen fails to context bridge properly
178
-
// Less than ideal, but better than disabling it everywhere
179
-
if (opts.webPreferences!.preload === openAsarConfigPreload) {
180
-
opts.webPreferences!.sandbox = false;
197
+
if (hasUrl) return cb({ cancel: true });
181
198
}
182
-
}
199
+
200
+
// Allow plugins to block some URLs,
201
+
// this is needed because multiple webRequest handlers cannot be registered at once
202
+
cb({ cancel: blockedUrls.some((u) => u.test(details.url)) });
203
+
});
183
204
}
184
205
}
185
206
···
200
221
writable: false
201
222
});
202
223
203
-
export async function inject(asarPath: string) {
204
-
isMoonlightDesktop = asarPath === "moonlightDesktop";
205
-
global.moonlightFS = createFS();
224
+
type InjectorConfig = { disablePersist?: boolean; disableLoad?: boolean };
225
+
export async function inject(asarPath: string, _injectorConfig?: InjectorConfig) {
226
+
injectorConfig = _injectorConfig;
227
+
228
+
global.moonlightNodeSandboxed = {
229
+
fs: createFS(),
230
+
// These aren't supposed to be used from host
231
+
addCors() {},
232
+
addBlocked() {}
233
+
};
206
234
207
235
try {
208
-
const config = await readConfig();
236
+
let config = await readConfig();
209
237
initLogger(config);
210
238
const extensions = await getExtensions();
239
+
const processedExtensions = await loadExtensions(extensions);
240
+
const moonlightDir = await getMoonlightDir();
241
+
const extensionsPath = await getExtensionsPath();
211
242
212
243
// Duplicated in node-preload... oops
213
-
// eslint-disable-next-line no-inner-declarations
214
244
function getConfig(ext: string) {
215
245
const val = config.extensions[ext];
216
246
if (val == null || typeof val === "boolean") return undefined;
217
247
return val.config;
218
248
}
219
-
220
249
global.moonlightHost = {
250
+
get config() {
251
+
return config;
252
+
},
253
+
extensions,
254
+
processedExtensions,
221
255
asarPath,
222
-
config,
223
256
events: new EventEmitter(),
224
-
extensions,
225
-
processedExtensions: {
226
-
extensions: [],
227
-
dependencyGraph: new Map()
228
-
},
229
257
230
258
version: MOONLIGHT_VERSION,
231
259
branch: MOONLIGHT_BRANCH as MoonlightBranch,
232
260
233
261
getConfig,
234
-
getConfigOption: <T>(ext: string, name: string) => {
235
-
const config = getConfig(ext);
236
-
if (config == null) return undefined;
237
-
const option = config[name];
238
-
if (option == null) return undefined;
239
-
return option as T;
262
+
getConfigPath,
263
+
getConfigOption(ext, name) {
264
+
const manifest = getManifest(extensions, ext);
265
+
return getConfigOption(ext, name, config, manifest?.settings);
240
266
},
241
-
getLogger: (id: string) => {
267
+
setConfigOption(ext, name, value) {
268
+
setConfigOption(config, ext, name, value);
269
+
this.writeConfig(config);
270
+
},
271
+
async writeConfig(newConfig) {
272
+
await writeConfig(newConfig);
273
+
config = newConfig;
274
+
},
275
+
276
+
getLogger(id) {
242
277
return new Logger(id);
278
+
},
279
+
getMoonlightDir() {
280
+
return moonlightDir;
281
+
},
282
+
getExtensionDir: (ext: string) => {
283
+
return path.join(extensionsPath, ext);
243
284
}
244
285
};
245
286
246
-
// Check if we're running with OpenAsar
247
-
try {
248
-
require.resolve(join(asarPath, "updater", "updater.js"));
249
-
hasOpenAsar = true;
250
-
openAsarConfigPreload = resolve(asarPath, "config", "preload.js");
251
-
// eslint-disable-next-line no-empty
252
-
} catch {}
253
-
254
-
if (hasOpenAsar) {
255
-
// Disable command line switch injection
256
-
// I personally think that the command line switches should be vetted by
257
-
// the user and not just "trust that these are sane defaults that work
258
-
// always". I'm not hating on Ducko or anything, I'm just opinionated.
259
-
// Someone can always make a command line modifier plugin, thats the point
260
-
// of having host modules.
261
-
try {
262
-
const cmdSwitchesPath = require.resolve(
263
-
join(asarPath, "cmdSwitches.js")
264
-
);
265
-
require.cache[cmdSwitchesPath] = new Module(
266
-
cmdSwitchesPath,
267
-
require.cache[require.resolve(asarPath)]
268
-
);
269
-
require.cache[cmdSwitchesPath]!.exports = () => {};
270
-
} catch (error) {
271
-
logger.error("Failed to disable OpenAsar's command line flags:", error);
272
-
}
273
-
}
274
-
275
287
patchElectron();
276
288
277
-
global.moonlightHost.processedExtensions = await loadExtensions(extensions);
278
289
await loadProcessedExtensions(global.moonlightHost.processedExtensions);
279
290
} catch (error) {
280
291
logger.error("Failed to inject:", error);
281
292
}
282
293
283
-
if (isMoonlightDesktop) return;
284
-
285
-
if (!hasOpenAsar && !isMoonlightDesktop) {
294
+
if (injectorConfig?.disablePersist !== true) {
286
295
persist(asarPath);
287
296
}
288
297
289
-
// Need to do this instead of require() or it breaks require.main
290
-
// @ts-expect-error Module internals
291
-
Module._load(asarPath, Module, true);
298
+
if (injectorConfig?.disableLoad !== true) {
299
+
// Need to do this instead of require() or it breaks require.main
300
+
// @ts-expect-error Module internals
301
+
Module._load(asarPath, Module, true);
302
+
}
292
303
}
293
304
294
305
function patchElectron() {
···
302
313
configurable: false
303
314
});
304
315
} else {
305
-
Object.defineProperty(
306
-
electronClone,
307
-
property,
308
-
Object.getOwnPropertyDescriptor(electron, property)!
309
-
);
316
+
Object.defineProperty(electronClone, property, Object.getOwnPropertyDescriptor(electron, property)!);
310
317
}
311
318
}
312
319
+8
-1
packages/node-preload/package.json
+8
-1
packages/node-preload/package.json
···
1
1
{
2
2
"name": "@moonlight-mod/node-preload",
3
3
"private": true,
4
+
"engines": {
5
+
"node": ">=22",
6
+
"pnpm": ">=10",
7
+
"npm": "pnpm",
8
+
"yarn": "pnpm"
9
+
},
4
10
"dependencies": {
5
11
"@moonlight-mod/core": "workspace:*",
6
12
"@moonlight-mod/types": "workspace:*"
7
-
}
13
+
},
14
+
"engineStrict": true
8
15
}
+121
-44
packages/node-preload/src/index.ts
+121
-44
packages/node-preload/src/index.ts
···
5
5
import { readConfig, writeConfig } from "@moonlight-mod/core/config";
6
6
import { constants, MoonlightBranch } from "@moonlight-mod/types";
7
7
import { getExtensions } from "@moonlight-mod/core/extension";
8
-
import {
9
-
getExtensionsPath,
10
-
getMoonlightDir
11
-
} from "@moonlight-mod/core/util/data";
8
+
import { getExtensionsPath, getMoonlightDir } from "@moonlight-mod/core/util/data";
12
9
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
13
-
import {
14
-
loadExtensions,
15
-
loadProcessedExtensions
16
-
} from "@moonlight-mod/core/extension/loader";
10
+
import { loadExtensions, loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
17
11
import createFS from "@moonlight-mod/core/fs";
12
+
import { registerCors, registerBlocked, getDynamicCors } from "@moonlight-mod/core/cors";
13
+
import { getConfig, getConfigOption, getManifest, setConfigOption } from "@moonlight-mod/core/util/config";
14
+
import { NodeEventPayloads, NodeEventType } from "@moonlight-mod/types/core/event";
15
+
import { createEventEmitter } from "@moonlight-mod/core/util/event";
16
+
17
+
let initialized = false;
18
+
let logger: Logger;
19
+
20
+
function setCors() {
21
+
const data = getDynamicCors();
22
+
ipcRenderer.invoke(constants.ipcSetCorsList, data.cors);
23
+
ipcRenderer.invoke(constants.ipcSetBlockedList, data.blocked);
24
+
}
18
25
19
26
async function injectGlobals() {
20
-
global.moonlightFS = createFS();
27
+
global.moonlightNodeSandboxed = {
28
+
fs: createFS(),
29
+
addCors(url) {
30
+
registerCors(url);
31
+
if (initialized) setCors();
32
+
},
33
+
addBlocked(url) {
34
+
registerBlocked(url);
35
+
if (initialized) setCors();
36
+
}
37
+
};
21
38
22
-
const config = await readConfig();
39
+
let config = await readConfig();
23
40
initLogger(config);
41
+
logger = new Logger("node-preload");
42
+
24
43
const extensions = await getExtensions();
25
44
const processedExtensions = await loadExtensions(extensions);
26
45
const moonlightDir = await getMoonlightDir();
27
46
const extensionsPath = await getExtensionsPath();
28
47
29
-
function getConfig(ext: string) {
30
-
const val = config.extensions[ext];
31
-
if (val == null || typeof val === "boolean") return undefined;
32
-
return val.config;
33
-
}
34
-
35
48
global.moonlightNode = {
36
-
config,
49
+
get config() {
50
+
return config;
51
+
},
37
52
extensions,
38
53
processedExtensions,
39
54
nativesCache: {},
40
55
isBrowser: false,
56
+
events: createEventEmitter<NodeEventType, NodeEventPayloads>(),
41
57
42
58
version: MOONLIGHT_VERSION,
43
59
branch: MOONLIGHT_BRANCH as MoonlightBranch,
44
60
45
-
getConfig,
46
-
getConfigOption: <T>(ext: string, name: string) => {
47
-
const config = getConfig(ext);
48
-
if (config == null) return undefined;
49
-
const option = config[name];
50
-
if (option == null) return undefined;
51
-
return option as T;
61
+
getConfig(ext) {
62
+
return getConfig(ext, config);
63
+
},
64
+
getConfigOption(ext, name) {
65
+
const manifest = getManifest(extensions, ext);
66
+
return getConfigOption(ext, name, config, manifest?.settings);
67
+
},
68
+
async setConfigOption(ext, name, value) {
69
+
setConfigOption(config, ext, name, value);
70
+
await this.writeConfig(config);
71
+
},
72
+
async writeConfig(newConfig) {
73
+
await writeConfig(newConfig);
74
+
config = newConfig;
75
+
this.events.dispatchEvent(NodeEventType.ConfigSaved, newConfig);
52
76
},
77
+
53
78
getNatives: (ext: string) => global.moonlightNode.nativesCache[ext],
54
79
getLogger: (id: string) => {
55
80
return new Logger(id);
56
81
},
57
-
58
82
getMoonlightDir() {
59
83
return moonlightDir;
60
84
},
61
85
getExtensionDir: (ext: string) => {
62
86
return path.join(extensionsPath, ext);
63
-
},
64
-
writeConfig
87
+
}
65
88
};
66
89
67
90
await loadProcessedExtensions(processedExtensions);
68
91
contextBridge.exposeInMainWorld("moonlightNode", moonlightNode);
69
92
70
-
const extCors = moonlightNode.processedExtensions.extensions.flatMap(
71
-
(x) => x.manifest.cors ?? []
72
-
);
93
+
const extCors = moonlightNode.processedExtensions.extensions.flatMap((x) => x.manifest.cors ?? []);
94
+
for (const cors of extCors) {
95
+
registerCors(cors);
96
+
}
73
97
74
98
for (const repo of moonlightNode.config.repositories) {
75
99
const url = new URL(repo);
76
100
url.pathname = "/";
77
-
extCors.push(url.toString());
101
+
registerCors(url.toString());
102
+
}
103
+
104
+
const extBlocked = moonlightNode.processedExtensions.extensions.flatMap((e) => e.manifest.blocked ?? []);
105
+
for (const blocked of extBlocked) {
106
+
registerBlocked(blocked);
78
107
}
79
108
80
-
ipcRenderer.invoke(constants.ipcSetCorsList, extCors);
109
+
setCors();
81
110
82
-
const extBlocked = moonlightNode.processedExtensions.extensions.flatMap(
83
-
(e) => e.manifest.blocked ?? []
84
-
);
85
-
ipcRenderer.invoke(constants.ipcSetBlockedList, extBlocked);
111
+
initialized = true;
86
112
}
87
113
88
114
async function loadPreload() {
89
115
const webPreloadPath = path.join(__dirname, "web-preload.js");
90
116
const webPreload = fs.readFileSync(webPreloadPath, "utf8");
91
117
await webFrame.executeJavaScript(webPreload);
118
+
119
+
const func = await webFrame.executeJavaScript("async () => { await window._moonlightWebLoad(); }");
120
+
await func();
92
121
}
93
122
94
-
async function init(oldPreloadPath: string) {
123
+
async function init() {
95
124
try {
96
125
await injectGlobals();
97
126
await loadPreload();
···
102
131
message: message
103
132
});
104
133
}
134
+
}
105
135
106
-
// Let Discord start even if we fail
107
-
if (oldPreloadPath) require(oldPreloadPath);
108
-
}
136
+
const oldPreloadPath: string = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
137
+
const isOverlay = window.location.href.indexOf("discord_overlay") > -1;
109
138
110
-
const oldPreloadPath: string = ipcRenderer.sendSync(
111
-
constants.ipcGetOldPreloadPath
112
-
);
113
-
init(oldPreloadPath);
139
+
if (isOverlay) {
140
+
// The overlay has an inline script tag to call to DiscordNative, so we'll
141
+
// just load it immediately. Somehow moonlight still loads in this env, I
142
+
// have no idea why - so I suspect it's just forwarding render calls or
143
+
// something from the original process
144
+
require(oldPreloadPath);
145
+
} else {
146
+
ipcRenderer.on(constants.ipcNodePreloadKickoff, (_, blockedScripts: string[]) => {
147
+
(async () => {
148
+
try {
149
+
await init();
150
+
logger.debug("Blocked scripts:", blockedScripts);
151
+
152
+
const oldPreloadPath: string = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
153
+
logger.debug("Old preload path:", oldPreloadPath);
154
+
if (oldPreloadPath) require(oldPreloadPath);
155
+
156
+
// Do this to get global.DiscordNative assigned
157
+
// @ts-expect-error Lying to discord_desktop_core
158
+
process.emit("loaded");
159
+
160
+
function replayScripts() {
161
+
const scripts = [...document.querySelectorAll("script")].filter(
162
+
(script) => script.src && blockedScripts.some((url) => url.includes(script.src))
163
+
);
164
+
165
+
blockedScripts.reverse();
166
+
for (const url of blockedScripts) {
167
+
if (url.includes("/sentry.")) continue;
168
+
169
+
const script = scripts.find((script) => url.includes(script.src))!;
170
+
const newScript = document.createElement("script");
171
+
for (const attr of script.attributes) {
172
+
if (attr.name === "src") attr.value += "?inj";
173
+
newScript.setAttribute(attr.name, attr.value);
174
+
}
175
+
script.remove();
176
+
document.documentElement.appendChild(newScript);
177
+
}
178
+
}
179
+
180
+
if (document.readyState === "complete") {
181
+
replayScripts();
182
+
} else {
183
+
window.addEventListener("load", replayScripts);
184
+
}
185
+
} catch (e) {
186
+
logger.error("Error restoring original scripts:", e);
187
+
}
188
+
})();
189
+
});
190
+
}
+4
-1
packages/node-preload/tsconfig.json
+4
-1
packages/node-preload/tsconfig.json
+14
-7
packages/types/package.json
+14
-7
packages/types/package.json
···
1
1
{
2
2
"name": "@moonlight-mod/types",
3
-
"version": "1.3.0",
4
-
"main": "./src/index.ts",
5
-
"types": "./src/index.ts",
3
+
"version": "1.3.17",
6
4
"exports": {
7
5
".": "./src/index.ts",
8
6
"./import": "./src/import.d.ts",
9
7
"./*": "./src/*.ts"
10
8
},
9
+
"main": "./src/index.ts",
10
+
"types": "./src/index.ts",
11
+
"engineStrict": false,
12
+
"engines": {
13
+
"node": ">=22",
14
+
"pnpm": ">=10",
15
+
"npm": "pnpm",
16
+
"yarn": "pnpm"
17
+
},
11
18
"dependencies": {
12
-
"@moonlight-mod/lunast": "^1.0.0",
13
-
"@moonlight-mod/mappings": "^1.0.2",
14
-
"@moonlight-mod/moonmap": "^1.0.2",
19
+
"@moonlight-mod/lunast": "^1.0.1",
20
+
"@moonlight-mod/mappings": "^1.1.25",
21
+
"@moonlight-mod/moonmap": "^1.0.5",
15
22
"@types/react": "^18.3.10",
16
-
"csstype": "^3.1.2",
23
+
"csstype": "^3.1.3",
17
24
"standalone-electron-types": "^1.0.0"
18
25
}
19
26
}
+49
-3
packages/types/src/config.ts
+49
-3
packages/types/src/config.ts
···
6
6
patchAll?: boolean;
7
7
};
8
8
9
-
export type ConfigExtensions =
10
-
| { [key: string]: boolean }
11
-
| { [key: string]: ConfigExtension };
9
+
export type ConfigExtensions = { [key: string]: boolean } | { [key: string]: ConfigExtension };
12
10
13
11
export type ConfigExtension = {
14
12
enabled: boolean;
···
35
33
};
36
34
37
35
export type BooleanSettingType = {
36
+
/**
37
+
* Displays as a simple switch.
38
+
*/
38
39
type: ExtensionSettingType.Boolean;
39
40
default?: boolean;
40
41
};
41
42
42
43
export type NumberSettingType = {
44
+
/**
45
+
* Displays as a simple slider.
46
+
*/
43
47
type: ExtensionSettingType.Number;
44
48
default?: number;
45
49
min?: number;
···
47
51
};
48
52
49
53
export type StringSettingType = {
54
+
/**
55
+
* Displays as a single line string input.
56
+
*/
50
57
type: ExtensionSettingType.String;
51
58
default?: string;
52
59
};
53
60
54
61
export type MultilineTextInputSettingType = {
62
+
/**
63
+
* Displays as a multiple line string input.
64
+
*/
55
65
type: ExtensionSettingType.MultilineString;
56
66
default?: string;
57
67
};
58
68
59
69
export type SelectSettingType = {
70
+
/**
71
+
* A dropdown to pick between one of many values.
72
+
*/
60
73
type: ExtensionSettingType.Select;
61
74
options: SelectOption[];
62
75
default?: string;
63
76
};
64
77
65
78
export type MultiSelectSettingType = {
79
+
/**
80
+
* A dropdown to pick multiple values.
81
+
*/
66
82
type: ExtensionSettingType.MultiSelect;
67
83
options: string[];
68
84
default?: string[];
69
85
};
70
86
71
87
export type ListSettingType = {
88
+
/**
89
+
* A list of strings that the user can add or remove from.
90
+
*/
72
91
type: ExtensionSettingType.List;
73
92
default?: string[];
74
93
};
75
94
76
95
export type DictionarySettingType = {
96
+
/**
97
+
* A dictionary (key-value pair) that the user can add or remove from.
98
+
*/
77
99
type: ExtensionSettingType.Dictionary;
78
100
default?: Record<string, string>;
79
101
};
80
102
81
103
export type CustomSettingType = {
104
+
/**
105
+
* A custom component.
106
+
* You can use the registerConfigComponent function in the Moonbase API to register a React component to render here.
107
+
*/
82
108
type: ExtensionSettingType.Custom;
83
109
default?: any;
84
110
};
85
111
112
+
export enum ExtensionSettingsAdvice {
113
+
None = "none",
114
+
Reload = "reload",
115
+
Restart = "restart"
116
+
}
117
+
86
118
export type ExtensionSettingsManifest = {
119
+
/**
120
+
* A human friendly name for the setting.
121
+
*/
87
122
displayName?: string;
123
+
124
+
/**
125
+
* A longer description for the setting.
126
+
* Markdown is not supported.
127
+
*/
88
128
description?: string;
129
+
130
+
/**
131
+
* The "advice" to give upon changing this setting.
132
+
* Can be configured to reload the client, restart the client, or do nothing.
133
+
*/
134
+
advice?: ExtensionSettingsAdvice;
89
135
} & (
90
136
| BooleanSettingType
91
137
| NumberSettingType
+6
-3
packages/types/src/constants.ts
+6
-3
packages/types/src/constants.ts
···
4
4
export const repoUrlFile = ".moonlight-repo-url";
5
5
export const installedVersionFile = ".moonlight-installed-version";
6
6
7
+
export const ipcNodePreloadKickoff = "_moonlight_nodePreloadKickoff";
7
8
export const ipcGetOldPreloadPath = "_moonlight_getOldPreloadPath";
9
+
8
10
export const ipcGetAppData = "_moonlight_getAppData";
9
-
export const ipcGetIsMoonlightDesktop = "_moonlight_getIsMoonlightDesktop";
11
+
export const ipcGetInjectorConfig = "_moonlight_getInjectorConfig";
10
12
export const ipcMessageBox = "_moonlight_messageBox";
11
13
export const ipcSetCorsList = "_moonlight_setCorsList";
12
14
export const ipcSetBlockedList = "_moonlight_setBlockedList";
13
15
14
16
export const apiLevel = 2;
15
17
16
-
export const mainRepo =
17
-
"https://moonlight-mod.github.io/extensions-dist/repo.json";
18
+
export const mainRepo = "https://moonlight-mod.github.io/extensions-dist/repo.json";
19
+
// If you're updating this, update `defaultConfig` in core as well
20
+
export const builtinExtensions = ["moonbase", "disableSentry", "noTrack", "noHideToken"];
+17
-20
packages/types/src/core/event.ts
+17
-20
packages/types/src/core/event.ts
···
1
+
import { Config } from "../config";
1
2
import { WebpackModuleFunc, WebpackRequireType } from "../discord";
2
3
3
-
export interface MoonlightEventEmitter<
4
-
EventId extends string = string,
5
-
EventData = Record<EventId, any>
6
-
> {
7
-
dispatchEvent: <Id extends keyof EventData>(
8
-
id: Id,
9
-
data: EventData[Id]
10
-
) => void;
11
-
addEventListener: <Id extends keyof EventData>(
12
-
id: Id,
13
-
cb: (data: EventData[Id]) => void
14
-
) => void;
15
-
removeEventListener: <Id extends keyof EventData>(
16
-
id: Id,
17
-
cb: (data: EventData[Id]) => void
18
-
) => void;
4
+
export interface MoonlightEventEmitter<EventId extends string = string, EventData = Record<EventId, any>> {
5
+
dispatchEvent: <Id extends keyof EventData>(id: Id, data: EventData[Id]) => void;
6
+
addEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => void;
7
+
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => void;
19
8
}
20
9
21
-
export enum EventType {
10
+
export enum WebEventType {
22
11
ChunkLoad = "chunkLoad",
23
12
ExtensionLoad = "extensionLoad"
24
13
}
25
14
26
-
export type EventPayloads = {
27
-
[EventType.ChunkLoad]: {
15
+
export type WebEventPayloads = {
16
+
[WebEventType.ChunkLoad]: {
28
17
chunkId?: number[];
29
18
modules: { [id: string]: WebpackModuleFunc };
30
19
require?: (require: WebpackRequireType) => any;
31
20
};
32
-
[EventType.ExtensionLoad]: string;
21
+
[WebEventType.ExtensionLoad]: string;
22
+
};
23
+
24
+
export enum NodeEventType {
25
+
ConfigSaved = "configSaved"
26
+
}
27
+
28
+
export type NodeEventPayloads = {
29
+
[NodeEventType.ConfigSaved]: Config;
33
30
};
+13
packages/types/src/coreExtensions/appPanels.ts
+13
packages/types/src/coreExtensions/appPanels.ts
···
1
+
export type AppPanels = {
2
+
/**
3
+
* Registers a new panel to be displayed around the user/voice controls.
4
+
* @param section A unique name for your section
5
+
* @param element A React component
6
+
*/
7
+
addPanel: (section: string, element: React.FC<any>) => void;
8
+
9
+
/**
10
+
* @private
11
+
*/
12
+
getPanels: (el: React.FC<any>) => React.ReactNode;
13
+
};
+204
packages/types/src/coreExtensions/commands.ts
+204
packages/types/src/coreExtensions/commands.ts
···
1
+
export const APPLICATION_ID = "-3";
2
+
3
+
export enum CommandType {
4
+
CHAT = 1,
5
+
MESSAGE = 3,
6
+
PRIMARY_ENTRY_POINT = 4,
7
+
USER = 2
8
+
}
9
+
10
+
export enum InputType {
11
+
BOT = 3,
12
+
BUILT_IN = 0,
13
+
BUILT_IN_INTEGRATION = 2,
14
+
BUILT_IN_TEXT = 1,
15
+
PLACEHOLDER = 4
16
+
}
17
+
18
+
export enum OptionType {
19
+
SUB_COMMAND = 1,
20
+
SUB_COMMAND_GROUP = 2,
21
+
STRING = 3,
22
+
INTEGER = 4,
23
+
BOOLEAN = 5,
24
+
USER = 6,
25
+
CHANNEL = 7,
26
+
ROLE = 8,
27
+
MENTIONABLE = 9,
28
+
NUMBER = 10,
29
+
ATTACHMENT = 11
30
+
}
31
+
32
+
export enum ChannelType {
33
+
GUILD_TEXT = 0,
34
+
DM = 1,
35
+
GUILD_VOICE = 2,
36
+
GROUP_DM = 3,
37
+
GUILD_CATEGORY = 4,
38
+
GUILD_ANNOUNCEMENT = 5,
39
+
GUILD_STORE = 6,
40
+
ANNOUNCEMENT_THREAD = 10,
41
+
PUBLIC_THREAD = 11,
42
+
PRIVATE_THREAD = 12,
43
+
GUILD_STAGE_VOICE = 13,
44
+
GUILD_DIRECTORY = 14,
45
+
GUILD_FORUM = 15,
46
+
GUILD_MEDIA = 16,
47
+
LOBBY = 17,
48
+
DM_SDK = 18
49
+
}
50
+
51
+
export type RegisteredCommandOption = MoonlightCommandOption & {
52
+
displayName: string;
53
+
displayDescription: string;
54
+
};
55
+
56
+
export type CommandOptionChoice<T> = {
57
+
name: string;
58
+
value: T;
59
+
};
60
+
61
+
type CommandOptionBase<T> = {
62
+
type: T;
63
+
name: string;
64
+
description: string;
65
+
required?: T extends OptionType.SUB_COMMAND
66
+
? never
67
+
: T extends OptionType.SUB_COMMAND_GROUP
68
+
? never
69
+
: boolean | undefined;
70
+
choices?: T extends OptionType.STRING
71
+
? CommandOptionChoice<string>[]
72
+
: T extends OptionType.INTEGER
73
+
? CommandOptionChoice<number>[]
74
+
: T extends OptionType.NUMBER
75
+
? CommandOptionChoice<number>[]
76
+
: never;
77
+
options?: T extends OptionType.SUB_COMMAND
78
+
? MoonlightCommandOption[]
79
+
: T extends OptionType.SUB_COMMAND_GROUP
80
+
? MoonlightCommandOption[]
81
+
: never;
82
+
channelTypes?: T extends OptionType.CHANNEL ? ChannelType[] : never;
83
+
minValue?: T extends OptionType.INTEGER ? number : T extends OptionType.NUMBER ? number : never;
84
+
maxValue?: T extends OptionType.INTEGER ? number : T extends OptionType.NUMBER ? number : never;
85
+
minLength?: T extends OptionType.STRING ? number : never;
86
+
maxLength?: T extends OptionType.STRING ? number : never;
87
+
};
88
+
89
+
// This is bad lol
90
+
export type MoonlightCommandOption =
91
+
| CommandOptionBase<OptionType.SUB_COMMAND>
92
+
| CommandOptionBase<OptionType.SUB_COMMAND_GROUP>
93
+
| CommandOptionBase<OptionType.STRING>
94
+
| CommandOptionBase<OptionType.INTEGER>
95
+
| CommandOptionBase<OptionType.BOOLEAN>
96
+
| CommandOptionBase<OptionType.USER>
97
+
| CommandOptionBase<OptionType.CHANNEL>
98
+
| CommandOptionBase<OptionType.ROLE>
99
+
| CommandOptionBase<OptionType.MENTIONABLE>
100
+
| CommandOptionBase<OptionType.NUMBER>
101
+
| CommandOptionBase<OptionType.ATTACHMENT>;
102
+
103
+
// TODO: types
104
+
export type CommandPredicateState = {
105
+
channel: any;
106
+
guild: any;
107
+
};
108
+
109
+
export type RegisteredCommand = {
110
+
id: string;
111
+
untranslatedName: string;
112
+
displayName: string;
113
+
type: CommandType;
114
+
inputType: InputType;
115
+
applicationId: string; // set to -3!
116
+
untranslatedDescription: string;
117
+
displayDescription: string;
118
+
options?: RegisteredCommandOption[];
119
+
predicate?: (state: CommandPredicateState) => boolean;
120
+
execute: (options: CommandOption[]) => void;
121
+
};
122
+
123
+
export type MoonlightCommand = {
124
+
id: string;
125
+
description: string;
126
+
127
+
/**
128
+
* You likely want CHAT
129
+
*/
130
+
type: CommandType;
131
+
132
+
/**
133
+
* You likely want BUILT_IN (or BUILT_IN_TEXT if usable with replies)
134
+
*/
135
+
inputType: InputType;
136
+
options?: MoonlightCommandOption[];
137
+
predicate?: (state: CommandPredicateState) => boolean;
138
+
execute: (options: CommandOption[]) => void;
139
+
};
140
+
141
+
export type CommandOption = {
142
+
name: string;
143
+
} & ( // TODO: more of these
144
+
| {
145
+
type: Exclude<OptionType, OptionType.STRING>;
146
+
value: any;
147
+
}
148
+
| {
149
+
type: OptionType.STRING;
150
+
value: string;
151
+
}
152
+
| {
153
+
type: OptionType.NUMBER | OptionType.INTEGER;
154
+
value: number;
155
+
}
156
+
| {
157
+
type: OptionType.BOOLEAN;
158
+
value: boolean;
159
+
}
160
+
| {
161
+
type: OptionType.SUB_COMMAND | OptionType.SUB_COMMAND_GROUP;
162
+
options: CommandOption[];
163
+
}
164
+
);
165
+
166
+
export type AnyScopeRegex = RegExp["exec"] & {
167
+
regex: RegExp;
168
+
};
169
+
170
+
export type Commands = {
171
+
/**
172
+
* Register a command in the internal slash command system
173
+
*/
174
+
registerCommand: (command: MoonlightCommand) => void;
175
+
176
+
/**
177
+
* Register a legacy command that works via regex
178
+
*/
179
+
registerLegacyCommand: (id: string, command: LegacyCommand) => void;
180
+
181
+
/**
182
+
* Creates a regular expression that legacy commands can understand
183
+
*/
184
+
anyScopeRegex: (regex: RegExp) => AnyScopeRegex;
185
+
186
+
/**
187
+
* @private
188
+
*/
189
+
_getCommands: () => RegisteredCommand[];
190
+
};
191
+
192
+
export type LegacyContext = {
193
+
channel: any;
194
+
isEdit: boolean;
195
+
};
196
+
197
+
export type LegacyReturn = {
198
+
content: string;
199
+
};
200
+
201
+
export type LegacyCommand = {
202
+
match?: RegExp | { regex: RegExp } | AnyScopeRegex;
203
+
action: (content: string, context: LegacyContext) => LegacyReturn;
204
+
};
+33
packages/types/src/coreExtensions/common.ts
+33
packages/types/src/coreExtensions/common.ts
···
1
+
import type { IconProps, IconSize } from "@moonlight-mod/mappings/discord/components/common/index";
2
+
3
+
export type ErrorBoundaryProps = React.PropsWithChildren<{
4
+
noop?: boolean;
5
+
fallback?: React.FC<any>;
6
+
message?: string;
7
+
}>;
8
+
9
+
export type ErrorBoundaryState = {
10
+
errored: boolean;
11
+
error?: Error;
12
+
componentStack?: string;
13
+
};
14
+
15
+
export type ErrorBoundary = React.ComponentClass<ErrorBoundaryProps, ErrorBoundaryState>;
16
+
17
+
export type ParsedIconProps = {
18
+
width: number;
19
+
height: number;
20
+
fill: string;
21
+
className: string;
22
+
};
23
+
24
+
export interface Icons {
25
+
/**
26
+
* Parse icon props into their actual width/height.
27
+
* @param props The icon props
28
+
*/
29
+
parseProps(props?: IconProps): ParsedIconProps;
30
+
}
31
+
32
+
// Re-export so extension developers don't need to depend on mappings
33
+
export type { IconProps, IconSize };
+162
packages/types/src/coreExtensions/componentEditor.ts
+162
packages/types/src/coreExtensions/componentEditor.ts
···
1
+
type Patcher<T> = (elements: React.ReactNode[], props: T) => React.ReactNode[];
2
+
3
+
//#region DM List
4
+
export type DMListAnchors =
5
+
| "content"
6
+
| "favorite-server-indicator"
7
+
| "ignored-indicator"
8
+
| "blocked-indicator"
9
+
| "close-button"
10
+
| undefined;
11
+
export type DMListDecoratorAnchors = "system-tag" | undefined;
12
+
13
+
export enum DMListAnchorIndicies {
14
+
content = 0,
15
+
"favorite-server-indicator",
16
+
"ignored-indicator",
17
+
"blocked-indicator",
18
+
"close-button"
19
+
}
20
+
export enum DMListDecoratorAnchorIndicies {
21
+
"system-tag" = 0
22
+
}
23
+
24
+
export type DMListItem = {
25
+
component: React.FC<any>;
26
+
anchor: DMListAnchors;
27
+
before: boolean;
28
+
};
29
+
export type DMListDecorator = {
30
+
component: React.FC<any>;
31
+
anchor: DMListDecoratorAnchors;
32
+
before: boolean;
33
+
};
34
+
35
+
export type DMList = {
36
+
addItem: (id: string, component: React.FC<any>, anchor?: DMListAnchors, before?: boolean) => void;
37
+
addDecorator: (id: string, component: React.FC<any>, anchor?: DMListDecoratorAnchors, before?: boolean) => void;
38
+
//TODO: fix props type
39
+
/**
40
+
* @private
41
+
*/
42
+
_patchItems: Patcher<any>;
43
+
/**
44
+
* @private
45
+
*/
46
+
_patchDecorators: Patcher<any>;
47
+
};
48
+
//#endregion
49
+
50
+
//#region Member List
51
+
export type MemberListDecoratorAnchors = "bot-tag" | "owner-crown" | "boost-icon" | undefined;
52
+
53
+
export enum MemberListDecoratorAnchorIndicies {
54
+
"bot-tag" = 0,
55
+
"owner-crown",
56
+
"boost-icon"
57
+
}
58
+
59
+
export type MemberListDecorator = {
60
+
component: React.FC<any>;
61
+
anchor: MemberListDecoratorAnchors;
62
+
before: boolean;
63
+
};
64
+
65
+
export type MemberList = {
66
+
addItem: (id: string, component: React.FC<any>) => void;
67
+
addDecorator: (id: string, component: React.FC<any>, anchor?: MemberListDecoratorAnchors, before?: boolean) => void;
68
+
//TODO: fix props type
69
+
/**
70
+
* @private
71
+
*/
72
+
_patchItems: Patcher<any>;
73
+
/**
74
+
* @private
75
+
*/
76
+
_patchDecorators: Patcher<any>;
77
+
};
78
+
//#endregion
79
+
80
+
//#region Messages
81
+
export type MessageUsernameAnchors = "communication-disabled" | "username" | undefined;
82
+
export type MessageUsernameBadgeAnchors =
83
+
| "nitro-author"
84
+
| "role-icon"
85
+
| "new-member"
86
+
| "leaderboard-champion"
87
+
| "connections"
88
+
| undefined;
89
+
export type MessageBadgeAnchors = "silent" | "potion" | undefined;
90
+
91
+
export type MessageUsername = {
92
+
component: React.FC<any>;
93
+
anchor: MessageUsernameAnchors;
94
+
before: boolean;
95
+
};
96
+
export type MessageUsernameBadge = {
97
+
component: React.FC<any>;
98
+
anchor: MessageUsernameBadgeAnchors;
99
+
before: boolean;
100
+
};
101
+
export type MessageBadge = {
102
+
component: React.FC<any>;
103
+
anchor: MessageBadgeAnchors;
104
+
before: boolean;
105
+
};
106
+
107
+
export enum MessageUsernameIndicies {
108
+
"communication-disabled" = 0,
109
+
username
110
+
}
111
+
export enum MessageUsernameBadgeIndicies {
112
+
"nitro-author" = 0,
113
+
"role-icon",
114
+
"new-member",
115
+
"leaderboard-champion",
116
+
connections
117
+
}
118
+
export enum MessageBadgeIndicies {
119
+
silent = 0,
120
+
potion
121
+
}
122
+
123
+
export type Messages = {
124
+
/**
125
+
* Adds a component to the username of a message
126
+
*/
127
+
addToUsername: (id: string, component: React.FC<any>, anchor?: MessageUsernameAnchors, before?: boolean) => void;
128
+
/**
129
+
* Adds a component to the username badge area of a message (e.g. where role icons/new member badge is)
130
+
*/
131
+
addUsernameBadge: (
132
+
id: string,
133
+
component: React.FC<any>,
134
+
anchor?: MessageUsernameBadgeAnchors,
135
+
before?: boolean
136
+
) => void;
137
+
/**
138
+
* Adds a component to the end of a message header (e.g. silent indicator)
139
+
*/
140
+
addBadge: (id: string, component: React.FC<any>, anchor?: MessageBadgeAnchors, before?: boolean) => void;
141
+
/**
142
+
* Adds a component to message accessories (e.g. embeds)
143
+
*/
144
+
addAccessory: (id: string, component: React.FC<any>) => void;
145
+
/**
146
+
* @private
147
+
*/
148
+
_patchUsername: Patcher<any>;
149
+
/**
150
+
* @private
151
+
*/
152
+
_patchUsernameBadges: Patcher<any>;
153
+
/**
154
+
* @private
155
+
*/
156
+
_patchBadges: Patcher<any>;
157
+
/**
158
+
* @private
159
+
*/
160
+
_patchAccessories: Patcher<any>;
161
+
};
162
+
//#endregion
+21
-121
packages/types/src/coreExtensions/contextMenu.ts
+21
-121
packages/types/src/coreExtensions/contextMenu.ts
···
1
-
// TODO: Deduplicate common props
2
-
3
-
export type Menu = React.FunctionComponent<{
4
-
navId: string;
5
-
variant?: string;
6
-
hideScrollbar?: boolean;
7
-
className?: string;
8
-
children: React.ReactComponentElement<MenuElement>[];
9
-
onClose?: () => void;
10
-
onSelect?: () => void;
11
-
}>;
12
-
export type MenuProps = React.ComponentProps<Menu>;
13
-
14
-
export type MenuElement =
15
-
| MenuSeparator
16
-
| MenuGroup
17
-
| MenuItem
18
-
| MenuCheckboxItem
19
-
| MenuRadioItem
20
-
| MenuControlItem;
21
-
22
-
/* eslint-disable prettier/prettier */
23
-
export type MenuSeparator = React.FunctionComponent;
24
-
export type MenuGroup = React.FunctionComponent<{
25
-
label?: string;
26
-
className?: string;
27
-
color?: string;
28
-
children: React.ReactComponentElement<MenuElement>[];
29
-
}>;
30
-
export type MenuItem = React.FunctionComponent<
31
-
{
32
-
id: any;
33
-
dontCloseOnActionIfHoldingShiftKey?: boolean;
34
-
} & (
35
-
| {
36
-
label: string;
37
-
subtext?: string;
38
-
color?: string;
39
-
hint?: string;
40
-
disabled?: boolean;
41
-
icon?: any;
42
-
showIconFirst?: boolean;
43
-
imageUrl?: string;
44
-
45
-
className?: string;
46
-
focusedClassName?: string;
47
-
subMenuIconClassName?: string;
48
-
49
-
action?: () => void;
50
-
onFocus?: () => void;
51
-
52
-
iconProps?: any;
53
-
sparkle?: any;
54
-
55
-
children?: React.ReactComponentElement<MenuElement>[];
56
-
onChildrenScroll?: any;
57
-
childRowHeight?: any;
58
-
listClassName?: string;
59
-
subMenuClassName?: string;
60
-
}
61
-
| {
62
-
color?: string;
63
-
disabled?: boolean;
64
-
keepItemStyles?: boolean;
65
-
66
-
action?: () => void;
67
-
68
-
render: any;
69
-
navigable?: boolean;
70
-
}
71
-
)
72
-
>;
73
-
export type MenuCheckboxItem = React.FunctionComponent<{
74
-
id: any;
75
-
label: string;
76
-
subtext?: string;
77
-
color?: string;
78
-
className?: string;
79
-
focusedClassName?: string;
80
-
disabled?: boolean;
81
-
checked: boolean;
82
-
action?: () => void;
83
-
}>;
84
-
export type MenuRadioItem = React.FunctionComponent<{
85
-
id: any;
86
-
label: string;
87
-
subtext?: string;
88
-
color?: string;
89
-
disabled?: boolean;
90
-
action?: () => void;
91
-
}>;
92
-
export type MenuControlItem = React.FunctionComponent<
93
-
{
94
-
id: any;
95
-
label: string;
96
-
color?: string;
97
-
disabled?: boolean;
98
-
showDefaultFocus?: boolean;
99
-
} & (
100
-
| {
101
-
control: any;
102
-
}
103
-
| {
104
-
control?: undefined;
105
-
interactive?: boolean;
106
-
children?: React.ReactComponentElement<MenuElement>[];
107
-
}
108
-
)
109
-
>;
110
-
/* eslint-disable prettier/prettier */
1
+
import {
2
+
Menu,
3
+
MenuCheckboxItem,
4
+
MenuControlItem,
5
+
MenuGroup,
6
+
MenuRadioItem,
7
+
MenuSeparator,
8
+
MenuItem,
9
+
MenuElement
10
+
} from "@moonlight-mod/mappings/discord/components/common/index";
111
11
112
12
export type ContextMenu = {
113
-
addItem: (
114
-
navId: string,
115
-
item: (props: any) => React.ReactComponentElement<MenuElement>,
116
-
anchorId: string,
117
-
before?: boolean
118
-
) => void;
13
+
/**
14
+
* Registers a new context menu item for a given context menu type.
15
+
* @param navId The navigation ID for the target context menu (e.g. "user-context", "message")
16
+
* @param item A React component
17
+
* @param anchor An existing item's ID to anchor the new item to
18
+
* @param before Whether to insert the new item before the anchor item
19
+
*/
20
+
addItem: (navId: string, item: React.FC<any>, anchor: string | RegExp, before?: boolean) => void;
119
21
120
22
MenuCheckboxItem: MenuCheckboxItem;
121
23
MenuControlItem: MenuControlItem;
···
157
59
label: string;
158
60
};
159
61
160
-
export type EvilItemParser = (
161
-
el:
162
-
| React.ReactComponentElement<MenuElement>
163
-
| React.ReactComponentElement<MenuElement>[]
164
-
) => InternalItem[];
62
+
export type EvilItemParser = (el: MenuElement | MenuElement[]) => InternalItem[];
63
+
64
+
export type { Menu, MenuElement };
+20
-23
packages/types/src/coreExtensions/markdown.ts
+20
-23
packages/types/src/coreExtensions/markdown.ts
···
11
11
12
12
export type ASTNode = SingleASTNode | Array<SingleASTNode>;
13
13
14
-
export type Parser = (
15
-
source: string,
16
-
state?: State | null | undefined
17
-
) => Array<SingleASTNode>;
14
+
export type Parser = (source: string, state?: State | null | undefined) => Array<SingleASTNode>;
18
15
19
-
export type ParseFunction = (
20
-
capture: Capture,
21
-
nestedParse: Parser,
22
-
state: State
23
-
) => UntypedASTNode | ASTNode;
16
+
export type ParseFunction = (capture: Capture, nestedParse: Parser, state: State) => UntypedASTNode | ASTNode;
24
17
25
18
export type Capture =
26
19
| (Array<string> & {
···
38
31
39
32
export type MatchFunction = {
40
33
regex?: RegExp;
41
-
} & ((
42
-
source: string,
43
-
state: State,
44
-
prevCapture: string
45
-
) => Capture | null | undefined);
34
+
} & ((source: string, state: State, prevCapture: string) => Capture | null | undefined);
46
35
47
-
export type Output<Result> = (
48
-
node: ASTNode,
49
-
state?: State | null | undefined
50
-
) => Result;
36
+
export type Output<Result> = (node: ASTNode, state?: State | null | undefined) => Result;
51
37
52
-
export type SingleNodeOutput<Result> = (
53
-
node: SingleASTNode,
54
-
nestedOutput: Output<Result>,
55
-
state: State
56
-
) => Result;
38
+
export type SingleNodeOutput<Result> = (node: SingleASTNode, nestedOutput: Output<Result>, state: State) => Result;
57
39
58
40
// }}}
59
41
···
100
82
slateDecorators: Record<string, string>;
101
83
ruleBlacklists: Record<Ruleset, Record<string, boolean>>;
102
84
85
+
/**
86
+
* Registers a new Markdown rule with simple-markdown.
87
+
* @param name The name of the rule
88
+
* @param markdown A function that returns simple-markdown rules
89
+
* @param slate A function that returns Slate rules
90
+
* @param decorator A decorator name for Slate
91
+
* @see https://www.npmjs.com/package/simple-markdown#adding-a-simple-extension
92
+
* @see https://docs.slatejs.org/
93
+
*/
103
94
addRule: (
104
95
name: string,
105
96
markdown: (rules: Record<string, MarkdownRule>) => MarkdownRule,
106
97
slate: (rules: Record<string, SlateRule>) => SlateRule,
107
98
decorator?: string | undefined
108
99
) => void;
100
+
101
+
/**
102
+
* Blacklist a rule from a ruleset.
103
+
* @param ruleset The ruleset name
104
+
* @param name The rule name
105
+
*/
109
106
blacklistFromRuleset: (ruleset: Ruleset, name: string) => void;
110
107
};
+12
-7
packages/types/src/coreExtensions/moonbase.ts
+12
-7
packages/types/src/coreExtensions/moonbase.ts
···
1
-
export type CustomComponent = React.FC<{
1
+
export type CustomComponentProps = {
2
2
value: any;
3
3
setValue: (value: any) => void;
4
-
}>;
4
+
};
5
+
6
+
export type CustomComponent = React.FC<CustomComponentProps>;
5
7
6
8
export type Moonbase = {
7
-
registerConfigComponent: (
8
-
ext: string,
9
-
option: string,
10
-
component: CustomComponent
11
-
) => void;
9
+
/**
10
+
* Registers a custom component for an extension setting.
11
+
* The extension setting must be of type "custom".
12
+
* @param ext The extension ID
13
+
* @param option The setting ID
14
+
* @param component A React component
15
+
*/
16
+
registerConfigComponent: (ext: string, option: string, component: CustomComponent) => void;
12
17
};
+16
-1
packages/types/src/coreExtensions/notices.ts
+16
-1
packages/types/src/coreExtensions/notices.ts
···
1
-
import type { Store } from "@moonlight-mod/mappings/discord/packages/flux";
1
+
import type { Store } from "@moonlight-mod/mappings/discord/packages/flux/Store";
2
2
3
3
export type NoticeButton = {
4
4
name: string;
···
14
14
};
15
15
16
16
export type Notices = Store<any> & {
17
+
/**
18
+
* Adds a custom notice to the top of the screen.
19
+
*/
17
20
addNotice: (notice: Notice) => void;
21
+
22
+
/**
23
+
* Removes the current notice from the top of the screen.
24
+
*/
18
25
popNotice: () => void;
26
+
27
+
/**
28
+
* @private
29
+
*/
19
30
getCurrentNotice: () => Notice | null;
31
+
32
+
/**
33
+
* @private
34
+
*/
20
35
shouldShowNotice: () => boolean;
21
36
};
+39
-8
packages/types/src/coreExtensions/settings.ts
+39
-8
packages/types/src/coreExtensions/settings.ts
···
1
1
import React, { ReactElement } from "react";
2
-
import type { Store } from "@moonlight-mod/mappings/discord/packages/flux";
2
+
import type { Store } from "@moonlight-mod/mappings/discord/packages/flux/Store";
3
3
4
4
export type NoticeProps = {
5
5
stores: Store<any>[];
···
7
7
};
8
8
9
9
export type SettingsSection =
10
-
| { section: "DIVIDER"; pos: number }
11
-
| { section: "HEADER"; label: string; pos: number }
10
+
| { section: "DIVIDER"; pos: number | ((sections: SettingsSection[]) => number) }
11
+
| { section: "HEADER"; label: string; pos: number | ((sections: SettingsSection[]) => number) }
12
12
| {
13
13
section: string;
14
14
label: string;
15
15
color: string | null;
16
16
element: React.FunctionComponent;
17
-
pos: number;
17
+
pos: number | ((sections: SettingsSection[]) => number);
18
18
notice?: NoticeProps;
19
+
onClick?: () => void;
19
20
_moonlight_submenu?: () => ReactElement | ReactElement[];
20
21
};
21
22
···
24
25
sectionNames: string[];
25
26
sectionMenuItems: Record<string, ReactElement[]>;
26
27
28
+
/**
29
+
* Registers a new section in the settings menu.
30
+
* @param section The section ID
31
+
* @param label The label for the section
32
+
* @param element The React component to render
33
+
* @param color A color to use for the section
34
+
* @param pos The position in the settings menu to place the section
35
+
* @param notice A notice to display when in the section
36
+
* @param onClick A custom action to execute when clicked from the context menu
37
+
*/
27
38
addSection: (
28
39
section: string,
29
40
label: string,
30
41
element: React.FunctionComponent,
31
42
color?: string | null,
32
-
pos?: number,
33
-
notice?: NoticeProps
43
+
pos?: number | ((sections: SettingsSection[]) => number),
44
+
notice?: NoticeProps,
45
+
onClick?: () => void
34
46
) => void;
47
+
48
+
/**
49
+
* Adds new items to a section in the settings menu.
50
+
* @param section The section ID
51
+
* @param items The React components to render
52
+
*/
35
53
addSectionMenuItems: (section: string, ...items: ReactElement[]) => void;
36
54
37
-
addDivider: (pos: number | null) => void;
38
-
addHeader: (label: string, pos: number | null) => void;
55
+
/**
56
+
* Places a divider in the settings menu.
57
+
* @param pos The position in the settings menu to place the divider
58
+
*/
59
+
addDivider: (pos: number | ((sections: SettingsSection[]) => number) | null) => void;
60
+
61
+
/**
62
+
* Places a header in the settings menu.
63
+
* @param pos The position in the settings menu to place the header
64
+
*/
65
+
addHeader: (label: string, pos: number | ((sections: SettingsSection[]) => number) | null) => void;
66
+
67
+
/**
68
+
* @private
69
+
*/
39
70
_mutateSections: (sections: SettingsSection[]) => SettingsSection[];
40
71
};
+83
-18
packages/types/src/coreExtensions/spacepack.ts
+83
-18
packages/types/src/coreExtensions/spacepack.ts
···
1
-
import {
2
-
WebpackModule,
3
-
WebpackModuleFunc,
4
-
WebpackRequireType
5
-
} from "../discord";
1
+
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "../discord";
6
2
7
3
export type Spacepack = {
4
+
/**
5
+
* Given a Webpack module ID, returns the function for the Webpack module.
6
+
* Can be double clicked to inspect in DevTools.
7
+
* @param module The module ID
8
+
* @returns The Webpack module, if found
9
+
*/
8
10
inspect: (module: number | string) => WebpackModuleFunc | null;
9
-
findByCode: (...args: (string | RegExp)[]) => any[];
10
-
findByExports: (...args: string[]) => any[];
11
+
12
+
/**
13
+
* Find Webpack modules based on matches in code.
14
+
* @param args A list of finds to match against
15
+
* @returns The Webpack modules, if found
16
+
*/
17
+
findByCode: (...args: (string | RegExp)[]) => WebpackModule[];
18
+
19
+
/**
20
+
* Find Webpack modules based on their exports.
21
+
* @deprecated This has race conditions. Consider using findByCode instead.
22
+
* @param args A list of finds to match exports against
23
+
* @returns The Webpack modules, if found
24
+
*/
25
+
findByExports: (...args: string[]) => WebpackModule[];
26
+
27
+
/**
28
+
* The Webpack require function.
29
+
*/
11
30
require: WebpackRequireType;
31
+
32
+
/**
33
+
* The Webpack module list.
34
+
* Re-export of require.m.
35
+
*/
12
36
modules: Record<string, WebpackModuleFunc>;
37
+
38
+
/**
39
+
* The Webpack module cache.
40
+
* Re-export of require.c.
41
+
*/
13
42
cache: Record<string, any>;
43
+
44
+
/**
45
+
* Finds an object from a module's exports using the given key.
46
+
* @param exports Exports from a Webpack module
47
+
* @param key The key to find with
48
+
* @returns The object, if found
49
+
*/
14
50
findObjectFromKey: (exports: Record<string, any>, key: string) => any | null;
51
+
52
+
/**
53
+
* Finds an object from a module's exports using the given value.
54
+
* @param exports Exports from a Webpack module
55
+
* @param value The value to find with
56
+
* @returns The object, if found
57
+
*/
15
58
findObjectFromValue: (exports: Record<string, any>, value: any) => any | null;
16
-
findObjectFromKeyValuePair: (
17
-
exports: Record<string, any>,
18
-
key: string,
19
-
value: any
20
-
) => any | null;
59
+
60
+
/**
61
+
* Finds an object from a module's exports using the given key-value pair.
62
+
* @param exports Exports from a Webpack module
63
+
* @param key The key to find with
64
+
* @param value The value to find with
65
+
* @returns The object, if found
66
+
*/
67
+
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => any | null;
68
+
69
+
/**
70
+
* Finds a function from a module's exports using the given source find.
71
+
* This behaves like findByCode but localized to the exported function.
72
+
* @param exports A module's exports
73
+
* @param strings A list of finds to use
74
+
* @returns The function, if found
75
+
*/
21
76
findFunctionByStrings: (
22
77
exports: Record<string, any>,
23
78
...strings: (string | RegExp)[]
24
-
// eslint-disable-next-line @typescript-eslint/ban-types
79
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
25
80
) => Function | null;
26
-
lazyLoad: (
27
-
find: string | RegExp | (string | RegExp)[],
28
-
chunk: RegExp,
29
-
module: RegExp
30
-
) => Promise<any>;
81
+
82
+
/**
83
+
* Lazy load a Webpack module.
84
+
* @param find A list of finds to discover a target module with
85
+
* @param chunk A RegExp to match chunks to load
86
+
* @param module A RegExp to match the target Webpack module
87
+
* @returns The target Webpack module
88
+
*/
89
+
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => Promise<any>;
90
+
91
+
/**
92
+
* Filter a list of Webpack modules to "real" ones from the Discord client.
93
+
* @param modules A list of Webpack modules
94
+
* @returns A filtered list of Webpack modules
95
+
*/
31
96
filterReal: (modules: WebpackModule[]) => WebpackModule[];
32
97
};
+4
packages/types/src/coreExtensions.ts
+4
packages/types/src/coreExtensions.ts
···
4
4
export * as ContextMenu from "./coreExtensions/contextMenu";
5
5
export * as Notices from "./coreExtensions/notices";
6
6
export * as Moonbase from "./coreExtensions/moonbase";
7
+
export * as AppPanels from "./coreExtensions/appPanels";
8
+
export * as Commands from "./coreExtensions/commands";
9
+
export * as ComponentEditor from "./coreExtensions/componentEditor";
10
+
export * as Common from "./coreExtensions/common";
+17
-2
packages/types/src/discord/require.ts
+17
-2
packages/types/src/discord/require.ts
···
1
+
import { AppPanels } from "../coreExtensions/appPanels";
2
+
import { Commands } from "../coreExtensions/commands";
3
+
import { ErrorBoundary, Icons } from "../coreExtensions/common";
4
+
import { DMList, MemberList, Messages } from "../coreExtensions/componentEditor";
1
5
import { ContextMenu, EvilItemParser } from "../coreExtensions/contextMenu";
2
6
import { Markdown } from "../coreExtensions/markdown";
7
+
import { Moonbase } from "../coreExtensions/moonbase";
8
+
import { Notices } from "../coreExtensions/notices";
3
9
import { Settings } from "../coreExtensions/settings";
4
10
import { Spacepack } from "../coreExtensions/spacepack";
5
-
import { Notices } from "../coreExtensions/notices";
6
-
import { Moonbase } from "../coreExtensions/moonbase";
7
11
8
12
declare function WebpackRequire(id: string): any;
13
+
14
+
declare function WebpackRequire(id: "appPanels_appPanels"): AppPanels;
15
+
16
+
declare function WebpackRequire(id: "commands_commands"): Commands;
17
+
18
+
declare function WebpackRequire(id: "common_ErrorBoundary"): ErrorBoundary;
19
+
declare function WebpackRequire(id: "common_icons"): Icons;
20
+
21
+
declare function WebpackRequire(id: "componentEditor_dmList"): DMList;
22
+
declare function WebpackRequire(id: "componentEditor_memberList"): MemberList;
23
+
declare function WebpackRequire(id: "componentEditor_messages"): Messages;
9
24
10
25
declare function WebpackRequire(id: "contextMenu_evilMenu"): EvilItemParser;
11
26
declare function WebpackRequire(id: "contextMenu_contextMenu"): ContextMenu;
+3
-11
packages/types/src/discord/webpack.ts
+3
-11
packages/types/src/discord/webpack.ts
···
10
10
11
11
export type WebpackModule = {
12
12
id: string | number;
13
-
loaded: boolean;
13
+
loaded?: boolean;
14
14
exports: any;
15
15
};
16
16
17
-
export type WebpackModuleFunc = ((
18
-
module: any,
19
-
exports: any,
20
-
require: WebpackRequireType
21
-
) => void) & {
17
+
export type WebpackModuleFunc = ((module: any, exports: any, require: WebpackRequireType) => void) & {
22
18
__moonlight?: boolean;
23
19
};
24
20
25
-
export type WebpackJsonpEntry = [
26
-
number[],
27
-
{ [id: string]: WebpackModuleFunc },
28
-
(require: WebpackRequireType) => any
29
-
];
21
+
export type WebpackJsonpEntry = [number[], { [id: string]: WebpackModuleFunc }, (require: WebpackRequireType) => any];
30
22
31
23
export type WebpackJsonp = WebpackJsonpEntry[] & {
32
24
push: {
+105
-3
packages/types/src/extension.ts
+105
-3
packages/types/src/extension.ts
···
28
28
};
29
29
30
30
export type ExtensionManifest = {
31
+
$schema?: string;
32
+
33
+
/**
34
+
* A unique identifier for your extension.
35
+
*/
31
36
id: string;
37
+
38
+
/**
39
+
* A version string for your extension - doesn't need to follow a specific format. Required for publishing.
40
+
*/
32
41
version?: string;
42
+
43
+
/**
44
+
* The API level this extension targets. If it does not match the current version, the extension will not be loaded.
45
+
*/
33
46
apiLevel?: number;
47
+
48
+
/**
49
+
* Which environment this extension is capable of running in.
50
+
*/
34
51
environment?: ExtensionEnvironment;
35
52
53
+
/**
54
+
* Metadata about your extension for use in Moonbase.
55
+
*/
36
56
meta?: {
57
+
/**
58
+
* A human friendly name for your extension as a proper noun.
59
+
*/
37
60
name?: string;
61
+
62
+
/**
63
+
* A short tagline that appears below the name.
64
+
*/
38
65
tagline?: string;
66
+
67
+
/**
68
+
* A longer description that can use Markdown.
69
+
*/
39
70
description?: string;
71
+
72
+
/**
73
+
* List of authors that worked on this extension - accepts string or object with ID.
74
+
*/
40
75
authors?: ExtensionAuthor[];
41
-
deprecated?: boolean;
76
+
77
+
/**
78
+
* A list of tags that are relevant to the extension.
79
+
*/
42
80
tags?: ExtensionTag[];
81
+
82
+
/**
83
+
* The URL to the source repository.
84
+
*/
43
85
source?: string;
86
+
87
+
/**
88
+
* A donation link (or other method of support). If you don't want financial contributions, consider putting your favorite charity here!
89
+
*/
90
+
donate?: string;
91
+
92
+
/**
93
+
* A changelog to show in Moonbase.
94
+
* Moonbase will show the changelog for the latest version, even if it is not installed.
95
+
*/
96
+
changelog?: string;
97
+
98
+
/**
99
+
* Whether the extension is deprecated and no longer receiving updates.
100
+
*/
101
+
deprecated?: boolean;
44
102
};
45
103
104
+
/**
105
+
* A list of extension IDs that are required for the extension to load.
106
+
*/
46
107
dependencies?: string[];
108
+
109
+
/**
110
+
* A list of extension IDs that the user may want to install.
111
+
*/
47
112
suggested?: string[];
113
+
114
+
/**
115
+
* A list of extension IDs that the extension is incompatible with.
116
+
* If two incompatible extensions are enabled, one of them will not load.
117
+
*/
48
118
incompatible?: string[];
49
119
120
+
/**
121
+
* A list of settings for your extension, where the key is the settings ID.
122
+
*/
50
123
settings?: Record<string, ExtensionSettingsManifest>;
51
124
125
+
/**
126
+
* A list of URLs to bypass CORS for.
127
+
* This is implemented by checking if the start of the URL matches.
128
+
* @example https://moonlight-mod.github.io/
129
+
*/
52
130
cors?: string[];
131
+
132
+
/**
133
+
* A list of URLs to block all requests to.
134
+
* This is implemented by checking if the start of the URL matches.
135
+
* @example https://moonlight-mod.github.io/
136
+
*/
53
137
blocked?: string[];
138
+
139
+
/**
140
+
* A mapping from CSP directives to URLs to allow.
141
+
* @example { "script-src": ["https://example.com"] }
142
+
*/
143
+
csp?: Record<string, string[]>;
54
144
};
55
145
56
146
export enum ExtensionEnvironment {
147
+
/**
148
+
* The extension will run on both platforms, the host/native modules MAY be loaded
149
+
*/
57
150
Both = "both",
151
+
152
+
/**
153
+
* Extension will run on desktop only, the host/native modules are guaranteed to load
154
+
*/
58
155
Desktop = "desktop",
156
+
157
+
/**
158
+
* Currently equivalent to Both
159
+
*/
59
160
Web = "web"
60
161
}
61
162
···
75
176
webpackModules?: Record<string, string>;
76
177
nodePath?: string;
77
178
hostPath?: string;
179
+
style?: string;
78
180
};
79
181
};
80
182
···
106
208
export type Patch = {
107
209
find: PatchMatch;
108
210
replace: PatchReplace | PatchReplace[];
211
+
hardFail?: boolean; // if any patches fail, all fail
109
212
prerequisite?: () => boolean;
110
213
};
111
214
···
133
236
id: number;
134
237
};
135
238
136
-
export type IdentifiedWebpackModule = ExtensionWebpackModule &
137
-
ExplicitExtensionDependency;
239
+
export type IdentifiedWebpackModule = ExtensionWebpackModule & ExplicitExtensionDependency;
+2
packages/types/src/fs.ts
+2
packages/types/src/fs.ts
+37
-21
packages/types/src/globals.ts
+37
-21
packages/types/src/globals.ts
···
1
1
import type { Logger } from "./logger";
2
2
import type { Config, ConfigExtension } from "./config";
3
-
import type {
4
-
DetectedExtension,
5
-
IdentifiedPatch,
6
-
IdentifiedWebpackModule,
7
-
ProcessedExtensions
8
-
} from "./extension";
3
+
import type { DetectedExtension, IdentifiedPatch, IdentifiedWebpackModule, ProcessedExtensions } from "./extension";
9
4
import type EventEmitter from "events";
10
5
import type LunAST from "@moonlight-mod/lunast";
11
6
import type Moonmap from "@moonlight-mod/moonmap";
12
7
import type {
13
-
EventPayloads,
14
-
EventType,
15
-
MoonlightEventEmitter
8
+
WebEventPayloads,
9
+
WebEventType,
10
+
MoonlightEventEmitter,
11
+
NodeEventType,
12
+
NodeEventPayloads
16
13
} from "./core/event";
14
+
import type { MoonlightFS } from "./fs";
17
15
18
16
export type MoonlightHost = {
19
-
asarPath: string;
20
17
config: Config;
21
-
events: EventEmitter;
22
18
extensions: DetectedExtension[];
23
19
processedExtensions: ProcessedExtensions;
20
+
asarPath: string;
21
+
events: EventEmitter;
24
22
25
23
version: string;
26
24
branch: MoonlightBranch;
27
25
28
26
getConfig: (ext: string) => ConfigExtension["config"];
27
+
getConfigPath: () => Promise<string>;
29
28
getConfigOption: <T>(ext: string, name: string) => T | undefined;
29
+
setConfigOption: <T>(ext: string, name: string, value: T) => void;
30
+
writeConfig: (config: Config) => Promise<void>;
31
+
30
32
getLogger: (id: string) => Logger;
33
+
getMoonlightDir: () => string;
34
+
getExtensionDir: (ext: string) => string;
31
35
};
32
36
33
37
export type MoonlightNode = {
···
36
40
processedExtensions: ProcessedExtensions;
37
41
nativesCache: Record<string, any>;
38
42
isBrowser: boolean;
43
+
events: MoonlightEventEmitter<NodeEventType, NodeEventPayloads>;
39
44
40
45
version: string;
41
46
branch: MoonlightBranch;
42
47
43
48
getConfig: (ext: string) => ConfigExtension["config"];
44
49
getConfigOption: <T>(ext: string, name: string) => T | undefined;
50
+
setConfigOption: <T>(ext: string, name: string, value: T) => Promise<void>;
51
+
writeConfig: (config: Config) => Promise<void>;
52
+
45
53
getNatives: (ext: string) => any | undefined;
46
54
getLogger: (id: string) => Logger;
47
-
48
55
getMoonlightDir: () => string;
49
56
getExtensionDir: (ext: string) => string;
50
-
writeConfig: (config: Config) => Promise<void>;
57
+
};
58
+
59
+
export type MoonlightNodeSandboxed = {
60
+
fs: MoonlightFS;
61
+
addCors: (url: string) => void;
62
+
addBlocked: (url: string) => void;
51
63
};
52
64
53
65
export type MoonlightWeb = {
66
+
patched: Map<string, Set<string>>;
54
67
unpatched: Set<IdentifiedPatch>;
55
68
pendingModules: Set<IdentifiedWebpackModule>;
56
69
enabledExtensions: Set<string>;
57
-
apiLevel: number;
58
-
events: MoonlightEventEmitter<EventType, EventPayloads>;
70
+
events: MoonlightEventEmitter<WebEventType, WebEventPayloads>;
59
71
patchingInternals: {
60
-
onModuleLoad: (
61
-
moduleId: string | string[],
62
-
callback: (moduleId: string) => void
63
-
) => void;
72
+
onModuleLoad: (moduleId: string | string[], callback: (moduleId: string) => void) => void;
64
73
registerPatch: (patch: IdentifiedPatch) => void;
65
74
registerWebpackModule: (module: IdentifiedWebpackModule) => void;
66
75
};
76
+
localStorage: Storage;
67
77
68
78
version: string;
69
79
branch: MoonlightBranch;
80
+
apiLevel: number;
70
81
71
-
getConfig: (ext: string) => ConfigExtension["config"];
72
-
getConfigOption: <T>(ext: string, name: string) => T | undefined;
82
+
// Re-exports for ease of use
83
+
getConfig: MoonlightNode["getConfig"];
84
+
getConfigOption: MoonlightNode["getConfigOption"];
85
+
setConfigOption: MoonlightNode["setConfigOption"];
86
+
writeConfig: MoonlightNode["writeConfig"];
87
+
73
88
getNatives: (ext: string) => any | undefined;
74
89
getLogger: (id: string) => Logger;
90
+
75
91
lunast: LunAST;
76
92
moonmap: Moonmap;
77
93
};
+38
packages/types/src/import.d.ts
+38
packages/types/src/import.d.ts
···
1
+
declare module "@moonlight-mod/wp/appPanels_appPanels" {
2
+
import { CoreExtensions } from "@moonlight-mod/types";
3
+
const AppPanels: CoreExtensions.AppPanels.AppPanels;
4
+
export = AppPanels;
5
+
}
6
+
7
+
declare module "@moonlight-mod/wp/commands_commands" {
8
+
import { CoreExtensions } from "@moonlight-mod/types";
9
+
export const commands: CoreExtensions.Commands.Commands;
10
+
export default commands;
11
+
}
12
+
13
+
declare module "@moonlight-mod/wp/common_ErrorBoundary" {
14
+
import { CoreExtensions } from "@moonlight-mod/types";
15
+
const ErrorBoundary: CoreExtensions.Common.ErrorBoundary;
16
+
export = ErrorBoundary;
17
+
}
18
+
declare module "@moonlight-mod/wp/common_icons" {
19
+
import { CoreExtensions } from "@moonlight-mod/types";
20
+
export const icons: CoreExtensions.Common.Icons;
21
+
export default icons;
22
+
}
1
23
declare module "@moonlight-mod/wp/common_stores";
24
+
25
+
declare module "@moonlight-mod/wp/componentEditor_dmList" {
26
+
import { CoreExtensions } from "@moonlight-mod/types";
27
+
export const dmList: CoreExtensions.ComponentEditor.DMList;
28
+
export default dmList;
29
+
}
30
+
declare module "@moonlight-mod/wp/componentEditor_memberList" {
31
+
import { CoreExtensions } from "@moonlight-mod/types";
32
+
export const memberList: CoreExtensions.ComponentEditor.MemberList;
33
+
export default memberList;
34
+
}
35
+
declare module "@moonlight-mod/wp/componentEditor_messages" {
36
+
import { CoreExtensions } from "@moonlight-mod/types";
37
+
export const message: CoreExtensions.ComponentEditor.Messages;
38
+
export default message;
39
+
}
2
40
3
41
declare module "@moonlight-mod/wp/contextMenu_evilMenu" {
4
42
import { CoreExtensions } from "@moonlight-mod/types";
+5
-10
packages/types/src/index.ts
+5
-10
packages/types/src/index.ts
···
4
4
/// <reference types="./mappings" />
5
5
/* eslint-disable no-var */
6
6
7
-
import { MoonlightFS } from "./fs";
8
-
import {
9
-
MoonlightEnv,
10
-
MoonlightHost,
11
-
MoonlightNode,
12
-
MoonlightWeb
13
-
} from "./globals";
7
+
import { MoonlightEnv, MoonlightHost, MoonlightNode, MoonlightNodeSandboxed, MoonlightWeb } from "./globals";
14
8
15
9
export * from "./discord";
16
10
export * from "./config";
···
36
30
37
31
var moonlightHost: MoonlightHost;
38
32
var moonlightNode: MoonlightNode;
33
+
var moonlightNodeSandboxed: MoonlightNodeSandboxed;
39
34
var moonlight: MoonlightWeb;
40
-
var moonlightFS: MoonlightFS;
35
+
var _moonlight_coreExtensionsStr: string;
41
36
42
-
var _moonlightBrowserInit: () => Promise<void>;
43
-
var _moonlightBrowserLoad: () => Promise<void>;
37
+
var _moonlightBrowserInit: undefined | (() => Promise<void>);
38
+
var _moonlightWebLoad: undefined | (() => Promise<void>);
44
39
}
+860
-14
packages/types/src/mappings.d.ts
+860
-14
packages/types/src/mappings.d.ts
···
1
1
// auto-generated
2
+
declare module "@moonlight-mod/wp/chroma-js" {}
3
+
4
+
declare module "@moonlight-mod/wp/classnames" {
5
+
import { MappedModules } from "@moonlight-mod/mappings";
6
+
const _default: MappedModules["classnames"]["default"];
7
+
export default _default;
8
+
}
9
+
10
+
declare module "@moonlight-mod/wp/dependency-graph" {
11
+
import { MappedModules } from "@moonlight-mod/mappings";
12
+
export const DepGraph: MappedModules["dependency-graph"]["DepGraph"];
13
+
}
14
+
15
+
declare module "@moonlight-mod/wp/discord/Constants" {
16
+
import { MappedModules } from "@moonlight-mod/mappings";
17
+
export const ActivityFlags: MappedModules["discord/Constants"]["ActivityFlags"];
18
+
export const ActivityTypes: MappedModules["discord/Constants"]["ActivityTypes"];
19
+
export const AnalyticsLocations: MappedModules["discord/Constants"]["AnalyticsLocations"];
20
+
export const ChannelLayouts: MappedModules["discord/Constants"]["ChannelLayouts"];
21
+
export const ChannelModes: MappedModules["discord/Constants"]["ChannelModes"];
22
+
export const ChannelTypes: MappedModules["discord/Constants"]["ChannelTypes"];
23
+
export const ChannelStreamTypes: MappedModules["discord/Constants"]["ChannelStreamTypes"];
24
+
export const ComponentActions: MappedModules["discord/Constants"]["ComponentActions"];
25
+
export const DEFAULT_ROLE_COLOR: MappedModules["discord/Constants"]["DEFAULT_ROLE_COLOR"];
26
+
export const Endpoints: MappedModules["discord/Constants"]["Endpoints"];
27
+
export const MessageFlags: MappedModules["discord/Constants"]["MessageFlags"];
28
+
export const MessageTypes: MappedModules["discord/Constants"]["MessageTypes"];
29
+
export const Permissions: MappedModules["discord/Constants"]["Permissions"];
30
+
export const PlatformTypes: MappedModules["discord/Constants"]["PlatformTypes"];
31
+
export const RelationshipTypes: MappedModules["discord/Constants"]["RelationshipTypes"];
32
+
export const Routes: MappedModules["discord/Constants"]["Routes"];
33
+
export const StatusTypes: MappedModules["discord/Constants"]["StatusTypes"];
34
+
export const Themes: MappedModules["discord/Constants"]["Themes"];
35
+
export const UserSettingsSections: MappedModules["discord/Constants"]["UserSettingsSections"];
36
+
export const UserFlags: MappedModules["discord/Constants"]["UserFlags"];
37
+
}
38
+
2
39
declare module "@moonlight-mod/wp/discord/Dispatcher" {
3
40
import { MappedModules } from "@moonlight-mod/mappings";
4
-
const _: MappedModules["discord/Dispatcher"];
5
-
export = _;
41
+
const _default: MappedModules["discord/Dispatcher"]["default"];
42
+
export default _default;
43
+
}
44
+
45
+
declare module "@moonlight-mod/wp/discord/actions/ContextMenuActionCreators" {
46
+
import { MappedModules } from "@moonlight-mod/mappings";
47
+
export const closeContextMenu: MappedModules["discord/actions/ContextMenuActionCreators"]["closeContextMenu"];
48
+
export const openContextMenu: MappedModules["discord/actions/ContextMenuActionCreators"]["openContextMenu"];
49
+
export const openContextMenuLazy: MappedModules["discord/actions/ContextMenuActionCreators"]["openContextMenuLazy"];
50
+
}
51
+
52
+
declare module "@moonlight-mod/wp/discord/actions/UserSettingsModalActionCreators" {
53
+
import { MappedModules } from "@moonlight-mod/mappings";
54
+
const _default: MappedModules["discord/actions/UserSettingsModalActionCreators"]["default"];
55
+
export default _default;
56
+
}
57
+
58
+
declare module "@moonlight-mod/wp/discord/common/AppStartPerformance" {
59
+
import { MappedModules } from "@moonlight-mod/mappings";
60
+
const _default: MappedModules["discord/common/AppStartPerformance"]["default"];
61
+
export default _default;
62
+
}
63
+
64
+
declare module "@moonlight-mod/wp/discord/components/common/Alerts" {
65
+
import { MappedModules } from "@moonlight-mod/mappings";
66
+
const _default: MappedModules["discord/components/common/Alerts"]["default"];
67
+
export default _default;
68
+
}
69
+
70
+
declare module "@moonlight-mod/wp/discord/components/common/BaseHeaderBar" {
71
+
import { MappedModules } from "@moonlight-mod/mappings";
72
+
export const Icon: MappedModules["discord/components/common/BaseHeaderBar"]["Icon"];
73
+
export const Divider: MappedModules["discord/components/common/BaseHeaderBar"]["Divider"];
74
+
const _default: MappedModules["discord/components/common/BaseHeaderBar"]["default"];
75
+
export default _default;
76
+
}
77
+
78
+
declare module "@moonlight-mod/wp/discord/components/common/Card" {
79
+
import { MappedModules } from "@moonlight-mod/mappings";
80
+
const _default: MappedModules["discord/components/common/Card"]["default"];
81
+
export default _default;
82
+
export const Types: MappedModules["discord/components/common/Card"]["Types"];
83
+
}
84
+
85
+
declare module "@moonlight-mod/wp/discord/components/common/FileUpload" {
86
+
import { MappedModules } from "@moonlight-mod/mappings";
87
+
const _default: MappedModules["discord/components/common/FileUpload"]["default"];
88
+
export default _default;
89
+
}
90
+
91
+
declare module "@moonlight-mod/wp/discord/components/common/FormSwitch.css" {
92
+
import { MappedModules } from "@moonlight-mod/mappings";
93
+
export const container: MappedModules["discord/components/common/FormSwitch.css"]["container"];
94
+
export const labelRow: MappedModules["discord/components/common/FormSwitch.css"]["labelRow"];
95
+
export const control: MappedModules["discord/components/common/FormSwitch.css"]["control"];
96
+
export const disabled: MappedModules["discord/components/common/FormSwitch.css"]["disabled"];
97
+
export const title: MappedModules["discord/components/common/FormSwitch.css"]["title"];
98
+
export const note: MappedModules["discord/components/common/FormSwitch.css"]["note"];
99
+
export const disabledText: MappedModules["discord/components/common/FormSwitch.css"]["disabledText"];
100
+
export const dividerDefault: MappedModules["discord/components/common/FormSwitch.css"]["dividerDefault"];
101
+
}
102
+
103
+
declare module "@moonlight-mod/wp/discord/components/common/HeaderBar.css" {
104
+
import { MappedModules } from "@moonlight-mod/mappings";
105
+
export const caret: MappedModules["discord/components/common/HeaderBar.css"]["caret"];
106
+
export const children: MappedModules["discord/components/common/HeaderBar.css"]["children"];
107
+
export const clickable: MappedModules["discord/components/common/HeaderBar.css"]["clickable"];
108
+
export const container: MappedModules["discord/components/common/HeaderBar.css"]["container"];
109
+
export const divider: MappedModules["discord/components/common/HeaderBar.css"]["divider"];
110
+
export const dot: MappedModules["discord/components/common/HeaderBar.css"]["dot"];
111
+
export const hamburger: MappedModules["discord/components/common/HeaderBar.css"]["hamburger"];
112
+
export const icon: MappedModules["discord/components/common/HeaderBar.css"]["icon"];
113
+
export const iconBadge: MappedModules["discord/components/common/HeaderBar.css"]["iconBadge"];
114
+
export const iconBadgeBottom: MappedModules["discord/components/common/HeaderBar.css"]["iconBadgeBottom"];
115
+
export const iconBadgeTop: MappedModules["discord/components/common/HeaderBar.css"]["iconBadgeTop"];
116
+
export const iconWrapper: MappedModules["discord/components/common/HeaderBar.css"]["iconWrapper"];
117
+
export const scrollable: MappedModules["discord/components/common/HeaderBar.css"]["scrollable"];
118
+
export const selected: MappedModules["discord/components/common/HeaderBar.css"]["selected"];
119
+
export const themed: MappedModules["discord/components/common/HeaderBar.css"]["themed"];
120
+
export const themedMobile: MappedModules["discord/components/common/HeaderBar.css"]["themedMobile"];
121
+
export const title: MappedModules["discord/components/common/HeaderBar.css"]["title"];
122
+
export const titleWrapper: MappedModules["discord/components/common/HeaderBar.css"]["titleWrapper"];
123
+
export const toolbar: MappedModules["discord/components/common/HeaderBar.css"]["toolbar"];
124
+
export const transparent: MappedModules["discord/components/common/HeaderBar.css"]["transparent"];
125
+
export const upperContainer: MappedModules["discord/components/common/HeaderBar.css"]["upperContainer"];
126
+
}
127
+
128
+
declare module "@moonlight-mod/wp/discord/components/common/HelpMessage.css" {
129
+
import { MappedModules } from "@moonlight-mod/mappings";
130
+
export const container: MappedModules["discord/components/common/HelpMessage.css"]["container"];
131
+
export const icon: MappedModules["discord/components/common/HelpMessage.css"]["icon"];
132
+
export const iconDiv: MappedModules["discord/components/common/HelpMessage.css"]["iconDiv"];
133
+
export const text: MappedModules["discord/components/common/HelpMessage.css"]["text"];
134
+
export const positive: MappedModules["discord/components/common/HelpMessage.css"]["positive"];
135
+
export const warning: MappedModules["discord/components/common/HelpMessage.css"]["warning"];
136
+
export const info: MappedModules["discord/components/common/HelpMessage.css"]["info"];
137
+
export const error: MappedModules["discord/components/common/HelpMessage.css"]["error"];
138
+
}
139
+
140
+
declare module "@moonlight-mod/wp/discord/components/common/Image" {}
141
+
142
+
declare module "@moonlight-mod/wp/discord/components/common/PanelButton" {
143
+
import { MappedModules } from "@moonlight-mod/mappings";
144
+
const _default: MappedModules["discord/components/common/PanelButton"]["default"];
145
+
export default _default;
146
+
}
147
+
148
+
declare module "@moonlight-mod/wp/discord/components/common/Scroller.css" {
149
+
import { MappedModules } from "@moonlight-mod/mappings";
150
+
export const auto: MappedModules["discord/components/common/Scroller.css"]["auto"];
151
+
export const content: MappedModules["discord/components/common/Scroller.css"]["content"];
152
+
export const customTheme: MappedModules["discord/components/common/Scroller.css"]["customTheme"];
153
+
export const disableScrollAnchor: MappedModules["discord/components/common/Scroller.css"]["disableScrollAnchor"];
154
+
export const fade: MappedModules["discord/components/common/Scroller.css"]["fade"];
155
+
export const managedReactiveScroller: MappedModules["discord/components/common/Scroller.css"]["managedReactiveScroller"];
156
+
export const none: MappedModules["discord/components/common/Scroller.css"]["none"];
157
+
export const pointerCover: MappedModules["discord/components/common/Scroller.css"]["pointerCover"];
158
+
export const scrolling: MappedModules["discord/components/common/Scroller.css"]["scrolling"];
159
+
export const thin: MappedModules["discord/components/common/Scroller.css"]["thin"];
6
160
}
7
161
8
162
declare module "@moonlight-mod/wp/discord/components/common/index" {
9
163
import { MappedModules } from "@moonlight-mod/mappings";
10
-
const _: MappedModules["discord/components/common/index"];
11
-
export = _;
164
+
export const Clickable: MappedModules["discord/components/common/index"]["Clickable"];
165
+
export const TextInput: MappedModules["discord/components/common/index"]["TextInput"];
166
+
export const TextArea: MappedModules["discord/components/common/index"]["TextArea"];
167
+
export const FormDivider: MappedModules["discord/components/common/index"]["FormDivider"];
168
+
export const FormSection: MappedModules["discord/components/common/index"]["FormSection"];
169
+
export const FormText: MappedModules["discord/components/common/index"]["FormText"];
170
+
export const FormTitle: MappedModules["discord/components/common/index"]["FormTitle"];
171
+
export const FormSwitch: MappedModules["discord/components/common/index"]["FormSwitch"];
172
+
export const FormItem: MappedModules["discord/components/common/index"]["FormItem"];
173
+
export const Slider: MappedModules["discord/components/common/index"]["Slider"];
174
+
export const Switch: MappedModules["discord/components/common/index"]["Switch"];
175
+
export const Button: MappedModules["discord/components/common/index"]["Button"];
176
+
export const Tooltip: MappedModules["discord/components/common/index"]["Tooltip"];
177
+
export const Avatar: MappedModules["discord/components/common/index"]["Avatar"];
178
+
export const AvatarSizes: MappedModules["discord/components/common/index"]["AvatarSizes"];
179
+
export const AvatarSizeSpecs: MappedModules["discord/components/common/index"]["AvatarSizeSpecs"];
180
+
export const Scroller: MappedModules["discord/components/common/index"]["Scroller"];
181
+
export const Text: MappedModules["discord/components/common/index"]["Text"];
182
+
export const Heading: MappedModules["discord/components/common/index"]["Heading"];
183
+
export const Card: MappedModules["discord/components/common/index"]["Card"];
184
+
export const Popout: MappedModules["discord/components/common/index"]["Popout"];
185
+
export const Dialog: MappedModules["discord/components/common/index"]["Dialog"];
186
+
export const Menu: MappedModules["discord/components/common/index"]["Menu"];
187
+
export const TabBar: MappedModules["discord/components/common/index"]["TabBar"];
188
+
export const SingleSelect: MappedModules["discord/components/common/index"]["SingleSelect"];
189
+
export const Select: MappedModules["discord/components/common/index"]["Select"];
190
+
export const NoticeColors: MappedModules["discord/components/common/index"]["NoticeColors"];
191
+
export const Notice: MappedModules["discord/components/common/index"]["Notice"];
192
+
export const NoticeCloseButton: MappedModules["discord/components/common/index"]["NoticeCloseButton"];
193
+
export const PrimaryCTANoticeButton: MappedModules["discord/components/common/index"]["PrimaryCTANoticeButton"];
194
+
export const Breadcrumbs: MappedModules["discord/components/common/index"]["Breadcrumbs"];
195
+
export const Image: MappedModules["discord/components/common/index"]["Image"];
196
+
export const tokens: MappedModules["discord/components/common/index"]["tokens"];
197
+
export const useVariableSelect: MappedModules["discord/components/common/index"]["useVariableSelect"];
198
+
export const useMultiSelect: MappedModules["discord/components/common/index"]["useMultiSelect"];
199
+
export const multiSelect: MappedModules["discord/components/common/index"]["multiSelect"];
200
+
export const openModal: MappedModules["discord/components/common/index"]["openModal"];
201
+
export const openModalLazy: MappedModules["discord/components/common/index"]["openModalLazy"];
202
+
export const closeModal: MappedModules["discord/components/common/index"]["closeModal"];
203
+
export const AngleBracketsIcon: MappedModules["discord/components/common/index"]["AngleBracketsIcon"];
204
+
export const ArrowAngleLeftUpIcon: MappedModules["discord/components/common/index"]["ArrowAngleLeftUpIcon"];
205
+
export const ArrowAngleRightUpIcon: MappedModules["discord/components/common/index"]["ArrowAngleRightUpIcon"];
206
+
export const ArrowsUpDownIcon: MappedModules["discord/components/common/index"]["ArrowsUpDownIcon"];
207
+
export const BookCheckIcon: MappedModules["discord/components/common/index"]["BookCheckIcon"];
208
+
export const ChannelListIcon: MappedModules["discord/components/common/index"]["ChannelListIcon"];
209
+
export const ChevronSmallDownIcon: MappedModules["discord/components/common/index"]["ChevronSmallDownIcon"];
210
+
export const ChevronSmallUpIcon: MappedModules["discord/components/common/index"]["ChevronSmallUpIcon"];
211
+
export const CircleInformationIcon: MappedModules["discord/components/common/index"]["CircleInformationIcon"];
212
+
export const CircleWarningIcon: MappedModules["discord/components/common/index"]["CircleWarningIcon"];
213
+
export const CircleXIcon: MappedModules["discord/components/common/index"]["CircleXIcon"];
214
+
export const ClydeIcon: MappedModules["discord/components/common/index"]["ClydeIcon"];
215
+
export const CopyIcon: MappedModules["discord/components/common/index"]["CopyIcon"];
216
+
export const DownloadIcon: MappedModules["discord/components/common/index"]["DownloadIcon"];
217
+
export const FullscreenEnterIcon: MappedModules["discord/components/common/index"]["FullscreenEnterIcon"];
218
+
export const GameControllerIcon: MappedModules["discord/components/common/index"]["GameControllerIcon"];
219
+
export const GlobeEarthIcon: MappedModules["discord/components/common/index"]["GlobeEarthIcon"];
220
+
export const HeartIcon: MappedModules["discord/components/common/index"]["HeartIcon"];
221
+
export const LinkIcon: MappedModules["discord/components/common/index"]["LinkIcon"];
222
+
export const MaximizeIcon: MappedModules["discord/components/common/index"]["MaximizeIcon"];
223
+
export const MinusIcon: MappedModules["discord/components/common/index"]["MinusIcon"];
224
+
export const MobilePhoneIcon: MappedModules["discord/components/common/index"]["MobilePhoneIcon"];
225
+
export const PauseIcon: MappedModules["discord/components/common/index"]["PauseIcon"];
226
+
export const PlayIcon: MappedModules["discord/components/common/index"]["PlayIcon"];
227
+
export const PlusLargeIcon: MappedModules["discord/components/common/index"]["PlusLargeIcon"];
228
+
export const RetryIcon: MappedModules["discord/components/common/index"]["RetryIcon"];
229
+
export const ScienceIcon: MappedModules["discord/components/common/index"]["ScienceIcon"];
230
+
export const ScreenIcon: MappedModules["discord/components/common/index"]["ScreenIcon"];
231
+
export const StarIcon: MappedModules["discord/components/common/index"]["StarIcon"];
232
+
export const TrashIcon: MappedModules["discord/components/common/index"]["TrashIcon"];
233
+
export const WarningIcon: MappedModules["discord/components/common/index"]["WarningIcon"];
234
+
export const WindowLaunchIcon: MappedModules["discord/components/common/index"]["WindowLaunchIcon"];
235
+
export const WindowTopOutlineIcon: MappedModules["discord/components/common/index"]["WindowTopOutlineIcon"];
236
+
export const XLargeIcon: MappedModules["discord/components/common/index"]["XLargeIcon"];
237
+
export const XSmallIcon: MappedModules["discord/components/common/index"]["XSmallIcon"];
238
+
export const ConfirmModal: MappedModules["discord/components/common/index"]["ConfirmModal"];
239
+
export const H: MappedModules["discord/components/common/index"]["H"];
240
+
export const HelpMessage: MappedModules["discord/components/common/index"]["HelpMessage"];
241
+
export const ModalCloseButton: MappedModules["discord/components/common/index"]["ModalCloseButton"];
242
+
export const ModalContent: MappedModules["discord/components/common/index"]["ModalContent"];
243
+
export const ModalFooter: MappedModules["discord/components/common/index"]["ModalFooter"];
244
+
export const ModalHeader: MappedModules["discord/components/common/index"]["ModalHeader"];
245
+
export const ModalRoot: MappedModules["discord/components/common/index"]["ModalRoot"];
246
+
export const NumberInputStepper: MappedModules["discord/components/common/index"]["NumberInputStepper"];
247
+
export const SearchableSelect: MappedModules["discord/components/common/index"]["SearchableSelect"];
248
+
export const createToast: MappedModules["discord/components/common/index"]["createToast"];
249
+
export const popToast: MappedModules["discord/components/common/index"]["popToast"];
250
+
export const showToast: MappedModules["discord/components/common/index"]["showToast"];
251
+
export const useThemeContext: MappedModules["discord/components/common/index"]["useThemeContext"];
252
+
export const AccessibilityAnnouncer: MappedModules["discord/components/common/index"]["AccessibilityAnnouncer"];
253
+
export const BackdropStyles: MappedModules["discord/components/common/index"]["BackdropStyles"];
254
+
export const BadgeShapes: MappedModules["discord/components/common/index"]["BadgeShapes"];
255
+
export const CardTypes: MappedModules["discord/components/common/index"]["CardTypes"];
256
+
export const CircleIconButtonColors: MappedModules["discord/components/common/index"]["CircleIconButtonColors"];
257
+
export const CircleIconButtonSizes: MappedModules["discord/components/common/index"]["CircleIconButtonSizes"];
258
+
export const FormErrorBlockColors: MappedModules["discord/components/common/index"]["FormErrorBlockColors"];
259
+
export const FormNoticeImagePositions: MappedModules["discord/components/common/index"]["FormNoticeImagePositions"];
260
+
export const FormTitleTags: MappedModules["discord/components/common/index"]["FormTitleTags"];
261
+
export const HelpMessageTypes: MappedModules["discord/components/common/index"]["HelpMessageTypes"];
262
+
export const ModalSize: MappedModules["discord/components/common/index"]["ModalSize"];
263
+
export const ModalTransitionState: MappedModules["discord/components/common/index"]["ModalTransitionState"];
264
+
export const PRETTY_KEYS: MappedModules["discord/components/common/index"]["PRETTY_KEYS"];
265
+
export const SelectLooks: MappedModules["discord/components/common/index"]["SelectLooks"];
266
+
export const SpinnerTypes: MappedModules["discord/components/common/index"]["SpinnerTypes"];
267
+
export const StatusTypes: MappedModules["discord/components/common/index"]["StatusTypes"];
268
+
export const ToastPosition: MappedModules["discord/components/common/index"]["ToastPosition"];
269
+
export const ToastType: MappedModules["discord/components/common/index"]["ToastType"];
270
+
export const TransitionStates: MappedModules["discord/components/common/index"]["TransitionStates"];
271
+
export const DEFAULT_MODAL_CONTEXT: MappedModules["discord/components/common/index"]["DEFAULT_MODAL_CONTEXT"];
272
+
export const LOW_SATURATION_THRESHOLD: MappedModules["discord/components/common/index"]["LOW_SATURATION_THRESHOLD"];
273
+
export const LayerClassName: MappedModules["discord/components/common/index"]["LayerClassName"];
274
+
export const POPOUT_MODAL_CONTEXT: MappedModules["discord/components/common/index"]["POPOUT_MODAL_CONTEXT"];
275
+
}
276
+
277
+
declare module "@moonlight-mod/wp/discord/components/modals/ConfirmModal" {
278
+
import { MappedModules } from "@moonlight-mod/mappings";
279
+
const _default: MappedModules["discord/components/modals/ConfirmModal"]["default"];
280
+
export default _default;
12
281
}
13
282
14
-
declare module "@moonlight-mod/wp/discord/modules/guild_settings/IntegrationCard.css" {
283
+
declare module "@moonlight-mod/wp/discord/lib/BaseRecord" {
15
284
import { MappedModules } from "@moonlight-mod/mappings";
16
-
const _: MappedModules["discord/modules/guild_settings/IntegrationCard.css"];
17
-
export = _;
285
+
const _default: MappedModules["discord/lib/BaseRecord"]["default"];
286
+
export default _default;
287
+
}
288
+
289
+
declare module "@moonlight-mod/wp/discord/lib/web/Storage" {
290
+
import { MappedModules } from "@moonlight-mod/mappings";
291
+
export const ObjectStorage: MappedModules["discord/lib/web/Storage"]["ObjectStorage"];
292
+
export const impl: MappedModules["discord/lib/web/Storage"]["impl"];
293
+
}
294
+
295
+
declare module "@moonlight-mod/wp/discord/modules/build_overrides/web/BuildOverride.css" {
296
+
import { MappedModules } from "@moonlight-mod/mappings";
297
+
export const wrapper: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["wrapper"];
298
+
export const titleRegion: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["titleRegion"];
299
+
export const title: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["title"];
300
+
export const infoIcon: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["infoIcon"];
301
+
export const copyLink: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["copyLink"];
302
+
export const copied: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["copied"];
303
+
export const copyLinkIcon: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["copyLinkIcon"];
304
+
export const content: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["content"];
305
+
export const infoLink: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["infoLink"];
306
+
export const buildInfo: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["buildInfo"];
307
+
export const button: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["button"];
308
+
export const buttonSize: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["buttonSize"];
309
+
export const subHead: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["subHead"];
310
+
export const icon: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["icon"];
311
+
export const buildDetails: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["buildDetails"];
312
+
export const barLoader: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["barLoader"];
313
+
export const barTitle: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["barTitle"];
314
+
export const buttonLoader: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["buttonLoader"];
315
+
export const disabledButtonOverride: MappedModules["discord/modules/build_overrides/web/BuildOverride.css"]["disabledButtonOverride"];
316
+
}
317
+
318
+
declare module "@moonlight-mod/wp/discord/modules/discovery/web/Discovery.css" {
319
+
import { MappedModules } from "@moonlight-mod/mappings";
320
+
export const header: MappedModules["discord/modules/discovery/web/Discovery.css"]["header"];
321
+
export const headerImage: MappedModules["discord/modules/discovery/web/Discovery.css"]["headerImage"];
322
+
export const headerImageSimple: MappedModules["discord/modules/discovery/web/Discovery.css"]["headerImageSimple"];
323
+
export const headerImageBG: MappedModules["discord/modules/discovery/web/Discovery.css"]["headerImageBG"];
324
+
export const searchTitle: MappedModules["discord/modules/discovery/web/Discovery.css"]["searchTitle"];
325
+
export const searchSubtitle: MappedModules["discord/modules/discovery/web/Discovery.css"]["searchSubtitle"];
326
+
export const headerContentWrapper: MappedModules["discord/modules/discovery/web/Discovery.css"]["headerContentWrapper"];
327
+
export const headerContent: MappedModules["discord/modules/discovery/web/Discovery.css"]["headerContent"];
328
+
export const headerContentSmall: MappedModules["discord/modules/discovery/web/Discovery.css"]["headerContentSmall"];
329
+
export const searchBox: MappedModules["discord/modules/discovery/web/Discovery.css"]["searchBox"];
330
+
export const searchBoxInput: MappedModules["discord/modules/discovery/web/Discovery.css"]["searchBoxInput"];
331
+
export const closeIcon: MappedModules["discord/modules/discovery/web/Discovery.css"]["closeIcon"];
332
+
export const searchIcon: MappedModules["discord/modules/discovery/web/Discovery.css"]["searchIcon"];
333
+
export const tabBar: MappedModules["discord/modules/discovery/web/Discovery.css"]["tabBar"];
334
+
export const tabBarItem: MappedModules["discord/modules/discovery/web/Discovery.css"]["tabBarItem"];
335
+
export const sectionHeader: MappedModules["discord/modules/discovery/web/Discovery.css"]["sectionHeader"];
336
+
}
337
+
338
+
declare module "@moonlight-mod/wp/discord/modules/forums/web/Forums.css" {
339
+
import { MappedModules } from "@moonlight-mod/mappings";
340
+
export const container: MappedModules["discord/modules/forums/web/Forums.css"]["container"];
341
+
export const uploadArea: MappedModules["discord/modules/forums/web/Forums.css"]["uploadArea"];
342
+
export const label: MappedModules["discord/modules/forums/web/Forums.css"]["label"];
343
+
export const content: MappedModules["discord/modules/forums/web/Forums.css"]["content"];
344
+
export const noListContainer: MappedModules["discord/modules/forums/web/Forums.css"]["noListContainer"];
345
+
export const list: MappedModules["discord/modules/forums/web/Forums.css"]["list"];
346
+
export const grid: MappedModules["discord/modules/forums/web/Forums.css"]["grid"];
347
+
export const headerRow: MappedModules["discord/modules/forums/web/Forums.css"]["headerRow"];
348
+
export const card: MappedModules["discord/modules/forums/web/Forums.css"]["card"];
349
+
export const columnsSpan: MappedModules["discord/modules/forums/web/Forums.css"]["columnsSpan"];
350
+
export const emptyStateRow: MappedModules["discord/modules/forums/web/Forums.css"]["emptyStateRow"];
351
+
export const newMemberBanner: MappedModules["discord/modules/forums/web/Forums.css"]["newMemberBanner"];
352
+
export const gridViewBanner: MappedModules["discord/modules/forums/web/Forums.css"]["gridViewBanner"];
353
+
export const placeholder: MappedModules["discord/modules/forums/web/Forums.css"]["placeholder"];
354
+
export const mainCard: MappedModules["discord/modules/forums/web/Forums.css"]["mainCard"];
355
+
export const emptyMainCard: MappedModules["discord/modules/forums/web/Forums.css"]["emptyMainCard"];
356
+
export const outOfDate: MappedModules["discord/modules/forums/web/Forums.css"]["outOfDate"];
357
+
export const header: MappedModules["discord/modules/forums/web/Forums.css"]["header"];
358
+
export const matchingPostsRow: MappedModules["discord/modules/forums/web/Forums.css"]["matchingPostsRow"];
359
+
export const headerWithMatchingPosts: MappedModules["discord/modules/forums/web/Forums.css"]["headerWithMatchingPosts"];
360
+
export const noForm: MappedModules["discord/modules/forums/web/Forums.css"]["noForm"];
361
+
export const sortContainer: MappedModules["discord/modules/forums/web/Forums.css"]["sortContainer"];
362
+
export const sort: MappedModules["discord/modules/forums/web/Forums.css"]["sort"];
363
+
export const sortPopout: MappedModules["discord/modules/forums/web/Forums.css"]["sortPopout"];
364
+
export const archivedDividerRow: MappedModules["discord/modules/forums/web/Forums.css"]["archivedDividerRow"];
365
+
export const archivedDivider: MappedModules["discord/modules/forums/web/Forums.css"]["archivedDivider"];
366
+
export const newPostsButton: MappedModules["discord/modules/forums/web/Forums.css"]["newPostsButton"];
367
+
export const loadingCard: MappedModules["discord/modules/forums/web/Forums.css"]["loadingCard"];
368
+
export const enterIcon: MappedModules["discord/modules/forums/web/Forums.css"]["enterIcon"];
369
+
export const warnIcon: MappedModules["discord/modules/forums/web/Forums.css"]["warnIcon"];
370
+
export const searchIcon: MappedModules["discord/modules/forums/web/Forums.css"]["searchIcon"];
371
+
export const missingReadHistoryPermission: MappedModules["discord/modules/forums/web/Forums.css"]["missingReadHistoryPermission"];
372
+
export const divider: MappedModules["discord/modules/forums/web/Forums.css"]["divider"];
373
+
export const tagsContainer: MappedModules["discord/modules/forums/web/Forums.css"]["tagsContainer"];
374
+
export const filterIcon: MappedModules["discord/modules/forums/web/Forums.css"]["filterIcon"];
375
+
export const tagList: MappedModules["discord/modules/forums/web/Forums.css"]["tagList"];
376
+
export const tagListInner: MappedModules["discord/modules/forums/web/Forums.css"]["tagListInner"];
377
+
export const tag: MappedModules["discord/modules/forums/web/Forums.css"]["tag"];
378
+
export const tagsButton: MappedModules["discord/modules/forums/web/Forums.css"]["tagsButton"];
379
+
export const tagsButtonInner: MappedModules["discord/modules/forums/web/Forums.css"]["tagsButtonInner"];
380
+
export const tagsButtonPlaceholder: MappedModules["discord/modules/forums/web/Forums.css"]["tagsButtonPlaceholder"];
381
+
export const tagsButtonWithCount: MappedModules["discord/modules/forums/web/Forums.css"]["tagsButtonWithCount"];
382
+
export const sortDropdown: MappedModules["discord/modules/forums/web/Forums.css"]["sortDropdown"];
383
+
export const sortDropdownInner: MappedModules["discord/modules/forums/web/Forums.css"]["sortDropdownInner"];
384
+
export const sortDropdownText: MappedModules["discord/modules/forums/web/Forums.css"]["sortDropdownText"];
385
+
export const clear: MappedModules["discord/modules/forums/web/Forums.css"]["clear"];
386
+
export const matchingPosts: MappedModules["discord/modules/forums/web/Forums.css"]["matchingPosts"];
387
+
export const startPostHelp: MappedModules["discord/modules/forums/web/Forums.css"]["startPostHelp"];
388
+
export const tagsSpacer: MappedModules["discord/modules/forums/web/Forums.css"]["tagsSpacer"];
389
+
export const keyboardShortcut: MappedModules["discord/modules/forums/web/Forums.css"]["keyboardShortcut"];
390
+
export const key: MappedModules["discord/modules/forums/web/Forums.css"]["key"];
391
+
export const countContainer: MappedModules["discord/modules/forums/web/Forums.css"]["countContainer"];
392
+
export const countText: MappedModules["discord/modules/forums/web/Forums.css"]["countText"];
393
+
export const optInNotice: MappedModules["discord/modules/forums/web/Forums.css"]["optInNotice"];
394
+
}
395
+
396
+
declare module "@moonlight-mod/wp/discord/modules/forums/web/Header.css" {
397
+
import { MappedModules } from "@moonlight-mod/mappings";
398
+
export const container: MappedModules["discord/modules/forums/web/Header.css"]["container"];
399
+
export const header: MappedModules["discord/modules/forums/web/Header.css"]["header"];
400
+
export const headerLeft: MappedModules["discord/modules/forums/web/Header.css"]["headerLeft"];
401
+
export const headerText: MappedModules["discord/modules/forums/web/Header.css"]["headerText"];
402
+
export const countContainer: MappedModules["discord/modules/forums/web/Header.css"]["countContainer"];
403
+
export const countText: MappedModules["discord/modules/forums/web/Header.css"]["countText"];
404
+
export const tagContainer: MappedModules["discord/modules/forums/web/Header.css"]["tagContainer"];
405
+
export const tag: MappedModules["discord/modules/forums/web/Header.css"]["tag"];
406
+
export const clear: MappedModules["discord/modules/forums/web/Header.css"]["clear"];
407
+
export const row: MappedModules["discord/modules/forums/web/Header.css"]["row"];
408
+
export const separator: MappedModules["discord/modules/forums/web/Header.css"]["separator"];
409
+
}
410
+
411
+
declare module "@moonlight-mod/wp/discord/modules/forums/web/SortMenu.css" {
412
+
import { MappedModules } from "@moonlight-mod/mappings";
413
+
export const container: MappedModules["discord/modules/forums/web/SortMenu.css"]["container"];
414
+
export const clearText: MappedModules["discord/modules/forums/web/SortMenu.css"]["clearText"];
415
+
}
416
+
417
+
declare module "@moonlight-mod/wp/discord/modules/forums/web/Tag" {
418
+
import { MappedModules } from "@moonlight-mod/mappings";
419
+
const _default: MappedModules["discord/modules/forums/web/Tag"]["default"];
420
+
export default _default;
421
+
export const TagBar: MappedModules["discord/modules/forums/web/Tag"]["TagBar"];
422
+
}
423
+
424
+
declare module "@moonlight-mod/wp/discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css" {
425
+
import { MappedModules } from "@moonlight-mod/mappings";
426
+
export const addButton: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["addButton"];
427
+
export const container: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["container"];
428
+
export const emptyRowContainer: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["emptyRowContainer"];
429
+
export const emptyRowText: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["emptyRowText"];
430
+
export const headerContainer: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["headerContainer"];
431
+
export const list: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["list"];
432
+
export const memberDetails: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["memberDetails"];
433
+
export const memberRow: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["memberRow"];
434
+
export const removeButton: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["removeButton"];
435
+
export const removeButtonContainer: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["removeButtonContainer"];
436
+
export const removeButtonDisabled: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["removeButtonDisabled"];
437
+
export const removeTip: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["removeTip"];
438
+
export const searchContainer: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["searchContainer"];
439
+
export const searchWarning: MappedModules["discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"]["searchWarning"];
440
+
}
441
+
442
+
declare module "@moonlight-mod/wp/discord/modules/guild_settings/web/AppCard.css" {
443
+
import { MappedModules } from "@moonlight-mod/mappings";
444
+
export const card: MappedModules["discord/modules/guild_settings/web/AppCard.css"]["card"];
445
+
export const inModal: MappedModules["discord/modules/guild_settings/web/AppCard.css"]["inModal"];
446
+
export const cardHeader: MappedModules["discord/modules/guild_settings/web/AppCard.css"]["cardHeader"];
447
+
export const title: MappedModules["discord/modules/guild_settings/web/AppCard.css"]["title"];
448
+
}
449
+
450
+
declare module "@moonlight-mod/wp/discord/modules/guild_settings/web/AppCardItem.css" {
451
+
import { MappedModules } from "@moonlight-mod/mappings";
452
+
export const icon: MappedModules["discord/modules/guild_settings/web/AppCardItem.css"]["icon"];
453
+
export const identifier: MappedModules["discord/modules/guild_settings/web/AppCardItem.css"]["identifier"];
454
+
export const item: MappedModules["discord/modules/guild_settings/web/AppCardItem.css"]["item"];
455
+
export const statusContainer: MappedModules["discord/modules/guild_settings/web/AppCardItem.css"]["statusContainer"];
456
+
export const statusLine: MappedModules["discord/modules/guild_settings/web/AppCardItem.css"]["statusLine"];
457
+
export const statusIcon: MappedModules["discord/modules/guild_settings/web/AppCardItem.css"]["statusIcon"];
458
+
}
459
+
460
+
declare module "@moonlight-mod/wp/discord/modules/guild_settings/web/SearchSection.css" {
461
+
import { MappedModules } from "@moonlight-mod/mappings";
462
+
export const container: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["container"];
463
+
export const headerContainer: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["headerContainer"];
464
+
export const searchContainer: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["searchContainer"];
465
+
export const searchWarning: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["searchWarning"];
466
+
export const addButton: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["addButton"];
467
+
export const memberRow: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["memberRow"];
468
+
export const emptyRowContainer: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["emptyRowContainer"];
469
+
export const emptyRowText: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["emptyRowText"];
470
+
export const memberDetails: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["memberDetails"];
471
+
export const list: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["list"];
472
+
export const removeButtonContainer: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["removeButtonContainer"];
473
+
export const removeButton: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["removeButton"];
474
+
export const removeButtonDisabled: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["removeButtonDisabled"];
475
+
export const removeTip: MappedModules["discord/modules/guild_settings/web/SearchSection.css"]["removeTip"];
476
+
}
477
+
478
+
declare module "@moonlight-mod/wp/discord/modules/guild_sidebar/web/CategoryChannel.css" {
479
+
import { MappedModules } from "@moonlight-mod/mappings";
480
+
export const containerDefault: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["containerDefault"];
481
+
export const containerDragBefore: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["containerDragBefore"];
482
+
export const containerDragAfter: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["containerDragAfter"];
483
+
export const addButton: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["addButton"];
484
+
export const forceVisible: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["forceVisible"];
485
+
export const iconVisibility: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["iconVisibility"];
486
+
export const addButtonIcon: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["addButtonIcon"];
487
+
export const wrapper: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["wrapper"];
488
+
export const wrapperStatic: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["wrapperStatic"];
489
+
export const clickable: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["clickable"];
490
+
export const children: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["children"];
491
+
export const mainContent: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["mainContent"];
492
+
export const icon: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["icon"];
493
+
export const collapsed: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["collapsed"];
494
+
export const muted: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["muted"];
495
+
export const name: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["name"];
496
+
export const dismissWrapper: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["dismissWrapper"];
497
+
export const dismissButton: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["dismissButton"];
498
+
export const dismiss: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["dismiss"];
499
+
export const voiceChannelsButton: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["voiceChannelsButton"];
500
+
export const voiceChannelsToggleIcon: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["voiceChannelsToggleIcon"];
501
+
export const refreshVoiceChannelsButton: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["refreshVoiceChannelsButton"];
502
+
export const refreshVoiceChannelsButtonInner: MappedModules["discord/modules/guild_sidebar/web/CategoryChannel.css"]["refreshVoiceChannelsButtonInner"];
18
503
}
19
504
20
505
declare module "@moonlight-mod/wp/discord/modules/markup/MarkupUtils" {
21
506
import { MappedModules } from "@moonlight-mod/mappings";
22
-
const _: MappedModules["discord/modules/markup/MarkupUtils"];
23
-
export = _;
507
+
const _default: MappedModules["discord/modules/markup/MarkupUtils"]["default"];
508
+
export default _default;
509
+
}
510
+
511
+
declare module "@moonlight-mod/wp/discord/modules/menus/web/Menu" {
512
+
import { MappedModules } from "@moonlight-mod/mappings";
513
+
export const MenuSpinner: MappedModules["discord/modules/menus/web/Menu"]["MenuSpinner"];
514
+
export const Menu: MappedModules["discord/modules/menus/web/Menu"]["Menu"];
515
+
}
516
+
517
+
declare module "@moonlight-mod/wp/discord/modules/messages/web/Markup.css" {
518
+
import { MappedModules } from "@moonlight-mod/mappings";
519
+
export const markup: MappedModules["discord/modules/messages/web/Markup.css"]["markup"];
520
+
export const inlineFormat: MappedModules["discord/modules/messages/web/Markup.css"]["inlineFormat"];
521
+
export const codeContainer: MappedModules["discord/modules/messages/web/Markup.css"]["codeContainer"];
522
+
export const codeActions: MappedModules["discord/modules/messages/web/Markup.css"]["codeActions"];
523
+
export const blockquoteContainer: MappedModules["discord/modules/messages/web/Markup.css"]["blockquoteContainer"];
524
+
export const blockquoteDivider: MappedModules["discord/modules/messages/web/Markup.css"]["blockquoteDivider"];
525
+
export const slateBlockquoteContainer: MappedModules["discord/modules/messages/web/Markup.css"]["slateBlockquoteContainer"];
526
+
export const roleMention: MappedModules["discord/modules/messages/web/Markup.css"]["roleMention"];
527
+
export const rolePopout: MappedModules["discord/modules/messages/web/Markup.css"]["rolePopout"];
528
+
export const roleHeader: MappedModules["discord/modules/messages/web/Markup.css"]["roleHeader"];
529
+
export const roleScroller: MappedModules["discord/modules/messages/web/Markup.css"]["roleScroller"];
530
+
export const timestamp: MappedModules["discord/modules/messages/web/Markup.css"]["timestamp"];
531
+
export const timestampTooltip: MappedModules["discord/modules/messages/web/Markup.css"]["timestampTooltip"];
532
+
}
533
+
534
+
declare module "@moonlight-mod/wp/discord/modules/messages/web/Message.css" {
535
+
import { MappedModules } from "@moonlight-mod/mappings";
536
+
export const wrapper: MappedModules["discord/modules/messages/web/Message.css"]["wrapper"];
537
+
export const compact: MappedModules["discord/modules/messages/web/Message.css"]["compact"];
538
+
export const cozy: MappedModules["discord/modules/messages/web/Message.css"]["cozy"];
539
+
export const contentOnly: MappedModules["discord/modules/messages/web/Message.css"]["contentOnly"];
540
+
export const repliedMessage: MappedModules["discord/modules/messages/web/Message.css"]["repliedMessage"];
541
+
export const threadMessageAccessory: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessory"];
542
+
export const executedCommand: MappedModules["discord/modules/messages/web/Message.css"]["executedCommand"];
543
+
export const latin12CompactTimeStamp: MappedModules["discord/modules/messages/web/Message.css"]["latin12CompactTimeStamp"];
544
+
export const latin24CompactTimeStamp: MappedModules["discord/modules/messages/web/Message.css"]["latin24CompactTimeStamp"];
545
+
export const asianCompactTimeStamp: MappedModules["discord/modules/messages/web/Message.css"]["asianCompactTimeStamp"];
546
+
export const contextCommandMessage: MappedModules["discord/modules/messages/web/Message.css"]["contextCommandMessage"];
547
+
export const messageSpine: MappedModules["discord/modules/messages/web/Message.css"]["messageSpine"];
548
+
export const repliedMessageClickableSpine: MappedModules["discord/modules/messages/web/Message.css"]["repliedMessageClickableSpine"];
549
+
export const repliedMessageContentHovered: MappedModules["discord/modules/messages/web/Message.css"]["repliedMessageContentHovered"];
550
+
export const threadMessageAccessoryAvatar: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessoryAvatar"];
551
+
export const replyAvatar: MappedModules["discord/modules/messages/web/Message.css"]["replyAvatar"];
552
+
export const replyBadge: MappedModules["discord/modules/messages/web/Message.css"]["replyBadge"];
553
+
export const executedCommandAvatar: MappedModules["discord/modules/messages/web/Message.css"]["executedCommandAvatar"];
554
+
export const replyChatIconContainer: MappedModules["discord/modules/messages/web/Message.css"]["replyChatIconContainer"];
555
+
export const replyIcon: MappedModules["discord/modules/messages/web/Message.css"]["replyIcon"];
556
+
export const clanTagChiplet: MappedModules["discord/modules/messages/web/Message.css"]["clanTagChiplet"];
557
+
export const userJoinSystemMessageIcon: MappedModules["discord/modules/messages/web/Message.css"]["userJoinSystemMessageIcon"];
558
+
export const ticketIcon: MappedModules["discord/modules/messages/web/Message.css"]["ticketIcon"];
559
+
export const commandIcon: MappedModules["discord/modules/messages/web/Message.css"]["commandIcon"];
560
+
export const username: MappedModules["discord/modules/messages/web/Message.css"]["username"];
561
+
export const roleDot: MappedModules["discord/modules/messages/web/Message.css"]["roleDot"];
562
+
export const commandName: MappedModules["discord/modules/messages/web/Message.css"]["commandName"];
563
+
export const appsIcon: MappedModules["discord/modules/messages/web/Message.css"]["appsIcon"];
564
+
export const appLauncherOnboardingCommandName: MappedModules["discord/modules/messages/web/Message.css"]["appLauncherOnboardingCommandName"];
565
+
export const targetUsername: MappedModules["discord/modules/messages/web/Message.css"]["targetUsername"];
566
+
export const executedCommandSeparator: MappedModules["discord/modules/messages/web/Message.css"]["executedCommandSeparator"];
567
+
export const repliedTextPreview: MappedModules["discord/modules/messages/web/Message.css"]["repliedTextPreview"];
568
+
export const threadMessageAccessoryPreview: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessoryPreview"];
569
+
export const repliedTextContent: MappedModules["discord/modules/messages/web/Message.css"]["repliedTextContent"];
570
+
export const clickable: MappedModules["discord/modules/messages/web/Message.css"]["clickable"];
571
+
export const repliedMessageClickableSpineHovered: MappedModules["discord/modules/messages/web/Message.css"]["repliedMessageClickableSpineHovered"];
572
+
export const threadMessageAccessoryContent: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessoryContent"];
573
+
export const repliedTextPlaceholder: MappedModules["discord/modules/messages/web/Message.css"]["repliedTextPlaceholder"];
574
+
export const threadMessageAccessoryPlaceholder: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessoryPlaceholder"];
575
+
export const repliedTextContentTrailingIcon: MappedModules["discord/modules/messages/web/Message.css"]["repliedTextContentTrailingIcon"];
576
+
export const threadMessageAccessoryContentTrailingIcon: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessoryContentTrailingIcon"];
577
+
export const repliedTextContentLeadingIcon: MappedModules["discord/modules/messages/web/Message.css"]["repliedTextContentLeadingIcon"];
578
+
export const threadMessageAccessoryContentLeadingIcon: MappedModules["discord/modules/messages/web/Message.css"]["threadMessageAccessoryContentLeadingIcon"];
579
+
export const contents: MappedModules["discord/modules/messages/web/Message.css"]["contents"];
580
+
export const zalgo: MappedModules["discord/modules/messages/web/Message.css"]["zalgo"];
581
+
export const messageContent: MappedModules["discord/modules/messages/web/Message.css"]["messageContent"];
582
+
export const header: MappedModules["discord/modules/messages/web/Message.css"]["header"];
583
+
export const buttonContainer: MappedModules["discord/modules/messages/web/Message.css"]["buttonContainer"];
584
+
export const avatar: MappedModules["discord/modules/messages/web/Message.css"]["avatar"];
585
+
export const avatarDecoration: MappedModules["discord/modules/messages/web/Message.css"]["avatarDecoration"];
586
+
export const roleIcon: MappedModules["discord/modules/messages/web/Message.css"]["roleIcon"];
587
+
export const timestamp: MappedModules["discord/modules/messages/web/Message.css"]["timestamp"];
588
+
export const timestampInline: MappedModules["discord/modules/messages/web/Message.css"]["timestampInline"];
589
+
export const alt: MappedModules["discord/modules/messages/web/Message.css"]["alt"];
590
+
export const timestampTooltip: MappedModules["discord/modules/messages/web/Message.css"]["timestampTooltip"];
591
+
export const timestampVisibleOnHover: MappedModules["discord/modules/messages/web/Message.css"]["timestampVisibleOnHover"];
592
+
export const nitroAuthorBadgeTootip: MappedModules["discord/modules/messages/web/Message.css"]["nitroAuthorBadgeTootip"];
593
+
export const headerText: MappedModules["discord/modules/messages/web/Message.css"]["headerText"];
594
+
export const hasRoleIcon: MappedModules["discord/modules/messages/web/Message.css"]["hasRoleIcon"];
595
+
export const hasBadges: MappedModules["discord/modules/messages/web/Message.css"]["hasBadges"];
596
+
export const botTagCompact: MappedModules["discord/modules/messages/web/Message.css"]["botTagCompact"];
597
+
export const botTagCozy: MappedModules["discord/modules/messages/web/Message.css"]["botTagCozy"];
598
+
export const nitroBadgeSvg: MappedModules["discord/modules/messages/web/Message.css"]["nitroBadgeSvg"];
599
+
export const nitroAuthorBadgeContainer: MappedModules["discord/modules/messages/web/Message.css"]["nitroAuthorBadgeContainer"];
600
+
export const separator: MappedModules["discord/modules/messages/web/Message.css"]["separator"];
601
+
export const hasThread: MappedModules["discord/modules/messages/web/Message.css"]["hasThread"];
602
+
export const isSystemMessage: MappedModules["discord/modules/messages/web/Message.css"]["isSystemMessage"];
603
+
export const hasReply: MappedModules["discord/modules/messages/web/Message.css"]["hasReply"];
604
+
export const markupRtl: MappedModules["discord/modules/messages/web/Message.css"]["markupRtl"];
605
+
export const isSending: MappedModules["discord/modules/messages/web/Message.css"]["isSending"];
606
+
export const isFailed: MappedModules["discord/modules/messages/web/Message.css"]["isFailed"];
607
+
export const isUnsupported: MappedModules["discord/modules/messages/web/Message.css"]["isUnsupported"];
608
+
export const edited: MappedModules["discord/modules/messages/web/Message.css"]["edited"];
609
+
export const communicationDisabled: MappedModules["discord/modules/messages/web/Message.css"]["communicationDisabled"];
610
+
export const compactCommunicationDisabled: MappedModules["discord/modules/messages/web/Message.css"]["compactCommunicationDisabled"];
611
+
export const communicationDisabledOpacity: MappedModules["discord/modules/messages/web/Message.css"]["communicationDisabledOpacity"];
612
+
export const badgesContainer: MappedModules["discord/modules/messages/web/Message.css"]["badgesContainer"];
613
+
}
614
+
615
+
declare module "@moonlight-mod/wp/discord/modules/modals/Modals" {
616
+
import { MappedModules } from "@moonlight-mod/mappings";
617
+
export const closeAllModals: MappedModules["discord/modules/modals/Modals"]["closeAllModals"];
618
+
export const closeAllModalsForContext: MappedModules["discord/modules/modals/Modals"]["closeAllModalsForContext"];
619
+
export const closeModal: MappedModules["discord/modules/modals/Modals"]["closeModal"];
620
+
export const getInteractingModalContext: MappedModules["discord/modules/modals/Modals"]["getInteractingModalContext"];
621
+
export const hasAnyModalOpen: MappedModules["discord/modules/modals/Modals"]["hasAnyModalOpen"];
622
+
export const hasAnyModalOpenSelector: MappedModules["discord/modules/modals/Modals"]["hasAnyModalOpenSelector"];
623
+
export const hasModalOpen: MappedModules["discord/modules/modals/Modals"]["hasModalOpen"];
624
+
export const hasModalOpenSelector: MappedModules["discord/modules/modals/Modals"]["hasModalOpenSelector"];
625
+
export const openModal: MappedModules["discord/modules/modals/Modals"]["openModal"];
626
+
export const openModalLazy: MappedModules["discord/modules/modals/Modals"]["openModalLazy"];
627
+
export const updateModal: MappedModules["discord/modules/modals/Modals"]["updateModal"];
628
+
export const useHasAnyModalOpen: MappedModules["discord/modules/modals/Modals"]["useHasAnyModalOpen"];
629
+
export const useIsModalAtTop: MappedModules["discord/modules/modals/Modals"]["useIsModalAtTop"];
630
+
export const useModalsStore: MappedModules["discord/modules/modals/Modals"]["useModalsStore"];
631
+
}
632
+
633
+
declare module "@moonlight-mod/wp/discord/modules/oauth2/index" {
634
+
import { MappedModules } from "@moonlight-mod/mappings";
635
+
export const OAuth2AuthorizeModal: MappedModules["discord/modules/oauth2/index"]["OAuth2AuthorizeModal"];
636
+
export const OAuth2AuthorizePage: MappedModules["discord/modules/oauth2/index"]["OAuth2AuthorizePage"];
637
+
export const getOAuth2AuthorizeProps: MappedModules["discord/modules/oauth2/index"]["getOAuth2AuthorizeProps"];
638
+
export const openOAuth2Modal: MappedModules["discord/modules/oauth2/index"]["openOAuth2Modal"];
639
+
export const openOAuth2ModalWithCreateGuildModal: MappedModules["discord/modules/oauth2/index"]["openOAuth2ModalWithCreateGuildModal"];
640
+
export const useOAuth2AuthorizeForm: MappedModules["discord/modules/oauth2/index"]["useOAuth2AuthorizeForm"];
641
+
}
642
+
643
+
declare module "@moonlight-mod/wp/discord/modules/people/web/PeoplePage.css" {
644
+
import { MappedModules } from "@moonlight-mod/mappings";
645
+
export const addFriend: MappedModules["discord/modules/people/web/PeoplePage.css"]["addFriend"];
646
+
export const badge: MappedModules["discord/modules/people/web/PeoplePage.css"]["badge"];
647
+
export const container: MappedModules["discord/modules/people/web/PeoplePage.css"]["container"];
648
+
export const inviteToolbar: MappedModules["discord/modules/people/web/PeoplePage.css"]["inviteToolbar"];
649
+
export const item: MappedModules["discord/modules/people/web/PeoplePage.css"]["item"];
650
+
export const nowPlayingColumn: MappedModules["discord/modules/people/web/PeoplePage.css"]["nowPlayingColumn"];
651
+
export const peopleColumn: MappedModules["discord/modules/people/web/PeoplePage.css"]["peopleColumn"];
652
+
export const tabBar: MappedModules["discord/modules/people/web/PeoplePage.css"]["tabBar"];
653
+
export const tabBody: MappedModules["discord/modules/people/web/PeoplePage.css"]["tabBody"];
654
+
}
655
+
656
+
declare module "@moonlight-mod/wp/discord/modules/user_profile/web/BiteSizeActivity.css" {
657
+
import { MappedModules } from "@moonlight-mod/mappings";
658
+
export const header: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["header"];
659
+
export const headerTag: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["headerTag"];
660
+
export const body: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["body"];
661
+
export const footer: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["footer"];
662
+
export const backdrop: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["backdrop"];
663
+
export const toast: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["toast"];
664
+
export const activity: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["activity"];
665
+
export const upsell: MappedModules["discord/modules/user_profile/web/BiteSizeActivity.css"]["upsell"];
24
666
}
25
667
26
668
declare module "@moonlight-mod/wp/discord/packages/flux" {
27
669
import { MappedModules } from "@moonlight-mod/mappings";
28
-
const _: MappedModules["discord/packages/flux"];
29
-
export = _;
670
+
export const BatchedStoreListener: MappedModules["discord/packages/flux"]["BatchedStoreListener"];
671
+
export const Dispatcher: MappedModules["discord/packages/flux"]["Dispatcher"];
672
+
export const Store: MappedModules["discord/packages/flux"]["Store"];
673
+
const _default: MappedModules["discord/packages/flux"]["default"];
674
+
export default _default;
675
+
export const statesWillNeverBeEqual: MappedModules["discord/packages/flux"]["statesWillNeverBeEqual"];
676
+
export const useStateFromStores: MappedModules["discord/packages/flux"]["useStateFromStores"];
677
+
export const useStateFromStoresArray: MappedModules["discord/packages/flux"]["useStateFromStoresArray"];
678
+
export const useStateFromStoresObject: MappedModules["discord/packages/flux"]["useStateFromStoresObject"];
679
+
}
680
+
681
+
declare module "@moonlight-mod/wp/discord/packages/flux/BatchedStoreListener" {
682
+
import { MappedModules } from "@moonlight-mod/mappings";
683
+
const _default: MappedModules["discord/packages/flux/BatchedStoreListener"]["default"];
684
+
export default _default;
685
+
}
686
+
687
+
declare module "@moonlight-mod/wp/discord/packages/flux/ChangeListeners" {
688
+
import { MappedModules } from "@moonlight-mod/mappings";
689
+
const _default: MappedModules["discord/packages/flux/ChangeListeners"]["default"];
690
+
export default _default;
691
+
}
692
+
693
+
declare module "@moonlight-mod/wp/discord/packages/flux/Dispatcher" {
694
+
import { MappedModules } from "@moonlight-mod/mappings";
695
+
export const Dispatcher: MappedModules["discord/packages/flux/Dispatcher"]["Dispatcher"];
696
+
}
697
+
698
+
declare module "@moonlight-mod/wp/discord/packages/flux/Emitter" {
699
+
import { MappedModules } from "@moonlight-mod/mappings";
700
+
const _default: MappedModules["discord/packages/flux/Emitter"]["default"];
701
+
export default _default;
702
+
}
703
+
704
+
declare module "@moonlight-mod/wp/discord/packages/flux/LoggingUtils" {
705
+
import { MappedModules } from "@moonlight-mod/mappings";
706
+
const _default: MappedModules["discord/packages/flux/LoggingUtils"]["default"];
707
+
export default _default;
708
+
}
709
+
710
+
declare module "@moonlight-mod/wp/discord/packages/flux/PersistedStore" {
711
+
import { MappedModules } from "@moonlight-mod/mappings";
712
+
export const PersistedStore: MappedModules["discord/packages/flux/PersistedStore"]["PersistedStore"];
713
+
}
714
+
715
+
declare module "@moonlight-mod/wp/discord/packages/flux/Store" {
716
+
import { MappedModules } from "@moonlight-mod/mappings";
717
+
export const Store: MappedModules["discord/packages/flux/Store"]["Store"];
718
+
}
719
+
720
+
declare module "@moonlight-mod/wp/discord/packages/flux/connectStores" {
721
+
import { MappedModules } from "@moonlight-mod/mappings";
722
+
const _default: MappedModules["discord/packages/flux/connectStores"]["default"];
723
+
export default _default;
724
+
}
725
+
726
+
declare module "@moonlight-mod/wp/discord/records/UserRecord" {
727
+
import { MappedModules } from "@moonlight-mod/mappings";
728
+
const _default: MappedModules["discord/records/UserRecord"]["default"];
729
+
export default _default;
730
+
}
731
+
732
+
declare module "@moonlight-mod/wp/discord/styles/shared/Margins.css" {
733
+
import { MappedModules } from "@moonlight-mod/mappings";
734
+
export const marginReset: MappedModules["discord/styles/shared/Margins.css"]["marginReset"];
735
+
export const marginTop4: MappedModules["discord/styles/shared/Margins.css"]["marginTop4"];
736
+
export const marginBottom4: MappedModules["discord/styles/shared/Margins.css"]["marginBottom4"];
737
+
export const marginTop8: MappedModules["discord/styles/shared/Margins.css"]["marginTop8"];
738
+
export const marginBottom8: MappedModules["discord/styles/shared/Margins.css"]["marginBottom8"];
739
+
export const marginTop20: MappedModules["discord/styles/shared/Margins.css"]["marginTop20"];
740
+
export const marginBottom20: MappedModules["discord/styles/shared/Margins.css"]["marginBottom20"];
741
+
export const marginTop40: MappedModules["discord/styles/shared/Margins.css"]["marginTop40"];
742
+
export const marginBottom40: MappedModules["discord/styles/shared/Margins.css"]["marginBottom40"];
743
+
export const marginTop60: MappedModules["discord/styles/shared/Margins.css"]["marginTop60"];
744
+
export const marginBottom60: MappedModules["discord/styles/shared/Margins.css"]["marginBottom60"];
745
+
export const marginCenterHorz: MappedModules["discord/styles/shared/Margins.css"]["marginCenterHorz"];
746
+
export const marginLeft8: MappedModules["discord/styles/shared/Margins.css"]["marginLeft8"];
30
747
}
31
748
32
749
declare module "@moonlight-mod/wp/discord/uikit/Flex" {
33
750
import { MappedModules } from "@moonlight-mod/mappings";
34
-
const _: MappedModules["discord/uikit/Flex"];
35
-
export = _;
751
+
const _default: MappedModules["discord/uikit/Flex"]["default"];
752
+
export default _default;
753
+
}
754
+
755
+
declare module "@moonlight-mod/wp/discord/utils/ClipboardUtils" {
756
+
import { MappedModules } from "@moonlight-mod/mappings";
757
+
export const SUPPORTS_COPY: MappedModules["discord/utils/ClipboardUtils"]["SUPPORTS_COPY"];
758
+
export const copy: MappedModules["discord/utils/ClipboardUtils"]["copy"];
759
+
}
760
+
761
+
declare module "@moonlight-mod/wp/discord/utils/ComponentDispatchUtils" {
762
+
import { MappedModules } from "@moonlight-mod/mappings";
763
+
export const ComponentDispatcher: MappedModules["discord/utils/ComponentDispatchUtils"]["ComponentDispatcher"];
764
+
export const ComponentDispatch: MappedModules["discord/utils/ComponentDispatchUtils"]["ComponentDispatch"];
765
+
}
766
+
767
+
declare module "@moonlight-mod/wp/discord/utils/HTTPUtils" {
768
+
import { MappedModules } from "@moonlight-mod/mappings";
769
+
export const HTTP: MappedModules["discord/utils/HTTPUtils"]["HTTP"];
770
+
}
771
+
772
+
declare module "@moonlight-mod/wp/discord/utils/MaskedLinkUtils" {
773
+
import { MappedModules } from "@moonlight-mod/mappings";
774
+
export const isLinkTrusted: MappedModules["discord/utils/MaskedLinkUtils"]["isLinkTrusted"];
775
+
export const handleClick: MappedModules["discord/utils/MaskedLinkUtils"]["handleClick"];
776
+
}
777
+
778
+
declare module "@moonlight-mod/wp/discord/utils/NativeUtils" {
779
+
import { MappedModules } from "@moonlight-mod/mappings";
780
+
const _default: MappedModules["discord/utils/NativeUtils"]["default"];
781
+
export default _default;
782
+
}
783
+
784
+
declare module "@moonlight-mod/wp/highlight.js" {
785
+
import { MappedModules } from "@moonlight-mod/mappings";
786
+
export const highlight: MappedModules["highlight.js"]["highlight"];
787
+
export const highlightAuto: MappedModules["highlight.js"]["highlightAuto"];
788
+
export const fixMarkup: MappedModules["highlight.js"]["fixMarkup"];
789
+
export const highlightBlock: MappedModules["highlight.js"]["highlightBlock"];
790
+
export const configure: MappedModules["highlight.js"]["configure"];
791
+
export const initHighlighting: MappedModules["highlight.js"]["initHighlighting"];
792
+
export const initHighlightingOnLoad: MappedModules["highlight.js"]["initHighlightingOnLoad"];
793
+
export const registerLanguage: MappedModules["highlight.js"]["registerLanguage"];
794
+
export const listLanguages: MappedModules["highlight.js"]["listLanguages"];
795
+
export const getLanguage: MappedModules["highlight.js"]["getLanguage"];
796
+
export const inherit: MappedModules["highlight.js"]["inherit"];
797
+
export const COMMENT: MappedModules["highlight.js"]["COMMENT"];
798
+
export const IDENT_RE: MappedModules["highlight.js"]["IDENT_RE"];
799
+
export const UNDERSCORE_IDENT_RE: MappedModules["highlight.js"]["UNDERSCORE_IDENT_RE"];
800
+
export const NUMBER_RE: MappedModules["highlight.js"]["NUMBER_RE"];
801
+
export const C_NUMBER_RE: MappedModules["highlight.js"]["C_NUMBER_RE"];
802
+
export const BINARY_NUMBER_RE: MappedModules["highlight.js"]["BINARY_NUMBER_RE"];
803
+
export const RE_STARTERS_RE: MappedModules["highlight.js"]["RE_STARTERS_RE"];
804
+
export const BACKSLASH_ESCAPE: MappedModules["highlight.js"]["BACKSLASH_ESCAPE"];
805
+
export const APOS_STRING_MODE: MappedModules["highlight.js"]["APOS_STRING_MODE"];
806
+
export const QUOTE_STRING_MODE: MappedModules["highlight.js"]["QUOTE_STRING_MODE"];
807
+
export const PHRASAL_WORDS_MODE: MappedModules["highlight.js"]["PHRASAL_WORDS_MODE"];
808
+
export const C_LINE_COMMENT_MODE: MappedModules["highlight.js"]["C_LINE_COMMENT_MODE"];
809
+
export const C_BLOCK_COMMENT_MODE: MappedModules["highlight.js"]["C_BLOCK_COMMENT_MODE"];
810
+
export const HASH_COMMENT_MODE: MappedModules["highlight.js"]["HASH_COMMENT_MODE"];
811
+
export const NUMBER_MODE: MappedModules["highlight.js"]["NUMBER_MODE"];
812
+
export const C_NUMBER_MODE: MappedModules["highlight.js"]["C_NUMBER_MODE"];
813
+
export const BINARY_NUMBER_MODE: MappedModules["highlight.js"]["BINARY_NUMBER_MODE"];
814
+
export const CSS_NUMBER_MODE: MappedModules["highlight.js"]["CSS_NUMBER_MODE"];
815
+
export const REGEX_MODE: MappedModules["highlight.js"]["REGEX_MODE"];
816
+
export const TITLE_MODE: MappedModules["highlight.js"]["TITLE_MODE"];
817
+
export const UNDERSCORE_TITLE_MODE: MappedModules["highlight.js"]["UNDERSCORE_TITLE_MODE"];
818
+
const _default: MappedModules["highlight.js"]["default"];
819
+
export default _default;
820
+
export const HighlightJS: MappedModules["highlight.js"]["HighlightJS"];
821
+
}
822
+
823
+
declare module "@moonlight-mod/wp/highlight.js/lib/core" {
824
+
import { MappedModules } from "@moonlight-mod/mappings";
825
+
export const highlight: MappedModules["highlight.js/lib/core"]["highlight"];
826
+
export const highlightAuto: MappedModules["highlight.js/lib/core"]["highlightAuto"];
827
+
export const fixMarkup: MappedModules["highlight.js/lib/core"]["fixMarkup"];
828
+
export const highlightBlock: MappedModules["highlight.js/lib/core"]["highlightBlock"];
829
+
export const configure: MappedModules["highlight.js/lib/core"]["configure"];
830
+
export const initHighlighting: MappedModules["highlight.js/lib/core"]["initHighlighting"];
831
+
export const initHighlightingOnLoad: MappedModules["highlight.js/lib/core"]["initHighlightingOnLoad"];
832
+
export const registerLanguage: MappedModules["highlight.js/lib/core"]["registerLanguage"];
833
+
export const listLanguages: MappedModules["highlight.js/lib/core"]["listLanguages"];
834
+
export const getLanguage: MappedModules["highlight.js/lib/core"]["getLanguage"];
835
+
export const inherit: MappedModules["highlight.js/lib/core"]["inherit"];
836
+
export const COMMENT: MappedModules["highlight.js/lib/core"]["COMMENT"];
837
+
export const IDENT_RE: MappedModules["highlight.js/lib/core"]["IDENT_RE"];
838
+
export const UNDERSCORE_IDENT_RE: MappedModules["highlight.js/lib/core"]["UNDERSCORE_IDENT_RE"];
839
+
export const NUMBER_RE: MappedModules["highlight.js/lib/core"]["NUMBER_RE"];
840
+
export const C_NUMBER_RE: MappedModules["highlight.js/lib/core"]["C_NUMBER_RE"];
841
+
export const BINARY_NUMBER_RE: MappedModules["highlight.js/lib/core"]["BINARY_NUMBER_RE"];
842
+
export const RE_STARTERS_RE: MappedModules["highlight.js/lib/core"]["RE_STARTERS_RE"];
843
+
export const BACKSLASH_ESCAPE: MappedModules["highlight.js/lib/core"]["BACKSLASH_ESCAPE"];
844
+
export const APOS_STRING_MODE: MappedModules["highlight.js/lib/core"]["APOS_STRING_MODE"];
845
+
export const QUOTE_STRING_MODE: MappedModules["highlight.js/lib/core"]["QUOTE_STRING_MODE"];
846
+
export const PHRASAL_WORDS_MODE: MappedModules["highlight.js/lib/core"]["PHRASAL_WORDS_MODE"];
847
+
export const C_LINE_COMMENT_MODE: MappedModules["highlight.js/lib/core"]["C_LINE_COMMENT_MODE"];
848
+
export const C_BLOCK_COMMENT_MODE: MappedModules["highlight.js/lib/core"]["C_BLOCK_COMMENT_MODE"];
849
+
export const HASH_COMMENT_MODE: MappedModules["highlight.js/lib/core"]["HASH_COMMENT_MODE"];
850
+
export const NUMBER_MODE: MappedModules["highlight.js/lib/core"]["NUMBER_MODE"];
851
+
export const C_NUMBER_MODE: MappedModules["highlight.js/lib/core"]["C_NUMBER_MODE"];
852
+
export const BINARY_NUMBER_MODE: MappedModules["highlight.js/lib/core"]["BINARY_NUMBER_MODE"];
853
+
export const CSS_NUMBER_MODE: MappedModules["highlight.js/lib/core"]["CSS_NUMBER_MODE"];
854
+
export const REGEX_MODE: MappedModules["highlight.js/lib/core"]["REGEX_MODE"];
855
+
export const TITLE_MODE: MappedModules["highlight.js/lib/core"]["TITLE_MODE"];
856
+
export const UNDERSCORE_TITLE_MODE: MappedModules["highlight.js/lib/core"]["UNDERSCORE_TITLE_MODE"];
857
+
}
858
+
859
+
declare module "@moonlight-mod/wp/lodash" {}
860
+
861
+
declare module "@moonlight-mod/wp/murmurhash" {
862
+
import { MappedModules } from "@moonlight-mod/mappings";
863
+
export const v2: MappedModules["murmurhash"]["v2"];
864
+
export const v3: MappedModules["murmurhash"]["v3"];
865
+
}
866
+
867
+
declare module "@moonlight-mod/wp/platform.js" {
868
+
import { MappedModules } from "@moonlight-mod/mappings";
869
+
export const description: MappedModules["platform.js"]["description"];
870
+
export const layout: MappedModules["platform.js"]["layout"];
871
+
export const manufacturer: MappedModules["platform.js"]["manufacturer"];
872
+
export const name: MappedModules["platform.js"]["name"];
873
+
export const prerelease: MappedModules["platform.js"]["prerelease"];
874
+
export const product: MappedModules["platform.js"]["product"];
875
+
export const ua: MappedModules["platform.js"]["ua"];
876
+
export const version: MappedModules["platform.js"]["version"];
877
+
export const os: MappedModules["platform.js"]["os"];
878
+
export const parse: MappedModules["platform.js"]["parse"];
879
+
export const toString: MappedModules["platform.js"]["toString"];
36
880
}
37
881
38
882
declare module "@moonlight-mod/wp/react" {
39
883
import { MappedModules } from "@moonlight-mod/mappings";
40
-
const _: MappedModules["react"];
884
+
const _: Omit<MappedModules["react"], "__mappings_exportEquals">;
41
885
export = _;
42
886
}
887
+
888
+
declare module "@moonlight-mod/wp/uuid/v4" {}
+7
-7
packages/types/tsconfig.json
+7
-7
packages/types/tsconfig.json
···
1
1
{
2
2
"compilerOptions": {
3
-
"target": "es2016",
4
-
"module": "es6",
5
-
"esModuleInterop": true,
6
-
"forceConsistentCasingInFileNames": true,
7
-
"strict": true,
8
-
"moduleResolution": "bundler",
3
+
"target": "ES2016",
9
4
"jsx": "react",
10
-
"declaration": true
5
+
"module": "ES6",
6
+
"moduleResolution": "bundler",
7
+
"strict": true,
8
+
"declaration": true,
9
+
"esModuleInterop": true,
10
+
"forceConsistentCasingInFileNames": true
11
11
},
12
12
"include": ["./src/**/*", "src/index.ts", "./src/import.d.ts"]
13
13
}
+10
-3
packages/web-preload/package.json
+10
-3
packages/web-preload/package.json
···
2
2
"name": "@moonlight-mod/web-preload",
3
3
"private": true,
4
4
"main": "src/index.ts",
5
+
"engineStrict": true,
6
+
"engines": {
7
+
"node": ">=22",
8
+
"pnpm": ">=10",
9
+
"npm": "pnpm",
10
+
"yarn": "pnpm"
11
+
},
5
12
"dependencies": {
6
13
"@moonlight-mod/core": "workspace:*",
7
-
"@moonlight-mod/lunast": "^1.0.0",
8
-
"@moonlight-mod/mappings": "^1.0.2",
9
-
"@moonlight-mod/moonmap": "^1.0.2",
14
+
"@moonlight-mod/lunast": "catalog:prod",
15
+
"@moonlight-mod/mappings": "catalog:prod",
16
+
"@moonlight-mod/moonmap": "catalog:prod",
10
17
"@moonlight-mod/types": "workspace:*"
11
18
}
12
19
}
+16
-19
packages/web-preload/src/index.ts
+16
-19
packages/web-preload/src/index.ts
···
1
1
import { loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
2
-
import {
3
-
installWebpackPatcher,
4
-
onModuleLoad,
5
-
registerPatch,
6
-
registerWebpackModule
7
-
} from "@moonlight-mod/core/patch";
2
+
import { installWebpackPatcher, onModuleLoad, registerPatch, registerWebpackModule } from "@moonlight-mod/core/patch";
8
3
import { constants, MoonlightBranch } from "@moonlight-mod/types";
9
4
import { installStyles } from "@moonlight-mod/core/styles";
10
5
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
···
12
7
import Moonmap from "@moonlight-mod/moonmap";
13
8
import loadMappings from "@moonlight-mod/mappings";
14
9
import { createEventEmitter } from "@moonlight-mod/core/util/event";
15
-
import { EventPayloads, EventType } from "@moonlight-mod/types/core/event";
10
+
import { WebEventPayloads, WebEventType } from "@moonlight-mod/types/core/event";
16
11
17
12
async function load() {
13
+
delete window._moonlightWebLoad;
18
14
initLogger(moonlightNode.config);
19
15
const logger = new Logger("web-preload");
20
16
21
17
window.moonlight = {
22
-
apiLevel: constants.apiLevel,
18
+
patched: new Map(),
23
19
unpatched: new Set(),
24
20
pendingModules: new Set(),
25
21
enabledExtensions: new Set(),
26
-
events: createEventEmitter<EventType, EventPayloads>(),
22
+
23
+
events: createEventEmitter<WebEventType, WebEventPayloads>(),
27
24
patchingInternals: {
28
25
onModuleLoad,
29
26
registerPatch,
30
27
registerWebpackModule
31
28
},
29
+
localStorage: window.localStorage,
32
30
33
31
version: MOONLIGHT_VERSION,
34
32
branch: MOONLIGHT_BRANCH as MoonlightBranch,
33
+
apiLevel: constants.apiLevel,
35
34
36
35
getConfig: moonlightNode.getConfig.bind(moonlightNode),
37
36
getConfigOption: moonlightNode.getConfigOption.bind(moonlightNode),
37
+
setConfigOption: moonlightNode.setConfigOption.bind(moonlightNode),
38
+
writeConfig: moonlightNode.writeConfig.bind(moonlightNode),
39
+
38
40
getNatives: moonlightNode.getNatives.bind(moonlightNode),
39
41
getLogger(id) {
40
42
return new Logger(id);
41
43
},
44
+
42
45
lunast: new LunAST(),
43
46
moonmap: new Moonmap()
44
47
};
···
51
54
logger.error("Error setting up web-preload", e);
52
55
}
53
56
54
-
if (MOONLIGHT_ENV === "web-preload") {
55
-
window.addEventListener("DOMContentLoaded", () => {
56
-
installStyles();
57
-
});
57
+
if (document.readyState === "complete") {
58
+
installStyles();
58
59
} else {
59
-
installStyles();
60
+
window.addEventListener("load", installStyles);
60
61
}
61
62
}
62
63
63
-
if (MOONLIGHT_ENV === "web-preload") {
64
-
load();
65
-
} else {
66
-
window._moonlightBrowserLoad = load;
67
-
}
64
+
window._moonlightWebLoad = load;
+4
-1
packages/web-preload/tsconfig.json
+4
-1
packages/web-preload/tsconfig.json
+1498
-1196
pnpm-lock.yaml
+1498
-1196
pnpm-lock.yaml
···
4
4
autoInstallPeers: true
5
5
excludeLinksFromLockfile: false
6
6
7
+
catalogs:
8
+
dev:
9
+
'@moonlight-mod/eslint-config':
10
+
specifier: github:moonlight-mod/eslint-config
11
+
version: 1.0.1
12
+
'@types/chrome':
13
+
specifier: ^0.0.313
14
+
version: 0.0.313
15
+
'@types/node':
16
+
specifier: ^22.14.0
17
+
version: 22.14.0
18
+
esbuild:
19
+
specifier: ^0.19.3
20
+
version: 0.19.3
21
+
esbuild-copy-static-files:
22
+
specifier: ^0.1.0
23
+
version: 0.1.0
24
+
eslint:
25
+
specifier: ^9.12.0
26
+
version: 9.23.0
27
+
husky:
28
+
specifier: ^8.0.3
29
+
version: 8.0.3
30
+
prettier:
31
+
specifier: ^3.1.0
32
+
version: 3.1.0
33
+
taze:
34
+
specifier: ^19.0.4
35
+
version: 19.0.4
36
+
typescript:
37
+
specifier: ^5.3.3
38
+
version: 5.8.2
39
+
prod:
40
+
'@moonlight-mod/lunast':
41
+
specifier: ^1.0.1
42
+
version: 1.0.1
43
+
'@moonlight-mod/mappings':
44
+
specifier: ^1.1.25
45
+
version: 1.1.25
46
+
'@moonlight-mod/moonmap':
47
+
specifier: ^1.0.5
48
+
version: 1.0.5
49
+
'@zenfs/core':
50
+
specifier: ^2.0.0
51
+
version: 2.0.0
52
+
'@zenfs/dom':
53
+
specifier: ^1.1.3
54
+
version: 1.1.6
55
+
microdiff:
56
+
specifier: ^1.5.0
57
+
version: 1.5.0
58
+
nanotar:
59
+
specifier: ^0.1.1
60
+
version: 0.1.1
61
+
7
62
importers:
8
63
9
64
.:
10
65
devDependencies:
11
-
'@typescript-eslint/eslint-plugin':
12
-
specifier: ^6.13.2
13
-
version: 6.13.2(@typescript-eslint/parser@6.13.2(eslint@8.55.0)(typescript@5.3.2))(eslint@8.55.0)(typescript@5.3.2)
14
-
'@typescript-eslint/parser':
15
-
specifier: ^6.13.2
16
-
version: 6.13.2(eslint@8.55.0)(typescript@5.3.2)
66
+
'@moonlight-mod/eslint-config':
67
+
specifier: catalog:dev
68
+
version: https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/e262ac24e1a0955a9b3e0d66da247a0a8c0446c9(@types/eslint@9.6.1)(eslint@9.23.0(jiti@2.4.2))(prettier@3.1.0)(typescript@5.8.2)
69
+
'@types/node':
70
+
specifier: catalog:dev
71
+
version: 22.14.0
17
72
esbuild:
18
-
specifier: ^0.19.3
73
+
specifier: catalog:dev
19
74
version: 0.19.3
20
75
esbuild-copy-static-files:
21
-
specifier: ^0.1.0
76
+
specifier: catalog:dev
22
77
version: 0.1.0
23
78
eslint:
24
-
specifier: ^8.55.0
25
-
version: 8.55.0
26
-
eslint-config-prettier:
27
-
specifier: ^9.1.0
28
-
version: 9.1.0(eslint@8.55.0)
29
-
eslint-plugin-prettier:
30
-
specifier: ^5.0.1
31
-
version: 5.0.1(eslint-config-prettier@9.1.0(eslint@8.55.0))(eslint@8.55.0)(prettier@3.1.0)
32
-
eslint-plugin-react:
33
-
specifier: ^7.33.2
34
-
version: 7.33.2(eslint@8.55.0)
79
+
specifier: catalog:dev
80
+
version: 9.23.0(jiti@2.4.2)
35
81
husky:
36
-
specifier: ^8.0.3
82
+
specifier: catalog:dev
37
83
version: 8.0.3
38
84
prettier:
39
-
specifier: ^3.1.0
85
+
specifier: catalog:dev
40
86
version: 3.1.0
87
+
taze:
88
+
specifier: catalog:dev
89
+
version: 19.0.4
41
90
typescript:
42
-
specifier: ^5.3.2
43
-
version: 5.3.2
91
+
specifier: catalog:dev
92
+
version: 5.8.2
44
93
45
94
packages/browser:
46
95
dependencies:
···
54
103
specifier: workspace:*
55
104
version: link:../web-preload
56
105
'@zenfs/core':
57
-
specifier: ^1.0.2
58
-
version: 1.0.2
106
+
specifier: catalog:prod
107
+
version: 2.0.0
59
108
'@zenfs/dom':
60
-
specifier: ^0.2.16
61
-
version: 0.2.16(@zenfs/core@1.0.2)
109
+
specifier: catalog:prod
110
+
version: 1.1.6(@zenfs/core@2.0.0)(utilium@1.10.1)
111
+
devDependencies:
112
+
'@types/chrome':
113
+
specifier: catalog:dev
114
+
version: 0.0.313
62
115
63
116
packages/core:
64
117
dependencies:
···
74
127
'@moonlight-mod/types':
75
128
specifier: workspace:*
76
129
version: link:../types
130
+
microdiff:
131
+
specifier: catalog:prod
132
+
version: 1.5.0
77
133
nanotar:
78
-
specifier: ^0.1.1
134
+
specifier: catalog:prod
79
135
version: 0.1.1
80
136
81
137
packages/injector:
···
99
155
packages/types:
100
156
dependencies:
101
157
'@moonlight-mod/lunast':
102
-
specifier: ^1.0.0
103
-
version: 1.0.0
158
+
specifier: ^1.0.1
159
+
version: 1.0.1
104
160
'@moonlight-mod/mappings':
105
-
specifier: ^1.0.2
106
-
version: 1.0.2(@moonlight-mod/lunast@1.0.0)(@moonlight-mod/moonmap@1.0.2)
161
+
specifier: ^1.1.25
162
+
version: 1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
107
163
'@moonlight-mod/moonmap':
108
-
specifier: ^1.0.2
109
-
version: 1.0.2
164
+
specifier: ^1.0.5
165
+
version: 1.0.5
110
166
'@types/react':
111
167
specifier: ^18.3.10
112
-
version: 18.3.10
168
+
version: 18.3.20
113
169
csstype:
114
-
specifier: ^3.1.2
115
-
version: 3.1.2
170
+
specifier: ^3.1.3
171
+
version: 3.1.3
116
172
standalone-electron-types:
117
173
specifier: ^1.0.0
118
174
version: 1.0.0
···
123
179
specifier: workspace:*
124
180
version: link:../core
125
181
'@moonlight-mod/lunast':
126
-
specifier: ^1.0.0
127
-
version: 1.0.0
182
+
specifier: catalog:prod
183
+
version: 1.0.1
128
184
'@moonlight-mod/mappings':
129
-
specifier: ^1.0.2
130
-
version: 1.0.2(@moonlight-mod/lunast@1.0.0)(@moonlight-mod/moonmap@1.0.2)
185
+
specifier: catalog:prod
186
+
version: 1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
131
187
'@moonlight-mod/moonmap':
132
-
specifier: ^1.0.2
133
-
version: 1.0.2
188
+
specifier: catalog:prod
189
+
version: 1.0.5
134
190
'@moonlight-mod/types':
135
191
specifier: workspace:*
136
192
version: link:../types
···
140
196
'@aashutoshrathi/word-wrap@1.2.6':
141
197
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
142
198
engines: {node: '>=0.10.0'}
199
+
200
+
'@antfu/ni@24.3.0':
201
+
resolution: {integrity: sha512-wBSav4mBxvHEW9RbdSo1SWLQ6MAlT0Dc423weC58yOWqW4OcMvtnNDdDrxOZeJ88fEIyPK93gDUWIelBxzSf8g==}
202
+
hasBin: true
143
203
144
204
'@esbuild/android-arm64@0.19.3':
145
205
resolution: {integrity: sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==}
···
273
333
cpu: [x64]
274
334
os: [win32]
275
335
276
-
'@eslint-community/eslint-utils@4.4.0':
277
-
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
336
+
'@eslint-community/eslint-utils@4.5.1':
337
+
resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
278
338
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
279
339
peerDependencies:
280
340
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
281
341
282
-
'@eslint-community/regexpp@4.10.0':
283
-
resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
342
+
'@eslint-community/regexpp@4.12.1':
343
+
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
284
344
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
285
345
286
-
'@eslint/eslintrc@2.1.4':
287
-
resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
288
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
346
+
'@eslint/config-array@0.19.2':
347
+
resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
348
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
349
+
350
+
'@eslint/config-helpers@0.2.1':
351
+
resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==}
352
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
353
+
354
+
'@eslint/core@0.12.0':
355
+
resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==}
356
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
357
+
358
+
'@eslint/core@0.13.0':
359
+
resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==}
360
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
361
+
362
+
'@eslint/eslintrc@3.3.1':
363
+
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
364
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
289
365
290
-
'@eslint/js@8.55.0':
291
-
resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==}
292
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
366
+
'@eslint/js@9.23.0':
367
+
resolution: {integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==}
368
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
293
369
294
-
'@humanwhocodes/config-array@0.11.13':
295
-
resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
296
-
engines: {node: '>=10.10.0'}
297
-
deprecated: Use @eslint/config-array instead
370
+
'@eslint/object-schema@2.1.6':
371
+
resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
372
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
373
+
374
+
'@eslint/plugin-kit@0.2.8':
375
+
resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==}
376
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
377
+
378
+
'@humanfs/core@0.19.1':
379
+
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
380
+
engines: {node: '>=18.18.0'}
381
+
382
+
'@humanfs/node@0.16.6':
383
+
resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
384
+
engines: {node: '>=18.18.0'}
298
385
299
386
'@humanwhocodes/module-importer@1.0.1':
300
387
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
301
388
engines: {node: '>=12.22'}
302
389
303
-
'@humanwhocodes/object-schema@2.0.1':
304
-
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
305
-
deprecated: Use @eslint/object-schema instead
390
+
'@humanwhocodes/retry@0.3.1':
391
+
resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
392
+
engines: {node: '>=18.18'}
306
393
307
-
'@moonlight-mod/lunast@1.0.0':
308
-
resolution: {integrity: sha512-kJgf41K12i6/2LbXK97CNO+pNO7ADGh9N4bCQcOPwosocKMcwKHDEZUgPqeihNshY3c3AEW1LiyXjlsl24PdDw==}
394
+
'@humanwhocodes/retry@0.4.2':
395
+
resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==}
396
+
engines: {node: '>=18.18'}
309
397
310
-
'@moonlight-mod/mappings@1.0.2':
311
-
resolution: {integrity: sha512-PjIv4LFyt3j4LyGiokUmJ6a0L5JljoLXjUkixCynLLpNLd660qTcLe8f9tbhOovvD8joqejq+f5oqSo2V4/Vfg==}
398
+
'@moonlight-mod/eslint-config@https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/e262ac24e1a0955a9b3e0d66da247a0a8c0446c9':
399
+
resolution: {tarball: https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/e262ac24e1a0955a9b3e0d66da247a0a8c0446c9}
400
+
version: 1.0.1
312
401
peerDependencies:
313
-
'@moonlight-mod/lunast': ^1.0.0
314
-
'@moonlight-mod/moonmap': ^1.0.0
402
+
eslint: '>= 9'
403
+
typescript: '>= 5.3'
404
+
405
+
'@moonlight-mod/lunast@1.0.1':
406
+
resolution: {integrity: sha512-K3vxzDlfFuYKjciIW2FMlcZ1qrrkAGDGpSBlNqYGtJ0sMt9bRCd2lpSpg6AX/giSljDtmAUXa/5mOfUoDQxjBA==}
315
407
316
-
'@moonlight-mod/moonmap@1.0.2':
317
-
resolution: {integrity: sha512-dqMFwk8o0duRfvBNYo6EwalEUWWR3bNF5V2N04ogHp4gYON6/5+XOUrTlQ9BFBDj9anZwGgVwGqnxV42Qs9pPw==}
408
+
'@moonlight-mod/mappings@1.1.25':
409
+
resolution: {integrity: sha512-bgnSN9H/IBdMGxGev6RQKXuzhQxwo1090NhIDHnflguZnjiu2pg/usPfh76bqyhxRuX4SS7tiZSNTwBoSflCLg==}
410
+
engines: {node: '>=22', npm: pnpm, pnpm: '>=10', yarn: pnpm}
411
+
peerDependencies:
412
+
'@moonlight-mod/lunast': ^1.0.1
413
+
'@moonlight-mod/moonmap': ^1.0.5
414
+
415
+
'@moonlight-mod/moonmap@1.0.5':
416
+
resolution: {integrity: sha512-Fdpxj8ghdulKB6TlTnchlCPey2YUKgEf1chuO1ofOIcvlqnVPBcQwSf2S80naOUQpXCDo4dQ+LWSE2fmhdDiiw==}
318
417
319
418
'@nodelib/fs.scandir@2.1.5':
320
419
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
···
328
427
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
329
428
engines: {node: '>= 8'}
330
429
331
-
'@pkgr/utils@2.4.2':
332
-
resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==}
430
+
'@pkgr/core@0.2.0':
431
+
resolution: {integrity: sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==}
333
432
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
334
433
434
+
'@quansync/fs@0.1.2':
435
+
resolution: {integrity: sha512-ezIadUb1aFhwJLd++WVqVpi9rnlX8vnd4ju7saPhwLHJN1mJgOv0puePTGV+FbtSnWtwoHDT8lAm4kagDZmpCg==}
436
+
engines: {node: '>=20.0.0'}
437
+
438
+
'@types/chroma-js@3.1.0':
439
+
resolution: {integrity: sha512-Uwl3SOtUkbQ6Ye6ZYu4q4xdLGBzmY839sEHYtOT7i691neeyd+7fXWT5VIkcUSfNwIFrIjQutNYQn9h4q5HFvg==}
440
+
441
+
'@types/chrome@0.0.313':
442
+
resolution: {integrity: sha512-9R5T7gTaYZhkxlu+Ho4wk9FL+y/werWQY2yjGWSqCuiTsqS7nL/BE5UMTP6rU7J+oIG2FRKqrEycHhJATeltVA==}
443
+
444
+
'@types/eslint@9.6.1':
445
+
resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==}
446
+
335
447
'@types/estree-jsx@1.0.5':
336
448
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
337
449
338
450
'@types/estree@1.0.6':
339
451
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
340
452
453
+
'@types/estree@1.0.7':
454
+
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
455
+
341
456
'@types/fbemitter@2.0.35':
342
457
resolution: {integrity: sha512-Xem6d7qUfmouCHntCrRYgDBwbf+WWRd6G+7WEFlEZFZ67LZXiYRvT2LV8wcZa6mIaAil95+ABQdKgB6hPIsnng==}
343
458
459
+
'@types/filesystem@0.0.36':
460
+
resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==}
461
+
462
+
'@types/filewriter@0.0.33':
463
+
resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==}
464
+
344
465
'@types/flux@3.1.14':
345
466
resolution: {integrity: sha512-WRXN0kQPCnqxN0/PgNgc7WBF6c8rbSHsEep3/qBLpsQ824RONdOmTs0TV7XhIW2GDNRAHO2CqCgAFLR5PChosw==}
346
467
468
+
'@types/har-format@1.2.16':
469
+
resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==}
470
+
471
+
'@types/highlightjs@9.12.6':
472
+
resolution: {integrity: sha512-Qfd1DUrwE851Hc3tExADJY4qY8yeZMt06Xw9AJm/UtpneepJS3MZY29c33BY0wP899veaaHD4gZzYiSuQm84Fg==}
473
+
347
474
'@types/json-schema@7.0.15':
348
475
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
349
476
477
+
'@types/lodash@4.17.14':
478
+
resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==}
479
+
350
480
'@types/node@18.17.17':
351
481
resolution: {integrity: sha512-cOxcXsQ2sxiwkykdJqvyFS+MLQPLvIdwh5l6gNg8qF6s+C7XSkEWOZjK+XhUZd+mYvHV/180g2cnCcIl4l06Pw==}
352
482
353
-
'@types/node@20.16.10':
354
-
resolution: {integrity: sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==}
483
+
'@types/node@22.13.6':
484
+
resolution: {integrity: sha512-GYmF65GI7417CpZXsEXMjT8goQQDnpRnJnDw6jIYa+le3V/lMazPZ4vZmK1B/9R17fh2VLr2zuy9d/h5xgrLAg==}
485
+
486
+
'@types/node@22.14.0':
487
+
resolution: {integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==}
488
+
489
+
'@types/platform@1.3.6':
490
+
resolution: {integrity: sha512-ZmSaqHuvzv+jC232cFoz2QqPUkaj6EvMmCrWcx3WRr7xTPVFCMUOTcOq8m2d+Zw1iKRc1kDiaA+jtNrV0hkVew==}
355
491
356
492
'@types/prop-types@15.7.13':
357
493
resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
358
494
359
-
'@types/react@18.3.10':
360
-
resolution: {integrity: sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==}
495
+
'@types/react@18.3.20':
496
+
resolution: {integrity: sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==}
361
497
362
-
'@types/readable-stream@4.0.15':
363
-
resolution: {integrity: sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==}
364
-
365
-
'@types/semver@7.5.6':
366
-
resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==}
367
-
368
-
'@typescript-eslint/eslint-plugin@6.13.2':
369
-
resolution: {integrity: sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==}
370
-
engines: {node: ^16.0.0 || >=18.0.0}
498
+
'@typescript-eslint/eslint-plugin@8.29.0':
499
+
resolution: {integrity: sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==}
500
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
371
501
peerDependencies:
372
-
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
373
-
eslint: ^7.0.0 || ^8.0.0
374
-
typescript: '*'
375
-
peerDependenciesMeta:
376
-
typescript:
377
-
optional: true
502
+
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
503
+
eslint: ^8.57.0 || ^9.0.0
504
+
typescript: '>=4.8.4 <5.9.0'
378
505
379
-
'@typescript-eslint/parser@6.13.2':
380
-
resolution: {integrity: sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==}
381
-
engines: {node: ^16.0.0 || >=18.0.0}
506
+
'@typescript-eslint/parser@8.29.0':
507
+
resolution: {integrity: sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==}
508
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
382
509
peerDependencies:
383
-
eslint: ^7.0.0 || ^8.0.0
384
-
typescript: '*'
385
-
peerDependenciesMeta:
386
-
typescript:
387
-
optional: true
510
+
eslint: ^8.57.0 || ^9.0.0
511
+
typescript: '>=4.8.4 <5.9.0'
388
512
389
-
'@typescript-eslint/scope-manager@6.13.2':
390
-
resolution: {integrity: sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==}
391
-
engines: {node: ^16.0.0 || >=18.0.0}
513
+
'@typescript-eslint/scope-manager@8.29.0':
514
+
resolution: {integrity: sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==}
515
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
392
516
393
-
'@typescript-eslint/type-utils@6.13.2':
394
-
resolution: {integrity: sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==}
395
-
engines: {node: ^16.0.0 || >=18.0.0}
517
+
'@typescript-eslint/type-utils@8.29.0':
518
+
resolution: {integrity: sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==}
519
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
396
520
peerDependencies:
397
-
eslint: ^7.0.0 || ^8.0.0
398
-
typescript: '*'
399
-
peerDependenciesMeta:
400
-
typescript:
401
-
optional: true
521
+
eslint: ^8.57.0 || ^9.0.0
522
+
typescript: '>=4.8.4 <5.9.0'
402
523
403
-
'@typescript-eslint/types@6.13.2':
404
-
resolution: {integrity: sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==}
405
-
engines: {node: ^16.0.0 || >=18.0.0}
524
+
'@typescript-eslint/types@8.29.0':
525
+
resolution: {integrity: sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==}
526
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
406
527
407
-
'@typescript-eslint/typescript-estree@6.13.2':
408
-
resolution: {integrity: sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==}
409
-
engines: {node: ^16.0.0 || >=18.0.0}
528
+
'@typescript-eslint/typescript-estree@8.29.0':
529
+
resolution: {integrity: sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==}
530
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
410
531
peerDependencies:
411
-
typescript: '*'
412
-
peerDependenciesMeta:
413
-
typescript:
414
-
optional: true
532
+
typescript: '>=4.8.4 <5.9.0'
415
533
416
-
'@typescript-eslint/utils@6.13.2':
417
-
resolution: {integrity: sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==}
418
-
engines: {node: ^16.0.0 || >=18.0.0}
534
+
'@typescript-eslint/utils@8.29.0':
535
+
resolution: {integrity: sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==}
536
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
419
537
peerDependencies:
420
-
eslint: ^7.0.0 || ^8.0.0
538
+
eslint: ^8.57.0 || ^9.0.0
539
+
typescript: '>=4.8.4 <5.9.0'
421
540
422
-
'@typescript-eslint/visitor-keys@6.13.2':
423
-
resolution: {integrity: sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==}
424
-
engines: {node: ^16.0.0 || >=18.0.0}
541
+
'@typescript-eslint/visitor-keys@8.29.0':
542
+
resolution: {integrity: sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==}
543
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
425
544
426
-
'@ungap/structured-clone@1.2.0':
427
-
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
545
+
'@xterm/xterm@5.5.0':
546
+
resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==}
428
547
429
-
'@zenfs/core@1.0.2':
430
-
resolution: {integrity: sha512-LMTD4ntn6Ag1y+IeOSVykDDvYC12dsGFtsX8M/54OQrLs7v+YnX4bpo0o2osbm8XFmU2MTNMX/G3PLsvzgWzrg==}
431
-
engines: {node: '>= 16'}
548
+
'@zenfs/core@2.0.0':
549
+
resolution: {integrity: sha512-wOKNFTY1DJ1vdLqKdU7M8cRh0nVYZcDVu7WHuk/3u49hrSwTZVm4PzGxJUjFd8O9Wi3U5nYTbZoN7RX5mS2ldA==}
550
+
engines: {node: '>= 18'}
432
551
hasBin: true
433
552
434
-
'@zenfs/dom@0.2.16':
435
-
resolution: {integrity: sha512-6Ev+ol9hZIgQECNZR+xxjQ/a99EhhrWeiQttm/+U7YJK3HdTjiKfU39DsfGeH64vSqhpa5Vj+LWRx75SHkjw0Q==}
553
+
'@zenfs/dom@1.1.6':
554
+
resolution: {integrity: sha512-7SBTWgA0esuEv/TE+N/xk6W/XJf8uBF+LhlPNHQdXds0H7aOy/UYsWv/8glvARe+meDMMidoeWFLzUWoMXfjlA==}
436
555
engines: {node: '>= 18'}
437
556
peerDependencies:
438
-
'@zenfs/core': ^1.0.0
557
+
'@zenfs/core': ^2.0.0
558
+
utilium: ^1.9.0
439
559
440
560
abort-controller@3.0.0:
441
561
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
···
446
566
peerDependencies:
447
567
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
448
568
449
-
acorn@8.12.1:
450
-
resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
569
+
acorn@8.14.1:
570
+
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
451
571
engines: {node: '>=0.4.0'}
452
572
hasBin: true
453
573
454
574
ajv@6.12.6:
455
575
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
456
576
457
-
ansi-regex@5.0.1:
458
-
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
459
-
engines: {node: '>=8'}
460
-
461
577
ansi-styles@4.3.0:
462
578
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
463
579
engines: {node: '>=8'}
464
580
581
+
ansis@3.17.0:
582
+
resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==}
583
+
engines: {node: '>=14'}
584
+
465
585
argparse@2.0.1:
466
586
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
467
587
468
-
array-buffer-byte-length@1.0.0:
469
-
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
588
+
array-buffer-byte-length@1.0.2:
589
+
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
590
+
engines: {node: '>= 0.4'}
470
591
471
-
array-includes@3.1.7:
472
-
resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==}
592
+
array-includes@3.1.8:
593
+
resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
473
594
engines: {node: '>= 0.4'}
474
595
475
-
array-union@2.1.0:
476
-
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
477
-
engines: {node: '>=8'}
596
+
array.prototype.findlast@1.2.5:
597
+
resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
598
+
engines: {node: '>= 0.4'}
478
599
479
-
array.prototype.flat@1.3.2:
480
-
resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
600
+
array.prototype.flat@1.3.3:
601
+
resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
481
602
engines: {node: '>= 0.4'}
482
603
483
-
array.prototype.flatmap@1.3.2:
484
-
resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
604
+
array.prototype.flatmap@1.3.3:
605
+
resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
485
606
engines: {node: '>= 0.4'}
486
607
487
-
array.prototype.tosorted@1.1.2:
488
-
resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==}
608
+
array.prototype.tosorted@1.1.4:
609
+
resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
610
+
engines: {node: '>= 0.4'}
489
611
490
-
arraybuffer.prototype.slice@1.0.2:
491
-
resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==}
612
+
arraybuffer.prototype.slice@1.0.4:
613
+
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
492
614
engines: {node: '>= 0.4'}
493
615
494
616
astring@1.9.0:
495
617
resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
496
618
hasBin: true
497
619
498
-
asynciterator.prototype@1.0.0:
499
-
resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==}
620
+
async-function@1.0.0:
621
+
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
622
+
engines: {node: '>= 0.4'}
500
623
501
-
available-typed-arrays@1.0.5:
502
-
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
624
+
available-typed-arrays@1.0.7:
625
+
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
503
626
engines: {node: '>= 0.4'}
504
627
505
628
balanced-match@1.0.2:
···
508
631
base64-js@1.5.1:
509
632
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
510
633
511
-
big-integer@1.6.52:
512
-
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
513
-
engines: {node: '>=0.6'}
514
-
515
-
bplist-parser@0.2.0:
516
-
resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==}
517
-
engines: {node: '>= 5.10.0'}
518
-
519
634
brace-expansion@1.1.11:
520
635
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
521
636
522
637
brace-expansion@2.0.1:
523
638
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
524
639
525
-
braces@3.0.2:
526
-
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
640
+
braces@3.0.3:
641
+
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
527
642
engines: {node: '>=8'}
528
643
529
644
buffer@6.0.3:
530
645
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
531
646
532
-
bundle-name@3.0.0:
533
-
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
534
-
engines: {node: '>=12'}
647
+
cac@6.7.14:
648
+
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
649
+
engines: {node: '>=8'}
535
650
536
-
call-bind@1.0.5:
537
-
resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
651
+
call-bind-apply-helpers@1.0.2:
652
+
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
653
+
engines: {node: '>= 0.4'}
654
+
655
+
call-bind@1.0.8:
656
+
resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
657
+
engines: {node: '>= 0.4'}
658
+
659
+
call-bound@1.0.4:
660
+
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
661
+
engines: {node: '>= 0.4'}
538
662
539
663
callsites@3.1.0:
540
664
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
···
554
678
concat-map@0.0.1:
555
679
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
556
680
557
-
cross-spawn@7.0.3:
558
-
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
681
+
cross-spawn@7.0.6:
682
+
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
559
683
engines: {node: '>= 8'}
560
684
561
-
csstype@3.1.2:
562
-
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
563
-
564
685
csstype@3.1.3:
565
686
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
566
687
567
-
debug@4.3.4:
568
-
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
688
+
data-view-buffer@1.0.2:
689
+
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
690
+
engines: {node: '>= 0.4'}
691
+
692
+
data-view-byte-length@1.0.2:
693
+
resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
694
+
engines: {node: '>= 0.4'}
695
+
696
+
data-view-byte-offset@1.0.1:
697
+
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
698
+
engines: {node: '>= 0.4'}
699
+
700
+
debug@4.4.0:
701
+
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
569
702
engines: {node: '>=6.0'}
570
703
peerDependencies:
571
704
supports-color: '*'
···
576
709
deep-is@0.1.4:
577
710
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
578
711
579
-
default-browser-id@3.0.0:
580
-
resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
581
-
engines: {node: '>=12'}
582
-
583
-
default-browser@4.0.0:
584
-
resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==}
585
-
engines: {node: '>=14.16'}
586
-
587
-
define-data-property@1.1.1:
588
-
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
712
+
define-data-property@1.1.4:
713
+
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
589
714
engines: {node: '>= 0.4'}
590
715
591
-
define-lazy-prop@3.0.0:
592
-
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
593
-
engines: {node: '>=12'}
594
-
595
716
define-properties@1.2.1:
596
717
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
597
718
engines: {node: '>= 0.4'}
598
719
599
-
dir-glob@3.0.1:
600
-
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
601
-
engines: {node: '>=8'}
720
+
defu@6.1.4:
721
+
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
722
+
723
+
destr@2.0.4:
724
+
resolution: {integrity: sha512-FCAorltMy7QwX0QU38jOkhrv20LBpsHA8ogzvMhhPHCCKVCaN6GxrB0GGaWEWBUYI4eEjjfJ95RdP6dk9IdMQA==}
602
725
603
726
doctrine@2.1.0:
604
727
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
605
728
engines: {node: '>=0.10.0'}
606
729
607
-
doctrine@3.0.0:
608
-
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
609
-
engines: {node: '>=6.0.0'}
730
+
dunder-proto@1.0.1:
731
+
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
732
+
engines: {node: '>= 0.4'}
610
733
611
-
es-abstract@1.22.3:
612
-
resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==}
734
+
es-abstract@1.23.9:
735
+
resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
613
736
engines: {node: '>= 0.4'}
614
737
615
-
es-iterator-helpers@1.0.15:
616
-
resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==}
738
+
es-define-property@1.0.1:
739
+
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
740
+
engines: {node: '>= 0.4'}
617
741
618
-
es-set-tostringtag@2.0.2:
619
-
resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==}
742
+
es-errors@1.3.0:
743
+
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
620
744
engines: {node: '>= 0.4'}
621
745
622
-
es-shim-unscopables@1.0.2:
623
-
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
746
+
es-iterator-helpers@1.2.1:
747
+
resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==}
748
+
engines: {node: '>= 0.4'}
624
749
625
-
es-to-primitive@1.2.1:
626
-
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
750
+
es-object-atoms@1.1.1:
751
+
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
752
+
engines: {node: '>= 0.4'}
753
+
754
+
es-set-tostringtag@2.1.0:
755
+
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
756
+
engines: {node: '>= 0.4'}
757
+
758
+
es-shim-unscopables@1.1.0:
759
+
resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
760
+
engines: {node: '>= 0.4'}
761
+
762
+
es-to-primitive@1.3.0:
763
+
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
627
764
engines: {node: '>= 0.4'}
628
765
629
766
esbuild-copy-static-files@0.1.0:
···
644
781
peerDependencies:
645
782
eslint: '>=7.0.0'
646
783
647
-
eslint-plugin-prettier@5.0.1:
648
-
resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==}
784
+
eslint-plugin-prettier@5.2.6:
785
+
resolution: {integrity: sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ==}
649
786
engines: {node: ^14.18.0 || >=16.0.0}
650
787
peerDependencies:
651
788
'@types/eslint': '>=8.0.0'
652
789
eslint: '>=8.0.0'
653
-
eslint-config-prettier: '*'
790
+
eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0'
654
791
prettier: '>=3.0.0'
655
792
peerDependenciesMeta:
656
793
'@types/eslint':
···
658
795
eslint-config-prettier:
659
796
optional: true
660
797
661
-
eslint-plugin-react@7.33.2:
662
-
resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==}
798
+
eslint-plugin-react@7.37.5:
799
+
resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
663
800
engines: {node: '>=4'}
664
801
peerDependencies:
665
-
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
802
+
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
666
803
667
-
eslint-scope@7.2.2:
668
-
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
669
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
804
+
eslint-scope@8.3.0:
805
+
resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
806
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
670
807
671
808
eslint-visitor-keys@3.4.3:
672
809
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
673
810
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
674
811
675
-
eslint@8.55.0:
676
-
resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==}
677
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
678
-
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
812
+
eslint-visitor-keys@4.2.0:
813
+
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
814
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
815
+
816
+
eslint@9.23.0:
817
+
resolution: {integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==}
818
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
679
819
hasBin: true
820
+
peerDependencies:
821
+
jiti: '*'
822
+
peerDependenciesMeta:
823
+
jiti:
824
+
optional: true
680
825
681
-
espree@9.6.1:
682
-
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
683
-
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
826
+
espree@10.3.0:
827
+
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
828
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
684
829
685
-
esquery@1.5.0:
686
-
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
830
+
esquery@1.6.0:
831
+
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
687
832
engines: {node: '>=0.10'}
688
833
689
834
esrecurse@4.3.0:
···
712
857
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
713
858
engines: {node: '>=0.8.x'}
714
859
715
-
execa@5.1.1:
716
-
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
717
-
engines: {node: '>=10'}
718
-
719
-
execa@7.2.0:
720
-
resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
721
-
engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
722
-
723
860
fast-deep-equal@3.1.3:
724
861
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
725
862
···
736
873
fast-levenshtein@2.0.6:
737
874
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
738
875
739
-
fastq@1.15.0:
740
-
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
876
+
fastq@1.17.1:
877
+
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
741
878
742
-
file-entry-cache@6.0.1:
743
-
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
744
-
engines: {node: ^10.12.0 || >=12.0.0}
879
+
fdir@6.4.3:
880
+
resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
881
+
peerDependencies:
882
+
picomatch: ^3 || ^4
883
+
peerDependenciesMeta:
884
+
picomatch:
885
+
optional: true
886
+
887
+
file-entry-cache@8.0.0:
888
+
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
889
+
engines: {node: '>=16.0.0'}
745
890
746
-
fill-range@7.0.1:
747
-
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
891
+
fill-range@7.1.1:
892
+
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
748
893
engines: {node: '>=8'}
749
894
895
+
find-up-simple@1.0.1:
896
+
resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==}
897
+
engines: {node: '>=18'}
898
+
750
899
find-up@5.0.0:
751
900
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
752
901
engines: {node: '>=10'}
753
902
754
-
flat-cache@3.2.0:
755
-
resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
756
-
engines: {node: ^10.12.0 || >=12.0.0}
903
+
flat-cache@4.0.1:
904
+
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
905
+
engines: {node: '>=16'}
757
906
758
907
flatted@3.2.9:
759
908
resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
760
909
761
-
for-each@0.3.3:
762
-
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
763
-
764
-
fs.realpath@1.0.0:
765
-
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
910
+
for-each@0.3.5:
911
+
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
912
+
engines: {node: '>= 0.4'}
766
913
767
914
function-bind@1.1.2:
768
915
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
769
916
770
-
function.prototype.name@1.1.6:
771
-
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
917
+
function.prototype.name@1.1.8:
918
+
resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
772
919
engines: {node: '>= 0.4'}
773
920
774
921
functions-have-names@1.2.3:
775
922
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
776
923
777
-
get-intrinsic@1.2.2:
778
-
resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
924
+
fzf@0.5.2:
925
+
resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==}
926
+
927
+
get-intrinsic@1.3.0:
928
+
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
929
+
engines: {node: '>= 0.4'}
779
930
780
-
get-stream@6.0.1:
781
-
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
782
-
engines: {node: '>=10'}
931
+
get-proto@1.0.1:
932
+
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
933
+
engines: {node: '>= 0.4'}
783
934
784
-
get-symbol-description@1.0.0:
785
-
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
935
+
get-symbol-description@1.1.0:
936
+
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
786
937
engines: {node: '>= 0.4'}
787
938
788
939
glob-parent@5.1.2:
···
793
944
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
794
945
engines: {node: '>=10.13.0'}
795
946
796
-
glob@7.2.3:
797
-
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
798
-
deprecated: Glob versions prior to v9 are no longer supported
947
+
globals@14.0.0:
948
+
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
949
+
engines: {node: '>=18'}
799
950
800
-
globals@13.23.0:
801
-
resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==}
802
-
engines: {node: '>=8'}
803
-
804
-
globalthis@1.0.3:
805
-
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
951
+
globalthis@1.0.4:
952
+
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
806
953
engines: {node: '>= 0.4'}
807
954
808
-
globby@11.1.0:
809
-
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
810
-
engines: {node: '>=10'}
811
-
812
-
gopd@1.0.1:
813
-
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
955
+
gopd@1.2.0:
956
+
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
957
+
engines: {node: '>= 0.4'}
814
958
815
959
graphemer@1.4.0:
816
960
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
817
961
818
-
has-bigints@1.0.2:
819
-
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
962
+
has-bigints@1.1.0:
963
+
resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
964
+
engines: {node: '>= 0.4'}
820
965
821
966
has-flag@4.0.0:
822
967
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
823
968
engines: {node: '>=8'}
824
969
825
-
has-property-descriptors@1.0.1:
826
-
resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==}
970
+
has-property-descriptors@1.0.2:
971
+
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
827
972
828
-
has-proto@1.0.1:
829
-
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
973
+
has-proto@1.2.0:
974
+
resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
830
975
engines: {node: '>= 0.4'}
831
976
832
-
has-symbols@1.0.3:
833
-
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
977
+
has-symbols@1.1.0:
978
+
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
834
979
engines: {node: '>= 0.4'}
835
980
836
-
has-tostringtag@1.0.0:
837
-
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
981
+
has-tostringtag@1.0.2:
982
+
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
838
983
engines: {node: '>= 0.4'}
839
984
840
-
hasown@2.0.0:
841
-
resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
985
+
hasown@2.0.2:
986
+
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
842
987
engines: {node: '>= 0.4'}
843
988
844
-
human-signals@2.1.0:
845
-
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
846
-
engines: {node: '>=10.17.0'}
847
-
848
-
human-signals@4.3.1:
849
-
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
850
-
engines: {node: '>=14.18.0'}
851
-
852
989
husky@8.0.3:
853
990
resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
854
991
engines: {node: '>=14'}
···
857
994
ieee754@1.2.1:
858
995
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
859
996
860
-
ignore@5.3.0:
861
-
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
997
+
ignore@5.3.2:
998
+
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
862
999
engines: {node: '>= 4'}
863
1000
864
1001
import-fresh@3.3.0:
···
869
1006
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
870
1007
engines: {node: '>=0.8.19'}
871
1008
872
-
inflight@1.0.6:
873
-
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
874
-
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
875
-
876
-
inherits@2.0.4:
877
-
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
878
-
879
-
internal-slot@1.0.6:
880
-
resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
1009
+
internal-slot@1.1.0:
1010
+
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
881
1011
engines: {node: '>= 0.4'}
882
1012
883
-
is-array-buffer@3.0.2:
884
-
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
1013
+
is-array-buffer@3.0.5:
1014
+
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
1015
+
engines: {node: '>= 0.4'}
885
1016
886
-
is-async-function@2.0.0:
887
-
resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
1017
+
is-async-function@2.1.1:
1018
+
resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
888
1019
engines: {node: '>= 0.4'}
889
1020
890
-
is-bigint@1.0.4:
891
-
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
1021
+
is-bigint@1.1.0:
1022
+
resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
1023
+
engines: {node: '>= 0.4'}
892
1024
893
-
is-boolean-object@1.1.2:
894
-
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
1025
+
is-boolean-object@1.2.2:
1026
+
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
895
1027
engines: {node: '>= 0.4'}
896
1028
897
1029
is-callable@1.2.7:
898
1030
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
899
1031
engines: {node: '>= 0.4'}
900
1032
901
-
is-core-module@2.13.1:
902
-
resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
1033
+
is-core-module@2.16.1:
1034
+
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
1035
+
engines: {node: '>= 0.4'}
903
1036
904
-
is-date-object@1.0.5:
905
-
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
1037
+
is-data-view@1.0.2:
1038
+
resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
906
1039
engines: {node: '>= 0.4'}
907
1040
908
-
is-docker@2.2.1:
909
-
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
910
-
engines: {node: '>=8'}
911
-
hasBin: true
912
-
913
-
is-docker@3.0.0:
914
-
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
915
-
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
916
-
hasBin: true
1041
+
is-date-object@1.1.0:
1042
+
resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
1043
+
engines: {node: '>= 0.4'}
917
1044
918
1045
is-extglob@2.1.1:
919
1046
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
920
1047
engines: {node: '>=0.10.0'}
921
1048
922
-
is-finalizationregistry@1.0.2:
923
-
resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==}
1049
+
is-finalizationregistry@1.1.1:
1050
+
resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
1051
+
engines: {node: '>= 0.4'}
924
1052
925
-
is-generator-function@1.0.10:
926
-
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
1053
+
is-generator-function@1.1.0:
1054
+
resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
927
1055
engines: {node: '>= 0.4'}
928
1056
929
1057
is-glob@4.0.3:
930
1058
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
931
1059
engines: {node: '>=0.10.0'}
932
1060
933
-
is-inside-container@1.0.0:
934
-
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
935
-
engines: {node: '>=14.16'}
936
-
hasBin: true
937
-
938
-
is-map@2.0.2:
939
-
resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
940
-
941
-
is-negative-zero@2.0.2:
942
-
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
1061
+
is-map@2.0.3:
1062
+
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
943
1063
engines: {node: '>= 0.4'}
944
1064
945
-
is-number-object@1.0.7:
946
-
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
1065
+
is-number-object@1.1.1:
1066
+
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
947
1067
engines: {node: '>= 0.4'}
948
1068
949
1069
is-number@7.0.0:
950
1070
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
951
1071
engines: {node: '>=0.12.0'}
952
1072
953
-
is-path-inside@3.0.3:
954
-
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
955
-
engines: {node: '>=8'}
1073
+
is-regex@1.2.1:
1074
+
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
1075
+
engines: {node: '>= 0.4'}
956
1076
957
-
is-regex@1.1.4:
958
-
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
1077
+
is-set@2.0.3:
1078
+
resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
959
1079
engines: {node: '>= 0.4'}
960
1080
961
-
is-set@2.0.2:
962
-
resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
1081
+
is-shared-array-buffer@1.0.4:
1082
+
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
1083
+
engines: {node: '>= 0.4'}
963
1084
964
-
is-shared-array-buffer@1.0.2:
965
-
resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
1085
+
is-string@1.1.1:
1086
+
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
1087
+
engines: {node: '>= 0.4'}
966
1088
967
-
is-stream@2.0.1:
968
-
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
969
-
engines: {node: '>=8'}
1089
+
is-symbol@1.1.1:
1090
+
resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
1091
+
engines: {node: '>= 0.4'}
970
1092
971
-
is-stream@3.0.0:
972
-
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
973
-
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
1093
+
is-typed-array@1.1.15:
1094
+
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
1095
+
engines: {node: '>= 0.4'}
974
1096
975
-
is-string@1.0.7:
976
-
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
1097
+
is-weakmap@2.0.2:
1098
+
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
977
1099
engines: {node: '>= 0.4'}
978
1100
979
-
is-symbol@1.0.4:
980
-
resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
1101
+
is-weakref@1.1.1:
1102
+
resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
981
1103
engines: {node: '>= 0.4'}
982
1104
983
-
is-typed-array@1.1.12:
984
-
resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==}
1105
+
is-weakset@2.0.4:
1106
+
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
985
1107
engines: {node: '>= 0.4'}
986
1108
987
-
is-weakmap@2.0.1:
988
-
resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
989
-
990
-
is-weakref@1.0.2:
991
-
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
992
-
993
-
is-weakset@2.0.2:
994
-
resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
995
-
996
-
is-wsl@2.2.0:
997
-
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
998
-
engines: {node: '>=8'}
999
-
1000
1109
isarray@2.0.5:
1001
1110
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
1002
1111
1003
1112
isexe@2.0.0:
1004
1113
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1005
1114
1006
-
iterator.prototype@1.1.2:
1007
-
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
1115
+
iterator.prototype@1.1.5:
1116
+
resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
1117
+
engines: {node: '>= 0.4'}
1118
+
1119
+
jiti@2.4.2:
1120
+
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
1121
+
hasBin: true
1008
1122
1009
1123
js-tokens@4.0.0:
1010
1124
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
···
1044
1158
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
1045
1159
hasBin: true
1046
1160
1047
-
lru-cache@6.0.0:
1048
-
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
1049
-
engines: {node: '>=10'}
1050
-
1051
-
merge-stream@2.0.0:
1052
-
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
1161
+
math-intrinsics@1.1.0:
1162
+
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
1163
+
engines: {node: '>= 0.4'}
1053
1164
1054
1165
merge2@1.4.1:
1055
1166
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
···
1059
1170
resolution: {integrity: sha512-OyvYIOgpzXREySYJ1cqEb2pOKdeQMTfF9M8dRU6nC4hi/GXMmNpe9ssZCrSoTHazu05BSAoRBN/uYeco+ymfOg==}
1060
1171
engines: {node: '>=18.0.0'}
1061
1172
1062
-
micromatch@4.0.5:
1063
-
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
1064
-
engines: {node: '>=8.6'}
1173
+
microdiff@1.5.0:
1174
+
resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==}
1065
1175
1066
-
mimic-fn@2.1.0:
1067
-
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
1068
-
engines: {node: '>=6'}
1176
+
micromatch@4.0.8:
1177
+
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
1178
+
engines: {node: '>=8.6'}
1069
1179
1070
-
mimic-fn@4.0.0:
1071
-
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
1072
-
engines: {node: '>=12'}
1180
+
mimic-function@5.0.1:
1181
+
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
1182
+
engines: {node: '>=18'}
1073
1183
1074
1184
minimatch@3.1.2:
1075
1185
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
···
1078
1188
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
1079
1189
engines: {node: '>=16 || 14 >=14.17'}
1080
1190
1081
-
ms@2.1.2:
1082
-
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
1191
+
ms@2.1.3:
1192
+
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1083
1193
1084
1194
nanotar@0.1.1:
1085
1195
resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==}
···
1087
1197
natural-compare@1.4.0:
1088
1198
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
1089
1199
1090
-
npm-run-path@4.0.1:
1091
-
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
1092
-
engines: {node: '>=8'}
1093
-
1094
-
npm-run-path@5.1.0:
1095
-
resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
1096
-
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
1200
+
node-fetch-native@1.6.6:
1201
+
resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==}
1097
1202
1098
1203
object-assign@4.1.1:
1099
1204
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
1100
1205
engines: {node: '>=0.10.0'}
1101
1206
1102
-
object-inspect@1.13.1:
1103
-
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
1207
+
object-inspect@1.13.4:
1208
+
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
1209
+
engines: {node: '>= 0.4'}
1104
1210
1105
1211
object-keys@1.1.1:
1106
1212
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
1107
1213
engines: {node: '>= 0.4'}
1108
1214
1109
-
object.assign@4.1.5:
1110
-
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
1215
+
object.assign@4.1.7:
1216
+
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
1111
1217
engines: {node: '>= 0.4'}
1112
1218
1113
-
object.entries@1.1.7:
1114
-
resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==}
1219
+
object.entries@1.1.9:
1220
+
resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
1115
1221
engines: {node: '>= 0.4'}
1116
1222
1117
-
object.fromentries@2.0.7:
1118
-
resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==}
1223
+
object.fromentries@2.0.8:
1224
+
resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
1119
1225
engines: {node: '>= 0.4'}
1120
1226
1121
-
object.hasown@1.1.3:
1122
-
resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==}
1123
-
1124
-
object.values@1.1.7:
1125
-
resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==}
1227
+
object.values@1.2.1:
1228
+
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
1126
1229
engines: {node: '>= 0.4'}
1127
1230
1128
-
once@1.4.0:
1129
-
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
1231
+
ofetch@1.4.1:
1232
+
resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==}
1130
1233
1131
-
onetime@5.1.2:
1132
-
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
1133
-
engines: {node: '>=6'}
1134
-
1135
-
onetime@6.0.0:
1136
-
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
1137
-
engines: {node: '>=12'}
1138
-
1139
-
open@9.1.0:
1140
-
resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==}
1141
-
engines: {node: '>=14.16'}
1234
+
onetime@7.0.0:
1235
+
resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
1236
+
engines: {node: '>=18'}
1142
1237
1143
1238
optionator@0.9.3:
1144
1239
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
1145
1240
engines: {node: '>= 0.8.0'}
1146
1241
1242
+
own-keys@1.0.1:
1243
+
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
1244
+
engines: {node: '>= 0.4'}
1245
+
1147
1246
p-limit@3.1.0:
1148
1247
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
1149
1248
engines: {node: '>=10'}
···
1152
1251
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
1153
1252
engines: {node: '>=10'}
1154
1253
1254
+
package-manager-detector@1.1.0:
1255
+
resolution: {integrity: sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==}
1256
+
1155
1257
parent-module@1.0.1:
1156
1258
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
1157
1259
engines: {node: '>=6'}
···
1159
1261
path-exists@4.0.0:
1160
1262
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
1161
1263
engines: {node: '>=8'}
1162
-
1163
-
path-is-absolute@1.0.1:
1164
-
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
1165
-
engines: {node: '>=0.10.0'}
1166
1264
1167
1265
path-key@3.1.1:
1168
1266
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1169
1267
engines: {node: '>=8'}
1170
1268
1171
-
path-key@4.0.0:
1172
-
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
1173
-
engines: {node: '>=12'}
1174
-
1175
1269
path-parse@1.0.7:
1176
1270
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
1177
1271
1178
-
path-type@4.0.0:
1179
-
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
1180
-
engines: {node: '>=8'}
1181
-
1182
-
picocolors@1.0.0:
1183
-
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
1272
+
pathe@2.0.3:
1273
+
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
1184
1274
1185
1275
picomatch@2.3.1:
1186
1276
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1187
1277
engines: {node: '>=8.6'}
1278
+
1279
+
picomatch@4.0.2:
1280
+
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
1281
+
engines: {node: '>=12'}
1282
+
1283
+
pnpm-workspace-yaml@0.3.1:
1284
+
resolution: {integrity: sha512-3nW5RLmREmZ8Pm8MbPsO2RM+99RRjYd25ynj3NV0cFsN7CcEl4sDFzgoFmSyduFwxFQ2Qbu3y2UdCh6HlyUOeA==}
1285
+
1286
+
possible-typed-array-names@1.1.0:
1287
+
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
1288
+
engines: {node: '>= 0.4'}
1188
1289
1189
1290
prelude-ls@1.2.1:
1190
1291
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
···
1209
1310
punycode@2.3.1:
1210
1311
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
1211
1312
engines: {node: '>=6'}
1313
+
1314
+
quansync@0.2.10:
1315
+
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
1212
1316
1213
1317
queue-microtask@1.2.3:
1214
1318
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
···
1220
1324
resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==}
1221
1325
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1222
1326
1223
-
reflect.getprototypeof@1.0.4:
1224
-
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
1327
+
reflect.getprototypeof@1.0.10:
1328
+
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
1225
1329
engines: {node: '>= 0.4'}
1226
1330
1227
-
regexp.prototype.flags@1.5.1:
1228
-
resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
1331
+
regexp.prototype.flags@1.5.4:
1332
+
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
1229
1333
engines: {node: '>= 0.4'}
1230
1334
1231
1335
resolve-from@4.0.0:
···
1236
1340
resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
1237
1341
hasBin: true
1238
1342
1343
+
restore-cursor@5.1.0:
1344
+
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
1345
+
engines: {node: '>=18'}
1346
+
1239
1347
reusify@1.0.4:
1240
1348
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
1241
1349
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1242
-
1243
-
rimraf@3.0.2:
1244
-
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
1245
-
deprecated: Rimraf versions prior to v4 are no longer supported
1246
-
hasBin: true
1247
-
1248
-
run-applescript@5.0.0:
1249
-
resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
1250
-
engines: {node: '>=12'}
1251
1350
1252
1351
run-parallel@1.2.0:
1253
1352
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
1254
1353
1255
-
safe-array-concat@1.0.1:
1256
-
resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==}
1354
+
safe-array-concat@1.1.3:
1355
+
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
1257
1356
engines: {node: '>=0.4'}
1258
1357
1259
-
safe-buffer@5.1.2:
1260
-
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
1261
-
1262
1358
safe-buffer@5.2.1:
1263
1359
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
1264
1360
1265
-
safe-regex-test@1.0.0:
1266
-
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
1361
+
safe-push-apply@1.0.0:
1362
+
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
1363
+
engines: {node: '>= 0.4'}
1364
+
1365
+
safe-regex-test@1.1.0:
1366
+
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
1367
+
engines: {node: '>= 0.4'}
1267
1368
1268
1369
semver@6.3.1:
1269
1370
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
1270
1371
hasBin: true
1271
1372
1272
-
semver@7.5.4:
1273
-
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
1373
+
semver@7.7.1:
1374
+
resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
1274
1375
engines: {node: '>=10'}
1275
1376
hasBin: true
1276
1377
1277
-
set-function-length@1.1.1:
1278
-
resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
1378
+
set-function-length@1.2.2:
1379
+
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
1380
+
engines: {node: '>= 0.4'}
1381
+
1382
+
set-function-name@2.0.2:
1383
+
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
1279
1384
engines: {node: '>= 0.4'}
1280
1385
1281
-
set-function-name@2.0.1:
1282
-
resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==}
1386
+
set-proto@1.0.0:
1387
+
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
1283
1388
engines: {node: '>= 0.4'}
1284
1389
1285
1390
shebang-command@2.0.0:
···
1290
1395
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1291
1396
engines: {node: '>=8'}
1292
1397
1293
-
side-channel@1.0.4:
1294
-
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
1398
+
side-channel-list@1.0.0:
1399
+
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
1400
+
engines: {node: '>= 0.4'}
1295
1401
1296
-
signal-exit@3.0.7:
1297
-
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
1402
+
side-channel-map@1.0.1:
1403
+
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
1404
+
engines: {node: '>= 0.4'}
1298
1405
1299
-
slash@3.0.0:
1300
-
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
1301
-
engines: {node: '>=8'}
1406
+
side-channel-weakmap@1.0.2:
1407
+
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
1408
+
engines: {node: '>= 0.4'}
1409
+
1410
+
side-channel@1.1.0:
1411
+
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
1412
+
engines: {node: '>= 0.4'}
1413
+
1414
+
signal-exit@4.1.0:
1415
+
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
1416
+
engines: {node: '>=14'}
1302
1417
1303
1418
standalone-electron-types@1.0.0:
1304
1419
resolution: {integrity: sha512-0HOi/tlTz3mjWhsAz4uRbpQcHMZ+ifj1JzWW9nugykOHClBBG77ps8QinrzX1eow4Iw2pnC+RFaSYRgufF4BOg==}
1305
1420
1306
-
string.prototype.matchall@4.0.10:
1307
-
resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==}
1421
+
string.prototype.matchall@4.0.12:
1422
+
resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
1423
+
engines: {node: '>= 0.4'}
1308
1424
1309
-
string.prototype.trim@1.2.8:
1310
-
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
1425
+
string.prototype.repeat@1.0.0:
1426
+
resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
1427
+
1428
+
string.prototype.trim@1.2.10:
1429
+
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
1311
1430
engines: {node: '>= 0.4'}
1312
1431
1313
-
string.prototype.trimend@1.0.7:
1314
-
resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
1432
+
string.prototype.trimend@1.0.9:
1433
+
resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
1434
+
engines: {node: '>= 0.4'}
1315
1435
1316
-
string.prototype.trimstart@1.0.7:
1317
-
resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
1436
+
string.prototype.trimstart@1.0.8:
1437
+
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
1438
+
engines: {node: '>= 0.4'}
1318
1439
1319
1440
string_decoder@1.3.0:
1320
1441
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
1321
1442
1322
-
strip-ansi@6.0.1:
1323
-
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
1324
-
engines: {node: '>=8'}
1325
-
1326
-
strip-final-newline@2.0.0:
1327
-
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
1328
-
engines: {node: '>=6'}
1329
-
1330
-
strip-final-newline@3.0.0:
1331
-
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
1332
-
engines: {node: '>=12'}
1333
-
1334
1443
strip-json-comments@3.1.1:
1335
1444
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
1336
1445
engines: {node: '>=8'}
···
1343
1452
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
1344
1453
engines: {node: '>= 0.4'}
1345
1454
1346
-
synckit@0.8.6:
1347
-
resolution: {integrity: sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA==}
1455
+
synckit@0.11.1:
1456
+
resolution: {integrity: sha512-fWZqNBZNNFp/7mTUy1fSsydhKsAKJ+u90Nk7kOK5Gcq9vObaqLBLjWFDBkyVU9Vvc6Y71VbOevMuGhqv02bT+Q==}
1348
1457
engines: {node: ^14.18.0 || >=16.0.0}
1349
1458
1350
-
text-table@0.2.0:
1351
-
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
1459
+
taze@19.0.4:
1460
+
resolution: {integrity: sha512-bviyNotzqcIWpVBCC4QYVb2yupzKyUDGQi2m/8GERdiPaudVMtgAqaE98+x0cDDaByYRMJCyhQWM04ikUL6+kQ==}
1461
+
hasBin: true
1352
1462
1353
-
titleize@3.0.0:
1354
-
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
1355
-
engines: {node: '>=12'}
1463
+
tinyexec@1.0.1:
1464
+
resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==}
1465
+
1466
+
tinyglobby@0.2.12:
1467
+
resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
1468
+
engines: {node: '>=12.0.0'}
1356
1469
1357
1470
to-regex-range@5.0.1:
1358
1471
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1359
1472
engines: {node: '>=8.0'}
1360
1473
1361
-
ts-api-utils@1.0.3:
1362
-
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
1363
-
engines: {node: '>=16.13.0'}
1474
+
ts-api-utils@2.1.0:
1475
+
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
1476
+
engines: {node: '>=18.12'}
1364
1477
peerDependencies:
1365
-
typescript: '>=4.2.0'
1478
+
typescript: '>=4.8.4'
1366
1479
1367
-
tslib@2.6.2:
1368
-
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
1480
+
tslib@2.8.1:
1481
+
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1369
1482
1370
1483
type-check@0.4.0:
1371
1484
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
1372
1485
engines: {node: '>= 0.8.0'}
1373
1486
1374
-
type-fest@0.20.2:
1375
-
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
1376
-
engines: {node: '>=10'}
1487
+
typed-array-buffer@1.0.3:
1488
+
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
1489
+
engines: {node: '>= 0.4'}
1377
1490
1378
-
typed-array-buffer@1.0.0:
1379
-
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
1491
+
typed-array-byte-length@1.0.3:
1492
+
resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
1380
1493
engines: {node: '>= 0.4'}
1381
1494
1382
-
typed-array-byte-length@1.0.0:
1383
-
resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
1495
+
typed-array-byte-offset@1.0.4:
1496
+
resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
1384
1497
engines: {node: '>= 0.4'}
1385
1498
1386
-
typed-array-byte-offset@1.0.0:
1387
-
resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
1499
+
typed-array-length@1.0.7:
1500
+
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
1388
1501
engines: {node: '>= 0.4'}
1389
1502
1390
-
typed-array-length@1.0.4:
1391
-
resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
1503
+
typescript-eslint@8.29.0:
1504
+
resolution: {integrity: sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg==}
1505
+
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1506
+
peerDependencies:
1507
+
eslint: ^8.57.0 || ^9.0.0
1508
+
typescript: '>=4.8.4 <5.9.0'
1392
1509
1393
-
typescript@5.3.2:
1394
-
resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
1510
+
typescript@5.8.2:
1511
+
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
1395
1512
engines: {node: '>=14.17'}
1396
1513
hasBin: true
1397
1514
1398
-
unbox-primitive@1.0.2:
1399
-
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
1515
+
ufo@1.5.4:
1516
+
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
1517
+
1518
+
unbox-primitive@1.1.0:
1519
+
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
1520
+
engines: {node: '>= 0.4'}
1400
1521
1401
-
undici-types@6.19.8:
1402
-
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
1522
+
unconfig@7.3.1:
1523
+
resolution: {integrity: sha512-LH5WL+un92tGAzWS87k7LkAfwpMdm7V0IXG2FxEjZz/QxiIW5J5LkcrKQThj0aRz6+h/lFmKI9EUXmK/T0bcrw==}
1403
1524
1404
-
untildify@4.0.0:
1405
-
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
1406
-
engines: {node: '>=8'}
1525
+
undici-types@6.20.0:
1526
+
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
1527
+
1528
+
undici-types@6.21.0:
1529
+
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
1407
1530
1408
1531
uri-js@4.4.1:
1409
1532
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
1410
1533
1411
-
utilium@0.7.1:
1412
-
resolution: {integrity: sha512-2ocvTkI7U8LERmwxL0LhFUvEfN66UqcjF6tMiURvUwSyU7U1QC9gST+3iSUSiGccFfnP3f2EXwHNXOnOzx+lAg==}
1534
+
utilium@1.10.1:
1535
+
resolution: {integrity: sha512-GQINDTb/ocyz4acQj3GXAe0wipYxws6L+9ouqaq10KlInTk9DGvW9TJd0pYa/Xu3cppNnZuB4T/sBuSXpcN2ng==}
1413
1536
1414
-
which-boxed-primitive@1.0.2:
1415
-
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
1537
+
which-boxed-primitive@1.1.1:
1538
+
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
1539
+
engines: {node: '>= 0.4'}
1416
1540
1417
-
which-builtin-type@1.1.3:
1418
-
resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==}
1541
+
which-builtin-type@1.2.1:
1542
+
resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
1419
1543
engines: {node: '>= 0.4'}
1420
1544
1421
-
which-collection@1.0.1:
1422
-
resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
1545
+
which-collection@1.0.2:
1546
+
resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
1547
+
engines: {node: '>= 0.4'}
1423
1548
1424
-
which-typed-array@1.1.13:
1425
-
resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==}
1549
+
which-typed-array@1.1.19:
1550
+
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
1426
1551
engines: {node: '>= 0.4'}
1427
1552
1428
1553
which@2.0.2:
···
1430
1555
engines: {node: '>= 8'}
1431
1556
hasBin: true
1432
1557
1433
-
wrappy@1.0.2:
1434
-
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
1435
-
1436
-
yallist@4.0.0:
1437
-
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
1558
+
yaml@2.7.1:
1559
+
resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
1560
+
engines: {node: '>= 14'}
1561
+
hasBin: true
1438
1562
1439
1563
yocto-queue@0.1.0:
1440
1564
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
1441
1565
engines: {node: '>=10'}
1442
1566
1567
+
zustand@5.0.3:
1568
+
resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==}
1569
+
engines: {node: '>=12.20.0'}
1570
+
peerDependencies:
1571
+
'@types/react': '>=18.0.0'
1572
+
immer: '>=9.0.6'
1573
+
react: '>=18.0.0'
1574
+
use-sync-external-store: '>=1.2.0'
1575
+
peerDependenciesMeta:
1576
+
'@types/react':
1577
+
optional: true
1578
+
immer:
1579
+
optional: true
1580
+
react:
1581
+
optional: true
1582
+
use-sync-external-store:
1583
+
optional: true
1584
+
1443
1585
snapshots:
1444
1586
1445
1587
'@aashutoshrathi/word-wrap@1.2.6': {}
1588
+
1589
+
'@antfu/ni@24.3.0':
1590
+
dependencies:
1591
+
ansis: 3.17.0
1592
+
fzf: 0.5.2
1593
+
package-manager-detector: 1.1.0
1594
+
tinyexec: 1.0.1
1446
1595
1447
1596
'@esbuild/android-arm64@0.19.3':
1448
1597
optional: true
···
1510
1659
'@esbuild/win32-x64@0.19.3':
1511
1660
optional: true
1512
1661
1513
-
'@eslint-community/eslint-utils@4.4.0(eslint@8.55.0)':
1662
+
'@eslint-community/eslint-utils@4.5.1(eslint@9.23.0(jiti@2.4.2))':
1514
1663
dependencies:
1515
-
eslint: 8.55.0
1664
+
eslint: 9.23.0(jiti@2.4.2)
1516
1665
eslint-visitor-keys: 3.4.3
1517
1666
1518
-
'@eslint-community/regexpp@4.10.0': {}
1667
+
'@eslint-community/regexpp@4.12.1': {}
1519
1668
1520
-
'@eslint/eslintrc@2.1.4':
1669
+
'@eslint/config-array@0.19.2':
1670
+
dependencies:
1671
+
'@eslint/object-schema': 2.1.6
1672
+
debug: 4.4.0
1673
+
minimatch: 3.1.2
1674
+
transitivePeerDependencies:
1675
+
- supports-color
1676
+
1677
+
'@eslint/config-helpers@0.2.1': {}
1678
+
1679
+
'@eslint/core@0.12.0':
1680
+
dependencies:
1681
+
'@types/json-schema': 7.0.15
1682
+
1683
+
'@eslint/core@0.13.0':
1684
+
dependencies:
1685
+
'@types/json-schema': 7.0.15
1686
+
1687
+
'@eslint/eslintrc@3.3.1':
1521
1688
dependencies:
1522
1689
ajv: 6.12.6
1523
-
debug: 4.3.4
1524
-
espree: 9.6.1
1525
-
globals: 13.23.0
1526
-
ignore: 5.3.0
1690
+
debug: 4.4.0
1691
+
espree: 10.3.0
1692
+
globals: 14.0.0
1693
+
ignore: 5.3.2
1527
1694
import-fresh: 3.3.0
1528
1695
js-yaml: 4.1.0
1529
1696
minimatch: 3.1.2
···
1531
1698
transitivePeerDependencies:
1532
1699
- supports-color
1533
1700
1534
-
'@eslint/js@8.55.0': {}
1701
+
'@eslint/js@9.23.0': {}
1702
+
1703
+
'@eslint/object-schema@2.1.6': {}
1535
1704
1536
-
'@humanwhocodes/config-array@0.11.13':
1705
+
'@eslint/plugin-kit@0.2.8':
1537
1706
dependencies:
1538
-
'@humanwhocodes/object-schema': 2.0.1
1539
-
debug: 4.3.4
1540
-
minimatch: 3.1.2
1541
-
transitivePeerDependencies:
1542
-
- supports-color
1707
+
'@eslint/core': 0.13.0
1708
+
levn: 0.4.1
1709
+
1710
+
'@humanfs/core@0.19.1': {}
1711
+
1712
+
'@humanfs/node@0.16.6':
1713
+
dependencies:
1714
+
'@humanfs/core': 0.19.1
1715
+
'@humanwhocodes/retry': 0.3.1
1543
1716
1544
1717
'@humanwhocodes/module-importer@1.0.1': {}
1545
1718
1546
-
'@humanwhocodes/object-schema@2.0.1': {}
1719
+
'@humanwhocodes/retry@0.3.1': {}
1720
+
1721
+
'@humanwhocodes/retry@0.4.2': {}
1547
1722
1548
-
'@moonlight-mod/lunast@1.0.0':
1723
+
'@moonlight-mod/eslint-config@https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/e262ac24e1a0955a9b3e0d66da247a0a8c0446c9(@types/eslint@9.6.1)(eslint@9.23.0(jiti@2.4.2))(prettier@3.1.0)(typescript@5.8.2)':
1724
+
dependencies:
1725
+
'@eslint/js': 9.23.0
1726
+
eslint: 9.23.0(jiti@2.4.2)
1727
+
eslint-config-prettier: 9.1.0(eslint@9.23.0(jiti@2.4.2))
1728
+
eslint-plugin-prettier: 5.2.6(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.23.0(jiti@2.4.2)))(eslint@9.23.0(jiti@2.4.2))(prettier@3.1.0)
1729
+
eslint-plugin-react: 7.37.5(eslint@9.23.0(jiti@2.4.2))
1730
+
typescript: 5.8.2
1731
+
typescript-eslint: 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
1732
+
transitivePeerDependencies:
1733
+
- '@types/eslint'
1734
+
- prettier
1735
+
- supports-color
1736
+
1737
+
'@moonlight-mod/lunast@1.0.1':
1549
1738
dependencies:
1550
1739
astring: 1.9.0
1551
1740
estree-toolkit: 1.7.8
1552
1741
meriyah: 6.0.1
1553
1742
1554
-
'@moonlight-mod/mappings@1.0.2(@moonlight-mod/lunast@1.0.0)(@moonlight-mod/moonmap@1.0.2)':
1743
+
'@moonlight-mod/mappings@1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)':
1555
1744
dependencies:
1556
-
'@moonlight-mod/lunast': 1.0.0
1557
-
'@moonlight-mod/moonmap': 1.0.2
1745
+
'@moonlight-mod/lunast': 1.0.1
1746
+
'@moonlight-mod/moonmap': 1.0.5
1747
+
'@types/chroma-js': 3.1.0
1558
1748
'@types/flux': 3.1.14
1559
-
'@types/react': 18.3.10
1749
+
'@types/highlightjs': 9.12.6
1750
+
'@types/lodash': 4.17.14
1751
+
'@types/platform': 1.3.6
1752
+
'@types/react': 18.3.20
1560
1753
csstype: 3.1.3
1754
+
zustand: 5.0.3(@types/react@18.3.20)
1755
+
transitivePeerDependencies:
1756
+
- immer
1757
+
- react
1758
+
- use-sync-external-store
1561
1759
1562
-
'@moonlight-mod/moonmap@1.0.2': {}
1760
+
'@moonlight-mod/moonmap@1.0.5': {}
1563
1761
1564
1762
'@nodelib/fs.scandir@2.1.5':
1565
1763
dependencies:
···
1571
1769
'@nodelib/fs.walk@1.2.8':
1572
1770
dependencies:
1573
1771
'@nodelib/fs.scandir': 2.1.5
1574
-
fastq: 1.15.0
1772
+
fastq: 1.17.1
1773
+
1774
+
'@pkgr/core@0.2.0': {}
1575
1775
1576
-
'@pkgr/utils@2.4.2':
1776
+
'@quansync/fs@0.1.2':
1577
1777
dependencies:
1578
-
cross-spawn: 7.0.3
1579
-
fast-glob: 3.3.2
1580
-
is-glob: 4.0.3
1581
-
open: 9.1.0
1582
-
picocolors: 1.0.0
1583
-
tslib: 2.6.2
1778
+
quansync: 0.2.10
1779
+
1780
+
'@types/chroma-js@3.1.0': {}
1781
+
1782
+
'@types/chrome@0.0.313':
1783
+
dependencies:
1784
+
'@types/filesystem': 0.0.36
1785
+
'@types/har-format': 1.2.16
1786
+
1787
+
'@types/eslint@9.6.1':
1788
+
dependencies:
1789
+
'@types/estree': 1.0.7
1790
+
'@types/json-schema': 7.0.15
1791
+
optional: true
1584
1792
1585
1793
'@types/estree-jsx@1.0.5':
1586
1794
dependencies:
···
1588
1796
1589
1797
'@types/estree@1.0.6': {}
1590
1798
1799
+
'@types/estree@1.0.7':
1800
+
optional: true
1801
+
1591
1802
'@types/fbemitter@2.0.35': {}
1592
1803
1804
+
'@types/filesystem@0.0.36':
1805
+
dependencies:
1806
+
'@types/filewriter': 0.0.33
1807
+
1808
+
'@types/filewriter@0.0.33': {}
1809
+
1593
1810
'@types/flux@3.1.14':
1594
1811
dependencies:
1595
1812
'@types/fbemitter': 2.0.35
1596
-
'@types/react': 18.3.10
1813
+
'@types/react': 18.3.20
1814
+
1815
+
'@types/har-format@1.2.16': {}
1816
+
1817
+
'@types/highlightjs@9.12.6': {}
1597
1818
1598
1819
'@types/json-schema@7.0.15': {}
1599
1820
1821
+
'@types/lodash@4.17.14': {}
1822
+
1600
1823
'@types/node@18.17.17': {}
1601
1824
1602
-
'@types/node@20.16.10':
1825
+
'@types/node@22.13.6':
1826
+
dependencies:
1827
+
undici-types: 6.20.0
1828
+
1829
+
'@types/node@22.14.0':
1603
1830
dependencies:
1604
-
undici-types: 6.19.8
1831
+
undici-types: 6.21.0
1832
+
1833
+
'@types/platform@1.3.6': {}
1605
1834
1606
1835
'@types/prop-types@15.7.13': {}
1607
1836
1608
-
'@types/react@18.3.10':
1837
+
'@types/react@18.3.20':
1609
1838
dependencies:
1610
1839
'@types/prop-types': 15.7.13
1611
1840
csstype: 3.1.3
1612
1841
1613
-
'@types/readable-stream@4.0.15':
1842
+
'@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
1614
1843
dependencies:
1615
-
'@types/node': 20.16.10
1616
-
safe-buffer: 5.1.2
1617
-
1618
-
'@types/semver@7.5.6': {}
1619
-
1620
-
'@typescript-eslint/eslint-plugin@6.13.2(@typescript-eslint/parser@6.13.2(eslint@8.55.0)(typescript@5.3.2))(eslint@8.55.0)(typescript@5.3.2)':
1621
-
dependencies:
1622
-
'@eslint-community/regexpp': 4.10.0
1623
-
'@typescript-eslint/parser': 6.13.2(eslint@8.55.0)(typescript@5.3.2)
1624
-
'@typescript-eslint/scope-manager': 6.13.2
1625
-
'@typescript-eslint/type-utils': 6.13.2(eslint@8.55.0)(typescript@5.3.2)
1626
-
'@typescript-eslint/utils': 6.13.2(eslint@8.55.0)(typescript@5.3.2)
1627
-
'@typescript-eslint/visitor-keys': 6.13.2
1628
-
debug: 4.3.4
1629
-
eslint: 8.55.0
1844
+
'@eslint-community/regexpp': 4.12.1
1845
+
'@typescript-eslint/parser': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
1846
+
'@typescript-eslint/scope-manager': 8.29.0
1847
+
'@typescript-eslint/type-utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
1848
+
'@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
1849
+
'@typescript-eslint/visitor-keys': 8.29.0
1850
+
eslint: 9.23.0(jiti@2.4.2)
1630
1851
graphemer: 1.4.0
1631
-
ignore: 5.3.0
1852
+
ignore: 5.3.2
1632
1853
natural-compare: 1.4.0
1633
-
semver: 7.5.4
1634
-
ts-api-utils: 1.0.3(typescript@5.3.2)
1635
-
optionalDependencies:
1636
-
typescript: 5.3.2
1854
+
ts-api-utils: 2.1.0(typescript@5.8.2)
1855
+
typescript: 5.8.2
1637
1856
transitivePeerDependencies:
1638
1857
- supports-color
1639
1858
1640
-
'@typescript-eslint/parser@6.13.2(eslint@8.55.0)(typescript@5.3.2)':
1859
+
'@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
1641
1860
dependencies:
1642
-
'@typescript-eslint/scope-manager': 6.13.2
1643
-
'@typescript-eslint/types': 6.13.2
1644
-
'@typescript-eslint/typescript-estree': 6.13.2(typescript@5.3.2)
1645
-
'@typescript-eslint/visitor-keys': 6.13.2
1646
-
debug: 4.3.4
1647
-
eslint: 8.55.0
1648
-
optionalDependencies:
1649
-
typescript: 5.3.2
1861
+
'@typescript-eslint/scope-manager': 8.29.0
1862
+
'@typescript-eslint/types': 8.29.0
1863
+
'@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2)
1864
+
'@typescript-eslint/visitor-keys': 8.29.0
1865
+
debug: 4.4.0
1866
+
eslint: 9.23.0(jiti@2.4.2)
1867
+
typescript: 5.8.2
1650
1868
transitivePeerDependencies:
1651
1869
- supports-color
1652
1870
1653
-
'@typescript-eslint/scope-manager@6.13.2':
1871
+
'@typescript-eslint/scope-manager@8.29.0':
1654
1872
dependencies:
1655
-
'@typescript-eslint/types': 6.13.2
1656
-
'@typescript-eslint/visitor-keys': 6.13.2
1873
+
'@typescript-eslint/types': 8.29.0
1874
+
'@typescript-eslint/visitor-keys': 8.29.0
1657
1875
1658
-
'@typescript-eslint/type-utils@6.13.2(eslint@8.55.0)(typescript@5.3.2)':
1876
+
'@typescript-eslint/type-utils@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
1659
1877
dependencies:
1660
-
'@typescript-eslint/typescript-estree': 6.13.2(typescript@5.3.2)
1661
-
'@typescript-eslint/utils': 6.13.2(eslint@8.55.0)(typescript@5.3.2)
1662
-
debug: 4.3.4
1663
-
eslint: 8.55.0
1664
-
ts-api-utils: 1.0.3(typescript@5.3.2)
1665
-
optionalDependencies:
1666
-
typescript: 5.3.2
1878
+
'@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2)
1879
+
'@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
1880
+
debug: 4.4.0
1881
+
eslint: 9.23.0(jiti@2.4.2)
1882
+
ts-api-utils: 2.1.0(typescript@5.8.2)
1883
+
typescript: 5.8.2
1667
1884
transitivePeerDependencies:
1668
1885
- supports-color
1669
1886
1670
-
'@typescript-eslint/types@6.13.2': {}
1887
+
'@typescript-eslint/types@8.29.0': {}
1671
1888
1672
-
'@typescript-eslint/typescript-estree@6.13.2(typescript@5.3.2)':
1889
+
'@typescript-eslint/typescript-estree@8.29.0(typescript@5.8.2)':
1673
1890
dependencies:
1674
-
'@typescript-eslint/types': 6.13.2
1675
-
'@typescript-eslint/visitor-keys': 6.13.2
1676
-
debug: 4.3.4
1677
-
globby: 11.1.0
1891
+
'@typescript-eslint/types': 8.29.0
1892
+
'@typescript-eslint/visitor-keys': 8.29.0
1893
+
debug: 4.4.0
1894
+
fast-glob: 3.3.2
1678
1895
is-glob: 4.0.3
1679
-
semver: 7.5.4
1680
-
ts-api-utils: 1.0.3(typescript@5.3.2)
1681
-
optionalDependencies:
1682
-
typescript: 5.3.2
1896
+
minimatch: 9.0.5
1897
+
semver: 7.7.1
1898
+
ts-api-utils: 2.1.0(typescript@5.8.2)
1899
+
typescript: 5.8.2
1683
1900
transitivePeerDependencies:
1684
1901
- supports-color
1685
1902
1686
-
'@typescript-eslint/utils@6.13.2(eslint@8.55.0)(typescript@5.3.2)':
1903
+
'@typescript-eslint/utils@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
1687
1904
dependencies:
1688
-
'@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
1689
-
'@types/json-schema': 7.0.15
1690
-
'@types/semver': 7.5.6
1691
-
'@typescript-eslint/scope-manager': 6.13.2
1692
-
'@typescript-eslint/types': 6.13.2
1693
-
'@typescript-eslint/typescript-estree': 6.13.2(typescript@5.3.2)
1694
-
eslint: 8.55.0
1695
-
semver: 7.5.4
1905
+
'@eslint-community/eslint-utils': 4.5.1(eslint@9.23.0(jiti@2.4.2))
1906
+
'@typescript-eslint/scope-manager': 8.29.0
1907
+
'@typescript-eslint/types': 8.29.0
1908
+
'@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2)
1909
+
eslint: 9.23.0(jiti@2.4.2)
1910
+
typescript: 5.8.2
1696
1911
transitivePeerDependencies:
1697
1912
- supports-color
1698
-
- typescript
1699
1913
1700
-
'@typescript-eslint/visitor-keys@6.13.2':
1914
+
'@typescript-eslint/visitor-keys@8.29.0':
1701
1915
dependencies:
1702
-
'@typescript-eslint/types': 6.13.2
1703
-
eslint-visitor-keys: 3.4.3
1916
+
'@typescript-eslint/types': 8.29.0
1917
+
eslint-visitor-keys: 4.2.0
1704
1918
1705
-
'@ungap/structured-clone@1.2.0': {}
1919
+
'@xterm/xterm@5.5.0':
1920
+
optional: true
1706
1921
1707
-
'@zenfs/core@1.0.2':
1922
+
'@zenfs/core@2.0.0':
1708
1923
dependencies:
1709
-
'@types/node': 20.16.10
1710
-
'@types/readable-stream': 4.0.15
1924
+
'@types/node': 22.13.6
1711
1925
buffer: 6.0.3
1712
1926
eventemitter3: 5.0.1
1713
-
minimatch: 9.0.5
1714
1927
readable-stream: 4.5.2
1715
-
utilium: 0.7.1
1928
+
utilium: 1.10.1
1716
1929
1717
-
'@zenfs/dom@0.2.16(@zenfs/core@1.0.2)':
1930
+
'@zenfs/dom@1.1.6(@zenfs/core@2.0.0)(utilium@1.10.1)':
1718
1931
dependencies:
1719
-
'@zenfs/core': 1.0.2
1932
+
'@zenfs/core': 2.0.0
1933
+
utilium: 1.10.1
1720
1934
1721
1935
abort-controller@3.0.0:
1722
1936
dependencies:
1723
1937
event-target-shim: 5.0.1
1724
1938
1725
-
acorn-jsx@5.3.2(acorn@8.12.1):
1939
+
acorn-jsx@5.3.2(acorn@8.14.1):
1726
1940
dependencies:
1727
-
acorn: 8.12.1
1941
+
acorn: 8.14.1
1728
1942
1729
-
acorn@8.12.1: {}
1943
+
acorn@8.14.1: {}
1730
1944
1731
1945
ajv@6.12.6:
1732
1946
dependencies:
···
1734
1948
fast-json-stable-stringify: 2.1.0
1735
1949
json-schema-traverse: 0.4.1
1736
1950
uri-js: 4.4.1
1737
-
1738
-
ansi-regex@5.0.1: {}
1739
1951
1740
1952
ansi-styles@4.3.0:
1741
1953
dependencies:
1742
1954
color-convert: 2.0.1
1743
1955
1956
+
ansis@3.17.0: {}
1957
+
1744
1958
argparse@2.0.1: {}
1745
1959
1746
-
array-buffer-byte-length@1.0.0:
1960
+
array-buffer-byte-length@1.0.2:
1747
1961
dependencies:
1748
-
call-bind: 1.0.5
1749
-
is-array-buffer: 3.0.2
1962
+
call-bound: 1.0.4
1963
+
is-array-buffer: 3.0.5
1750
1964
1751
-
array-includes@3.1.7:
1965
+
array-includes@3.1.8:
1752
1966
dependencies:
1753
-
call-bind: 1.0.5
1967
+
call-bind: 1.0.8
1754
1968
define-properties: 1.2.1
1755
-
es-abstract: 1.22.3
1756
-
get-intrinsic: 1.2.2
1757
-
is-string: 1.0.7
1969
+
es-abstract: 1.23.9
1970
+
es-object-atoms: 1.1.1
1971
+
get-intrinsic: 1.3.0
1972
+
is-string: 1.1.1
1758
1973
1759
-
array-union@2.1.0: {}
1974
+
array.prototype.findlast@1.2.5:
1975
+
dependencies:
1976
+
call-bind: 1.0.8
1977
+
define-properties: 1.2.1
1978
+
es-abstract: 1.23.9
1979
+
es-errors: 1.3.0
1980
+
es-object-atoms: 1.1.1
1981
+
es-shim-unscopables: 1.1.0
1760
1982
1761
-
array.prototype.flat@1.3.2:
1983
+
array.prototype.flat@1.3.3:
1762
1984
dependencies:
1763
-
call-bind: 1.0.5
1985
+
call-bind: 1.0.8
1764
1986
define-properties: 1.2.1
1765
-
es-abstract: 1.22.3
1766
-
es-shim-unscopables: 1.0.2
1987
+
es-abstract: 1.23.9
1988
+
es-shim-unscopables: 1.1.0
1767
1989
1768
-
array.prototype.flatmap@1.3.2:
1990
+
array.prototype.flatmap@1.3.3:
1769
1991
dependencies:
1770
-
call-bind: 1.0.5
1992
+
call-bind: 1.0.8
1771
1993
define-properties: 1.2.1
1772
-
es-abstract: 1.22.3
1773
-
es-shim-unscopables: 1.0.2
1994
+
es-abstract: 1.23.9
1995
+
es-shim-unscopables: 1.1.0
1774
1996
1775
-
array.prototype.tosorted@1.1.2:
1997
+
array.prototype.tosorted@1.1.4:
1776
1998
dependencies:
1777
-
call-bind: 1.0.5
1999
+
call-bind: 1.0.8
1778
2000
define-properties: 1.2.1
1779
-
es-abstract: 1.22.3
1780
-
es-shim-unscopables: 1.0.2
1781
-
get-intrinsic: 1.2.2
2001
+
es-abstract: 1.23.9
2002
+
es-errors: 1.3.0
2003
+
es-shim-unscopables: 1.1.0
1782
2004
1783
-
arraybuffer.prototype.slice@1.0.2:
2005
+
arraybuffer.prototype.slice@1.0.4:
1784
2006
dependencies:
1785
-
array-buffer-byte-length: 1.0.0
1786
-
call-bind: 1.0.5
2007
+
array-buffer-byte-length: 1.0.2
2008
+
call-bind: 1.0.8
1787
2009
define-properties: 1.2.1
1788
-
es-abstract: 1.22.3
1789
-
get-intrinsic: 1.2.2
1790
-
is-array-buffer: 3.0.2
1791
-
is-shared-array-buffer: 1.0.2
2010
+
es-abstract: 1.23.9
2011
+
es-errors: 1.3.0
2012
+
get-intrinsic: 1.3.0
2013
+
is-array-buffer: 3.0.5
1792
2014
1793
2015
astring@1.9.0: {}
1794
2016
1795
-
asynciterator.prototype@1.0.0:
1796
-
dependencies:
1797
-
has-symbols: 1.0.3
2017
+
async-function@1.0.0: {}
1798
2018
1799
-
available-typed-arrays@1.0.5: {}
2019
+
available-typed-arrays@1.0.7:
2020
+
dependencies:
2021
+
possible-typed-array-names: 1.1.0
1800
2022
1801
2023
balanced-match@1.0.2: {}
1802
2024
1803
2025
base64-js@1.5.1: {}
1804
2026
1805
-
big-integer@1.6.52: {}
1806
-
1807
-
bplist-parser@0.2.0:
1808
-
dependencies:
1809
-
big-integer: 1.6.52
1810
-
1811
2027
brace-expansion@1.1.11:
1812
2028
dependencies:
1813
2029
balanced-match: 1.0.2
···
1817
2033
dependencies:
1818
2034
balanced-match: 1.0.2
1819
2035
1820
-
braces@3.0.2:
2036
+
braces@3.0.3:
1821
2037
dependencies:
1822
-
fill-range: 7.0.1
2038
+
fill-range: 7.1.1
1823
2039
1824
2040
buffer@6.0.3:
1825
2041
dependencies:
1826
2042
base64-js: 1.5.1
1827
2043
ieee754: 1.2.1
1828
2044
1829
-
bundle-name@3.0.0:
1830
-
dependencies:
1831
-
run-applescript: 5.0.0
2045
+
cac@6.7.14: {}
1832
2046
1833
-
call-bind@1.0.5:
2047
+
call-bind-apply-helpers@1.0.2:
1834
2048
dependencies:
2049
+
es-errors: 1.3.0
1835
2050
function-bind: 1.1.2
1836
-
get-intrinsic: 1.2.2
1837
-
set-function-length: 1.1.1
2051
+
2052
+
call-bind@1.0.8:
2053
+
dependencies:
2054
+
call-bind-apply-helpers: 1.0.2
2055
+
es-define-property: 1.0.1
2056
+
get-intrinsic: 1.3.0
2057
+
set-function-length: 1.2.2
2058
+
2059
+
call-bound@1.0.4:
2060
+
dependencies:
2061
+
call-bind-apply-helpers: 1.0.2
2062
+
get-intrinsic: 1.3.0
1838
2063
1839
2064
callsites@3.1.0: {}
1840
2065
···
1851
2076
1852
2077
concat-map@0.0.1: {}
1853
2078
1854
-
cross-spawn@7.0.3:
2079
+
cross-spawn@7.0.6:
1855
2080
dependencies:
1856
2081
path-key: 3.1.1
1857
2082
shebang-command: 2.0.0
1858
2083
which: 2.0.2
1859
2084
1860
-
csstype@3.1.2: {}
1861
-
1862
2085
csstype@3.1.3: {}
1863
2086
1864
-
debug@4.3.4:
2087
+
data-view-buffer@1.0.2:
1865
2088
dependencies:
1866
-
ms: 2.1.2
1867
-
1868
-
deep-is@0.1.4: {}
2089
+
call-bound: 1.0.4
2090
+
es-errors: 1.3.0
2091
+
is-data-view: 1.0.2
1869
2092
1870
-
default-browser-id@3.0.0:
2093
+
data-view-byte-length@1.0.2:
1871
2094
dependencies:
1872
-
bplist-parser: 0.2.0
1873
-
untildify: 4.0.0
2095
+
call-bound: 1.0.4
2096
+
es-errors: 1.3.0
2097
+
is-data-view: 1.0.2
1874
2098
1875
-
default-browser@4.0.0:
2099
+
data-view-byte-offset@1.0.1:
1876
2100
dependencies:
1877
-
bundle-name: 3.0.0
1878
-
default-browser-id: 3.0.0
1879
-
execa: 7.2.0
1880
-
titleize: 3.0.0
2101
+
call-bound: 1.0.4
2102
+
es-errors: 1.3.0
2103
+
is-data-view: 1.0.2
1881
2104
1882
-
define-data-property@1.1.1:
2105
+
debug@4.4.0:
1883
2106
dependencies:
1884
-
get-intrinsic: 1.2.2
1885
-
gopd: 1.0.1
1886
-
has-property-descriptors: 1.0.1
2107
+
ms: 2.1.3
1887
2108
1888
-
define-lazy-prop@3.0.0: {}
2109
+
deep-is@0.1.4: {}
2110
+
2111
+
define-data-property@1.1.4:
2112
+
dependencies:
2113
+
es-define-property: 1.0.1
2114
+
es-errors: 1.3.0
2115
+
gopd: 1.2.0
1889
2116
1890
2117
define-properties@1.2.1:
1891
2118
dependencies:
1892
-
define-data-property: 1.1.1
1893
-
has-property-descriptors: 1.0.1
2119
+
define-data-property: 1.1.4
2120
+
has-property-descriptors: 1.0.2
1894
2121
object-keys: 1.1.1
1895
2122
1896
-
dir-glob@3.0.1:
1897
-
dependencies:
1898
-
path-type: 4.0.0
2123
+
defu@6.1.4: {}
2124
+
2125
+
destr@2.0.4: {}
1899
2126
1900
2127
doctrine@2.1.0:
1901
2128
dependencies:
1902
2129
esutils: 2.0.3
1903
2130
1904
-
doctrine@3.0.0:
2131
+
dunder-proto@1.0.1:
1905
2132
dependencies:
1906
-
esutils: 2.0.3
2133
+
call-bind-apply-helpers: 1.0.2
2134
+
es-errors: 1.3.0
2135
+
gopd: 1.2.0
1907
2136
1908
-
es-abstract@1.22.3:
2137
+
es-abstract@1.23.9:
1909
2138
dependencies:
1910
-
array-buffer-byte-length: 1.0.0
1911
-
arraybuffer.prototype.slice: 1.0.2
1912
-
available-typed-arrays: 1.0.5
1913
-
call-bind: 1.0.5
1914
-
es-set-tostringtag: 2.0.2
1915
-
es-to-primitive: 1.2.1
1916
-
function.prototype.name: 1.1.6
1917
-
get-intrinsic: 1.2.2
1918
-
get-symbol-description: 1.0.0
1919
-
globalthis: 1.0.3
1920
-
gopd: 1.0.1
1921
-
has-property-descriptors: 1.0.1
1922
-
has-proto: 1.0.1
1923
-
has-symbols: 1.0.3
1924
-
hasown: 2.0.0
1925
-
internal-slot: 1.0.6
1926
-
is-array-buffer: 3.0.2
2139
+
array-buffer-byte-length: 1.0.2
2140
+
arraybuffer.prototype.slice: 1.0.4
2141
+
available-typed-arrays: 1.0.7
2142
+
call-bind: 1.0.8
2143
+
call-bound: 1.0.4
2144
+
data-view-buffer: 1.0.2
2145
+
data-view-byte-length: 1.0.2
2146
+
data-view-byte-offset: 1.0.1
2147
+
es-define-property: 1.0.1
2148
+
es-errors: 1.3.0
2149
+
es-object-atoms: 1.1.1
2150
+
es-set-tostringtag: 2.1.0
2151
+
es-to-primitive: 1.3.0
2152
+
function.prototype.name: 1.1.8
2153
+
get-intrinsic: 1.3.0
2154
+
get-proto: 1.0.1
2155
+
get-symbol-description: 1.1.0
2156
+
globalthis: 1.0.4
2157
+
gopd: 1.2.0
2158
+
has-property-descriptors: 1.0.2
2159
+
has-proto: 1.2.0
2160
+
has-symbols: 1.1.0
2161
+
hasown: 2.0.2
2162
+
internal-slot: 1.1.0
2163
+
is-array-buffer: 3.0.5
1927
2164
is-callable: 1.2.7
1928
-
is-negative-zero: 2.0.2
1929
-
is-regex: 1.1.4
1930
-
is-shared-array-buffer: 1.0.2
1931
-
is-string: 1.0.7
1932
-
is-typed-array: 1.1.12
1933
-
is-weakref: 1.0.2
1934
-
object-inspect: 1.13.1
2165
+
is-data-view: 1.0.2
2166
+
is-regex: 1.2.1
2167
+
is-shared-array-buffer: 1.0.4
2168
+
is-string: 1.1.1
2169
+
is-typed-array: 1.1.15
2170
+
is-weakref: 1.1.1
2171
+
math-intrinsics: 1.1.0
2172
+
object-inspect: 1.13.4
1935
2173
object-keys: 1.1.1
1936
-
object.assign: 4.1.5
1937
-
regexp.prototype.flags: 1.5.1
1938
-
safe-array-concat: 1.0.1
1939
-
safe-regex-test: 1.0.0
1940
-
string.prototype.trim: 1.2.8
1941
-
string.prototype.trimend: 1.0.7
1942
-
string.prototype.trimstart: 1.0.7
1943
-
typed-array-buffer: 1.0.0
1944
-
typed-array-byte-length: 1.0.0
1945
-
typed-array-byte-offset: 1.0.0
1946
-
typed-array-length: 1.0.4
1947
-
unbox-primitive: 1.0.2
1948
-
which-typed-array: 1.1.13
2174
+
object.assign: 4.1.7
2175
+
own-keys: 1.0.1
2176
+
regexp.prototype.flags: 1.5.4
2177
+
safe-array-concat: 1.1.3
2178
+
safe-push-apply: 1.0.0
2179
+
safe-regex-test: 1.1.0
2180
+
set-proto: 1.0.0
2181
+
string.prototype.trim: 1.2.10
2182
+
string.prototype.trimend: 1.0.9
2183
+
string.prototype.trimstart: 1.0.8
2184
+
typed-array-buffer: 1.0.3
2185
+
typed-array-byte-length: 1.0.3
2186
+
typed-array-byte-offset: 1.0.4
2187
+
typed-array-length: 1.0.7
2188
+
unbox-primitive: 1.1.0
2189
+
which-typed-array: 1.1.19
2190
+
2191
+
es-define-property@1.0.1: {}
2192
+
2193
+
es-errors@1.3.0: {}
1949
2194
1950
-
es-iterator-helpers@1.0.15:
2195
+
es-iterator-helpers@1.2.1:
1951
2196
dependencies:
1952
-
asynciterator.prototype: 1.0.0
1953
-
call-bind: 1.0.5
2197
+
call-bind: 1.0.8
2198
+
call-bound: 1.0.4
1954
2199
define-properties: 1.2.1
1955
-
es-abstract: 1.22.3
1956
-
es-set-tostringtag: 2.0.2
2200
+
es-abstract: 1.23.9
2201
+
es-errors: 1.3.0
2202
+
es-set-tostringtag: 2.1.0
1957
2203
function-bind: 1.1.2
1958
-
get-intrinsic: 1.2.2
1959
-
globalthis: 1.0.3
1960
-
has-property-descriptors: 1.0.1
1961
-
has-proto: 1.0.1
1962
-
has-symbols: 1.0.3
1963
-
internal-slot: 1.0.6
1964
-
iterator.prototype: 1.1.2
1965
-
safe-array-concat: 1.0.1
2204
+
get-intrinsic: 1.3.0
2205
+
globalthis: 1.0.4
2206
+
gopd: 1.2.0
2207
+
has-property-descriptors: 1.0.2
2208
+
has-proto: 1.2.0
2209
+
has-symbols: 1.1.0
2210
+
internal-slot: 1.1.0
2211
+
iterator.prototype: 1.1.5
2212
+
safe-array-concat: 1.1.3
1966
2213
1967
-
es-set-tostringtag@2.0.2:
2214
+
es-object-atoms@1.1.1:
1968
2215
dependencies:
1969
-
get-intrinsic: 1.2.2
1970
-
has-tostringtag: 1.0.0
1971
-
hasown: 2.0.0
2216
+
es-errors: 1.3.0
1972
2217
1973
-
es-shim-unscopables@1.0.2:
2218
+
es-set-tostringtag@2.1.0:
2219
+
dependencies:
2220
+
es-errors: 1.3.0
2221
+
get-intrinsic: 1.3.0
2222
+
has-tostringtag: 1.0.2
2223
+
hasown: 2.0.2
2224
+
2225
+
es-shim-unscopables@1.1.0:
1974
2226
dependencies:
1975
-
hasown: 2.0.0
2227
+
hasown: 2.0.2
1976
2228
1977
-
es-to-primitive@1.2.1:
2229
+
es-to-primitive@1.3.0:
1978
2230
dependencies:
1979
2231
is-callable: 1.2.7
1980
-
is-date-object: 1.0.5
1981
-
is-symbol: 1.0.4
2232
+
is-date-object: 1.1.0
2233
+
is-symbol: 1.1.1
1982
2234
1983
2235
esbuild-copy-static-files@0.1.0: {}
1984
2236
···
2009
2261
2010
2262
escape-string-regexp@4.0.0: {}
2011
2263
2012
-
eslint-config-prettier@9.1.0(eslint@8.55.0):
2264
+
eslint-config-prettier@9.1.0(eslint@9.23.0(jiti@2.4.2)):
2013
2265
dependencies:
2014
-
eslint: 8.55.0
2266
+
eslint: 9.23.0(jiti@2.4.2)
2015
2267
2016
-
eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.1.0(eslint@8.55.0))(eslint@8.55.0)(prettier@3.1.0):
2268
+
eslint-plugin-prettier@5.2.6(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.23.0(jiti@2.4.2)))(eslint@9.23.0(jiti@2.4.2))(prettier@3.1.0):
2017
2269
dependencies:
2018
-
eslint: 8.55.0
2270
+
eslint: 9.23.0(jiti@2.4.2)
2019
2271
prettier: 3.1.0
2020
2272
prettier-linter-helpers: 1.0.0
2021
-
synckit: 0.8.6
2273
+
synckit: 0.11.1
2022
2274
optionalDependencies:
2023
-
eslint-config-prettier: 9.1.0(eslint@8.55.0)
2275
+
'@types/eslint': 9.6.1
2276
+
eslint-config-prettier: 9.1.0(eslint@9.23.0(jiti@2.4.2))
2024
2277
2025
-
eslint-plugin-react@7.33.2(eslint@8.55.0):
2278
+
eslint-plugin-react@7.37.5(eslint@9.23.0(jiti@2.4.2)):
2026
2279
dependencies:
2027
-
array-includes: 3.1.7
2028
-
array.prototype.flatmap: 1.3.2
2029
-
array.prototype.tosorted: 1.1.2
2280
+
array-includes: 3.1.8
2281
+
array.prototype.findlast: 1.2.5
2282
+
array.prototype.flatmap: 1.3.3
2283
+
array.prototype.tosorted: 1.1.4
2030
2284
doctrine: 2.1.0
2031
-
es-iterator-helpers: 1.0.15
2032
-
eslint: 8.55.0
2285
+
es-iterator-helpers: 1.2.1
2286
+
eslint: 9.23.0(jiti@2.4.2)
2033
2287
estraverse: 5.3.0
2288
+
hasown: 2.0.2
2034
2289
jsx-ast-utils: 3.3.5
2035
2290
minimatch: 3.1.2
2036
-
object.entries: 1.1.7
2037
-
object.fromentries: 2.0.7
2038
-
object.hasown: 1.1.3
2039
-
object.values: 1.1.7
2291
+
object.entries: 1.1.9
2292
+
object.fromentries: 2.0.8
2293
+
object.values: 1.2.1
2040
2294
prop-types: 15.8.1
2041
2295
resolve: 2.0.0-next.5
2042
2296
semver: 6.3.1
2043
-
string.prototype.matchall: 4.0.10
2297
+
string.prototype.matchall: 4.0.12
2298
+
string.prototype.repeat: 1.0.0
2044
2299
2045
-
eslint-scope@7.2.2:
2300
+
eslint-scope@8.3.0:
2046
2301
dependencies:
2047
2302
esrecurse: 4.3.0
2048
2303
estraverse: 5.3.0
2049
2304
2050
2305
eslint-visitor-keys@3.4.3: {}
2051
2306
2052
-
eslint@8.55.0:
2307
+
eslint-visitor-keys@4.2.0: {}
2308
+
2309
+
eslint@9.23.0(jiti@2.4.2):
2053
2310
dependencies:
2054
-
'@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
2055
-
'@eslint-community/regexpp': 4.10.0
2056
-
'@eslint/eslintrc': 2.1.4
2057
-
'@eslint/js': 8.55.0
2058
-
'@humanwhocodes/config-array': 0.11.13
2311
+
'@eslint-community/eslint-utils': 4.5.1(eslint@9.23.0(jiti@2.4.2))
2312
+
'@eslint-community/regexpp': 4.12.1
2313
+
'@eslint/config-array': 0.19.2
2314
+
'@eslint/config-helpers': 0.2.1
2315
+
'@eslint/core': 0.12.0
2316
+
'@eslint/eslintrc': 3.3.1
2317
+
'@eslint/js': 9.23.0
2318
+
'@eslint/plugin-kit': 0.2.8
2319
+
'@humanfs/node': 0.16.6
2059
2320
'@humanwhocodes/module-importer': 1.0.1
2060
-
'@nodelib/fs.walk': 1.2.8
2061
-
'@ungap/structured-clone': 1.2.0
2321
+
'@humanwhocodes/retry': 0.4.2
2322
+
'@types/estree': 1.0.6
2323
+
'@types/json-schema': 7.0.15
2062
2324
ajv: 6.12.6
2063
2325
chalk: 4.1.2
2064
-
cross-spawn: 7.0.3
2065
-
debug: 4.3.4
2066
-
doctrine: 3.0.0
2326
+
cross-spawn: 7.0.6
2327
+
debug: 4.4.0
2067
2328
escape-string-regexp: 4.0.0
2068
-
eslint-scope: 7.2.2
2069
-
eslint-visitor-keys: 3.4.3
2070
-
espree: 9.6.1
2071
-
esquery: 1.5.0
2329
+
eslint-scope: 8.3.0
2330
+
eslint-visitor-keys: 4.2.0
2331
+
espree: 10.3.0
2332
+
esquery: 1.6.0
2072
2333
esutils: 2.0.3
2073
2334
fast-deep-equal: 3.1.3
2074
-
file-entry-cache: 6.0.1
2335
+
file-entry-cache: 8.0.0
2075
2336
find-up: 5.0.0
2076
2337
glob-parent: 6.0.2
2077
-
globals: 13.23.0
2078
-
graphemer: 1.4.0
2079
-
ignore: 5.3.0
2338
+
ignore: 5.3.2
2080
2339
imurmurhash: 0.1.4
2081
2340
is-glob: 4.0.3
2082
-
is-path-inside: 3.0.3
2083
-
js-yaml: 4.1.0
2084
2341
json-stable-stringify-without-jsonify: 1.0.1
2085
-
levn: 0.4.1
2086
2342
lodash.merge: 4.6.2
2087
2343
minimatch: 3.1.2
2088
2344
natural-compare: 1.4.0
2089
2345
optionator: 0.9.3
2090
-
strip-ansi: 6.0.1
2091
-
text-table: 0.2.0
2346
+
optionalDependencies:
2347
+
jiti: 2.4.2
2092
2348
transitivePeerDependencies:
2093
2349
- supports-color
2094
2350
2095
-
espree@9.6.1:
2351
+
espree@10.3.0:
2096
2352
dependencies:
2097
-
acorn: 8.12.1
2098
-
acorn-jsx: 5.3.2(acorn@8.12.1)
2099
-
eslint-visitor-keys: 3.4.3
2353
+
acorn: 8.14.1
2354
+
acorn-jsx: 5.3.2(acorn@8.14.1)
2355
+
eslint-visitor-keys: 4.2.0
2100
2356
2101
-
esquery@1.5.0:
2357
+
esquery@1.6.0:
2102
2358
dependencies:
2103
2359
estraverse: 5.3.0
2104
2360
···
2121
2377
2122
2378
events@3.3.0: {}
2123
2379
2124
-
execa@5.1.1:
2125
-
dependencies:
2126
-
cross-spawn: 7.0.3
2127
-
get-stream: 6.0.1
2128
-
human-signals: 2.1.0
2129
-
is-stream: 2.0.1
2130
-
merge-stream: 2.0.0
2131
-
npm-run-path: 4.0.1
2132
-
onetime: 5.1.2
2133
-
signal-exit: 3.0.7
2134
-
strip-final-newline: 2.0.0
2135
-
2136
-
execa@7.2.0:
2137
-
dependencies:
2138
-
cross-spawn: 7.0.3
2139
-
get-stream: 6.0.1
2140
-
human-signals: 4.3.1
2141
-
is-stream: 3.0.0
2142
-
merge-stream: 2.0.0
2143
-
npm-run-path: 5.1.0
2144
-
onetime: 6.0.0
2145
-
signal-exit: 3.0.7
2146
-
strip-final-newline: 3.0.0
2147
-
2148
2380
fast-deep-equal@3.1.3: {}
2149
2381
2150
2382
fast-diff@1.3.0: {}
···
2155
2387
'@nodelib/fs.walk': 1.2.8
2156
2388
glob-parent: 5.1.2
2157
2389
merge2: 1.4.1
2158
-
micromatch: 4.0.5
2390
+
micromatch: 4.0.8
2159
2391
2160
2392
fast-json-stable-stringify@2.1.0: {}
2161
2393
2162
2394
fast-levenshtein@2.0.6: {}
2163
2395
2164
-
fastq@1.15.0:
2396
+
fastq@1.17.1:
2165
2397
dependencies:
2166
2398
reusify: 1.0.4
2167
2399
2168
-
file-entry-cache@6.0.1:
2400
+
fdir@6.4.3(picomatch@4.0.2):
2401
+
optionalDependencies:
2402
+
picomatch: 4.0.2
2403
+
2404
+
file-entry-cache@8.0.0:
2169
2405
dependencies:
2170
-
flat-cache: 3.2.0
2406
+
flat-cache: 4.0.1
2171
2407
2172
-
fill-range@7.0.1:
2408
+
fill-range@7.1.1:
2173
2409
dependencies:
2174
2410
to-regex-range: 5.0.1
2411
+
2412
+
find-up-simple@1.0.1: {}
2175
2413
2176
2414
find-up@5.0.0:
2177
2415
dependencies:
2178
2416
locate-path: 6.0.0
2179
2417
path-exists: 4.0.0
2180
2418
2181
-
flat-cache@3.2.0:
2419
+
flat-cache@4.0.1:
2182
2420
dependencies:
2183
2421
flatted: 3.2.9
2184
2422
keyv: 4.5.4
2185
-
rimraf: 3.0.2
2186
2423
2187
2424
flatted@3.2.9: {}
2188
2425
2189
-
for-each@0.3.3:
2426
+
for-each@0.3.5:
2190
2427
dependencies:
2191
2428
is-callable: 1.2.7
2192
2429
2193
-
fs.realpath@1.0.0: {}
2194
-
2195
2430
function-bind@1.1.2: {}
2196
2431
2197
-
function.prototype.name@1.1.6:
2432
+
function.prototype.name@1.1.8:
2198
2433
dependencies:
2199
-
call-bind: 1.0.5
2434
+
call-bind: 1.0.8
2435
+
call-bound: 1.0.4
2200
2436
define-properties: 1.2.1
2201
-
es-abstract: 1.22.3
2202
2437
functions-have-names: 1.2.3
2438
+
hasown: 2.0.2
2439
+
is-callable: 1.2.7
2203
2440
2204
2441
functions-have-names@1.2.3: {}
2205
2442
2206
-
get-intrinsic@1.2.2:
2443
+
fzf@0.5.2: {}
2444
+
2445
+
get-intrinsic@1.3.0:
2207
2446
dependencies:
2447
+
call-bind-apply-helpers: 1.0.2
2448
+
es-define-property: 1.0.1
2449
+
es-errors: 1.3.0
2450
+
es-object-atoms: 1.1.1
2208
2451
function-bind: 1.1.2
2209
-
has-proto: 1.0.1
2210
-
has-symbols: 1.0.3
2211
-
hasown: 2.0.0
2452
+
get-proto: 1.0.1
2453
+
gopd: 1.2.0
2454
+
has-symbols: 1.1.0
2455
+
hasown: 2.0.2
2456
+
math-intrinsics: 1.1.0
2212
2457
2213
-
get-stream@6.0.1: {}
2458
+
get-proto@1.0.1:
2459
+
dependencies:
2460
+
dunder-proto: 1.0.1
2461
+
es-object-atoms: 1.1.1
2214
2462
2215
-
get-symbol-description@1.0.0:
2463
+
get-symbol-description@1.1.0:
2216
2464
dependencies:
2217
-
call-bind: 1.0.5
2218
-
get-intrinsic: 1.2.2
2465
+
call-bound: 1.0.4
2466
+
es-errors: 1.3.0
2467
+
get-intrinsic: 1.3.0
2219
2468
2220
2469
glob-parent@5.1.2:
2221
2470
dependencies:
···
2225
2474
dependencies:
2226
2475
is-glob: 4.0.3
2227
2476
2228
-
glob@7.2.3:
2229
-
dependencies:
2230
-
fs.realpath: 1.0.0
2231
-
inflight: 1.0.6
2232
-
inherits: 2.0.4
2233
-
minimatch: 3.1.2
2234
-
once: 1.4.0
2235
-
path-is-absolute: 1.0.1
2477
+
globals@14.0.0: {}
2236
2478
2237
-
globals@13.23.0:
2238
-
dependencies:
2239
-
type-fest: 0.20.2
2240
-
2241
-
globalthis@1.0.3:
2479
+
globalthis@1.0.4:
2242
2480
dependencies:
2243
2481
define-properties: 1.2.1
2244
-
2245
-
globby@11.1.0:
2246
-
dependencies:
2247
-
array-union: 2.1.0
2248
-
dir-glob: 3.0.1
2249
-
fast-glob: 3.3.2
2250
-
ignore: 5.3.0
2251
-
merge2: 1.4.1
2252
-
slash: 3.0.0
2482
+
gopd: 1.2.0
2253
2483
2254
-
gopd@1.0.1:
2255
-
dependencies:
2256
-
get-intrinsic: 1.2.2
2484
+
gopd@1.2.0: {}
2257
2485
2258
2486
graphemer@1.4.0: {}
2259
2487
2260
-
has-bigints@1.0.2: {}
2488
+
has-bigints@1.1.0: {}
2261
2489
2262
2490
has-flag@4.0.0: {}
2263
2491
2264
-
has-property-descriptors@1.0.1:
2492
+
has-property-descriptors@1.0.2:
2265
2493
dependencies:
2266
-
get-intrinsic: 1.2.2
2494
+
es-define-property: 1.0.1
2267
2495
2268
-
has-proto@1.0.1: {}
2496
+
has-proto@1.2.0:
2497
+
dependencies:
2498
+
dunder-proto: 1.0.1
2269
2499
2270
-
has-symbols@1.0.3: {}
2500
+
has-symbols@1.1.0: {}
2271
2501
2272
-
has-tostringtag@1.0.0:
2502
+
has-tostringtag@1.0.2:
2273
2503
dependencies:
2274
-
has-symbols: 1.0.3
2504
+
has-symbols: 1.1.0
2275
2505
2276
-
hasown@2.0.0:
2506
+
hasown@2.0.2:
2277
2507
dependencies:
2278
2508
function-bind: 1.1.2
2279
2509
2280
-
human-signals@2.1.0: {}
2281
-
2282
-
human-signals@4.3.1: {}
2283
-
2284
2510
husky@8.0.3: {}
2285
2511
2286
2512
ieee754@1.2.1: {}
2287
2513
2288
-
ignore@5.3.0: {}
2514
+
ignore@5.3.2: {}
2289
2515
2290
2516
import-fresh@3.3.0:
2291
2517
dependencies:
···
2294
2520
2295
2521
imurmurhash@0.1.4: {}
2296
2522
2297
-
inflight@1.0.6:
2523
+
internal-slot@1.1.0:
2298
2524
dependencies:
2299
-
once: 1.4.0
2300
-
wrappy: 1.0.2
2525
+
es-errors: 1.3.0
2526
+
hasown: 2.0.2
2527
+
side-channel: 1.1.0
2301
2528
2302
-
inherits@2.0.4: {}
2303
-
2304
-
internal-slot@1.0.6:
2529
+
is-array-buffer@3.0.5:
2305
2530
dependencies:
2306
-
get-intrinsic: 1.2.2
2307
-
hasown: 2.0.0
2308
-
side-channel: 1.0.4
2309
-
2310
-
is-array-buffer@3.0.2:
2311
-
dependencies:
2312
-
call-bind: 1.0.5
2313
-
get-intrinsic: 1.2.2
2314
-
is-typed-array: 1.1.12
2531
+
call-bind: 1.0.8
2532
+
call-bound: 1.0.4
2533
+
get-intrinsic: 1.3.0
2315
2534
2316
-
is-async-function@2.0.0:
2535
+
is-async-function@2.1.1:
2317
2536
dependencies:
2318
-
has-tostringtag: 1.0.0
2537
+
async-function: 1.0.0
2538
+
call-bound: 1.0.4
2539
+
get-proto: 1.0.1
2540
+
has-tostringtag: 1.0.2
2541
+
safe-regex-test: 1.1.0
2319
2542
2320
-
is-bigint@1.0.4:
2543
+
is-bigint@1.1.0:
2321
2544
dependencies:
2322
-
has-bigints: 1.0.2
2545
+
has-bigints: 1.1.0
2323
2546
2324
-
is-boolean-object@1.1.2:
2547
+
is-boolean-object@1.2.2:
2325
2548
dependencies:
2326
-
call-bind: 1.0.5
2327
-
has-tostringtag: 1.0.0
2549
+
call-bound: 1.0.4
2550
+
has-tostringtag: 1.0.2
2328
2551
2329
2552
is-callable@1.2.7: {}
2330
2553
2331
-
is-core-module@2.13.1:
2554
+
is-core-module@2.16.1:
2332
2555
dependencies:
2333
-
hasown: 2.0.0
2556
+
hasown: 2.0.2
2334
2557
2335
-
is-date-object@1.0.5:
2558
+
is-data-view@1.0.2:
2336
2559
dependencies:
2337
-
has-tostringtag: 1.0.0
2560
+
call-bound: 1.0.4
2561
+
get-intrinsic: 1.3.0
2562
+
is-typed-array: 1.1.15
2338
2563
2339
-
is-docker@2.2.1: {}
2340
-
2341
-
is-docker@3.0.0: {}
2564
+
is-date-object@1.1.0:
2565
+
dependencies:
2566
+
call-bound: 1.0.4
2567
+
has-tostringtag: 1.0.2
2342
2568
2343
2569
is-extglob@2.1.1: {}
2344
2570
2345
-
is-finalizationregistry@1.0.2:
2571
+
is-finalizationregistry@1.1.1:
2346
2572
dependencies:
2347
-
call-bind: 1.0.5
2573
+
call-bound: 1.0.4
2348
2574
2349
-
is-generator-function@1.0.10:
2575
+
is-generator-function@1.1.0:
2350
2576
dependencies:
2351
-
has-tostringtag: 1.0.0
2577
+
call-bound: 1.0.4
2578
+
get-proto: 1.0.1
2579
+
has-tostringtag: 1.0.2
2580
+
safe-regex-test: 1.1.0
2352
2581
2353
2582
is-glob@4.0.3:
2354
2583
dependencies:
2355
2584
is-extglob: 2.1.1
2356
2585
2357
-
is-inside-container@1.0.0:
2358
-
dependencies:
2359
-
is-docker: 3.0.0
2586
+
is-map@2.0.3: {}
2360
2587
2361
-
is-map@2.0.2: {}
2362
-
2363
-
is-negative-zero@2.0.2: {}
2364
-
2365
-
is-number-object@1.0.7:
2588
+
is-number-object@1.1.1:
2366
2589
dependencies:
2367
-
has-tostringtag: 1.0.0
2590
+
call-bound: 1.0.4
2591
+
has-tostringtag: 1.0.2
2368
2592
2369
2593
is-number@7.0.0: {}
2370
2594
2371
-
is-path-inside@3.0.3: {}
2372
-
2373
-
is-regex@1.1.4:
2595
+
is-regex@1.2.1:
2374
2596
dependencies:
2375
-
call-bind: 1.0.5
2376
-
has-tostringtag: 1.0.0
2597
+
call-bound: 1.0.4
2598
+
gopd: 1.2.0
2599
+
has-tostringtag: 1.0.2
2600
+
hasown: 2.0.2
2377
2601
2378
-
is-set@2.0.2: {}
2602
+
is-set@2.0.3: {}
2379
2603
2380
-
is-shared-array-buffer@1.0.2:
2604
+
is-shared-array-buffer@1.0.4:
2381
2605
dependencies:
2382
-
call-bind: 1.0.5
2383
-
2384
-
is-stream@2.0.1: {}
2385
-
2386
-
is-stream@3.0.0: {}
2606
+
call-bound: 1.0.4
2387
2607
2388
-
is-string@1.0.7:
2608
+
is-string@1.1.1:
2389
2609
dependencies:
2390
-
has-tostringtag: 1.0.0
2610
+
call-bound: 1.0.4
2611
+
has-tostringtag: 1.0.2
2391
2612
2392
-
is-symbol@1.0.4:
2613
+
is-symbol@1.1.1:
2393
2614
dependencies:
2394
-
has-symbols: 1.0.3
2615
+
call-bound: 1.0.4
2616
+
has-symbols: 1.1.0
2617
+
safe-regex-test: 1.1.0
2395
2618
2396
-
is-typed-array@1.1.12:
2619
+
is-typed-array@1.1.15:
2397
2620
dependencies:
2398
-
which-typed-array: 1.1.13
2621
+
which-typed-array: 1.1.19
2399
2622
2400
-
is-weakmap@2.0.1: {}
2623
+
is-weakmap@2.0.2: {}
2401
2624
2402
-
is-weakref@1.0.2:
2625
+
is-weakref@1.1.1:
2403
2626
dependencies:
2404
-
call-bind: 1.0.5
2627
+
call-bound: 1.0.4
2405
2628
2406
-
is-weakset@2.0.2:
2629
+
is-weakset@2.0.4:
2407
2630
dependencies:
2408
-
call-bind: 1.0.5
2409
-
get-intrinsic: 1.2.2
2410
-
2411
-
is-wsl@2.2.0:
2412
-
dependencies:
2413
-
is-docker: 2.2.1
2631
+
call-bound: 1.0.4
2632
+
get-intrinsic: 1.3.0
2414
2633
2415
2634
isarray@2.0.5: {}
2416
2635
2417
2636
isexe@2.0.0: {}
2418
2637
2419
-
iterator.prototype@1.1.2:
2638
+
iterator.prototype@1.1.5:
2420
2639
dependencies:
2421
-
define-properties: 1.2.1
2422
-
get-intrinsic: 1.2.2
2423
-
has-symbols: 1.0.3
2424
-
reflect.getprototypeof: 1.0.4
2425
-
set-function-name: 2.0.1
2640
+
define-data-property: 1.1.4
2641
+
es-object-atoms: 1.1.1
2642
+
get-intrinsic: 1.3.0
2643
+
get-proto: 1.0.1
2644
+
has-symbols: 1.1.0
2645
+
set-function-name: 2.0.2
2646
+
2647
+
jiti@2.4.2: {}
2426
2648
2427
2649
js-tokens@4.0.0: {}
2428
2650
···
2438
2660
2439
2661
jsx-ast-utils@3.3.5:
2440
2662
dependencies:
2441
-
array-includes: 3.1.7
2442
-
array.prototype.flat: 1.3.2
2443
-
object.assign: 4.1.5
2444
-
object.values: 1.1.7
2663
+
array-includes: 3.1.8
2664
+
array.prototype.flat: 1.3.3
2665
+
object.assign: 4.1.7
2666
+
object.values: 1.2.1
2445
2667
2446
2668
keyv@4.5.4:
2447
2669
dependencies:
···
2462
2684
dependencies:
2463
2685
js-tokens: 4.0.0
2464
2686
2465
-
lru-cache@6.0.0:
2466
-
dependencies:
2467
-
yallist: 4.0.0
2468
-
2469
-
merge-stream@2.0.0: {}
2687
+
math-intrinsics@1.1.0: {}
2470
2688
2471
2689
merge2@1.4.1: {}
2472
2690
2473
2691
meriyah@6.0.1: {}
2474
2692
2475
-
micromatch@4.0.5:
2693
+
microdiff@1.5.0: {}
2694
+
2695
+
micromatch@4.0.8:
2476
2696
dependencies:
2477
-
braces: 3.0.2
2697
+
braces: 3.0.3
2478
2698
picomatch: 2.3.1
2479
2699
2480
-
mimic-fn@2.1.0: {}
2481
-
2482
-
mimic-fn@4.0.0: {}
2700
+
mimic-function@5.0.1: {}
2483
2701
2484
2702
minimatch@3.1.2:
2485
2703
dependencies:
···
2489
2707
dependencies:
2490
2708
brace-expansion: 2.0.1
2491
2709
2492
-
ms@2.1.2: {}
2710
+
ms@2.1.3: {}
2493
2711
2494
2712
nanotar@0.1.1: {}
2495
2713
2496
2714
natural-compare@1.4.0: {}
2497
2715
2498
-
npm-run-path@4.0.1:
2499
-
dependencies:
2500
-
path-key: 3.1.1
2501
-
2502
-
npm-run-path@5.1.0:
2503
-
dependencies:
2504
-
path-key: 4.0.0
2716
+
node-fetch-native@1.6.6: {}
2505
2717
2506
2718
object-assign@4.1.1: {}
2507
2719
2508
-
object-inspect@1.13.1: {}
2720
+
object-inspect@1.13.4: {}
2509
2721
2510
2722
object-keys@1.1.1: {}
2511
2723
2512
-
object.assign@4.1.5:
2724
+
object.assign@4.1.7:
2513
2725
dependencies:
2514
-
call-bind: 1.0.5
2726
+
call-bind: 1.0.8
2727
+
call-bound: 1.0.4
2515
2728
define-properties: 1.2.1
2516
-
has-symbols: 1.0.3
2729
+
es-object-atoms: 1.1.1
2730
+
has-symbols: 1.1.0
2517
2731
object-keys: 1.1.1
2518
2732
2519
-
object.entries@1.1.7:
2733
+
object.entries@1.1.9:
2520
2734
dependencies:
2521
-
call-bind: 1.0.5
2735
+
call-bind: 1.0.8
2736
+
call-bound: 1.0.4
2522
2737
define-properties: 1.2.1
2523
-
es-abstract: 1.22.3
2738
+
es-object-atoms: 1.1.1
2524
2739
2525
-
object.fromentries@2.0.7:
2740
+
object.fromentries@2.0.8:
2526
2741
dependencies:
2527
-
call-bind: 1.0.5
2528
-
define-properties: 1.2.1
2529
-
es-abstract: 1.22.3
2530
-
2531
-
object.hasown@1.1.3:
2532
-
dependencies:
2742
+
call-bind: 1.0.8
2533
2743
define-properties: 1.2.1
2534
-
es-abstract: 1.22.3
2744
+
es-abstract: 1.23.9
2745
+
es-object-atoms: 1.1.1
2535
2746
2536
-
object.values@1.1.7:
2747
+
object.values@1.2.1:
2537
2748
dependencies:
2538
-
call-bind: 1.0.5
2749
+
call-bind: 1.0.8
2750
+
call-bound: 1.0.4
2539
2751
define-properties: 1.2.1
2540
-
es-abstract: 1.22.3
2752
+
es-object-atoms: 1.1.1
2541
2753
2542
-
once@1.4.0:
2754
+
ofetch@1.4.1:
2543
2755
dependencies:
2544
-
wrappy: 1.0.2
2545
-
2546
-
onetime@5.1.2:
2547
-
dependencies:
2548
-
mimic-fn: 2.1.0
2549
-
2550
-
onetime@6.0.0:
2551
-
dependencies:
2552
-
mimic-fn: 4.0.0
2756
+
destr: 2.0.4
2757
+
node-fetch-native: 1.6.6
2758
+
ufo: 1.5.4
2553
2759
2554
-
open@9.1.0:
2760
+
onetime@7.0.0:
2555
2761
dependencies:
2556
-
default-browser: 4.0.0
2557
-
define-lazy-prop: 3.0.0
2558
-
is-inside-container: 1.0.0
2559
-
is-wsl: 2.2.0
2762
+
mimic-function: 5.0.1
2560
2763
2561
2764
optionator@0.9.3:
2562
2765
dependencies:
···
2567
2770
prelude-ls: 1.2.1
2568
2771
type-check: 0.4.0
2569
2772
2773
+
own-keys@1.0.1:
2774
+
dependencies:
2775
+
get-intrinsic: 1.3.0
2776
+
object-keys: 1.1.1
2777
+
safe-push-apply: 1.0.0
2778
+
2570
2779
p-limit@3.1.0:
2571
2780
dependencies:
2572
2781
yocto-queue: 0.1.0
···
2574
2783
p-locate@5.0.0:
2575
2784
dependencies:
2576
2785
p-limit: 3.1.0
2786
+
2787
+
package-manager-detector@1.1.0: {}
2577
2788
2578
2789
parent-module@1.0.1:
2579
2790
dependencies:
···
2581
2792
2582
2793
path-exists@4.0.0: {}
2583
2794
2584
-
path-is-absolute@1.0.1: {}
2585
-
2586
2795
path-key@3.1.1: {}
2587
2796
2588
-
path-key@4.0.0: {}
2589
-
2590
2797
path-parse@1.0.7: {}
2591
2798
2592
-
path-type@4.0.0: {}
2799
+
pathe@2.0.3: {}
2593
2800
2594
-
picocolors@1.0.0: {}
2801
+
picomatch@2.3.1: {}
2802
+
2803
+
picomatch@4.0.2: {}
2804
+
2805
+
pnpm-workspace-yaml@0.3.1:
2806
+
dependencies:
2807
+
yaml: 2.7.1
2595
2808
2596
-
picomatch@2.3.1: {}
2809
+
possible-typed-array-names@1.1.0: {}
2597
2810
2598
2811
prelude-ls@1.2.1: {}
2599
2812
···
2613
2826
2614
2827
punycode@2.3.1: {}
2615
2828
2829
+
quansync@0.2.10: {}
2830
+
2616
2831
queue-microtask@1.2.3: {}
2617
2832
2618
2833
react-is@16.13.1: {}
···
2625
2840
process: 0.11.10
2626
2841
string_decoder: 1.3.0
2627
2842
2628
-
reflect.getprototypeof@1.0.4:
2843
+
reflect.getprototypeof@1.0.10:
2629
2844
dependencies:
2630
-
call-bind: 1.0.5
2845
+
call-bind: 1.0.8
2631
2846
define-properties: 1.2.1
2632
-
es-abstract: 1.22.3
2633
-
get-intrinsic: 1.2.2
2634
-
globalthis: 1.0.3
2635
-
which-builtin-type: 1.1.3
2847
+
es-abstract: 1.23.9
2848
+
es-errors: 1.3.0
2849
+
es-object-atoms: 1.1.1
2850
+
get-intrinsic: 1.3.0
2851
+
get-proto: 1.0.1
2852
+
which-builtin-type: 1.2.1
2636
2853
2637
-
regexp.prototype.flags@1.5.1:
2854
+
regexp.prototype.flags@1.5.4:
2638
2855
dependencies:
2639
-
call-bind: 1.0.5
2856
+
call-bind: 1.0.8
2640
2857
define-properties: 1.2.1
2641
-
set-function-name: 2.0.1
2858
+
es-errors: 1.3.0
2859
+
get-proto: 1.0.1
2860
+
gopd: 1.2.0
2861
+
set-function-name: 2.0.2
2642
2862
2643
2863
resolve-from@4.0.0: {}
2644
2864
2645
2865
resolve@2.0.0-next.5:
2646
2866
dependencies:
2647
-
is-core-module: 2.13.1
2867
+
is-core-module: 2.16.1
2648
2868
path-parse: 1.0.7
2649
2869
supports-preserve-symlinks-flag: 1.0.0
2650
2870
2651
-
reusify@1.0.4: {}
2652
-
2653
-
rimraf@3.0.2:
2871
+
restore-cursor@5.1.0:
2654
2872
dependencies:
2655
-
glob: 7.2.3
2873
+
onetime: 7.0.0
2874
+
signal-exit: 4.1.0
2656
2875
2657
-
run-applescript@5.0.0:
2658
-
dependencies:
2659
-
execa: 5.1.1
2876
+
reusify@1.0.4: {}
2660
2877
2661
2878
run-parallel@1.2.0:
2662
2879
dependencies:
2663
2880
queue-microtask: 1.2.3
2664
2881
2665
-
safe-array-concat@1.0.1:
2882
+
safe-array-concat@1.1.3:
2666
2883
dependencies:
2667
-
call-bind: 1.0.5
2668
-
get-intrinsic: 1.2.2
2669
-
has-symbols: 1.0.3
2884
+
call-bind: 1.0.8
2885
+
call-bound: 1.0.4
2886
+
get-intrinsic: 1.3.0
2887
+
has-symbols: 1.1.0
2670
2888
isarray: 2.0.5
2671
2889
2672
-
safe-buffer@5.1.2: {}
2673
-
2674
2890
safe-buffer@5.2.1: {}
2675
2891
2676
-
safe-regex-test@1.0.0:
2892
+
safe-push-apply@1.0.0:
2677
2893
dependencies:
2678
-
call-bind: 1.0.5
2679
-
get-intrinsic: 1.2.2
2680
-
is-regex: 1.1.4
2894
+
es-errors: 1.3.0
2895
+
isarray: 2.0.5
2896
+
2897
+
safe-regex-test@1.1.0:
2898
+
dependencies:
2899
+
call-bound: 1.0.4
2900
+
es-errors: 1.3.0
2901
+
is-regex: 1.2.1
2681
2902
2682
2903
semver@6.3.1: {}
2683
2904
2684
-
semver@7.5.4:
2685
-
dependencies:
2686
-
lru-cache: 6.0.0
2905
+
semver@7.7.1: {}
2687
2906
2688
-
set-function-length@1.1.1:
2907
+
set-function-length@1.2.2:
2689
2908
dependencies:
2690
-
define-data-property: 1.1.1
2691
-
get-intrinsic: 1.2.2
2692
-
gopd: 1.0.1
2693
-
has-property-descriptors: 1.0.1
2909
+
define-data-property: 1.1.4
2910
+
es-errors: 1.3.0
2911
+
function-bind: 1.1.2
2912
+
get-intrinsic: 1.3.0
2913
+
gopd: 1.2.0
2914
+
has-property-descriptors: 1.0.2
2694
2915
2695
-
set-function-name@2.0.1:
2916
+
set-function-name@2.0.2:
2696
2917
dependencies:
2697
-
define-data-property: 1.1.1
2918
+
define-data-property: 1.1.4
2919
+
es-errors: 1.3.0
2698
2920
functions-have-names: 1.2.3
2699
-
has-property-descriptors: 1.0.1
2921
+
has-property-descriptors: 1.0.2
2922
+
2923
+
set-proto@1.0.0:
2924
+
dependencies:
2925
+
dunder-proto: 1.0.1
2926
+
es-errors: 1.3.0
2927
+
es-object-atoms: 1.1.1
2700
2928
2701
2929
shebang-command@2.0.0:
2702
2930
dependencies:
···
2704
2932
2705
2933
shebang-regex@3.0.0: {}
2706
2934
2707
-
side-channel@1.0.4:
2935
+
side-channel-list@1.0.0:
2708
2936
dependencies:
2709
-
call-bind: 1.0.5
2710
-
get-intrinsic: 1.2.2
2711
-
object-inspect: 1.13.1
2937
+
es-errors: 1.3.0
2938
+
object-inspect: 1.13.4
2712
2939
2713
-
signal-exit@3.0.7: {}
2940
+
side-channel-map@1.0.1:
2941
+
dependencies:
2942
+
call-bound: 1.0.4
2943
+
es-errors: 1.3.0
2944
+
get-intrinsic: 1.3.0
2945
+
object-inspect: 1.13.4
2714
2946
2715
-
slash@3.0.0: {}
2947
+
side-channel-weakmap@1.0.2:
2948
+
dependencies:
2949
+
call-bound: 1.0.4
2950
+
es-errors: 1.3.0
2951
+
get-intrinsic: 1.3.0
2952
+
object-inspect: 1.13.4
2953
+
side-channel-map: 1.0.1
2954
+
2955
+
side-channel@1.1.0:
2956
+
dependencies:
2957
+
es-errors: 1.3.0
2958
+
object-inspect: 1.13.4
2959
+
side-channel-list: 1.0.0
2960
+
side-channel-map: 1.0.1
2961
+
side-channel-weakmap: 1.0.2
2962
+
2963
+
signal-exit@4.1.0: {}
2716
2964
2717
2965
standalone-electron-types@1.0.0:
2718
2966
dependencies:
2719
2967
'@types/node': 18.17.17
2720
2968
2721
-
string.prototype.matchall@4.0.10:
2969
+
string.prototype.matchall@4.0.12:
2722
2970
dependencies:
2723
-
call-bind: 1.0.5
2971
+
call-bind: 1.0.8
2972
+
call-bound: 1.0.4
2724
2973
define-properties: 1.2.1
2725
-
es-abstract: 1.22.3
2726
-
get-intrinsic: 1.2.2
2727
-
has-symbols: 1.0.3
2728
-
internal-slot: 1.0.6
2729
-
regexp.prototype.flags: 1.5.1
2730
-
set-function-name: 2.0.1
2731
-
side-channel: 1.0.4
2974
+
es-abstract: 1.23.9
2975
+
es-errors: 1.3.0
2976
+
es-object-atoms: 1.1.1
2977
+
get-intrinsic: 1.3.0
2978
+
gopd: 1.2.0
2979
+
has-symbols: 1.1.0
2980
+
internal-slot: 1.1.0
2981
+
regexp.prototype.flags: 1.5.4
2982
+
set-function-name: 2.0.2
2983
+
side-channel: 1.1.0
2732
2984
2733
-
string.prototype.trim@1.2.8:
2985
+
string.prototype.repeat@1.0.0:
2734
2986
dependencies:
2735
-
call-bind: 1.0.5
2736
2987
define-properties: 1.2.1
2737
-
es-abstract: 1.22.3
2988
+
es-abstract: 1.23.9
2738
2989
2739
-
string.prototype.trimend@1.0.7:
2990
+
string.prototype.trim@1.2.10:
2740
2991
dependencies:
2741
-
call-bind: 1.0.5
2992
+
call-bind: 1.0.8
2993
+
call-bound: 1.0.4
2994
+
define-data-property: 1.1.4
2742
2995
define-properties: 1.2.1
2743
-
es-abstract: 1.22.3
2996
+
es-abstract: 1.23.9
2997
+
es-object-atoms: 1.1.1
2998
+
has-property-descriptors: 1.0.2
2744
2999
2745
-
string.prototype.trimstart@1.0.7:
3000
+
string.prototype.trimend@1.0.9:
2746
3001
dependencies:
2747
-
call-bind: 1.0.5
3002
+
call-bind: 1.0.8
3003
+
call-bound: 1.0.4
2748
3004
define-properties: 1.2.1
2749
-
es-abstract: 1.22.3
3005
+
es-object-atoms: 1.1.1
2750
3006
2751
-
string_decoder@1.3.0:
3007
+
string.prototype.trimstart@1.0.8:
2752
3008
dependencies:
2753
-
safe-buffer: 5.2.1
3009
+
call-bind: 1.0.8
3010
+
define-properties: 1.2.1
3011
+
es-object-atoms: 1.1.1
2754
3012
2755
-
strip-ansi@6.0.1:
3013
+
string_decoder@1.3.0:
2756
3014
dependencies:
2757
-
ansi-regex: 5.0.1
2758
-
2759
-
strip-final-newline@2.0.0: {}
2760
-
2761
-
strip-final-newline@3.0.0: {}
3015
+
safe-buffer: 5.2.1
2762
3016
2763
3017
strip-json-comments@3.1.1: {}
2764
3018
···
2768
3022
2769
3023
supports-preserve-symlinks-flag@1.0.0: {}
2770
3024
2771
-
synckit@0.8.6:
3025
+
synckit@0.11.1:
2772
3026
dependencies:
2773
-
'@pkgr/utils': 2.4.2
2774
-
tslib: 2.6.2
3027
+
'@pkgr/core': 0.2.0
3028
+
tslib: 2.8.1
2775
3029
2776
-
text-table@0.2.0: {}
3030
+
taze@19.0.4:
3031
+
dependencies:
3032
+
'@antfu/ni': 24.3.0
3033
+
cac: 6.7.14
3034
+
find-up-simple: 1.0.1
3035
+
ofetch: 1.4.1
3036
+
package-manager-detector: 1.1.0
3037
+
pathe: 2.0.3
3038
+
pnpm-workspace-yaml: 0.3.1
3039
+
restore-cursor: 5.1.0
3040
+
tinyexec: 1.0.1
3041
+
tinyglobby: 0.2.12
3042
+
unconfig: 7.3.1
3043
+
yaml: 2.7.1
2777
3044
2778
-
titleize@3.0.0: {}
3045
+
tinyexec@1.0.1: {}
3046
+
3047
+
tinyglobby@0.2.12:
3048
+
dependencies:
3049
+
fdir: 6.4.3(picomatch@4.0.2)
3050
+
picomatch: 4.0.2
2779
3051
2780
3052
to-regex-range@5.0.1:
2781
3053
dependencies:
2782
3054
is-number: 7.0.0
2783
3055
2784
-
ts-api-utils@1.0.3(typescript@5.3.2):
3056
+
ts-api-utils@2.1.0(typescript@5.8.2):
2785
3057
dependencies:
2786
-
typescript: 5.3.2
3058
+
typescript: 5.8.2
2787
3059
2788
-
tslib@2.6.2: {}
3060
+
tslib@2.8.1: {}
2789
3061
2790
3062
type-check@0.4.0:
2791
3063
dependencies:
2792
3064
prelude-ls: 1.2.1
2793
3065
2794
-
type-fest@0.20.2: {}
3066
+
typed-array-buffer@1.0.3:
3067
+
dependencies:
3068
+
call-bound: 1.0.4
3069
+
es-errors: 1.3.0
3070
+
is-typed-array: 1.1.15
2795
3071
2796
-
typed-array-buffer@1.0.0:
3072
+
typed-array-byte-length@1.0.3:
2797
3073
dependencies:
2798
-
call-bind: 1.0.5
2799
-
get-intrinsic: 1.2.2
2800
-
is-typed-array: 1.1.12
3074
+
call-bind: 1.0.8
3075
+
for-each: 0.3.5
3076
+
gopd: 1.2.0
3077
+
has-proto: 1.2.0
3078
+
is-typed-array: 1.1.15
2801
3079
2802
-
typed-array-byte-length@1.0.0:
3080
+
typed-array-byte-offset@1.0.4:
2803
3081
dependencies:
2804
-
call-bind: 1.0.5
2805
-
for-each: 0.3.3
2806
-
has-proto: 1.0.1
2807
-
is-typed-array: 1.1.12
3082
+
available-typed-arrays: 1.0.7
3083
+
call-bind: 1.0.8
3084
+
for-each: 0.3.5
3085
+
gopd: 1.2.0
3086
+
has-proto: 1.2.0
3087
+
is-typed-array: 1.1.15
3088
+
reflect.getprototypeof: 1.0.10
2808
3089
2809
-
typed-array-byte-offset@1.0.0:
3090
+
typed-array-length@1.0.7:
2810
3091
dependencies:
2811
-
available-typed-arrays: 1.0.5
2812
-
call-bind: 1.0.5
2813
-
for-each: 0.3.3
2814
-
has-proto: 1.0.1
2815
-
is-typed-array: 1.1.12
3092
+
call-bind: 1.0.8
3093
+
for-each: 0.3.5
3094
+
gopd: 1.2.0
3095
+
is-typed-array: 1.1.15
3096
+
possible-typed-array-names: 1.1.0
3097
+
reflect.getprototypeof: 1.0.10
2816
3098
2817
-
typed-array-length@1.0.4:
3099
+
typescript-eslint@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2):
2818
3100
dependencies:
2819
-
call-bind: 1.0.5
2820
-
for-each: 0.3.3
2821
-
is-typed-array: 1.1.12
3101
+
'@typescript-eslint/eslint-plugin': 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
3102
+
'@typescript-eslint/parser': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
3103
+
'@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
3104
+
eslint: 9.23.0(jiti@2.4.2)
3105
+
typescript: 5.8.2
3106
+
transitivePeerDependencies:
3107
+
- supports-color
3108
+
3109
+
typescript@5.8.2: {}
2822
3110
2823
-
typescript@5.3.2: {}
3111
+
ufo@1.5.4: {}
2824
3112
2825
-
unbox-primitive@1.0.2:
3113
+
unbox-primitive@1.1.0:
2826
3114
dependencies:
2827
-
call-bind: 1.0.5
2828
-
has-bigints: 1.0.2
2829
-
has-symbols: 1.0.3
2830
-
which-boxed-primitive: 1.0.2
3115
+
call-bound: 1.0.4
3116
+
has-bigints: 1.1.0
3117
+
has-symbols: 1.1.0
3118
+
which-boxed-primitive: 1.1.1
2831
3119
2832
-
undici-types@6.19.8: {}
3120
+
unconfig@7.3.1:
3121
+
dependencies:
3122
+
'@quansync/fs': 0.1.2
3123
+
defu: 6.1.4
3124
+
jiti: 2.4.2
3125
+
quansync: 0.2.10
3126
+
3127
+
undici-types@6.20.0: {}
2833
3128
2834
-
untildify@4.0.0: {}
3129
+
undici-types@6.21.0: {}
2835
3130
2836
3131
uri-js@4.4.1:
2837
3132
dependencies:
2838
3133
punycode: 2.3.1
2839
3134
2840
-
utilium@0.7.1:
3135
+
utilium@1.10.1:
2841
3136
dependencies:
2842
3137
eventemitter3: 5.0.1
3138
+
optionalDependencies:
3139
+
'@xterm/xterm': 5.5.0
2843
3140
2844
-
which-boxed-primitive@1.0.2:
3141
+
which-boxed-primitive@1.1.1:
2845
3142
dependencies:
2846
-
is-bigint: 1.0.4
2847
-
is-boolean-object: 1.1.2
2848
-
is-number-object: 1.0.7
2849
-
is-string: 1.0.7
2850
-
is-symbol: 1.0.4
3143
+
is-bigint: 1.1.0
3144
+
is-boolean-object: 1.2.2
3145
+
is-number-object: 1.1.1
3146
+
is-string: 1.1.1
3147
+
is-symbol: 1.1.1
2851
3148
2852
-
which-builtin-type@1.1.3:
3149
+
which-builtin-type@1.2.1:
2853
3150
dependencies:
2854
-
function.prototype.name: 1.1.6
2855
-
has-tostringtag: 1.0.0
2856
-
is-async-function: 2.0.0
2857
-
is-date-object: 1.0.5
2858
-
is-finalizationregistry: 1.0.2
2859
-
is-generator-function: 1.0.10
2860
-
is-regex: 1.1.4
2861
-
is-weakref: 1.0.2
3151
+
call-bound: 1.0.4
3152
+
function.prototype.name: 1.1.8
3153
+
has-tostringtag: 1.0.2
3154
+
is-async-function: 2.1.1
3155
+
is-date-object: 1.1.0
3156
+
is-finalizationregistry: 1.1.1
3157
+
is-generator-function: 1.1.0
3158
+
is-regex: 1.2.1
3159
+
is-weakref: 1.1.1
2862
3160
isarray: 2.0.5
2863
-
which-boxed-primitive: 1.0.2
2864
-
which-collection: 1.0.1
2865
-
which-typed-array: 1.1.13
3161
+
which-boxed-primitive: 1.1.1
3162
+
which-collection: 1.0.2
3163
+
which-typed-array: 1.1.19
2866
3164
2867
-
which-collection@1.0.1:
3165
+
which-collection@1.0.2:
2868
3166
dependencies:
2869
-
is-map: 2.0.2
2870
-
is-set: 2.0.2
2871
-
is-weakmap: 2.0.1
2872
-
is-weakset: 2.0.2
3167
+
is-map: 2.0.3
3168
+
is-set: 2.0.3
3169
+
is-weakmap: 2.0.2
3170
+
is-weakset: 2.0.4
2873
3171
2874
-
which-typed-array@1.1.13:
3172
+
which-typed-array@1.1.19:
2875
3173
dependencies:
2876
-
available-typed-arrays: 1.0.5
2877
-
call-bind: 1.0.5
2878
-
for-each: 0.3.3
2879
-
gopd: 1.0.1
2880
-
has-tostringtag: 1.0.0
3174
+
available-typed-arrays: 1.0.7
3175
+
call-bind: 1.0.8
3176
+
call-bound: 1.0.4
3177
+
for-each: 0.3.5
3178
+
get-proto: 1.0.1
3179
+
gopd: 1.2.0
3180
+
has-tostringtag: 1.0.2
2881
3181
2882
3182
which@2.0.2:
2883
3183
dependencies:
2884
3184
isexe: 2.0.0
2885
3185
2886
-
wrappy@1.0.2: {}
2887
-
2888
-
yallist@4.0.0: {}
3186
+
yaml@2.7.1: {}
2889
3187
2890
3188
yocto-queue@0.1.0: {}
3189
+
3190
+
zustand@5.0.3(@types/react@18.3.20):
3191
+
optionalDependencies:
3192
+
'@types/react': 18.3.20
+31
-1
pnpm-workspace.yaml
+31
-1
pnpm-workspace.yaml
···
1
1
packages:
2
-
- "packages/*"
2
+
- packages/*
3
+
4
+
catalogs:
5
+
dev:
6
+
esbuild: ^0.19.3
7
+
esbuild-copy-static-files: ^0.1.0
8
+
"@types/node": ^22.14.0
9
+
"@moonlight-mod/eslint-config": "github:moonlight-mod/eslint-config"
10
+
eslint: ^9.12.0
11
+
"@types/chrome": ^0.0.313
12
+
husky: ^8.0.3
13
+
prettier: ^3.1.0
14
+
typescript: ^5.3.3
15
+
taze: ^19.0.4
16
+
prod:
17
+
"@moonlight-mod/lunast": ^1.0.1
18
+
"@moonlight-mod/mappings": ^1.1.25
19
+
"@moonlight-mod/moonmap": ^1.0.5
20
+
microdiff: ^1.5.0
21
+
nanotar: ^0.1.1
22
+
"@zenfs/core": ^2.0.0
23
+
"@zenfs/dom": ^1.1.3
24
+
25
+
onlyBuiltDependencies:
26
+
- esbuild
27
+
28
+
engineStrict: true
29
+
strictSsl: true
30
+
strictDepBuilds: true
31
+
packageManagerStrict: true
32
+
registry: https://registry.npmjs.org/
-70
scripts/link.js
-70
scripts/link.js
···
1
-
// Janky script to get around pnpm link issues
2
-
// Probably don't use this. Probably
3
-
/* eslint-disable no-console */
4
-
const fs = require("fs");
5
-
const path = require("path");
6
-
const child_process = require("child_process");
7
-
8
-
const onDisk = {
9
-
"@moonlight-mod/lunast": "../lunast",
10
-
"@moonlight-mod/moonmap": "../moonmap",
11
-
"@moonlight-mod/mappings": "../mappings"
12
-
};
13
-
14
-
function exec(cmd, dir) {
15
-
child_process.execSync(cmd, { cwd: dir, stdio: "inherit" });
16
-
}
17
-
18
-
function getDeps(packageJSON) {
19
-
const ret = {};
20
-
Object.assign(ret, packageJSON.dependencies || {});
21
-
Object.assign(ret, packageJSON.devDependencies || {});
22
-
Object.assign(ret, packageJSON.peerDependencies || {});
23
-
return ret;
24
-
}
25
-
26
-
function link(dir) {
27
-
const packageJSON = JSON.parse(
28
-
fs.readFileSync(path.join(dir, "package.json"), "utf8")
29
-
);
30
-
const deps = getDeps(packageJSON);
31
-
32
-
for (const [dep, path] of Object.entries(onDisk)) {
33
-
if (deps[dep]) {
34
-
exec(`pnpm link ${path}`, dir);
35
-
}
36
-
}
37
-
}
38
-
39
-
function undo(dir) {
40
-
exec("pnpm unlink", dir);
41
-
try {
42
-
exec("git restore pnpm-lock.yaml", dir);
43
-
} catch {
44
-
// ignored
45
-
}
46
-
}
47
-
48
-
const shouldUndo = process.argv.includes("--undo");
49
-
const packages = fs.readdirSync("./packages");
50
-
51
-
for (const path of Object.values(onDisk)) {
52
-
console.log(path);
53
-
if (shouldUndo) {
54
-
undo(path);
55
-
} else {
56
-
link(path);
57
-
}
58
-
}
59
-
60
-
if (shouldUndo) {
61
-
const dir = __dirname;
62
-
console.log(dir);
63
-
undo(dir);
64
-
} else {
65
-
for (const pkg of packages) {
66
-
const dir = path.join(__dirname, "packages", pkg);
67
-
console.log(dir);
68
-
link(dir);
69
-
}
70
-
}
+78
scripts/link.mjs
+78
scripts/link.mjs
···
1
+
// Janky script to get around pnpm link issues
2
+
// Probably don't use this. Probably
3
+
/* eslint-disable no-console */
4
+
const fs = require("fs");
5
+
const path = require("path");
6
+
const child_process = require("child_process");
7
+
8
+
const cwd = process.cwd();
9
+
const onDisk = {
10
+
//"@moonlight-mod/lunast": "../lunast",
11
+
//"@moonlight-mod/moonmap": "../moonmap",
12
+
"@moonlight-mod/mappings": "../mappings"
13
+
};
14
+
15
+
function exec(cmd, dir) {
16
+
child_process.execSync(cmd, { cwd: dir, stdio: "inherit" });
17
+
}
18
+
19
+
function getDeps(packageJSON) {
20
+
const ret = {};
21
+
Object.assign(ret, packageJSON.dependencies || {});
22
+
Object.assign(ret, packageJSON.devDependencies || {});
23
+
Object.assign(ret, packageJSON.peerDependencies || {});
24
+
return ret;
25
+
}
26
+
27
+
function link(dir) {
28
+
const packageJSONPath = path.join(dir, "package.json");
29
+
if (!fs.existsSync(packageJSONPath)) return;
30
+
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"));
31
+
const deps = getDeps(packageJSON);
32
+
33
+
for (const [dep, relativePath] of Object.entries(onDisk)) {
34
+
const fullPath = path.join(cwd, relativePath);
35
+
if (deps[dep]) {
36
+
exec(`pnpm link ${fullPath}`, dir);
37
+
}
38
+
}
39
+
}
40
+
41
+
function undo(dir) {
42
+
exec("pnpm unlink", dir);
43
+
try {
44
+
if (fs.existsSync(path.join(dir, "pnpm-lock.yaml"))) {
45
+
exec("git restore pnpm-lock.yaml", dir);
46
+
}
47
+
} catch {
48
+
// ignored
49
+
}
50
+
}
51
+
52
+
const shouldUndo = process.argv.includes("--undo");
53
+
const packages = fs.readdirSync("./packages");
54
+
55
+
for (const path of Object.values(onDisk)) {
56
+
console.log(path);
57
+
if (shouldUndo) {
58
+
undo(path);
59
+
} else {
60
+
link(path);
61
+
}
62
+
}
63
+
64
+
if (shouldUndo) {
65
+
console.log(cwd);
66
+
undo(cwd);
67
+
for (const pkg of packages) {
68
+
const dir = path.join(cwd, "packages", pkg);
69
+
console.log(dir);
70
+
undo(dir);
71
+
}
72
+
} else {
73
+
for (const pkg of packages) {
74
+
const dir = path.join(cwd, "packages", pkg);
75
+
console.log(dir);
76
+
link(dir);
77
+
}
78
+
}
-31
scripts/update.js
-31
scripts/update.js
···
1
-
// Update dependencies in all packages
2
-
/* eslint-disable no-console */
3
-
const fs = require("fs");
4
-
const path = require("path");
5
-
const child_process = require("child_process");
6
-
7
-
const packageToUpdate = process.argv[2];
8
-
9
-
function getDeps(packageJSON) {
10
-
const ret = {};
11
-
Object.assign(ret, packageJSON.dependencies || {});
12
-
Object.assign(ret, packageJSON.devDependencies || {});
13
-
Object.assign(ret, packageJSON.peerDependencies || {});
14
-
return ret;
15
-
}
16
-
17
-
function exec(cmd, dir) {
18
-
child_process.execSync(cmd, { cwd: dir, stdio: "inherit" });
19
-
}
20
-
21
-
for (const package of fs.readdirSync("./packages")) {
22
-
const packageJSON = JSON.parse(
23
-
fs.readFileSync(path.join("./packages", package, "package.json"), "utf8")
24
-
);
25
-
26
-
const deps = getDeps(packageJSON);
27
-
if (Object.keys(deps).includes(packageToUpdate)) {
28
-
console.log(`Updating ${packageToUpdate} in ${package}`);
29
-
exec(`pnpm update ${packageToUpdate}`, path.join("./packages", package));
30
-
}
31
-
}
+35
tsconfig.base.json
+35
tsconfig.base.json
···
1
+
{
2
+
"$schema": "https://json.schemastore.org/tsconfig.json",
3
+
"display": "Base",
4
+
"_version": "1.0.0",
5
+
"compilerOptions": {
6
+
"incremental": true,
7
+
"target": "ES2022",
8
+
"jsx": "react",
9
+
"lib": ["ESNext", "ESNext.Disposable", "DOM", "DOM.Iterable"],
10
+
"module": "ES2020",
11
+
"moduleResolution": "Bundler",
12
+
"resolveJsonModule": true,
13
+
"allowArbitraryExtensions": false,
14
+
"allowImportingTsExtensions": true,
15
+
"allowJs": true,
16
+
"strict": true,
17
+
"strictNullChecks": true,
18
+
19
+
// disable unreachable code detection because it breaks with esbuild labels
20
+
"allowUnreachableCode": true,
21
+
"noFallthroughCasesInSwitch": true,
22
+
"noImplicitReturns": true,
23
+
"declaration": true,
24
+
"declarationMap": true,
25
+
"outDir": "dist",
26
+
"sourceMap": true,
27
+
"stripInternal": true,
28
+
"esModuleInterop": true,
29
+
"forceConsistentCasingInFileNames": true,
30
+
"noErrorTruncation": true,
31
+
"verbatimModuleSyntax": false,
32
+
// meriyah has a broken import lol
33
+
"skipLibCheck": true
34
+
}
35
+
}
+7
-16
tsconfig.json
+7
-16
tsconfig.json
···
1
1
{
2
+
"extends": ["./tsconfig.base.json"],
2
3
"compilerOptions": {
3
-
"target": "es2022",
4
-
"module": "es6",
5
-
"esModuleInterop": true,
6
-
"forceConsistentCasingInFileNames": true,
7
-
"strict": true,
8
-
"moduleResolution": "bundler",
9
4
"baseUrl": "./packages/",
10
-
"jsx": "react",
11
-
"noEmit": true,
12
-
13
-
// meriyah has a broken import lol
14
-
"skipLibCheck": true,
15
-
16
-
// disable unreachable code detection because it breaks with esbuild labels
17
-
"allowUnreachableCode": true
5
+
"noEmit": true
18
6
},
19
-
"include": ["./packages/**/*", "./env.d.ts"],
20
-
"exclude": ["node_modules"]
7
+
"exclude": [
8
+
"**/node_modules/**",
9
+
"**/dist/**",
10
+
"**/build/**"
11
+
]
21
12
}