this repo has no description

Bump prettier to 120 columns

Changed files
+405 -1315
packages
browser
core
core-extensions
src
contextMenu
devToolsExtensions
disableSentry
webpackModules
markdown
webpackModules
moonbase
nativeFixes
notices
quietLoggers
rocketship
settings
webpackModules
spacepack
webpackModules
injector
src
node-preload
src
types
web-preload
src
+1 -1
.prettierrc
···
{
-
"printWidth": 80,
+
"printWidth": 120,
"trailingComma": "none",
"tabWidth": 2,
"singleQuote": false
+1 -1
package.json
···
"browser": "node build.mjs --browser",
"browser-mv2": "node build.mjs --browser --mv2",
"lint": "eslint packages",
-
"lint:fix": "eslint packages",
+
"lint:fix": "eslint packages --fix",
"lint:report": "eslint --output-file eslint_report.json --format json packages",
"typecheck": "tsc --noEmit",
"check": "pnpm run lint && pnpm run typecheck",
+1 -2
packages/browser/src/background.js
···
args: [urls],
func: async (urls) => {
const scripts = [...document.querySelectorAll("script")].filter(
-
(script) =>
-
script.src && urls.some((url) => url.includes(script.src))
+
(script) => script.src && urls.some((url) => url.includes(script.src))
);
// backwards
+4 -12
packages/core-extensions/src/contextMenu/index.tsx
···
find: "Menu API only allows Items and groups of Items as children.",
replace: [
{
-
match:
-
/(?<=let{navId[^}]+?}=(.),(.)=function .\(.\){.+(?=,.=function))/,
+
match: /(?<=let{navId[^}]+?}=(.),(.)=function .\(.\){.+(?=,.=function))/,
replacement: (_, props, items) =>
`,__contextMenu=!${props}.__contextMenu_evilMenu&&require("contextMenu_contextMenu")._patchMenu(${props}, ${items})`
}
···
replace: [
{
match: /(?<=let\{[^}]+?\}=.;return ).\({[^}]+?}\)/,
-
replacement: (render) =>
-
`require("contextMenu_contextMenu")._saveProps(this,${render})`
+
replacement: (render) => `require("contextMenu_contextMenu")._saveProps(this,${render})`
}
]
}
···
export const webpackModules: Record<string, ExtensionWebpackModule> = {
contextMenu: {
-
dependencies: [
-
{ ext: "spacepack", id: "spacepack" },
-
"Menu API only allows Items and groups of Items as children."
-
]
+
dependencies: [{ ext: "spacepack", id: "spacepack" }, "Menu API only allows Items and groups of Items as children."]
},
evilMenu: {
-
dependencies: [
-
{ ext: "spacepack", id: "spacepack" },
-
"Menu API only allows Items and groups of Items as children."
-
]
+
dependencies: [{ ext: "spacepack", id: "spacepack" }, "Menu API only allows Items and groups of Items as children."]
}
};
+4 -18
packages/core-extensions/src/contextMenu/webpackModules/contextMenu.ts
···
-
import {
-
InternalItem,
-
MenuElement,
-
MenuProps
-
} from "@moonlight-mod/types/coreExtensions/contextMenu";
+
import { InternalItem, MenuElement, MenuProps } from "@moonlight-mod/types/coreExtensions/contextMenu";
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
import parser from "@moonlight-mod/wp/contextMenu_evilMenu";
type Patch = {
navId: string;
-
item: (
-
props: any
-
) =>
-
| React.ReactComponentElement<MenuElement>
-
| React.ReactComponentElement<MenuElement>[];
+
item: (props: any) => React.ReactComponentElement<MenuElement> | React.ReactComponentElement<MenuElement>[];
anchorId: string;
before: boolean;
};
function addItem<T>(
navId: string,
-
item: (
-
props: T
-
) =>
-
| React.ReactComponentElement<MenuElement>
-
| React.ReactComponentElement<MenuElement>[],
+
item: (props: T) => React.ReactComponentElement<MenuElement> | React.ReactComponentElement<MenuElement>[],
anchorId: string,
before = false
) {
···
// Unmangle Menu elements
const code =
spacepack.require.m[
-
spacepack.findByCode(
-
"Menu API only allows Items and groups of Items as children."
-
)[0].id
+
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
].toString();
let MangledMenu;
+3 -13
packages/core-extensions/src/contextMenu/webpackModules/evilMenu.ts
···
let code =
spacepack.require.m[
-
spacepack.findByCode(
-
"Menu API only allows Items and groups of Items as children."
-
)[0].id
+
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
].toString();
code = code.replace(/,.=(?=function .\(.\){.+?,.=function)/, ";return ");
code = code.replace(/,(?=__contextMenu)/, ";let ");
-
const mod = new Function(
-
"module",
-
"exports",
-
"require",
-
`(${code}).apply(this, arguments)`
-
);
+
const mod = new Function("module", "exports", "require", `(${code}).apply(this, arguments)`);
const exp: any = {};
mod({}, exp, require);
-
const Menu = spacepack.findFunctionByStrings(
-
exp,
-
"Menu API only allows Items and groups of Items as children."
-
)!;
+
const Menu = spacepack.findFunctionByStrings(exp, "Menu API only allows Items and groups of Items as children.")!;
module.exports = (el: any) => {
return Menu({
children: el,
+1 -3
packages/core-extensions/src/devToolsExtensions/host.ts
···
const logger = new Logger("DevTools Extensions");
app.whenReady().then(async () => {
-
const paths =
-
moonlightHost.getConfigOption<string[]>("devToolsExtensions", "paths") ??
-
[];
+
const paths = moonlightHost.getConfigOption<string[]>("devToolsExtensions", "paths") ?? [];
for (const path of paths) {
const resolved = resolve(path);
+2 -7
packages/core-extensions/src/disableSentry/host.ts
···
if (moonlightHost.asarPath !== "moonlightDesktop") {
try {
-
const hostSentryPath = require.resolve(
-
join(moonlightHost.asarPath, "node_modules", "@sentry", "electron")
-
);
-
require.cache[hostSentryPath] = new Module(
-
hostSentryPath,
-
require.cache[require.resolve(moonlightHost.asarPath)]
-
);
+
const hostSentryPath = require.resolve(join(moonlightHost.asarPath, "node_modules", "@sentry", "electron"));
+
require.cache[hostSentryPath] = new Module(hostSentryPath, require.cache[require.resolve(moonlightHost.asarPath)]);
require.cache[hostSentryPath]!.exports = {
init: () => {},
captureException: () => {},
+2 -7
packages/core-extensions/src/disableSentry/node.ts
···
if (!ipcRenderer.sendSync(constants.ipcGetIsMoonlightDesktop)) {
const preloadPath = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
try {
-
const sentryPath = require.resolve(
-
resolve(preloadPath, "..", "node_modules", "@sentry", "electron")
-
);
-
require.cache[sentryPath] = new Module(
-
sentryPath,
-
require.cache[require.resolve(preloadPath)]
-
);
+
const sentryPath = require.resolve(resolve(preloadPath, "..", "node_modules", "@sentry", "electron"));
+
require.cache[sentryPath] = new Module(sentryPath, require.cache[require.resolve(preloadPath)]);
require.cache[sentryPath]!.exports = {
init: () => {},
setTag: () => {},
+1 -2
packages/core-extensions/src/disableSentry/webpackModules/stub.ts
···
throw Error("crash");
};
} else if (keys.includes(prop.toString())) {
-
return (...args: any[]) =>
-
logger.debug(`Sentry calling "${prop.toString()}":`, ...args);
+
return (...args: any[]) => logger.debug(`Sentry calling "${prop.toString()}":`, ...args);
} else {
return undefined;
}
+5 -17
packages/core-extensions/src/markdown/index.ts
···
replace: [
{
match: /={newline:(.+?)},(.{1,2})=\(0,/,
-
replacement: (_, rules, RULES) =>
-
`=require("markdown_markdown")._addRules({newline:${rules}}),${RULES}=(0,`
+
replacement: (_, rules, RULES) => `=require("markdown_markdown")._addRules({newline:${rules}}),${RULES}=(0,`
},
{
match: /(?<=;(.{1,2}\.Z)={RULES:.+?})/,
-
replacement: (_, rulesets) =>
-
`;require("markdown_markdown")._applyRulesetBlacklist(${rulesets});`
+
replacement: (_, rulesets) => `;require("markdown_markdown")._applyRulesetBlacklist(${rulesets});`
}
]
},
···
`__slateRules,${rulesDef}=__slateRules=require("markdown_markdown")._addSlateRules({link:{${rules}}),${syntaxBefore}=new Set`
},
{
-
match:
-
/(originalMatch:.}=(.);)(.+?)case"emoticon":(return .+?;)(.+?)case"subtext":{(.+?)}default:/,
-
replacement: (
-
_,
-
start,
-
rule,
-
body,
-
plaintextReturn,
-
otherRules,
-
inlineStyleBody
-
) =>
+
match: /(originalMatch:.}=(.);)(.+?)case"emoticon":(return .+?;)(.+?)case"subtext":{(.+?)}default:/,
+
replacement: (_, start, rule, body, plaintextReturn, otherRules, inlineStyleBody) =>
`${start}if(${rule}.type.startsWith("__moonlight_")){if(__slateRules[${rule}.type].type=="inlineStyle"){${inlineStyleBody}}else{${plaintextReturn}}}${body}case"emoticon":${plaintextReturn}${otherRules}case"link":{${inlineStyleBody}}default:`
}
]
···
find: '"Slate: Unknown decoration attribute: "',
replace: {
match: /=({strong:.+?});/,
-
replacement: (_, rules) =>
-
`=require("markdown_markdown")._addSlateDecorators(${rules});`
+
replacement: (_, rules) => `=require("markdown_markdown")._addSlateDecorators(${rules});`
}
}
];
+4 -16
packages/core-extensions/src/markdown/webpackModules/markdown.ts
···
-
import {
-
MarkdownRule,
-
Ruleset,
-
SlateRule
-
} from "@moonlight-mod/types/coreExtensions/markdown";
+
import { MarkdownRule, Ruleset, SlateRule } from "@moonlight-mod/types/coreExtensions/markdown";
-
export const rules: Record<
-
string,
-
(rules: Record<string, MarkdownRule>) => MarkdownRule
-
> = {};
-
export const slateRules: Record<
-
string,
-
(rules: Record<string, SlateRule>) => SlateRule
-
> = {};
+
export const rules: Record<string, (rules: Record<string, MarkdownRule>) => MarkdownRule> = {};
+
export const slateRules: Record<string, (rules: Record<string, SlateRule>) => SlateRule> = {};
export const slateDecorators: Record<string, string> = {};
export const ruleBlacklists: Record<Ruleset, Record<string, boolean>> = {
RULES: {},
···
return originalRules;
}
-
export function _applyRulesetBlacklist(
-
rulesets: Record<Ruleset, Record<string, MarkdownRule>>
-
) {
+
export function _applyRulesetBlacklist(rulesets: Record<Ruleset, Record<string, MarkdownRule>>) {
for (const ruleset of Object.keys(rulesets) as Ruleset[]) {
if (ruleset === "RULES") continue;
+1 -4
packages/core-extensions/src/moonbase/index.tsx
···
export const webpackModules: Record<string, ExtensionWebpackModule> = {
stores: {
-
dependencies: [
-
{ id: "discord/packages/flux" },
-
{ id: "discord/Dispatcher" }
-
]
+
dependencies: [{ id: "discord/packages/flux" }, { id: "discord/Dispatcher" }]
},
ui: {
+5 -17
packages/core-extensions/src/moonbase/native.ts
···
import { MoonlightBranch } from "@moonlight-mod/types";
import type { MoonbaseNatives, RepositoryManifest } from "./types";
import extractAsar from "@moonlight-mod/core/asar";
-
import {
-
distDir,
-
repoUrlFile,
-
installedVersionFile
-
} from "@moonlight-mod/types/constants";
+
import { distDir, repoUrlFile, installedVersionFile } from "@moonlight-mod/types/constants";
import { parseTarGzip } from "nanotar";
const githubRepo = "moonlight-mod/moonlight";
···
const fullFile = moonlightFS.join(dist, file.name);
const fullDir = moonlightFS.dirname(fullFile);
-
if (!(await moonlightFS.exists(fullDir)))
-
await moonlightFS.mkdir(fullDir);
+
if (!(await moonlightFS.exists(fullDir))) await moonlightFS.mkdir(fullDir);
await moonlightFS.writeFile(fullFile, file.data);
}
logger.debug("Writing version file:", ref);
-
const versionFile = moonlightFS.join(
-
moonlightNode.getMoonlightDir(),
-
installedVersionFile
-
);
+
const versionFile = moonlightFS.join(moonlightNode.getMoonlightDir(), installedVersionFile);
await moonlightFS.writeFileString(versionFile, ref.trim());
logger.debug("Update extracted");
···
const fullFile = moonlightFS.join(dir, file);
const fullDir = moonlightFS.dirname(fullFile);
-
if (!(await moonlightFS.exists(fullDir)))
-
await moonlightFS.mkdir(fullDir);
+
if (!(await moonlightFS.exists(fullDir))) await moonlightFS.mkdir(fullDir);
await moonlightFS.writeFile(moonlightFS.join(dir, file), buf);
}
-
await moonlightFS.writeFileString(
-
moonlightFS.join(dir, repoUrlFile),
-
repo
-
);
+
await moonlightFS.writeFileString(moonlightFS.join(dir, repoUrlFile), repo);
},
async deleteExtension(id) {
+2 -8
packages/core-extensions/src/moonbase/types.ts
···
checkForMoonlightUpdate(): Promise<string | null>;
updateMoonlight(): Promise<void>;
-
fetchRepositories(
-
repos: string[]
-
): Promise<Record<string, RepositoryManifest[]>>;
-
installExtension(
-
manifest: RepositoryManifest,
-
url: string,
-
repo: string
-
): Promise<void>;
+
fetchRepositories(repos: string[]): Promise<Record<string, RepositoryManifest[]>>;
+
installExtension(manifest: RepositoryManifest, url: string, repo: string): Promise<void>;
deleteExtension(id: string): Promise<void>;
getExtensionConfig(id: string, key: string): any;
};
+6 -29
packages/core-extensions/src/moonbase/webpackModules/settings.tsx
···
const Margins = spacepack.require("discord/styles/shared/Margins.css");
-
const { open } = spacepack.findByExports("setSection", "clearSubsection")[0]
-
.exports.Z;
+
const { open } = spacepack.findByExports("setSection", "clearSubsection")[0].exports.Z;
const notice = {
stores: [MoonbaseSettingsStore],
element: () => {
// Require it here because lazy loading SUX
-
const SettingsNotice = spacepack.findByCode(
-
"onSaveButtonColor",
-
"FocusRingScope"
-
)[0].exports.Z;
+
const SettingsNotice = spacepack.findByCode("onSaveButtonColor", "FocusRingScope")[0].exports.Z;
return (
<SettingsNotice
submitting={MoonbaseSettingsStore.submitting}
···
}
};
-
function addSection(
-
id: string,
-
name: string,
-
element: React.FunctionComponent
-
) {
+
function addSection(id: string, name: string, element: React.FunctionComponent) {
settings.addSection(`moonbase-${id}`, name, element, null, -2, notice);
}
···
function renderBreadcrumb(crumb: Breadcrumb, last: boolean) {
return (
-
<Text
-
variant="heading-lg/semibold"
-
tag="h2"
-
color={last ? "header-primary" : "header-secondary"}
-
>
+
<Text variant="heading-lg/semibold" tag="h2" color={last ? "header-primary" : "header-secondary"}>
{crumb.label}
</Text>
);
}
-
if (
-
MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
-
"moonbase",
-
"sections",
-
false
-
)
-
) {
+
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "sections", false)) {
settings.addHeader("Moonbase", -2);
for (const page of pages) {
···
settings.addSectionMenuItems(
"moonbase",
...pages.map((page, i) => (
-
<MenuItem
-
key={page.id}
-
id={`moonbase-${page.id}`}
-
label={page.name}
-
action={() => open("moonbase", i)}
-
/>
+
<MenuItem key={page.id} id={`moonbase-${page.id}`} label={page.name} action={() => open("moonbase", i)} />
))
);
}
+16 -55
packages/core-extensions/src/moonbase/webpackModules/stores.ts
···
import { Config, ExtensionLoadSource } from "@moonlight-mod/types";
-
import {
-
ExtensionState,
-
MoonbaseExtension,
-
MoonbaseNatives,
-
RepositoryManifest
-
} from "../types";
+
import { ExtensionState, MoonbaseExtension, MoonbaseNatives, RepositoryManifest } from "../types";
import { Store } from "@moonlight-mod/wp/discord/packages/flux";
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
import getNatives from "../native";
import { mainRepo } from "@moonlight-mod/types/constants";
-
import {
-
checkExtensionCompat,
-
ExtensionCompat
-
} from "@moonlight-mod/core/extension/loader";
+
import { checkExtensionCompat, ExtensionCompat } from "@moonlight-mod/core/extension/loader";
import { CustomComponent } from "@moonlight-mod/types/coreExtensions/moonbase";
const logger = moonlight.getLogger("moonbase");
···
private origConfig: Config;
private config: Config;
private extensionIndex: number;
-
private configComponents: Record<string, Record<string, CustomComponent>> =
-
{};
+
private configComponents: Record<string, Record<string, CustomComponent>> = {};
modified: boolean;
submitting: boolean;
···
this.extensions[uniqueId] = {
...ext,
uniqueId,
-
state: moonlight.enabledExtensions.has(ext.id)
-
? ExtensionState.Enabled
-
: ExtensionState.Disabled,
+
state: moonlight.enabledExtensions.has(ext.id) ? ExtensionState.Enabled : ExtensionState.Disabled,
compat: checkExtensionCompat(ext.manifest),
hasUpdate: false
};
···
};
// Don't present incompatible updates
-
if (checkExtensionCompat(ext) !== ExtensionCompat.Compatible)
-
continue;
+
if (checkExtensionCompat(ext) !== ExtensionCompat.Compatible) continue;
const existing = this.getExisting(extensionData);
if (existing != null) {
···
this.emitChange();
})
.then(() => {
-
this.shouldShowNotice =
-
this.newVersion != null || Object.keys(this.updates).length > 0;
+
this.shouldShowNotice = this.newVersion != null || Object.keys(this.updates).length > 0;
this.emitChange();
});
}
private getExisting(ext: MoonbaseExtension) {
-
return Object.values(this.extensions).find(
-
(e) => e.id === ext.id && e.source.url === ext.source.url
-
);
+
return Object.values(this.extensions).find((e) => e.id === ext.id && e.source.url === ext.source.url);
}
private hasUpdate(ext: MoonbaseExtension) {
-
const existing = Object.values(this.extensions).find(
-
(e) => e.id === ext.id && e.source.url === ext.source.url
-
);
+
const existing = Object.values(this.extensions).find((e) => e.id === ext.id && e.source.url === ext.source.url);
if (existing == null) return false;
-
return (
-
existing.manifest.version !== ext.manifest.version &&
-
existing.state !== ExtensionState.NotDownloaded
-
);
+
return existing.manifest.version !== ext.manifest.version && existing.state !== ExtensionState.NotDownloaded;
}
// Jank
···
}
getExtensionUniqueId(id: string) {
-
return Object.values(this.extensions).find((ext) => ext.id === id)
-
?.uniqueId;
+
return Object.values(this.extensions).find((ext) => ext.id === id)?.uniqueId;
}
getExtensionConflicting(uniqueId: number) {
const ext = this.getExtension(uniqueId);
if (ext.state !== ExtensionState.NotDownloaded) return false;
return Object.values(this.extensions).some(
-
(e) =>
-
e.id === ext.id &&
-
e.uniqueId !== uniqueId &&
-
e.state !== ExtensionState.NotDownloaded
+
(e) => e.id === ext.id && e.uniqueId !== uniqueId && e.state !== ExtensionState.NotDownloaded
);
}
···
return cfg.config?.[key] ?? clonedDefaultValue;
}
-
getExtensionConfigRaw<T>(
-
id: string,
-
key: string,
-
defaultValue: T | undefined
-
): T | undefined {
+
getExtensionConfigRaw<T>(id: string, key: string, defaultValue: T | undefined): T | undefined {
const cfg = this.config.extensions[id];
if (cfg == null || typeof cfg === "boolean") return defaultValue;
···
this.extensions[uniqueId].state = ExtensionState.Disabled;
}
-
if (update != null)
-
this.extensions[uniqueId].compat = checkExtensionCompat(
-
update.updateManifest
-
);
+
if (update != null) this.extensions[uniqueId].compat = checkExtensionCompat(update.updateManifest);
delete this.updates[uniqueId];
} catch (e) {
···
const deps: Record<string, MoonbaseExtension[]> = {};
for (const dep of missingDeps) {
-
const candidates = Object.values(this.extensions).filter(
-
(e) => e.id === dep
-
);
+
const candidates = Object.values(this.extensions).filter((e) => e.id === dep);
deps[dep] = candidates.sort((a, b) => {
const aRank = this.getRank(a);
const bRank = this.getRank(b);
if (aRank === bRank) {
const repoIndex = this.config.repositories.indexOf(a.source.url!);
-
const otherRepoIndex = this.config.repositories.indexOf(
-
b.source.url!
-
);
+
const otherRepoIndex = this.config.repositories.indexOf(b.source.url!);
return repoIndex - otherRepoIndex;
} else {
return bRank - aRank;
···
return (uniqueId != null ? this.getExtensionName(uniqueId) : null) ?? id;
}
-
registerConfigComponent(
-
ext: string,
-
name: string,
-
component: CustomComponent
-
) {
+
registerConfigComponent(ext: string, name: string, component: CustomComponent) {
if (!(ext in this.configComponents)) this.configComponents[ext] = {};
this.configComponents[ext][name] = component;
}
+8 -34
packages/core-extensions/src/moonbase/webpackModules/ui/config/index.tsx
···
import { LogLevel } from "@moonlight-mod/types";
-
const logLevels = Object.values(LogLevel).filter(
-
(v) => typeof v === "string"
-
) as string[];
+
const logLevels = Object.values(LogLevel).filter((v) => typeof v === "string") as string[];
import React from "@moonlight-mod/wp/react";
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
···
/\[(?:.\.e\("\d+?"\),?)+\][^}]+?webpackId:\d+,name:"GuildSettings"/,
/webpackId:(\d+),name:"GuildSettings"/
)
-
.then(
-
() =>
-
(RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0]
-
.exports)
-
);
+
.then(() => (RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0].exports));
// FIXME: type component keys
const { CircleXIcon } = Components;
···
<div className={RemoveButtonClasses.removeButtonContainer}>
<Tooltip text="Remove entry" position="top">
{(props: any) => (
-
<Clickable
-
{...props}
-
className={RemoveButtonClasses.removeButton}
-
onClick={onClick}
-
>
+
<Clickable {...props} className={RemoveButtonClasses.removeButton} onClick={onClick}>
<CircleXIcon width={24} height={24} />
</Clickable>
)}
···
);
}
-
function ArrayFormItem({
-
config
-
}: {
-
config: "repositories" | "devSearchPaths";
-
}) {
+
function ArrayFormItem({ config }: { config: "repositories" | "devSearchPaths" }) {
const items = MoonbaseSettingsStore.getConfigOption(config) ?? [];
return (
<Flex
···
<>
<FormSwitch
className={Margins.marginTop20}
-
value={MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
-
"moonbase",
-
"updateChecking",
-
true
-
)}
+
value={MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "updateChecking", true)}
onChange={(value: boolean) => {
-
MoonbaseSettingsStore.setExtensionConfig(
-
"moonbase",
-
"updateChecking",
-
value
-
);
+
MoonbaseSettingsStore.setExtensionConfig("moonbase", "updateChecking", value);
}}
note="Checks for updates to moonlight"
>
Automatic update checking
</FormSwitch>
<FormItem title="Repositories">
-
<FormText className={Margins.marginBottom4}>
-
A list of remote repositories to display extensions from
-
</FormText>
+
<FormText className={Margins.marginBottom4}>A list of remote repositories to display extensions from</FormText>
<ArrayFormItem config="repositories" />
</FormItem>
<FormDivider className={FormClasses.dividerDefault} />
···
value: o.toLowerCase(),
label: o[0] + o.slice(1).toLowerCase()
}))}
-
onChange={(v) =>
-
MoonbaseSettingsStore.setConfigOption("loggerLevel", v)
-
}
+
onChange={(v) => MoonbaseSettingsStore.setConfigOption("loggerLevel", v)}
/>
</FormItem>
</>
+28 -84
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/card.tsx
···
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
-
const { BeakerIcon, DownloadIcon, TrashIcon, CircleWarningIcon, Tooltip } =
-
Components;
+
const { BeakerIcon, DownloadIcon, TrashIcon, CircleWarningIcon, Tooltip } = Components;
const PanelButton = spacepack.findByCode("Masks.PANEL_BUTTON")[0].exports.Z;
-
const TabBarClasses = spacepack.findByExports(
-
"tabBar",
-
"tabBarItem",
-
"headerContentWrapper"
-
)[0].exports;
-
const MarkupClasses = spacepack.findByExports("markup", "inlineFormat")[0]
-
.exports;
+
const TabBarClasses = spacepack.findByExports("tabBar", "tabBarItem", "headerContentWrapper")[0].exports;
+
const MarkupClasses = spacepack.findByExports("markup", "inlineFormat")[0].exports;
-
const BuildOverrideClasses = spacepack.findByExports(
-
"disabledButtonOverride"
-
)[0].exports;
+
const BuildOverrideClasses = spacepack.findByExports("disabledButtonOverride")[0].exports;
const COMPAT_TEXT_MAP: Record<ExtensionCompat, string> = {
[ExtensionCompat.Compatible]: "huh?",
···
const [tab, setTab] = React.useState(ExtensionPage.Info);
const [restartNeeded, setRestartNeeded] = React.useState(false);
-
const { ext, enabled, busy, update, conflicting } = useStateFromStores(
-
[MoonbaseSettingsStore],
-
() => {
-
return {
-
ext: MoonbaseSettingsStore.getExtension(uniqueId),
-
enabled: MoonbaseSettingsStore.getExtensionEnabled(uniqueId),
-
busy: MoonbaseSettingsStore.busy,
-
update: MoonbaseSettingsStore.getExtensionUpdate(uniqueId),
-
conflicting: MoonbaseSettingsStore.getExtensionConflicting(uniqueId)
-
};
-
}
-
);
+
const { ext, enabled, busy, update, conflicting } = useStateFromStores([MoonbaseSettingsStore], () => {
+
return {
+
ext: MoonbaseSettingsStore.getExtension(uniqueId),
+
enabled: MoonbaseSettingsStore.getExtensionEnabled(uniqueId),
+
busy: MoonbaseSettingsStore.busy,
+
update: MoonbaseSettingsStore.getExtensionUpdate(uniqueId),
+
conflicting: MoonbaseSettingsStore.getExtensionConflicting(uniqueId)
+
};
+
});
// Why it work like that :sob:
if (ext == null) return <></>;
···
const enabledDependants = useStateFromStores([MoonbaseSettingsStore], () =>
Object.keys(MoonbaseSettingsStore.extensions)
.filter((uniqueId) => {
-
const potentialDependant = MoonbaseSettingsStore.getExtension(
-
parseInt(uniqueId)
-
);
+
const potentialDependant = MoonbaseSettingsStore.getExtension(parseInt(uniqueId));
return (
potentialDependant.manifest.dependencies?.includes(ext.id) &&
···
<div className={IntegrationCard.cardHeader}>
<Flex direction={Flex.Direction.VERTICAL}>
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.CENTER}>
-
<Text variant="text-md/semibold">
-
{ext.manifest?.meta?.name ?? ext.id}
-
</Text>
+
<Text variant="text-md/semibold">{ext.manifest?.meta?.name ?? ext.id}</Text>
{ext.source.type === ExtensionLoadSource.Developer && (
<Tooltip text="This is a local extension" position="top">
-
{(props: any) => (
-
<BeakerIcon
-
{...props}
-
class={BuildOverrideClasses.infoIcon}
-
size="xs"
-
/>
-
)}
+
{(props: any) => <BeakerIcon {...props} class={BuildOverrideClasses.infoIcon} size="xs" />}
</Tooltip>
)}
</Flex>
-
{tagline != null && (
-
<Text variant="text-sm/normal">{MarkupUtils.parse(tagline)}</Text>
-
)}
+
{tagline != null && <Text variant="text-sm/normal">{MarkupUtils.parse(tagline)}</Text>}
</Flex>
-
<Flex
-
direction={Flex.Direction.HORIZONTAL}
-
align={Flex.Align.END}
-
justify={Flex.Justify.END}
-
>
+
<Flex direction={Flex.Direction.HORIZONTAL} align={Flex.Align.END} justify={Flex.Justify.END}>
{ext.state === ExtensionState.NotDownloaded ? (
-
<Tooltip
-
text={COMPAT_TEXT_MAP[ext.compat]}
-
shouldShow={ext.compat !== ExtensionCompat.Compatible}
-
>
+
<Tooltip text={COMPAT_TEXT_MAP[ext.compat]} shouldShow={ext.compat !== ExtensionCompat.Compatible}>
{(props: any) => (
<Button
{...props}
color={Button.Colors.BRAND}
submitting={busy}
-
disabled={
-
ext.compat !== ExtensionCompat.Compatible || conflicting
-
}
+
disabled={ext.compat !== ExtensionCompat.Compatible || conflicting}
onClick={async () => {
await installWithDependencyPopup(uniqueId);
}}
···
{restartNeeded && (
<PanelButton
-
icon={() => (
-
<CircleWarningIcon
-
color={Components.tokens.colors.STATUS_DANGER}
-
/>
-
)}
+
icon={() => <CircleWarningIcon color={Components.tokens.colors.STATUS_DANGER} />}
onClick={() => window.location.reload()}
tooltipText="You will need to reload/restart your client for this extension to work properly."
/>
)}
<FormSwitch
-
value={
-
ext.compat === ExtensionCompat.Compatible &&
-
(enabled || implicitlyEnabled)
-
}
-
disabled={
-
implicitlyEnabled || ext.compat !== ExtensionCompat.Compatible
-
}
+
value={ext.compat === ExtensionCompat.Compatible && (enabled || implicitlyEnabled)}
+
disabled={implicitlyEnabled || ext.compat !== ExtensionCompat.Compatible}
hideBorder={true}
style={{ marginBottom: "0px" }}
tooltipNote={
···
: implicitlyEnabled
? `This extension is a dependency of the following enabled extension${
enabledDependants.length > 1 ? "s" : ""
-
}: ${enabledDependants
-
.map((a) => a.manifest.meta?.name ?? a.id)
-
.join(", ")}`
+
}: ${enabledDependants.map((a) => a.manifest.meta?.name ?? a.id).join(", ")}`
: undefined
}
onChange={() => {
···
padding: "0 20px"
}}
>
-
<TabBar.Item
-
className={TabBarClasses.tabBarItem}
-
id={ExtensionPage.Info}
-
>
+
<TabBar.Item className={TabBarClasses.tabBarItem} id={ExtensionPage.Info}>
Info
</TabBar.Item>
{description != null && (
-
<TabBar.Item
-
className={TabBarClasses.tabBarItem}
-
id={ExtensionPage.Description}
-
>
+
<TabBar.Item className={TabBarClasses.tabBarItem} id={ExtensionPage.Description}>
Description
</TabBar.Item>
)}
{settings != null && (
-
<TabBar.Item
-
className={TabBarClasses.tabBarItem}
-
id={ExtensionPage.Settings}
-
>
+
<TabBar.Item className={TabBarClasses.tabBarItem} id={ExtensionPage.Settings}>
Settings
</TabBar.Item>
)}
···
>
{tab === ExtensionPage.Info && <ExtensionInfo ext={ext} />}
{tab === ExtensionPage.Description && (
-
<Text
-
variant="text-md/normal"
-
class={MarkupClasses.markup}
-
style={{ width: "100%" }}
-
>
+
<Text variant="text-md/normal" class={MarkupClasses.markup} style={{ width: "100%" }}>
{MarkupUtils.parse(description ?? "*No description*", true, {
allowHeading: true,
allowLinks: true,
+17 -67
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/filterBar.tsx
···
export const defaultFilter = 127 as Filter;
const Margins = spacepack.findByCode("marginCenterHorz:")[0].exports;
-
const SortMenuClasses = spacepack.findByCode("container:", "clearText:")[0]
-
.exports;
+
const SortMenuClasses = spacepack.findByCode("container:", "clearText:")[0].exports;
let FilterDialogClasses: any;
let FilterBarClasses: any;
spacepack
-
.lazyLoad(
-
'"Missing channel in Channel.openChannelContextMenu"',
-
/e\("(\d+)"\)/g,
-
/webpackId:(\d+?),/
-
)
+
.lazyLoad('"Missing channel in Channel.openChannelContextMenu"', /e\("(\d+)"\)/g, /webpackId:(\d+?),/)
.then(() => {
FilterBarClasses = spacepack.findByCode("tagsButtonWithCount:")[0].exports;
-
FilterDialogClasses = spacepack.findByCode(
-
"countContainer:",
-
"tagContainer:"
-
)[0].exports;
+
FilterDialogClasses = spacepack.findByCode("countContainer:", "tagContainer:")[0].exports;
});
-
const TagItem = spacepack.findByCode(".FORUM_TAG_A11Y_FILTER_BY_TAG")[0].exports
-
.Z;
+
const TagItem = spacepack.findByCode(".FORUM_TAG_A11Y_FILTER_BY_TAG")[0].exports.Z;
// FIXME: type component keys
-
const { ChevronSmallDownIcon, ChevronSmallUpIcon, ArrowsUpDownIcon } =
-
Components;
+
const { ChevronSmallDownIcon, ChevronSmallUpIcon, ArrowsUpDownIcon } = Components;
-
function toggleTag(
-
selectedTags: Set<string>,
-
setSelectedTags: (tags: Set<string>) => void,
-
tag: string
-
) {
+
function toggleTag(selectedTags: Set<string>, setSelectedTags: (tags: Set<string>) => void, tag: string) {
const newState = new Set(selectedTags);
if (newState.has(tag)) newState.delete(tag);
else newState.add(tag);
···
setFilter: (filter: Filter) => void;
closePopout: () => void;
}) {
-
const toggleFilter = (set: Filter) =>
-
setFilter(filter & set ? filter & ~set : filter | set);
+
const toggleFilter = (set: Filter) => setFilter(filter & set ? filter & ~set : filter | set);
return (
<div className={SortMenuClasses.container}>
···
);
}
-
function TagButtonPopout({
-
selectedTags,
-
setSelectedTags,
-
setPopoutRef,
-
closePopout
-
}: any) {
+
function TagButtonPopout({ selectedTags, setSelectedTags, setPopoutRef, closePopout }: any) {
return (
<Dialog ref={setPopoutRef} className={FilterDialogClasses.container}>
<div className={FilterDialogClasses.header}>
<div className={FilterDialogClasses.headerLeft}>
-
<Heading
-
color="interactive-normal"
-
variant="text-xs/bold"
-
className={FilterDialogClasses.headerText}
-
>
+
<Heading color="interactive-normal" variant="text-xs/bold" className={FilterDialogClasses.headerText}>
Select tags
</Heading>
<div className={FilterDialogClasses.countContainer}>
-
<Text
-
className={FilterDialogClasses.countText}
-
color="none"
-
variant="text-xs/medium"
-
>
+
<Text className={FilterDialogClasses.countText} color="none" variant="text-xs/medium">
{selectedTags.size}
</Text>
</div>
···
selectedTags: Set<string>;
setSelectedTags: (tags: Set<string>) => void;
}) {
-
const windowSize = useStateFromStores([WindowStore], () =>
-
WindowStore.windowSize()
-
);
+
const windowSize = useStateFromStores([WindowStore], () => WindowStore.windowSize());
const tagsContainer = React.useRef<HTMLDivElement>(null);
const tagListInner = React.useRef<HTMLDivElement>(null);
const [tagsButtonOffset, setTagsButtonOffset] = React.useState(0);
React.useLayoutEffect(() => {
if (tagsContainer.current === null || tagListInner.current === null) return;
-
const { left: containerX, top: containerY } =
-
tagsContainer.current.getBoundingClientRect();
+
const { left: containerX, top: containerY } = tagsContainer.current.getBoundingClientRect();
let offset = 0;
for (const child of tagListInner.current.children) {
-
const {
-
right: childX,
-
top: childY,
-
height
-
} = child.getBoundingClientRect();
+
const { right: childX, top: childY, height } = child.getBoundingClientRect();
if (childY - containerY > height) break;
const newOffset = childX - containerX;
if (newOffset > offset) {
···
>
<Popout
renderPopout={({ closePopout }: any) => (
-
<FilterButtonPopout
-
filter={filter}
-
setFilter={setFilter}
-
closePopout={closePopout}
-
/>
+
<FilterButtonPopout filter={filter} setFilter={setFilter} closePopout={closePopout} />
)}
position="bottom"
align="left"
···
innerClassName={FilterBarClasses.sortDropdownInner}
>
<ArrowsUpDownIcon size="xs" />
-
<Text
-
className={FilterBarClasses.sortDropdownText}
-
variant="text-sm/medium"
-
color="interactive-normal"
-
>
+
<Text className={FilterBarClasses.sortDropdownText} variant="text-sm/medium" color="interactive-normal">
Sort & filter
</Text>
{isShown ? (
···
innerClassName={FilterBarClasses.tagsButtonInner}
>
{selectedTags.size > 0 ? (
-
<div
-
style={{ boxSizing: "content-box" }}
-
className={FilterBarClasses.countContainer}
-
>
-
<Text
-
className={FilterBarClasses.countText}
-
color="none"
-
variant="text-xs/medium"
-
>
+
<div style={{ boxSizing: "content-box" }} className={FilterBarClasses.countContainer}>
+
<Text className={FilterBarClasses.countText} color="none" variant="text-xs/medium">
{selectedTags.size}
</Text>
</div>
+18 -48
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/index.tsx
···
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
import { ExtensionCompat } from "@moonlight-mod/core/extension/loader";
-
const SearchBar: any = Object.values(
-
spacepack.findByCode("Messages.SEARCH", "hideSearchIcon")[0].exports
-
)[0];
+
const SearchBar: any = Object.values(spacepack.findByCode("Messages.SEARCH", "hideSearchIcon")[0].exports)[0];
export default function ExtensionsPage() {
-
const { extensions, savedFilter } = useStateFromStoresObject(
-
[MoonbaseSettingsStore],
-
() => {
-
return {
-
extensions: MoonbaseSettingsStore.extensions,
-
savedFilter: MoonbaseSettingsStore.getExtensionConfigRaw<number>(
-
"moonbase",
-
"filter",
-
defaultFilter
-
)
-
};
-
}
-
);
+
const { extensions, savedFilter } = useStateFromStoresObject([MoonbaseSettingsStore], () => {
+
return {
+
extensions: MoonbaseSettingsStore.extensions,
+
savedFilter: MoonbaseSettingsStore.getExtensionConfigRaw<number>("moonbase", "filter", defaultFilter)
+
};
+
});
const [query, setQuery] = React.useState("");
const filterState = React.useState(defaultFilter);
let filter: Filter, setFilter: (filter: Filter) => void;
-
if (
-
MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
-
"moonbase",
-
"saveFilter",
-
false
-
)
-
) {
+
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "saveFilter", false)) {
filter = savedFilter ?? defaultFilter;
-
setFilter = (filter) =>
-
MoonbaseSettingsStore.setExtensionConfig("moonbase", "filter", filter);
+
setFilter = (filter) => MoonbaseSettingsStore.setExtensionConfig("moonbase", "filter", filter);
} else {
filter = filterState[0];
setFilter = filterState[1];
···
ext.manifest.meta?.name?.toLowerCase().includes(query) ||
ext.manifest.meta?.tagline?.toLowerCase().includes(query) ||
ext.manifest.meta?.description?.toLowerCase().includes(query)) &&
-
[...selectedTags.values()].every(
-
(tag) => ext.manifest.meta?.tags?.includes(tag as ExtensionTag)
-
) &&
+
[...selectedTags.values()].every((tag) => ext.manifest.meta?.tags?.includes(tag as ExtensionTag)) &&
// This seems very bad, sorry
!(
-
(!(filter & Filter.Core) &&
-
ext.source.type === ExtensionLoadSource.Core) ||
-
(!(filter & Filter.Normal) &&
-
ext.source.type === ExtensionLoadSource.Normal) ||
-
(!(filter & Filter.Developer) &&
-
ext.source.type === ExtensionLoadSource.Developer) ||
-
(!(filter & Filter.Enabled) &&
-
MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
-
(!(filter & Filter.Disabled) &&
-
!MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
-
(!(filter & Filter.Installed) &&
-
ext.state !== ExtensionState.NotDownloaded) ||
-
(!(filter & Filter.Repository) &&
-
ext.state === ExtensionState.NotDownloaded)
+
(!(filter & Filter.Core) && ext.source.type === ExtensionLoadSource.Core) ||
+
(!(filter & Filter.Normal) && ext.source.type === ExtensionLoadSource.Normal) ||
+
(!(filter & Filter.Developer) && ext.source.type === ExtensionLoadSource.Developer) ||
+
(!(filter & Filter.Enabled) && MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
+
(!(filter & Filter.Disabled) && !MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
+
(!(filter & Filter.Installed) && ext.state !== ExtensionState.NotDownloaded) ||
+
(!(filter & Filter.Repository) && ext.state === ExtensionState.NotDownloaded)
) &&
(filter & Filter.Incompatible ||
ext.compat === ExtensionCompat.Compatible ||
···
spellCheck: "false"
}}
/>
-
<FilterBar
-
filter={filter}
-
setFilter={setFilter}
-
selectedTags={selectedTags}
-
setSelectedTags={setSelectedTags}
-
/>
+
<FilterBar filter={filter} setFilter={setFilter} selectedTags={selectedTags} setSelectedTags={setSelectedTags} />
{filtered.map((ext) => (
<ExtensionCard uniqueId={ext.uniqueId} key={ext.uniqueId} />
))}
+4 -27
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/info.tsx
···
[ExtensionTag.Library]: "Library"
};
-
const UserInfoClasses = spacepack.findByCode(
-
"infoScroller",
-
"userInfoSection",
-
"userInfoSectionHeader"
-
)[0].exports;
+
const UserInfoClasses = spacepack.findByCode("infoScroller", "userInfoSection", "userInfoSectionHeader")[0].exports;
import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
// FIXME: type component keys
const { Text } = Components;
-
function InfoSection({
-
title,
-
children
-
}: {
-
title: string;
-
children: React.ReactNode;
-
}) {
+
function InfoSection({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div
style={{
···
);
}
-
function Badge({
-
color,
-
children
-
}: {
-
color: string;
-
children: React.ReactNode;
-
}) {
+
function Badge({ color, children }: { color: string; children: React.ReactNode }) {
return (
<span
style={{
···
const name = tagNames[tag];
return (
-
<Badge
-
key={i}
-
color={
-
tag === ExtensionTag.DangerZone
-
? "var(--red-400)"
-
: "var(--brand-500)"
-
}
-
>
+
<Badge key={i} color={tag === ExtensionTag.DangerZone ? "var(--red-400)" : "var(--brand-500)"}>
{name}
</Badge>
);
+7 -19
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/popup.tsx
···
import { ExtensionLoadSource } from "@moonlight-mod/types";
import Flex from "@moonlight-mod/wp/discord/uikit/Flex";
-
const { openModalLazy, closeModal } = spacepack.require(
-
"@moonlight-mod/wp/discord/components/common/index"
-
);
-
const Popup = spacepack.findByCode(".minorContainer", "secondaryAction")[0]
-
.exports.default;
+
const { openModalLazy, closeModal } = spacepack.require("@moonlight-mod/wp/discord/components/common/index");
+
const Popup = spacepack.findByCode(".minorContainer", "secondaryAction")[0].exports.default;
const presentableLoadSources: Record<ExtensionLoadSource, string> = {
[ExtensionLoadSource.Developer]: "Local extension", // should never show up
···
return {
value: candidate.uniqueId.toString(),
label:
-
candidate.source.url ??
-
presentableLoadSources[candidate.source.type] ??
-
candidate.manifest.version ??
-
""
+
candidate.source.url ?? presentableLoadSources[candidate.source.type] ?? candidate.manifest.version ?? ""
};
})}
onChange={(value: string) => {
···
}) {
const { Text } = Components;
-
const amountNotAvailable = Object.values(deps).filter(
-
(candidates) => candidates.length === 0
-
).length;
+
const amountNotAvailable = Object.values(deps).filter((candidates) => candidates.length === 0).length;
-
const [options, setOptions] = React.useState<
-
Record<string, string | undefined>
-
>(
+
const [options, setOptions] = React.useState<Record<string, string | undefined>>(
Object.fromEntries(
Object.entries(deps).map(([id, candidates]) => [
id,
···
direction={Flex.Direction.VERTICAL}
>
<Text variant="text-md/normal">
-
This extension depends on other extensions which are not downloaded.
-
Choose which extensions to download.
+
This extension depends on other extensions which are not downloaded. Choose which extensions to download.
</Text>
{amountNotAvailable > 0 && (
<Text variant="text-md/normal">
{amountNotAvailable} extension
-
{amountNotAvailable > 1 ? "s" : ""} could not be found, and must
-
be installed manually.
+
{amountNotAvailable > 1 ? "s" : ""} could not be found, and must be installed manually.
</Text>
)}
+27 -102
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/settings.tsx
···
() => {
return {
value: MoonbaseSettingsStore.getExtensionConfig<T>(uniqueId, name),
-
displayName: MoonbaseSettingsStore.getExtensionConfigName(
-
uniqueId,
-
name
-
),
-
description: MoonbaseSettingsStore.getExtensionConfigDescription(
-
uniqueId,
-
name
-
)
+
displayName: MoonbaseSettingsStore.getExtensionConfigName(uniqueId, name),
+
description: MoonbaseSettingsStore.getExtensionConfigDescription(uniqueId, name)
};
},
[uniqueId, name]
···
function Boolean({ ext, name, setting, disabled }: SettingsProps) {
const { FormSwitch } = Components;
-
const { value, displayName, description } = useConfigEntry<boolean>(
-
ext.uniqueId,
-
name
-
);
+
const { value, displayName, description } = useConfigEntry<boolean>(ext.uniqueId, name);
return (
<FormSwitch
···
function Number({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, Slider } = Components;
-
const { value, displayName, description } = useConfigEntry<number>(
-
ext.uniqueId,
-
name
-
);
+
const { value, displayName, description } = useConfigEntry<number>(ext.uniqueId, name);
const castedSetting = setting as NumberSettingType;
const min = castedSetting.min ?? 0;
···
function String({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput } = Components;
-
const { value, displayName, description } = useConfigEntry<string>(
-
ext.uniqueId,
-
name
-
);
+
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
return (
<FormItem className={Margins.marginTop20} title={displayName}>
-
{description && (
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
-
)}
+
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
<TextInput
value={value ?? ""}
onChange={(value: string) => {
···
function MultilineString({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextArea } = Components;
-
const { value, displayName, description } = useConfigEntry<string>(
-
ext.uniqueId,
-
name
-
);
+
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
return (
<FormItem className={Margins.marginTop20} title={displayName}>
-
{description && (
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
-
)}
+
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
<TextArea
rows={5}
value={value ?? ""}
···
function Select({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, SingleSelect } = Components;
-
const { value, displayName, description } = useConfigEntry<string>(
-
ext.uniqueId,
-
name
-
);
+
const { value, displayName, description } = useConfigEntry<string>(ext.uniqueId, name);
const castedSetting = setting as SelectSettingType;
const options = castedSetting.options;
return (
<FormItem className={Margins.marginTop20} title={displayName}>
-
{description && (
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
-
)}
+
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
<SingleSelect
autofocus={false}
clearable={false}
value={value ?? ""}
-
options={options.map((o: SelectOption) =>
-
typeof o === "string" ? { value: o, label: o } : o
-
)}
+
options={options.map((o: SelectOption) => (typeof o === "string" ? { value: o, label: o } : o))}
onChange={(value: string) => {
if (disabled) return;
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
···
}
function MultiSelect({ ext, name, setting, disabled }: SettingsProps) {
-
const { FormItem, FormText, Select, useVariableSelect, multiSelect } =
-
Components;
-
const { value, displayName, description } = useConfigEntry<string | string[]>(
-
ext.uniqueId,
-
name
-
);
+
const { FormItem, FormText, Select, useVariableSelect, multiSelect } = Components;
+
const { value, displayName, description } = useConfigEntry<string | string[]>(ext.uniqueId, name);
const castedSetting = setting as MultiSelectSettingType;
const options = castedSetting.options;
return (
<FormItem className={Margins.marginTop20} title={displayName}>
-
{description && (
-
<FormText className={Margins.marginBottom8}>{description}</FormText>
-
)}
+
{description && <FormText className={Margins.marginBottom8}>{description}</FormText>}
<Select
autofocus={false}
clearable={false}
closeOnSelect={false}
-
options={options.map((o: SelectOption) =>
-
typeof o === "string" ? { value: o, label: o } : o
-
)}
+
options={options.map((o: SelectOption) => (typeof o === "string" ? { value: o, label: o } : o))}
{...useVariableSelect({
onSelectInteraction: multiSelect,
value: new Set(Array.isArray(value) ? value : [value]),
onChange: (value: string) => {
if (disabled) return;
-
MoonbaseSettingsStore.setExtensionConfig(
-
ext.id,
-
name,
-
Array.from(value)
-
);
+
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, Array.from(value));
}
})}
/>
···
);
}
-
const RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0]
-
.exports;
+
const RemoveButtonClasses = spacepack.findByCode("removeButtonContainer")[0].exports;
// FIXME: type component keys
const { CircleXIcon } = Components;
-
function RemoveEntryButton({
-
onClick,
-
disabled
-
}: {
-
onClick: () => void;
-
disabled: boolean;
-
}) {
+
function RemoveEntryButton({ onClick, disabled }: { onClick: () => void; disabled: boolean }) {
const { Tooltip, Clickable } = Components;
return (
<div className={RemoveButtonClasses.removeButtonContainer}>
<Tooltip text="Remove entry" position="top">
{(props: any) => (
-
<Clickable
-
{...props}
-
className={RemoveButtonClasses.removeButton}
-
onClick={onClick}
-
>
+
<Clickable {...props} className={RemoveButtonClasses.removeButton} onClick={onClick}>
<CircleXIcon width={16} height={16} />
</Clickable>
)}
···
function List({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput, Button } = Components;
-
const { value, displayName, description } = useConfigEntry<string[]>(
-
ext.uniqueId,
-
name
-
);
+
const { value, displayName, description } = useConfigEntry<string[]>(ext.uniqueId, name);
const entries = value ?? [];
-
const updateConfig = () =>
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, entries);
+
const updateConfig = () => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, entries);
return (
<FormItem className={Margins.marginTop20} title={displayName}>
-
{description && (
-
<FormText className={Margins.marginBottom4}>{description}</FormText>
-
)}
+
{description && <FormText className={Margins.marginBottom4}>{description}</FormText>}
<Flex direction={Flex.Direction.VERTICAL}>
{entries.map((val, i) => (
// FIXME: stylesheets
···
function Dictionary({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput, Button } = Components;
-
const { value, displayName, description } = useConfigEntry<
-
Record<string, string>
-
>(ext.uniqueId, name);
+
const { value, displayName, description } = useConfigEntry<Record<string, string>>(ext.uniqueId, name);
const entries = Object.entries(value ?? {});
-
const updateConfig = () =>
-
MoonbaseSettingsStore.setExtensionConfig(
-
ext.id,
-
name,
-
Object.fromEntries(entries)
-
);
+
const updateConfig = () => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, Object.fromEntries(entries));
return (
<FormItem className={Margins.marginTop20} title={displayName}>
-
{description && (
-
<FormText className={Margins.marginBottom4}>{description}</FormText>
-
)}
+
{description && <FormText className={Margins.marginBottom4}>{description}</FormText>}
<Flex direction={Flex.Direction.VERTICAL}>
{entries.map(([key, val], i) => (
// FIXME: stylesheets
···
[MoonbaseSettingsStore],
() => {
return {
-
component: MoonbaseSettingsStore.getExtensionConfigComponent(
-
ext.id,
-
name
-
)
+
component: MoonbaseSettingsStore.getExtensionConfigComponent(ext.id, name)
};
},
[ext.uniqueId, name]
···
}
return (
-
<Component
-
value={value}
-
setValue={(value) =>
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)
-
}
-
/>
+
<Component value={value} setValue={(value) => MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value)} />
);
}
+6 -25
packages/core-extensions/src/moonbase/webpackModules/ui/index.tsx
···
import React from "@moonlight-mod/wp/react";
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
-
import {
-
Text,
-
TabBar
-
} from "@moonlight-mod/wp/discord/components/common/index";
+
import { Text, TabBar } from "@moonlight-mod/wp/discord/components/common/index";
import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux";
import { UserSettingsModalStore } from "@moonlight-mod/wp/common_stores";
···
import Update from "./update";
const { Divider } = spacepack.findByCode(".forumOrHome]:")[0].exports.Z;
-
const TitleBarClasses = spacepack.findByCode("iconWrapper:", "children:")[0]
-
.exports;
+
const TitleBarClasses = spacepack.findByCode("iconWrapper:", "children:")[0].exports;
const TabBarClasses = spacepack.findByCode("nowPlayingColumn:")[0].exports;
-
const { setSection, clearSubsection } = spacepack.findByExports(
-
"setSection",
-
"clearSubsection"
-
)[0].exports.Z;
+
const { setSection, clearSubsection } = spacepack.findByExports("setSection", "clearSubsection")[0].exports.Z;
const Margins = spacepack.require("discord/styles/shared/Margins.css");
export const pages: {
···
];
export function Moonbase(props: { initialTab?: number } = {}) {
-
const subsection = useStateFromStores(
-
[UserSettingsModalStore],
-
() => UserSettingsModalStore.getSubsection() ?? 0
-
);
+
const subsection = useStateFromStores([UserSettingsModalStore], () => UserSettingsModalStore.getSubsection() ?? 0);
const setSubsection = React.useCallback(
(to: string) => {
if (subsection !== to) setSection("moonbase", to);
···
return (
<>
<div className={`${TitleBarClasses.children} ${Margins.marginBottom20}`}>
-
<Text
-
className={TitleBarClasses.titleWrapper}
-
variant="heading-lg/semibold"
-
tag="h2"
-
>
+
<Text className={TitleBarClasses.titleWrapper} variant="heading-lg/semibold" tag="h2">
Moonbase
</Text>
<Divider />
-
<TabBar
-
selectedItem={subsection}
-
onItemSelect={setSubsection}
-
type="top-pill"
-
className={TabBarClasses.tabBar}
-
>
+
<TabBar selectedItem={subsection} onItemSelect={setSubsection} type="top-pill" className={TabBarClasses.tabBar}>
{pages.map((page, i) => (
<TabBar.Item key={page.id} id={i} className={TabBarClasses.item}>
{page.name}
+5 -18
packages/core-extensions/src/moonbase/webpackModules/ui/update.tsx
···
const { ThemeDarkIcon, Text, Button } = Components;
const Margins = spacepack.require("discord/styles/shared/Margins.css");
-
const HelpMessageClasses = spacepack.findByExports("positive", "iconDiv")[0]
-
.exports;
+
const HelpMessageClasses = spacepack.findByExports("positive", "iconDiv")[0].exports;
const logger = moonlight.getLogger("moonbase/ui/update");
···
[UpdateState.Ready]: "A new version of moonlight is available.",
[UpdateState.Working]: "Updating moonlight...",
[UpdateState.Installed]: "Updated. Restart Discord to apply changes.",
-
[UpdateState.Failed]:
-
"Failed to update moonlight. Please use the installer instead."
+
[UpdateState.Failed]: "Failed to update moonlight. Please use the installer instead."
};
export default function Update() {
const [state, setState] = React.useState(UpdateState.Ready);
-
const newVersion = useStateFromStores(
-
[MoonbaseSettingsStore],
-
() => MoonbaseSettingsStore.newVersion
-
);
+
const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion);
if (newVersion == null) return null;
···
alignItems: "center"
}}
>
-
<ThemeDarkIcon
-
size="sm"
-
color="currentColor"
-
className={HelpMessageClasses.icon}
-
/>
+
<ThemeDarkIcon size="sm" color="currentColor" className={HelpMessageClasses.icon} />
</div>
-
<Text
-
variant="text-sm/medium"
-
color="currentColor"
-
className={HelpMessageClasses.text}
-
>
+
<Text variant="text-sm/medium" color="currentColor" className={HelpMessageClasses.text}>
{strings[state]}
</Text>
</Flex>
+5 -23
packages/core-extensions/src/moonbase/webpackModules/updates.tsx
···
// FIXME: not indexed as importable
const Constants = spacepack.require("discord/Constants");
-
const UserSettingsSections = spacepack.findObjectFromKey(
-
Constants,
-
"APPEARANCE_THEME_PICKER"
-
);
+
const UserSettingsSections = spacepack.findObjectFromKey(Constants, "APPEARANCE_THEME_PICKER");
const { ThemeDarkIcon } = Components;
···
function listener() {
if (
MoonbaseSettingsStore.shouldShowNotice &&
-
MoonbaseSettingsStore.getExtensionConfigRaw(
-
"moonbase",
-
"updateBanner",
-
true
-
)
+
MoonbaseSettingsStore.getExtensionConfigRaw("moonbase", "updateBanner", true)
) {
// @ts-expect-error epic type fail
MoonbaseSettingsStore.removeChangeListener(listener);
const version = MoonbaseSettingsStore.newVersion;
-
const extensionUpdateCount = Object.keys(
-
MoonbaseSettingsStore.updates
-
).length;
+
const extensionUpdateCount = Object.keys(MoonbaseSettingsStore.updates).length;
const hasExtensionUpdates = extensionUpdateCount > 0;
let message;
···
{
name: "Open Moonbase",
onClick: () => {
-
const { open } = spacepack.findByExports(
-
"setSection",
-
"clearSubsection"
-
)[0].exports.Z;
+
const { open } = spacepack.findByExports("setSection", "clearSubsection")[0].exports.Z;
// settings is lazy loaded thus lazily patched
// FIXME: figure out a way to detect if settings has been opened
// alreadyjust so the transition isnt as jarring
open(UserSettingsSections.ACCOUNT);
setTimeout(() => {
-
if (
-
MoonbaseSettingsStore.getExtensionConfigRaw<boolean>(
-
"moonbase",
-
"sections",
-
false
-
)
-
) {
+
if (MoonbaseSettingsStore.getExtensionConfigRaw<boolean>("moonbase", "sections", false)) {
open("moonbase-extensions");
} else {
open("moonbase", 0);
+9 -42
packages/core-extensions/src/nativeFixes/host.ts
···
import { app, nativeTheme } from "electron";
-
const enabledFeatures = app.commandLine
-
.getSwitchValue("enable-features")
-
.split(",");
+
const enabledFeatures = app.commandLine.getSwitchValue("enable-features").split(",");
moonlightHost.events.on("window-created", function (browserWindow) {
-
if (
-
moonlightHost.getConfigOption<boolean>("nativeFixes", "devtoolsThemeFix") ??
-
true
-
) {
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "devtoolsThemeFix") ?? true) {
browserWindow.webContents.on("devtools-opened", () => {
if (!nativeTheme.shouldUseDarkColors) return;
nativeTheme.themeSource = "light";
···
}
});
-
if (
-
moonlightHost.getConfigOption<boolean>(
-
"nativeFixes",
-
"disableRendererBackgrounding"
-
) ??
-
true
-
) {
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "disableRendererBackgrounding") ?? true) {
// Discord already disables UseEcoQoSForBackgroundProcess and some other
// related features
app.commandLine.appendSwitch("disable-renderer-backgrounding");
···
}
if (process.platform === "linux") {
-
if (
-
moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxAutoscroll") ??
-
false
-
) {
-
app.commandLine.appendSwitch(
-
"enable-blink-features",
-
"MiddleClickAutoscroll"
-
);
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxAutoscroll") ?? false) {
+
app.commandLine.appendSwitch("enable-blink-features", "MiddleClickAutoscroll");
}
-
if (
-
moonlightHost.getConfigOption<boolean>(
-
"nativeFixes",
-
"linuxSpeechDispatcher"
-
) ??
-
true
-
) {
+
if (moonlightHost.getConfigOption<boolean>("nativeFixes", "linuxSpeechDispatcher") ?? true) {
app.commandLine.appendSwitch("enable-speech-dispatcher");
}
}
···
// NOTE: Only tested if this appears on Windows, it should appear on all when
// hardware acceleration is disabled
const noAccel = app.commandLine.hasSwitch("disable-gpu-compositing");
-
if (
-
(moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapi") ?? true) &&
-
!noAccel
-
) {
+
if ((moonlightHost.getConfigOption<boolean>("nativeFixes", "vaapi") ?? true) && !noAccel) {
if (process.platform === "linux")
// These will eventually be renamed https://source.chromium.org/chromium/chromium/src/+/5482210941a94d70406b8da962426e4faca7fce4
-
enabledFeatures.push(
-
"VaapiVideoEncoder",
-
"VaapiVideoDecoder",
-
"VaapiVideoDecodeLinuxGL"
-
);
+
enabledFeatures.push("VaapiVideoEncoder", "VaapiVideoDecoder", "VaapiVideoDecodeLinuxGL");
}
-
app.commandLine.appendSwitch(
-
"enable-features",
-
[...new Set(enabledFeatures)].join(",")
-
);
+
app.commandLine.appendSwitch("enable-features", [...new Set(enabledFeatures)].join(","));
+2 -6
packages/core-extensions/src/notices/index.ts
···
{
find: ".GUILD_RAID_NOTIFICATION:",
replace: {
-
match:
-
/(?<=return(\(0,.\.jsx\))\(.+?\);)case .{1,2}\..{1,3}\.GUILD_RAID_NOTIFICATION:/,
+
match: /(?<=return(\(0,.\.jsx\))\(.+?\);)case .{1,2}\..{1,3}\.GUILD_RAID_NOTIFICATION:/,
replacement: (orig, createElement) =>
`case "__moonlight_notice":return${createElement}(require("notices_component").default,{});${orig}`
}
···
export const webpackModules: Record<string, ExtensionWebpackModule> = {
notices: {
-
dependencies: [
-
{ id: "discord/packages/flux" },
-
{ id: "discord/Dispatcher" }
-
]
+
dependencies: [{ id: "discord/packages/flux" }, { id: "discord/Dispatcher" }]
},
component: {
+1 -4
packages/core-extensions/src/notices/webpackModules/component.tsx
···
{notice.element}
{(notice.showClose ?? true) && (
-
<NoticeCloseButton
-
onClick={() => popAndDismiss(notice)}
-
noticeType="__moonlight_notice"
-
/>
+
<NoticeCloseButton onClick={() => popAndDismiss(notice)} noticeType="__moonlight_notice" />
)}
{(notice.buttons ?? []).map((button) => (
+1 -4
packages/core-extensions/src/notices/webpackModules/notices.ts
···
import { Store } from "@moonlight-mod/wp/discord/packages/flux";
import Dispatcher from "@moonlight-mod/wp/discord/Dispatcher";
-
import type {
-
Notice,
-
Notices
-
} from "@moonlight-mod/types/coreExtensions/notices";
+
import type { Notice, Notices } from "@moonlight-mod/types/coreExtensions/notices";
// very lazy way of doing this, FIXME
let open = false;
+9 -34
packages/core-extensions/src/quietLoggers/index.ts
···
import { Patch } from "@moonlight-mod/types";
const notXssDefensesOnly = () =>
-
(moonlight.getConfigOption<boolean>("quietLoggers", "xssDefensesOnly") ??
-
false) === false;
+
(moonlight.getConfigOption<boolean>("quietLoggers", "xssDefensesOnly") ?? false) === false;
// These patches MUST run before the simple patches, these are to remove loggers
// that end up causing syntax errors by the normal patch
···
// Patches to simply remove a logger call
const stubPatches = [
// "sh" is not a valid locale.
-
[
-
"is not a valid locale",
-
/(.)\.error\(""\.concat\((.)," is not a valid locale\."\)\)/g
-
],
+
["is not a valid locale", /(.)\.error\(""\.concat\((.)," is not a valid locale\."\)\)/g],
['="RunningGameStore"', /.\.info\("games",{.+?}\),/],
-
[
-
'"[BUILD INFO] Release Channel: "',
-
/new .{1,2}\.Z\(\)\.log\("\[BUILD INFO\] Release Channel: ".+?"\)\),/
-
],
-
[
-
'.APP_NATIVE_CRASH,"Storage"',
-
/console\.log\("AppCrashedFatalReport lastCrash:",.,.\);/
-
],
-
[
-
'.APP_NATIVE_CRASH,"Storage"',
-
'console.log("AppCrashedFatalReport: getLastCrash not supported.");'
-
],
+
['"[BUILD INFO] Release Channel: "', /new .{1,2}\.Z\(\)\.log\("\[BUILD INFO\] Release Channel: ".+?"\)\),/],
+
['.APP_NATIVE_CRASH,"Storage"', /console\.log\("AppCrashedFatalReport lastCrash:",.,.\);/],
+
['.APP_NATIVE_CRASH,"Storage"', 'console.log("AppCrashedFatalReport: getLastCrash not supported.");'],
['"[NATIVE INFO] ', /new .{1,2}\.Z\(\)\.log\("\[NATIVE INFO] .+?\)\);/],
['"Spellchecker"', /.\.info\("Switching to ".+?"\(unavailable\)"\);?/g],
-
[
-
'throw Error("Messages are still loading.");',
-
/console\.warn\("Unsupported Locale",.\),/
-
],
+
['throw Error("Messages are still loading.");', /console\.warn\("Unsupported Locale",.\),/],
["}_dispatchWithDevtools(", /.\.totalTime>100&&.\.verbose\(.+?\);/],
-
[
-
'"NativeDispatchUtils"',
-
/null==.&&.\.warn\("Tried getting Dispatch instance before instantiated"\),/
-
],
+
['"NativeDispatchUtils"', /null==.&&.\.warn\("Tried getting Dispatch instance before instantiated"\),/],
['("DatabaseManager")', /.\.log\("removing database \(user: ".+?\)\),/],
[
'"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. Action: "',
/.\.has\(.\.type\)&&.\.log\(.+?\.type\)\),/
],
-
[
-
'console.warn("Window state not initialized"',
-
/console\.warn\("Window state not initialized",.\),/
-
]
+
['console.warn("Window state not initialized"', /console\.warn\("Window state not initialized",.\),/]
];
const simplePatches = [
···
["suppressDeprecationWarnings=!1", "suppressDeprecationWarnings=!0"],
// Zustand related
-
[
-
/console\.warn\("\[DEPRECATED\] Please use `subscribeWithSelector` middleware"\)/g,
-
"/*$&*/"
-
],
+
[/console\.warn\("\[DEPRECATED\] Please use `subscribeWithSelector` middleware"\)/g, "/*$&*/"],
["this.getDebugLogging()", "false"]
] as { [0]: string | RegExp; [1]: string }[];
+46 -67
packages/core-extensions/src/rocketship/host/permissions.ts
···
details: Electron.PermissionCheckHandlerHandlerDetails
) => boolean;
-
moonlightHost.events.on(
-
"window-created",
-
(window: BrowserWindow, isMainWindow: boolean) => {
-
if (!isMainWindow) return;
-
const windowSession = window.webContents.session;
+
moonlightHost.events.on("window-created", (window: BrowserWindow, isMainWindow: boolean) => {
+
if (!isMainWindow) return;
+
const windowSession = window.webContents.session;
-
// setPermissionRequestHandler
-
windowSession.setPermissionRequestHandler(
-
(webcontents, permission, callback, details) => {
-
let cbResult = false;
-
function fakeCallback(result: boolean) {
-
cbResult = result;
-
}
+
// setPermissionRequestHandler
+
windowSession.setPermissionRequestHandler((webcontents, permission, callback, details) => {
+
let cbResult = false;
+
function fakeCallback(result: boolean) {
+
cbResult = result;
+
}
-
if (caughtPermissionRequestHandler) {
-
caughtPermissionRequestHandler(
-
webcontents,
-
permission,
-
fakeCallback,
-
details
-
);
-
}
+
if (caughtPermissionRequestHandler) {
+
caughtPermissionRequestHandler(webcontents, permission, fakeCallback, details);
+
}
-
if (permission === "media" || permission === "display-capture") {
-
cbResult = true;
-
}
+
if (permission === "media" || permission === "display-capture") {
+
cbResult = true;
+
}
-
callback(cbResult);
-
}
-
);
+
callback(cbResult);
+
});
-
let caughtPermissionRequestHandler: PermissionRequestHandler | undefined;
+
let caughtPermissionRequestHandler: PermissionRequestHandler | undefined;
-
windowSession.setPermissionRequestHandler =
-
function catchSetPermissionRequestHandler(
-
handler: (
-
webcontents: Electron.WebContents,
-
permission: string,
-
callback: (permissionGranted: boolean) => void
-
) => void
-
) {
-
caughtPermissionRequestHandler = handler;
-
};
+
windowSession.setPermissionRequestHandler = function catchSetPermissionRequestHandler(
+
handler: (
+
webcontents: Electron.WebContents,
+
permission: string,
+
callback: (permissionGranted: boolean) => void
+
) => void
+
) {
+
caughtPermissionRequestHandler = handler;
+
};
-
// setPermissionCheckHandler
-
windowSession.setPermissionCheckHandler(
-
(webcontents, permission, requestingOrigin, details) => {
-
return false;
-
}
-
);
+
// setPermissionCheckHandler
+
windowSession.setPermissionCheckHandler((webcontents, permission, requestingOrigin, details) => {
+
return false;
+
});
-
let caughtPermissionCheckHandler: PermissionCheckHandler | undefined;
+
let caughtPermissionCheckHandler: PermissionCheckHandler | undefined;
-
windowSession.setPermissionCheckHandler(
-
(webcontents, permission, requestingOrigin, details) => {
-
let result = false;
+
windowSession.setPermissionCheckHandler((webcontents, permission, requestingOrigin, details) => {
+
let result = false;
-
if (caughtPermissionCheckHandler) {
-
result = caughtPermissionCheckHandler(
-
webcontents,
-
permission,
-
requestingOrigin,
-
details
-
);
-
}
+
if (caughtPermissionCheckHandler) {
+
result = caughtPermissionCheckHandler(webcontents, permission, requestingOrigin, details);
+
}
-
if (permission === "media" || permission === "display-capture") {
-
result = true;
-
}
+
if (permission === "media" || permission === "display-capture") {
+
result = true;
+
}
-
return result;
-
}
-
);
+
return result;
+
});
-
windowSession.setPermissionCheckHandler =
-
function catchSetPermissionCheckHandler(handler: PermissionCheckHandler) {
-
caughtPermissionCheckHandler = handler;
-
};
-
}
-
);
+
windowSession.setPermissionCheckHandler = function catchSetPermissionCheckHandler(handler: PermissionCheckHandler) {
+
caughtPermissionCheckHandler = handler;
+
};
+
});
+4 -12
packages/core-extensions/src/rocketship/host/types.ts
···
// https://github.com/Vencord/venmic/blob/d737ef33eaae7a73d03ec02673e008cf0243434d/lib/module.d.ts
type DefaultProps = "node.name" | "application.name";
-
type LiteralUnion<LiteralType, BaseType extends string> =
-
| LiteralType
-
| (BaseType & Record<never, never>);
+
type LiteralUnion<LiteralType, BaseType extends string> = LiteralType | (BaseType & Record<never, never>);
-
type Optional<Type, Key extends keyof Type> = Partial<Pick<Type, Key>> &
-
Omit<Type, Key>;
+
type Optional<Type, Key extends keyof Type> = Partial<Pick<Type, Key>> & Omit<Type, Key>;
-
export type Node<T extends string = never> = Record<
-
LiteralUnion<T, string>,
-
string
-
>;
+
export type Node<T extends string = never> = Record<LiteralUnion<T, string>, string>;
export interface LinkData {
include: Node[];
···
unlink(): void;
list<T extends string = DefaultProps>(props?: T[]): Node<T>[];
-
link(
-
data: Optional<LinkData, "exclude"> | Optional<LinkData, "include">
-
): boolean;
+
link(data: Optional<LinkData, "exclude"> | Optional<LinkData, "include">): boolean;
}
+23 -31
packages/core-extensions/src/rocketship/host/venmic.ts
···
function getPatchbay() {
try {
-
const venmic = require(
-
path.join(path.dirname(moonlightHost.asarPath), "..", "venmic.node")
-
) as { PatchBay: new () => PatchBay };
+
const venmic = require(path.join(path.dirname(moonlightHost.asarPath), "..", "venmic.node")) as {
+
PatchBay: new () => PatchBay;
+
};
const patchbay = new venmic.PatchBay();
return patchbay;
} catch (error) {
···
patchbay.unlink();
return patchbay.link({
-
exclude: [
-
{ "application.process.id": pid },
-
{ "media.class": "Stream/Input/Audio" }
-
],
+
exclude: [{ "application.process.id": pid }, { "media.class": "Stream/Input/Audio" }],
ignore_devices: true,
only_speakers: true,
only_default_speakers: true
···
}
}
-
moonlightHost.events.on(
-
"window-created",
-
(window: BrowserWindow, isMainWindow: boolean) => {
-
if (!isMainWindow) return;
-
const windowSession = window.webContents.session;
+
moonlightHost.events.on("window-created", (window: BrowserWindow, isMainWindow: boolean) => {
+
if (!isMainWindow) return;
+
const windowSession = window.webContents.session;
-
// @ts-expect-error these types ancient
-
windowSession.setDisplayMediaRequestHandler(
-
(request: any, callback: any) => {
-
const linked = linkVenmic();
-
desktopCapturer
-
.getSources({ types: ["screen", "window"] })
-
.then((sources) => {
-
//logger.debug("desktopCapturer.getSources", sources);
-
logger.debug("Linked to venmic:", linked);
+
// @ts-expect-error these types ancient
+
windowSession.setDisplayMediaRequestHandler(
+
(request: any, callback: any) => {
+
const linked = linkVenmic();
+
desktopCapturer.getSources({ types: ["screen", "window"] }).then((sources) => {
+
//logger.debug("desktopCapturer.getSources", sources);
+
logger.debug("Linked to venmic:", linked);
-
callback({
-
video: sources[0],
-
audio: "loopback"
-
});
-
});
-
},
-
{ useSystemPicker: true }
-
);
-
}
-
);
+
callback({
+
video: sources[0],
+
audio: "loopback"
+
});
+
});
+
},
+
{ useSystemPicker: true }
+
);
+
});
+5 -11
packages/core-extensions/src/rocketship/index.ts
···
logger.debug("Devices:", devices);
// This isn't vencord :(
-
const id = devices.find((device) => device.label === "vencord-screen-share")
-
?.deviceId;
+
const id = devices.find((device) => device.label === "vencord-screen-share")?.deviceId;
if (!id) return null;
logger.debug("Got venmic device ID:", id);
···
}
}
-
navigator.mediaDevices.getDisplayMedia = async function getDisplayMediaRedirect(
-
options
-
) {
+
navigator.mediaDevices.getDisplayMedia = async function getDisplayMediaRedirect(options) {
const orig = await getDisplayMediaOrig.call(this, options);
const venmic = await getVenmicStream();
···
replace: [
// Prevent loading of krisp native module by stubbing out desktop checks
{
-
match:
-
/\(\(0,.\.isWindows\)\(\)\|\|\(0,.\.isLinux\)\(\)\|\|.+?&&!__OVERLAY__/,
+
match: /\(\(0,.\.isWindows\)\(\)\|\|\(0,.\.isLinux\)\(\)\|\|.+?&&!__OVERLAY__/,
replacement: (orig, macosPlatformCheck) => `false&&!__OVERLAY__`
},
// Enable loading of web krisp equivelant by replacing isWeb with true
{
-
match:
-
/\(0,.\.isWeb\)\(\)&&(.{1,2}\.supports\(.{1,2}\..{1,2}.NOISE_CANCELLATION)/,
-
replacement: (orig, supportsNoiseCancellation) =>
-
`true&&${supportsNoiseCancellation}`
+
match: /\(0,.\.isWeb\)\(\)&&(.{1,2}\.supports\(.{1,2}\..{1,2}.NOISE_CANCELLATION)/,
+
replacement: (orig, supportsNoiseCancellation) => `true&&${supportsNoiseCancellation}`
}
]
}
+2 -4
packages/core-extensions/src/settings/index.ts
···
find: '"useGenerateUserSettingsSections"',
replace: {
match: /(?<=\.push\(.+?\)}\)\)}\),)(.+?)}/,
-
replacement: (_, sections: string) =>
-
`require("settings_settings").Settings._mutateSections(${sections})}`
+
replacement: (_, sections: string) => `require("settings_settings").Settings._mutateSections(${sections})}`
}
},
{
···
replacement: (orig, sections, section) =>
`${orig.replace(
/Object\.values\(.\..+?\)/,
-
(orig) =>
-
`[...require("settings_settings").Settings.sectionNames,...${orig}]`
+
(orig) => `[...require("settings_settings").Settings.sectionNames,...${orig}]`
)}??${sections}.find(x=>x.section==${section})?._moonlight_submenu?.()`
}
}
+3 -11
packages/core-extensions/src/settings/webpackModules/settings.ts
···
-
import {
-
SettingsSection,
-
Settings as SettingsType
-
} from "@moonlight-mod/types/coreExtensions/settings";
+
import { SettingsSection, Settings as SettingsType } from "@moonlight-mod/types/coreExtensions/settings";
export const Settings: SettingsType = {
ourSections: [],
···
},
addSectionMenuItems(section, ...newItems) {
const data = Settings.ourSections.find((x) => x.section === section);
-
if (!data || !("element" in data))
-
throw new Error(`Could not find section "${section}"`);
+
if (!data || !("element" in data)) throw new Error(`Could not find section "${section}"`);
(Settings.sectionMenuItems[section] ??= []).push(...newItems);
data._moonlight_submenu ??= () => Settings.sectionMenuItems[section];
},
···
_mutateSections: (sections) => {
for (const section of Settings.ourSections) {
-
sections.splice(
-
section.pos < 0 ? sections.length + section.pos : section.pos,
-
0,
-
section
-
);
+
sections.splice(section.pos < 0 ? sections.length + section.pos : section.pos, 0, section);
}
return sections;
+13 -46
packages/core-extensions/src/spacepack/webpackModules/spacepack.ts
···
-
import {
-
WebpackModule,
-
WebpackModuleFunc,
-
WebpackRequireType
-
} from "@moonlight-mod/types";
+
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "@moonlight-mod/types";
import { Spacepack } from "@moonlight-mod/types/coreExtensions/spacepack";
const webpackRequire = require as unknown as WebpackRequireType;
···
"module",
"exports",
"require",
-
`(${funcStr}).apply(this, arguments)\n` +
-
`//# sourceURL=Webpack-Module-${module}`
+
`(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module-${module}`
) as WebpackModuleFunc;
},
···
.filter(
([id, mod]) =>
!args.some(
-
(item) =>
-
!(item instanceof RegExp
-
? item.test(mod.toString())
-
: mod.toString().indexOf(item) !== -1)
+
(item) => !(item instanceof RegExp ? item.test(mod.toString()) : mod.toString().indexOf(item) !== -1)
)
)
.map(([id]) => {
···
!(
exports !== undefined &&
exports !== window &&
-
(exports?.[item] ||
-
exports?.default?.[item] ||
-
exports?.Z?.[item] ||
-
exports?.ZP?.[item])
+
(exports?.[item] || exports?.default?.[item] || exports?.Z?.[item] || exports?.ZP?.[item])
)
)
)
···
return null;
},
-
findObjectFromKeyValuePair: (
-
exports: Record<string, any>,
-
key: string,
-
value: any
-
) => {
+
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => {
for (const exportKey in exports) {
const obj = exports[exportKey];
// eslint-disable-next-line eqeqeq
···
return null;
},
-
findFunctionByStrings: (
-
exports: Record<string, any>,
-
...strings: (string | RegExp)[]
-
) => {
+
findFunctionByStrings: (exports: Record<string, any>, ...strings: (string | RegExp)[]) => {
return (
Object.entries(exports).filter(
([index, func]) =>
typeof func === "function" &&
!strings.some(
-
(query) =>
-
!(query instanceof RegExp
-
? func.toString().match(query)
-
: func.toString().includes(query))
+
(query) => !(query instanceof RegExp ? func.toString().match(query) : func.toString().includes(query))
)
)?.[0]?.[1] ?? null
);
},
-
lazyLoad: (
-
find: string | RegExp | (string | RegExp)[],
-
chunk: RegExp,
-
module: RegExp
-
) => {
-
const mod = Array.isArray(find)
-
? spacepack.findByCode(...find)
-
: spacepack.findByCode(find);
+
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => {
+
const mod = Array.isArray(find) ? spacepack.findByCode(...find) : spacepack.findByCode(find);
if (mod.length < 1) return Promise.reject("Module find failed");
const findId = mod[0].id;
···
chunkIds = [...findCode.matchAll(chunk)].map(([, id]) => id);
} else {
const match = findCode.match(chunk);
-
if (match)
-
chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
+
if (match) chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
}
-
if (!chunkIds || chunkIds.length === 0)
-
return Promise.reject("Chunk ID match failed");
+
if (!chunkIds || chunkIds.length === 0) return Promise.reject("Chunk ID match failed");
const moduleId = findCode.match(module)?.[1];
if (!moduleId) return Promise.reject("Module ID match failed");
-
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() =>
-
webpackRequire(moduleId)
-
);
+
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() => webpackRequire(moduleId));
},
filterReal: (modules: WebpackModule[]) => {
···
}
};
-
if (
-
moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true
-
) {
+
if (moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true) {
window.spacepack = spacepack;
}
+2 -7
packages/core/src/config.ts
···
export async function writeConfig(config: Config) {
try {
const configPath = await getConfigPath();
-
await moonlightFS.writeFileString(
-
configPath,
-
JSON.stringify(config, null, 2)
-
);
+
await moonlightFS.writeFileString(configPath, JSON.stringify(config, null, 2));
} catch (e) {
logger.error("Failed to write config", e);
}
···
return defaultConfig;
} else {
try {
-
let config: Config = JSON.parse(
-
await moonlightFS.readFileString(configPath)
-
);
+
let config: Config = JSON.parse(await moonlightFS.readFileString(configPath));
// Assign the default values if they don't exist (newly added)
config = { ...defaultConfig, ...config };
await writeConfig(config);
+15 -59
packages/core/src/extension.ts
···
-
import {
-
ExtensionManifest,
-
DetectedExtension,
-
ExtensionLoadSource,
-
constants
-
} from "@moonlight-mod/types";
+
import { ExtensionManifest, DetectedExtension, ExtensionLoadSource, constants } from "@moonlight-mod/types";
import { readConfig } from "./config";
import { getCoreExtensionsPath, getExtensionsPath } from "./util/data";
import Logger from "./util/logger";
···
return ret;
}
-
async function loadDetectedExtensions(
-
dir: string,
-
type: ExtensionLoadSource
-
): Promise<DetectedExtension[]> {
+
async function loadDetectedExtensions(dir: string, type: ExtensionLoadSource): Promise<DetectedExtension[]> {
const ret: DetectedExtension[] = [];
const manifests = await findManifests(dir);
···
if (!(await moonlightFS.exists(manifestPath))) continue;
const dir = moonlightFS.dirname(manifestPath);
-
const manifest: ExtensionManifest = JSON.parse(
-
await moonlightFS.readFileString(manifestPath)
-
);
+
const manifest: ExtensionManifest = JSON.parse(await moonlightFS.readFileString(manifestPath));
const webPath = moonlightFS.join(dir, "index.js");
const nodePath = moonlightFS.join(dir, "node.js");
const hostPath = moonlightFS.join(dir, "host.js");
// if none exist (empty manifest) don't give a shit
-
if (
-
!moonlightFS.exists(webPath) &&
-
!moonlightFS.exists(nodePath) &&
-
!moonlightFS.exists(hostPath)
-
) {
+
if (!moonlightFS.exists(webPath) && !moonlightFS.exists(nodePath) && !moonlightFS.exists(hostPath)) {
continue;
}
-
const web = (await moonlightFS.exists(webPath))
-
? await moonlightFS.readFileString(webPath)
-
: undefined;
+
const web = (await moonlightFS.exists(webPath)) ? await moonlightFS.readFileString(webPath) : undefined;
let url: string | undefined = undefined;
const urlPath = moonlightFS.join(dir, constants.repoUrlFile);
-
if (
-
type === ExtensionLoadSource.Normal &&
-
(await moonlightFS.exists(urlPath))
-
) {
+
if (type === ExtensionLoadSource.Normal && (await moonlightFS.exists(urlPath))) {
url = await moonlightFS.readFileString(urlPath);
}
···
for (const wpModuleFile of wpModulesFile) {
if (wpModuleFile.endsWith(".js")) {
-
wpModules[wpModuleFile.replace(".js", "")] =
-
await moonlightFS.readFileString(
-
moonlightFS.join(wpModulesPath, wpModuleFile)
-
);
+
wpModules[wpModuleFile.replace(".js", "")] = await moonlightFS.readFileString(
+
moonlightFS.join(wpModulesPath, wpModuleFile)
+
);
}
}
}
···
const config = await readConfig();
const res = [];
-
res.push(
-
...(await loadDetectedExtensions(
-
getCoreExtensionsPath(),
-
ExtensionLoadSource.Core
-
))
-
);
+
res.push(...(await loadDetectedExtensions(getCoreExtensionsPath(), ExtensionLoadSource.Core)));
-
res.push(
-
...(await loadDetectedExtensions(
-
await getExtensionsPath(),
-
ExtensionLoadSource.Normal
-
))
-
);
+
res.push(...(await loadDetectedExtensions(await getExtensionsPath(), ExtensionLoadSource.Normal)));
for (const devSearchPath of config.devSearchPaths ?? []) {
-
res.push(
-
...(await loadDetectedExtensions(
-
devSearchPath,
-
ExtensionLoadSource.Developer
-
))
-
);
+
res.push(...(await loadDetectedExtensions(devSearchPath, ExtensionLoadSource.Developer)));
}
return res;
···
// @ts-expect-error shut up
_moonlight_coreExtensionsStr
);
-
const coreExtensions = Array.from(
-
new Set(Object.keys(coreExtensionsFs).map((x) => x.split("/")[0]))
-
);
+
const coreExtensions = Array.from(new Set(Object.keys(coreExtensionsFs).map((x) => x.split("/")[0])));
for (const ext of coreExtensions) {
if (!coreExtensionsFs[`${ext}/index.js`]) continue;
···
const wpModulesPath = `${ext}/webpackModules`;
for (const wpModuleFile of Object.keys(coreExtensionsFs)) {
if (wpModuleFile.startsWith(wpModulesPath)) {
-
wpModules[
-
wpModuleFile.replace(wpModulesPath + "/", "").replace(".js", "")
-
] = coreExtensionsFs[wpModuleFile];
+
wpModules[wpModuleFile.replace(wpModulesPath + "/", "").replace(".js", "")] = coreExtensionsFs[wpModuleFile];
}
}
···
}
if (await moonlightFS.exists("/extensions")) {
-
ret.push(
-
...(await loadDetectedExtensions(
-
"/extensions",
-
ExtensionLoadSource.Normal
-
))
-
);
+
ret.push(...(await loadDetectedExtensions("/extensions", ExtensionLoadSource.Normal)));
}
return ret;
+8 -25
packages/core/src/extension/loader.ts
···
}
if (exports.styles != null) {
-
registerStyles(
-
exports.styles.map((style, i) => `/* ${ext.id}#${i} */ ${style}`)
-
);
+
registerStyles(exports.styles.map((style, i) => `/* ${ext.id}#${i} */ ${style}`));
}
}
}
···
InvalidEnvironment
}
-
export function checkExtensionCompat(
-
manifest: ExtensionManifest
-
): ExtensionCompat {
+
export function checkExtensionCompat(manifest: ExtensionManifest): ExtensionCompat {
let environment;
webTarget: {
environment = ExtensionEnvironment.Web;
···
environment = ExtensionEnvironment.Desktop;
}
-
if (manifest.apiLevel !== constants.apiLevel)
-
return ExtensionCompat.InvalidApiLevel;
-
if (
-
(manifest.environment ?? "both") !== "both" &&
-
manifest.environment !== environment
-
)
+
if (manifest.apiLevel !== constants.apiLevel) return ExtensionCompat.InvalidApiLevel;
+
if ((manifest.environment ?? "both") !== "both" && manifest.environment !== environment)
return ExtensionCompat.InvalidEnvironment;
return ExtensionCompat.Compatible;
}
···
extensions fires an event on completion, which allows us to await the loading
of another extension, resolving dependencies & load order effectively.
*/
-
export async function loadExtensions(
-
exts: DetectedExtension[]
-
): Promise<ProcessedExtensions> {
-
exts = exts.filter(
-
(ext) => checkExtensionCompat(ext.manifest) === ExtensionCompat.Compatible
-
);
+
export async function loadExtensions(exts: DetectedExtension[]): Promise<ProcessedExtensions> {
+
exts = exts.filter((ext) => checkExtensionCompat(ext.manifest) === ExtensionCompat.Compatible);
const config = await readConfig();
const items = exts
···
};
}
-
export async function loadProcessedExtensions({
-
extensions,
-
dependencyGraph
-
}: ProcessedExtensions) {
+
export async function loadProcessedExtensions({ extensions, dependencyGraph }: ProcessedExtensions) {
const eventEmitter = createEventEmitter<EventType, EventPayloads>();
const finished: Set<string> = new Set();
···
);
if (waitPromises.length > 0) {
-
logger.debug(
-
`Waiting on ${waitPromises.length} dependencies for "${ext.id}"`
-
);
+
logger.debug(`Waiting on ${waitPromises.length} dependencies for "${ext.id}"`);
await Promise.all(waitPromises);
}
+21 -59
packages/core/src/patch.ts
···
let webpackModules: Set<IdentifiedWebpackModule> = new Set();
let webpackRequire: WebpackRequireType | null = null;
-
const moduleLoadSubscriptions: Map<string, ((moduleId: string) => void)[]> =
-
new Map();
+
const moduleLoadSubscriptions: Map<string, ((moduleId: string) => void)[]> = new Map();
export function registerPatch(patch: IdentifiedPatch) {
patches.push(patch);
···
}
}
-
export function onModuleLoad(
-
module: string | string[],
-
callback: (moduleId: string) => void
-
): void {
+
export function onModuleLoad(module: string | string[], callback: (moduleId: string) => void): void {
let moduleIds = module;
if (typeof module === "string") {
···
`//# sourceURL=Webpack-Module-${id}`;
try {
-
const func = new Function(
-
"module",
-
"exports",
-
"require",
-
wrapped
-
) as WebpackModuleFunc;
+
const func = new Function("module", "exports", "require", wrapped) as WebpackModuleFunc;
entry[id] = func;
entry[id].__moonlight = true;
return true;
···
// indexOf is faster than includes by 0.25% lmao
const match =
-
typeof patch.find === "string"
-
? moduleString.indexOf(patch.find) !== -1
-
: patch.find.test(moduleString);
+
typeof patch.find === "string" ? moduleString.indexOf(patch.find) !== -1 : patch.find.test(moduleString);
// Global regexes apply to all modules
-
const shouldRemove =
-
typeof patch.find === "string" ? true : !patch.find.global;
+
const shouldRemove = typeof patch.find === "string" ? true : !patch.find.global;
if (match) {
moonlight.unpatched.delete(patch);
···
// We ensured all arrays get turned into normal PatchReplace objects on register
const replace = patch.replace as PatchReplace;
-
if (
-
replace.type === undefined ||
-
replace.type === PatchReplaceType.Normal
-
) {
+
if (replace.type === undefined || replace.type === PatchReplaceType.Normal) {
// Add support for \i to match rspack's minified names
if (typeof replace.match !== "string") {
-
replace.match = new RegExp(
-
replace.match.source.replace(/\\i/g, "[A-Za-z_$][\\w$]*"),
-
replace.match.flags
-
);
+
replace.match = new RegExp(replace.match.source.replace(/\\i/g, "[A-Za-z_$][\\w$]*"), replace.match.flags);
}
// tsc fails to detect the overloads for this, so I'll just do this
// Verbose, but it works
···
const newModule = replace.replacement(moduleString);
entry[id] = newModule;
entry[id].__moonlight = true;
-
moduleString =
-
newModule.toString().replace(/\n/g, "") +
-
`//# sourceURL=Webpack-Module-${id}`;
+
moduleString = newModule.toString().replace(/\n/g, "") + `//# sourceURL=Webpack-Module-${id}`;
}
if (shouldRemove) {
···
}
if (moonlightNode.config.patchAll === true) {
-
if (
-
(typeof id !== "string" || !id.includes("_")) &&
-
!entry[id].__moonlight
-
) {
-
const wrapped =
-
`(${moduleCache[id]}).apply(this, arguments)\n` +
-
`//# sourceURL=Webpack-Module-${id}`;
-
entry[id] = new Function(
-
"module",
-
"exports",
-
"require",
-
wrapped
-
) as WebpackModuleFunc;
+
if ((typeof id !== "string" || !id.includes("_")) && !entry[id].__moonlight) {
+
const wrapped = `(${moduleCache[id]}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module-${id}`;
+
entry[id] = new Function("module", "exports", "require", wrapped) as WebpackModuleFunc;
entry[id].__moonlight = true;
}
}
···
function handleModuleDependencies() {
const modules = Array.from(webpackModules.values());
-
const dependencies: Dependency<string, IdentifiedWebpackModule>[] =
-
modules.map((wp) => {
-
return {
-
id: depToString(wp),
-
data: wp
-
};
-
});
+
const dependencies: Dependency<string, IdentifiedWebpackModule>[] = modules.map((wp) => {
+
return {
+
id: depToString(wp),
+
data: wp
+
};
+
});
const [sorted, _] = calculateDependencies(dependencies, {
fetchDep: (id) => {
···
const deps = item.data?.dependencies ?? [];
return (
deps.filter(
-
(dep) =>
-
!(dep instanceof RegExp || typeof dep === "string") &&
-
dep.ext != null
+
(dep) => !(dep instanceof RegExp || typeof dep === "string") && dep.ext != null
) as ExplicitExtensionDependency[]
).map(depToString);
}
···
if (dep.test(modStr)) deps.delete(dep);
} else if (
dep.ext != null
-
? injectedWpModules.find(
-
(x) => x.ext === dep.ext && x.id === dep.id
-
)
+
? injectedWpModules.find((x) => x.ext === dep.ext && x.id === dep.id)
: injectedWpModules.find((x) => x.id === dep.id)
) {
deps.delete(dep);
···
if (!webpackModules.size) break;
}
-
for (const [name, func] of Object.entries(
-
moonlight.moonmap.getWebpackModules("window.moonlight.moonmap")
-
)) {
+
for (const [name, func] of Object.entries(moonlight.moonmap.getWebpackModules("window.moonlight.moonmap"))) {
injectedWpModules.push({ id: name, run: func });
modules[name] = func;
inject = true;
···
});
patchModules(modules);
-
if (!window.webpackChunkdiscord_app)
-
window.webpackChunkdiscord_app = [];
+
if (!window.webpackChunkdiscord_app) window.webpackChunkdiscord_app = [];
injectModules(modules);
}
+2 -12
packages/core/src/persist.ts
···
import { join, dirname } from "node:path";
-
import {
-
mkdirSync,
-
renameSync,
-
existsSync,
-
copyFileSync,
-
readdirSync
-
} from "node:fs";
+
import { mkdirSync, renameSync, existsSync, copyFileSync, readdirSync } from "node:fs";
import Logger from "./util/logger";
const logger = new Logger("core/persist");
···
if (event === "host-updated") {
const versions = this.queryCurrentVersionsSync();
-
const newRootDir = join(
-
this.rootPath,
-
"app-" +
-
versions.current_host.map((v: number) => v.toString()).join(".")
-
);
+
const newRootDir = join(this.rootPath, "app-" + versions.current_host.map((v: number) => v.toString()).join("."));
logger.info(`Persisting moonlight - new root dir: ${newRootDir}`);
const newResources = join(newRootDir, "resources");
+1 -4
packages/core/src/util/binary.ts
···
return data;
}
-
private _read<T>(
-
func: (position: number, littleEndian?: boolean) => T,
-
length: number
-
): T {
+
private _read<T>(func: (position: number, littleEndian?: boolean) => T, length: number): T {
const result = func.call(this.view, this.position, true);
this.position += length;
return result;
+2 -7
packages/core/src/util/data.ts
···
let configPath = "";
-
const buildInfoPath = moonlightFS.join(
-
process.resourcesPath,
-
"build_info.json"
-
);
+
const buildInfoPath = moonlightFS.join(process.resourcesPath, "build_info.json");
if (!(await moonlightFS.exists(buildInfoPath))) {
configPath = moonlightFS.join(dir, "desktop.json");
} else {
-
const buildInfo: BuildInfo = JSON.parse(
-
await moonlightFS.readFileString(buildInfoPath)
-
);
+
const buildInfo: BuildInfo = JSON.parse(await moonlightFS.readFileString(buildInfoPath));
configPath = moonlightFS.join(dir, buildInfo.releaseChannel + ".json");
}
+4 -12
packages/core/src/util/dependency.ts
···
validateDeps({ id, data });
}
} else {
-
const dependsOnMe = Array.from(dependencyGraphOrig.entries()).filter(
-
([, v]) => v?.has(dep.id)
-
);
+
const dependsOnMe = Array.from(dependencyGraphOrig.entries()).filter(([, v]) => v?.has(dep.id));
if (dependsOnMe.length > 0) {
logger.debug("Implicitly enabling dependency", dep.id);
···
}
for (const dep of itemsOrig) validateDeps(dep);
-
itemsOrig = itemsOrig.filter(
-
(x) => getEnabled(x) || implicitlyEnabled.includes(x.id)
-
);
+
itemsOrig = itemsOrig.filter((x) => getEnabled(x) || implicitlyEnabled.includes(x.id));
}
if (getIncompatible != null) {
···
dependencyGraph.set(item.id, new Set(dependencyGraph.get(item.id)));
}
-
while (
-
Array.from(dependencyGraph.values()).filter((x) => x != null).length > 0
-
) {
-
const noDependents = items.filter(
-
(e) => dependencyGraph.get(e.id)?.size === 0
-
);
+
while (Array.from(dependencyGraph.values()).filter((x) => x != null).length > 0) {
+
const noDependents = items.filter((e) => dependencyGraph.get(e.id)?.size === 0);
if (noDependents.length === 0) {
logger.warn("Stuck dependency graph detected", dependencyGraph);
+7 -27
packages/core/src/util/event.ts
···
const listeners = new Map<(data: EventData) => void, (e: Event) => void>();
return {
-
dispatchEvent: <Id extends keyof EventData>(
-
id: Id,
-
data: EventData[Id]
-
) => {
-
eventEmitter.dispatchEvent(
-
new CustomEvent(id as string, { detail: data })
-
);
+
dispatchEvent: <Id extends keyof EventData>(id: Id, data: EventData[Id]) => {
+
eventEmitter.dispatchEvent(new CustomEvent(id as string, { detail: data }));
},
-
addEventListener: <Id extends keyof EventData>(
-
id: Id,
-
cb: (data: EventData[Id]) => void
-
) => {
+
addEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
const untyped = cb as (data: EventData) => void;
if (listeners.has(untyped)) return;
···
eventEmitter.addEventListener(id as string, listener);
},
-
removeEventListener: <Id extends keyof EventData>(
-
id: Id,
-
cb: (data: EventData[Id]) => void
-
) => {
+
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
const untyped = cb as (data: EventData) => void;
const listener = listeners.get(untyped);
if (listener == null) return;
···
const listeners = new Map<(data: EventData) => void, (e: Event) => void>();
return {
-
dispatchEvent: <Id extends keyof EventData>(
-
id: Id,
-
data: EventData[Id]
-
) => {
+
dispatchEvent: <Id extends keyof EventData>(id: Id, data: EventData[Id]) => {
eventEmitter.emit(id as string, data);
},
-
addEventListener: <Id extends keyof EventData>(
-
id: Id,
-
cb: (data: EventData[Id]) => void
-
) => {
+
addEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
const untyped = cb as (data: EventData) => void;
if (listeners.has(untyped)) return;
···
eventEmitter.on(id as string, listener);
},
-
removeEventListener: <Id extends keyof EventData>(
-
id: Id,
-
cb: (data: EventData[Id]) => void
-
) => {
+
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => {
const untyped = cb as (data: EventData) => void;
const listener = listeners.get(untyped);
if (listener == null) return;
+1 -3
packages/core/src/util/import.ts
···
fs: typeof import("fs");
};
-
export default function requireImport<T extends CanRequire>(
-
type: T
-
): Awaited<ImportTypes[T]> {
+
export default function requireImport<T extends CanRequire>(type: T): Awaited<ImportTypes[T]> {
return require(type);
}
+2 -8
packages/core/src/util/logger.ts
···
if (maxLevel > level) return;
if (MOONLIGHT_WEB_PRELOAD || MOONLIGHT_BROWSER) {
-
args = [
-
`%c[${logLevel}]`,
-
`background-color: ${colors[level]}; color: #FFFFFF;`,
-
`[${this.name}]`,
-
...obj
-
];
+
args = [`%c[${logLevel}]`, `background-color: ${colors[level]}; color: #FFFFFF;`, `[${this.name}]`, ...obj];
} else {
args = [`[${logLevel}]`, `[${this.name}]`, ...obj];
}
···
export function initLogger(config: Config) {
if (config.loggerLevel != null) {
-
const enumValue =
-
LogLevel[config.loggerLevel.toUpperCase() as keyof typeof LogLevel];
+
const enumValue = LogLevel[config.loggerLevel.toUpperCase() as keyof typeof LogLevel];
if (enumValue != null) {
maxLevel = enumValue;
}
+8 -31
packages/injector/src/index.ts
···
import { readConfig } from "@moonlight-mod/core/config";
import { getExtensions } from "@moonlight-mod/core/extension";
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
-
import {
-
loadExtensions,
-
loadProcessedExtensions
-
} from "@moonlight-mod/core/extension/loader";
+
import { loadExtensions, loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
import EventEmitter from "node:events";
import { join, resolve } from "node:path";
import persist from "@moonlight-mod/core/persist";
···
});
const reEscapeRegExp = /[\\^$.*+?()[\]{}|]/g;
-
const reMatchPattern =
-
/^(?<scheme>\*|[a-z][a-z0-9+.-]*):\/\/(?<host>.+?)\/(?<path>.+)?$/;
+
const reMatchPattern = /^(?<scheme>\*|[a-z][a-z0-9+.-]*):\/\/(?<host>.+?)\/(?<path>.+)?$/;
const escapeRegExp = (s: string) => s.replace(reEscapeRegExp, "\\$&");
ipcMain.handle(constants.ipcSetBlockedList, (_, list: string[]) => {
···
});
function patchCsp(headers: Record<string, string[]>) {
-
const directives = [
-
"style-src",
-
"connect-src",
-
"img-src",
-
"font-src",
-
"media-src",
-
"worker-src",
-
"prefetch-src"
-
];
+
const directives = ["style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src", "prefetch-src"];
const values = ["*", "blob:", "data:", "'unsafe-inline'", "disclip:"];
const csp = "content-security-policy";
···
constructor(opts: BrowserWindowConstructorOptions) {
oldPreloadPath = opts.webPreferences!.preload;
-
const isMainWindow =
-
opts.webPreferences!.preload!.indexOf("discord_desktop_core") > -1;
+
const isMainWindow = opts.webPreferences!.preload!.indexOf("discord_desktop_core") > -1;
-
if (isMainWindow)
-
opts.webPreferences!.preload = require.resolve("./node-preload.js");
+
if (isMainWindow) opts.webPreferences!.preload = require.resolve("./node-preload.js");
// Event for modifying window options
moonlightHost.events.emit("window-options", opts, isMainWindow);
···
// Someone can always make a command line modifier plugin, thats the point
// of having host modules.
try {
-
const cmdSwitchesPath = require.resolve(
-
join(asarPath, "cmdSwitches.js")
-
);
-
require.cache[cmdSwitchesPath] = new Module(
-
cmdSwitchesPath,
-
require.cache[require.resolve(asarPath)]
-
);
+
const cmdSwitchesPath = require.resolve(join(asarPath, "cmdSwitches.js"));
+
require.cache[cmdSwitchesPath] = new Module(cmdSwitchesPath, require.cache[require.resolve(asarPath)]);
require.cache[cmdSwitchesPath]!.exports = () => {};
} catch (error) {
logger.error("Failed to disable OpenAsar's command line flags:", error);
···
configurable: false
});
} else {
-
Object.defineProperty(
-
electronClone,
-
property,
-
Object.getOwnPropertyDescriptor(electron, property)!
-
);
+
Object.defineProperty(electronClone, property, Object.getOwnPropertyDescriptor(electron, property)!);
}
}
+5 -17
packages/node-preload/src/index.ts
···
import { readConfig, writeConfig } from "@moonlight-mod/core/config";
import { constants, MoonlightBranch } from "@moonlight-mod/types";
import { getExtensions } from "@moonlight-mod/core/extension";
-
import {
-
getExtensionsPath,
-
getMoonlightDir
-
} from "@moonlight-mod/core/util/data";
+
import { getExtensionsPath, getMoonlightDir } from "@moonlight-mod/core/util/data";
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
-
import {
-
loadExtensions,
-
loadProcessedExtensions
-
} from "@moonlight-mod/core/extension/loader";
+
import { loadExtensions, loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
import createFS from "@moonlight-mod/core/fs";
async function injectGlobals() {
···
await loadProcessedExtensions(processedExtensions);
contextBridge.exposeInMainWorld("moonlightNode", moonlightNode);
-
const extCors = moonlightNode.processedExtensions.extensions.flatMap(
-
(x) => x.manifest.cors ?? []
-
);
+
const extCors = moonlightNode.processedExtensions.extensions.flatMap((x) => x.manifest.cors ?? []);
for (const repo of moonlightNode.config.repositories) {
const url = new URL(repo);
···
ipcRenderer.invoke(constants.ipcSetCorsList, extCors);
-
const extBlocked = moonlightNode.processedExtensions.extensions.flatMap(
-
(e) => e.manifest.blocked ?? []
-
);
+
const extBlocked = moonlightNode.processedExtensions.extensions.flatMap((e) => e.manifest.blocked ?? []);
ipcRenderer.invoke(constants.ipcSetBlockedList, extBlocked);
}
···
if (oldPreloadPath) require(oldPreloadPath);
}
-
const oldPreloadPath: string = ipcRenderer.sendSync(
-
constants.ipcGetOldPreloadPath
-
);
+
const oldPreloadPath: string = ipcRenderer.sendSync(constants.ipcGetOldPreloadPath);
init(oldPreloadPath);
+1 -3
packages/types/src/config.ts
···
patchAll?: boolean;
};
-
export type ConfigExtensions =
-
| { [key: string]: boolean }
-
| { [key: string]: ConfigExtension };
+
export type ConfigExtensions = { [key: string]: boolean } | { [key: string]: ConfigExtension };
export type ConfigExtension = {
enabled: boolean;
+1 -2
packages/types/src/constants.ts
···
export const apiLevel = 2;
-
export const mainRepo =
-
"https://moonlight-mod.github.io/extensions-dist/repo.json";
+
export const mainRepo = "https://moonlight-mod.github.io/extensions-dist/repo.json";
+4 -16
packages/types/src/core/event.ts
···
import { WebpackModuleFunc, WebpackRequireType } from "../discord";
-
export interface MoonlightEventEmitter<
-
EventId extends string = string,
-
EventData = Record<EventId, any>
-
> {
-
dispatchEvent: <Id extends keyof EventData>(
-
id: Id,
-
data: EventData[Id]
-
) => void;
-
addEventListener: <Id extends keyof EventData>(
-
id: Id,
-
cb: (data: EventData[Id]) => void
-
) => void;
-
removeEventListener: <Id extends keyof EventData>(
-
id: Id,
-
cb: (data: EventData[Id]) => void
-
) => void;
+
export interface MoonlightEventEmitter<EventId extends string = string, EventData = Record<EventId, any>> {
+
dispatchEvent: <Id extends keyof EventData>(id: Id, data: EventData[Id]) => void;
+
addEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => void;
+
removeEventListener: <Id extends keyof EventData>(id: Id, cb: (data: EventData[Id]) => void) => void;
}
export enum EventType {
+2 -10
packages/types/src/coreExtensions/contextMenu.ts
···
}>;
export type MenuProps = React.ComponentProps<Menu>;
-
export type MenuElement =
-
| MenuSeparator
-
| MenuGroup
-
| MenuItem
-
| MenuCheckboxItem
-
| MenuRadioItem
-
| MenuControlItem;
+
export type MenuElement = MenuSeparator | MenuGroup | MenuItem | MenuCheckboxItem | MenuRadioItem | MenuControlItem;
export type MenuSeparator = React.FunctionComponent;
export type MenuGroup = React.FunctionComponent<{
···
};
export type EvilItemParser = (
-
el:
-
| React.ReactComponentElement<MenuElement>
-
| React.ReactComponentElement<MenuElement>[]
+
el: React.ReactComponentElement<MenuElement> | React.ReactComponentElement<MenuElement>[]
) => InternalItem[];
+5 -23
packages/types/src/coreExtensions/markdown.ts
···
export type ASTNode = SingleASTNode | Array<SingleASTNode>;
-
export type Parser = (
-
source: string,
-
state?: State | null | undefined
-
) => Array<SingleASTNode>;
+
export type Parser = (source: string, state?: State | null | undefined) => Array<SingleASTNode>;
-
export type ParseFunction = (
-
capture: Capture,
-
nestedParse: Parser,
-
state: State
-
) => UntypedASTNode | ASTNode;
+
export type ParseFunction = (capture: Capture, nestedParse: Parser, state: State) => UntypedASTNode | ASTNode;
export type Capture =
| (Array<string> & {
···
export type MatchFunction = {
regex?: RegExp;
-
} & ((
-
source: string,
-
state: State,
-
prevCapture: string
-
) => Capture | null | undefined);
+
} & ((source: string, state: State, prevCapture: string) => Capture | null | undefined);
-
export type Output<Result> = (
-
node: ASTNode,
-
state?: State | null | undefined
-
) => Result;
+
export type Output<Result> = (node: ASTNode, state?: State | null | undefined) => Result;
-
export type SingleNodeOutput<Result> = (
-
node: SingleASTNode,
-
nestedOutput: Output<Result>,
-
state: State
-
) => Result;
+
export type SingleNodeOutput<Result> = (node: SingleASTNode, nestedOutput: Output<Result>, state: State) => Result;
// }}}
+1 -5
packages/types/src/coreExtensions/moonbase.ts
···
}>;
export type Moonbase = {
-
registerConfigComponent: (
-
ext: string,
-
option: string,
-
component: CustomComponent
-
) => void;
+
registerConfigComponent: (ext: string, option: string, component: CustomComponent) => void;
};
+3 -15
packages/types/src/coreExtensions/spacepack.ts
···
-
import {
-
WebpackModule,
-
WebpackModuleFunc,
-
WebpackRequireType
-
} from "../discord";
+
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "../discord";
export type Spacepack = {
inspect: (module: number | string) => WebpackModuleFunc | null;
···
cache: Record<string, any>;
findObjectFromKey: (exports: Record<string, any>, key: string) => any | null;
findObjectFromValue: (exports: Record<string, any>, value: any) => any | null;
-
findObjectFromKeyValuePair: (
-
exports: Record<string, any>,
-
key: string,
-
value: any
-
) => any | null;
+
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => any | null;
findFunctionByStrings: (
exports: Record<string, any>,
...strings: (string | RegExp)[]
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
) => Function | null;
-
lazyLoad: (
-
find: string | RegExp | (string | RegExp)[],
-
chunk: RegExp,
-
module: RegExp
-
) => Promise<any>;
+
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => Promise<any>;
filterReal: (modules: WebpackModule[]) => WebpackModule[];
};
+2 -10
packages/types/src/discord/webpack.ts
···
exports: any;
};
-
export type WebpackModuleFunc = ((
-
module: any,
-
exports: any,
-
require: WebpackRequireType
-
) => void) & {
+
export type WebpackModuleFunc = ((module: any, exports: any, require: WebpackRequireType) => void) & {
__moonlight?: boolean;
};
-
export type WebpackJsonpEntry = [
-
number[],
-
{ [id: string]: WebpackModuleFunc },
-
(require: WebpackRequireType) => any
-
];
+
export type WebpackJsonpEntry = [number[], { [id: string]: WebpackModuleFunc }, (require: WebpackRequireType) => any];
export type WebpackJsonp = WebpackJsonpEntry[] & {
push: {
+1 -2
packages/types/src/extension.ts
···
id: number;
};
-
export type IdentifiedWebpackModule = ExtensionWebpackModule &
-
ExplicitExtensionDependency;
+
export type IdentifiedWebpackModule = ExtensionWebpackModule & ExplicitExtensionDependency;
+3 -15
packages/types/src/globals.ts
···
import type { Logger } from "./logger";
import type { Config, ConfigExtension } from "./config";
-
import type {
-
DetectedExtension,
-
IdentifiedPatch,
-
IdentifiedWebpackModule,
-
ProcessedExtensions
-
} from "./extension";
+
import type { DetectedExtension, IdentifiedPatch, IdentifiedWebpackModule, ProcessedExtensions } from "./extension";
import type EventEmitter from "events";
import type LunAST from "@moonlight-mod/lunast";
import type Moonmap from "@moonlight-mod/moonmap";
-
import type {
-
EventPayloads,
-
EventType,
-
MoonlightEventEmitter
-
} from "./core/event";
+
import type { EventPayloads, EventType, MoonlightEventEmitter } from "./core/event";
export type MoonlightHost = {
asarPath: string;
···
apiLevel: number;
events: MoonlightEventEmitter<EventType, EventPayloads>;
patchingInternals: {
-
onModuleLoad: (
-
moduleId: string | string[],
-
callback: (moduleId: string) => void
-
) => void;
+
onModuleLoad: (moduleId: string | string[], callback: (moduleId: string) => void) => void;
registerPatch: (patch: IdentifiedPatch) => void;
registerWebpackModule: (module: IdentifiedWebpackModule) => void;
};
+1 -6
packages/types/src/index.ts
···
/* eslint-disable no-var */
import { MoonlightFS } from "./fs";
-
import {
-
MoonlightEnv,
-
MoonlightHost,
-
MoonlightNode,
-
MoonlightWeb
-
} from "./globals";
+
import { MoonlightEnv, MoonlightHost, MoonlightNode, MoonlightWeb } from "./globals";
export * from "./discord";
export * from "./config";
+1 -6
packages/web-preload/src/index.ts
···
import { loadProcessedExtensions } from "@moonlight-mod/core/extension/loader";
-
import {
-
installWebpackPatcher,
-
onModuleLoad,
-
registerPatch,
-
registerWebpackModule
-
} from "@moonlight-mod/core/patch";
+
import { installWebpackPatcher, onModuleLoad, registerPatch, registerWebpackModule } from "@moonlight-mod/core/patch";
import { constants, MoonlightBranch } from "@moonlight-mod/types";
import { installStyles } from "@moonlight-mod/core/styles";
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";