+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
+5
-11
.github/workflows/types.yml
+5
-11
.github/workflows/types.yml
···
11
11
name: Publish types on npm
12
12
runs-on: ubuntu-latest
13
13
steps:
14
-
- uses: actions/checkout@v3
15
-
16
-
- uses: pnpm/action-setup@v2
17
-
with:
18
-
version: 9
19
-
run_install: false
20
-
- uses: actions/setup-node@v3
14
+
- uses: actions/checkout@v4
15
+
- uses: pnpm/action-setup@v4
16
+
- uses: actions/setup-node@v4
21
17
with:
22
-
node-version: 18
18
+
node-version: 22
23
19
cache: pnpm
24
20
registry-url: https://registry.npmjs.org
25
21
···
31
27
run: pnpm run build
32
28
33
29
- name: Publish types
34
-
run: |
35
-
cd packages/types
36
-
pnpm publish --access public --no-git-checks
30
+
run: pnpm publish --filter=./packages/types --access public --no-git-checks
37
31
env:
38
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
+3
-7
CHANGELOG.md
+3
-7
CHANGELOG.md
···
1
-
- Fixed CSP in the browser extension
2
-
- Added support for ESM when loading an extension entrypoint
3
-
- Added screenshots of Moonbase to the README
4
-
- Added an API to write to the extension settings
5
-
- Added isDir to the filesystem API
6
-
- Added localStorage to the moonlight global
1
+
## Core
2
+
7
3
- Updated mappings
8
-
- The extension loader now prioritizes loading developer extensions
4
+
- Fixed using remapped paths as patch finds not working
+4
-3
README.md
+4
-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 />
13
14
···
22
23
23
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.
24
25
25
-
**_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.
26
27
27
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.
+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";
+23
-12
package.json
+23
-12
package.json
···
1
1
{
2
2
"name": "moonlight",
3
-
"version": "1.2.5",
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",
···
18
26
"browser": "node build.mjs --browser",
19
27
"browser-mv2": "node build.mjs --browser --mv2",
20
28
"lint": "eslint packages",
21
-
"lint:fix": "eslint packages --fix",
22
-
"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",
23
31
"typecheck": "tsc --noEmit",
24
32
"check": "pnpm run lint && pnpm run typecheck",
25
-
"prepare": "husky install"
33
+
"prepare": "husky install",
34
+
"updates": "pnpm taze -r"
26
35
},
27
36
"devDependencies": {
28
-
"esbuild": "^0.19.3",
29
-
"esbuild-copy-static-files": "^0.1.0",
30
-
"eslint": "^9.12.0",
31
-
"@moonlight-mod/eslint-config": "github:moonlight-mod/eslint-config",
32
-
"husky": "^8.0.3",
33
-
"prettier": "^3.1.0",
34
-
"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"
35
46
}
36
47
}
+2
-1
packages/browser/blockLoading.json
+2
-1
packages/browser/blockLoading.json
+10
-4
packages/browser/manifest.json
+10
-4
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.2.5",
6
+
"version": "1.3.14",
6
7
"permissions": ["declarativeNetRequestWithHostAccess", "webRequest", "scripting", "webNavigation"],
7
-
"host_permissions": ["https://moonlight-mod.github.io/*", "https://api.github.com/*", "https://*.discord.com/*"],
8
+
"host_permissions": [
9
+
"https://moonlight-mod.github.io/*",
10
+
"https://api.github.com/*",
11
+
"https://*.discord.com/*",
12
+
"https://*.discordapp.com/*"
13
+
],
8
14
"content_scripts": [
9
15
{
10
16
"js": ["index.js"],
11
-
"matches": ["https://*.discord.com/*"],
17
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"],
12
18
"run_at": "document_start",
13
19
"world": "MAIN"
14
20
}
···
34
40
"web_accessible_resources": [
35
41
{
36
42
"resources": ["index.js"],
37
-
"matches": ["https://*.discord.com/*"]
43
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"]
38
44
}
39
45
]
40
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.2.5",
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
}
+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
-39
packages/browser/src/background.js
+37
-39
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
-
}
27
23
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);
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
+
});
32
+
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) => script.src && urls.some((url) => url.includes(script.src))
85
+
(script) => script.src && blockedScripts.some((url) => url.includes(script.src))
83
86
);
84
87
85
-
// backwards
86
-
urls.reverse();
87
-
for (const url of urls) {
88
-
const script = scripts.find((script) => url.includes(script.src));
89
-
console.log("adding new script", script);
88
+
blockedScripts.reverse();
89
+
for (const url of blockedScripts) {
90
+
if (url.includes("/sentry.")) continue;
90
91
92
+
const script = scripts.find((script) => url.includes(script.src));
91
93
const newScript = document.createElement("script");
92
-
for (const { name, value } of script.attributes) {
93
-
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);
94
97
}
95
-
96
98
script.remove();
97
99
document.documentElement.appendChild(newScript);
98
100
}
99
101
}
100
102
});
101
103
} catch (e) {
102
-
console.log(e);
104
+
console.error(e);
103
105
}
104
-
105
-
console.log("Done");
106
-
doing = false;
107
-
collectedUrls.clear();
108
106
}
109
107
},
110
108
{
111
-
urls: ["*://*.discord.com/assets/*.js"]
109
+
urls: ["*://*.discord.com/assets/*.js", "*://*.discordapp.com/assets/*.js"]
112
110
}
113
111
);
+18
-14
packages/browser/src/index.ts
+18
-14
packages/browser/src/index.ts
···
6
6
import { MoonlightBranch, MoonlightNode } from "@moonlight-mod/types";
7
7
import { getConfig, getConfigOption, getManifest, setConfigOption } from "@moonlight-mod/core/util/config";
8
8
import { IndexedDB } from "@zenfs/dom";
9
-
import { configure } from "@zenfs/core";
9
+
import { configureSingle } from "@zenfs/core";
10
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";
11
13
12
14
function getParts(path: string) {
13
15
if (path.startsWith("/")) path = path.substring(1);
···
15
17
}
16
18
17
19
window._moonlightBrowserInit = async () => {
20
+
delete window._moonlightBrowserInit;
21
+
18
22
// Set up a virtual filesystem with IndexedDB
19
-
await configure({
20
-
mounts: {
21
-
"/": {
22
-
backend: IndexedDB,
23
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
24
-
// @ts-ignore tsc tweaking
25
-
storeName: "moonlight-fs"
26
-
}
27
-
}
23
+
await configureSingle({
24
+
backend: IndexedDB,
25
+
storeName: "moonlight-fs"
28
26
});
29
27
30
28
window.moonlightNodeSandboxed = {
···
92
90
dirname(path) {
93
91
const parts = getParts(path);
94
92
return "/" + parts.slice(0, parts.length - 1).join("/");
93
+
},
94
+
basename(path) {
95
+
const parts = getParts(path);
96
+
return parts[parts.length - 1];
95
97
}
96
98
},
97
99
// TODO
···
114
116
processedExtensions,
115
117
nativesCache: {},
116
118
isBrowser: true,
119
+
events: createEventEmitter<NodeEventType, NodeEventPayloads>(),
117
120
118
121
version: MOONLIGHT_VERSION,
119
122
branch: MOONLIGHT_BRANCH as MoonlightBranch,
···
123
126
},
124
127
getConfigOption(ext, name) {
125
128
const manifest = getManifest(extensions, ext);
126
-
return getConfigOption(ext, name, config, manifest);
129
+
return getConfigOption(ext, name, config, manifest?.settings);
127
130
},
128
-
setConfigOption(ext, name, value) {
131
+
async setConfigOption(ext, name, value) {
129
132
setConfigOption(config, ext, name, value);
130
-
this.writeConfig(config);
133
+
await this.writeConfig(config);
131
134
},
132
135
133
136
getNatives: () => {},
···
145
148
async writeConfig(newConfig) {
146
149
await writeConfig(newConfig);
147
150
config = newConfig;
151
+
this.events.dispatchEvent(NodeEventType.ConfigSaved, newConfig);
148
152
}
149
153
};
150
154
···
153
157
});
154
158
155
159
// This is set by web-preload for us
156
-
await window._moonlightBrowserLoad();
160
+
await window._moonlightWebLoad!();
157
161
};
+1
packages/browser/tsconfig.json
+1
packages/browser/tsconfig.json
+7
packages/core/package.json
+7
packages/core/package.json
+8
-15
packages/core/src/extension/loader.ts
+8
-15
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
···
60
60
let idx = 0;
61
61
for (const patch of exports.patches) {
62
62
if (Array.isArray(patch.replace)) {
63
-
for (const replacement of patch.replace) {
64
-
const newPatch = Object.assign({}, patch, {
65
-
replace: replacement
66
-
});
67
-
68
-
registerPatch({ ...newPatch, ext: ext.id, id: idx });
69
-
idx++;
70
-
}
63
+
registerPatch({ ...patch, ext: ext.id, id: idx });
71
64
} else {
72
-
registerPatch({ ...patch, ext: ext.id, id: idx });
73
-
idx++;
65
+
registerPatch({ ...patch, replace: [patch.replace], ext: ext.id, id: idx });
74
66
}
67
+
idx++;
75
68
}
76
69
}
77
70
···
209
202
}
210
203
211
204
export async function loadProcessedExtensions({ extensions, dependencyGraph }: ProcessedExtensions) {
212
-
const eventEmitter = createEventEmitter<EventType, EventPayloads>();
205
+
const eventEmitter = createEventEmitter<WebEventType, WebEventPayloads>();
213
206
const finished: Set<string> = new Set();
214
207
215
208
logger.trace(
···
231
224
}
232
225
233
226
function done() {
234
-
eventEmitter.removeEventListener(EventType.ExtensionLoad, cb);
227
+
eventEmitter.removeEventListener(WebEventType.ExtensionLoad, cb);
235
228
r();
236
229
}
237
230
238
-
eventEmitter.addEventListener(EventType.ExtensionLoad, cb);
231
+
eventEmitter.addEventListener(WebEventType.ExtensionLoad, cb);
239
232
if (finished.has(dep)) done();
240
233
})
241
234
);
···
249
242
await loadExt(ext);
250
243
251
244
finished.add(ext.id);
252
-
eventEmitter.dispatchEvent(EventType.ExtensionLoad, ext.id);
245
+
eventEmitter.dispatchEvent(WebEventType.ExtensionLoad, ext.id);
253
246
logger.debug(`Loaded "${ext.id}"`);
254
247
}
255
248
+1
-4
packages/core/src/extension.ts
+1
-4
packages/core/src/extension.ts
···
129
129
const ret: DetectedExtension[] = [];
130
130
const seen = new Set<string>();
131
131
132
-
const coreExtensionsFs: Record<string, string> = JSON.parse(
133
-
// @ts-expect-error shut up
134
-
_moonlight_coreExtensionsStr
135
-
);
132
+
const coreExtensionsFs: Record<string, string> = JSON.parse(_moonlight_coreExtensionsStr);
136
133
const coreExtensions = Array.from(new Set(Object.keys(coreExtensionsFs).map((x) => x.split("/")[0])));
137
134
138
135
for (const ext of coreExtensions) {
+3
packages/core/src/fs.ts
+3
packages/core/src/fs.ts
+123
-69
packages/core/src/patch.ts
+123
-69
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
···
24
24
const moduleLoadSubscriptions: Map<string, ((moduleId: string) => void)[]> = new Map();
25
25
26
26
export function registerPatch(patch: IdentifiedPatch) {
27
+
patch.find = processFind(patch.find);
28
+
processReplace(patch.replace);
29
+
27
30
patches.push(patch);
28
31
moonlight.unpatched.add(patch);
29
32
}
···
63
66
const moduleCache: Record<string, string> = {};
64
67
const patched: Record<string, Array<string>> = {};
65
68
66
-
function patchModules(entry: WebpackJsonpEntry[1]) {
67
-
function patchModule(id: string, patchId: string, replaced: string) {
68
-
// Store what extensions patched what modules for easier debugging
69
-
patched[id] = patched[id] || [];
70
-
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);
71
83
72
-
// Webpack module arguments are minified, so we replace them with consistent names
73
-
// We have to wrap it so things don't break, though
74
-
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(", ");
75
87
76
-
const wrapped =
77
-
`(${replaced}).apply(this, arguments)\n` +
78
-
`// Patched by moonlight: ${patchedStr}\n` +
79
-
`//# sourceURL=Webpack-Module-${id}`;
88
+
const wrapped =
89
+
`(${replaced}).apply(this, arguments)\n` + `// Patched by moonlight: ${patchedStr}\n` + createSourceURL(id);
80
90
81
-
try {
82
-
const func = new Function("module", "exports", "require", wrapped) as WebpackModuleFunc;
83
-
entry[id] = func;
84
-
entry[id].__moonlight = true;
85
-
return true;
86
-
} catch (e) {
87
-
logger.warn("Error constructing function for patch", patchId, e);
88
-
patched[id].pop();
89
-
return false;
90
-
}
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;
91
100
}
101
+
}
92
102
103
+
function patchModules(entry: WebpackJsonpEntry[1]) {
93
104
// Populate the module cache
94
105
for (const [id, func] of Object.entries(entry)) {
95
106
if (!Object.hasOwn(moduleCache, id) && func.__moonlight !== true) {
···
100
111
101
112
for (const [id, func] of Object.entries(entry)) {
102
113
if (func.__moonlight === true) continue;
103
-
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>();
104
124
105
125
for (let i = 0; i < patches.length; i++) {
106
126
const patch = patches[i];
107
127
if (patch.prerequisite != null && !patch.prerequisite()) {
128
+
moonlight.unpatched.delete(patch);
108
129
continue;
109
130
}
110
131
···
113
134
patch.find.lastIndex = 0;
114
135
}
115
136
116
-
// indexOf is faster than includes by 0.25% lmao
117
-
const match =
118
-
typeof patch.find === "string" ? moduleString.indexOf(patch.find) !== -1 : patch.find.test(moduleString);
137
+
const match = testFind(origModuleString, patch.find) || patch.find === mappedName;
119
138
120
139
// Global regexes apply to all modules
121
140
const shouldRemove = typeof patch.find === "string" ? true : !patch.find.global;
122
141
142
+
let replaced = moduleString;
143
+
let hardFailed = false;
123
144
if (match) {
124
-
// We ensured all arrays get turned into normal PatchReplace objects on register
125
-
const replace = patch.replace as PatchReplace;
145
+
// We ensured normal PatchReplace objects get turned into arrays on register
146
+
const replaces = patch.replace as PatchReplace[];
126
147
127
-
if (replace.type === undefined || replace.type === PatchReplaceType.Normal) {
128
-
// Add support for \i to match rspack's minified names
129
-
if (typeof replace.match !== "string") {
130
-
replace.match = new RegExp(replace.match.source.replace(/\\i/g, "[A-Za-z_$][\\w$]*"), replace.match.flags);
131
-
}
132
-
// tsc fails to detect the overloads for this, so I'll just do this
133
-
// Verbose, but it works
134
-
let replaced;
135
-
if (typeof replace.replacement === "string") {
136
-
replaced = moduleString.replace(replace.match, replace.replacement);
137
-
} else {
138
-
replaced = moduleString.replace(replace.match, replace.replacement);
139
-
}
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);
140
154
141
-
if (replaced === moduleString) {
142
-
logger.warn("Patch replacement failed", id, patch);
143
-
continue;
144
-
}
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
+
}
145
163
146
-
if (patchModule(id, `${patch.ext}#${patch.id}`, replaced)) {
147
-
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;
148
181
}
149
-
} else if (replace.type === PatchReplaceType.Module) {
150
-
// Directly replace the module with a new one
151
-
const newModule = replace.replacement(moduleString);
152
-
entry[id] = newModule;
153
-
entry[id].__moonlight = true;
154
-
moduleString = newModule.toString().replace(/\n/g, "") + `//# sourceURL=Webpack-Module-${id}`;
155
182
}
156
183
157
-
moonlight.unpatched.delete(patch);
158
-
159
-
if (shouldRemove) {
160
-
patches.splice(i--, 1);
184
+
if (!hardFailed) {
185
+
moduleString = replaced;
186
+
modified = true;
187
+
exts.add(patch.ext);
161
188
}
189
+
190
+
if (isPatched) moonlight.unpatched.delete(patch);
191
+
if (shouldRemove) patches.splice(i--, 1);
162
192
}
163
193
}
164
194
165
-
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
+
}
166
201
167
202
try {
168
203
const parsed = moonlight.lunast.parseScript(id, moduleString);
169
204
if (parsed != null) {
170
205
for (const [parsedId, parsedScript] of Object.entries(parsed)) {
171
-
if (patchModule(parsedId, "lunast", parsedScript)) {
206
+
if (patchModule(parsedId, "lunast", parsedScript, entry)) {
172
207
moduleCache[parsedId] = parsedScript;
173
208
}
174
209
}
···
179
214
180
215
if (moonlightNode.config.patchAll === true) {
181
216
if ((typeof id !== "string" || !id.includes("_")) && !entry[id].__moonlight) {
182
-
const wrapped = `(${moduleCache[id]}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module-${id}`;
217
+
const wrapped = `(${moduleCache[id]}).apply(this, arguments)\n` + createSourceURL(id);
183
218
entry[id] = new Function("module", "exports", "require", wrapped) as WebpackModuleFunc;
184
219
entry[id].__moonlight = true;
185
220
}
···
271
306
}
272
307
}
273
308
309
+
wpModule.dependencies = Array.from(deps);
274
310
if (deps.size !== 0) {
275
-
wpModule.dependencies = Array.from(deps);
276
311
continue;
277
312
}
278
-
279
-
wpModule.dependencies = Array.from(deps);
280
313
}
281
314
}
282
315
···
289
322
if (wpModule.run) {
290
323
modules[id] = wpModule.run;
291
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);
292
334
}
293
-
if (wpModule.entrypoint) entrypoints.push(id);
294
335
}
295
336
if (!webpackModules.size) break;
296
337
}
297
338
298
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;
299
342
injectedWpModules.push({ id: name, run: func });
300
343
modules[name] = func;
301
344
inject = true;
···
312
355
window.webpackChunkdiscord_app.push([
313
356
[--chunkId],
314
357
modules,
315
-
(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
+
})
316
370
]);
317
371
}
318
372
}
···
362
416
const realPush = jsonp.push;
363
417
if (jsonp.push.__moonlight !== true) {
364
418
jsonp.push = (items) => {
365
-
moonlight.events.dispatchEvent(EventType.ChunkLoad, {
419
+
moonlight.events.dispatchEvent(WebEventType.ChunkLoad, {
366
420
chunkId: items[0],
367
421
modules: items[1],
368
422
require: items[2]
···
410
464
set(modules: any) {
411
465
const { stack } = new Error();
412
466
if (stack!.includes("/assets/") && !Array.isArray(modules)) {
413
-
moonlight.events.dispatchEvent(EventType.ChunkLoad, {
467
+
moonlight.events.dispatchEvent(WebEventType.ChunkLoad, {
414
468
modules: modules
415
469
});
416
470
patchModules(modules);
+2
-2
packages/core/src/util/config.ts
+2
-2
packages/core/src/util/config.ts
···
14
14
ext: string,
15
15
key: string,
16
16
config: Config,
17
-
manifest?: ExtensionManifest
17
+
settings?: ExtensionManifest["settings"]
18
18
): T | undefined {
19
-
const defaultValue: T | undefined = structuredClone(manifest?.settings?.[key]?.default);
19
+
const defaultValue: T | undefined = structuredClone(settings?.[key]?.default);
20
20
const cfg = getConfig(ext, config);
21
21
if (cfg == null || typeof cfg === "boolean") return defaultValue;
22
22
return cfg?.[key] ?? defaultValue;
+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
}
+1
packages/core-extensions/src/appPanels/manifest.json
+1
packages/core-extensions/src/appPanels/manifest.json
+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;
+1
packages/core-extensions/src/contextMenu/manifest.json
+1
packages/core-extensions/src/contextMenu/manifest.json
+17
-6
packages/core-extensions/src/contextMenu/webpackModules/contextMenu.ts
+17
-6
packages/core-extensions/src/contextMenu/webpackModules/contextMenu.ts
···
2
2
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
3
3
import parser from "@moonlight-mod/wp/contextMenu_evilMenu";
4
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
+
5
11
type Patch = {
6
12
navId: string;
7
-
item: (props: any) => MenuElement | MenuElement[];
8
-
anchorId: string;
13
+
item: React.FC<any>;
14
+
anchor: string | RegExp;
9
15
before: boolean;
10
16
};
11
17
12
-
function addItem<T>(navId: string, item: (props: T) => MenuElement | MenuElement[], anchorId: string, before = false) {
13
-
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 });
14
22
}
15
23
16
24
const patches: Patch[] = [];
···
19
27
if (!matches.length) return items;
20
28
21
29
for (const patch of matches) {
22
-
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
+
);
23
33
if (idx === -1) continue;
24
-
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));
25
35
}
26
36
27
37
return items;
···
48
58
};
49
59
50
60
// Unmangle Menu elements
61
+
// spacepack.require.m[moonlight.moonmap.modules["discord/modules/menus/web/Menu"]].toString();
51
62
const code =
52
63
spacepack.require.m[
53
64
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
+2
-1
packages/core-extensions/src/contextMenu/webpackModules/evilMenu.ts
+2
-1
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
6
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
···
7
8
8
9
const parserSym = code.match(/(?<=_patchMenu\(.,).+?(?=\()/)![0];
9
10
10
-
code = code.replace(/(?<=function\(\){return ).(?=})/, parserSym);
11
+
code = code.replace(/{(.):\(\)=>./, (orig, e) => `{${e}:()=>${parserSym}`);
11
12
const mod = new Function("module", "exports", "require", `(${code}).apply(this, arguments)`);
12
13
13
14
const exp: any = {};
+1
packages/core-extensions/src/devToolsExtensions/manifest.json
+1
packages/core-extensions/src/devToolsExtensions/manifest.json
+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
-15
packages/core-extensions/src/disableSentry/node.ts
+13
-15
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(resolve(preloadPath, "..", "node_modules", "@sentry", "electron"));
12
-
require.cache[sentryPath] = new Module(sentryPath, require.cache[require.resolve(preloadPath)]);
13
-
require.cache[sentryPath]!.exports = {
14
-
init: () => {},
15
-
setTag: () => {},
16
-
setUser: () => {},
17
-
captureMessage: () => {}
18
-
};
19
-
logger.debug("Stubbed Sentry node side!");
20
-
} catch (err) {
21
-
logger.error("Failed to stub Sentry:", err);
22
-
}
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);
23
21
}
+23
-9
packages/core-extensions/src/experiments/index.ts
+23
-9
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
16
}
17
17
},
18
18
19
19
// Enable staff help menu
20
-
// FIXME: either make this actually work live (needs a state hook) or just
21
-
// wait for #122
22
20
{
23
21
find: ".HEADER_BAR)",
24
22
replace: {
25
-
match: /&&\((.)\?\(0,/,
23
+
match: /&&\((\i)\?\(0,/,
26
24
replacement: (_, isStaff) =>
27
25
`&&(((moonlight.getConfigOption("experiments","devtools")??false)?true:${isStaff})?(0,`
28
26
}
29
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
+
},
30
45
31
46
// Enable further staff-locked options
32
-
// FIXME: #122, this doesn't work live
33
47
{
34
48
find: "shouldShowLurkerModeUpsellPopout:",
35
49
replace: {
36
-
match: /\.useReducedMotion,isStaff:(.),/,
37
-
replacement: (_, isStaff) =>
38
-
`.useReducedMotion,isStaff:(moonlight.getConfigOption("experiments","staffSettings")??false)?true:${isStaff},`
50
+
match: /\.useReducedMotion,isStaff:(\i)(,|})/,
51
+
replacement: (_, isStaff, trail) =>
52
+
`.useReducedMotion,isStaff:(moonlight.getConfigOption("experiments","staffSettings")??false)?true:${isStaff}${trail}`
39
53
}
40
54
}
41
55
];
+3
packages/core-extensions/src/experiments/manifest.json
+3
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": {
···
9
10
},
10
11
"settings": {
11
12
"devtools": {
13
+
"advice": "reload",
12
14
"displayName": "Enable staff help menu (DevTools)",
13
15
"type": "boolean",
14
16
"default": false
15
17
},
16
18
"staffSettings": {
19
+
"advice": "reload",
17
20
"displayName": "Allow access to other staff settings elsewhere",
18
21
"type": "boolean",
19
22
"default": false
+1
packages/core-extensions/src/markdown/manifest.json
+1
packages/core-extensions/src/markdown/manifest.json
+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
+
});
+18
-6
packages/core-extensions/src/moonbase/index.tsx
+18
-6
packages/core-extensions/src/moonbase/index.tsx
···
8
8
{
9
9
// CvQlAA mapped to ERRORS_ACTION_TO_TAKE
10
10
// FIXME: Better patch find?
11
-
match: /,(\(0,(.)\.jsx\))\("p",{children:.\.intl\.string\(.\..\.CvQlAA\)}\)/,
11
+
match: /,(\(0,(\i)\.jsx\))\("p",{children:\i\.\i\.string\(\i\.\i\.CvQlAA\)}\)/,
12
12
replacement: (_, createElement, ReactJSX) =>
13
13
`,${createElement}(require("moonbase_crashScreen")?.UpdateText??${ReactJSX}.Fragment,{state:this.state,setState:this.setState.bind(this)})`
14
14
},
15
15
16
16
// wrap actions field to display error details
17
17
{
18
-
match: /(?<=return(\(0,(.)\.jsx\))\(.+?,)action:(.),className:/,
18
+
match: /(?<=return(\(0,(\i)\.jsx\))\(.+?,)action:(\i),className:/,
19
19
replacement: (_, createElement, ReactJSX, action) =>
20
20
`action:require("moonbase_crashScreen")?.wrapAction?${createElement}(require("moonbase_crashScreen").wrapAction,{action:${action},state:this.state}):${action},className:`
21
21
},
···
23
23
// add update button
24
24
// +hivLS -> ERRORS_RELOAD
25
25
{
26
-
match: /(?<=\["\+hivLS"\]\)}\),(\(0,(.)\.jsx\))\(.,{}\))/,
26
+
match: /(?<=\["\+hivLS"\]\)}\),(\(0,(\i)\.jsx\))\(\i,{}\))/,
27
27
replacement: (_, createElement, ReactJSX) =>
28
28
`,${createElement}(require("moonbase_crashScreen")?.UpdateButton??${ReactJSX}.Fragment,{state:this.state,setState:this.setState.bind(this)})`
29
29
}
···
42
42
{ id: "react" },
43
43
{ id: "discord/components/common/index" },
44
44
{ ext: "moonbase", id: "stores" },
45
-
{ 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" },
46
49
"Masks.PANEL_BUTTON",
47
50
'"Missing channel in Channel.openChannelContextMenu"',
48
51
".forumOrHome]:"
49
52
]
50
53
},
51
54
55
+
ThemeDarkIcon: {
56
+
dependencies: [{ ext: "common", id: "icons" }, { id: "react" }]
57
+
},
58
+
52
59
settings: {
53
60
dependencies: [
54
61
{ ext: "spacepack", id: "spacepack" },
55
62
{ ext: "settings", id: "settings" },
56
63
{ id: "react" },
57
-
{ ext: "moonbase", id: "ui" }
64
+
{ ext: "moonbase", id: "ui" },
65
+
{ ext: "contextMenu", id: "contextMenu" },
66
+
':"USER_SETTINGS_MODAL_SET_SECTION"'
58
67
],
59
68
entrypoint: true
60
69
},
···
63
72
dependencies: [
64
73
{ id: "react" },
65
74
{ ext: "moonbase", id: "stores" },
75
+
{ ext: "moonbase", id: "ThemeDarkIcon" },
66
76
{ ext: "notices", id: "notices" },
67
77
{
68
78
ext: "spacepack",
69
79
id: "spacepack"
70
-
}
80
+
},
81
+
{ id: "discord/Constants" },
82
+
{ id: "discord/components/common/index" }
71
83
],
72
84
entrypoint: true
73
85
},
+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": [
+29
-34
packages/core-extensions/src/moonbase/native.ts
+29
-34
packages/core-extensions/src/moonbase/native.ts
···
4
4
import { distDir, repoUrlFile, installedVersionFile } from "@moonlight-mod/types/constants";
5
5
import { parseTarGzip } from "nanotar";
6
6
7
+
const moonlightGlobal = globalThis.moonlightHost ?? globalThis.moonlightNode;
8
+
7
9
const githubRepo = "moonlight-mod/moonlight";
8
10
const githubApiUrl = `https://api.github.com/repos/${githubRepo}/releases/latest`;
9
11
const artifactName = "dist.tar.gz";
···
11
13
const nightlyRefUrl = "https://moonlight-mod.github.io/moonlight/ref";
12
14
const nightlyZipUrl = "https://moonlight-mod.github.io/moonlight/dist.tar.gz";
13
15
14
-
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;
15
22
16
23
async function getStableRelease(): Promise<{
17
24
name: string;
···
22
29
}> {
23
30
const req = await fetch(githubApiUrl, {
24
31
cache: "no-store",
25
-
headers: {
26
-
"User-Agent": userAgent
27
-
}
32
+
headers: sharedHeaders
28
33
});
29
34
return await req.json();
30
35
}
31
36
32
37
export default function getNatives(): MoonbaseNatives {
33
-
const logger = moonlightNode.getLogger("moonbase/natives");
38
+
const logger = moonlightGlobal.getLogger("moonbase/natives");
34
39
35
40
return {
36
41
async checkForMoonlightUpdate() {
37
42
try {
38
-
if (moonlightNode.branch === MoonlightBranch.STABLE) {
43
+
if (moonlightGlobal.branch === MoonlightBranch.STABLE) {
39
44
const json = await getStableRelease();
40
-
return json.name !== moonlightNode.version ? json.name : null;
41
-
} else if (moonlightNode.branch === MoonlightBranch.NIGHTLY) {
45
+
return json.name !== moonlightGlobal.version ? json.name : null;
46
+
} else if (moonlightGlobal.branch === MoonlightBranch.NIGHTLY) {
42
47
const req = await fetch(nightlyRefUrl, {
43
48
cache: "no-store",
44
-
headers: {
45
-
"User-Agent": userAgent
46
-
}
49
+
headers: sharedHeaders
47
50
});
48
51
const ref = (await req.text()).split("\n")[0];
49
-
return ref !== moonlightNode.version ? ref : null;
52
+
return ref !== moonlightGlobal.version ? ref : null;
50
53
}
51
54
52
55
return null;
···
56
59
}
57
60
},
58
61
59
-
async updateMoonlight() {
62
+
async updateMoonlight(overrideBranch?: MoonlightBranch) {
63
+
const branch = overrideBranch ?? moonlightGlobal.branch;
64
+
60
65
// Note: this won't do anything on browser, we should probably disable it
61
66
// entirely when running in browser.
62
67
async function downloadStable(): Promise<[ArrayBuffer, string]> {
···
67
72
logger.debug(`Downloading ${asset.browser_download_url}`);
68
73
const req = await fetch(asset.browser_download_url, {
69
74
cache: "no-store",
70
-
headers: {
71
-
"User-Agent": userAgent
72
-
}
75
+
headers: sharedHeaders
73
76
});
74
77
75
78
return [await req.arrayBuffer(), json.name];
···
79
82
logger.debug(`Downloading ${nightlyZipUrl}`);
80
83
const zipReq = await fetch(nightlyZipUrl, {
81
84
cache: "no-store",
82
-
headers: {
83
-
"User-Agent": userAgent
84
-
}
85
+
headers: sharedHeaders
85
86
});
86
87
87
88
const refReq = await fetch(nightlyRefUrl, {
88
89
cache: "no-store",
89
-
headers: {
90
-
"User-Agent": userAgent
91
-
}
90
+
headers: sharedHeaders
92
91
});
93
92
const ref = (await refReq.text()).split("\n")[0];
94
93
···
96
95
}
97
96
98
97
const [tar, ref] =
99
-
moonlightNode.branch === MoonlightBranch.STABLE
98
+
branch === MoonlightBranch.STABLE
100
99
? await downloadStable()
101
-
: moonlightNode.branch === MoonlightBranch.NIGHTLY
100
+
: branch === MoonlightBranch.NIGHTLY
102
101
? await downloadNightly()
103
102
: [null, null];
104
103
105
104
if (!tar || !ref) return;
106
105
107
-
const dist = moonlightNodeSandboxed.fs.join(moonlightNode.getMoonlightDir(), distDir);
106
+
const dist = moonlightNodeSandboxed.fs.join(moonlightGlobal.getMoonlightDir(), distDir);
108
107
if (await moonlightNodeSandboxed.fs.exists(dist)) await moonlightNodeSandboxed.fs.rmdir(dist);
109
108
await moonlightNodeSandboxed.fs.mkdir(dist);
110
109
···
122
121
}
123
122
124
123
logger.debug("Writing version file:", ref);
125
-
const versionFile = moonlightNodeSandboxed.fs.join(moonlightNode.getMoonlightDir(), installedVersionFile);
124
+
const versionFile = moonlightNodeSandboxed.fs.join(moonlightGlobal.getMoonlightDir(), installedVersionFile);
126
125
await moonlightNodeSandboxed.fs.writeFileString(versionFile, ref.trim());
127
126
128
127
logger.debug("Update extracted");
···
135
134
try {
136
135
const req = await fetch(repo, {
137
136
cache: "no-store",
138
-
headers: {
139
-
"User-Agent": userAgent
140
-
}
137
+
headers: sharedHeaders
141
138
});
142
139
const json = await req.json();
143
140
ret[repo] = json;
···
152
149
async installExtension(manifest, url, repo) {
153
150
const req = await fetch(url, {
154
151
cache: "no-store",
155
-
headers: {
156
-
"User-Agent": userAgent
157
-
}
152
+
headers: sharedHeaders
158
153
});
159
154
160
-
const dir = moonlightNode.getExtensionDir(manifest.id);
155
+
const dir = moonlightGlobal.getExtensionDir(manifest.id);
161
156
// remake it in case of updates
162
157
if (await moonlightNodeSandboxed.fs.exists(dir)) await moonlightNodeSandboxed.fs.rmdir(dir);
163
158
await moonlightNodeSandboxed.fs.mkdir(dir);
···
176
171
},
177
172
178
173
async deleteExtension(id) {
179
-
const dir = moonlightNode.getExtensionDir(id);
174
+
const dir = moonlightGlobal.getExtensionDir(id);
180
175
await moonlightNodeSandboxed.fs.rmdir(dir);
181
176
}
182
177
};
+99
-11
packages/core-extensions/src/moonbase/style.css
+99
-11
packages/core-extensions/src/moonbase/style.css
···
3
3
--moonbase-fg: #fffba6;
4
4
}
5
5
6
-
.moonbase-settings> :first-child {
6
+
.moonbase-settings > :first-child {
7
7
margin-top: 0px;
8
+
}
9
+
10
+
.moonbase-retry-button {
11
+
padding: 8px;
12
+
margin-right: 8px;
8
13
}
9
14
10
15
textarea.moonbase-resizeable {
11
16
resize: vertical;
12
17
}
13
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 */
14
41
.moonbase-updates-notice {
15
42
background-color: var(--moonbase-bg);
16
43
color: var(--moonbase-fg);
44
+
--custom-notice-text: var(--moonbase-fg);
17
45
line-height: unset;
18
46
height: 36px;
19
47
}
···
30
58
gap: 2px;
31
59
}
32
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
+
33
79
.moonbase-update-section {
34
80
background-color: var(--moonbase-bg);
35
81
--info-help-foreground: var(--moonbase-fg);
36
82
border: none !important;
37
83
color: var(--moonbase-fg);
38
-
39
-
display: flex;
40
-
flex-direction: row;
41
-
justify-content: space-between;
42
84
}
43
85
44
86
.moonbase-update-section button {
···
48
90
border-color: var(--moonbase-fg);
49
91
}
50
92
51
-
.moonbase-update-section-buttons {
93
+
.moonbase-help-message-buttons {
52
94
display: flex;
53
95
flex-direction: row;
54
96
gap: 8px;
97
+
align-items: center;
55
98
}
56
99
57
-
/* crash screen */
58
-
.moonbase-crash-wrapper>[class^="buttons_"] {
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_"] {
59
117
gap: 1rem;
60
118
}
61
119
···
106
164
box-sizing: border-box;
107
165
padding: 0;
108
166
font-family: var(--font-code);
109
-
font-size: .75rem;
167
+
font-size: 0.75rem;
110
168
line-height: 1rem;
111
169
margin: 6px;
112
170
white-space: pre-wrap;
113
171
background-clip: border-box;
114
172
115
-
&>code {
116
-
font-size: .875rem;
173
+
& > code {
174
+
font-size: 0.875rem;
117
175
line-height: 1.125rem;
118
176
text-indent: 0;
119
177
white-space: pre-wrap;
···
179
237
line-height: 1.286;
180
238
font-weight: 400;
181
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
+
}
+12
-2
packages/core-extensions/src/moonbase/types.ts
+12
-2
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
8
fetchRepositories(repos: string[]): Promise<Record<string, RepositoryManifest[]>>;
9
9
installExtension(manifest: RepositoryManifest, url: string, repo: string): Promise<void>;
···
28
28
state: ExtensionState;
29
29
compat: ExtensionCompat;
30
30
hasUpdate: boolean;
31
+
changelog?: string;
32
+
settingsOverride?: ExtensionManifest["settings"];
31
33
};
32
34
33
35
export enum UpdateState {
···
36
38
Installed,
37
39
Failed
38
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
+
}
+90
-9
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
+90
-9
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
···
1
1
import React from "@moonlight-mod/wp/react";
2
-
import * as Components from "@moonlight-mod/wp/discord/components/common/index";
2
+
import { Button, TabBar } from "@moonlight-mod/wp/discord/components/common/index";
3
3
import { useStateFromStores, useStateFromStoresObject } from "@moonlight-mod/wp/discord/packages/flux";
4
-
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
5
4
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
6
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";
7
8
8
-
const { Button, TabBar } = Components;
9
-
const TabBarClasses = spacepack.findByCode(/tabBar:"tabBar_[a-z0-9]+",tabBarItem:"tabBarItem_[a-z0-9]+"/)[0].exports;
9
+
const MODULE_REGEX = /Webpack-Module\/(\d+)\/(\d+)/g;
10
10
11
11
const logger = moonlight.getLogger("moonbase/crashScreen");
12
12
···
77
77
}}
78
78
>
79
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
80
122
</Button>
81
123
</div>
82
124
</div>
···
94
136
};
95
137
});
96
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
+
97
166
return (
98
167
<div className="moonbase-crash-wrapper">
99
168
{action}
100
169
<TabBar
101
-
className={`${TabBarClasses.tabBar} moonbase-crash-tabs`}
170
+
className={`${DiscoveryClasses.tabBar} moonbase-crash-tabs`}
102
171
type="top"
103
172
selectedItem={tab}
104
173
onItemSelect={(v) => setTab(v)}
105
174
>
106
-
<TabBar.Item className={TabBarClasses.tabBarItem} id="crash">
107
-
Crash Details
175
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id="crash">
176
+
Crash details
108
177
</TabBar.Item>
109
-
<TabBar.Item className={TabBarClasses.tabBarItem} id="extensions" disabled={updateCount === 0}>
110
-
{`Extension Updates (${updateCount})`}
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})`}
111
183
</TabBar.Item>
112
184
</TabBar>
113
185
{tab === "crash" ? (
···
126
198
{updates.map(([id, ext]) => (
127
199
<ExtensionUpdateCard id={Number(id)} ext={ext} />
128
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
+
))}
129
210
</div>
130
211
) : null}
131
212
</div>
+29
-19
packages/core-extensions/src/moonbase/webpackModules/settings.tsx
+29
-19
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].exports.Z;
8
+
import { Text, Breadcrumbs } from "@moonlight-mod/wp/discord/components/common/index";
9
+
import { MenuItem } from "@moonlight-mod/wp/contextMenu_contextMenu";
16
10
17
11
const notice = {
18
12
stores: [MoonbaseSettingsStore],
19
13
element: () => {
20
14
// Require it here because lazy loading SUX
21
-
const SettingsNotice = spacepack.findByCode("onSaveButtonColor", "FocusRingScope")[0].exports.Z;
15
+
const SettingsNotice = spacepack.require("discord/components/common/SettingsNotice").default;
22
16
return (
23
17
<SettingsNotice
24
18
submitting={MoonbaseSettingsStore.submitting}
25
19
onReset={() => {
26
20
MoonbaseSettingsStore.reset();
27
21
}}
28
-
onSave={() => {
29
-
MoonbaseSettingsStore.writeConfig();
22
+
onSave={async () => {
23
+
await MoonbaseSettingsStore.writeConfig();
30
24
}}
31
25
/>
32
26
);
33
27
}
34
28
};
35
29
30
+
const oldLocation = MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "oldLocation", false);
31
+
const position = oldLocation ? -2 : -9999;
32
+
36
33
function addSection(id: string, name: string, element: React.FunctionComponent) {
37
-
settings.addSection(`moonbase-${id}`, name, element, null, -2, notice);
34
+
settings.addSection(`moonbase-${id}`, name, element, null, position, notice);
38
35
}
39
36
40
37
// FIXME: move to component types
···
51
48
);
52
49
}
53
50
51
+
if (!oldLocation) {
52
+
settings.addDivider(position);
53
+
}
54
+
54
55
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "sections", false)) {
55
-
settings.addHeader("Moonbase", -2);
56
+
if (oldLocation) settings.addHeader("Moonbase", position);
56
57
57
-
for (const page of pages) {
58
+
const _pages = oldLocation ? pages : pages.reverse();
59
+
for (const page of _pages) {
58
60
addSection(page.id, page.name, () => {
59
61
const breadcrumbs = [
60
62
{ id: "moonbase", label: "Moonbase" },
···
71
73
{page.name}
72
74
</Breadcrumbs>
73
75
76
+
<RestartAdviceMessage />
74
77
<Update />
75
78
76
79
<page.element />
···
78
81
);
79
82
});
80
83
}
84
+
85
+
if (!oldLocation) settings.addHeader("Moonbase", position);
81
86
} else {
82
-
settings.addSection("moonbase", "Moonbase", Moonbase, null, -2, notice);
87
+
settings.addSection("moonbase", "Moonbase", Moonbase, null, position, notice);
83
88
84
89
settings.addSectionMenuItems(
85
90
"moonbase",
86
91
...pages.map((page, i) => (
87
-
<MenuItem key={page.id} id={`moonbase-${page.id}`} label={page.name} action={() => open("moonbase", i)} />
92
+
<MenuItem
93
+
key={page.id}
94
+
id={`moonbase-${page.id}`}
95
+
label={page.name}
96
+
action={() => UserSettingsModalActionCreators.open("moonbase", i.toString())}
97
+
/>
88
98
))
89
99
);
90
100
}
+262
-79
packages/core-extensions/src/moonbase/webpackModules/stores.ts
+262
-79
packages/core-extensions/src/moonbase/webpackModules/stores.ts
···
1
-
import { Config, ExtensionLoadSource } from "@moonlight-mod/types";
2
-
import { ExtensionState, MoonbaseExtension, MoonbaseNatives, RepositoryManifest } from "../types";
1
+
import { Config, ExtensionEnvironment, ExtensionLoadSource, ExtensionSettingsAdvice } from "@moonlight-mod/types";
2
+
import {
3
+
ExtensionState,
4
+
MoonbaseExtension,
5
+
MoonbaseNatives,
6
+
RepositoryManifest,
7
+
RestartAdvice,
8
+
UpdateState
9
+
} from "../types";
3
10
import { Store } from "@moonlight-mod/wp/discord/packages/flux";
4
11
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
5
12
import getNatives from "../native";
6
13
import { mainRepo } from "@moonlight-mod/types/constants";
7
14
import { checkExtensionCompat, ExtensionCompat } from "@moonlight-mod/core/extension/loader";
8
15
import { CustomComponent } from "@moonlight-mod/types/coreExtensions/moonbase";
16
+
import { NodeEventType } from "@moonlight-mod/types/core/event";
9
17
import { getConfigOption, setConfigOption } from "@moonlight-mod/core/util/config";
18
+
import diff from "microdiff";
10
19
11
20
const logger = moonlight.getLogger("moonbase");
12
21
···
14
23
if (moonlightNode.isBrowser) natives = getNatives();
15
24
16
25
class MoonbaseSettingsStore extends Store<any> {
17
-
private origConfig: Config;
26
+
private initialConfig: Config;
27
+
private savedConfig: Config;
18
28
private config: Config;
19
29
private extensionIndex: number;
20
30
private configComponents: Record<string, Record<string, CustomComponent>> = {};
···
23
33
submitting: boolean;
24
34
installing: boolean;
25
35
36
+
#updateState = UpdateState.Ready;
37
+
get updateState() {
38
+
return this.#updateState;
39
+
}
26
40
newVersion: string | null;
27
41
shouldShowNotice: boolean;
42
+
43
+
restartAdvice = RestartAdvice.NotNeeded;
28
44
29
45
extensions: { [id: number]: MoonbaseExtension };
30
46
updates: {
···
38
54
constructor() {
39
55
super(Dispatcher);
40
56
41
-
this.origConfig = moonlightNode.config;
42
-
this.config = this.clone(this.origConfig);
57
+
this.initialConfig = moonlightNode.config;
58
+
this.savedConfig = moonlightNode.config;
59
+
this.config = this.clone(this.savedConfig);
43
60
this.extensionIndex = 0;
44
61
45
62
this.modified = false;
···
62
79
};
63
80
}
64
81
65
-
natives!
66
-
.fetchRepositories(this.config.repositories)
67
-
.then((ret) => {
68
-
for (const [repo, exts] of Object.entries(ret)) {
69
-
try {
70
-
for (const ext of exts) {
71
-
const uniqueId = this.extensionIndex++;
72
-
const extensionData = {
73
-
id: ext.id,
74
-
uniqueId,
75
-
manifest: ext,
76
-
source: { type: ExtensionLoadSource.Normal, url: repo },
77
-
state: ExtensionState.NotDownloaded,
78
-
compat: ExtensionCompat.Compatible,
79
-
hasUpdate: false
80
-
};
82
+
// This is async but we're calling it without
83
+
this.checkUpdates();
81
84
82
-
// Don't present incompatible updates
83
-
if (checkExtensionCompat(ext) !== ExtensionCompat.Compatible) 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
+
}
94
+
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 = {};
84
111
85
-
const existing = this.getExisting(extensionData);
86
-
if (existing != null) {
87
-
// Make sure the download URL is properly updated
88
-
for (const [id, e] of Object.entries(this.extensions)) {
89
-
if (e.id === ext.id && e.source.url === repo) {
90
-
this.extensions[parseInt(id)].manifest = {
91
-
...e.manifest,
92
-
download: ext.download
93
-
};
94
-
break;
95
-
}
96
-
}
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
+
};
97
124
98
-
if (this.hasUpdate(extensionData)) {
99
-
this.updates[existing.uniqueId] = {
100
-
version: ext.version!,
101
-
download: ext.download,
102
-
updateManifest: ext
103
-
};
104
-
existing.hasUpdate = true;
105
-
}
125
+
// Don't present incompatible updates
126
+
if (checkExtensionCompat(ext) !== ExtensionCompat.Compatible) continue;
106
127
107
-
continue;
108
-
}
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
+
};
109
135
110
-
this.extensions[uniqueId] = extensionData;
111
-
}
112
-
} catch (e) {
113
-
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;
114
144
}
145
+
} else {
146
+
this.extensions[uniqueId] = extensionData;
115
147
}
148
+
}
149
+
}
150
+
}
116
151
117
-
this.emitChange();
118
-
})
119
-
.then(() =>
120
-
this.getExtensionConfigRaw("moonbase", "updateChecking", true)
121
-
? natives!.checkForMoonlightUpdate()
122
-
: new Promise<null>((resolve) => resolve(null))
123
-
)
124
-
.then((version) => {
125
-
this.newVersion = version;
126
-
this.emitChange();
127
-
})
128
-
.then(() => {
129
-
this.shouldShowNotice = this.newVersion != null || Object.keys(this.updates).length > 0;
130
-
this.emitChange();
131
-
});
152
+
private async checkMoonlightUpdates() {
153
+
this.newVersion = this.getExtensionConfigRaw("moonbase", "updateChecking", true)
154
+
? await natives!.checkForMoonlightUpdate()
155
+
: null;
132
156
}
133
157
134
158
private getExisting(ext: MoonbaseExtension) {
···
144
168
145
169
// Jank
146
170
private isModified() {
147
-
const orig = JSON.stringify(this.origConfig);
171
+
const orig = JSON.stringify(this.savedConfig);
148
172
const curr = JSON.stringify(this.config);
149
173
return orig !== curr;
150
174
}
···
153
177
return this.submitting || this.installing;
154
178
}
155
179
180
+
// Required for the settings store contract
156
181
showNotice() {
157
182
return this.modified;
158
183
}
···
192
217
193
218
getExtensionConfig<T>(uniqueId: number, key: string): T | undefined {
194
219
const ext = this.getExtension(uniqueId);
195
-
return getConfigOption(ext.id, key, this.config, ext.manifest);
220
+
const settings = ext.settingsOverride ?? ext.manifest.settings;
221
+
return getConfigOption(ext.id, key, this.config, settings);
196
222
}
197
223
198
224
getExtensionConfigRaw<T>(id: string, key: string, defaultValue: T | undefined): T | undefined {
···
203
229
204
230
getExtensionConfigName(uniqueId: number, key: string) {
205
231
const ext = this.getExtension(uniqueId);
206
-
return ext.manifest.settings?.[key]?.displayName ?? key;
232
+
const settings = ext.settingsOverride ?? ext.manifest.settings;
233
+
return settings?.[key]?.displayName ?? key;
207
234
}
208
235
209
236
getExtensionConfigDescription(uniqueId: number, key: string) {
210
237
const ext = this.getExtension(uniqueId);
211
-
return ext.manifest.settings?.[key]?.description;
238
+
const settings = ext.settingsOverride ?? ext.manifest.settings;
239
+
return settings?.[key]?.description;
212
240
}
213
241
214
242
setExtensionConfig(id: string, key: string, value: any) {
···
222
250
let val = this.config.extensions[ext.id];
223
251
224
252
if (val == null) {
225
-
this.config.extensions[ext.id] = { enabled };
253
+
this.config.extensions[ext.id] = enabled;
226
254
this.modified = this.isModified();
227
255
this.emitChange();
228
256
return;
···
239
267
this.emitChange();
240
268
}
241
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
+
242
287
async installExtension(uniqueId: number) {
243
288
const ext = this.getExtension(uniqueId);
244
289
if (!("download" in ext.manifest)) {
···
254
299
this.extensions[uniqueId].state = ExtensionState.Disabled;
255
300
}
256
301
257
-
if (update != null) this.extensions[uniqueId].compat = checkExtensionCompat(update.updateManifest);
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
+
}
258
309
259
310
delete this.updates[uniqueId];
260
311
} catch (e) {
···
262
313
}
263
314
264
315
this.installing = false;
316
+
this.restartAdvice = this.#computeRestartAdvice();
265
317
this.emitChange();
266
318
}
267
319
···
293
345
const aRank = this.getRank(a);
294
346
const bRank = this.getRank(b);
295
347
if (aRank === bRank) {
296
-
const repoIndex = this.config.repositories.indexOf(a.source.url!);
297
-
const otherRepoIndex = this.config.repositories.indexOf(b.source.url!);
348
+
const repoIndex = this.savedConfig.repositories.indexOf(a.source.url!);
349
+
const otherRepoIndex = this.savedConfig.repositories.indexOf(b.source.url!);
298
350
return repoIndex - otherRepoIndex;
299
351
} else {
300
352
return bRank - aRank;
···
318
370
}
319
371
320
372
this.installing = false;
373
+
this.restartAdvice = this.#computeRestartAdvice();
321
374
this.emitChange();
322
375
}
323
376
324
377
async updateMoonlight() {
325
-
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();
326
390
}
327
391
328
392
getConfigOption<K extends keyof Config>(key: K): Config[K] {
···
349
413
return this.configComponents[ext]?.[name];
350
414
}
351
415
352
-
writeConfig() {
353
-
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);
354
425
355
-
moonlightNode.writeConfig(this.config);
356
-
this.origConfig = this.clone(this.config);
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);
357
431
358
-
this.submitting = false;
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);
438
+
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();
359
529
this.modified = false;
530
+
531
+
const modifiedRepos = diff(this.savedConfig.repositories, this.config.repositories);
532
+
if (modifiedRepos.length !== 0) await this.checkUpdates();
533
+
360
534
this.emitChange();
361
535
}
362
536
363
537
reset() {
364
538
this.submitting = false;
365
539
this.modified = false;
366
-
this.config = this.clone(this.origConfig);
540
+
this.config = this.clone(this.savedConfig);
367
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
+
}
368
551
}
369
552
370
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
+
}
+14
-13
packages/core-extensions/src/moonbase/webpackModules/ui/config/index.tsx
+14
-13
packages/core-extensions/src/moonbase/webpackModules/ui/config/index.tsx
···
16
16
Clickable
17
17
} from "@moonlight-mod/wp/discord/components/common/index";
18
18
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
19
-
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";
20
22
21
23
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
22
24
23
-
const FormClasses = spacepack.findByCode("dividerDefault:")[0].exports;
24
-
const Margins = spacepack.findByCode("marginCenterHorz:")[0].exports;
25
-
26
-
let RemoveButtonClasses: any;
25
+
let GuildSettingsRoleEditClasses: any;
27
26
spacepack
28
27
.lazyLoad(
29
28
"renderArtisanalHack",
30
29
/\[(?:.\.e\("\d+?"\),?)+\][^}]+?webpackId:\d+,name:"GuildSettings"/,
31
30
/webpackId:(\d+),name:"GuildSettings"/
32
31
)
33
-
.then(() => (RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0].exports));
34
-
35
-
// FIXME: type component keys
36
-
const { CircleXIcon } = Components;
32
+
.then(
33
+
() =>
34
+
(GuildSettingsRoleEditClasses = spacepack.require(
35
+
"discord/modules/guild_settings/roles/web/GuildSettingsRoleEdit.css"
36
+
))
37
+
);
37
38
38
39
function RemoveEntryButton({ onClick }: { onClick: () => void }) {
39
40
return (
40
-
<div className={RemoveButtonClasses.removeButtonContainer}>
41
+
<div className={GuildSettingsRoleEditClasses.removeButtonContainer}>
41
42
<Tooltip text="Remove entry" position="top">
42
43
{(props: any) => (
43
-
<Clickable {...props} className={RemoveButtonClasses.removeButton} onClick={onClick}>
44
+
<Clickable {...props} className={GuildSettingsRoleEditClasses.removeButton} onClick={onClick}>
44
45
<CircleXIcon width={24} height={24} />
45
46
</Clickable>
46
47
)}
···
121
122
<FormText className={Margins.marginBottom4}>A list of remote repositories to display extensions from</FormText>
122
123
<ArrayFormItem config="repositories" />
123
124
</FormItem>
124
-
<FormDivider className={FormClasses.dividerDefault} />
125
+
<FormDivider className={FormSwitchClasses.dividerDefault} />
125
126
<FormItem title="Extension search paths" className={Margins.marginTop20}>
126
127
<FormText className={Margins.marginBottom4}>
127
128
A list of local directories to search for built extensions
128
129
</FormText>
129
130
<ArrayFormItem config="devSearchPaths" />
130
131
</FormItem>
131
-
<FormDivider className={FormClasses.dividerDefault} />
132
+
<FormDivider className={FormSwitchClasses.dividerDefault} />
132
133
<FormSwitch
133
134
className={Margins.marginTop20}
134
135
value={MoonbaseSettingsStore.getConfigOption("patchAll") ?? false}
+176
-86
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/card.tsx
+176
-86
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/card.tsx
···
1
1
import { ExtensionState } from "../../../types";
2
-
import { constants, 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 { doBuiltinExtensionPopup, doMissingExtensionPopup } 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, AngleBracketsIcon, CircleWarningIcon, Tooltip } = Components;
26
-
27
-
const PanelButton = spacepack.findByCode("Masks.PANEL_BUTTON")[0].exports.Z;
28
-
const TabBarClasses = spacepack.findByExports("tabBar", "tabBarItem", "headerContentWrapper")[0].exports;
29
-
const MarkupClasses = spacepack.findByExports("markup", "inlineFormat")[0].exports;
30
-
31
-
const BuildOverrideClasses = spacepack.findByExports("disabledButtonOverride")[0].exports;
32
-
33
43
const COMPAT_TEXT_MAP: Record<ExtensionCompat, string> = {
34
44
[ExtensionCompat.Compatible]: "huh?",
35
45
[ExtensionCompat.InvalidApiLevel]: "Incompatible API level",
36
46
[ExtensionCompat.InvalidEnvironment]: "Incompatible platform"
37
47
};
48
+
const CONFLICTING_TEXT = "This extension is already installed from another source.";
38
49
39
-
export default function ExtensionCard({ uniqueId }: { uniqueId: number }) {
40
-
const [tab, setTab] = React.useState(ExtensionPage.Info);
41
-
const [restartNeeded, setRestartNeeded] = React.useState(false);
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
+
/>
59
+
);
60
+
}
42
61
62
+
export default function ExtensionCard({ uniqueId, selectTag }: { uniqueId: number; selectTag: (tag: string) => void }) {
43
63
const { ext, enabled, busy, update, conflicting } = useStateFromStores([MoonbaseSettingsStore], () => {
44
64
return {
45
65
ext: MoonbaseSettingsStore.getExtension(uniqueId),
···
50
70
};
51
71
});
52
72
53
-
// Why it work like that :sob:
54
-
if (ext == null) return <></>;
55
-
56
-
const { Card, Text, FormSwitch, TabBar, Button } = Components;
73
+
const [tab, setTab] = React.useState(
74
+
update != null && ext?.changelog != null ? ExtensionPage.Changelog : ExtensionPage.Info
75
+
);
57
76
58
77
const tagline = ext.manifest?.meta?.tagline;
59
-
const settings = ext.manifest?.settings;
78
+
const settings = ext.settingsOverride ?? ext.manifest?.settings;
60
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
+
61
91
const enabledDependants = useStateFromStores([MoonbaseSettingsStore], () =>
62
92
Object.keys(MoonbaseSettingsStore.extensions)
63
93
.filter((uniqueId) => {
64
94
const potentialDependant = MoonbaseSettingsStore.getExtension(parseInt(uniqueId));
65
95
66
96
return (
67
-
potentialDependant.manifest.dependencies?.includes(ext.id) &&
97
+
potentialDependant.manifest.dependencies?.includes(ext?.id) &&
68
98
MoonbaseSettingsStore.getExtensionEnabled(parseInt(uniqueId))
69
99
);
70
100
})
···
72
102
);
73
103
const implicitlyEnabled = enabledDependants.length > 0;
74
104
75
-
return (
76
-
<Card editable={true} className={IntegrationCard.card}>
77
-
<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}>
78
117
<Flex direction={Flex.Direction.VERTICAL}>
79
118
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.CENTER}>
80
119
<Text variant="text-md/semibold">{ext.manifest?.meta?.name ?? ext.id}</Text>
81
120
{ext.source.type === ExtensionLoadSource.Developer && (
82
121
<Tooltip text="This is a local extension" position="top">
83
-
{(props: any) => <BeakerIcon {...props} class={BuildOverrideClasses.infoIcon} size="xs" />}
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" />}
84
135
</Tooltip>
85
136
)}
86
137
</Flex>
···
97
148
gap: "1rem"
98
149
}}
99
150
>
100
-
{ext.manifest.meta?.source != null && (
101
-
<PanelButton
102
-
icon={AngleBracketsIcon}
103
-
tooltipText="View source"
104
-
onClick={() => {
105
-
window.open(ext.manifest.meta!.source);
106
-
}}
107
-
/>
108
-
)}
109
-
110
151
{ext.state === ExtensionState.NotDownloaded ? (
111
-
<Tooltip text={COMPAT_TEXT_MAP[ext.compat]} shouldShow={ext.compat !== ExtensionCompat.Compatible}>
152
+
<Tooltip
153
+
text={conflicting ? CONFLICTING_TEXT : COMPAT_TEXT_MAP[ext.compat]}
154
+
shouldShow={conflicting || ext.compat !== ExtensionCompat.Compatible}
155
+
>
112
156
{(props: any) => (
113
157
<Button
114
158
{...props}
···
120
164
const deps = await MoonbaseSettingsStore.getDependencies(uniqueId);
121
165
if (deps != null) {
122
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);
123
172
}
124
173
}}
125
174
>
···
145
194
tooltipText="Update"
146
195
onClick={() => {
147
196
MoonbaseSettingsStore.installExtension(uniqueId);
148
-
setRestartNeeded(true);
149
197
}}
150
-
/>
151
-
)}
152
-
153
-
{restartNeeded && (
154
-
<PanelButton
155
-
icon={() => <CircleWarningIcon color={Components.tokens.colors.STATUS_DANGER} />}
156
-
onClick={() => window.location.reload()}
157
-
tooltipText="You will need to reload/restart your client for this extension to work properly."
158
198
/>
159
199
)}
160
200
···
163
203
disabled={implicitlyEnabled || ext.compat !== ExtensionCompat.Compatible}
164
204
hideBorder={true}
165
205
style={{ marginBottom: "0px" }}
206
+
// @ts-expect-error fix type later
166
207
tooltipNote={
167
-
ext.compat !== ExtensionCompat.Compatible
168
-
? COMPAT_TEXT_MAP[ext.compat]
169
-
: implicitlyEnabled
170
-
? `This extension is a dependency of the following enabled extension${
171
-
enabledDependants.length > 1 ? "s" : ""
172
-
}: ${enabledDependants.map((a) => a.manifest.meta?.name ?? a.id).join(", ")}`
173
-
: undefined
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
174
220
}
175
221
onChange={() => {
176
222
const toggle = () => {
177
223
MoonbaseSettingsStore.setExtensionEnabled(uniqueId, !enabled);
178
-
setRestartNeeded(true);
179
224
};
180
225
181
226
if (enabled && constants.builtinExtensions.includes(ext.id)) {
182
-
doBuiltinExtensionPopup(uniqueId, toggle);
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
+
);
183
240
} else {
184
241
toggle();
185
242
}
···
192
249
</div>
193
250
194
251
<div>
195
-
{(description != null || settings != null) && (
196
-
<TabBar
197
-
selectedItem={tab}
198
-
type="top"
199
-
onItemSelect={setTab}
200
-
className={TabBarClasses.tabBar}
201
-
style={{
202
-
padding: "0 20px"
203
-
}}
204
-
>
205
-
<TabBar.Item className={TabBarClasses.tabBarItem} id={ExtensionPage.Info}>
206
-
Info
207
-
</TabBar.Item>
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}
259
+
style={{
260
+
padding: "0 20px"
261
+
}}
262
+
>
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>
271
+
)}
272
+
273
+
{changelog != null && (
274
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id={ExtensionPage.Changelog}>
275
+
Changelog
276
+
</TabBar.Item>
277
+
)}
208
278
209
-
{description != null && (
210
-
<TabBar.Item className={TabBarClasses.tabBarItem} id={ExtensionPage.Description}>
211
-
Description
212
-
</TabBar.Item>
213
-
)}
279
+
{settings != null && (
280
+
<TabBar.Item className={DiscoveryClasses.tabBarItem} id={ExtensionPage.Settings}>
281
+
Settings
282
+
</TabBar.Item>
283
+
)}
284
+
</TabBar>
214
285
215
-
{settings != null && (
216
-
<TabBar.Item className={TabBarClasses.tabBarItem} id={ExtensionPage.Settings}>
217
-
Settings
218
-
</TabBar.Item>
219
-
)}
220
-
</TabBar>
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"
292
+
>
293
+
{linkButtons.length > 0 && linkButtons}
294
+
</Flex>
295
+
</Flex>
221
296
)}
222
297
223
298
<Flex
224
299
justify={Flex.Justify.START}
225
300
wrap={Flex.Wrap.WRAP}
226
301
style={{
227
-
padding: "16px 16px"
302
+
padding: "16px 16px",
303
+
// This looks wonky in the settings tab
304
+
rowGap: tab === ExtensionPage.Info ? "16px" : undefined
228
305
}}
229
306
>
230
-
{tab === ExtensionPage.Info && <ExtensionInfo ext={ext} />}
307
+
{tab === ExtensionPage.Info && <ExtensionInfo ext={ext} selectTag={selectTag} />}
231
308
{tab === ExtensionPage.Description && (
232
309
<Text variant="text-md/normal" className={MarkupClasses.markup} style={{ width: "100%" }}>
233
310
{MarkupUtils.parse(description ?? "*No description*", true, {
···
237
314
})}
238
315
</Text>
239
316
)}
240
-
{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
+
)}
241
331
</Flex>
242
332
</div>
243
333
</Card>
+91
-45
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/filterBar.tsx
+91
-45
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].exports;
34
-
35
-
let FilterDialogClasses: any;
36
-
let FilterBarClasses: any;
37
+
let HeaderClasses: any;
38
+
let ForumsClasses: any;
39
+
let SortMenuClasses: any;
37
40
spacepack
38
41
.lazyLoad('"Missing channel in Channel.openChannelContextMenu"', /e\("(\d+)"\)/g, /webpackId:(\d+?),/)
39
42
.then(() => {
40
-
FilterBarClasses = spacepack.findByCode("tagsButtonWithCount:")[0].exports;
41
-
FilterDialogClasses = spacepack.findByCode("countContainer:", "tagContainer:")[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");
42
46
});
43
47
44
-
const TagItem = spacepack.findByCode('"forum-tag-"')[0].exports.Z;
45
-
46
-
// FIXME: type component keys
47
-
const { ChevronSmallDownIcon, ChevronSmallUpIcon, ArrowsUpDownIcon } = Components;
48
-
49
48
function toggleTag(selectedTags: Set<string>, setSelectedTags: (tags: Set<string>) => void, tag: string) {
50
49
const newState = new Set(selectedTags);
51
50
if (newState.has(tag)) newState.delete(tag);
···
122
121
checked={(filter & Filter.Incompatible) === Filter.Incompatible}
123
122
action={() => toggleFilter(Filter.Incompatible)}
124
123
/>
124
+
<MenuCheckboxItem
125
+
id="l-deprecated"
126
+
label="Show deprecated"
127
+
checked={(filter & Filter.Deprecated) === Filter.Deprecated}
128
+
action={() => toggleFilter(Filter.Deprecated)}
129
+
/>
125
130
<MenuItem
126
131
id="reset-all"
127
132
className={SortMenuClasses.clearText}
···
139
144
140
145
function TagButtonPopout({ selectedTags, setSelectedTags, setPopoutRef, closePopout }: any) {
141
146
return (
142
-
<Dialog ref={setPopoutRef} className={FilterDialogClasses.container}>
143
-
<div className={FilterDialogClasses.header}>
144
-
<div className={FilterDialogClasses.headerLeft}>
145
-
<Heading color="interactive-normal" variant="text-xs/bold" className={FilterDialogClasses.headerText}>
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}>
146
151
Select tags
147
152
</Heading>
148
-
<div className={FilterDialogClasses.countContainer}>
149
-
<Text className={FilterDialogClasses.countText} color="none" variant="text-xs/medium">
153
+
<div className={HeaderClasses.countContainer}>
154
+
<Text className={HeaderClasses.countText} color="none" variant="text-xs/medium">
150
155
{selectedTags.size}
151
156
</Text>
152
157
</div>
153
158
</div>
154
159
</div>
155
-
<div className={FilterDialogClasses.tagContainer}>
160
+
<div className={HeaderClasses.tagContainer}>
156
161
{Object.keys(tagNames).map((tag) => (
157
162
<TagItem
158
163
key={tag}
159
-
className={FilterDialogClasses.tag}
160
-
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] }}
161
166
onClick={() => toggleTag(selectedTags, setSelectedTags, tag)}
162
167
selected={selectedTags.has(tag)}
163
168
/>
164
169
))}
165
170
</div>
166
-
<div className={FilterDialogClasses.separator} />
171
+
<div className={HeaderClasses.separator} />
167
172
<Button
168
173
look={Button.Looks.LINK}
169
174
size={Button.Sizes.MIN}
170
175
color={Button.Colors.CUSTOM}
171
-
className={FilterDialogClasses.clear}
176
+
className={HeaderClasses.clear}
172
177
onClick={() => {
173
178
setSelectedTags(new Set());
174
179
closePopout();
···
198
203
const tagsContainer = React.useRef<HTMLDivElement>(null);
199
204
const tagListInner = React.useRef<HTMLDivElement>(null);
200
205
const [tagsButtonOffset, setTagsButtonOffset] = React.useState(0);
206
+
const [checkingUpdates, setCheckingUpdates] = React.useState(false);
207
+
201
208
React.useLayoutEffect(() => {
202
209
if (tagsContainer.current === null || tagListInner.current === null) return;
203
210
const { left: containerX, top: containerY } = tagsContainer.current.getBoundingClientRect();
···
211
218
}
212
219
}
213
220
setTagsButtonOffset(offset);
214
-
}, [windowSize]);
221
+
}, [windowSize, tagsContainer.current, tagListInner.current, tagListInner.current?.getBoundingClientRect()?.width]);
215
222
216
223
return (
217
224
<div
···
219
226
style={{
220
227
paddingTop: "12px"
221
228
}}
222
-
className={`${FilterBarClasses.tagsContainer} ${Margins.marginBottom8}`}
229
+
className={`${ForumsClasses.tagsContainer} ${Margins.marginBottom8}`}
223
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>
224
256
<Popout
225
257
renderPopout={({ closePopout }: any) => (
226
258
<FilterButtonPopout filter={filter} setFilter={setFilter} closePopout={closePopout} />
···
233
265
{...props}
234
266
size={Button.Sizes.MIN}
235
267
color={Button.Colors.CUSTOM}
236
-
className={FilterBarClasses.sortDropdown}
237
-
innerClassName={FilterBarClasses.sortDropdownInner}
268
+
className={ForumsClasses.sortDropdown}
269
+
innerClassName={ForumsClasses.sortDropdownInner}
238
270
>
239
271
<ArrowsUpDownIcon size="xs" />
240
-
<Text className={FilterBarClasses.sortDropdownText} variant="text-sm/medium" color="interactive-normal">
272
+
<Text className={ForumsClasses.sortDropdownText} variant="text-sm/medium" color="interactive-normal">
241
273
Sort & filter
242
274
</Text>
243
275
{isShown ? (
···
248
280
</Button>
249
281
)}
250
282
</Popout>
251
-
<div className={FilterBarClasses.divider} />
252
-
<div className={FilterBarClasses.tagList}>
253
-
<div ref={tagListInner} className={FilterBarClasses.tagListInner}>
283
+
<div className={ForumsClasses.divider} />
284
+
<div className={ForumsClasses.tagList}>
285
+
<div ref={tagListInner} className={ForumsClasses.tagListInner}>
254
286
{Object.keys(tagNames).map((tag) => (
255
287
<TagItem
256
288
key={tag}
257
-
className={FilterBarClasses.tag}
258
-
tag={{ name: tagNames[tag as keyof typeof tagNames] }}
289
+
className={ForumsClasses.tag}
290
+
tag={{ name: tagNames[tag as keyof typeof tagNames], id: tag }}
259
291
onClick={() => toggleTag(selectedTags, setSelectedTags, tag)}
260
292
selected={selectedTags.has(tag)}
261
293
/>
···
283
315
left: tagsButtonOffset
284
316
}}
285
317
// TODO: Use Discord's class name utility
286
-
className={`${FilterBarClasses.tagsButton} ${
287
-
selectedTags.size > 0 ? FilterBarClasses.tagsButtonWithCount : ""
288
-
}`}
289
-
innerClassName={FilterBarClasses.tagsButtonInner}
318
+
className={`${ForumsClasses.tagsButton} ${selectedTags.size > 0 ? ForumsClasses.tagsButtonWithCount : ""}`}
319
+
innerClassName={ForumsClasses.tagsButtonInner}
290
320
>
291
321
{selectedTags.size > 0 ? (
292
-
<div style={{ boxSizing: "content-box" }} className={FilterBarClasses.countContainer}>
293
-
<Text className={FilterBarClasses.countText} color="none" variant="text-xs/medium">
322
+
<div style={{ boxSizing: "content-box" }} className={ForumsClasses.countContainer}>
323
+
<Text className={ForumsClasses.countText} color="none" variant="text-xs/medium">
294
324
{selectedTags.size}
295
325
</Text>
296
326
</div>
···
305
335
</Button>
306
336
)}
307
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>
308
354
</div>
309
355
);
310
356
}
+74
-9
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/index.tsx
+74
-9
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";
21
+
22
+
const SearchBar = spacepack.require("discord/uikit/search/SearchBar").default;
12
23
13
-
const SearchBar: any = Object.values(spacepack.findByCode("hideSearchIcon")[0].exports)[0];
24
+
const validTags: string[] = Object.values(ExtensionTag);
14
25
15
26
export default function ExtensionsPage() {
16
27
const { extensions, savedFilter } = useStateFromStoresObject([MoonbaseSettingsStore], () => {
···
21
32
});
22
33
23
34
const [query, setQuery] = React.useState("");
35
+
const [hitUpdateAll, setHitUpdateAll] = React.useState(false);
24
36
25
37
const filterState = React.useState(defaultFilter);
26
38
···
32
44
filter = filterState[0];
33
45
setFilter = filterState[1];
34
46
}
47
+
35
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
+
36
58
const sorted = Object.values(extensions).sort((a, b) => {
37
59
const aName = a.manifest.meta?.name ?? a.id;
38
60
const bName = b.manifest.meta?.name ?? b.id;
···
49
71
Object.entries(ext.manifest.settings).some(([key, setting]) =>
50
72
(setting.displayName ?? key).toLowerCase().includes(query)
51
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
+
)) ||
52
78
ext.manifest.meta?.description?.toLowerCase().includes(query)) &&
53
79
[...selectedTags.values()].every((tag) => ext.manifest.meta?.tags?.includes(tag as ExtensionTag)) &&
54
80
// This seems very bad, sorry
···
63
89
) &&
64
90
(filter & Filter.Incompatible ||
65
91
ext.compat === ExtensionCompat.Compatible ||
66
-
(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)
67
96
);
68
97
69
98
// Prioritize extensions with updates
70
-
filtered.sort((a, b) => {
71
-
if (a.hasUpdate && !b.hasUpdate) return -1;
72
-
if (!a.hasUpdate && b.hasUpdate) return 1;
73
-
return 0;
74
-
});
99
+
const filteredWithUpdates = filtered.filter((ext) => ext!.hasUpdate);
100
+
const filteredWithoutUpdates = filtered.filter((ext) => !ext!.hasUpdate);
75
101
76
102
return (
77
103
<>
···
89
115
}}
90
116
/>
91
117
<FilterBar filter={filter} setFilter={setFilter} selectedTags={selectedTags} setSelectedTags={setSelectedTags} />
92
-
{filtered.map((ext) => (
93
-
<ExtensionCard uniqueId={ext.uniqueId} key={ext.uniqueId} />
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>
94
159
))}
95
160
</>
96
161
);
+55
-26
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/info.tsx
+55
-26
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("infoScroller", "userInfoSection", "userInfoSectionHeader")[0].exports;
38
-
39
36
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
40
-
41
-
// FIXME: type component keys
42
-
const { Text } = Components;
43
37
44
38
function InfoSection({ title, children }: { title: string; children: React.ReactNode }) {
45
39
return (
···
48
42
marginRight: "1em"
49
43
}}
50
44
>
51
-
<Text variant="eyebrow" className={UserInfoClasses.userInfoSectionHeader}>
45
+
<Text variant="eyebrow" className="moonlight-card-info-header">
52
46
{title}
53
47
</Text>
54
48
···
57
51
);
58
52
}
59
53
60
-
function Badge({ color, children }: { color: string; children: React.ReactNode }) {
54
+
function Badge({
55
+
color,
56
+
children,
57
+
style = {},
58
+
onClick
59
+
}: {
60
+
color: string;
61
+
children: React.ReactNode;
62
+
style?: React.CSSProperties;
63
+
onClick?: () => void;
64
+
}) {
65
+
if (onClick) style.cursor ??= "pointer";
61
66
return (
62
67
<span
63
-
style={{
64
-
borderRadius: ".1875rem",
65
-
padding: "0 0.275rem",
66
-
marginRight: "0.4em",
67
-
backgroundColor: color,
68
-
color: "#fff"
69
-
}}
68
+
className="moonlight-card-badge"
69
+
style={
70
+
{
71
+
"--badge-color": color,
72
+
...style
73
+
} as React.CSSProperties
74
+
}
75
+
onClick={onClick}
70
76
>
71
77
{children}
72
78
</span>
73
79
);
74
80
}
75
81
76
-
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
+
}) {
77
89
const authors = ext.manifest?.meta?.authors;
78
90
const tags = ext.manifest?.meta?.tags;
79
91
const version = ext.manifest?.version;
80
92
81
93
const dependencies: Dependency[] = [];
94
+
const incompatible: Dependency[] = [];
95
+
82
96
if (ext.manifest.dependencies != null) {
83
97
dependencies.push(
84
98
...ext.manifest.dependencies.map((dep) => ({
···
98
112
}
99
113
100
114
if (ext.manifest.incompatible != null) {
101
-
dependencies.push(
115
+
incompatible.push(
102
116
...ext.manifest.incompatible.map((dep) => ({
103
117
id: dep,
104
118
type: DependencyType.Incompatible
···
136
150
<InfoSection title="Tags">
137
151
{tags.map((tag, i) => {
138
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
+
}
139
159
140
160
return (
141
-
<Badge key={i} color={tag === ExtensionTag.DangerZone ? "var(--red-400)" : "var(--brand-500)"}>
161
+
<Badge key={i} color={color} style={style} onClick={() => selectTag(tag)}>
142
162
{name}
143
163
</Badge>
144
164
);
···
149
169
{dependencies.length > 0 && (
150
170
<InfoSection title="Dependencies">
151
171
{dependencies.map((dep) => {
152
-
const colors = {
153
-
[DependencyType.Dependency]: "var(--brand-500)",
154
-
[DependencyType.Optional]: "var(--orange-400)",
155
-
[DependencyType.Incompatible]: "var(--red-400)"
156
-
};
157
-
const color = colors[dep.type];
158
172
const name = MoonbaseSettingsStore.tryGetExtensionName(dep.id);
159
173
174
+
// TODO: figure out a decent way to distinguish suggested
160
175
return (
161
-
<Badge color={color} key={dep.id}>
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) => {
187
+
const name = MoonbaseSettingsStore.tryGetExtensionName(dep.id);
188
+
189
+
return (
190
+
<Badge color="var(--bg-mod-strong)" key={dep.id}>
162
191
{name}
163
192
</Badge>
164
193
);
+33
-20
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/popup.tsx
+33
-20
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 { openModalLazy, useModalsStore, closeModal } = Components;
11
-
const Popup = spacepack.findByCode(".minorContainer", "secondaryAction")[0].exports.default;
11
+
let ConfirmModal: typeof import("@moonlight-mod/wp/discord/components/modals/ConfirmModal").default;
12
12
13
13
function close() {
14
14
const ModalStore = useModalsStore.getState();
15
15
closeModal(ModalStore.default[0].key);
16
16
}
17
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
+
}
24
+
18
25
const presentableLoadSources: Record<ExtensionLoadSource, string> = {
19
26
[ExtensionLoadSource.Developer]: "Local extension", // should never show up
20
27
[ExtensionLoadSource.Core]: "Core extension",
···
32
39
option: string | undefined;
33
40
setOption: (pick: string | undefined) => void;
34
41
}) {
35
-
const { SingleSelect } = Components;
36
-
37
42
return (
38
43
<SingleSelect
39
44
key={id}
···
61
66
deps: Record<string, MoonbaseExtension[]>;
62
67
transitionState: number | null;
63
68
}) {
64
-
const { Text } = Components;
65
-
69
+
lazyLoad();
66
70
const amountNotAvailable = Object.values(deps).filter((candidates) => candidates.length === 0).length;
67
71
68
72
const [options, setOptions] = React.useState<Record<string, string | undefined>>(
···
75
79
);
76
80
77
81
return (
78
-
<Popup
82
+
<ConfirmModal
79
83
body={
80
84
<Flex
81
85
style={{
···
155
159
});
156
160
}
157
161
158
-
function BuiltinExtensionPopup({
162
+
function GenericExtensionPopup({
163
+
title,
164
+
content,
159
165
transitionState,
160
166
uniqueId,
161
167
cb
162
168
}: {
169
+
title: string;
170
+
content: string;
163
171
transitionState: number | null;
164
172
uniqueId: number;
165
173
cb: () => void;
166
174
}) {
167
-
const { Text } = Components;
175
+
lazyLoad();
168
176
169
177
return (
170
-
<Popup
178
+
<ConfirmModal
179
+
title={title}
171
180
body={
172
181
<Flex>
173
-
<Text variant="text-md/normal">
174
-
This extension is enabled by default. Disabling it might have consequences. Are you sure you want to disable
175
-
it?
176
-
</Text>
182
+
<Text variant="text-md/normal">{content}</Text>
177
183
</Flex>
178
184
}
185
+
confirmText="Yes"
179
186
cancelText="No"
180
-
confirmText="Yes"
181
187
onCancel={close}
182
188
onConfirm={() => {
183
189
close();
184
190
cb();
185
191
}}
186
-
title="Built in extension"
187
192
transitionState={transitionState}
188
193
/>
189
194
);
190
195
}
191
196
192
-
export async function doBuiltinExtensionPopup(uniqueId: number, cb: () => void) {
197
+
export async function doGenericExtensionPopup(title: string, content: string, uniqueId: number, cb: () => void) {
193
198
await openModalLazy(async () => {
194
199
return ({ transitionState }: { transitionState: number | null }) => {
195
-
return <BuiltinExtensionPopup transitionState={transitionState} uniqueId={uniqueId} cb={cb} />;
200
+
return (
201
+
<GenericExtensionPopup
202
+
title={title}
203
+
content={content}
204
+
transitionState={transitionState}
205
+
uniqueId={uniqueId}
206
+
cb={cb}
207
+
/>
208
+
);
196
209
};
197
210
});
198
211
}
+85
-51
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/settings.tsx
+85
-51
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],
···
42
81
}
43
82
44
83
function Boolean({ ext, name, setting, disabled }: SettingsProps) {
45
-
const { FormSwitch } = Components;
46
84
const { value, displayName, description } = useConfigEntry<boolean>(ext.uniqueId, name);
47
85
48
86
return (
···
53
91
onChange={(value: boolean) => {
54
92
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
55
93
}}
56
-
note={description}
94
+
note={description != null ? markdownify(description) : undefined}
57
95
className={`${Margins.marginReset} ${Margins.marginTop20}`}
58
96
>
59
97
{displayName}
···
62
100
}
63
101
64
102
function Number({ ext, name, setting, disabled }: SettingsProps) {
65
-
const { FormItem, FormText, Slider } = Components;
66
103
const { value, displayName, description } = useConfigEntry<number>(ext.uniqueId, name);
67
104
68
105
const castedSetting = setting as NumberSettingType;
69
-
const min = castedSetting.min ?? 0;
70
-
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
+
};
71
113
72
114
return (
73
115
<FormItem className={Margins.marginTop20} title={displayName}>
74
-
{description && <FormText>{description}</FormText>}
75
-
<Slider
76
-
initialValue={value ?? 0}
77
-
disabled={disabled}
78
-
minValue={castedSetting.min ?? 0}
79
-
maxValue={castedSetting.max ?? 100}
80
-
onValueChange={(value: number) => {
81
-
const rounded = Math.max(min, Math.min(max, Math.round(value)));
82
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, rounded);
83
-
}}
84
-
/>
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
+
)}
85
134
</FormItem>
86
135
);
87
136
}
88
137
89
138
function String({ ext, name, setting, disabled }: SettingsProps) {
90
-
const { FormItem, FormText, TextInput } = Components;
91
139
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
92
140
93
141
return (
94
142
<FormItem className={Margins.marginTop20} title={displayName}>
95
-
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
143
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
96
144
<TextInput
97
145
value={value ?? ""}
98
-
onChange={(value: string) => {
99
-
if (disabled) return;
100
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
101
-
}}
146
+
disabled={disabled}
147
+
onChange={(value: string) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)}
102
148
/>
103
149
</FormItem>
104
150
);
105
151
}
106
152
107
153
function MultilineString({ ext, name, setting, disabled }: SettingsProps) {
108
-
const { FormItem, FormText, TextArea } = Components;
109
154
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
110
155
111
156
return (
112
157
<FormItem className={Margins.marginTop20} title={displayName}>
113
-
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
158
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
114
159
<TextArea
115
160
rows={5}
116
161
value={value ?? ""}
162
+
disabled={disabled}
117
163
className={"moonbase-resizeable"}
118
-
onChange={(value: string) => {
119
-
if (disabled) return;
120
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
121
-
}}
164
+
onChange={(value: string) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)}
122
165
/>
123
166
</FormItem>
124
167
);
125
168
}
126
169
127
170
function Select({ ext, name, setting, disabled }: SettingsProps) {
128
-
const { FormItem, FormText, SingleSelect } = Components;
129
171
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
130
172
131
173
const castedSetting = setting as SelectSettingType;
···
133
175
134
176
return (
135
177
<FormItem className={Margins.marginTop20} title={displayName}>
136
-
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
178
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
137
179
<SingleSelect
138
180
autofocus={false}
139
181
clearable={false}
···
149
191
}
150
192
151
193
function MultiSelect({ ext, name, setting, disabled }: SettingsProps) {
152
-
const { FormItem, FormText, Select, useVariableSelect, multiSelect } = Components;
153
194
const { value, displayName, description } = useConfigEntry<string | string[]>(ext.uniqueId, name);
154
195
155
196
const castedSetting = setting as MultiSelectSettingType;
···
157
198
158
199
return (
159
200
<FormItem className={Margins.marginTop20} title={displayName}>
160
-
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
161
-
<Select
201
+
{description && <FormText className={Margins.marginBottom8}>{markdownify(description)}</FormText>}
202
+
<DiscordSelect
162
203
autofocus={false}
163
204
clearable={false}
164
205
closeOnSelect={false}
···
176
217
);
177
218
}
178
219
179
-
const RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0].exports;
180
-
181
-
// FIXME: type component keys
182
-
const { CircleXIcon } = Components;
183
-
184
220
function RemoveEntryButton({ onClick, disabled }: { onClick: () => void; disabled: boolean }) {
185
-
const { Tooltip, Clickable } = Components;
186
221
return (
187
-
<div className={RemoveButtonClasses.removeButtonContainer}>
222
+
<div className={GuildSettingsRoleEditClasses.removeButtonContainer}>
188
223
<Tooltip text="Remove entry" position="top">
189
224
{(props: any) => (
190
-
<Clickable {...props} className={RemoveButtonClasses.removeButton} onClick={onClick}>
225
+
<Clickable {...props} className={GuildSettingsRoleEditClasses.removeButton} onClick={onClick}>
191
226
<CircleXIcon width={16} height={16} />
192
227
</Clickable>
193
228
)}
···
197
232
}
198
233
199
234
function List({ ext, name, setting, disabled }: SettingsProps) {
200
-
const { FormItem, FormText, TextInput, Button } = Components;
201
235
const { value, displayName, description } = useConfigEntry<string[]>(ext.uniqueId, name);
202
236
203
237
const entries = value ?? [];
···
205
239
206
240
return (
207
241
<FormItem className={Margins.marginTop20} title={displayName}>
208
-
{description && <FormText className={Margins.marginBottom4}>{description}</FormText>}
242
+
{description && <FormText className={Margins.marginBottom4}>{markdownify(description)}</FormText>}
209
243
<Flex direction={Flex.Direction.VERTICAL}>
210
244
{entries.map((val, i) => (
211
245
// FIXME: stylesheets
···
257
291
}
258
292
259
293
function Dictionary({ ext, name, setting, disabled }: SettingsProps) {
260
-
const { FormItem, FormText, TextInput, Button } = Components;
261
294
const { value, displayName, description } = useConfigEntry<Record<string, string>>(ext.uniqueId, name);
262
295
263
296
const entries = Object.entries(value ?? {});
···
265
298
266
299
return (
267
300
<FormItem className={Margins.marginTop20} title={displayName}>
268
-
{description && <FormText className={Margins.marginBottom4}>{description}</FormText>}
301
+
{description && <FormText className={Margins.marginBottom4}>{markdownify(description)}</FormText>}
269
302
<Flex direction={Flex.Direction.VERTICAL}>
270
303
{entries.map(([key, val], i) => (
271
304
// FIXME: stylesheets
···
339
372
);
340
373
341
374
if (Component == null) {
342
-
const { Text } = Components;
343
375
return (
344
376
<Text variant="text-md/normal">{`Custom setting "${displayName}" is missing a component. Perhaps the extension is not installed?`}</Text>
345
377
);
346
378
}
347
379
348
380
return (
349
-
<Component value={value} setValue={(value) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)} />
381
+
<ErrorBoundary>
382
+
<Component value={value} setValue={(value) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)} />
383
+
</ErrorBoundary>
350
384
);
351
385
}
352
386
···
370
404
export default function Settings({ ext }: { ext: MoonbaseExtension }) {
371
405
return (
372
406
<Flex className="moonbase-settings" direction={Flex.Direction.VERTICAL}>
373
-
{Object.entries(ext.manifest.settings!).map(([name, setting]) => (
407
+
{Object.entries(ext.settingsOverride ?? ext.manifest.settings!).map(([name, setting]) => (
374
408
<Setting
375
409
ext={ext}
376
410
key={name}
+26
-13
packages/core-extensions/src/moonbase/webpackModules/ui/index.tsx
+26
-13
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
2
import { Text, TabBar } from "@moonlight-mod/wp/discord/components/common/index";
4
3
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
5
4
import { UserSettingsModalStore } from "@moonlight-mod/wp/common_stores";
6
5
7
6
import ExtensionsPage from "./extensions";
8
7
import ConfigPage from "./config";
8
+
import AboutPage from "./about";
9
9
import Update from "./update";
10
-
11
-
const { Divider } = spacepack.findByCode(".forumOrHome]:")[0].exports.Z;
12
-
const TitleBarClasses = spacepack.findByCode("iconWrapper:", "children:")[0].exports;
13
-
const TabBarClasses = spacepack.findByCode("nowPlayingColumn:")[0].exports;
14
-
const { setSection, clearSubsection } = spacepack.findByExports("setSection", "clearSubsection")[0].exports.Z;
15
-
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";
16
16
17
17
export const pages: {
18
18
id: string;
···
28
28
id: "config",
29
29
name: "Config",
30
30
element: ConfigPage
31
+
},
32
+
{
33
+
id: "about",
34
+
name: "About",
35
+
element: AboutPage
31
36
}
32
37
];
33
38
···
35
40
const subsection = useStateFromStores([UserSettingsModalStore], () => UserSettingsModalStore.getSubsection() ?? 0);
36
41
const setSubsection = React.useCallback(
37
42
(to: string) => {
38
-
if (subsection !== to) setSection("moonbase", to);
43
+
if (subsection !== to) UserSettingsModalActionCreators.setSection("moonbase", to);
39
44
},
40
45
[subsection]
41
46
);
···
43
48
React.useEffect(
44
49
() => () => {
45
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
46
-
clearSubsection("moonbase");
51
+
UserSettingsModalActionCreators.clearSubsection("moonbase");
47
52
},
48
53
[]
49
54
);
50
55
51
56
return (
52
57
<>
53
-
<div className={`${TitleBarClasses.children} ${Margins.marginBottom20}`}>
54
-
<Text className={TitleBarClasses.titleWrapper} variant="heading-lg/semibold" tag="h2">
58
+
<div className={`${HeaderBarClasses.children} ${Margins.marginBottom20}`}>
59
+
<Text className={HeaderBarClasses.titleWrapper} variant="heading-lg/semibold" tag="h2">
55
60
Moonbase
56
61
</Text>
57
62
<Divider />
58
-
<TabBar selectedItem={subsection} onItemSelect={setSubsection} type="top-pill" className={TabBarClasses.tabBar}>
63
+
<TabBar
64
+
selectedItem={subsection}
65
+
onItemSelect={setSubsection}
66
+
type="top-pill"
67
+
className={PeoplePageClasses.tabBar}
68
+
>
59
69
{pages.map((page, i) => (
60
-
<TabBar.Item key={page.id} id={i} className={TabBarClasses.item}>
70
+
<TabBar.Item key={page.id} id={i} className={PeoplePageClasses.item}>
61
71
{page.name}
62
72
</TabBar.Item>
63
73
))}
64
74
</TabBar>
65
75
</div>
66
76
77
+
<RestartAdviceMessage />
67
78
<Update />
68
79
69
80
{React.createElement(pages[subsection].element)}
70
81
</>
71
82
);
72
83
}
84
+
85
+
export { RestartAdviceMessage, Update };
+83
-40
packages/core-extensions/src/moonbase/webpackModules/ui/update.tsx
+83
-40
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
-
import { UpdateState } from "../../types";
8
-
9
-
const { ThemeDarkIcon, Text, Button } = Components;
10
-
const Margins = spacepack.require("discord/styles/shared/Margins.css");
11
-
const HelpMessageClasses = spacepack.findByExports("positive", "iconDiv")[0].exports;
12
-
13
-
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";
14
22
15
23
const strings: Record<UpdateState, string> = {
16
24
[UpdateState.Ready]: "A new version of moonlight is available.",
···
19
27
[UpdateState.Failed]: "Failed to update moonlight. Please use the installer instead."
20
28
};
21
29
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>
64
+
);
65
+
}
66
+
22
67
export default function Update() {
23
-
const [state, setState] = React.useState(UpdateState.Ready);
24
-
const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion);
68
+
const [newVersion, state] = useStateFromStores([MoonbaseSettingsStore], () => [
69
+
MoonbaseSettingsStore.newVersion,
70
+
MoonbaseSettingsStore.updateState
71
+
]);
25
72
26
73
if (newVersion == null) return null;
27
74
28
-
// reimpl of HelpMessage but with a custom icon
29
75
return (
30
-
<div
31
-
className={`${Margins.marginBottom20} ${HelpMessageClasses.info} ${HelpMessageClasses.container} moonbase-update-section`}
32
-
>
33
-
<Flex direction={Flex.Direction.HORIZONTAL}>
34
-
<div
35
-
className={HelpMessageClasses.iconDiv}
36
-
style={{
37
-
alignItems: "center"
38
-
}}
39
-
>
40
-
<ThemeDarkIcon size="sm" color="currentColor" className={HelpMessageClasses.icon} />
41
-
</div>
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
+
)}
42
96
43
-
<Text variant="text-sm/medium" color="currentColor" className={HelpMessageClasses.text}>
44
-
{strings[state]}
45
-
</Text>
46
-
</Flex>
47
-
48
-
<div className="moonbase-update-section-buttons">
49
97
{state === UpdateState.Installed && (
50
98
<Button
51
99
look={Button.Looks.OUTLINED}
52
100
color={Button.Colors.CUSTOM}
53
101
size={Button.Sizes.TINY}
54
-
onClick={() => window.location.reload()}
102
+
onClick={() => {
103
+
MoonbaseSettingsStore.restartDiscord();
104
+
}}
55
105
>
56
106
Restart Discord
57
107
</Button>
···
63
113
size={Button.Sizes.TINY}
64
114
disabled={state !== UpdateState.Ready}
65
115
onClick={() => {
66
-
setState(UpdateState.Working);
67
-
68
-
MoonbaseSettingsStore.updateMoonlight()
69
-
.then(() => setState(UpdateState.Installed))
70
-
.catch((e) => {
71
-
logger.error(e);
72
-
setState(UpdateState.Failed);
73
-
});
116
+
MoonbaseSettingsStore.updateMoonlight();
74
117
}}
75
118
>
76
119
Update
77
120
</Button>
78
121
</div>
79
-
</div>
122
+
</HelpMessage>
80
123
);
81
124
}
+7
-20
packages/core-extensions/src/moonbase/webpackModules/updates.tsx
+7
-20
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(Constants, "APPEARANCE_THEME_PICKER");
11
-
12
-
const { ThemeDarkIcon } = Components;
6
+
import ThemeDarkIcon from "@moonlight-mod/wp/moonbase_ThemeDarkIcon";
13
7
14
8
function plural(str: string, num: number) {
15
9
return `${str}${num > 1 ? "s" : ""}`;
···
63
57
{
64
58
name: "Open Moonbase",
65
59
onClick: () => {
66
-
const { open } = spacepack.findByExports("setSection", "clearSubsection")[0].exports.Z;
67
-
68
-
// settings is lazy loaded thus lazily patched
69
-
// FIXME: figure out a way to detect if settings has been opened
70
-
// alreadyjust so the transition isnt as jarring
71
-
open(UserSettingsSections.ACCOUNT);
72
-
setTimeout(() => {
73
-
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "sections", false)) {
74
-
open("moonbase-extensions");
75
-
} else {
76
-
open("moonbase", 0);
77
-
}
78
-
}, 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
+
}
79
66
return true;
80
67
}
81
68
}
+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
+
}
+141
-1
packages/core-extensions/src/nativeFixes/host.ts
+141
-1
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
7
+
const logger = moonlightHost.getLogger("nativeFixes/host");
3
8
const enabledFeatures = app.commandLine.getSwitchValue("enable-features").split(",");
4
9
5
10
moonlightHost.events.on("window-created", function (browserWindow) {
···
22
27
23
28
// already added on Windows, but not on other operating systems
24
29
app.commandLine.appendSwitch("disable-background-timer-throttling");
30
+
}
31
+
32
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "vulkan") ?? false) {
33
+
enabledFeatures.push("Vulkan", "DefaultANGLEVulkan", "VulkanFromANGLE");
25
34
}
26
35
27
36
if (process.platform === "linux") {
···
32
41
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxSpeechDispatcher") ?? true) {
33
42
app.commandLine.appendSwitch("enable-speech-dispatcher");
34
43
}
44
+
45
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxHevcSupport") ?? true) {
46
+
enabledFeatures.push("PlatformHEVCDecoderSupport");
47
+
}
35
48
}
36
49
37
50
// NOTE: Only tested if this appears on Windows, it should appear on all when
38
51
// hardware acceleration is disabled
39
52
const noAccel = app.commandLine.hasSwitch("disable-gpu-compositing");
40
53
if ((moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapi") ?? true) && !noAccel) {
41
-
if (process.platform === "linux")
54
+
if (process.platform === "linux") {
42
55
// These will eventually be renamed https://source.chromium.org/chromium/chromium/src/+/5482210941a94d70406b8da962426e4faca7fce4
43
56
enabledFeatures.push("VaapiVideoEncoder", "VaapiVideoDecoder", "VaapiVideoDecodeLinuxGL");
57
+
58
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapiIgnoreDriverChecks") ?? false)
59
+
enabledFeatures.push("VaapiIgnoreDriverChecks");
60
+
}
44
61
}
45
62
46
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
}
+1
packages/core-extensions/src/notices/manifest.json
+1
packages/core-extensions/src/notices/manifest.json
+3
-6
packages/core-extensions/src/notices/webpackModules/component.tsx
+3
-6
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();
+103
-15
packages/core-extensions/src/quietLoggers/index.ts
+103
-15
packages/core-extensions/src/quietLoggers/index.ts
···
3
3
const notXssDefensesOnly = () =>
4
4
(moonlight.getConfigOption<boolean>("quietLoggers", "xssDefensesOnly") ?? false) === false;
5
5
6
+
const silenceDiscordLogger = moonlight.getConfigOption<boolean>("quietLoggers", "silenceDiscordLogger") ?? false;
7
+
6
8
// These patches MUST run before the simple patches, these are to remove loggers
7
9
// that end up causing syntax errors by the normal patch
8
10
const loggerFixes: Patch[] = [
···
16
18
{
17
19
find: '("GatewaySocket")',
18
20
replace: {
19
-
match: /.\.(info|log)(\(.+?\))(;|,)/g,
20
-
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: "(()=>{})("
21
30
}
22
31
}
23
32
];
···
28
37
// Patches to simply remove a logger call
29
38
const stubPatches = [
30
39
// "sh" is not a valid locale.
31
-
["is not a valid locale", /(.)\.error\(""\.concat\((.)," is not a valid locale\."\)\)/g],
32
-
['"[BUILD INFO] Release Channel: "', /new .{1,2}\.Z\(\)\.log\("\[BUILD INFO\] Release Channel: ".+?\)\),/],
33
-
['.APP_NATIVE_CRASH,"Storage"', /console\.log\("AppCrashedFatalReport lastCrash:",.,.\);/],
34
-
['.APP_NATIVE_CRASH,"Storage"', 'console.log("AppCrashedFatalReport: getLastCrash not supported.");'],
35
-
['"[NATIVE INFO] ', /new .{1,2}\.Z\(\)\.log\("\[NATIVE INFO] .+?\)\);/],
36
-
['"Spellchecker"', /.\.info\("Switching to ".+?"\(unavailable\)"\);?/g],
37
-
['throw Error("Messages are still loading.");', /console\.warn\("Unsupported Locale",.\),/],
38
-
["}_dispatchWithDevtools(", /.\.totalTime>.{1,2}&&.\.verbose\(.+?\);/],
39
-
['"NativeDispatchUtils"', /null==.&&.\.warn\("Tried getting Dispatch instance before instantiated"\),/],
40
-
['("DatabaseManager")', /.\.log\("removing database \(user: ".+?\)\),/],
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"\),/],
41
49
[
42
50
'"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. Action: "',
43
-
/.\.has\(.\.type\)&&.\.log\(.+?\.type\)\),/
51
+
/\i\.has\(\i\.type\)&&\i\.log\(.+?\.type\)\),/
52
+
],
53
+
['console.warn("Window state not initialized"', /console\.warn\("Window state not initialized",\i\),/],
54
+
['.name="MaxListenersExceededWarning",', /(?<=\.length),\i\(\i\)/],
55
+
[
56
+
'"The answer for life the universe and everything is:"',
57
+
/\i\.info\("The answer for life the universe and everything is:",\i\),/
58
+
],
59
+
[
60
+
'"isLibdiscoreBlockedDomainsEnabled called but libdiscore is not loaded"',
61
+
/,\i\.verbose\("isLibdiscoreBlockedDomainsEnabledThisSession: ".concat\(\i\)\)/
62
+
],
63
+
[
64
+
'"Unable to determine render window for element"',
65
+
/console\.warn\("Unable to determine render window for element",\i\),/
44
66
],
45
-
['console.warn("Window state not initialized"', /console\.warn\("Window state not initialized",.\),/]
67
+
[
68
+
'"Unable to determine render window for element"',
69
+
/console\.warn\('Unable to find element constructor "'\.concat\(\i,'" in'\),\i\),/
70
+
],
71
+
[
72
+
'"[PostMessageTransport] Protocol error: event data should be an Array!"',
73
+
/void console\.warn\("\[PostMessageTransport] Protocol error: event data should be an Array!"\)/
74
+
],
75
+
[
76
+
'("ComponentDispatchUtils")',
77
+
/new \i\.Z\("ComponentDispatchUtils"\)\.warn\("ComponentDispatch\.resubscribe: Resubscribe without existing subscription",\i\),/
78
+
]
79
+
];
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")'
46
99
];
47
100
48
101
const simplePatches = [
···
54
107
{
55
108
find: ".Messages.SELF_XSS_HEADER",
56
109
replace: {
57
-
match: /\(null!=.{1,2}&&"0\.0\.0"===.{1,2}\.remoteApp\.getVersion\(\)\)/,
110
+
match: /\(null!=\i&&"0\.0\.0"===\i\.remoteApp\.getVersion\(\)\)/,
58
111
replacement: "(true)"
59
112
}
60
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
+
},
61
141
...loggerFixes,
62
142
...stubPatches.map((patch) => ({
63
143
find: patch[0],
···
72
152
replace: {
73
153
match: patch[0],
74
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: "(()=>{})("
75
163
},
76
164
prerequisite: notXssDefensesOnly
77
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
}
+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
}
+1
-1
packages/core-extensions/src/settings/index.ts
+1
-1
packages/core-extensions/src/settings/index.ts
···
12
12
{
13
13
find: 'navId:"user-settings-cog",',
14
14
replace: {
15
-
match: /children:\[(.)\.map\(.+?\),children:.\((.)\)/,
15
+
match: /children:\[(\i)\.map\(.+?\),.*?children:\i\((\i)\)/,
16
16
replacement: (orig, sections, section) =>
17
17
`${orig.replace(
18
18
/Object\.values\(.\..+?\)/,
+1
packages/core-extensions/src/settings/manifest.json
+1
packages/core-extensions/src/settings/manifest.json
+8
-2
packages/core-extensions/src/settings/webpackModules/settings.ts
+8
-2
packages/core-extensions/src/settings/webpackModules/settings.ts
···
1
1
import { SettingsSection, Settings as SettingsType } from "@moonlight-mod/types/coreExtensions/settings";
2
+
import UserSettingsModalActionCreators from "@moonlight-mod/wp/discord/actions/UserSettingsModalActionCreators";
2
3
3
4
export const Settings: SettingsType = {
4
5
ourSections: [],
5
6
sectionNames: [],
6
7
sectionMenuItems: {},
7
8
8
-
addSection: (section, label, element, color = null, pos, notice) => {
9
+
addSection: (section, label, element, color = null, pos, notice, onClick) => {
9
10
const data: SettingsSection = {
10
11
section,
11
12
label,
12
13
color,
13
14
element,
14
15
pos: pos ?? -4,
15
-
notice: notice
16
+
notice: notice,
17
+
onClick: onClick ?? (() => UserSettingsModalActionCreators.open(section))
16
18
};
17
19
18
20
Settings.ourSections.push(data);
···
43
45
44
46
_mutateSections: (sections) => {
45
47
for (const section of Settings.ourSections) {
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
+
}
46
52
sections.splice(section.pos < 0 ? sections.length + section.pos : section.pos, 0, section);
47
53
}
48
54
+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",
+76
-26
packages/core-extensions/src/spacepack/webpackModules/spacepack.ts
+76
-26
packages/core-extensions/src/spacepack/webpackModules/spacepack.ts
···
1
1
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "@moonlight-mod/types";
2
2
import { Spacepack } from "@moonlight-mod/types/coreExtensions/spacepack";
3
+
import { processFind, testFind } from "@moonlight-mod/core/util/patch";
3
4
4
5
const webpackRequire = require as unknown as WebpackRequireType;
5
6
const cache = webpackRequire.c;
···
36
37
"module",
37
38
"exports",
38
39
"require",
39
-
`(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module-${module}`
40
+
`(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module/${module.slice(0, 3)}/${module}`
40
41
) as WebpackModuleFunc;
41
42
},
42
43
43
44
findByCode: (...args: (string | RegExp)[]) => {
44
-
return Object.entries(modules)
45
-
.filter(
46
-
([id, mod]) =>
47
-
!args.some(
48
-
(item) => !(item instanceof RegExp ? item.test(mod.toString()) : mod.toString().indexOf(item) !== -1)
49
-
)
50
-
)
45
+
const ret = Object.entries(modules)
46
+
.filter(([id, mod]) => !args.some((item) => !testFind(mod.toString(), processFind(item))))
51
47
.map(([id]) => {
52
48
//if (!(id in cache)) require(id);
53
49
//return cache[id];
···
56
52
try {
57
53
exports = require(id);
58
54
} catch (e) {
59
-
logger.error(`Error requiring module "${id}": `, e);
55
+
logger.error(`findByCode: Error requiring module "${id}": `, args, e);
60
56
}
61
57
62
58
return {
···
65
61
};
66
62
})
67
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;
68
70
},
69
71
70
72
findByExports: (...args: string[]) => {
···
88
90
},
89
91
90
92
findObjectFromKey: (exports: Record<string, any>, key: string) => {
93
+
let ret = null;
91
94
let subKey;
92
95
if (key.indexOf(".") > -1) {
93
96
const splitKey = key.split(".");
···
98
101
const obj = exports[exportKey];
99
102
if (obj && obj[key] !== undefined) {
100
103
if (subKey) {
101
-
if (obj[key][subKey]) return obj;
104
+
if (obj[key][subKey]) {
105
+
ret = obj;
106
+
break;
107
+
}
102
108
} else {
103
-
return obj;
109
+
ret = obj;
110
+
break;
104
111
}
105
112
}
106
113
}
107
-
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;
108
120
},
109
121
110
122
findObjectFromValue: (exports: Record<string, any>, value: any) => {
123
+
let ret = null;
111
124
for (const exportKey in exports) {
112
125
const obj = exports[exportKey];
113
126
// eslint-disable-next-line eqeqeq
114
-
if (obj == value) return obj;
127
+
if (obj == value) {
128
+
ret = obj;
129
+
break;
130
+
}
115
131
for (const subKey in obj) {
116
132
// eslint-disable-next-line eqeqeq
117
133
if (obj && obj[subKey] == value) {
118
-
return obj;
134
+
ret = obj;
135
+
break;
119
136
}
120
137
}
121
138
}
122
-
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;
123
145
},
124
146
125
147
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => {
148
+
let ret = null;
126
149
for (const exportKey in exports) {
127
150
const obj = exports[exportKey];
128
151
// eslint-disable-next-line eqeqeq
129
152
if (obj && obj[key] == value) {
130
-
return obj;
153
+
ret = obj;
154
+
break;
131
155
}
132
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
+
133
169
return null;
134
170
},
135
171
136
172
findFunctionByStrings: (exports: Record<string, any>, ...strings: (string | RegExp)[]) => {
137
-
return (
173
+
const ret =
138
174
Object.entries(exports).filter(
139
175
([index, func]) =>
140
-
typeof func === "function" &&
141
-
!strings.some(
142
-
(query) => !(query instanceof RegExp ? func.toString().match(query) : func.toString().includes(query))
143
-
)
144
-
)?.[0]?.[1] ?? null
145
-
);
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;
146
184
},
147
185
148
186
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => {
187
+
chunk = processFind(chunk);
188
+
module = processFind(module);
189
+
149
190
const mod = Array.isArray(find) ? spacepack.findByCode(...find) : spacepack.findByCode(find);
150
-
if (mod.length < 1) return Promise.reject("Module find failed");
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
+
}
151
195
152
196
const findId = mod[0].id;
153
197
const findCode = webpackRequire.m[findId].toString().replace(/\n/g, "");
···
160
204
if (match) chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
161
205
}
162
206
163
-
if (!chunkIds || chunkIds.length === 0) return Promise.reject("Chunk ID match failed");
207
+
if (!chunkIds || chunkIds.length === 0) {
208
+
logger.warn("lazyLoad: Chunk ID match failed", find, chunk, module, new Error().stack!.substring(5));
209
+
return Promise.reject("Chunk ID match failed");
210
+
}
164
211
165
212
const moduleId = findCode.match(module)?.[1];
166
-
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
+
}
167
217
168
218
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() => webpackRequire(moduleId));
169
219
},
+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
}
+119
-93
packages/injector/src/index.ts
+119
-93
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
12
import { loadExtensions, loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
13
13
import EventEmitter from "node:events";
14
-
import { join, resolve } from "node:path";
14
+
import path from "node:path";
15
15
import persist from "@moonlight-mod/core/persist";
16
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";
17
19
18
20
const logger = new Logger("injector");
19
21
20
22
let oldPreloadPath: string | undefined;
21
23
let corsAllow: string[] = [];
22
24
let blockedUrls: RegExp[] = [];
23
-
let isMoonlightDesktop = false;
24
-
let hasOpenAsar = false;
25
-
let openAsarConfigPreload: string | undefined;
25
+
let injectorConfig: InjectorConfig | undefined;
26
+
27
+
const scriptUrls = ["web.", "sentry."];
28
+
const blockedScripts = new Set<string>();
26
29
27
30
ipcMain.on(constants.ipcGetOldPreloadPath, (e) => {
28
31
e.returnValue = oldPreloadPath;
29
32
});
33
+
30
34
ipcMain.on(constants.ipcGetAppData, (e) => {
31
35
e.returnValue = app.getPath("appData");
32
36
});
33
-
ipcMain.on(constants.ipcGetIsMoonlightDesktop, (e) => {
34
-
e.returnValue = isMoonlightDesktop;
37
+
ipcMain.on(constants.ipcGetInjectorConfig, (e) => {
38
+
e.returnValue = injectorConfig;
35
39
});
36
40
ipcMain.handle(constants.ipcMessageBox, (_, opts) => {
37
41
electron.dialog.showMessageBoxSync(opts);
···
72
76
blockedUrls = compiled;
73
77
});
74
78
75
-
function patchCsp(headers: Record<string, string[]>) {
76
-
const directives = ["style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src", "prefetch-src"];
77
-
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:"];
78
82
79
83
const csp = "content-security-policy";
80
84
if (headers[csp] == null) return;
···
93
97
parts[directive] = values;
94
98
}
95
99
100
+
for (const [directive, urls] of Object.entries(extensionCspOverrides)) {
101
+
parts[directive] ??= [];
102
+
parts[directive].push(...urls);
103
+
}
104
+
96
105
const stringified = Object.entries<string[]>(parts)
97
106
.map(([key, value]) => {
98
107
return `${key} ${value.join(" ")}`;
···
101
110
headers[csp] = [stringified];
102
111
}
103
112
104
-
function removeOpenAsarEventIfPresent(eventHandler: (...args: any[]) => void) {
105
-
const code = eventHandler.toString();
106
-
if (code.indexOf("bw.webContents.on('dom-ready'") > -1) {
107
-
electron.app.off("browser-window-created", eventHandler);
108
-
}
109
-
}
110
-
111
113
class BrowserWindow extends ElectronBrowserWindow {
112
114
constructor(opts: BrowserWindowConstructorOptions) {
113
-
oldPreloadPath = opts.webPreferences!.preload;
114
-
115
115
const isMainWindow = opts.webPreferences!.preload!.indexOf("discord_desktop_core") > -1;
116
116
117
-
if (isMainWindow) opts.webPreferences!.preload = require.resolve("./node-preload.js");
117
+
if (isMainWindow) {
118
+
if (!oldPreloadPath) oldPreloadPath = opts.webPreferences!.preload;
119
+
opts.webPreferences!.preload = require.resolve("./node-preload.js");
120
+
}
118
121
119
122
// Event for modifying window options
120
123
moonlightHost.events.emit("window-options", opts, isMainWindow);
···
124
127
// Event for when a window is created
125
128
moonlightHost.events.emit("window-created", this, isMainWindow);
126
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
+
127
142
this.webContents.session.webRequest.onHeadersReceived((details, cb) => {
128
143
if (details.responseHeaders != null) {
129
144
// Patch CSP so things can use externally hosted assets
130
145
if (details.resourceType === "mainFrame") {
131
-
patchCsp(details.responseHeaders);
146
+
patchCsp(details.responseHeaders, extensionCspOverrides);
132
147
}
133
148
134
149
// Allow plugins to bypass CORS for specific URLs
135
150
if (corsAllow.some((x) => details.url.startsWith(x))) {
136
-
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] = ["*"];
137
158
}
159
+
160
+
moonlightHost.events.emit("headers-received", details, isMainWindow);
138
161
139
162
cb({ cancel: false, responseHeaders: details.responseHeaders });
140
163
}
141
164
});
142
165
143
-
// Allow plugins to block some URLs,
144
-
// this is needed because multiple webRequest handlers cannot be registered at once
145
166
this.webContents.session.webRequest.onBeforeRequest((details, cb) => {
146
-
cb({ cancel: blockedUrls.some((u) => u.test(details.url)) });
147
-
});
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.
173
+
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);
148
188
149
-
if (hasOpenAsar) {
150
-
// Remove DOM injections
151
-
// Settings can still be opened via:
152
-
// `DiscordNative.ipc.send("DISCORD_UPDATED_QUOTES","o")`
153
-
// @ts-expect-error Electron internals
154
-
const events = electron.app._events["browser-window-created"];
155
-
if (Array.isArray(events)) {
156
-
for (const event of events) {
157
-
removeOpenAsarEventIfPresent(event);
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);
158
195
}
159
-
} else if (events != null) {
160
-
removeOpenAsarEventIfPresent(events);
161
-
}
162
196
163
-
// Config screen fails to context bridge properly
164
-
// Less than ideal, but better than disabling it everywhere
165
-
if (opts.webPreferences!.preload === openAsarConfigPreload) {
166
-
opts.webPreferences!.sandbox = false;
197
+
if (hasUrl) return cb({ cancel: true });
167
198
}
168
-
}
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
+
});
169
204
}
170
205
}
171
206
···
186
221
writable: false
187
222
});
188
223
189
-
export async function inject(asarPath: string) {
190
-
isMoonlightDesktop = asarPath === "moonlightDesktop";
224
+
type InjectorConfig = { disablePersist?: boolean; disableLoad?: boolean };
225
+
export async function inject(asarPath: string, _injectorConfig?: InjectorConfig) {
226
+
injectorConfig = _injectorConfig;
227
+
191
228
global.moonlightNodeSandboxed = {
192
229
fs: createFS(),
193
230
// These aren't supposed to be used from host
194
-
addCors(url) {},
195
-
addBlocked(url) {}
231
+
addCors() {},
232
+
addBlocked() {}
196
233
};
197
234
198
235
try {
199
-
const config = await readConfig();
236
+
let config = await readConfig();
200
237
initLogger(config);
201
238
const extensions = await getExtensions();
239
+
const processedExtensions = await loadExtensions(extensions);
240
+
const moonlightDir = await getMoonlightDir();
241
+
const extensionsPath = await getExtensionsPath();
202
242
203
243
// Duplicated in node-preload... oops
204
244
function getConfig(ext: string) {
···
206
246
if (val == null || typeof val === "boolean") return undefined;
207
247
return val.config;
208
248
}
209
-
210
249
global.moonlightHost = {
250
+
get config() {
251
+
return config;
252
+
},
253
+
extensions,
254
+
processedExtensions,
211
255
asarPath,
212
-
config,
213
256
events: new EventEmitter(),
214
-
extensions,
215
-
processedExtensions: {
216
-
extensions: [],
217
-
dependencyGraph: new Map()
218
-
},
219
257
220
258
version: MOONLIGHT_VERSION,
221
259
branch: MOONLIGHT_BRANCH as MoonlightBranch,
222
260
223
261
getConfig,
224
-
getConfigOption: <T>(ext: string, name: string) => {
225
-
const config = getConfig(ext);
226
-
if (config == null) return undefined;
227
-
const option = config[name];
228
-
if (option == null) return undefined;
229
-
return option as T;
262
+
getConfigPath,
263
+
getConfigOption(ext, name) {
264
+
const manifest = getManifest(extensions, ext);
265
+
return getConfigOption(ext, name, config, manifest?.settings);
230
266
},
231
-
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) {
232
277
return new Logger(id);
278
+
},
279
+
getMoonlightDir() {
280
+
return moonlightDir;
281
+
},
282
+
getExtensionDir: (ext: string) => {
283
+
return path.join(extensionsPath, ext);
233
284
}
234
285
};
235
286
236
-
// Check if we're running with OpenAsar
237
-
try {
238
-
require.resolve(join(asarPath, "updater", "updater.js"));
239
-
hasOpenAsar = true;
240
-
openAsarConfigPreload = resolve(asarPath, "config", "preload.js");
241
-
// eslint-disable-next-line no-empty
242
-
} catch {}
243
-
244
-
if (hasOpenAsar) {
245
-
// Disable command line switch injection
246
-
// I personally think that the command line switches should be vetted by
247
-
// the user and not just "trust that these are sane defaults that work
248
-
// always". I'm not hating on Ducko or anything, I'm just opinionated.
249
-
// Someone can always make a command line modifier plugin, thats the point
250
-
// of having host modules.
251
-
try {
252
-
const cmdSwitchesPath = require.resolve(join(asarPath, "cmdSwitches.js"));
253
-
require.cache[cmdSwitchesPath] = new Module(cmdSwitchesPath, require.cache[require.resolve(asarPath)]);
254
-
require.cache[cmdSwitchesPath]!.exports = () => {};
255
-
} catch (error) {
256
-
logger.error("Failed to disable OpenAsar's command line flags:", error);
257
-
}
258
-
}
259
-
260
287
patchElectron();
261
288
262
-
global.moonlightHost.processedExtensions = await loadExtensions(extensions);
263
289
await loadProcessedExtensions(global.moonlightHost.processedExtensions);
264
290
} catch (error) {
265
291
logger.error("Failed to inject:", error);
266
292
}
267
293
268
-
if (isMoonlightDesktop) return;
269
-
270
-
if (!hasOpenAsar && !isMoonlightDesktop) {
294
+
if (injectorConfig?.disablePersist !== true) {
271
295
persist(asarPath);
272
296
}
273
297
274
-
// Need to do this instead of require() or it breaks require.main
275
-
// @ts-expect-error Module internals
276
-
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
+
}
277
303
}
278
304
279
305
function patchElectron() {
+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
}
+72
-13
packages/node-preload/src/index.ts
+72
-13
packages/node-preload/src/index.ts
···
11
11
import createFS from "@moonlight-mod/core/fs";
12
12
import { registerCors, registerBlocked, getDynamicCors } from "@moonlight-mod/core/cors";
13
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";
14
16
15
17
let initialized = false;
18
+
let logger: Logger;
16
19
17
20
function setCors() {
18
21
const data = getDynamicCors();
···
35
38
36
39
let config = await readConfig();
37
40
initLogger(config);
41
+
logger = new Logger("node-preload");
42
+
38
43
const extensions = await getExtensions();
39
44
const processedExtensions = await loadExtensions(extensions);
40
45
const moonlightDir = await getMoonlightDir();
···
48
53
processedExtensions,
49
54
nativesCache: {},
50
55
isBrowser: false,
56
+
events: createEventEmitter<NodeEventType, NodeEventPayloads>(),
51
57
52
58
version: MOONLIGHT_VERSION,
53
59
branch: MOONLIGHT_BRANCH as MoonlightBranch,
···
57
63
},
58
64
getConfigOption(ext, name) {
59
65
const manifest = getManifest(extensions, ext);
60
-
return getConfigOption(ext, name, config, manifest);
66
+
return getConfigOption(ext, name, config, manifest?.settings);
61
67
},
62
-
setConfigOption(ext, name, value) {
68
+
async setConfigOption(ext, name, value) {
63
69
setConfigOption(config, ext, name, value);
64
-
this.writeConfig(config);
70
+
await this.writeConfig(config);
71
+
},
72
+
async writeConfig(newConfig) {
73
+
await writeConfig(newConfig);
74
+
config = newConfig;
75
+
this.events.dispatchEvent(NodeEventType.ConfigSaved, newConfig);
65
76
},
66
77
67
78
getNatives: (ext: string) => global.moonlightNode.nativesCache[ext],
68
79
getLogger: (id: string) => {
69
80
return new Logger(id);
70
81
},
71
-
72
82
getMoonlightDir() {
73
83
return moonlightDir;
74
84
},
75
85
getExtensionDir: (ext: string) => {
76
86
return path.join(extensionsPath, ext);
77
-
},
78
-
async writeConfig(newConfig) {
79
-
await writeConfig(newConfig);
80
-
config = newConfig;
81
87
}
82
88
};
83
89
···
109
115
const webPreloadPath = path.join(__dirname, "web-preload.js");
110
116
const webPreload = fs.readFileSync(webPreloadPath, "utf8");
111
117
await webFrame.executeJavaScript(webPreload);
118
+
119
+
const func = await webFrame.executeJavaScript("async () => { await window._moonlightWebLoad(); }");
120
+
await func();
112
121
}
113
122
114
-
async function init(oldPreloadPath: string) {
123
+
async function init() {
115
124
try {
116
125
await injectGlobals();
117
126
await loadPreload();
···
122
131
message: message
123
132
});
124
133
}
125
-
126
-
// Let Discord start even if we fail
127
-
if (oldPreloadPath) require(oldPreloadPath);
128
134
}
129
135
130
136
const oldPreloadPath: string = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
131
-
init(oldPreloadPath);
137
+
const isOverlay = window.location.href.indexOf("discord_overlay") > -1;
138
+
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.3",
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.10",
14
-
"@moonlight-mod/moonmap": "^1.0.3",
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
}
+48
packages/types/src/config.ts
+48
packages/types/src/config.ts
···
33
33
};
34
34
35
35
export type BooleanSettingType = {
36
+
/**
37
+
* Displays as a simple switch.
38
+
*/
36
39
type: ExtensionSettingType.Boolean;
37
40
default?: boolean;
38
41
};
39
42
40
43
export type NumberSettingType = {
44
+
/**
45
+
* Displays as a simple slider.
46
+
*/
41
47
type: ExtensionSettingType.Number;
42
48
default?: number;
43
49
min?: number;
···
45
51
};
46
52
47
53
export type StringSettingType = {
54
+
/**
55
+
* Displays as a single line string input.
56
+
*/
48
57
type: ExtensionSettingType.String;
49
58
default?: string;
50
59
};
51
60
52
61
export type MultilineTextInputSettingType = {
62
+
/**
63
+
* Displays as a multiple line string input.
64
+
*/
53
65
type: ExtensionSettingType.MultilineString;
54
66
default?: string;
55
67
};
56
68
57
69
export type SelectSettingType = {
70
+
/**
71
+
* A dropdown to pick between one of many values.
72
+
*/
58
73
type: ExtensionSettingType.Select;
59
74
options: SelectOption[];
60
75
default?: string;
61
76
};
62
77
63
78
export type MultiSelectSettingType = {
79
+
/**
80
+
* A dropdown to pick multiple values.
81
+
*/
64
82
type: ExtensionSettingType.MultiSelect;
65
83
options: string[];
66
84
default?: string[];
67
85
};
68
86
69
87
export type ListSettingType = {
88
+
/**
89
+
* A list of strings that the user can add or remove from.
90
+
*/
70
91
type: ExtensionSettingType.List;
71
92
default?: string[];
72
93
};
73
94
74
95
export type DictionarySettingType = {
96
+
/**
97
+
* A dictionary (key-value pair) that the user can add or remove from.
98
+
*/
75
99
type: ExtensionSettingType.Dictionary;
76
100
default?: Record<string, string>;
77
101
};
78
102
79
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
+
*/
80
108
type: ExtensionSettingType.Custom;
81
109
default?: any;
82
110
};
83
111
112
+
export enum ExtensionSettingsAdvice {
113
+
None = "none",
114
+
Reload = "reload",
115
+
Restart = "restart"
116
+
}
117
+
84
118
export type ExtensionSettingsManifest = {
119
+
/**
120
+
* A human friendly name for the setting.
121
+
*/
85
122
displayName?: string;
123
+
124
+
/**
125
+
* A longer description for the setting.
126
+
* Markdown is not supported.
127
+
*/
86
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;
87
135
} & (
88
136
| BooleanSettingType
89
137
| NumberSettingType
+3
-1
packages/types/src/constants.ts
+3
-1
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
-4
packages/types/src/core/event.ts
+13
-4
packages/types/src/core/event.ts
···
1
+
import { Config } from "../config";
1
2
import { WebpackModuleFunc, WebpackRequireType } from "../discord";
2
3
3
4
export interface MoonlightEventEmitter<EventId extends string = string, EventData = Record<EventId, any>> {
···
6
7
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => void;
7
8
}
8
9
9
-
export enum EventType {
10
+
export enum WebEventType {
10
11
ChunkLoad = "chunkLoad",
11
12
ExtensionLoad = "extensionLoad"
12
13
}
13
14
14
-
export type EventPayloads = {
15
-
[EventType.ChunkLoad]: {
15
+
export type WebEventPayloads = {
16
+
[WebEventType.ChunkLoad]: {
16
17
chunkId?: number[];
17
18
modules: { [id: string]: WebpackModuleFunc };
18
19
require?: (require: WebpackRequireType) => any;
19
20
};
20
-
[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;
21
30
};
+9
packages/types/src/coreExtensions/appPanels.ts
+9
packages/types/src/coreExtensions/appPanels.ts
···
1
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
+
*/
2
7
addPanel: (section: string, element: React.FC<any>) => void;
8
+
9
+
/**
10
+
* @private
11
+
*/
3
12
getPanels: (el: React.FC<any>) => React.ReactNode;
4
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
+8
-1
packages/types/src/coreExtensions/contextMenu.ts
+8
-1
packages/types/src/coreExtensions/contextMenu.ts
···
10
10
} from "@moonlight-mod/mappings/discord/components/common/index";
11
11
12
12
export type ContextMenu = {
13
-
addItem: (navId: string, item: (props: any) => MenuElement, anchorId: string, before?: boolean) => 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;
14
21
15
22
MenuCheckboxItem: MenuCheckboxItem;
16
23
MenuControlItem: MenuControlItem;
+15
packages/types/src/coreExtensions/markdown.ts
+15
packages/types/src/coreExtensions/markdown.ts
···
82
82
slateDecorators: Record<string, string>;
83
83
ruleBlacklists: Record<Ruleset, Record<string, boolean>>;
84
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
+
*/
85
94
addRule: (
86
95
name: string,
87
96
markdown: (rules: Record<string, MarkdownRule>) => MarkdownRule,
88
97
slate: (rules: Record<string, SlateRule>) => SlateRule,
89
98
decorator?: string | undefined
90
99
) => void;
100
+
101
+
/**
102
+
* Blacklist a rule from a ruleset.
103
+
* @param ruleset The ruleset name
104
+
* @param name The rule name
105
+
*/
91
106
blacklistFromRuleset: (ruleset: Ruleset, name: string) => void;
92
107
};
+11
-2
packages/types/src/coreExtensions/moonbase.ts
+11
-2
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 = {
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
+
*/
7
16
registerConfigComponent: (ext: string, option: string, component: CustomComponent) => void;
8
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
};
+58
-5
packages/types/src/coreExtensions/spacepack.ts
+58
-5
packages/types/src/coreExtensions/spacepack.ts
···
1
1
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "../discord";
2
2
3
-
// Only bothered TSDoc'ing the hard-to-understand functions
4
-
5
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
+
*/
6
10
inspect: (module: number | string) => WebpackModuleFunc | null;
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
+
*/
7
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
+
*/
8
25
findByExports: (...args: string[]) => WebpackModule[];
9
-
// re-export of require
26
+
27
+
/**
28
+
* The Webpack require function.
29
+
*/
10
30
require: WebpackRequireType;
11
-
// re-export of require.m
31
+
32
+
/**
33
+
* The Webpack module list.
34
+
* Re-export of require.m.
35
+
*/
12
36
modules: Record<string, WebpackModuleFunc>;
13
-
// re-export of require.c
37
+
38
+
/**
39
+
* The Webpack module cache.
40
+
* Re-export of require.c.
41
+
*/
14
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
+
*/
15
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
+
*/
16
58
findObjectFromValue: (exports: Record<string, any>, value: any) => 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
+
*/
17
67
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => any | null;
68
+
18
69
/**
19
70
* Finds a function from a module's exports using the given source find.
20
71
* This behaves like findByCode but localized to the exported function.
···
27
78
...strings: (string | RegExp)[]
28
79
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
29
80
) => Function | null;
81
+
30
82
/**
31
83
* Lazy load a Webpack module.
32
84
* @param find A list of finds to discover a target module with
···
35
87
* @returns The target Webpack module
36
88
*/
37
89
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => Promise<any>;
90
+
38
91
/**
39
92
* Filter a list of Webpack modules to "real" ones from the Discord client.
40
93
* @param modules A list of Webpack modules
+3
packages/types/src/coreExtensions.ts
+3
packages/types/src/coreExtensions.ts
···
5
5
export * as Notices from "./coreExtensions/notices";
6
6
export * as Moonbase from "./coreExtensions/moonbase";
7
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";
+12
packages/types/src/discord/require.ts
+12
packages/types/src/discord/require.ts
···
1
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";
2
5
import { ContextMenu, EvilItemParser } from "../coreExtensions/contextMenu";
3
6
import { Markdown } from "../coreExtensions/markdown";
4
7
import { Moonbase } from "../coreExtensions/moonbase";
···
9
12
declare function WebpackRequire(id: string): any;
10
13
11
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;
12
24
13
25
declare function WebpackRequire(id: "contextMenu_evilMenu"): EvilItemParser;
14
26
declare function WebpackRequire(id: "contextMenu_contextMenu"): ContextMenu;
+103
-1
packages/types/src/extension.ts
+103
-1
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
···
107
208
export type Patch = {
108
209
find: PatchMatch;
109
210
replace: PatchReplace | PatchReplace[];
211
+
hardFail?: boolean; // if any patches fail, all fail
110
212
prerequisite?: () => boolean;
111
213
};
112
214
+1
packages/types/src/fs.ts
+1
packages/types/src/fs.ts
+24
-9
packages/types/src/globals.ts
+24
-9
packages/types/src/globals.ts
···
4
4
import type EventEmitter from "events";
5
5
import type LunAST from "@moonlight-mod/lunast";
6
6
import type Moonmap from "@moonlight-mod/moonmap";
7
-
import type { EventPayloads, EventType, MoonlightEventEmitter } from "./core/event";
8
-
import { MoonlightFS } from "./fs";
7
+
import type {
8
+
WebEventPayloads,
9
+
WebEventType,
10
+
MoonlightEventEmitter,
11
+
NodeEventType,
12
+
NodeEventPayloads
13
+
} from "./core/event";
14
+
import type { MoonlightFS } from "./fs";
9
15
10
16
export type MoonlightHost = {
11
-
asarPath: string;
12
17
config: Config;
13
-
events: EventEmitter;
14
18
extensions: DetectedExtension[];
15
19
processedExtensions: ProcessedExtensions;
20
+
asarPath: string;
21
+
events: EventEmitter;
16
22
17
23
version: string;
18
24
branch: MoonlightBranch;
19
25
20
26
getConfig: (ext: string) => ConfigExtension["config"];
27
+
getConfigPath: () => Promise<string>;
21
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
+
22
32
getLogger: (id: string) => Logger;
33
+
getMoonlightDir: () => string;
34
+
getExtensionDir: (ext: string) => string;
23
35
};
24
36
25
37
export type MoonlightNode = {
···
28
40
processedExtensions: ProcessedExtensions;
29
41
nativesCache: Record<string, any>;
30
42
isBrowser: boolean;
43
+
events: MoonlightEventEmitter<NodeEventType, NodeEventPayloads>;
31
44
32
45
version: string;
33
46
branch: MoonlightBranch;
34
47
35
48
getConfig: (ext: string) => ConfigExtension["config"];
36
49
getConfigOption: <T>(ext: string, name: string) => T | undefined;
37
-
setConfigOption: <T>(ext: string, name: string, value: T) => void;
50
+
setConfigOption: <T>(ext: string, name: string, value: T) => Promise<void>;
51
+
writeConfig: (config: Config) => Promise<void>;
38
52
39
53
getNatives: (ext: string) => any | undefined;
40
54
getLogger: (id: string) => Logger;
41
-
42
55
getMoonlightDir: () => string;
43
56
getExtensionDir: (ext: string) => string;
44
-
writeConfig: (config: Config) => Promise<void>;
45
57
};
46
58
47
59
export type MoonlightNodeSandboxed = {
···
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
72
onModuleLoad: (moduleId: string | string[], callback: (moduleId: string) => void) => void;
61
73
registerPatch: (patch: IdentifiedPatch) => void;
···
65
77
66
78
version: string;
67
79
branch: MoonlightBranch;
80
+
apiLevel: number;
68
81
69
82
// Re-exports for ease of use
70
83
getConfig: MoonlightNode["getConfig"];
71
84
getConfigOption: MoonlightNode["getConfigOption"];
72
85
setConfigOption: MoonlightNode["setConfigOption"];
86
+
writeConfig: MoonlightNode["writeConfig"];
73
87
74
88
getNatives: (ext: string) => any | undefined;
75
89
getLogger: (id: string) => Logger;
90
+
76
91
lunast: LunAST;
77
92
moonmap: Moonmap;
78
93
};
+32
packages/types/src/import.d.ts
+32
packages/types/src/import.d.ts
···
4
4
export = AppPanels;
5
5
}
6
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
+
}
7
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
+
}
8
40
9
41
declare module "@moonlight-mod/wp/contextMenu_evilMenu" {
10
42
import { CoreExtensions } from "@moonlight-mod/types";
+3
-2
packages/types/src/index.ts
+3
-2
packages/types/src/index.ts
···
32
32
var moonlightNode: MoonlightNode;
33
33
var moonlightNodeSandboxed: MoonlightNodeSandboxed;
34
34
var moonlight: MoonlightWeb;
35
+
var _moonlight_coreExtensionsStr: string;
35
36
36
-
var _moonlightBrowserInit: () => Promise<void>;
37
-
var _moonlightBrowserLoad: () => Promise<void>;
37
+
var _moonlightBrowserInit: undefined | (() => Promise<void>);
38
+
var _moonlightWebLoad: undefined | (() => Promise<void>);
38
39
}
+841
-25
packages/types/src/mappings.d.ts
+841
-25
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;
6
43
}
7
44
8
45
declare module "@moonlight-mod/wp/discord/actions/ContextMenuActionCreators" {
9
46
import { MappedModules } from "@moonlight-mod/mappings";
10
-
const _: MappedModules["discord/actions/ContextMenuActionCreators"];
11
-
export = _;
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"];
12
160
}
13
161
14
162
declare module "@moonlight-mod/wp/discord/components/common/index" {
15
163
import { MappedModules } from "@moonlight-mod/mappings";
16
-
const _: MappedModules["discord/components/common/index"];
17
-
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"];
18
275
}
19
276
20
-
declare module "@moonlight-mod/wp/discord/modules/guild_settings/IntegrationCard.css" {
277
+
declare module "@moonlight-mod/wp/discord/components/modals/ConfirmModal" {
21
278
import { MappedModules } from "@moonlight-mod/mappings";
22
-
const _: MappedModules["discord/modules/guild_settings/IntegrationCard.css"];
23
-
export = _;
279
+
const _default: MappedModules["discord/components/modals/ConfirmModal"]["default"];
280
+
export default _default;
281
+
}
282
+
283
+
declare module "@moonlight-mod/wp/discord/lib/BaseRecord" {
284
+
import { MappedModules } from "@moonlight-mod/mappings";
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"];
24
503
}
25
504
26
505
declare module "@moonlight-mod/wp/discord/modules/markup/MarkupUtils" {
27
506
import { MappedModules } from "@moonlight-mod/mappings";
28
-
const _: MappedModules["discord/modules/markup/MarkupUtils"];
29
-
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"];
30
613
}
31
614
32
-
declare module "@moonlight-mod/wp/discord/modules/user_settings/web/openUserSettings" {
615
+
declare module "@moonlight-mod/wp/discord/modules/modals/Modals" {
33
616
import { MappedModules } from "@moonlight-mod/mappings";
34
-
const _: MappedModules["discord/modules/user_settings/web/openUserSettings"];
35
-
export = _;
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"];
36
666
}
37
667
38
668
declare module "@moonlight-mod/wp/discord/packages/flux" {
39
669
import { MappedModules } from "@moonlight-mod/mappings";
40
-
const _: MappedModules["discord/packages/flux"];
41
-
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"];
42
747
}
43
748
44
749
declare module "@moonlight-mod/wp/discord/uikit/Flex" {
45
750
import { MappedModules } from "@moonlight-mod/mappings";
46
-
const _: MappedModules["discord/uikit/Flex"];
47
-
export = _;
751
+
const _default: MappedModules["discord/uikit/Flex"]["default"];
752
+
export default _default;
48
753
}
49
754
50
755
declare module "@moonlight-mod/wp/discord/utils/ClipboardUtils" {
51
756
import { MappedModules } from "@moonlight-mod/mappings";
52
-
const _: MappedModules["discord/utils/ClipboardUtils"];
53
-
export = _;
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"];
54
765
}
55
766
56
767
declare module "@moonlight-mod/wp/discord/utils/HTTPUtils" {
57
768
import { MappedModules } from "@moonlight-mod/mappings";
58
-
const _: MappedModules["discord/utils/HTTPUtils"];
59
-
export = _;
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"];
60
776
}
61
777
62
778
declare module "@moonlight-mod/wp/discord/utils/NativeUtils" {
63
779
import { MappedModules } from "@moonlight-mod/mappings";
64
-
const _: MappedModules["discord/utils/NativeUtils"];
65
-
export = _;
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"];
66
880
}
67
881
68
882
declare module "@moonlight-mod/wp/react" {
69
883
import { MappedModules } from "@moonlight-mod/mappings";
70
-
const _: MappedModules["react"];
884
+
const _: Omit<MappedModules["react"], "__mappings_exportEquals">;
71
885
export = _;
72
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.10",
9
-
"@moonlight-mod/moonmap": "^1.0.3",
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
}
+12
-13
packages/web-preload/src/index.ts
+12
-13
packages/web-preload/src/index.ts
···
7
7
import Moonmap from "@moonlight-mod/moonmap";
8
8
import loadMappings from "@moonlight-mod/mappings";
9
9
import { createEventEmitter } from "@moonlight-mod/core/util/event";
10
-
import { EventPayloads, EventType } from "@moonlight-mod/types/core/event";
10
+
import { WebEventPayloads, WebEventType } from "@moonlight-mod/types/core/event";
11
11
12
12
async function load() {
13
+
delete window._moonlightWebLoad;
13
14
initLogger(moonlightNode.config);
14
15
const logger = new Logger("web-preload");
15
16
16
17
window.moonlight = {
17
-
apiLevel: constants.apiLevel,
18
+
patched: new Map(),
18
19
unpatched: new Set(),
19
20
pendingModules: new Set(),
20
21
enabledExtensions: new Set(),
21
-
events: createEventEmitter<EventType, EventPayloads>(),
22
+
23
+
events: createEventEmitter<WebEventType, WebEventPayloads>(),
22
24
patchingInternals: {
23
25
onModuleLoad,
24
26
registerPatch,
···
28
30
29
31
version: MOONLIGHT_VERSION,
30
32
branch: MOONLIGHT_BRANCH as MoonlightBranch,
33
+
apiLevel: constants.apiLevel,
31
34
32
35
getConfig: moonlightNode.getConfig.bind(moonlightNode),
33
36
getConfigOption: moonlightNode.getConfigOption.bind(moonlightNode),
34
37
setConfigOption: moonlightNode.setConfigOption.bind(moonlightNode),
38
+
writeConfig: moonlightNode.writeConfig.bind(moonlightNode),
35
39
36
40
getNatives: moonlightNode.getNatives.bind(moonlightNode),
37
41
getLogger(id) {
38
42
return new Logger(id);
39
43
},
44
+
40
45
lunast: new LunAST(),
41
46
moonmap: new Moonmap()
42
47
};
···
49
54
logger.error("Error setting up web-preload", e);
50
55
}
51
56
52
-
if (MOONLIGHT_ENV === "web-preload") {
53
-
window.addEventListener("DOMContentLoaded", () => {
54
-
installStyles();
55
-
});
57
+
if (document.readyState === "complete") {
58
+
installStyles();
56
59
} else {
57
-
installStyles();
60
+
window.addEventListener("load", installStyles);
58
61
}
59
62
}
60
63
61
-
if (MOONLIGHT_ENV === "web-preload") {
62
-
load();
63
-
} else {
64
-
window._moonlightBrowserLoad = load;
65
-
}
64
+
window._moonlightWebLoad = load;
+4
-1
packages/web-preload/tsconfig.json
+4
-1
packages/web-preload/tsconfig.json
+1253
-731
pnpm-lock.yaml
+1253
-731
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
66
'@moonlight-mod/eslint-config':
12
-
specifier: github:moonlight-mod/eslint-config
13
-
version: https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/7eb7bd7c51fe0e3ee9d2a0baf149212d2bb893af(eslint@9.12.0)(prettier@3.1.0)(typescript@5.3.2)
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
14
72
esbuild:
15
-
specifier: ^0.19.3
73
+
specifier: catalog:dev
16
74
version: 0.19.3
17
75
esbuild-copy-static-files:
18
-
specifier: ^0.1.0
76
+
specifier: catalog:dev
19
77
version: 0.1.0
20
78
eslint:
21
-
specifier: ^9.12.0
22
-
version: 9.12.0
79
+
specifier: catalog:dev
80
+
version: 9.23.0(jiti@2.4.2)
23
81
husky:
24
-
specifier: ^8.0.3
82
+
specifier: catalog:dev
25
83
version: 8.0.3
26
84
prettier:
27
-
specifier: ^3.1.0
85
+
specifier: catalog:dev
28
86
version: 3.1.0
87
+
taze:
88
+
specifier: catalog:dev
89
+
version: 19.0.4
29
90
typescript:
30
-
specifier: ^5.3.2
31
-
version: 5.3.2
91
+
specifier: catalog:dev
92
+
version: 5.8.2
32
93
33
94
packages/browser:
34
95
dependencies:
···
42
103
specifier: workspace:*
43
104
version: link:../web-preload
44
105
'@zenfs/core':
45
-
specifier: ^1.0.2
46
-
version: 1.0.2
106
+
specifier: catalog:prod
107
+
version: 2.0.0
47
108
'@zenfs/dom':
48
-
specifier: ^0.2.16
49
-
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
50
115
51
116
packages/core:
52
117
dependencies:
···
62
127
'@moonlight-mod/types':
63
128
specifier: workspace:*
64
129
version: link:../types
130
+
microdiff:
131
+
specifier: catalog:prod
132
+
version: 1.5.0
65
133
nanotar:
66
-
specifier: ^0.1.1
134
+
specifier: catalog:prod
67
135
version: 0.1.1
68
136
69
137
packages/injector:
···
87
155
packages/types:
88
156
dependencies:
89
157
'@moonlight-mod/lunast':
90
-
specifier: ^1.0.0
91
-
version: 1.0.0
158
+
specifier: ^1.0.1
159
+
version: 1.0.1
92
160
'@moonlight-mod/mappings':
93
-
specifier: ^1.0.10
94
-
version: 1.0.10(@moonlight-mod/lunast@1.0.0)(@moonlight-mod/moonmap@1.0.3)
161
+
specifier: ^1.1.25
162
+
version: 1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
95
163
'@moonlight-mod/moonmap':
96
-
specifier: ^1.0.3
97
-
version: 1.0.3
164
+
specifier: ^1.0.5
165
+
version: 1.0.5
98
166
'@types/react':
99
167
specifier: ^18.3.10
100
-
version: 18.3.10
168
+
version: 18.3.20
101
169
csstype:
102
-
specifier: ^3.1.2
103
-
version: 3.1.2
170
+
specifier: ^3.1.3
171
+
version: 3.1.3
104
172
standalone-electron-types:
105
173
specifier: ^1.0.0
106
174
version: 1.0.0
···
111
179
specifier: workspace:*
112
180
version: link:../core
113
181
'@moonlight-mod/lunast':
114
-
specifier: ^1.0.0
115
-
version: 1.0.0
182
+
specifier: catalog:prod
183
+
version: 1.0.1
116
184
'@moonlight-mod/mappings':
117
-
specifier: ^1.0.10
118
-
version: 1.0.10(@moonlight-mod/lunast@1.0.0)(@moonlight-mod/moonmap@1.0.3)
185
+
specifier: catalog:prod
186
+
version: 1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
119
187
'@moonlight-mod/moonmap':
120
-
specifier: ^1.0.3
121
-
version: 1.0.3
188
+
specifier: catalog:prod
189
+
version: 1.0.5
122
190
'@moonlight-mod/types':
123
191
specifier: workspace:*
124
192
version: link:../types
···
128
196
'@aashutoshrathi/word-wrap@1.2.6':
129
197
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
130
198
engines: {node: '>=0.10.0'}
199
+
200
+
'@antfu/ni@24.3.0':
201
+
resolution: {integrity: sha512-wBSav4mBxvHEW9RbdSo1SWLQ6MAlT0Dc423weC58yOWqW4OcMvtnNDdDrxOZeJ88fEIyPK93gDUWIelBxzSf8g==}
202
+
hasBin: true
131
203
132
204
'@esbuild/android-arm64@0.19.3':
133
205
resolution: {integrity: sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==}
···
261
333
cpu: [x64]
262
334
os: [win32]
263
335
264
-
'@eslint-community/eslint-utils@4.4.0':
265
-
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
336
+
'@eslint-community/eslint-utils@4.5.1':
337
+
resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
266
338
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
267
339
peerDependencies:
268
340
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
269
341
270
-
'@eslint-community/regexpp@4.11.1':
271
-
resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==}
342
+
'@eslint-community/regexpp@4.12.1':
343
+
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
272
344
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
273
345
274
-
'@eslint/config-array@0.18.0':
275
-
resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==}
346
+
'@eslint/config-array@0.19.2':
347
+
resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
276
348
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
277
349
278
-
'@eslint/core@0.6.0':
279
-
resolution: {integrity: sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==}
350
+
'@eslint/config-helpers@0.2.1':
351
+
resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==}
280
352
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
281
353
282
-
'@eslint/eslintrc@3.1.0':
283
-
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
354
+
'@eslint/core@0.12.0':
355
+
resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==}
284
356
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
285
357
286
-
'@eslint/js@9.12.0':
287
-
resolution: {integrity: sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==}
358
+
'@eslint/core@0.13.0':
359
+
resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==}
288
360
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
289
361
290
-
'@eslint/object-schema@2.1.4':
291
-
resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==}
362
+
'@eslint/eslintrc@3.3.1':
363
+
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
292
364
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
293
365
294
-
'@eslint/plugin-kit@0.2.0':
295
-
resolution: {integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==}
366
+
'@eslint/js@9.23.0':
367
+
resolution: {integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==}
296
368
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
297
369
298
-
'@humanfs/core@0.19.0':
299
-
resolution: {integrity: sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==}
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==}
300
380
engines: {node: '>=18.18.0'}
301
381
302
-
'@humanfs/node@0.16.5':
303
-
resolution: {integrity: sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==}
382
+
'@humanfs/node@0.16.6':
383
+
resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
304
384
engines: {node: '>=18.18.0'}
305
385
306
386
'@humanwhocodes/module-importer@1.0.1':
···
311
391
resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
312
392
engines: {node: '>=18.18'}
313
393
314
-
'@moonlight-mod/eslint-config@https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/7eb7bd7c51fe0e3ee9d2a0baf149212d2bb893af':
315
-
resolution: {tarball: https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/7eb7bd7c51fe0e3ee9d2a0baf149212d2bb893af}
316
-
version: 1.0.0
394
+
'@humanwhocodes/retry@0.4.2':
395
+
resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==}
396
+
engines: {node: '>=18.18'}
397
+
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
317
401
peerDependencies:
318
402
eslint: '>= 9'
319
403
typescript: '>= 5.3'
320
404
321
-
'@moonlight-mod/lunast@1.0.0':
322
-
resolution: {integrity: sha512-kJgf41K12i6/2LbXK97CNO+pNO7ADGh9N4bCQcOPwosocKMcwKHDEZUgPqeihNshY3c3AEW1LiyXjlsl24PdDw==}
405
+
'@moonlight-mod/lunast@1.0.1':
406
+
resolution: {integrity: sha512-K3vxzDlfFuYKjciIW2FMlcZ1qrrkAGDGpSBlNqYGtJ0sMt9bRCd2lpSpg6AX/giSljDtmAUXa/5mOfUoDQxjBA==}
323
407
324
-
'@moonlight-mod/mappings@1.0.10':
325
-
resolution: {integrity: sha512-L04To4MhlxOWxvvfVIRwj7d8H5qHthjUfikSx9WMk60qt67+6dFzN9CoAG9uG5l1B27IIEG3voVXBr0oSkooYw==}
408
+
'@moonlight-mod/mappings@1.1.25':
409
+
resolution: {integrity: sha512-bgnSN9H/IBdMGxGev6RQKXuzhQxwo1090NhIDHnflguZnjiu2pg/usPfh76bqyhxRuX4SS7tiZSNTwBoSflCLg==}
410
+
engines: {node: '>=22', npm: pnpm, pnpm: '>=10', yarn: pnpm}
326
411
peerDependencies:
327
-
'@moonlight-mod/lunast': ^1.0.0
328
-
'@moonlight-mod/moonmap': ^1.0.0
412
+
'@moonlight-mod/lunast': ^1.0.1
413
+
'@moonlight-mod/moonmap': ^1.0.5
329
414
330
-
'@moonlight-mod/moonmap@1.0.3':
331
-
resolution: {integrity: sha512-G7pwvrcVDimc388IX6VZFzBXpbuyvqbJ+w9/v+MUIc8P7dADJXQ9YkBWvobtRc6eaBBl1FWUwTeU8oobbxLVag==}
415
+
'@moonlight-mod/moonmap@1.0.5':
416
+
resolution: {integrity: sha512-Fdpxj8ghdulKB6TlTnchlCPey2YUKgEf1chuO1ofOIcvlqnVPBcQwSf2S80naOUQpXCDo4dQ+LWSE2fmhdDiiw==}
332
417
333
418
'@nodelib/fs.scandir@2.1.5':
334
419
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
···
342
427
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
343
428
engines: {node: '>= 8'}
344
429
345
-
'@pkgr/core@0.1.1':
346
-
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
430
+
'@pkgr/core@0.2.0':
431
+
resolution: {integrity: sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==}
347
432
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
348
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
+
349
447
'@types/estree-jsx@1.0.5':
350
448
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
351
449
352
450
'@types/estree@1.0.6':
353
451
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
354
452
453
+
'@types/estree@1.0.7':
454
+
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
455
+
355
456
'@types/fbemitter@2.0.35':
356
457
resolution: {integrity: sha512-Xem6d7qUfmouCHntCrRYgDBwbf+WWRd6G+7WEFlEZFZ67LZXiYRvT2LV8wcZa6mIaAil95+ABQdKgB6hPIsnng==}
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==}
357
464
358
465
'@types/flux@3.1.14':
359
466
resolution: {integrity: sha512-WRXN0kQPCnqxN0/PgNgc7WBF6c8rbSHsEep3/qBLpsQ824RONdOmTs0TV7XhIW2GDNRAHO2CqCgAFLR5PChosw==}
360
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
+
361
474
'@types/json-schema@7.0.15':
362
475
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
363
476
477
+
'@types/lodash@4.17.14':
478
+
resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==}
479
+
364
480
'@types/node@18.17.17':
365
481
resolution: {integrity: sha512-cOxcXsQ2sxiwkykdJqvyFS+MLQPLvIdwh5l6gNg8qF6s+C7XSkEWOZjK+XhUZd+mYvHV/180g2cnCcIl4l06Pw==}
366
482
367
-
'@types/node@20.16.10':
368
-
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==}
369
491
370
492
'@types/prop-types@15.7.13':
371
493
resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
372
494
373
-
'@types/react@18.3.10':
374
-
resolution: {integrity: sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==}
375
-
376
-
'@types/readable-stream@4.0.15':
377
-
resolution: {integrity: sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==}
495
+
'@types/react@18.3.20':
496
+
resolution: {integrity: sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==}
378
497
379
-
'@typescript-eslint/eslint-plugin@8.8.1':
380
-
resolution: {integrity: sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==}
498
+
'@typescript-eslint/eslint-plugin@8.29.0':
499
+
resolution: {integrity: sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==}
381
500
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
382
501
peerDependencies:
383
502
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
384
503
eslint: ^8.57.0 || ^9.0.0
385
-
typescript: '*'
386
-
peerDependenciesMeta:
387
-
typescript:
388
-
optional: true
504
+
typescript: '>=4.8.4 <5.9.0'
389
505
390
-
'@typescript-eslint/parser@8.8.1':
391
-
resolution: {integrity: sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==}
506
+
'@typescript-eslint/parser@8.29.0':
507
+
resolution: {integrity: sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==}
392
508
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
393
509
peerDependencies:
394
510
eslint: ^8.57.0 || ^9.0.0
395
-
typescript: '*'
396
-
peerDependenciesMeta:
397
-
typescript:
398
-
optional: true
511
+
typescript: '>=4.8.4 <5.9.0'
399
512
400
-
'@typescript-eslint/scope-manager@8.8.1':
401
-
resolution: {integrity: sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==}
513
+
'@typescript-eslint/scope-manager@8.29.0':
514
+
resolution: {integrity: sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==}
402
515
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
403
516
404
-
'@typescript-eslint/type-utils@8.8.1':
405
-
resolution: {integrity: sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==}
517
+
'@typescript-eslint/type-utils@8.29.0':
518
+
resolution: {integrity: sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==}
406
519
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
407
520
peerDependencies:
408
-
typescript: '*'
409
-
peerDependenciesMeta:
410
-
typescript:
411
-
optional: true
521
+
eslint: ^8.57.0 || ^9.0.0
522
+
typescript: '>=4.8.4 <5.9.0'
412
523
413
-
'@typescript-eslint/types@8.8.1':
414
-
resolution: {integrity: sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==}
524
+
'@typescript-eslint/types@8.29.0':
525
+
resolution: {integrity: sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==}
415
526
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
416
527
417
-
'@typescript-eslint/typescript-estree@8.8.1':
418
-
resolution: {integrity: sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==}
528
+
'@typescript-eslint/typescript-estree@8.29.0':
529
+
resolution: {integrity: sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==}
419
530
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
420
531
peerDependencies:
421
-
typescript: '*'
422
-
peerDependenciesMeta:
423
-
typescript:
424
-
optional: true
532
+
typescript: '>=4.8.4 <5.9.0'
425
533
426
-
'@typescript-eslint/utils@8.8.1':
427
-
resolution: {integrity: sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==}
534
+
'@typescript-eslint/utils@8.29.0':
535
+
resolution: {integrity: sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==}
428
536
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
429
537
peerDependencies:
430
538
eslint: ^8.57.0 || ^9.0.0
539
+
typescript: '>=4.8.4 <5.9.0'
431
540
432
-
'@typescript-eslint/visitor-keys@8.8.1':
433
-
resolution: {integrity: sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==}
541
+
'@typescript-eslint/visitor-keys@8.29.0':
542
+
resolution: {integrity: sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==}
434
543
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
435
544
436
-
'@zenfs/core@1.0.2':
437
-
resolution: {integrity: sha512-LMTD4ntn6Ag1y+IeOSVykDDvYC12dsGFtsX8M/54OQrLs7v+YnX4bpo0o2osbm8XFmU2MTNMX/G3PLsvzgWzrg==}
438
-
engines: {node: '>= 16'}
545
+
'@xterm/xterm@5.5.0':
546
+
resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==}
547
+
548
+
'@zenfs/core@2.0.0':
549
+
resolution: {integrity: sha512-wOKNFTY1DJ1vdLqKdU7M8cRh0nVYZcDVu7WHuk/3u49hrSwTZVm4PzGxJUjFd8O9Wi3U5nYTbZoN7RX5mS2ldA==}
550
+
engines: {node: '>= 18'}
439
551
hasBin: true
440
552
441
-
'@zenfs/dom@0.2.16':
442
-
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==}
443
555
engines: {node: '>= 18'}
444
556
peerDependencies:
445
-
'@zenfs/core': ^1.0.0
557
+
'@zenfs/core': ^2.0.0
558
+
utilium: ^1.9.0
446
559
447
560
abort-controller@3.0.0:
448
561
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
···
453
566
peerDependencies:
454
567
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
455
568
456
-
acorn@8.12.1:
457
-
resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
569
+
acorn@8.14.1:
570
+
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
458
571
engines: {node: '>=0.4.0'}
459
572
hasBin: true
460
573
···
465
578
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
466
579
engines: {node: '>=8'}
467
580
581
+
ansis@3.17.0:
582
+
resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==}
583
+
engines: {node: '>=14'}
584
+
468
585
argparse@2.0.1:
469
586
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
470
587
471
-
array-buffer-byte-length@1.0.1:
472
-
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
588
+
array-buffer-byte-length@1.0.2:
589
+
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
473
590
engines: {node: '>= 0.4'}
474
591
475
592
array-includes@3.1.8:
···
480
597
resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
481
598
engines: {node: '>= 0.4'}
482
599
483
-
array.prototype.flat@1.3.2:
484
-
resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
600
+
array.prototype.flat@1.3.3:
601
+
resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
485
602
engines: {node: '>= 0.4'}
486
603
487
-
array.prototype.flatmap@1.3.2:
488
-
resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
604
+
array.prototype.flatmap@1.3.3:
605
+
resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
489
606
engines: {node: '>= 0.4'}
490
607
491
608
array.prototype.tosorted@1.1.4:
492
609
resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
493
610
engines: {node: '>= 0.4'}
494
611
495
-
arraybuffer.prototype.slice@1.0.3:
496
-
resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
612
+
arraybuffer.prototype.slice@1.0.4:
613
+
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
497
614
engines: {node: '>= 0.4'}
498
615
499
616
astring@1.9.0:
500
617
resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
501
618
hasBin: true
619
+
620
+
async-function@1.0.0:
621
+
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
622
+
engines: {node: '>= 0.4'}
502
623
503
624
available-typed-arrays@1.0.7:
504
625
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
···
523
644
buffer@6.0.3:
524
645
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
525
646
526
-
call-bind@1.0.7:
527
-
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
647
+
cac@6.7.14:
648
+
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
649
+
engines: {node: '>=8'}
650
+
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==}
528
661
engines: {node: '>= 0.4'}
529
662
530
663
callsites@3.1.0:
···
545
678
concat-map@0.0.1:
546
679
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
547
680
548
-
cross-spawn@7.0.3:
549
-
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
681
+
cross-spawn@7.0.6:
682
+
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
550
683
engines: {node: '>= 8'}
551
684
552
-
csstype@3.1.2:
553
-
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
554
-
555
685
csstype@3.1.3:
556
686
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
557
687
558
-
data-view-buffer@1.0.1:
559
-
resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
688
+
data-view-buffer@1.0.2:
689
+
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
560
690
engines: {node: '>= 0.4'}
561
691
562
-
data-view-byte-length@1.0.1:
563
-
resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==}
692
+
data-view-byte-length@1.0.2:
693
+
resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
564
694
engines: {node: '>= 0.4'}
565
695
566
-
data-view-byte-offset@1.0.0:
567
-
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
696
+
data-view-byte-offset@1.0.1:
697
+
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
568
698
engines: {node: '>= 0.4'}
569
699
570
-
debug@4.3.4:
571
-
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
700
+
debug@4.4.0:
701
+
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
572
702
engines: {node: '>=6.0'}
573
703
peerDependencies:
574
704
supports-color: '*'
···
587
717
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
588
718
engines: {node: '>= 0.4'}
589
719
720
+
defu@6.1.4:
721
+
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
722
+
723
+
destr@2.0.4:
724
+
resolution: {integrity: sha512-FCAorltMy7QwX0QU38jOkhrv20LBpsHA8ogzvMhhPHCCKVCaN6GxrB0GGaWEWBUYI4eEjjfJ95RdP6dk9IdMQA==}
725
+
590
726
doctrine@2.1.0:
591
727
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
592
728
engines: {node: '>=0.10.0'}
593
729
594
-
es-abstract@1.23.3:
595
-
resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==}
730
+
dunder-proto@1.0.1:
731
+
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
596
732
engines: {node: '>= 0.4'}
597
733
598
-
es-define-property@1.0.0:
599
-
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
734
+
es-abstract@1.23.9:
735
+
resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
736
+
engines: {node: '>= 0.4'}
737
+
738
+
es-define-property@1.0.1:
739
+
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
600
740
engines: {node: '>= 0.4'}
601
741
602
742
es-errors@1.3.0:
603
743
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
604
744
engines: {node: '>= 0.4'}
605
745
606
-
es-iterator-helpers@1.1.0:
607
-
resolution: {integrity: sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==}
746
+
es-iterator-helpers@1.2.1:
747
+
resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==}
608
748
engines: {node: '>= 0.4'}
609
749
610
-
es-object-atoms@1.0.0:
611
-
resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
750
+
es-object-atoms@1.1.1:
751
+
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
612
752
engines: {node: '>= 0.4'}
613
753
614
-
es-set-tostringtag@2.0.3:
615
-
resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
754
+
es-set-tostringtag@2.1.0:
755
+
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
616
756
engines: {node: '>= 0.4'}
617
757
618
-
es-shim-unscopables@1.0.2:
619
-
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
758
+
es-shim-unscopables@1.1.0:
759
+
resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
760
+
engines: {node: '>= 0.4'}
620
761
621
-
es-to-primitive@1.2.1:
622
-
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
762
+
es-to-primitive@1.3.0:
763
+
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
623
764
engines: {node: '>= 0.4'}
624
765
625
766
esbuild-copy-static-files@0.1.0:
···
640
781
peerDependencies:
641
782
eslint: '>=7.0.0'
642
783
643
-
eslint-plugin-prettier@5.2.1:
644
-
resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==}
784
+
eslint-plugin-prettier@5.2.6:
785
+
resolution: {integrity: sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ==}
645
786
engines: {node: ^14.18.0 || >=16.0.0}
646
787
peerDependencies:
647
788
'@types/eslint': '>=8.0.0'
648
789
eslint: '>=8.0.0'
649
-
eslint-config-prettier: '*'
790
+
eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0'
650
791
prettier: '>=3.0.0'
651
792
peerDependenciesMeta:
652
793
'@types/eslint':
···
654
795
eslint-config-prettier:
655
796
optional: true
656
797
657
-
eslint-plugin-react@7.37.1:
658
-
resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==}
798
+
eslint-plugin-react@7.37.5:
799
+
resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
659
800
engines: {node: '>=4'}
660
801
peerDependencies:
661
802
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
662
803
663
-
eslint-scope@8.1.0:
664
-
resolution: {integrity: sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==}
804
+
eslint-scope@8.3.0:
805
+
resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
665
806
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
666
807
667
808
eslint-visitor-keys@3.4.3:
668
809
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
669
810
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
670
811
671
-
eslint-visitor-keys@4.1.0:
672
-
resolution: {integrity: sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==}
812
+
eslint-visitor-keys@4.2.0:
813
+
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
673
814
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
674
815
675
-
eslint@9.12.0:
676
-
resolution: {integrity: sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==}
816
+
eslint@9.23.0:
817
+
resolution: {integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==}
677
818
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
678
819
hasBin: true
679
820
peerDependencies:
···
682
823
jiti:
683
824
optional: true
684
825
685
-
espree@10.2.0:
686
-
resolution: {integrity: sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==}
826
+
espree@10.3.0:
827
+
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
687
828
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
688
829
689
-
esquery@1.5.0:
690
-
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
830
+
esquery@1.6.0:
831
+
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
691
832
engines: {node: '>=0.10'}
692
833
693
834
esrecurse@4.3.0:
···
735
876
fastq@1.17.1:
736
877
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
737
878
879
+
fdir@6.4.3:
880
+
resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
881
+
peerDependencies:
882
+
picomatch: ^3 || ^4
883
+
peerDependenciesMeta:
884
+
picomatch:
885
+
optional: true
886
+
738
887
file-entry-cache@8.0.0:
739
888
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
740
889
engines: {node: '>=16.0.0'}
···
743
892
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
744
893
engines: {node: '>=8'}
745
894
895
+
find-up-simple@1.0.1:
896
+
resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==}
897
+
engines: {node: '>=18'}
898
+
746
899
find-up@5.0.0:
747
900
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
748
901
engines: {node: '>=10'}
···
754
907
flatted@3.2.9:
755
908
resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
756
909
757
-
for-each@0.3.3:
758
-
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
910
+
for-each@0.3.5:
911
+
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
912
+
engines: {node: '>= 0.4'}
759
913
760
914
function-bind@1.1.2:
761
915
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
762
916
763
-
function.prototype.name@1.1.6:
764
-
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
917
+
function.prototype.name@1.1.8:
918
+
resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
765
919
engines: {node: '>= 0.4'}
766
920
767
921
functions-have-names@1.2.3:
768
922
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
769
923
770
-
get-intrinsic@1.2.4:
771
-
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
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==}
772
929
engines: {node: '>= 0.4'}
773
930
774
-
get-symbol-description@1.0.2:
775
-
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
931
+
get-proto@1.0.1:
932
+
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
933
+
engines: {node: '>= 0.4'}
934
+
935
+
get-symbol-description@1.1.0:
936
+
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
776
937
engines: {node: '>= 0.4'}
777
938
778
939
glob-parent@5.1.2:
···
791
952
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
792
953
engines: {node: '>= 0.4'}
793
954
794
-
gopd@1.0.1:
795
-
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
955
+
gopd@1.2.0:
956
+
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
957
+
engines: {node: '>= 0.4'}
796
958
797
959
graphemer@1.4.0:
798
960
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
799
961
800
-
has-bigints@1.0.2:
801
-
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'}
802
965
803
966
has-flag@4.0.0:
804
967
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
···
807
970
has-property-descriptors@1.0.2:
808
971
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
809
972
810
-
has-proto@1.0.3:
811
-
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
973
+
has-proto@1.2.0:
974
+
resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
812
975
engines: {node: '>= 0.4'}
813
976
814
-
has-symbols@1.0.3:
815
-
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
977
+
has-symbols@1.1.0:
978
+
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
816
979
engines: {node: '>= 0.4'}
817
980
818
981
has-tostringtag@1.0.2:
···
831
994
ieee754@1.2.1:
832
995
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
833
996
834
-
ignore@5.3.0:
835
-
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
836
-
engines: {node: '>= 4'}
837
-
838
997
ignore@5.3.2:
839
998
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
840
999
engines: {node: '>= 4'}
···
847
1006
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
848
1007
engines: {node: '>=0.8.19'}
849
1008
850
-
internal-slot@1.0.7:
851
-
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
1009
+
internal-slot@1.1.0:
1010
+
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
852
1011
engines: {node: '>= 0.4'}
853
1012
854
-
is-array-buffer@3.0.4:
855
-
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
1013
+
is-array-buffer@3.0.5:
1014
+
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
856
1015
engines: {node: '>= 0.4'}
857
1016
858
-
is-async-function@2.0.0:
859
-
resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
1017
+
is-async-function@2.1.1:
1018
+
resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
860
1019
engines: {node: '>= 0.4'}
861
1020
862
-
is-bigint@1.0.4:
863
-
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
1021
+
is-bigint@1.1.0:
1022
+
resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
1023
+
engines: {node: '>= 0.4'}
864
1024
865
-
is-boolean-object@1.1.2:
866
-
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
1025
+
is-boolean-object@1.2.2:
1026
+
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
867
1027
engines: {node: '>= 0.4'}
868
1028
869
1029
is-callable@1.2.7:
870
1030
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
871
1031
engines: {node: '>= 0.4'}
872
1032
873
-
is-core-module@2.15.1:
874
-
resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
1033
+
is-core-module@2.16.1:
1034
+
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
875
1035
engines: {node: '>= 0.4'}
876
1036
877
-
is-data-view@1.0.1:
878
-
resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
1037
+
is-data-view@1.0.2:
1038
+
resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
879
1039
engines: {node: '>= 0.4'}
880
1040
881
-
is-date-object@1.0.5:
882
-
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
1041
+
is-date-object@1.1.0:
1042
+
resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
883
1043
engines: {node: '>= 0.4'}
884
1044
885
1045
is-extglob@2.1.1:
886
1046
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
887
1047
engines: {node: '>=0.10.0'}
888
1048
889
-
is-finalizationregistry@1.0.2:
890
-
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'}
891
1052
892
-
is-generator-function@1.0.10:
893
-
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
1053
+
is-generator-function@1.1.0:
1054
+
resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
894
1055
engines: {node: '>= 0.4'}
895
1056
896
1057
is-glob@4.0.3:
···
901
1062
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
902
1063
engines: {node: '>= 0.4'}
903
1064
904
-
is-negative-zero@2.0.3:
905
-
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
906
-
engines: {node: '>= 0.4'}
907
-
908
-
is-number-object@1.0.7:
909
-
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
1065
+
is-number-object@1.1.1:
1066
+
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
910
1067
engines: {node: '>= 0.4'}
911
1068
912
1069
is-number@7.0.0:
913
1070
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
914
1071
engines: {node: '>=0.12.0'}
915
1072
916
-
is-regex@1.1.4:
917
-
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
1073
+
is-regex@1.2.1:
1074
+
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
918
1075
engines: {node: '>= 0.4'}
919
1076
920
1077
is-set@2.0.3:
921
1078
resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
922
1079
engines: {node: '>= 0.4'}
923
1080
924
-
is-shared-array-buffer@1.0.3:
925
-
resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
1081
+
is-shared-array-buffer@1.0.4:
1082
+
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
926
1083
engines: {node: '>= 0.4'}
927
1084
928
-
is-string@1.0.7:
929
-
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
1085
+
is-string@1.1.1:
1086
+
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
930
1087
engines: {node: '>= 0.4'}
931
1088
932
-
is-symbol@1.0.4:
933
-
resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
1089
+
is-symbol@1.1.1:
1090
+
resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
934
1091
engines: {node: '>= 0.4'}
935
1092
936
-
is-typed-array@1.1.13:
937
-
resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
1093
+
is-typed-array@1.1.15:
1094
+
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
938
1095
engines: {node: '>= 0.4'}
939
1096
940
1097
is-weakmap@2.0.2:
941
1098
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
942
1099
engines: {node: '>= 0.4'}
943
1100
944
-
is-weakref@1.0.2:
945
-
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
1101
+
is-weakref@1.1.1:
1102
+
resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
1103
+
engines: {node: '>= 0.4'}
946
1104
947
-
is-weakset@2.0.3:
948
-
resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==}
1105
+
is-weakset@2.0.4:
1106
+
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
949
1107
engines: {node: '>= 0.4'}
950
1108
951
1109
isarray@2.0.5:
···
954
1112
isexe@2.0.0:
955
1113
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
956
1114
957
-
iterator.prototype@1.1.3:
958
-
resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==}
1115
+
iterator.prototype@1.1.5:
1116
+
resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
959
1117
engines: {node: '>= 0.4'}
1118
+
1119
+
jiti@2.4.2:
1120
+
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
1121
+
hasBin: true
960
1122
961
1123
js-tokens@4.0.0:
962
1124
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
···
996
1158
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
997
1159
hasBin: true
998
1160
1161
+
math-intrinsics@1.1.0:
1162
+
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
1163
+
engines: {node: '>= 0.4'}
1164
+
999
1165
merge2@1.4.1:
1000
1166
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
1001
1167
engines: {node: '>= 8'}
···
1004
1170
resolution: {integrity: sha512-OyvYIOgpzXREySYJ1cqEb2pOKdeQMTfF9M8dRU6nC4hi/GXMmNpe9ssZCrSoTHazu05BSAoRBN/uYeco+ymfOg==}
1005
1171
engines: {node: '>=18.0.0'}
1006
1172
1173
+
microdiff@1.5.0:
1174
+
resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==}
1175
+
1007
1176
micromatch@4.0.8:
1008
1177
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
1009
1178
engines: {node: '>=8.6'}
1010
1179
1180
+
mimic-function@5.0.1:
1181
+
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
1182
+
engines: {node: '>=18'}
1183
+
1011
1184
minimatch@3.1.2:
1012
1185
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
1013
1186
···
1015
1188
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
1016
1189
engines: {node: '>=16 || 14 >=14.17'}
1017
1190
1018
-
ms@2.1.2:
1019
-
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
1191
+
ms@2.1.3:
1192
+
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1020
1193
1021
1194
nanotar@0.1.1:
1022
1195
resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==}
1023
1196
1024
1197
natural-compare@1.4.0:
1025
1198
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
1199
+
1200
+
node-fetch-native@1.6.6:
1201
+
resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==}
1026
1202
1027
1203
object-assign@4.1.1:
1028
1204
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
1029
1205
engines: {node: '>=0.10.0'}
1030
1206
1031
-
object-inspect@1.13.2:
1032
-
resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
1207
+
object-inspect@1.13.4:
1208
+
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
1033
1209
engines: {node: '>= 0.4'}
1034
1210
1035
1211
object-keys@1.1.1:
1036
1212
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
1037
1213
engines: {node: '>= 0.4'}
1038
1214
1039
-
object.assign@4.1.5:
1040
-
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
1215
+
object.assign@4.1.7:
1216
+
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
1041
1217
engines: {node: '>= 0.4'}
1042
1218
1043
-
object.entries@1.1.8:
1044
-
resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==}
1219
+
object.entries@1.1.9:
1220
+
resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
1045
1221
engines: {node: '>= 0.4'}
1046
1222
1047
1223
object.fromentries@2.0.8:
1048
1224
resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
1049
1225
engines: {node: '>= 0.4'}
1050
1226
1051
-
object.values@1.2.0:
1052
-
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
1227
+
object.values@1.2.1:
1228
+
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
1053
1229
engines: {node: '>= 0.4'}
1230
+
1231
+
ofetch@1.4.1:
1232
+
resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==}
1233
+
1234
+
onetime@7.0.0:
1235
+
resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
1236
+
engines: {node: '>=18'}
1054
1237
1055
1238
optionator@0.9.3:
1056
1239
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
1057
1240
engines: {node: '>= 0.8.0'}
1058
1241
1242
+
own-keys@1.0.1:
1243
+
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
1244
+
engines: {node: '>= 0.4'}
1245
+
1059
1246
p-limit@3.1.0:
1060
1247
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
1061
1248
engines: {node: '>=10'}
···
1063
1250
p-locate@5.0.0:
1064
1251
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
1065
1252
engines: {node: '>=10'}
1253
+
1254
+
package-manager-detector@1.1.0:
1255
+
resolution: {integrity: sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==}
1066
1256
1067
1257
parent-module@1.0.1:
1068
1258
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
···
1079
1269
path-parse@1.0.7:
1080
1270
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
1081
1271
1272
+
pathe@2.0.3:
1273
+
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
1274
+
1082
1275
picomatch@2.3.1:
1083
1276
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1084
1277
engines: {node: '>=8.6'}
1085
1278
1086
-
possible-typed-array-names@1.0.0:
1087
-
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
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==}
1088
1288
engines: {node: '>= 0.4'}
1089
1289
1090
1290
prelude-ls@1.2.1:
···
1111
1311
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
1112
1312
engines: {node: '>=6'}
1113
1313
1314
+
quansync@0.2.10:
1315
+
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
1316
+
1114
1317
queue-microtask@1.2.3:
1115
1318
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
1116
1319
···
1121
1324
resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==}
1122
1325
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1123
1326
1124
-
reflect.getprototypeof@1.0.6:
1125
-
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
1327
+
reflect.getprototypeof@1.0.10:
1328
+
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
1126
1329
engines: {node: '>= 0.4'}
1127
1330
1128
-
regexp.prototype.flags@1.5.3:
1129
-
resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==}
1331
+
regexp.prototype.flags@1.5.4:
1332
+
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
1130
1333
engines: {node: '>= 0.4'}
1131
1334
1132
1335
resolve-from@4.0.0:
···
1137
1340
resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
1138
1341
hasBin: true
1139
1342
1343
+
restore-cursor@5.1.0:
1344
+
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
1345
+
engines: {node: '>=18'}
1346
+
1140
1347
reusify@1.0.4:
1141
1348
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
1142
1349
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
···
1144
1351
run-parallel@1.2.0:
1145
1352
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
1146
1353
1147
-
safe-array-concat@1.1.2:
1148
-
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
1354
+
safe-array-concat@1.1.3:
1355
+
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
1149
1356
engines: {node: '>=0.4'}
1150
-
1151
-
safe-buffer@5.1.2:
1152
-
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
1153
1357
1154
1358
safe-buffer@5.2.1:
1155
1359
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
1156
1360
1157
-
safe-regex-test@1.0.3:
1158
-
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
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==}
1159
1367
engines: {node: '>= 0.4'}
1160
1368
1161
1369
semver@6.3.1:
1162
1370
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
1163
1371
hasBin: true
1164
1372
1165
-
semver@7.6.3:
1166
-
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
1373
+
semver@7.7.1:
1374
+
resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
1167
1375
engines: {node: '>=10'}
1168
1376
hasBin: true
1169
1377
···
1175
1383
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
1176
1384
engines: {node: '>= 0.4'}
1177
1385
1386
+
set-proto@1.0.0:
1387
+
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
1388
+
engines: {node: '>= 0.4'}
1389
+
1178
1390
shebang-command@2.0.0:
1179
1391
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
1180
1392
engines: {node: '>=8'}
···
1183
1395
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1184
1396
engines: {node: '>=8'}
1185
1397
1186
-
side-channel@1.0.6:
1187
-
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
1398
+
side-channel-list@1.0.0:
1399
+
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
1188
1400
engines: {node: '>= 0.4'}
1189
1401
1402
+
side-channel-map@1.0.1:
1403
+
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
1404
+
engines: {node: '>= 0.4'}
1405
+
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'}
1417
+
1190
1418
standalone-electron-types@1.0.0:
1191
1419
resolution: {integrity: sha512-0HOi/tlTz3mjWhsAz4uRbpQcHMZ+ifj1JzWW9nugykOHClBBG77ps8QinrzX1eow4Iw2pnC+RFaSYRgufF4BOg==}
1192
1420
1193
-
string.prototype.matchall@4.0.11:
1194
-
resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==}
1421
+
string.prototype.matchall@4.0.12:
1422
+
resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
1195
1423
engines: {node: '>= 0.4'}
1196
1424
1197
1425
string.prototype.repeat@1.0.0:
1198
1426
resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
1199
1427
1200
-
string.prototype.trim@1.2.9:
1201
-
resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
1428
+
string.prototype.trim@1.2.10:
1429
+
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
1202
1430
engines: {node: '>= 0.4'}
1203
1431
1204
-
string.prototype.trimend@1.0.8:
1205
-
resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
1432
+
string.prototype.trimend@1.0.9:
1433
+
resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
1434
+
engines: {node: '>= 0.4'}
1206
1435
1207
1436
string.prototype.trimstart@1.0.8:
1208
1437
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
···
1223
1452
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
1224
1453
engines: {node: '>= 0.4'}
1225
1454
1226
-
synckit@0.9.2:
1227
-
resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==}
1455
+
synckit@0.11.1:
1456
+
resolution: {integrity: sha512-fWZqNBZNNFp/7mTUy1fSsydhKsAKJ+u90Nk7kOK5Gcq9vObaqLBLjWFDBkyVU9Vvc6Y71VbOevMuGhqv02bT+Q==}
1228
1457
engines: {node: ^14.18.0 || >=16.0.0}
1229
1458
1230
-
text-table@0.2.0:
1231
-
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
1459
+
taze@19.0.4:
1460
+
resolution: {integrity: sha512-bviyNotzqcIWpVBCC4QYVb2yupzKyUDGQi2m/8GERdiPaudVMtgAqaE98+x0cDDaByYRMJCyhQWM04ikUL6+kQ==}
1461
+
hasBin: true
1462
+
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'}
1232
1469
1233
1470
to-regex-range@5.0.1:
1234
1471
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1235
1472
engines: {node: '>=8.0'}
1236
1473
1237
-
ts-api-utils@1.3.0:
1238
-
resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
1239
-
engines: {node: '>=16'}
1474
+
ts-api-utils@2.1.0:
1475
+
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
1476
+
engines: {node: '>=18.12'}
1240
1477
peerDependencies:
1241
-
typescript: '>=4.2.0'
1478
+
typescript: '>=4.8.4'
1242
1479
1243
-
tslib@2.7.0:
1244
-
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
1480
+
tslib@2.8.1:
1481
+
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1245
1482
1246
1483
type-check@0.4.0:
1247
1484
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
1248
1485
engines: {node: '>= 0.8.0'}
1249
1486
1250
-
typed-array-buffer@1.0.2:
1251
-
resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
1487
+
typed-array-buffer@1.0.3:
1488
+
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
1252
1489
engines: {node: '>= 0.4'}
1253
1490
1254
-
typed-array-byte-length@1.0.1:
1255
-
resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
1491
+
typed-array-byte-length@1.0.3:
1492
+
resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
1256
1493
engines: {node: '>= 0.4'}
1257
1494
1258
-
typed-array-byte-offset@1.0.2:
1259
-
resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
1495
+
typed-array-byte-offset@1.0.4:
1496
+
resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
1260
1497
engines: {node: '>= 0.4'}
1261
1498
1262
-
typed-array-length@1.0.6:
1263
-
resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
1499
+
typed-array-length@1.0.7:
1500
+
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
1264
1501
engines: {node: '>= 0.4'}
1265
1502
1266
-
typescript-eslint@8.8.1:
1267
-
resolution: {integrity: sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==}
1503
+
typescript-eslint@8.29.0:
1504
+
resolution: {integrity: sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg==}
1268
1505
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1269
1506
peerDependencies:
1270
-
typescript: '*'
1271
-
peerDependenciesMeta:
1272
-
typescript:
1273
-
optional: true
1507
+
eslint: ^8.57.0 || ^9.0.0
1508
+
typescript: '>=4.8.4 <5.9.0'
1274
1509
1275
-
typescript@5.3.2:
1276
-
resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
1510
+
typescript@5.8.2:
1511
+
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
1277
1512
engines: {node: '>=14.17'}
1278
1513
hasBin: true
1279
1514
1280
-
unbox-primitive@1.0.2:
1281
-
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
1515
+
ufo@1.5.4:
1516
+
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
1282
1517
1283
-
undici-types@6.19.8:
1284
-
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
1518
+
unbox-primitive@1.1.0:
1519
+
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
1520
+
engines: {node: '>= 0.4'}
1521
+
1522
+
unconfig@7.3.1:
1523
+
resolution: {integrity: sha512-LH5WL+un92tGAzWS87k7LkAfwpMdm7V0IXG2FxEjZz/QxiIW5J5LkcrKQThj0aRz6+h/lFmKI9EUXmK/T0bcrw==}
1524
+
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==}
1285
1530
1286
1531
uri-js@4.4.1:
1287
1532
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
1288
1533
1289
-
utilium@0.7.1:
1290
-
resolution: {integrity: sha512-2ocvTkI7U8LERmwxL0LhFUvEfN66UqcjF6tMiURvUwSyU7U1QC9gST+3iSUSiGccFfnP3f2EXwHNXOnOzx+lAg==}
1534
+
utilium@1.10.1:
1535
+
resolution: {integrity: sha512-GQINDTb/ocyz4acQj3GXAe0wipYxws6L+9ouqaq10KlInTk9DGvW9TJd0pYa/Xu3cppNnZuB4T/sBuSXpcN2ng==}
1291
1536
1292
-
which-boxed-primitive@1.0.2:
1293
-
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
1537
+
which-boxed-primitive@1.1.1:
1538
+
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
1539
+
engines: {node: '>= 0.4'}
1294
1540
1295
-
which-builtin-type@1.1.4:
1296
-
resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==}
1541
+
which-builtin-type@1.2.1:
1542
+
resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
1297
1543
engines: {node: '>= 0.4'}
1298
1544
1299
1545
which-collection@1.0.2:
1300
1546
resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
1301
1547
engines: {node: '>= 0.4'}
1302
1548
1303
-
which-typed-array@1.1.15:
1304
-
resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
1549
+
which-typed-array@1.1.19:
1550
+
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
1305
1551
engines: {node: '>= 0.4'}
1306
1552
1307
1553
which@2.0.2:
···
1309
1555
engines: {node: '>= 8'}
1310
1556
hasBin: true
1311
1557
1558
+
yaml@2.7.1:
1559
+
resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
1560
+
engines: {node: '>= 14'}
1561
+
hasBin: true
1562
+
1312
1563
yocto-queue@0.1.0:
1313
1564
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
1314
1565
engines: {node: '>=10'}
1315
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
+
1316
1585
snapshots:
1317
1586
1318
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
1319
1595
1320
1596
'@esbuild/android-arm64@0.19.3':
1321
1597
optional: true
···
1383
1659
'@esbuild/win32-x64@0.19.3':
1384
1660
optional: true
1385
1661
1386
-
'@eslint-community/eslint-utils@4.4.0(eslint@9.12.0)':
1662
+
'@eslint-community/eslint-utils@4.5.1(eslint@9.23.0(jiti@2.4.2))':
1387
1663
dependencies:
1388
-
eslint: 9.12.0
1664
+
eslint: 9.23.0(jiti@2.4.2)
1389
1665
eslint-visitor-keys: 3.4.3
1390
1666
1391
-
'@eslint-community/regexpp@4.11.1': {}
1667
+
'@eslint-community/regexpp@4.12.1': {}
1392
1668
1393
-
'@eslint/config-array@0.18.0':
1669
+
'@eslint/config-array@0.19.2':
1394
1670
dependencies:
1395
-
'@eslint/object-schema': 2.1.4
1396
-
debug: 4.3.4
1671
+
'@eslint/object-schema': 2.1.6
1672
+
debug: 4.4.0
1397
1673
minimatch: 3.1.2
1398
1674
transitivePeerDependencies:
1399
1675
- supports-color
1400
1676
1401
-
'@eslint/core@0.6.0': {}
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
1402
1686
1403
-
'@eslint/eslintrc@3.1.0':
1687
+
'@eslint/eslintrc@3.3.1':
1404
1688
dependencies:
1405
1689
ajv: 6.12.6
1406
-
debug: 4.3.4
1407
-
espree: 10.2.0
1690
+
debug: 4.4.0
1691
+
espree: 10.3.0
1408
1692
globals: 14.0.0
1409
-
ignore: 5.3.0
1693
+
ignore: 5.3.2
1410
1694
import-fresh: 3.3.0
1411
1695
js-yaml: 4.1.0
1412
1696
minimatch: 3.1.2
···
1414
1698
transitivePeerDependencies:
1415
1699
- supports-color
1416
1700
1417
-
'@eslint/js@9.12.0': {}
1701
+
'@eslint/js@9.23.0': {}
1418
1702
1419
-
'@eslint/object-schema@2.1.4': {}
1703
+
'@eslint/object-schema@2.1.6': {}
1420
1704
1421
-
'@eslint/plugin-kit@0.2.0':
1705
+
'@eslint/plugin-kit@0.2.8':
1422
1706
dependencies:
1707
+
'@eslint/core': 0.13.0
1423
1708
levn: 0.4.1
1424
1709
1425
-
'@humanfs/core@0.19.0': {}
1710
+
'@humanfs/core@0.19.1': {}
1426
1711
1427
-
'@humanfs/node@0.16.5':
1712
+
'@humanfs/node@0.16.6':
1428
1713
dependencies:
1429
-
'@humanfs/core': 0.19.0
1714
+
'@humanfs/core': 0.19.1
1430
1715
'@humanwhocodes/retry': 0.3.1
1431
1716
1432
1717
'@humanwhocodes/module-importer@1.0.1': {}
1433
1718
1434
1719
'@humanwhocodes/retry@0.3.1': {}
1435
1720
1436
-
'@moonlight-mod/eslint-config@https://codeload.github.com/moonlight-mod/eslint-config/tar.gz/7eb7bd7c51fe0e3ee9d2a0baf149212d2bb893af(eslint@9.12.0)(prettier@3.1.0)(typescript@5.3.2)':
1721
+
'@humanwhocodes/retry@0.4.2': {}
1722
+
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)':
1437
1724
dependencies:
1438
-
'@eslint/js': 9.12.0
1439
-
eslint: 9.12.0
1440
-
eslint-config-prettier: 9.1.0(eslint@9.12.0)
1441
-
eslint-plugin-prettier: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.12.0))(eslint@9.12.0)(prettier@3.1.0)
1442
-
eslint-plugin-react: 7.37.1(eslint@9.12.0)
1443
-
typescript: 5.3.2
1444
-
typescript-eslint: 8.8.1(eslint@9.12.0)(typescript@5.3.2)
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)
1445
1732
transitivePeerDependencies:
1446
1733
- '@types/eslint'
1447
1734
- prettier
1448
1735
- supports-color
1449
1736
1450
-
'@moonlight-mod/lunast@1.0.0':
1737
+
'@moonlight-mod/lunast@1.0.1':
1451
1738
dependencies:
1452
1739
astring: 1.9.0
1453
1740
estree-toolkit: 1.7.8
1454
1741
meriyah: 6.0.1
1455
1742
1456
-
'@moonlight-mod/mappings@1.0.10(@moonlight-mod/lunast@1.0.0)(@moonlight-mod/moonmap@1.0.3)':
1743
+
'@moonlight-mod/mappings@1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)':
1457
1744
dependencies:
1458
-
'@moonlight-mod/lunast': 1.0.0
1459
-
'@moonlight-mod/moonmap': 1.0.3
1745
+
'@moonlight-mod/lunast': 1.0.1
1746
+
'@moonlight-mod/moonmap': 1.0.5
1747
+
'@types/chroma-js': 3.1.0
1460
1748
'@types/flux': 3.1.14
1461
-
'@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
1462
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
1463
1759
1464
-
'@moonlight-mod/moonmap@1.0.3': {}
1760
+
'@moonlight-mod/moonmap@1.0.5': {}
1465
1761
1466
1762
'@nodelib/fs.scandir@2.1.5':
1467
1763
dependencies:
···
1475
1771
'@nodelib/fs.scandir': 2.1.5
1476
1772
fastq: 1.17.1
1477
1773
1478
-
'@pkgr/core@0.1.1': {}
1774
+
'@pkgr/core@0.2.0': {}
1775
+
1776
+
'@quansync/fs@0.1.2':
1777
+
dependencies:
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
1479
1792
1480
1793
'@types/estree-jsx@1.0.5':
1481
1794
dependencies:
···
1483
1796
1484
1797
'@types/estree@1.0.6': {}
1485
1798
1799
+
'@types/estree@1.0.7':
1800
+
optional: true
1801
+
1486
1802
'@types/fbemitter@2.0.35': {}
1487
1803
1804
+
'@types/filesystem@0.0.36':
1805
+
dependencies:
1806
+
'@types/filewriter': 0.0.33
1807
+
1808
+
'@types/filewriter@0.0.33': {}
1809
+
1488
1810
'@types/flux@3.1.14':
1489
1811
dependencies:
1490
1812
'@types/fbemitter': 2.0.35
1491
-
'@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': {}
1492
1818
1493
1819
'@types/json-schema@7.0.15': {}
1494
1820
1821
+
'@types/lodash@4.17.14': {}
1822
+
1495
1823
'@types/node@18.17.17': {}
1496
1824
1497
-
'@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':
1498
1830
dependencies:
1499
-
undici-types: 6.19.8
1831
+
undici-types: 6.21.0
1832
+
1833
+
'@types/platform@1.3.6': {}
1500
1834
1501
1835
'@types/prop-types@15.7.13': {}
1502
1836
1503
-
'@types/react@18.3.10':
1837
+
'@types/react@18.3.20':
1504
1838
dependencies:
1505
1839
'@types/prop-types': 15.7.13
1506
1840
csstype: 3.1.3
1507
1841
1508
-
'@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)':
1509
1843
dependencies:
1510
-
'@types/node': 20.16.10
1511
-
safe-buffer: 5.1.2
1512
-
1513
-
'@typescript-eslint/eslint-plugin@8.8.1(@typescript-eslint/parser@8.8.1(eslint@9.12.0)(typescript@5.3.2))(eslint@9.12.0)(typescript@5.3.2)':
1514
-
dependencies:
1515
-
'@eslint-community/regexpp': 4.11.1
1516
-
'@typescript-eslint/parser': 8.8.1(eslint@9.12.0)(typescript@5.3.2)
1517
-
'@typescript-eslint/scope-manager': 8.8.1
1518
-
'@typescript-eslint/type-utils': 8.8.1(eslint@9.12.0)(typescript@5.3.2)
1519
-
'@typescript-eslint/utils': 8.8.1(eslint@9.12.0)(typescript@5.3.2)
1520
-
'@typescript-eslint/visitor-keys': 8.8.1
1521
-
eslint: 9.12.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)
1522
1851
graphemer: 1.4.0
1523
1852
ignore: 5.3.2
1524
1853
natural-compare: 1.4.0
1525
-
ts-api-utils: 1.3.0(typescript@5.3.2)
1526
-
optionalDependencies:
1527
-
typescript: 5.3.2
1854
+
ts-api-utils: 2.1.0(typescript@5.8.2)
1855
+
typescript: 5.8.2
1528
1856
transitivePeerDependencies:
1529
1857
- supports-color
1530
1858
1531
-
'@typescript-eslint/parser@8.8.1(eslint@9.12.0)(typescript@5.3.2)':
1859
+
'@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
1532
1860
dependencies:
1533
-
'@typescript-eslint/scope-manager': 8.8.1
1534
-
'@typescript-eslint/types': 8.8.1
1535
-
'@typescript-eslint/typescript-estree': 8.8.1(typescript@5.3.2)
1536
-
'@typescript-eslint/visitor-keys': 8.8.1
1537
-
debug: 4.3.4
1538
-
eslint: 9.12.0
1539
-
optionalDependencies:
1540
-
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
1541
1868
transitivePeerDependencies:
1542
1869
- supports-color
1543
1870
1544
-
'@typescript-eslint/scope-manager@8.8.1':
1871
+
'@typescript-eslint/scope-manager@8.29.0':
1545
1872
dependencies:
1546
-
'@typescript-eslint/types': 8.8.1
1547
-
'@typescript-eslint/visitor-keys': 8.8.1
1873
+
'@typescript-eslint/types': 8.29.0
1874
+
'@typescript-eslint/visitor-keys': 8.29.0
1548
1875
1549
-
'@typescript-eslint/type-utils@8.8.1(eslint@9.12.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)':
1550
1877
dependencies:
1551
-
'@typescript-eslint/typescript-estree': 8.8.1(typescript@5.3.2)
1552
-
'@typescript-eslint/utils': 8.8.1(eslint@9.12.0)(typescript@5.3.2)
1553
-
debug: 4.3.4
1554
-
ts-api-utils: 1.3.0(typescript@5.3.2)
1555
-
optionalDependencies:
1556
-
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
1557
1884
transitivePeerDependencies:
1558
-
- eslint
1559
1885
- supports-color
1560
1886
1561
-
'@typescript-eslint/types@8.8.1': {}
1887
+
'@typescript-eslint/types@8.29.0': {}
1562
1888
1563
-
'@typescript-eslint/typescript-estree@8.8.1(typescript@5.3.2)':
1889
+
'@typescript-eslint/typescript-estree@8.29.0(typescript@5.8.2)':
1564
1890
dependencies:
1565
-
'@typescript-eslint/types': 8.8.1
1566
-
'@typescript-eslint/visitor-keys': 8.8.1
1567
-
debug: 4.3.4
1891
+
'@typescript-eslint/types': 8.29.0
1892
+
'@typescript-eslint/visitor-keys': 8.29.0
1893
+
debug: 4.4.0
1568
1894
fast-glob: 3.3.2
1569
1895
is-glob: 4.0.3
1570
1896
minimatch: 9.0.5
1571
-
semver: 7.6.3
1572
-
ts-api-utils: 1.3.0(typescript@5.3.2)
1573
-
optionalDependencies:
1574
-
typescript: 5.3.2
1897
+
semver: 7.7.1
1898
+
ts-api-utils: 2.1.0(typescript@5.8.2)
1899
+
typescript: 5.8.2
1575
1900
transitivePeerDependencies:
1576
1901
- supports-color
1577
1902
1578
-
'@typescript-eslint/utils@8.8.1(eslint@9.12.0)(typescript@5.3.2)':
1903
+
'@typescript-eslint/utils@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
1579
1904
dependencies:
1580
-
'@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0)
1581
-
'@typescript-eslint/scope-manager': 8.8.1
1582
-
'@typescript-eslint/types': 8.8.1
1583
-
'@typescript-eslint/typescript-estree': 8.8.1(typescript@5.3.2)
1584
-
eslint: 9.12.0
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
1585
1911
transitivePeerDependencies:
1586
1912
- supports-color
1587
-
- typescript
1588
1913
1589
-
'@typescript-eslint/visitor-keys@8.8.1':
1914
+
'@typescript-eslint/visitor-keys@8.29.0':
1590
1915
dependencies:
1591
-
'@typescript-eslint/types': 8.8.1
1592
-
eslint-visitor-keys: 3.4.3
1916
+
'@typescript-eslint/types': 8.29.0
1917
+
eslint-visitor-keys: 4.2.0
1593
1918
1594
-
'@zenfs/core@1.0.2':
1919
+
'@xterm/xterm@5.5.0':
1920
+
optional: true
1921
+
1922
+
'@zenfs/core@2.0.0':
1595
1923
dependencies:
1596
-
'@types/node': 20.16.10
1597
-
'@types/readable-stream': 4.0.15
1924
+
'@types/node': 22.13.6
1598
1925
buffer: 6.0.3
1599
1926
eventemitter3: 5.0.1
1600
-
minimatch: 9.0.5
1601
1927
readable-stream: 4.5.2
1602
-
utilium: 0.7.1
1928
+
utilium: 1.10.1
1603
1929
1604
-
'@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)':
1605
1931
dependencies:
1606
-
'@zenfs/core': 1.0.2
1932
+
'@zenfs/core': 2.0.0
1933
+
utilium: 1.10.1
1607
1934
1608
1935
abort-controller@3.0.0:
1609
1936
dependencies:
1610
1937
event-target-shim: 5.0.1
1611
1938
1612
-
acorn-jsx@5.3.2(acorn@8.12.1):
1939
+
acorn-jsx@5.3.2(acorn@8.14.1):
1613
1940
dependencies:
1614
-
acorn: 8.12.1
1941
+
acorn: 8.14.1
1615
1942
1616
-
acorn@8.12.1: {}
1943
+
acorn@8.14.1: {}
1617
1944
1618
1945
ajv@6.12.6:
1619
1946
dependencies:
···
1626
1953
dependencies:
1627
1954
color-convert: 2.0.1
1628
1955
1956
+
ansis@3.17.0: {}
1957
+
1629
1958
argparse@2.0.1: {}
1630
1959
1631
-
array-buffer-byte-length@1.0.1:
1960
+
array-buffer-byte-length@1.0.2:
1632
1961
dependencies:
1633
-
call-bind: 1.0.7
1634
-
is-array-buffer: 3.0.4
1962
+
call-bound: 1.0.4
1963
+
is-array-buffer: 3.0.5
1635
1964
1636
1965
array-includes@3.1.8:
1637
1966
dependencies:
1638
-
call-bind: 1.0.7
1967
+
call-bind: 1.0.8
1639
1968
define-properties: 1.2.1
1640
-
es-abstract: 1.23.3
1641
-
es-object-atoms: 1.0.0
1642
-
get-intrinsic: 1.2.4
1643
-
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
1644
1973
1645
1974
array.prototype.findlast@1.2.5:
1646
1975
dependencies:
1647
-
call-bind: 1.0.7
1976
+
call-bind: 1.0.8
1648
1977
define-properties: 1.2.1
1649
-
es-abstract: 1.23.3
1978
+
es-abstract: 1.23.9
1650
1979
es-errors: 1.3.0
1651
-
es-object-atoms: 1.0.0
1652
-
es-shim-unscopables: 1.0.2
1980
+
es-object-atoms: 1.1.1
1981
+
es-shim-unscopables: 1.1.0
1653
1982
1654
-
array.prototype.flat@1.3.2:
1983
+
array.prototype.flat@1.3.3:
1655
1984
dependencies:
1656
-
call-bind: 1.0.7
1985
+
call-bind: 1.0.8
1657
1986
define-properties: 1.2.1
1658
-
es-abstract: 1.23.3
1659
-
es-shim-unscopables: 1.0.2
1987
+
es-abstract: 1.23.9
1988
+
es-shim-unscopables: 1.1.0
1660
1989
1661
-
array.prototype.flatmap@1.3.2:
1990
+
array.prototype.flatmap@1.3.3:
1662
1991
dependencies:
1663
-
call-bind: 1.0.7
1992
+
call-bind: 1.0.8
1664
1993
define-properties: 1.2.1
1665
-
es-abstract: 1.23.3
1666
-
es-shim-unscopables: 1.0.2
1994
+
es-abstract: 1.23.9
1995
+
es-shim-unscopables: 1.1.0
1667
1996
1668
1997
array.prototype.tosorted@1.1.4:
1669
1998
dependencies:
1670
-
call-bind: 1.0.7
1999
+
call-bind: 1.0.8
1671
2000
define-properties: 1.2.1
1672
-
es-abstract: 1.23.3
2001
+
es-abstract: 1.23.9
1673
2002
es-errors: 1.3.0
1674
-
es-shim-unscopables: 1.0.2
2003
+
es-shim-unscopables: 1.1.0
1675
2004
1676
-
arraybuffer.prototype.slice@1.0.3:
2005
+
arraybuffer.prototype.slice@1.0.4:
1677
2006
dependencies:
1678
-
array-buffer-byte-length: 1.0.1
1679
-
call-bind: 1.0.7
2007
+
array-buffer-byte-length: 1.0.2
2008
+
call-bind: 1.0.8
1680
2009
define-properties: 1.2.1
1681
-
es-abstract: 1.23.3
2010
+
es-abstract: 1.23.9
1682
2011
es-errors: 1.3.0
1683
-
get-intrinsic: 1.2.4
1684
-
is-array-buffer: 3.0.4
1685
-
is-shared-array-buffer: 1.0.3
2012
+
get-intrinsic: 1.3.0
2013
+
is-array-buffer: 3.0.5
1686
2014
1687
2015
astring@1.9.0: {}
1688
2016
2017
+
async-function@1.0.0: {}
2018
+
1689
2019
available-typed-arrays@1.0.7:
1690
2020
dependencies:
1691
-
possible-typed-array-names: 1.0.0
2021
+
possible-typed-array-names: 1.1.0
1692
2022
1693
2023
balanced-match@1.0.2: {}
1694
2024
···
1712
2042
base64-js: 1.5.1
1713
2043
ieee754: 1.2.1
1714
2044
1715
-
call-bind@1.0.7:
2045
+
cac@6.7.14: {}
2046
+
2047
+
call-bind-apply-helpers@1.0.2:
1716
2048
dependencies:
1717
-
es-define-property: 1.0.0
1718
2049
es-errors: 1.3.0
1719
2050
function-bind: 1.1.2
1720
-
get-intrinsic: 1.2.4
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
1721
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
1722
2063
1723
2064
callsites@3.1.0: {}
1724
2065
···
1735
2076
1736
2077
concat-map@0.0.1: {}
1737
2078
1738
-
cross-spawn@7.0.3:
2079
+
cross-spawn@7.0.6:
1739
2080
dependencies:
1740
2081
path-key: 3.1.1
1741
2082
shebang-command: 2.0.0
1742
2083
which: 2.0.2
1743
2084
1744
-
csstype@3.1.2: {}
1745
-
1746
2085
csstype@3.1.3: {}
1747
2086
1748
-
data-view-buffer@1.0.1:
2087
+
data-view-buffer@1.0.2:
1749
2088
dependencies:
1750
-
call-bind: 1.0.7
2089
+
call-bound: 1.0.4
1751
2090
es-errors: 1.3.0
1752
-
is-data-view: 1.0.1
2091
+
is-data-view: 1.0.2
1753
2092
1754
-
data-view-byte-length@1.0.1:
2093
+
data-view-byte-length@1.0.2:
1755
2094
dependencies:
1756
-
call-bind: 1.0.7
2095
+
call-bound: 1.0.4
1757
2096
es-errors: 1.3.0
1758
-
is-data-view: 1.0.1
2097
+
is-data-view: 1.0.2
1759
2098
1760
-
data-view-byte-offset@1.0.0:
2099
+
data-view-byte-offset@1.0.1:
1761
2100
dependencies:
1762
-
call-bind: 1.0.7
2101
+
call-bound: 1.0.4
1763
2102
es-errors: 1.3.0
1764
-
is-data-view: 1.0.1
2103
+
is-data-view: 1.0.2
1765
2104
1766
-
debug@4.3.4:
2105
+
debug@4.4.0:
1767
2106
dependencies:
1768
-
ms: 2.1.2
2107
+
ms: 2.1.3
1769
2108
1770
2109
deep-is@0.1.4: {}
1771
2110
1772
2111
define-data-property@1.1.4:
1773
2112
dependencies:
1774
-
es-define-property: 1.0.0
2113
+
es-define-property: 1.0.1
1775
2114
es-errors: 1.3.0
1776
-
gopd: 1.0.1
2115
+
gopd: 1.2.0
1777
2116
1778
2117
define-properties@1.2.1:
1779
2118
dependencies:
···
1781
2120
has-property-descriptors: 1.0.2
1782
2121
object-keys: 1.1.1
1783
2122
2123
+
defu@6.1.4: {}
2124
+
2125
+
destr@2.0.4: {}
2126
+
1784
2127
doctrine@2.1.0:
1785
2128
dependencies:
1786
2129
esutils: 2.0.3
1787
2130
1788
-
es-abstract@1.23.3:
2131
+
dunder-proto@1.0.1:
1789
2132
dependencies:
1790
-
array-buffer-byte-length: 1.0.1
1791
-
arraybuffer.prototype.slice: 1.0.3
2133
+
call-bind-apply-helpers: 1.0.2
2134
+
es-errors: 1.3.0
2135
+
gopd: 1.2.0
2136
+
2137
+
es-abstract@1.23.9:
2138
+
dependencies:
2139
+
array-buffer-byte-length: 1.0.2
2140
+
arraybuffer.prototype.slice: 1.0.4
1792
2141
available-typed-arrays: 1.0.7
1793
-
call-bind: 1.0.7
1794
-
data-view-buffer: 1.0.1
1795
-
data-view-byte-length: 1.0.1
1796
-
data-view-byte-offset: 1.0.0
1797
-
es-define-property: 1.0.0
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
1798
2148
es-errors: 1.3.0
1799
-
es-object-atoms: 1.0.0
1800
-
es-set-tostringtag: 2.0.3
1801
-
es-to-primitive: 1.2.1
1802
-
function.prototype.name: 1.1.6
1803
-
get-intrinsic: 1.2.4
1804
-
get-symbol-description: 1.0.2
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
1805
2156
globalthis: 1.0.4
1806
-
gopd: 1.0.1
2157
+
gopd: 1.2.0
1807
2158
has-property-descriptors: 1.0.2
1808
-
has-proto: 1.0.3
1809
-
has-symbols: 1.0.3
2159
+
has-proto: 1.2.0
2160
+
has-symbols: 1.1.0
1810
2161
hasown: 2.0.2
1811
-
internal-slot: 1.0.7
1812
-
is-array-buffer: 3.0.4
2162
+
internal-slot: 1.1.0
2163
+
is-array-buffer: 3.0.5
1813
2164
is-callable: 1.2.7
1814
-
is-data-view: 1.0.1
1815
-
is-negative-zero: 2.0.3
1816
-
is-regex: 1.1.4
1817
-
is-shared-array-buffer: 1.0.3
1818
-
is-string: 1.0.7
1819
-
is-typed-array: 1.1.13
1820
-
is-weakref: 1.0.2
1821
-
object-inspect: 1.13.2
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
1822
2173
object-keys: 1.1.1
1823
-
object.assign: 4.1.5
1824
-
regexp.prototype.flags: 1.5.3
1825
-
safe-array-concat: 1.1.2
1826
-
safe-regex-test: 1.0.3
1827
-
string.prototype.trim: 1.2.9
1828
-
string.prototype.trimend: 1.0.8
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
1829
2183
string.prototype.trimstart: 1.0.8
1830
-
typed-array-buffer: 1.0.2
1831
-
typed-array-byte-length: 1.0.1
1832
-
typed-array-byte-offset: 1.0.2
1833
-
typed-array-length: 1.0.6
1834
-
unbox-primitive: 1.0.2
1835
-
which-typed-array: 1.1.15
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
1836
2190
1837
-
es-define-property@1.0.0:
1838
-
dependencies:
1839
-
get-intrinsic: 1.2.4
2191
+
es-define-property@1.0.1: {}
1840
2192
1841
2193
es-errors@1.3.0: {}
1842
2194
1843
-
es-iterator-helpers@1.1.0:
2195
+
es-iterator-helpers@1.2.1:
1844
2196
dependencies:
1845
-
call-bind: 1.0.7
2197
+
call-bind: 1.0.8
2198
+
call-bound: 1.0.4
1846
2199
define-properties: 1.2.1
1847
-
es-abstract: 1.23.3
2200
+
es-abstract: 1.23.9
1848
2201
es-errors: 1.3.0
1849
-
es-set-tostringtag: 2.0.3
2202
+
es-set-tostringtag: 2.1.0
1850
2203
function-bind: 1.1.2
1851
-
get-intrinsic: 1.2.4
2204
+
get-intrinsic: 1.3.0
1852
2205
globalthis: 1.0.4
2206
+
gopd: 1.2.0
1853
2207
has-property-descriptors: 1.0.2
1854
-
has-proto: 1.0.3
1855
-
has-symbols: 1.0.3
1856
-
internal-slot: 1.0.7
1857
-
iterator.prototype: 1.1.3
1858
-
safe-array-concat: 1.1.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
1859
2213
1860
-
es-object-atoms@1.0.0:
2214
+
es-object-atoms@1.1.1:
1861
2215
dependencies:
1862
2216
es-errors: 1.3.0
1863
2217
1864
-
es-set-tostringtag@2.0.3:
2218
+
es-set-tostringtag@2.1.0:
1865
2219
dependencies:
1866
-
get-intrinsic: 1.2.4
2220
+
es-errors: 1.3.0
2221
+
get-intrinsic: 1.3.0
1867
2222
has-tostringtag: 1.0.2
1868
2223
hasown: 2.0.2
1869
2224
1870
-
es-shim-unscopables@1.0.2:
2225
+
es-shim-unscopables@1.1.0:
1871
2226
dependencies:
1872
2227
hasown: 2.0.2
1873
2228
1874
-
es-to-primitive@1.2.1:
2229
+
es-to-primitive@1.3.0:
1875
2230
dependencies:
1876
2231
is-callable: 1.2.7
1877
-
is-date-object: 1.0.5
1878
-
is-symbol: 1.0.4
2232
+
is-date-object: 1.1.0
2233
+
is-symbol: 1.1.1
1879
2234
1880
2235
esbuild-copy-static-files@0.1.0: {}
1881
2236
···
1906
2261
1907
2262
escape-string-regexp@4.0.0: {}
1908
2263
1909
-
eslint-config-prettier@9.1.0(eslint@9.12.0):
2264
+
eslint-config-prettier@9.1.0(eslint@9.23.0(jiti@2.4.2)):
1910
2265
dependencies:
1911
-
eslint: 9.12.0
2266
+
eslint: 9.23.0(jiti@2.4.2)
1912
2267
1913
-
eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.12.0))(eslint@9.12.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):
1914
2269
dependencies:
1915
-
eslint: 9.12.0
2270
+
eslint: 9.23.0(jiti@2.4.2)
1916
2271
prettier: 3.1.0
1917
2272
prettier-linter-helpers: 1.0.0
1918
-
synckit: 0.9.2
2273
+
synckit: 0.11.1
1919
2274
optionalDependencies:
1920
-
eslint-config-prettier: 9.1.0(eslint@9.12.0)
2275
+
'@types/eslint': 9.6.1
2276
+
eslint-config-prettier: 9.1.0(eslint@9.23.0(jiti@2.4.2))
1921
2277
1922
-
eslint-plugin-react@7.37.1(eslint@9.12.0):
2278
+
eslint-plugin-react@7.37.5(eslint@9.23.0(jiti@2.4.2)):
1923
2279
dependencies:
1924
2280
array-includes: 3.1.8
1925
2281
array.prototype.findlast: 1.2.5
1926
-
array.prototype.flatmap: 1.3.2
2282
+
array.prototype.flatmap: 1.3.3
1927
2283
array.prototype.tosorted: 1.1.4
1928
2284
doctrine: 2.1.0
1929
-
es-iterator-helpers: 1.1.0
1930
-
eslint: 9.12.0
2285
+
es-iterator-helpers: 1.2.1
2286
+
eslint: 9.23.0(jiti@2.4.2)
1931
2287
estraverse: 5.3.0
1932
2288
hasown: 2.0.2
1933
2289
jsx-ast-utils: 3.3.5
1934
2290
minimatch: 3.1.2
1935
-
object.entries: 1.1.8
2291
+
object.entries: 1.1.9
1936
2292
object.fromentries: 2.0.8
1937
-
object.values: 1.2.0
2293
+
object.values: 1.2.1
1938
2294
prop-types: 15.8.1
1939
2295
resolve: 2.0.0-next.5
1940
2296
semver: 6.3.1
1941
-
string.prototype.matchall: 4.0.11
2297
+
string.prototype.matchall: 4.0.12
1942
2298
string.prototype.repeat: 1.0.0
1943
2299
1944
-
eslint-scope@8.1.0:
2300
+
eslint-scope@8.3.0:
1945
2301
dependencies:
1946
2302
esrecurse: 4.3.0
1947
2303
estraverse: 5.3.0
1948
2304
1949
2305
eslint-visitor-keys@3.4.3: {}
1950
2306
1951
-
eslint-visitor-keys@4.1.0: {}
2307
+
eslint-visitor-keys@4.2.0: {}
1952
2308
1953
-
eslint@9.12.0:
2309
+
eslint@9.23.0(jiti@2.4.2):
1954
2310
dependencies:
1955
-
'@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0)
1956
-
'@eslint-community/regexpp': 4.11.1
1957
-
'@eslint/config-array': 0.18.0
1958
-
'@eslint/core': 0.6.0
1959
-
'@eslint/eslintrc': 3.1.0
1960
-
'@eslint/js': 9.12.0
1961
-
'@eslint/plugin-kit': 0.2.0
1962
-
'@humanfs/node': 0.16.5
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
1963
2320
'@humanwhocodes/module-importer': 1.0.1
1964
-
'@humanwhocodes/retry': 0.3.1
2321
+
'@humanwhocodes/retry': 0.4.2
1965
2322
'@types/estree': 1.0.6
1966
2323
'@types/json-schema': 7.0.15
1967
2324
ajv: 6.12.6
1968
2325
chalk: 4.1.2
1969
-
cross-spawn: 7.0.3
1970
-
debug: 4.3.4
2326
+
cross-spawn: 7.0.6
2327
+
debug: 4.4.0
1971
2328
escape-string-regexp: 4.0.0
1972
-
eslint-scope: 8.1.0
1973
-
eslint-visitor-keys: 4.1.0
1974
-
espree: 10.2.0
1975
-
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
1976
2333
esutils: 2.0.3
1977
2334
fast-deep-equal: 3.1.3
1978
2335
file-entry-cache: 8.0.0
1979
2336
find-up: 5.0.0
1980
2337
glob-parent: 6.0.2
1981
-
ignore: 5.3.0
2338
+
ignore: 5.3.2
1982
2339
imurmurhash: 0.1.4
1983
2340
is-glob: 4.0.3
1984
2341
json-stable-stringify-without-jsonify: 1.0.1
···
1986
2343
minimatch: 3.1.2
1987
2344
natural-compare: 1.4.0
1988
2345
optionator: 0.9.3
1989
-
text-table: 0.2.0
2346
+
optionalDependencies:
2347
+
jiti: 2.4.2
1990
2348
transitivePeerDependencies:
1991
2349
- supports-color
1992
2350
1993
-
espree@10.2.0:
2351
+
espree@10.3.0:
1994
2352
dependencies:
1995
-
acorn: 8.12.1
1996
-
acorn-jsx: 5.3.2(acorn@8.12.1)
1997
-
eslint-visitor-keys: 4.1.0
2353
+
acorn: 8.14.1
2354
+
acorn-jsx: 5.3.2(acorn@8.14.1)
2355
+
eslint-visitor-keys: 4.2.0
1998
2356
1999
-
esquery@1.5.0:
2357
+
esquery@1.6.0:
2000
2358
dependencies:
2001
2359
estraverse: 5.3.0
2002
2360
···
2039
2397
dependencies:
2040
2398
reusify: 1.0.4
2041
2399
2400
+
fdir@6.4.3(picomatch@4.0.2):
2401
+
optionalDependencies:
2402
+
picomatch: 4.0.2
2403
+
2042
2404
file-entry-cache@8.0.0:
2043
2405
dependencies:
2044
2406
flat-cache: 4.0.1
···
2047
2409
dependencies:
2048
2410
to-regex-range: 5.0.1
2049
2411
2412
+
find-up-simple@1.0.1: {}
2413
+
2050
2414
find-up@5.0.0:
2051
2415
dependencies:
2052
2416
locate-path: 6.0.0
···
2059
2423
2060
2424
flatted@3.2.9: {}
2061
2425
2062
-
for-each@0.3.3:
2426
+
for-each@0.3.5:
2063
2427
dependencies:
2064
2428
is-callable: 1.2.7
2065
2429
2066
2430
function-bind@1.1.2: {}
2067
2431
2068
-
function.prototype.name@1.1.6:
2432
+
function.prototype.name@1.1.8:
2069
2433
dependencies:
2070
-
call-bind: 1.0.7
2434
+
call-bind: 1.0.8
2435
+
call-bound: 1.0.4
2071
2436
define-properties: 1.2.1
2072
-
es-abstract: 1.23.3
2073
2437
functions-have-names: 1.2.3
2438
+
hasown: 2.0.2
2439
+
is-callable: 1.2.7
2074
2440
2075
2441
functions-have-names@1.2.3: {}
2076
2442
2077
-
get-intrinsic@1.2.4:
2443
+
fzf@0.5.2: {}
2444
+
2445
+
get-intrinsic@1.3.0:
2078
2446
dependencies:
2447
+
call-bind-apply-helpers: 1.0.2
2448
+
es-define-property: 1.0.1
2079
2449
es-errors: 1.3.0
2450
+
es-object-atoms: 1.1.1
2080
2451
function-bind: 1.1.2
2081
-
has-proto: 1.0.3
2082
-
has-symbols: 1.0.3
2452
+
get-proto: 1.0.1
2453
+
gopd: 1.2.0
2454
+
has-symbols: 1.1.0
2083
2455
hasown: 2.0.2
2456
+
math-intrinsics: 1.1.0
2084
2457
2085
-
get-symbol-description@1.0.2:
2458
+
get-proto@1.0.1:
2459
+
dependencies:
2460
+
dunder-proto: 1.0.1
2461
+
es-object-atoms: 1.1.1
2462
+
2463
+
get-symbol-description@1.1.0:
2086
2464
dependencies:
2087
-
call-bind: 1.0.7
2465
+
call-bound: 1.0.4
2088
2466
es-errors: 1.3.0
2089
-
get-intrinsic: 1.2.4
2467
+
get-intrinsic: 1.3.0
2090
2468
2091
2469
glob-parent@5.1.2:
2092
2470
dependencies:
···
2101
2479
globalthis@1.0.4:
2102
2480
dependencies:
2103
2481
define-properties: 1.2.1
2104
-
gopd: 1.0.1
2482
+
gopd: 1.2.0
2105
2483
2106
-
gopd@1.0.1:
2107
-
dependencies:
2108
-
get-intrinsic: 1.2.4
2484
+
gopd@1.2.0: {}
2109
2485
2110
2486
graphemer@1.4.0: {}
2111
2487
2112
-
has-bigints@1.0.2: {}
2488
+
has-bigints@1.1.0: {}
2113
2489
2114
2490
has-flag@4.0.0: {}
2115
2491
2116
2492
has-property-descriptors@1.0.2:
2117
2493
dependencies:
2118
-
es-define-property: 1.0.0
2494
+
es-define-property: 1.0.1
2119
2495
2120
-
has-proto@1.0.3: {}
2496
+
has-proto@1.2.0:
2497
+
dependencies:
2498
+
dunder-proto: 1.0.1
2121
2499
2122
-
has-symbols@1.0.3: {}
2500
+
has-symbols@1.1.0: {}
2123
2501
2124
2502
has-tostringtag@1.0.2:
2125
2503
dependencies:
2126
-
has-symbols: 1.0.3
2504
+
has-symbols: 1.1.0
2127
2505
2128
2506
hasown@2.0.2:
2129
2507
dependencies:
···
2132
2510
husky@8.0.3: {}
2133
2511
2134
2512
ieee754@1.2.1: {}
2135
-
2136
-
ignore@5.3.0: {}
2137
2513
2138
2514
ignore@5.3.2: {}
2139
2515
···
2144
2520
2145
2521
imurmurhash@0.1.4: {}
2146
2522
2147
-
internal-slot@1.0.7:
2523
+
internal-slot@1.1.0:
2148
2524
dependencies:
2149
2525
es-errors: 1.3.0
2150
2526
hasown: 2.0.2
2151
-
side-channel: 1.0.6
2527
+
side-channel: 1.1.0
2152
2528
2153
-
is-array-buffer@3.0.4:
2529
+
is-array-buffer@3.0.5:
2154
2530
dependencies:
2155
-
call-bind: 1.0.7
2156
-
get-intrinsic: 1.2.4
2531
+
call-bind: 1.0.8
2532
+
call-bound: 1.0.4
2533
+
get-intrinsic: 1.3.0
2157
2534
2158
-
is-async-function@2.0.0:
2535
+
is-async-function@2.1.1:
2159
2536
dependencies:
2537
+
async-function: 1.0.0
2538
+
call-bound: 1.0.4
2539
+
get-proto: 1.0.1
2160
2540
has-tostringtag: 1.0.2
2541
+
safe-regex-test: 1.1.0
2161
2542
2162
-
is-bigint@1.0.4:
2543
+
is-bigint@1.1.0:
2163
2544
dependencies:
2164
-
has-bigints: 1.0.2
2545
+
has-bigints: 1.1.0
2165
2546
2166
-
is-boolean-object@1.1.2:
2547
+
is-boolean-object@1.2.2:
2167
2548
dependencies:
2168
-
call-bind: 1.0.7
2549
+
call-bound: 1.0.4
2169
2550
has-tostringtag: 1.0.2
2170
2551
2171
2552
is-callable@1.2.7: {}
2172
2553
2173
-
is-core-module@2.15.1:
2554
+
is-core-module@2.16.1:
2174
2555
dependencies:
2175
2556
hasown: 2.0.2
2176
2557
2177
-
is-data-view@1.0.1:
2558
+
is-data-view@1.0.2:
2178
2559
dependencies:
2179
-
is-typed-array: 1.1.13
2560
+
call-bound: 1.0.4
2561
+
get-intrinsic: 1.3.0
2562
+
is-typed-array: 1.1.15
2180
2563
2181
-
is-date-object@1.0.5:
2564
+
is-date-object@1.1.0:
2182
2565
dependencies:
2566
+
call-bound: 1.0.4
2183
2567
has-tostringtag: 1.0.2
2184
2568
2185
2569
is-extglob@2.1.1: {}
2186
2570
2187
-
is-finalizationregistry@1.0.2:
2571
+
is-finalizationregistry@1.1.1:
2188
2572
dependencies:
2189
-
call-bind: 1.0.7
2573
+
call-bound: 1.0.4
2190
2574
2191
-
is-generator-function@1.0.10:
2575
+
is-generator-function@1.1.0:
2192
2576
dependencies:
2577
+
call-bound: 1.0.4
2578
+
get-proto: 1.0.1
2193
2579
has-tostringtag: 1.0.2
2580
+
safe-regex-test: 1.1.0
2194
2581
2195
2582
is-glob@4.0.3:
2196
2583
dependencies:
···
2198
2585
2199
2586
is-map@2.0.3: {}
2200
2587
2201
-
is-negative-zero@2.0.3: {}
2202
-
2203
-
is-number-object@1.0.7:
2588
+
is-number-object@1.1.1:
2204
2589
dependencies:
2590
+
call-bound: 1.0.4
2205
2591
has-tostringtag: 1.0.2
2206
2592
2207
2593
is-number@7.0.0: {}
2208
2594
2209
-
is-regex@1.1.4:
2595
+
is-regex@1.2.1:
2210
2596
dependencies:
2211
-
call-bind: 1.0.7
2597
+
call-bound: 1.0.4
2598
+
gopd: 1.2.0
2212
2599
has-tostringtag: 1.0.2
2600
+
hasown: 2.0.2
2213
2601
2214
2602
is-set@2.0.3: {}
2215
2603
2216
-
is-shared-array-buffer@1.0.3:
2604
+
is-shared-array-buffer@1.0.4:
2217
2605
dependencies:
2218
-
call-bind: 1.0.7
2606
+
call-bound: 1.0.4
2219
2607
2220
-
is-string@1.0.7:
2608
+
is-string@1.1.1:
2221
2609
dependencies:
2610
+
call-bound: 1.0.4
2222
2611
has-tostringtag: 1.0.2
2223
2612
2224
-
is-symbol@1.0.4:
2613
+
is-symbol@1.1.1:
2225
2614
dependencies:
2226
-
has-symbols: 1.0.3
2615
+
call-bound: 1.0.4
2616
+
has-symbols: 1.1.0
2617
+
safe-regex-test: 1.1.0
2227
2618
2228
-
is-typed-array@1.1.13:
2619
+
is-typed-array@1.1.15:
2229
2620
dependencies:
2230
-
which-typed-array: 1.1.15
2621
+
which-typed-array: 1.1.19
2231
2622
2232
2623
is-weakmap@2.0.2: {}
2233
2624
2234
-
is-weakref@1.0.2:
2625
+
is-weakref@1.1.1:
2235
2626
dependencies:
2236
-
call-bind: 1.0.7
2627
+
call-bound: 1.0.4
2237
2628
2238
-
is-weakset@2.0.3:
2629
+
is-weakset@2.0.4:
2239
2630
dependencies:
2240
-
call-bind: 1.0.7
2241
-
get-intrinsic: 1.2.4
2631
+
call-bound: 1.0.4
2632
+
get-intrinsic: 1.3.0
2242
2633
2243
2634
isarray@2.0.5: {}
2244
2635
2245
2636
isexe@2.0.0: {}
2246
2637
2247
-
iterator.prototype@1.1.3:
2638
+
iterator.prototype@1.1.5:
2248
2639
dependencies:
2249
-
define-properties: 1.2.1
2250
-
get-intrinsic: 1.2.4
2251
-
has-symbols: 1.0.3
2252
-
reflect.getprototypeof: 1.0.6
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
2253
2645
set-function-name: 2.0.2
2646
+
2647
+
jiti@2.4.2: {}
2254
2648
2255
2649
js-tokens@4.0.0: {}
2256
2650
···
2267
2661
jsx-ast-utils@3.3.5:
2268
2662
dependencies:
2269
2663
array-includes: 3.1.8
2270
-
array.prototype.flat: 1.3.2
2271
-
object.assign: 4.1.5
2272
-
object.values: 1.2.0
2664
+
array.prototype.flat: 1.3.3
2665
+
object.assign: 4.1.7
2666
+
object.values: 1.2.1
2273
2667
2274
2668
keyv@4.5.4:
2275
2669
dependencies:
···
2290
2684
dependencies:
2291
2685
js-tokens: 4.0.0
2292
2686
2687
+
math-intrinsics@1.1.0: {}
2688
+
2293
2689
merge2@1.4.1: {}
2294
2690
2295
2691
meriyah@6.0.1: {}
2296
2692
2693
+
microdiff@1.5.0: {}
2694
+
2297
2695
micromatch@4.0.8:
2298
2696
dependencies:
2299
2697
braces: 3.0.3
2300
2698
picomatch: 2.3.1
2699
+
2700
+
mimic-function@5.0.1: {}
2301
2701
2302
2702
minimatch@3.1.2:
2303
2703
dependencies:
···
2307
2707
dependencies:
2308
2708
brace-expansion: 2.0.1
2309
2709
2310
-
ms@2.1.2: {}
2710
+
ms@2.1.3: {}
2311
2711
2312
2712
nanotar@0.1.1: {}
2313
2713
2314
2714
natural-compare@1.4.0: {}
2715
+
2716
+
node-fetch-native@1.6.6: {}
2315
2717
2316
2718
object-assign@4.1.1: {}
2317
2719
2318
-
object-inspect@1.13.2: {}
2720
+
object-inspect@1.13.4: {}
2319
2721
2320
2722
object-keys@1.1.1: {}
2321
2723
2322
-
object.assign@4.1.5:
2724
+
object.assign@4.1.7:
2323
2725
dependencies:
2324
-
call-bind: 1.0.7
2726
+
call-bind: 1.0.8
2727
+
call-bound: 1.0.4
2325
2728
define-properties: 1.2.1
2326
-
has-symbols: 1.0.3
2729
+
es-object-atoms: 1.1.1
2730
+
has-symbols: 1.1.0
2327
2731
object-keys: 1.1.1
2328
2732
2329
-
object.entries@1.1.8:
2733
+
object.entries@1.1.9:
2330
2734
dependencies:
2331
-
call-bind: 1.0.7
2735
+
call-bind: 1.0.8
2736
+
call-bound: 1.0.4
2332
2737
define-properties: 1.2.1
2333
-
es-object-atoms: 1.0.0
2738
+
es-object-atoms: 1.1.1
2334
2739
2335
2740
object.fromentries@2.0.8:
2336
2741
dependencies:
2337
-
call-bind: 1.0.7
2742
+
call-bind: 1.0.8
2338
2743
define-properties: 1.2.1
2339
-
es-abstract: 1.23.3
2340
-
es-object-atoms: 1.0.0
2744
+
es-abstract: 1.23.9
2745
+
es-object-atoms: 1.1.1
2341
2746
2342
-
object.values@1.2.0:
2747
+
object.values@1.2.1:
2343
2748
dependencies:
2344
-
call-bind: 1.0.7
2749
+
call-bind: 1.0.8
2750
+
call-bound: 1.0.4
2345
2751
define-properties: 1.2.1
2346
-
es-object-atoms: 1.0.0
2752
+
es-object-atoms: 1.1.1
2753
+
2754
+
ofetch@1.4.1:
2755
+
dependencies:
2756
+
destr: 2.0.4
2757
+
node-fetch-native: 1.6.6
2758
+
ufo: 1.5.4
2759
+
2760
+
onetime@7.0.0:
2761
+
dependencies:
2762
+
mimic-function: 5.0.1
2347
2763
2348
2764
optionator@0.9.3:
2349
2765
dependencies:
···
2354
2770
prelude-ls: 1.2.1
2355
2771
type-check: 0.4.0
2356
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
+
2357
2779
p-limit@3.1.0:
2358
2780
dependencies:
2359
2781
yocto-queue: 0.1.0
···
2362
2784
dependencies:
2363
2785
p-limit: 3.1.0
2364
2786
2787
+
package-manager-detector@1.1.0: {}
2788
+
2365
2789
parent-module@1.0.1:
2366
2790
dependencies:
2367
2791
callsites: 3.1.0
···
2372
2796
2373
2797
path-parse@1.0.7: {}
2374
2798
2799
+
pathe@2.0.3: {}
2800
+
2375
2801
picomatch@2.3.1: {}
2376
2802
2377
-
possible-typed-array-names@1.0.0: {}
2803
+
picomatch@4.0.2: {}
2804
+
2805
+
pnpm-workspace-yaml@0.3.1:
2806
+
dependencies:
2807
+
yaml: 2.7.1
2808
+
2809
+
possible-typed-array-names@1.1.0: {}
2378
2810
2379
2811
prelude-ls@1.2.1: {}
2380
2812
···
2394
2826
2395
2827
punycode@2.3.1: {}
2396
2828
2829
+
quansync@0.2.10: {}
2830
+
2397
2831
queue-microtask@1.2.3: {}
2398
2832
2399
2833
react-is@16.13.1: {}
···
2406
2840
process: 0.11.10
2407
2841
string_decoder: 1.3.0
2408
2842
2409
-
reflect.getprototypeof@1.0.6:
2843
+
reflect.getprototypeof@1.0.10:
2410
2844
dependencies:
2411
-
call-bind: 1.0.7
2845
+
call-bind: 1.0.8
2412
2846
define-properties: 1.2.1
2413
-
es-abstract: 1.23.3
2847
+
es-abstract: 1.23.9
2414
2848
es-errors: 1.3.0
2415
-
get-intrinsic: 1.2.4
2416
-
globalthis: 1.0.4
2417
-
which-builtin-type: 1.1.4
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
2418
2853
2419
-
regexp.prototype.flags@1.5.3:
2854
+
regexp.prototype.flags@1.5.4:
2420
2855
dependencies:
2421
-
call-bind: 1.0.7
2856
+
call-bind: 1.0.8
2422
2857
define-properties: 1.2.1
2423
2858
es-errors: 1.3.0
2859
+
get-proto: 1.0.1
2860
+
gopd: 1.2.0
2424
2861
set-function-name: 2.0.2
2425
2862
2426
2863
resolve-from@4.0.0: {}
2427
2864
2428
2865
resolve@2.0.0-next.5:
2429
2866
dependencies:
2430
-
is-core-module: 2.15.1
2867
+
is-core-module: 2.16.1
2431
2868
path-parse: 1.0.7
2432
2869
supports-preserve-symlinks-flag: 1.0.0
2433
2870
2871
+
restore-cursor@5.1.0:
2872
+
dependencies:
2873
+
onetime: 7.0.0
2874
+
signal-exit: 4.1.0
2875
+
2434
2876
reusify@1.0.4: {}
2435
2877
2436
2878
run-parallel@1.2.0:
2437
2879
dependencies:
2438
2880
queue-microtask: 1.2.3
2439
2881
2440
-
safe-array-concat@1.1.2:
2882
+
safe-array-concat@1.1.3:
2441
2883
dependencies:
2442
-
call-bind: 1.0.7
2443
-
get-intrinsic: 1.2.4
2444
-
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
2445
2888
isarray: 2.0.5
2446
-
2447
-
safe-buffer@5.1.2: {}
2448
2889
2449
2890
safe-buffer@5.2.1: {}
2450
2891
2451
-
safe-regex-test@1.0.3:
2892
+
safe-push-apply@1.0.0:
2452
2893
dependencies:
2453
-
call-bind: 1.0.7
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
2454
2900
es-errors: 1.3.0
2455
-
is-regex: 1.1.4
2901
+
is-regex: 1.2.1
2456
2902
2457
2903
semver@6.3.1: {}
2458
2904
2459
-
semver@7.6.3: {}
2905
+
semver@7.7.1: {}
2460
2906
2461
2907
set-function-length@1.2.2:
2462
2908
dependencies:
2463
2909
define-data-property: 1.1.4
2464
2910
es-errors: 1.3.0
2465
2911
function-bind: 1.1.2
2466
-
get-intrinsic: 1.2.4
2467
-
gopd: 1.0.1
2912
+
get-intrinsic: 1.3.0
2913
+
gopd: 1.2.0
2468
2914
has-property-descriptors: 1.0.2
2469
2915
2470
2916
set-function-name@2.0.2:
···
2473
2919
es-errors: 1.3.0
2474
2920
functions-have-names: 1.2.3
2475
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
2476
2928
2477
2929
shebang-command@2.0.0:
2478
2930
dependencies:
···
2480
2932
2481
2933
shebang-regex@3.0.0: {}
2482
2934
2483
-
side-channel@1.0.6:
2935
+
side-channel-list@1.0.0:
2936
+
dependencies:
2937
+
es-errors: 1.3.0
2938
+
object-inspect: 1.13.4
2939
+
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
2946
+
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:
2484
2956
dependencies:
2485
-
call-bind: 1.0.7
2486
2957
es-errors: 1.3.0
2487
-
get-intrinsic: 1.2.4
2488
-
object-inspect: 1.13.2
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: {}
2489
2964
2490
2965
standalone-electron-types@1.0.0:
2491
2966
dependencies:
2492
2967
'@types/node': 18.17.17
2493
2968
2494
-
string.prototype.matchall@4.0.11:
2969
+
string.prototype.matchall@4.0.12:
2495
2970
dependencies:
2496
-
call-bind: 1.0.7
2971
+
call-bind: 1.0.8
2972
+
call-bound: 1.0.4
2497
2973
define-properties: 1.2.1
2498
-
es-abstract: 1.23.3
2974
+
es-abstract: 1.23.9
2499
2975
es-errors: 1.3.0
2500
-
es-object-atoms: 1.0.0
2501
-
get-intrinsic: 1.2.4
2502
-
gopd: 1.0.1
2503
-
has-symbols: 1.0.3
2504
-
internal-slot: 1.0.7
2505
-
regexp.prototype.flags: 1.5.3
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
2506
2982
set-function-name: 2.0.2
2507
-
side-channel: 1.0.6
2983
+
side-channel: 1.1.0
2508
2984
2509
2985
string.prototype.repeat@1.0.0:
2510
2986
dependencies:
2511
2987
define-properties: 1.2.1
2512
-
es-abstract: 1.23.3
2988
+
es-abstract: 1.23.9
2513
2989
2514
-
string.prototype.trim@1.2.9:
2990
+
string.prototype.trim@1.2.10:
2515
2991
dependencies:
2516
-
call-bind: 1.0.7
2992
+
call-bind: 1.0.8
2993
+
call-bound: 1.0.4
2994
+
define-data-property: 1.1.4
2517
2995
define-properties: 1.2.1
2518
-
es-abstract: 1.23.3
2519
-
es-object-atoms: 1.0.0
2996
+
es-abstract: 1.23.9
2997
+
es-object-atoms: 1.1.1
2998
+
has-property-descriptors: 1.0.2
2520
2999
2521
-
string.prototype.trimend@1.0.8:
3000
+
string.prototype.trimend@1.0.9:
2522
3001
dependencies:
2523
-
call-bind: 1.0.7
3002
+
call-bind: 1.0.8
3003
+
call-bound: 1.0.4
2524
3004
define-properties: 1.2.1
2525
-
es-object-atoms: 1.0.0
3005
+
es-object-atoms: 1.1.1
2526
3006
2527
3007
string.prototype.trimstart@1.0.8:
2528
3008
dependencies:
2529
-
call-bind: 1.0.7
3009
+
call-bind: 1.0.8
2530
3010
define-properties: 1.2.1
2531
-
es-object-atoms: 1.0.0
3011
+
es-object-atoms: 1.1.1
2532
3012
2533
3013
string_decoder@1.3.0:
2534
3014
dependencies:
···
2542
3022
2543
3023
supports-preserve-symlinks-flag@1.0.0: {}
2544
3024
2545
-
synckit@0.9.2:
3025
+
synckit@0.11.1:
2546
3026
dependencies:
2547
-
'@pkgr/core': 0.1.1
2548
-
tslib: 2.7.0
3027
+
'@pkgr/core': 0.2.0
3028
+
tslib: 2.8.1
2549
3029
2550
-
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
3044
+
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
2551
3051
2552
3052
to-regex-range@5.0.1:
2553
3053
dependencies:
2554
3054
is-number: 7.0.0
2555
3055
2556
-
ts-api-utils@1.3.0(typescript@5.3.2):
3056
+
ts-api-utils@2.1.0(typescript@5.8.2):
2557
3057
dependencies:
2558
-
typescript: 5.3.2
3058
+
typescript: 5.8.2
2559
3059
2560
-
tslib@2.7.0: {}
3060
+
tslib@2.8.1: {}
2561
3061
2562
3062
type-check@0.4.0:
2563
3063
dependencies:
2564
3064
prelude-ls: 1.2.1
2565
3065
2566
-
typed-array-buffer@1.0.2:
3066
+
typed-array-buffer@1.0.3:
2567
3067
dependencies:
2568
-
call-bind: 1.0.7
3068
+
call-bound: 1.0.4
2569
3069
es-errors: 1.3.0
2570
-
is-typed-array: 1.1.13
3070
+
is-typed-array: 1.1.15
2571
3071
2572
-
typed-array-byte-length@1.0.1:
3072
+
typed-array-byte-length@1.0.3:
2573
3073
dependencies:
2574
-
call-bind: 1.0.7
2575
-
for-each: 0.3.3
2576
-
gopd: 1.0.1
2577
-
has-proto: 1.0.3
2578
-
is-typed-array: 1.1.13
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
2579
3079
2580
-
typed-array-byte-offset@1.0.2:
3080
+
typed-array-byte-offset@1.0.4:
2581
3081
dependencies:
2582
3082
available-typed-arrays: 1.0.7
2583
-
call-bind: 1.0.7
2584
-
for-each: 0.3.3
2585
-
gopd: 1.0.1
2586
-
has-proto: 1.0.3
2587
-
is-typed-array: 1.1.13
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
2588
3089
2589
-
typed-array-length@1.0.6:
3090
+
typed-array-length@1.0.7:
2590
3091
dependencies:
2591
-
call-bind: 1.0.7
2592
-
for-each: 0.3.3
2593
-
gopd: 1.0.1
2594
-
has-proto: 1.0.3
2595
-
is-typed-array: 1.1.13
2596
-
possible-typed-array-names: 1.0.0
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
2597
3098
2598
-
typescript-eslint@8.8.1(eslint@9.12.0)(typescript@5.3.2):
3099
+
typescript-eslint@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2):
2599
3100
dependencies:
2600
-
'@typescript-eslint/eslint-plugin': 8.8.1(@typescript-eslint/parser@8.8.1(eslint@9.12.0)(typescript@5.3.2))(eslint@9.12.0)(typescript@5.3.2)
2601
-
'@typescript-eslint/parser': 8.8.1(eslint@9.12.0)(typescript@5.3.2)
2602
-
'@typescript-eslint/utils': 8.8.1(eslint@9.12.0)(typescript@5.3.2)
2603
-
optionalDependencies:
2604
-
typescript: 5.3.2
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
2605
3106
transitivePeerDependencies:
2606
-
- eslint
2607
3107
- supports-color
2608
3108
2609
-
typescript@5.3.2: {}
3109
+
typescript@5.8.2: {}
3110
+
3111
+
ufo@1.5.4: {}
2610
3112
2611
-
unbox-primitive@1.0.2:
3113
+
unbox-primitive@1.1.0:
2612
3114
dependencies:
2613
-
call-bind: 1.0.7
2614
-
has-bigints: 1.0.2
2615
-
has-symbols: 1.0.3
2616
-
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
2617
3119
2618
-
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: {}
3128
+
3129
+
undici-types@6.21.0: {}
2619
3130
2620
3131
uri-js@4.4.1:
2621
3132
dependencies:
2622
3133
punycode: 2.3.1
2623
3134
2624
-
utilium@0.7.1:
3135
+
utilium@1.10.1:
2625
3136
dependencies:
2626
3137
eventemitter3: 5.0.1
3138
+
optionalDependencies:
3139
+
'@xterm/xterm': 5.5.0
2627
3140
2628
-
which-boxed-primitive@1.0.2:
3141
+
which-boxed-primitive@1.1.1:
2629
3142
dependencies:
2630
-
is-bigint: 1.0.4
2631
-
is-boolean-object: 1.1.2
2632
-
is-number-object: 1.0.7
2633
-
is-string: 1.0.7
2634
-
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
2635
3148
2636
-
which-builtin-type@1.1.4:
3149
+
which-builtin-type@1.2.1:
2637
3150
dependencies:
2638
-
function.prototype.name: 1.1.6
3151
+
call-bound: 1.0.4
3152
+
function.prototype.name: 1.1.8
2639
3153
has-tostringtag: 1.0.2
2640
-
is-async-function: 2.0.0
2641
-
is-date-object: 1.0.5
2642
-
is-finalizationregistry: 1.0.2
2643
-
is-generator-function: 1.0.10
2644
-
is-regex: 1.1.4
2645
-
is-weakref: 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
2646
3160
isarray: 2.0.5
2647
-
which-boxed-primitive: 1.0.2
3161
+
which-boxed-primitive: 1.1.1
2648
3162
which-collection: 1.0.2
2649
-
which-typed-array: 1.1.15
3163
+
which-typed-array: 1.1.19
2650
3164
2651
3165
which-collection@1.0.2:
2652
3166
dependencies:
2653
3167
is-map: 2.0.3
2654
3168
is-set: 2.0.3
2655
3169
is-weakmap: 2.0.2
2656
-
is-weakset: 2.0.3
3170
+
is-weakset: 2.0.4
2657
3171
2658
-
which-typed-array@1.1.15:
3172
+
which-typed-array@1.1.19:
2659
3173
dependencies:
2660
3174
available-typed-arrays: 1.0.7
2661
-
call-bind: 1.0.7
2662
-
for-each: 0.3.3
2663
-
gopd: 1.0.1
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
2664
3180
has-tostringtag: 1.0.2
2665
3181
2666
3182
which@2.0.2:
2667
3183
dependencies:
2668
3184
isexe: 2.0.0
2669
3185
3186
+
yaml@2.7.1: {}
3187
+
2670
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/
-78
scripts/link.js
-78
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 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
-
}
+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
+
}
-29
scripts/update.js
-29
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(fs.readFileSync(path.join("./packages", package, "package.json"), "utf8"));
23
-
24
-
const deps = getDeps(packageJSON);
25
-
if (Object.keys(deps).includes(packageToUpdate)) {
26
-
console.log(`Updating ${packageToUpdate} in ${package}`);
27
-
exec(`pnpm update ${packageToUpdate}`, path.join("./packages", package));
28
-
}
29
-
}
+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": "es2020",
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
}