+6
nix/default.nix
+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
+6
-1
packages/browser/manifestv2.json
+4
packages/browser/src/index.ts
+4
packages/browser/src/index.ts
+3
packages/core/src/fs.ts
+3
packages/core/src/fs.ts
+2
-1
packages/core-extensions/src/componentEditor/index.ts
+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
+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
+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
+2
-2
packages/core-extensions/src/moonbase/webpackModules/settings.tsx
+30
-10
packages/core-extensions/src/moonbase/webpackModules/stores.ts
+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
+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
}))