this repo has no description

Compare changes

Choose any two refs to compare.

Changed files
+142 -34
nix
packages
browser
core
src
core-extensions
src
componentEditor
experiments
moonbase
quietLoggers
types
src
+6
nix/default.nix
··· 11 11 12 12 src = ./..; 13 13 14 + outputs = [ "out" "firefox" ]; 15 + 14 16 nativeBuildInputs = [ 15 17 nodejs_22 16 18 pnpm_10.configHook ··· 30 32 runHook preBuild 31 33 32 34 pnpm run build 35 + pnpm run browser-mv2 33 36 34 37 runHook postBuild 35 38 ''; ··· 38 41 runHook preInstall 39 42 40 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} 41 47 42 48 runHook postInstall 43 49 '';
+6 -1
packages/browser/manifestv2.json
··· 24 24 "run_at": "document_start", 25 25 "world": "MAIN" 26 26 } 27 - ] 27 + ], 28 + "browser_specific_settings": { 29 + "gecko": { 30 + "id": "{0fb6d66f-f22d-4555-a87b-34ef4bea5e2a}" 31 + } 32 + } 28 33 }
+4
packages/browser/src/index.ts
··· 90 90 dirname(path) { 91 91 const parts = getParts(path); 92 92 return "/" + parts.slice(0, parts.length - 1).join("/"); 93 + }, 94 + basename(path) { 95 + const parts = getParts(path); 96 + return parts[parts.length - 1]; 93 97 } 94 98 }, 95 99 // TODO
+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 }
+2 -1
packages/core-extensions/src/componentEditor/index.ts
··· 27 27 find: ".lostPermission", 28 28 replace: [ 29 29 { 30 - match: /(?<=\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[\i\(\),.+?\i\(\)])/, 30 + match: 31 + /(?<=\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[\(0,\i\.jsx\)\(\i,{user:\i}\),.+?onClickPremiumGuildIcon:\i}\)])/, 31 32 replacement: (_, decorators) => 32 33 `children:require("componentEditor_memberList").default._patchDecorators(${decorators},arguments[0])` 33 34 },
+4 -4
packages/core-extensions/src/experiments/index.ts
··· 20 20 { 21 21 find: ".HEADER_BAR)", 22 22 replace: { 23 - match: /&&\((.)\?\(0,/, 23 + match: /&&\((\i)\?\(0,/, 24 24 replacement: (_, isStaff) => 25 25 `&&(((moonlight.getConfigOption("experiments","devtools")??false)?true:${isStaff})?(0,` 26 26 } ··· 47 47 { 48 48 find: "shouldShowLurkerModeUpsellPopout:", 49 49 replace: { 50 - match: /\.useReducedMotion,isStaff:(.),/, 51 - replacement: (_, isStaff) => 52 - `.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}` 53 53 } 54 54 } 55 55 ];
+2 -2
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
··· 84 84 } 85 85 86 86 function ExtensionDisableCard({ ext }: { ext: DetectedExtension }) { 87 - function disableWithDependents() { 87 + async function disableWithDependents() { 88 88 const disable = new Set<string>(); 89 89 disable.add(ext.id); 90 90 for (const [id, dependencies] of moonlightNode.processedExtensions.dependencyGraph) { ··· 105 105 msg += "?"; 106 106 107 107 if (confirm(msg)) { 108 - moonlightNode.writeConfig(config); 108 + await moonlightNode.writeConfig(config); 109 109 window.location.reload(); 110 110 } 111 111 }
+2 -2
packages/core-extensions/src/moonbase/webpackModules/settings.tsx
··· 19 19 onReset={() => { 20 20 MoonbaseSettingsStore.reset(); 21 21 }} 22 - onSave={() => { 23 - MoonbaseSettingsStore.writeConfig(); 22 + onSave={async () => { 23 + await MoonbaseSettingsStore.writeConfig(); 24 24 }} 25 25 /> 26 26 );
+30 -10
packages/core-extensions/src/moonbase/webpackModules/stores.ts
··· 13 13 import { mainRepo } from "@moonlight-mod/types/constants"; 14 14 import { checkExtensionCompat, ExtensionCompat } from "@moonlight-mod/core/extension/loader"; 15 15 import { CustomComponent } from "@moonlight-mod/types/coreExtensions/moonbase"; 16 + import { NodeEventType } from "@moonlight-mod/types/core/event"; 16 17 import { getConfigOption, setConfigOption } from "@moonlight-mod/core/util/config"; 17 18 import diff from "microdiff"; 18 19 ··· 78 79 }; 79 80 } 80 81 82 + // This is async but we're calling it without 81 83 this.checkUpdates(); 84 + 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 + }); 82 93 } 83 94 84 95 async checkUpdates() { ··· 239 250 let val = this.config.extensions[ext.id]; 240 251 241 252 if (val == null) { 242 - this.config.extensions[ext.id] = { enabled }; 253 + this.config.extensions[ext.id] = enabled; 243 254 this.modified = this.isModified(); 244 255 this.emitChange(); 245 256 return; ··· 499 510 return returnedAdvice; 500 511 } 501 512 502 - writeConfig() { 503 - this.submitting = true; 504 - this.restartAdvice = this.#computeRestartAdvice(); 505 - const modifiedRepos = diff(this.savedConfig.repositories, this.config.repositories); 513 + async writeConfig() { 514 + try { 515 + this.submitting = true; 516 + this.emitChange(); 506 517 507 - moonlightNode.writeConfig(this.config); 508 - this.savedConfig = this.clone(this.config); 518 + await moonlightNode.writeConfig(this.config); 519 + await this.processConfigChanged(); 520 + } finally { 521 + this.submitting = false; 522 + this.emitChange(); 523 + } 524 + } 509 525 510 - this.submitting = false; 526 + private async processConfigChanged() { 527 + this.savedConfig = this.clone(this.config); 528 + this.restartAdvice = this.#computeRestartAdvice(); 511 529 this.modified = false; 512 - this.emitChange(); 513 530 514 - if (modifiedRepos.length !== 0) this.checkUpdates(); 531 + const modifiedRepos = diff(this.savedConfig.repositories, this.config.repositories); 532 + if (modifiedRepos.length !== 0) await this.checkUpdates(); 533 + 534 + this.emitChange(); 515 535 } 516 536 517 537 reset() {
+82 -14
packages/core-extensions/src/quietLoggers/index.ts
··· 18 18 { 19 19 find: '("GatewaySocket")', 20 20 replace: { 21 - match: /.\.(info|log)(\(.+?\))(;|,)/g, 22 - 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: "(()=>{})(" 23 30 } 24 31 } 25 32 ]; ··· 30 37 // Patches to simply remove a logger call 31 38 const stubPatches = [ 32 39 // "sh" is not a valid locale. 33 - ["is not a valid locale", /void (.)\.error\(""\.concat\((.)," is not a valid locale\."\)\)/g], 34 - ['"[BUILD INFO] Release Channel: "', /new .{1,2}\.Z\(\)\.log\("\[BUILD INFO\] Release Channel: ".+?\)\),/], 35 - ['.APP_NATIVE_CRASH,"Storage"', /console\.log\("AppCrashedFatalReport lastCrash:",.,.\);/], 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\);/], 36 43 ['.APP_NATIVE_CRASH,"Storage"', 'void console.log("AppCrashedFatalReport: getLastCrash not supported.")'], 37 - ['"[NATIVE INFO] ', /new .{1,2}\.Z\(\)\.log\("\[NATIVE INFO] .+?\)\);/], 38 - ['"Spellchecker"', /.\.info\("Switching to ".+?"\(unavailable\)"\);?/g], 39 - ['throw Error("Messages are still loading.");', /console\.warn\("Unsupported Locale",.\),/], 40 - ["}_dispatchWithDevtools(", /.\.totalTime>.{1,2}&&.\.verbose\(.+?\);/], 41 - ['"NativeDispatchUtils"', /null==.&&.\.warn\("Tried getting Dispatch instance before instantiated"\),/], 42 - ['("DatabaseManager")', /.\.log\("removing database \(user: ".+?\)\),/], 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"\),/], 43 49 [ 44 50 '"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. Action: "', 45 - /.\.has\(.\.type\)&&.\.log\(.+?\.type\)\),/ 51 + /\i\.has\(\i\.type\)&&\i\.log\(.+?\.type\)\),/ 46 52 ], 47 - ['console.warn("Window state not initialized"', /console\.warn\("Window state not initialized",.\),/] 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\),/ 66 + ], 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")' 48 99 ]; 49 100 50 101 const simplePatches = [ ··· 56 107 { 57 108 find: ".Messages.SELF_XSS_HEADER", 58 109 replace: { 59 - match: /\(null!=.{1,2}&&"0\.0\.0"===.{1,2}\.remoteApp\.getVersion\(\)\)/, 110 + match: /\(null!=\i&&"0\.0\.0"===\i\.remoteApp\.getVersion\(\)\)/, 60 111 replacement: "(true)" 61 112 } 62 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 + }, 63 123 // Highlight.js deprecation warnings 64 124 { 65 125 find: "Deprecated as of", ··· 92 152 replace: { 93 153 match: patch[0], 94 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: "(()=>{})(" 95 163 }, 96 164 prerequisite: notXssDefensesOnly 97 165 }))
+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 };