this repo has no description

Compare changes

Choose any two refs to compare.

Changed files
+6374 -2060
.github
.vscode
nix
packages
browser
core
core-extensions
injector
node-preload
types
web-preload
scripts
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 3 3 dist.tar.gz 4 4 .DS_Store 5 5 eslint_report.json 6 - 6 + .eslintcache 7 7 # Nix 8 8 /result 9 9 *.drv 10 + 11 + # IDEs 12 + .vscode/ 13 + .idea/
+4 -4
.prettierrc
··· 1 1 { 2 - "printWidth": 120, 3 - "trailingComma": "none", 4 - "tabWidth": 2, 5 - "singleQuote": false 2 + "printWidth": 120, 3 + "trailingComma": "none", 4 + "tabWidth": 2, 5 + "singleQuote": false 6 6 }
-14
.vscode/tasks.json
··· 1 - { 2 - "version": "2.0.0", 3 - "tasks": [ 4 - { 5 - "label": "build", 6 - "type": "shell", 7 - "command": "pnpm run build", 8 - "group": { 9 - "kind": "build", 10 - "isDefault": true 11 - } 12 - } 13 - ] 14 - }
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 6 6 "type": "block" 7 7 }, 8 8 "condition": { 9 - "urlFilter": "*://discord.com/assets/*.js", 9 + "requestDomains": ["discord.com", "discordapp.com"], 10 + "urlFilter": "*/assets/*.js", 10 11 "resourceTypes": ["script"] 11 12 } 12 13 }
+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
··· 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
··· 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
··· 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
··· 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
··· 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 1 { 2 2 "extends": "../../tsconfig.json", 3 3 "compilerOptions": { 4 + "lib": ["DOM", "ESNext", "ESNext.AsyncIterable"], 4 5 "module": "ES2022" 5 6 } 6 7 }
+7
packages/core/package.json
··· 4 4 "exports": { 5 5 "./*": "./src/*.ts" 6 6 }, 7 + "engineStrict": true, 8 + "engines": { 9 + "node": ">=22", 10 + "pnpm": ">=10", 11 + "npm": "pnpm", 12 + "yarn": "pnpm" 13 + }, 7 14 "dependencies": { 8 15 "@moonlight-mod/types": "workspace:*" 9 16 }
+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
··· 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
··· 48 48 }, 49 49 dirname(dir) { 50 50 return path.dirname(dir); 51 + }, 52 + basename(dir) { 53 + return path.basename(dir); 51 54 } 52 55 }; 53 56 }
+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
··· 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
··· 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
··· 1 1 { 2 - "extends": "../../tsconfig.json" 2 + "extends": "../../tsconfig.json", 3 + "compilerOptions": { 4 + "lib": ["ESNext", "DOM"] 5 + } 3 6 }
+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 1 { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 2 3 "id": "appPanels", 3 4 "apiLevel": 2, 4 5 "meta": {
+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
··· 1 + { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 3 + "id": "commands", 4 + "apiLevel": 2, 5 + "meta": { 6 + "name": "Commands", 7 + "tagline": "A library to add commands", 8 + "authors": ["Cynosphere", "NotNite"], 9 + "tags": ["library"] 10 + } 11 + }
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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 1 { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 2 3 "id": "contextMenu", 3 4 "apiLevel": 2, 4 5 "meta": {
+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
··· 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
··· 13 13 }, 14 14 "settings": { 15 15 "paths": { 16 + "advice": "restart", 16 17 "displayName": "Extension Paths", 17 18 "type": "list" 18 19 }
+2 -2
packages/core-extensions/src/disableSentry/index.ts
··· 6 6 find: "profiledRootComponent:", 7 7 replace: { 8 8 type: PatchReplaceType.Normal, 9 - match: /(?<=\.Z=){.+?}}/, 10 - replacement: 'require("disableSentry_stub").proxy()' 9 + match: /Z:\(\)=>\i/, 10 + replacement: 'Z:()=>require("disableSentry_stub").proxy()' 11 11 } 12 12 }, 13 13 {
+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
··· 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
··· 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
··· 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 1 { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 2 3 "id": "markdown", 3 4 "apiLevel": 2, 4 5 "meta": {
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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 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
··· 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
··· 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
··· 2 2 3 3 export const patches: Patch[] = [ 4 4 { 5 - find: "hideToken:function", 5 + find: "hideToken:()=>", 6 6 replace: { 7 - match: /(?<=hideToken:function\(\){)/, 8 - replacement: `return()=>{};` 7 + match: /hideToken:\(\)=>.+?,/, 8 + replacement: `hideToken:()=>{},` 9 9 } 10 10 } 11 11 ];
+1
packages/core-extensions/src/noHideToken/manifest.json
··· 1 1 { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 2 3 "id": "noHideToken", 3 4 "apiLevel": 2, 4 5 "meta": {
+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
··· 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 1 { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 2 3 "id": "notices", 3 4 "apiLevel": 2, 4 5 "meta": {
+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
··· 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
··· 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
··· 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
··· 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 1 { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 2 3 "id": "settings", 3 4 "apiLevel": 2, 4 5 "meta": {
+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
··· 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
··· 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
··· 1 1 { 2 - "extends": "../../tsconfig.json" 2 + "extends": "../../tsconfig.json", 3 + "compilerOptions": { 4 + "lib": ["ESNext", "DOM", "DOM.Iterable"] 5 + } 3 6 }
+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
··· 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
··· 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
··· 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
··· 1 1 { 2 - "extends": "../../tsconfig.json" 2 + "extends": "../../tsconfig.json", 3 + "compilerOptions": { 4 + "lib": ["DOM", "ESNext", "DOM.Iterable"] 5 + } 3 6 }
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 15 15 16 16 join: (...parts: string[]) => string; 17 17 dirname: (path: string) => string; 18 + basename: (path: string) => string; 18 19 };
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 1 1 { 2 - "extends": "../../tsconfig.json" 2 + "extends": "../../tsconfig.json", 3 + "compilerOptions": { 4 + "lib": ["ESNext", "DOM"] 5 + } 3 6 }
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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 }