this repo has no description

Compare changes

Choose any two refs to compare.

+16
.github/workflows/nix.yml
···
+
name: Check Nix flake
+
on: [push, pull_request]
+
+
permissions:
+
checks: write
+
+
jobs:
+
nix:
+
name: Check Nix flake
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@v4
+
- uses: DeterminateSystems/nix-installer-action@main
+
+
- name: Build default flake output
+
run: nix build
+1
.github/workflows/types.yml
···
with:
node-version: 22
cache: pnpm
+
registry-url: https://registry.npmjs.org
- name: Install dependencies
run: pnpm install --frozen-lockfile
+2 -8
CHANGELOG.md
···
## Core
-
- Updated moonmap, now logs when remapped exports fail
-
- Updated mappings to fix Moonbase
-
-
## Core extensions
-
-
- Extensions: Visual Refresh support for staff help button (devtools)
-
- Native Fixes: Added flag to enable HEVC on Linux (your mileage may vary)
-
- Moonbase: Added error boundaries, should no longer crash in most cases when things break
+
- Updated mappings
+
- Fixed using remapped paths as patch finds not working
+4 -73
flake.lock
···
"type": "github"
}
},
-
"flake-utils_2": {
-
"inputs": {
-
"systems": "systems_2"
-
},
-
"locked": {
-
"lastModified": 1701680307,
-
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
-
"owner": "numtide",
-
"repo": "flake-utils",
-
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
-
"type": "github"
-
},
-
"original": {
-
"owner": "numtide",
-
"repo": "flake-utils",
-
"type": "github"
-
}
-
},
"nixpkgs": {
"locked": {
-
"lastModified": 1728067476,
-
"narHash": "sha256-/uJcVXuBt+VFCPQIX+4YnYrHaubJSx4HoNsJVNRgANM=",
+
"lastModified": 1744232761,
+
"narHash": "sha256-gbl9hE39nQRpZaLjhWKmEu5ejtQsgI5TWYrIVVJn30U=",
"owner": "NixOS",
"repo": "nixpkgs",
-
"rev": "6e6b3dd395c3b1eb9be9f2d096383a8d05add030",
+
"rev": "f675531bc7e6657c10a18b565cfebd8aa9e24c14",
"type": "github"
},
"original": {
"owner": "NixOS",
-
"ref": "nixos-24.05",
-
"repo": "nixpkgs",
-
"type": "github"
-
}
-
},
-
"nixpkgs_2": {
-
"locked": {
-
"lastModified": 1736344531,
-
"narHash": "sha256-8YVQ9ZbSfuUk2bUf2KRj60NRraLPKPS0Q4QFTbc+c2c=",
-
"owner": "nixos",
-
"repo": "nixpkgs",
-
"rev": "bffc22eb12172e6db3c5dde9e3e5628f8e3e7912",
-
"type": "github"
-
},
-
"original": {
-
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
-
"pnpm2nix": {
-
"inputs": {
-
"flake-utils": "flake-utils_2",
-
"nixpkgs": "nixpkgs_2"
-
},
-
"locked": {
-
"lastModified": 1736457458,
-
"narHash": "sha256-eiw+hAsxavEgBfhwrktNI2hwvgeVDzBDYClx/yqka78=",
-
"owner": "NotNite",
-
"repo": "pnpm2nix-nzbr",
-
"rev": "4ac61c6a50623da937dca005e3dbcb8862aafb83",
-
"type": "github"
-
},
-
"original": {
-
"owner": "NotNite",
-
"repo": "pnpm2nix-nzbr",
-
"type": "github"
-
}
-
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
-
"nixpkgs": "nixpkgs",
-
"pnpm2nix": "pnpm2nix"
+
"nixpkgs": "nixpkgs"
}
},
"systems": {
-
"locked": {
-
"lastModified": 1681028828,
-
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-
"owner": "nix-systems",
-
"repo": "default",
-
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-
"type": "github"
-
},
-
"original": {
-
"owner": "nix-systems",
-
"repo": "default",
-
"type": "github"
-
}
-
},
-
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+3 -4
flake.nix
···
description = "Yet another Discord mod";
inputs = {
-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
-
pnpm2nix.url = "github:NotNite/pnpm2nix-nzbr";
};
-
outputs = { self, nixpkgs, flake-utils, pnpm2nix }:
-
let overlay = import ./nix/overlay.nix { inherit pnpm2nix; };
+
outputs = { self, nixpkgs, flake-utils }:
+
let overlay = import ./nix/overlay.nix { };
in flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
+40 -17
nix/default.nix
···
-
{ pkgs, mkPnpmPackage }:
+
{
+
lib,
+
stdenv,
+
nodejs_22,
+
pnpm_10,
+
}:
+
+
stdenv.mkDerivation (finalAttrs: {
+
pname = "moonlight";
+
version = (builtins.fromJSON (builtins.readFile ./../package.json)).version;
-
mkPnpmPackage rec {
-
workspace = ./..;
src = ./..;
-
# Work around a bug with how it expects dist
-
components = [
-
"packages/core"
-
"packages/core-extensions"
-
"packages/injector"
-
"packages/node-preload"
-
"packages/types"
-
"packages/web-preload"
+
nativeBuildInputs = [
+
nodejs_22
+
pnpm_10.configHook
];
-
distDirs = [ "dist" ];
+
+
pnpmDeps = pnpm_10.fetchDeps {
+
inherit (finalAttrs) pname version src;
+
hash = "sha256-I+zRCUqJabpGJRFBGW0NrM9xzyzeCjioF54zlCpynBU=";
+
};
-
copyNodeModules = true;
-
buildPhase = "pnpm run build";
-
installPhase = "cp -r dist $out";
+
env = {
+
NODE_ENV = "production";
+
MOONLIGHT_VERSION = "v${finalAttrs.version}";
+
};
+
+
buildPhase = ''
+
runHook preBuild
-
meta = with pkgs.lib; {
+
pnpm run build
+
+
runHook postBuild
+
'';
+
+
installPhase = ''
+
runHook preInstall
+
+
cp -r dist $out
+
+
runHook postInstall
+
'';
+
+
meta = with lib; {
description = "Yet another Discord mod";
homepage = "https://moonlight-mod.github.io/";
license = licenses.lgpl3;
maintainers = with maintainers; [ notnite ];
};
-
}
+
})
+3 -6
nix/overlay.nix
···
-
{ pnpm2nix }:
+
{ ... }:
let
nameTable = {
···
'';
packageJson = ''
-
{"name":"discord","main":"./injector.js","private":true}
+
{"name":"${name}","main":"./injector.js","private":true}
'';
in old.installPhase + "\n" + ''
···
'';
});
in final: prev: rec {
-
moonlight-mod = final.callPackage ./default.nix {
-
pkgs = final;
-
mkPnpmPackage = pnpm2nix.packages.${final.system}.mkPnpmPackage;
-
};
+
moonlight-mod = final.callPackage ./default.nix { };
discord = mkOverride prev moonlight-mod "discord";
discord-ptb = mkOverride prev moonlight-mod "discord-ptb";
discord-canary = mkOverride prev moonlight-mod "discord-canary";
+1 -1
package.json
···
{
"name": "moonlight",
-
"version": "1.3.11",
+
"version": "1.3.14",
"packageManager": "pnpm@10.7.1",
"description": "Yet another Discord mod",
"license": "LGPL-3.0-or-later",
+2 -1
packages/browser/blockLoading.json
···
"type": "block"
},
"condition": {
-
"urlFilter": "*://discord.com/assets/*.js",
+
"requestDomains": ["discord.com", "discordapp.com"],
+
"urlFilter": "*/assets/*.js",
"resourceTypes": ["script"]
}
}
+9 -4
packages/browser/manifest.json
···
"manifest_version": 3,
"name": "moonlight",
"description": "Yet another Discord mod",
-
"version": "1.3.11",
+
"version": "1.3.14",
"permissions": ["declarativeNetRequestWithHostAccess", "webRequest", "scripting", "webNavigation"],
-
"host_permissions": ["https://moonlight-mod.github.io/*", "https://api.github.com/*", "https://*.discord.com/*"],
+
"host_permissions": [
+
"https://moonlight-mod.github.io/*",
+
"https://api.github.com/*",
+
"https://*.discord.com/*",
+
"https://*.discordapp.com/*"
+
],
"content_scripts": [
{
"js": ["index.js"],
-
"matches": ["https://*.discord.com/*"],
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"],
"run_at": "document_start",
"world": "MAIN"
}
···
"web_accessible_resources": [
{
"resources": ["index.js"],
-
"matches": ["https://*.discord.com/*"]
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"]
}
]
}
+5 -5
packages/browser/manifestv2.json
···
"manifest_version": 2,
"name": "moonlight",
"description": "Yet another Discord mod",
-
"version": "1.3.11",
+
"version": "1.3.14",
"permissions": [
"webRequest",
"webRequestBlocking",
"scripting",
"webNavigation",
-
"https://*.discord.com/assets/*.js",
+
"https://*.discord.com/*",
+
"https://*.discordapp.com/*",
"https://moonlight-mod.github.io/*",
-
"https://api.github.com/*",
-
"https://*.discord.com/*"
+
"https://api.github.com/*"
],
"background": {
"scripts": ["background.js"]
···
"content_scripts": [
{
"js": ["index.js"],
-
"matches": ["https://*.discord.com/*"],
+
"matches": ["https://*.discord.com/*", "https://*.discordapp.com/*"],
"run_at": "document_start",
"world": "MAIN"
}
+55 -70
packages/browser/src/background-mv2.js
···
/* eslint-disable no-console */
/* eslint-disable no-undef */
-
const starterUrls = ["web.", "sentry."];
-
let blockLoading = true;
-
let doing = false;
-
let collectedUrls = new Set();
+
const scriptUrls = ["web.", "sentry."];
+
let blockedScripts = new Set();
-
chrome.webNavigation.onBeforeNavigate.addListener(async (details) => {
-
const url = new URL(details.url);
-
if (!blockLoading && url.hostname.endsWith("discord.com")) {
-
console.log("Blocking", details.url);
-
blockLoading = true;
-
collectedUrls.clear();
-
}
-
});
+
chrome.webRequest.onBeforeRequest.addListener(
+
async (details) => {
+
if (details.tabId === -1) return;
-
async function doTheThing(urls, tabId) {
-
console.log("Doing", urls, tabId);
+
const url = new URL(details.url);
+
const hasUrl = scriptUrls.some((scriptUrl) => {
+
return (
+
details.url.includes(scriptUrl) &&
+
!url.searchParams.has("inj") &&
+
(url.host.endsWith("discord.com") || url.host.endsWith("discordapp.com"))
+
);
+
});
+
if (hasUrl) blockedScripts.add(details.url);
-
blockLoading = false;
+
if (blockedScripts.size === scriptUrls.length) {
+
const blockedScriptsCopy = Array.from(blockedScripts);
+
blockedScripts.clear();
-
try {
-
await chrome.scripting.executeScript({
-
target: { tabId },
-
world: "MAIN",
-
args: [urls],
-
func: async (urls) => {
-
try {
-
await window._moonlightBrowserInit();
-
} catch (e) {
-
console.log(e);
-
}
+
setTimeout(async () => {
+
console.log("Starting moonlight");
+
await chrome.scripting.executeScript({
+
target: { tabId: details.tabId },
+
world: "MAIN",
+
args: [blockedScriptsCopy],
+
func: async (blockedScripts) => {
+
console.log("Initializing moonlight");
+
try {
+
await window._moonlightBrowserInit();
+
} catch (e) {
+
console.error(e);
+
}
-
const scripts = [...document.querySelectorAll("script")].filter(
-
(script) => script.src && urls.some((url) => url.includes(script.src))
-
);
+
console.log("Readding scripts");
+
try {
+
const scripts = [...document.querySelectorAll("script")].filter(
+
(script) => script.src && blockedScripts.some((url) => url.includes(script.src))
+
);
-
// backwards
-
urls.reverse();
-
for (const url of urls) {
-
const script = scripts.find((script) => url.includes(script.src));
-
console.log("adding new script", script);
+
blockedScripts.reverse();
+
for (const url of blockedScripts) {
+
if (url.includes("/sentry.")) continue;
-
const newScript = document.createElement("script");
-
for (const { name, value } of script.attributes) {
-
newScript.setAttribute(name, value);
+
const script = scripts.find((script) => url.includes(script.src));
+
const newScript = document.createElement("script");
+
for (const attr of script.attributes) {
+
if (attr.name === "src") attr.value += "?inj";
+
newScript.setAttribute(attr.name, attr.value);
+
}
+
script.remove();
+
document.documentElement.appendChild(newScript);
+
}
+
} catch (e) {
+
console.error(e);
+
}
}
-
-
script.remove();
-
document.documentElement.appendChild(newScript);
-
}
-
}
-
});
-
} catch (e) {
-
console.log(e);
-
}
-
-
doing = false;
-
collectedUrls.clear();
-
}
-
-
chrome.webRequest.onBeforeRequest.addListener(
-
async (details) => {
-
if (starterUrls.some((url) => details.url.includes(url))) {
-
console.log("Adding", details.url);
-
collectedUrls.add(details.url);
+
});
+
}, 0);
}
-
if (collectedUrls.size === starterUrls.length) {
-
if (doing) return;
-
if (!blockLoading) return;
-
doing = true;
-
const urls = [...collectedUrls];
-
const tabId = details.tabId;
-
-
// yes this is a load-bearing sleep
-
setTimeout(() => doTheThing(urls, tabId), 0);
-
}
-
-
if (blockLoading) return { cancel: true };
+
if (hasUrl) return { cancel: true };
},
{
-
urls: ["https://*.discord.com/assets/*.js"]
+
urls: ["https://*.discord.com/assets/*.js", "https://*.discordapp.com/assets/*.js"]
},
["blocking"]
);
···
)
};
},
-
{ urls: ["https://*.discord.com/*"] },
+
{ urls: ["https://*.discord.com/*", "https://*.discordapp.com/*"] },
["blocking", "responseHeaders"]
);
+37 -39
packages/browser/src/background.js
···
/* eslint-disable no-console */
/* eslint-disable no-undef */
-
const starterUrls = ["web.", "sentry."];
-
let blockLoading = true;
-
let doing = false;
-
let collectedUrls = new Set();
+
const scriptUrls = ["web.", "sentry."];
+
let blockedScripts = new Set();
chrome.webNavigation.onBeforeNavigate.addListener(async (details) => {
const url = new URL(details.url);
-
if (!blockLoading && url.hostname.endsWith("discord.com")) {
+
if (
+
!url.searchParams.has("inj") &&
+
(url.hostname.endsWith("discord.com") || url.hostname.endsWith("discordapp.com"))
+
) {
+
console.log("Enabling block ruleset");
await chrome.declarativeNetRequest.updateEnabledRulesets({
enableRulesetIds: ["modifyResponseHeaders", "blockLoading"]
});
-
blockLoading = true;
-
collectedUrls.clear();
}
});
chrome.webRequest.onBeforeRequest.addListener(
async (details) => {
if (details.tabId === -1) return;
-
if (starterUrls.some((url) => details.url.includes(url))) {
-
console.log("Adding", details.url);
-
collectedUrls.add(details.url);
-
}
-
if (collectedUrls.size === starterUrls.length) {
-
if (doing) return;
-
if (!blockLoading) return;
-
doing = true;
-
const urls = [...collectedUrls];
-
console.log("Doing", urls);
+
const url = new URL(details.url);
+
const hasUrl = scriptUrls.some((scriptUrl) => {
+
return (
+
details.url.includes(scriptUrl) &&
+
!url.searchParams.has("inj") &&
+
(url.hostname.endsWith("discord.com") || url.hostname.endsWith("discordapp.com"))
+
);
+
});
+
+
if (hasUrl) blockedScripts.add(details.url);
+
+
if (blockedScripts.size === scriptUrls.length) {
+
const blockedScriptsCopy = Array.from(blockedScripts);
+
blockedScripts.clear();
console.log("Running moonlight script");
try {
···
files: ["index.js"]
});
} catch (e) {
-
console.log(e);
+
console.error(e);
}
console.log("Initializing moonlight");
···
try {
await window._moonlightBrowserInit();
} catch (e) {
-
console.log(e);
+
console.error(e);
}
}
});
···
console.log(e);
}
-
console.log("Updating rulesets");
+
console.log("Disabling block ruleset");
try {
-
blockLoading = false;
await chrome.declarativeNetRequest.updateEnabledRulesets({
disableRulesetIds: ["blockLoading"],
enableRulesetIds: ["modifyResponseHeaders"]
});
} catch (e) {
-
console.log(e);
+
console.error(e);
}
console.log("Readding scripts");
···
await chrome.scripting.executeScript({
target: { tabId: details.tabId },
world: "MAIN",
-
args: [urls],
-
func: async (urls) => {
+
args: [blockedScriptsCopy],
+
func: async (blockedScripts) => {
const scripts = [...document.querySelectorAll("script")].filter(
-
(script) => script.src && urls.some((url) => url.includes(script.src))
+
(script) => script.src && blockedScripts.some((url) => url.includes(script.src))
);
-
// backwards
-
urls.reverse();
-
for (const url of urls) {
-
const script = scripts.find((script) => url.includes(script.src));
-
console.log("adding new script", script);
+
blockedScripts.reverse();
+
for (const url of blockedScripts) {
+
if (url.includes("/sentry.")) continue;
+
const script = scripts.find((script) => url.includes(script.src));
const newScript = document.createElement("script");
-
for (const { name, value } of script.attributes) {
-
newScript.setAttribute(name, value);
+
for (const attr of script.attributes) {
+
if (attr.name === "src") attr.value += "?inj";
+
newScript.setAttribute(attr.name, attr.value);
}
-
script.remove();
document.documentElement.appendChild(newScript);
}
}
});
} catch (e) {
-
console.log(e);
+
console.error(e);
}
-
-
console.log("Done");
-
doing = false;
-
collectedUrls.clear();
}
},
{
-
urls: ["*://*.discord.com/assets/*.js"]
+
urls: ["*://*.discord.com/assets/*.js", "*://*.discordapp.com/assets/*.js"]
}
);
+1 -1
packages/core/src/patch.ts
···
const origModuleString = moduleCache[id];
let moduleString = origModuleString;
const patchedStr = [];
-
const mappedName = moonlight.moonmap.modules[id];
+
const mappedName = Object.entries(moonlight.moonmap.modules).find((m) => m[1] === id)?.[0];
let modified = false;
let swappedModule = false;
+12 -3
packages/core-extensions/src/commands/index.ts
···
}
},
{
-
find: ".icon,bot:null===",
+
find: ".icon,bot:null==",
replace: {
-
match: /(\.useMemo\(\(\)=>{)(if\((\i)\.type)/,
-
replacement: (_, before, after, section) => `${before}
+
match: /(\.useMemo\(\(\)=>{(var \i;)?)((return |if\()(\i)\.type)/,
+
replacement: (_, before, beforeVar, after, afterIf, section) => `${before}
if (${section}.id==="${APPLICATION_ID}") return "https://moonlight-mod.github.io/favicon.png";
${after}`
}
···
replace: {
match: /(\i)\.type===\i\.\i\.BUILT_IN/,
replacement: (orig, section) => `${section}.id!=="${APPLICATION_ID}"&&${orig}`
+
}
+
},
+
+
// tell it this app id is authorized
+
{
+
find: /let{customInstallUrl:\i,installParams:\i,integrationTypesConfig:\i}/,
+
replace: {
+
match: /\|\|(\i)===\i\.\i\.BUILT_IN/,
+
replacement: (orig, id) => `${orig}||${id}==="${APPLICATION_ID}"`
}
}
];
+3
packages/core-extensions/src/common/index.ts
···
},
ErrorBoundary: {
dependencies: [{ id: "react" }]
+
},
+
icons: {
+
dependencies: [{ id: "react" }, { id: "discord/components/common/index" }]
}
};
+1 -1
packages/core-extensions/src/common/manifest.json
···
"apiLevel": 2,
"meta": {
"name": "Common",
-
"tagline": "A *lot* of common clientmodding utilities from the Discord client",
+
"tagline": "Common client modding utilities for the Discord client",
"authors": ["Cynosphere", "NotNite"],
"tags": ["library"]
},
+31
packages/core-extensions/src/common/webpackModules/icons.ts
···
+
import { Icons, IconSize } from "@moonlight-mod/types/coreExtensions/common";
+
import { tokens } from "@moonlight-mod/wp/discord/components/common/index";
+
+
// This is defined in a Webpack module but we copy it here to be less breakage-prone
+
const sizes: Partial<Record<IconSize, number>> = {
+
xxs: 12,
+
xs: 16,
+
sm: 18,
+
md: 24,
+
lg: 32,
+
refresh_sm: 20
+
};
+
+
export const icons: Icons = {
+
parseProps(props) {
+
// NOTE: var() fallback is non-standard behavior, just for safety reasons
+
const color = props?.color ?? tokens?.colors?.["INTERACTIVE_NORMAL"] ?? "var(--interactive-normal)";
+
+
const size = sizes[props?.size ?? "md"];
+
+
return {
+
// note: this default size is also non-standard behavior, just for safety
+
width: size ?? props?.width ?? sizes.md!,
+
height: size ?? props?.width ?? sizes.md!,
+
+
fill: typeof color === "string" ? color : color.css,
+
className: props?.colorClass ?? ""
+
};
+
}
+
};
+
export default icons;
+6
packages/core-extensions/src/moonbase/index.tsx
···
{ id: "react" },
{ id: "discord/components/common/index" },
{ ext: "moonbase", id: "stores" },
+
{ ext: "moonbase", id: "ThemeDarkIcon" },
{ id: "discord/modules/guild_settings/web/AppCard.css" },
{ ext: "contextMenu", id: "contextMenu" },
{ id: "discord/modules/modals/Modals" },
···
'"Missing channel in Channel.openChannelContextMenu"',
".forumOrHome]:"
]
+
},
+
+
ThemeDarkIcon: {
+
dependencies: [{ ext: "common", id: "icons" }, { id: "react" }]
},
settings: {
···
dependencies: [
{ id: "react" },
{ ext: "moonbase", id: "stores" },
+
{ ext: "moonbase", id: "ThemeDarkIcon" },
{ ext: "notices", id: "notices" },
{
ext: "spacepack",
+12 -21
packages/core-extensions/src/moonbase/native.ts
···
export const userAgent = `moonlight/${moonlightGlobal.version} (https://github.com/moonlight-mod/moonlight)`;
+
// User-Agent header causes trouble on Firefox
+
const isBrowser = globalThis.moonlightNode != null && globalThis.moonlightNode.isBrowser;
+
const sharedHeaders: Record<string, string> = {};
+
if (!isBrowser) sharedHeaders["User-Agent"] = userAgent;
+
async function getStableRelease(): Promise<{
name: string;
assets: {
···
}> {
const req = await fetch(githubApiUrl, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
return await req.json();
}
···
} else if (moonlightGlobal.branch === MoonlightBranch.NIGHTLY) {
const req = await fetch(nightlyRefUrl, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
const ref = (await req.text()).split("\n")[0];
return ref !== moonlightGlobal.version ? ref : null;
···
logger.debug(`Downloading ${asset.browser_download_url}`);
const req = await fetch(asset.browser_download_url, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
return [await req.arrayBuffer(), json.name];
···
logger.debug(`Downloading ${nightlyZipUrl}`);
const zipReq = await fetch(nightlyZipUrl, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
const refReq = await fetch(nightlyRefUrl, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
const ref = (await refReq.text()).split("\n")[0];
···
try {
const req = await fetch(repo, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
const json = await req.json();
ret[repo] = json;
···
async installExtension(manifest, url, repo) {
const req = await fetch(url, {
cache: "no-store",
-
headers: {
-
"User-Agent": userAgent
-
}
+
headers: sharedHeaders
});
const dir = moonlightGlobal.getExtensionDir(manifest.id);
+36
packages/core-extensions/src/moonbase/webpackModules/ThemeDarkIcon.tsx
···
+
// RIP to ThemeDarkIcon ????-2025
+
// <Cynthia> Failed to remap "ThemeDarkIcon" in "discord/components/common/index"
+
// <NotNite> bro are you fucking kidding me
+
// <NotNite> that's literally the icon we use for the update banner
+
+
import React from "@moonlight-mod/wp/react";
+
import icons from "@moonlight-mod/wp/common_icons";
+
import type { IconProps } from "@moonlight-mod/types/coreExtensions/common";
+
+
export default function ThemeDarkIcon(props?: IconProps) {
+
const parsed = icons.parseProps(props);
+
+
return (
+
<svg
+
aria-hidden="true"
+
role="img"
+
xmlns="http://www.w3.org/2000/svg"
+
width={parsed.width}
+
height={parsed.height}
+
fill="none"
+
viewBox="0 0 24 24"
+
>
+
<path
+
fill={parsed.fill}
+
className={parsed.className}
+
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"
+
/>
+
+
<path
+
fill={parsed.fill}
+
className={parsed.className}
+
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"
+
/>
+
</svg>
+
);
+
}
+1 -1
packages/core-extensions/src/moonbase/webpackModules/ui/update.tsx
···
import MarkupUtils from "@moonlight-mod/wp/discord/modules/markup/MarkupUtils";
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
import {
-
ThemeDarkIcon,
Button,
Text,
ModalRoot,
···
openModal
} from "@moonlight-mod/wp/discord/components/common/index";
import MarkupClasses from "@moonlight-mod/wp/discord/modules/messages/web/Markup.css";
+
import ThemeDarkIcon from "@moonlight-mod/wp/moonbase_ThemeDarkIcon";
const strings: Record<UpdateState, string> = {
[UpdateState.Ready]: "A new version of moonlight is available.",
+1 -1
packages/core-extensions/src/moonbase/webpackModules/updates.tsx
···
import Notices from "@moonlight-mod/wp/notices_notices";
import { MoonlightBranch } from "@moonlight-mod/types";
import React from "@moonlight-mod/wp/react";
-
import { ThemeDarkIcon } from "@moonlight-mod/wp/discord/components/common/index";
+
import ThemeDarkIcon from "@moonlight-mod/wp/moonbase_ThemeDarkIcon";
function plural(str: string, num: number) {
return `${str}${num > 1 ? "s" : ""}`;
+5
packages/core-extensions/src/moonbase/wp.d.ts
···
declare module "@moonlight-mod/wp/moonbase_stores" {
export * from "core-extensions/src/moonbase/webpackModules/stores";
}
+
+
declare module "@moonlight-mod/wp/moonbase_ThemeDarkIcon" {
+
import ThemeDarkIcon from "core-extensions/src/moonbase/webpackModules/ThemeDarkIcon";
+
export = ThemeDarkIcon;
+
}
+1 -1
packages/core-extensions/src/settings/index.ts
···
{
find: 'navId:"user-settings-cog",',
replace: {
-
match: /children:\[(.)\.map\(.+?\),children:.\((.)\)/,
+
match: /children:\[(\i)\.map\(.+?\),.*?children:\i\((\i)\)/,
replacement: (orig, sections, section) =>
`${orig.replace(
/Object\.values\(.\..+?\)/,
+2 -2
packages/types/package.json
···
{
"name": "@moonlight-mod/types",
-
"version": "1.3.14",
+
"version": "1.3.17",
"exports": {
".": "./src/index.ts",
"./import": "./src/import.d.ts",
···
},
"dependencies": {
"@moonlight-mod/lunast": "^1.0.1",
-
"@moonlight-mod/mappings": "^1.1.22",
+
"@moonlight-mod/mappings": "^1.1.25",
"@moonlight-mod/moonmap": "^1.0.5",
"@types/react": "^18.3.10",
"csstype": "^3.1.3",
+22
packages/types/src/coreExtensions/common.ts
···
+
import type { IconProps, IconSize } from "@moonlight-mod/mappings/discord/components/common/index";
+
export type ErrorBoundaryProps = React.PropsWithChildren<{
noop?: boolean;
fallback?: React.FC<any>;
···
error?: Error;
componentStack?: string;
};
+
+
export type ErrorBoundary = React.ComponentClass<ErrorBoundaryProps, ErrorBoundaryState>;
+
+
export type ParsedIconProps = {
+
width: number;
+
height: number;
+
fill: string;
+
className: string;
+
};
+
+
export interface Icons {
+
/**
+
* Parse icon props into their actual width/height.
+
* @param props The icon props
+
*/
+
parseProps(props?: IconProps): ParsedIconProps;
+
}
+
+
// Re-export so extension developers don't need to depend on mappings
+
export type { IconProps, IconSize };
+4
packages/types/src/discord/require.ts
···
import { AppPanels } from "../coreExtensions/appPanels";
import { Commands } from "../coreExtensions/commands";
+
import { ErrorBoundary, Icons } from "../coreExtensions/common";
import { DMList, MemberList, Messages } from "../coreExtensions/componentEditor";
import { ContextMenu, EvilItemParser } from "../coreExtensions/contextMenu";
import { Markdown } from "../coreExtensions/markdown";
···
declare function WebpackRequire(id: "appPanels_appPanels"): AppPanels;
declare function WebpackRequire(id: "commands_commands"): Commands;
+
+
declare function WebpackRequire(id: "common_ErrorBoundary"): ErrorBoundary;
+
declare function WebpackRequire(id: "common_icons"): Icons;
declare function WebpackRequire(id: "componentEditor_dmList"): DMList;
declare function WebpackRequire(id: "componentEditor_memberList"): MemberList;
+10 -1
packages/types/src/import.d.ts
···
export default commands;
}
-
declare module "@moonlight-mod/wp/common_ErrorBoundary";
+
declare module "@moonlight-mod/wp/common_ErrorBoundary" {
+
import { CoreExtensions } from "@moonlight-mod/types";
+
const ErrorBoundary: CoreExtensions.Common.ErrorBoundary;
+
export = ErrorBoundary;
+
}
+
declare module "@moonlight-mod/wp/common_icons" {
+
import { CoreExtensions } from "@moonlight-mod/types";
+
export const icons: CoreExtensions.Common.Icons;
+
export default icons;
+
}
declare module "@moonlight-mod/wp/common_stores";
declare module "@moonlight-mod/wp/componentEditor_dmList" {
-1
packages/types/src/mappings.d.ts
···
export const ScienceIcon: MappedModules["discord/components/common/index"]["ScienceIcon"];
export const ScreenIcon: MappedModules["discord/components/common/index"]["ScreenIcon"];
export const StarIcon: MappedModules["discord/components/common/index"]["StarIcon"];
-
export const ThemeDarkIcon: MappedModules["discord/components/common/index"]["ThemeDarkIcon"];
export const TrashIcon: MappedModules["discord/components/common/index"]["TrashIcon"];
export const WarningIcon: MappedModules["discord/components/common/index"]["WarningIcon"];
export const WindowLaunchIcon: MappedModules["discord/components/common/index"]["WindowLaunchIcon"];
+16 -9
pnpm-lock.yaml
···
specifier: ^1.0.1
version: 1.0.1
'@moonlight-mod/mappings':
-
specifier: ^1.1.22
-
version: 1.1.22
+
specifier: ^1.1.25
+
version: 1.1.25
'@moonlight-mod/moonmap':
specifier: ^1.0.5
version: 1.0.5
···
specifier: ^1.0.1
version: 1.0.1
'@moonlight-mod/mappings':
-
specifier: ^1.1.22
-
version: 1.1.22(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
+
specifier: ^1.1.25
+
version: 1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
'@moonlight-mod/moonmap':
specifier: ^1.0.5
version: 1.0.5
···
version: 1.0.1
'@moonlight-mod/mappings':
specifier: catalog:prod
-
version: 1.1.22(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
+
version: 1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)
'@moonlight-mod/moonmap':
specifier: catalog:prod
version: 1.0.5
···
'@moonlight-mod/lunast@1.0.1':
resolution: {integrity: sha512-K3vxzDlfFuYKjciIW2FMlcZ1qrrkAGDGpSBlNqYGtJ0sMt9bRCd2lpSpg6AX/giSljDtmAUXa/5mOfUoDQxjBA==}
-
'@moonlight-mod/mappings@1.1.22':
-
resolution: {integrity: sha512-GJjAz/DwaVg724vzOWbEzANbXVIWX8zWAohIh7y6eXCxvwAgq2KuP27iiFmx4RboHQvhWP0nwyqTuKF3A1Ttgw==}
+
'@moonlight-mod/mappings@1.1.25':
+
resolution: {integrity: sha512-bgnSN9H/IBdMGxGev6RQKXuzhQxwo1090NhIDHnflguZnjiu2pg/usPfh76bqyhxRuX4SS7tiZSNTwBoSflCLg==}
+
engines: {node: '>=22', npm: pnpm, pnpm: '>=10', yarn: pnpm}
peerDependencies:
'@moonlight-mod/lunast': ^1.0.1
'@moonlight-mod/moonmap': ^1.0.5
···
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
+
+
'@types/estree@1.0.7':
+
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
'@types/fbemitter@2.0.35':
resolution: {integrity: sha512-Xem6d7qUfmouCHntCrRYgDBwbf+WWRd6G+7WEFlEZFZ67LZXiYRvT2LV8wcZa6mIaAil95+ABQdKgB6hPIsnng==}
···
estree-toolkit: 1.7.8
meriyah: 6.0.1
-
'@moonlight-mod/mappings@1.1.22(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)':
+
'@moonlight-mod/mappings@1.1.25(@moonlight-mod/lunast@1.0.1)(@moonlight-mod/moonmap@1.0.5)':
dependencies:
'@moonlight-mod/lunast': 1.0.1
'@moonlight-mod/moonmap': 1.0.5
···
'@types/eslint@9.6.1':
dependencies:
-
'@types/estree': 1.0.6
+
'@types/estree': 1.0.7
'@types/json-schema': 7.0.15
optional: true
···
'@types/estree': 1.0.6
'@types/estree@1.0.6': {}
+
+
'@types/estree@1.0.7':
+
optional: true
'@types/fbemitter@2.0.35': {}
+1 -1
pnpm-workspace.yaml
···
taze: ^19.0.4
prod:
"@moonlight-mod/lunast": ^1.0.1
-
"@moonlight-mod/mappings": ^1.1.22
+
"@moonlight-mod/mappings": ^1.1.25
"@moonlight-mod/moonmap": ^1.0.5
microdiff: ^1.5.0
nanotar: ^0.1.1