diff --git a/package.json b/package.json
index 43ac36304..eb3e95a68 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"buildWeb": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/buildWeb.mjs",
"buildWebStandalone": "pnpm buildWeb --standalone",
"buildReporter": "pnpm buildWebStandalone --reporter --skip-extension",
+ "buildReporterDesktop": "pnpm build --reporter",
"watch": "pnpm build --watch",
"watchWeb": "pnpm buildWeb --watch",
"generatePluginJson": "tsx scripts/generatePluginList.ts",
diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts
index b5f040aa7..8864c78e4 100644
--- a/scripts/generateReport.ts
+++ b/scripts/generateReport.ts
@@ -16,6 +16,8 @@
* along with this program. If not, see .
*/
+/* eslint-disable no-fallthrough */
+
// eslint-disable-next-line spaced-comment
///
// eslint-disable-next-line spaced-comment
@@ -40,10 +42,11 @@ const browser = await pup.launch({
const page = await browser.newPage();
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36");
+await page.setBypassCSP(true);
-function maybeGetError(handle: JSHandle) {
- return (handle as JSHandle)?.getProperty("message")
- .then(m => m.jsonValue());
+async function maybeGetError(handle: JSHandle): Promise {
+ return await (handle as JSHandle)?.getProperty("message")
+ .then(m => m?.jsonValue());
}
const report = {
@@ -59,6 +62,7 @@ const report = {
error: string;
}[],
otherErrors: [] as string[],
+ ignoredErrors: [] as string[],
badWebpackFinds: [] as string[]
};
@@ -106,15 +110,6 @@ async function printReport() {
console.log();
- const ignoredErrors = [] as string[];
- report.otherErrors = report.otherErrors.filter(e => {
- if (IGNORED_DISCORD_ERRORS.some(regex => e.match(regex))) {
- ignoredErrors.push(e);
- return false;
- }
- return true;
- });
-
console.log("## Discord Errors");
report.otherErrors.forEach(e => {
console.log(`- ${toCodeBlock(e)}`);
@@ -123,7 +118,7 @@ async function printReport() {
console.log();
console.log("## Ignored Discord Errors");
- ignoredErrors.forEach(e => {
+ report.ignoredErrors.forEach(e => {
console.log(`- ${toCodeBlock(e)}`);
});
@@ -188,66 +183,6 @@ page.on("console", async e => {
const level = e.type();
const rawArgs = e.args();
- const firstArg = await rawArgs[0]?.jsonValue();
- if (firstArg === "[PUPPETEER_TEST_DONE_SIGNAL]") {
- await browser.close();
- await printReport();
- process.exit();
- }
-
- const isVencord = firstArg === "[Vencord]";
- const isDebug = firstArg === "[PUP_DEBUG]";
- const isWebpackFindFail = firstArg === "[PUP_WEBPACK_FIND_FAIL]";
-
- if (isWebpackFindFail) {
- process.exitCode = 1;
- report.badWebpackFinds.push(await rawArgs[1].jsonValue() as string);
- }
-
- if (isVencord) {
- let args: unknown[] = [];
- try {
- args = await Promise.all(e.args().map(a => a.jsonValue()));
- } catch {
- return;
- }
-
- const [, tag, message] = args as Array;
- const cause = await maybeGetError(e.args()[3]);
-
- switch (tag) {
- case "WebpackInterceptor:":
- const patchFailMatch = message.match(/Patch by (.+?) (had no effect|errored|found no module) \(Module id is (.+?)\): (.+)/)!;
- if (!patchFailMatch) break;
-
- process.exitCode = 1;
-
- const [, plugin, type, id, regex] = patchFailMatch;
- report.badPatches.push({
- plugin,
- type,
- id,
- match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
- error: cause
- });
-
- break;
- case "PluginManager:":
- const failedToStartMatch = message.match(/Failed to start (.+)/);
- if (!failedToStartMatch) break;
-
- process.exitCode = 1;
-
- const [, name] = failedToStartMatch;
- report.badStarts.push({
- plugin: name,
- error: cause
- });
-
- break;
- }
- }
-
async function getText() {
try {
return await Promise.all(
@@ -260,308 +195,98 @@ page.on("console", async e => {
}
}
- if (isDebug) {
- const text = await getText();
+ const firstArg = await rawArgs[0]?.jsonValue();
- console.error(text);
- if (text.includes("A fatal error occurred:")) {
- process.exit(1);
+ const isVencord = firstArg === "[Vencord]";
+ const isDebug = firstArg === "[PUP_DEBUG]";
+
+ outer:
+ if (isVencord) {
+ try {
+ var args = await Promise.all(e.args().map(a => a.jsonValue()));
+ } catch {
+ break outer;
}
+
+ const [, tag, message, otherMessage] = args as Array;
+
+ switch (tag) {
+ case "WebpackInterceptor:":
+ const patchFailMatch = message.match(/Patch by (.+?) (had no effect|errored|found no module) \(Module id is (.+?)\): (.+)/)!;
+ if (!patchFailMatch) break;
+
+ console.error(await getText());
+ process.exitCode = 1;
+
+ const [, plugin, type, id, regex] = patchFailMatch;
+ report.badPatches.push({
+ plugin,
+ type,
+ id,
+ match: regex.replace(/\[A-Za-z_\$\]\[\\w\$\]\*/g, "\\i"),
+ error: await maybeGetError(e.args()[3])
+ });
+
+ break;
+ case "PluginManager:":
+ const failedToStartMatch = message.match(/Failed to start (.+)/);
+ if (!failedToStartMatch) break;
+
+ console.error(await getText());
+ process.exitCode = 1;
+
+ const [, name] = failedToStartMatch;
+ report.badStarts.push({
+ plugin: name,
+ error: await maybeGetError(e.args()[3]) ?? "Unknown error"
+ });
+
+ break;
+ case "Reporter:":
+ console.error(await getText());
+
+ switch (message) {
+ case "Webpack Find Fail:":
+ process.exitCode = 1;
+ report.badWebpackFinds.push(otherMessage);
+ break;
+ case "A fatal error occurred:":
+ process.exit(1);
+ case "Finished test":
+ await browser.close();
+ await printReport();
+ process.exit();
+ }
+ }
+ }
+
+ if (isDebug) {
+ console.error(await getText());
} else if (level === "error") {
const text = await getText();
if (text.length && !text.startsWith("Failed to load resource: the server responded with a status of") && !text.includes("Webpack")) {
- console.error("[Unexpected Error]", text);
- report.otherErrors.push(text);
+ if (IGNORED_DISCORD_ERRORS.some(regex => text.match(regex))) {
+ report.ignoredErrors.push(text);
+ } else {
+ console.error("[Unexpected Error]", text);
+ report.otherErrors.push(text);
+ }
}
}
});
-page.on("error", e => console.error("[Error]", e));
-page.on("pageerror", e => console.error("[Page Error]", e));
-
-await page.setBypassCSP(true);
+page.on("error", e => console.error("[Error]", e.message));
+page.on("pageerror", e => console.error("[Page Error]", e.message));
async function reporterRuntime(token: string) {
- console.log("[PUP_DEBUG]", "Starting test...");
-
- try {
- // Spoof languages to not be suspicious
- Object.defineProperty(navigator, "languages", {
- get: function () {
- return ["en-US", "en"];
- }
- });
-
- let wreq: typeof Vencord.Webpack.wreq;
-
- const { canonicalizeMatch, Logger } = Vencord.Util;
-
- const validChunks = new Set();
- const invalidChunks = new Set();
- const deferredRequires = new Set();
-
- let chunksSearchingResolve: (value: void | PromiseLike) => void;
- const chunksSearchingDone = new Promise(r => chunksSearchingResolve = r);
-
- // True if resolved, false otherwise
- const chunksSearchPromises = [] as Array<() => boolean>;
-
- const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g);
-
- async function searchAndLoadLazyChunks(factoryCode: string) {
- const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
- const validChunkGroups = new Set<[chunkIds: string[], entryPoint: string]>();
-
- // Workaround for a chunk that depends on the ChannelMessage component but may be be force loaded before
- // the chunk containing the component
- const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT");
-
- await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => {
- const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Vencord.Webpack.ChunkIdsRegex)).map(m => m[1]) : [];
-
- if (chunkIds.length === 0) {
- return;
- }
-
- let invalidChunkGroup = false;
-
- for (const id of chunkIds) {
- if (wreq.u(id) == null || wreq.u(id) === "undefined.js") continue;
-
- const isWasm = await fetch(wreq.p + wreq.u(id))
- .then(r => r.text())
- .then(t => t.includes(".module.wasm") || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
-
- if (isWasm) {
- invalidChunks.add(id);
- invalidChunkGroup = true;
- continue;
- }
-
- validChunks.add(id);
- }
-
- if (!invalidChunkGroup) {
- validChunkGroups.add([chunkIds, entryPoint]);
- }
- }));
-
- // Loads all found valid chunk groups
- await Promise.all(
- Array.from(validChunkGroups)
- .map(([chunkIds]) =>
- Promise.all(chunkIds.map(id => wreq.e(id as any).catch(() => { })))
- )
- );
-
- // Requires the entry points for all valid chunk groups
- for (const [, entryPoint] of validChunkGroups) {
- try {
- if (shouldForceDefer) {
- deferredRequires.add(entryPoint);
- continue;
- }
-
- if (wreq.m[entryPoint]) wreq(entryPoint as any);
- } catch (err) {
- console.error(err);
- }
- }
-
- // setImmediate to only check if all chunks were loaded after this function resolves
- // We check if all chunks were loaded every time a factory is loaded
- // If we are still looking for chunks in the other factories, the array will have that factory's chunk search promise not resolved
- // But, if all chunk search promises are resolved, this means we found every lazy chunk loaded by Discord code and manually loaded them
- setTimeout(() => {
- let allResolved = true;
-
- for (let i = 0; i < chunksSearchPromises.length; i++) {
- const isResolved = chunksSearchPromises[i]();
-
- if (isResolved) {
- // Remove finished promises to avoid having to iterate through a huge array everytime
- chunksSearchPromises.splice(i--, 1);
- } else {
- allResolved = false;
- }
- }
-
- if (allResolved) chunksSearchingResolve();
- }, 0);
+ Vencord.Webpack.waitFor(
+ Vencord.Webpack.filters.byProps("loginToken"),
+ m => {
+ console.log("[PUP_DEBUG]", "Logging in with token...");
+ m.loginToken(token);
}
-
- Vencord.Webpack.waitFor(
- Vencord.Webpack.filters.byProps("loginToken"),
- m => {
- console.log("[PUP_DEBUG]", "Logging in with token...");
- m.loginToken(token);
- }
- );
-
- Vencord.Webpack.beforeInitListeners.add(async webpackRequire => {
- console.log("[PUP_DEBUG]", "Loading all chunks...");
-
- wreq = webpackRequire;
-
- Vencord.Webpack.factoryListeners.add(factory => {
- let isResolved = false;
- searchAndLoadLazyChunks(factory.toString()).then(() => isResolved = true);
-
- chunksSearchPromises.push(() => isResolved);
- });
-
- // setImmediate to only search the initial factories after Discord initialized the app
- // our beforeInitListeners are called before Discord initializes the app
- setTimeout(() => {
- for (const factoryId in wreq.m) {
- let isResolved = false;
- searchAndLoadLazyChunks(wreq.m[factoryId].toString()).then(() => isResolved = true);
-
- chunksSearchPromises.push(() => isResolved);
- }
- }, 0);
- });
-
- await chunksSearchingDone;
-
- // Require deferred entry points
- for (const deferredRequire of deferredRequires) {
- wreq!(deferredRequire as any);
- }
-
- // All chunks Discord has mapped to asset files, even if they are not used anymore
- const allChunks = [] as string[];
-
- // Matches "id" or id:
- for (const currentMatch of wreq!.u.toString().matchAll(/(?:"(\d+?)")|(?:(\d+?):)/g)) {
- const id = currentMatch[1] ?? currentMatch[2];
- if (id == null) continue;
-
- allChunks.push(id);
- }
-
- if (allChunks.length === 0) throw new Error("Failed to get all chunks");
-
- // Chunks that are not loaded (not used) by Discord code anymore
- const chunksLeft = allChunks.filter(id => {
- return !(validChunks.has(id) || invalidChunks.has(id));
- });
-
- await Promise.all(chunksLeft.map(async id => {
- const isWasm = await fetch(wreq.p + wreq.u(id))
- .then(r => r.text())
- .then(t => t.includes(".module.wasm") || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
-
- // Loads and requires a chunk
- if (!isWasm) {
- await wreq.e(id as any);
- if (wreq.m[id]) wreq(id as any);
- }
- }));
-
- console.log("[PUP_DEBUG]", "Finished loading all chunks!");
-
- for (const patch of Vencord.Plugins.patches) {
- if (!patch.all) {
- new Logger("WebpackInterceptor").warn(`Patch by ${patch.plugin} found no module (Module id is -): ${patch.find}`);
- }
- }
-
- await Promise.all(Vencord.Webpack.webpackSearchHistory.map(async ([searchType, args]) => {
- args = [...args];
-
- try {
- let result = null as any;
-
- switch (searchType) {
- case "webpackDependantLazy":
- case "webpackDependantLazyComponent": {
- const [factory] = args;
- result = factory();
- break;
- }
- case "extractAndLoadChunks": {
- const [code, matcher] = args;
-
- result = await Vencord.Webpack.extractAndLoadChunks(code, matcher);
- if (result === false) {
- result = null;
- }
-
- break;
- }
- default: {
- const findResult = args.shift();
-
- if (findResult != null) {
- if (findResult.$$vencordCallbackCalled != null && findResult.$$vencordCallbackCalled()) {
- result = findResult;
- }
-
- if (findResult[Vencord.Util.SYM_PROXY_INNER_GET] != null) {
- result = findResult[Vencord.Util.SYM_PROXY_INNER_VALUE];
- }
-
- if (findResult.$$vencordInner != null) {
- result = findResult.$$vencordInner();
- }
- }
-
- break;
- }
- }
-
- if (result == null) {
- throw "a rock at ben shapiro";
- }
- } catch (e) {
- let logMessage = searchType;
-
- let filterName = "";
- let parsedArgs = args;
-
- if (args[0].$$vencordProps != null) {
- if (["find", "findComponent", "waitFor"].includes(searchType)) {
- filterName = args[0].$$vencordProps[0];
- }
-
- parsedArgs = args[0].$$vencordProps.slice(1);
- }
-
- // if parsedArgs is the same as args, it means vencordProps of the filter was not available (like in normal filter functions),
- // so log the filter function instead
- if (
- parsedArgs === args &&
- ["waitFor", "find", "findComponent", "webpackDependantLazy", "webpackDependantLazyComponent"].includes(searchType)
- ) {
- let filter = parsedArgs[0].toString();
- if (filter.length > 150) {
- filter = filter.slice(0, 147) + "...";
- }
-
- logMessage += `(${filter})`;
- } else if (searchType === "extractAndLoadChunks") {
- let regexStr: string;
- if (parsedArgs[1] === Vencord.Webpack.DefaultExtractAndLoadChunksRegex) {
- regexStr = "DefaultExtractAndLoadChunksRegex";
- } else {
- regexStr = parsedArgs[1].toString();
- }
-
- logMessage += `([${parsedArgs[0].map((arg: any) => `"${arg}"`).join(", ")}], ${regexStr})`;
- } else {
- logMessage += `(${filterName.length ? `${filterName}(` : ""}${parsedArgs.map(arg => `"${arg}"`).join(", ")})${filterName.length ? ")" : ""}`;
- }
-
- console.log("[PUP_WEBPACK_FIND_FAIL]", logMessage);
- }
- }));
-
- setTimeout(() => console.log("[PUPPETEER_TEST_DONE_SIGNAL]"), 1000);
- } catch (e) {
- console.log("[PUP_DEBUG]", "A fatal error occurred:", e);
- }
+ );
}
await page.evaluateOnNewDocument(`
diff --git a/src/Vencord.ts b/src/Vencord.ts
index 4a73ee339..80aa1f9c7 100644
--- a/src/Vencord.ts
+++ b/src/Vencord.ts
@@ -42,6 +42,10 @@ import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
import { onceDiscordLoaded } from "./webpack";
import { SettingsRouter } from "./webpack/common";
+if (IS_REPORTER) {
+ require("./debug/runReporter");
+}
+
async function syncSettings() {
// pre-check for local shared settings
if (
diff --git a/src/api/DataStore/index.ts b/src/api/DataStore/index.ts
index 97f43edd6..47ae39dbd 100644
--- a/src/api/DataStore/index.ts
+++ b/src/api/DataStore/index.ts
@@ -49,7 +49,7 @@ let defaultGetStoreFunc: UseStore | undefined;
function defaultGetStore() {
if (!defaultGetStoreFunc) {
- defaultGetStoreFunc = createStore("VencordData", "VencordStore");
+ defaultGetStoreFunc = createStore(!IS_REPORTER ? "VencordData" : "VencordDataReporter", "VencordStore");
}
return defaultGetStoreFunc;
}
diff --git a/src/api/Settings.ts b/src/api/Settings.ts
index 490e6ef7f..b94e6a3fd 100644
--- a/src/api/Settings.ts
+++ b/src/api/Settings.ts
@@ -106,7 +106,7 @@ const DefaultSettings: Settings = {
}
};
-const settings = VencordNative.settings.get();
+const settings = !IS_REPORTER ? VencordNative.settings.get() : {} as Settings;
mergeDefaults(settings, DefaultSettings);
const saveSettingsOnFrequentAction = debounce(async () => {
@@ -156,12 +156,14 @@ export const SettingsStore = new SettingsStoreClass(settings, {
}
});
-SettingsStore.addGlobalChangeListener((_, path) => {
- SettingsStore.plain.cloud.settingsSyncVersion = Date.now();
- localStorage.Vencord_settingsDirty = true;
- saveSettingsOnFrequentAction();
- VencordNative.settings.set(SettingsStore.plain, path);
-});
+if (!IS_REPORTER) {
+ SettingsStore.addGlobalChangeListener((_, path) => {
+ SettingsStore.plain.cloud.settingsSyncVersion = Date.now();
+ localStorage.Vencord_settingsDirty = true;
+ saveSettingsOnFrequentAction();
+ VencordNative.settings.set(SettingsStore.plain, path);
+ });
+}
/**
* Same as {@link Settings} but unproxied. You should treat this as readonly,
diff --git a/src/debug/runReporter.ts b/src/debug/runReporter.ts
new file mode 100644
index 000000000..d2bae3365
--- /dev/null
+++ b/src/debug/runReporter.ts
@@ -0,0 +1,276 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { Logger } from "@utils/Logger";
+import { canonicalizeMatch } from "@utils/patches";
+import { SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner";
+import * as Webpack from "@webpack";
+import { wreq } from "@webpack";
+import { patches } from "plugins";
+
+const ReporterLogger = new Logger("Reporter");
+
+async function runReporter() {
+ ReporterLogger.log("Starting test...");
+
+ try {
+ const validChunks = new Set();
+ const invalidChunks = new Set();
+ const deferredRequires = new Set();
+
+ let chunksSearchingResolve: (value: void | PromiseLike) => void;
+ const chunksSearchingDone = new Promise(r => chunksSearchingResolve = r);
+
+ // True if resolved, false otherwise
+ const chunksSearchPromises = [] as Array<() => boolean>;
+
+ const LazyChunkRegex = canonicalizeMatch(/(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?)\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g);
+
+ async function searchAndLoadLazyChunks(factoryCode: string) {
+ const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
+ const validChunkGroups = new Set<[chunkIds: string[], entryPoint: string]>();
+
+ // Workaround for a chunk that depends on the ChannelMessage component but may be be force loaded before
+ // the chunk containing the component
+ const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT");
+
+ await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => {
+ const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Webpack.ChunkIdsRegex)).map(m => m[1]) : [];
+
+ if (chunkIds.length === 0) {
+ return;
+ }
+
+ let invalidChunkGroup = false;
+
+ for (const id of chunkIds) {
+ if (wreq.u(id) == null || wreq.u(id) === "undefined.js") continue;
+
+ const isWasm = await fetch(wreq.p + wreq.u(id))
+ .then(r => r.text())
+ .then(t => (IS_WEB && t.includes(".module.wasm")) || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
+
+ if (isWasm && IS_WEB) {
+ invalidChunks.add(id);
+ invalidChunkGroup = true;
+ continue;
+ }
+
+ validChunks.add(id);
+ }
+
+ if (!invalidChunkGroup) {
+ validChunkGroups.add([chunkIds, entryPoint]);
+ }
+ }));
+
+ // Loads all found valid chunk groups
+ await Promise.all(
+ Array.from(validChunkGroups)
+ .map(([chunkIds]) =>
+ Promise.all(chunkIds.map(id => wreq.e(id as any).catch(() => { })))
+ )
+ );
+
+ // Requires the entry points for all valid chunk groups
+ for (const [, entryPoint] of validChunkGroups) {
+ try {
+ if (shouldForceDefer) {
+ deferredRequires.add(entryPoint);
+ continue;
+ }
+
+ if (wreq.m[entryPoint]) wreq(entryPoint as any);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
+ // setImmediate to only check if all chunks were loaded after this function resolves
+ // We check if all chunks were loaded every time a factory is loaded
+ // If we are still looking for chunks in the other factories, the array will have that factory's chunk search promise not resolved
+ // But, if all chunk search promises are resolved, this means we found every lazy chunk loaded by Discord code and manually loaded them
+ setTimeout(() => {
+ let allResolved = true;
+
+ for (let i = 0; i < chunksSearchPromises.length; i++) {
+ const isResolved = chunksSearchPromises[i]();
+
+ if (isResolved) {
+ // Remove finished promises to avoid having to iterate through a huge array everytime
+ chunksSearchPromises.splice(i--, 1);
+ } else {
+ allResolved = false;
+ }
+ }
+
+ if (allResolved) chunksSearchingResolve();
+ }, 0);
+ }
+
+ Webpack.beforeInitListeners.add(async () => {
+ ReporterLogger.log("Loading all chunks...");
+
+ Webpack.factoryListeners.add(factory => {
+ let isResolved = false;
+ searchAndLoadLazyChunks(factory.toString()).then(() => isResolved = true);
+
+ chunksSearchPromises.push(() => isResolved);
+ });
+
+ // setImmediate to only search the initial factories after Discord initialized the app
+ // our beforeInitListeners are called before Discord initializes the app
+ setTimeout(() => {
+ for (const factoryId in wreq.m) {
+ let isResolved = false;
+ searchAndLoadLazyChunks(wreq.m[factoryId].toString()).then(() => isResolved = true);
+
+ chunksSearchPromises.push(() => isResolved);
+ }
+ }, 0);
+ });
+
+ await chunksSearchingDone;
+
+ // Require deferred entry points
+ for (const deferredRequire of deferredRequires) {
+ wreq!(deferredRequire as any);
+ }
+
+ // All chunks Discord has mapped to asset files, even if they are not used anymore
+ const allChunks = [] as string[];
+
+ // Matches "id" or id:
+ for (const currentMatch of wreq!.u.toString().matchAll(/(?:"(\d+?)")|(?:(\d+?):)/g)) {
+ const id = currentMatch[1] ?? currentMatch[2];
+ if (id == null) continue;
+
+ allChunks.push(id);
+ }
+
+ if (allChunks.length === 0) throw new Error("Failed to get all chunks");
+
+ // Chunks that are not loaded (not used) by Discord code anymore
+ const chunksLeft = allChunks.filter(id => {
+ return !(validChunks.has(id) || invalidChunks.has(id));
+ });
+
+ await Promise.all(chunksLeft.map(async id => {
+ const isWasm = await fetch(wreq.p + wreq.u(id))
+ .then(r => r.text())
+ .then(t => (IS_WEB && t.includes(".module.wasm")) || !t.includes("(this.webpackChunkdiscord_app=this.webpackChunkdiscord_app||[]).push"));
+
+ // Loads and requires a chunk
+ if (!isWasm) {
+ await wreq.e(id as any);
+ if (wreq.m[id]) wreq(id as any);
+ }
+ }));
+
+ ReporterLogger.log("Finished loading all chunks!");
+
+ for (const patch of patches) {
+ if (!patch.all) {
+ new Logger("WebpackInterceptor").warn(`Patch by ${patch.plugin} found no module (Module id is -): ${patch.find}`);
+ }
+ }
+ await Promise.all(Webpack.webpackSearchHistory.map(async ([searchType, args]) => {
+ args = [...args];
+
+ try {
+ let result = null as any;
+
+ switch (searchType) {
+ case "webpackDependantLazy":
+ case "webpackDependantLazyComponent": {
+ const [factory] = args;
+ result = factory();
+ break;
+ }
+ case "extractAndLoadChunks": {
+ const [code, matcher] = args;
+
+ result = await Webpack.extractAndLoadChunks(code, matcher);
+ if (result === false) {
+ result = null;
+ }
+
+ break;
+ }
+ default: {
+ const findResult = args.shift();
+
+ if (findResult != null) {
+ if (findResult.$$vencordCallbackCalled != null && findResult.$$vencordCallbackCalled()) {
+ result = findResult;
+ }
+
+ if (findResult[SYM_PROXY_INNER_GET] != null) {
+ result = findResult[SYM_PROXY_INNER_VALUE];
+ }
+
+ if (findResult.$$vencordInner != null) {
+ result = findResult.$$vencordInner();
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (result == null) {
+ throw "a rock at ben shapiro";
+ }
+ } catch (e) {
+ let logMessage = searchType;
+
+ let filterName = "";
+ let parsedArgs = args;
+
+ if (args[0].$$vencordProps != null) {
+ if (["find", "findComponent", "waitFor"].includes(searchType)) {
+ filterName = args[0].$$vencordProps[0];
+ }
+
+ parsedArgs = args[0].$$vencordProps.slice(1);
+ }
+
+ // if parsedArgs is the same as args, it means vencordProps of the filter was not available (like in normal filter functions),
+ // so log the filter function instead
+ if (
+ parsedArgs === args &&
+ ["waitFor", "find", "findComponent", "webpackDependantLazy", "webpackDependantLazyComponent"].includes(searchType)
+ ) {
+ let filter = parsedArgs[0].toString();
+ if (filter.length > 150) {
+ filter = filter.slice(0, 147) + "...";
+ }
+
+ logMessage += `(${filter})`;
+ } else if (searchType === "extractAndLoadChunks") {
+ let regexStr: string;
+ if (parsedArgs[1] === Webpack.DefaultExtractAndLoadChunksRegex) {
+ regexStr = "DefaultExtractAndLoadChunksRegex";
+ } else {
+ regexStr = parsedArgs[1].toString();
+ }
+
+ logMessage += `([${parsedArgs[0].map((arg: any) => `"${arg}"`).join(", ")}], ${regexStr})`;
+ } else {
+ logMessage += `(${filterName.length ? `${filterName}(` : ""}${parsedArgs.map(arg => `"${arg}"`).join(", ")})${filterName.length ? ")" : ""}`;
+ }
+
+ ReporterLogger.log("Webpack Find Fail:", logMessage);
+ }
+ }));
+
+ ReporterLogger.log("Finished test");
+ } catch (e) {
+ ReporterLogger.log("A fatal error occurred:", e);
+ }
+}
+
+runReporter();
diff --git a/src/main/updater/index.ts b/src/main/updater/index.ts
index 32d5cd663..539b02a48 100644
--- a/src/main/updater/index.ts
+++ b/src/main/updater/index.ts
@@ -17,4 +17,4 @@
*/
if (!IS_UPDATER_DISABLED)
- import(IS_STANDALONE ? "./http" : "./git");
+ require(IS_STANDALONE ? "./http" : "./git");
diff --git a/src/plugins/secretRingTone/index.ts b/src/plugins/secretRingTone/index.ts
index 9c3956a80..be804efc4 100644
--- a/src/plugins/secretRingTone/index.ts
+++ b/src/plugins/secretRingTone/index.ts
@@ -16,9 +16,8 @@ export default definePlugin({
{
find: '"call_ringing_beat"',
replacement: {
- // FIXME Remove === alternative when it hits stable
- match: /500(!==|===)\i\(\)\.random\(1,1e3\)/,
- replace: (_, predicate) => predicate === "!==" ? "false" : "true",
+ match: /500!==\i\(\)\.random\(1,1e3\)/,
+ replace: "false",
}
},
],
diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx
index aa0c03d56..0ea842954 100644
--- a/src/plugins/showHiddenChannels/index.tsx
+++ b/src/plugins/showHiddenChannels/index.tsx
@@ -73,8 +73,9 @@ export default definePlugin({
find: '"placeholder-channel-id"',
replacement: [
// Remove the special logic for channels we don't have access to
+ // FIXME Remove variable matcher from threadsIds when it hits stable
{
- match: /if\(!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL.+?{if\(this\.id===\i\).+?threadIds:\i}}/,
+ match: /if\(!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL.+?{if\(this\.id===\i\).+?threadIds:(?:\[\]|\i)}}/,
replace: ""
},
// Do not check for unreads when selecting the render level if the channel is hidden
diff --git a/src/utils/Logger.ts b/src/utils/Logger.ts
index e222d71fb..5296184d4 100644
--- a/src/utils/Logger.ts
+++ b/src/utils/Logger.ts
@@ -32,7 +32,7 @@ export class Logger {
constructor(public name: string, public color: string = "white") { }
private _log(level: "log" | "error" | "warn" | "info" | "debug", levelColor: string, args: any[], customFmt = "") {
- if (IS_REPORTER && (level === "warn" || level === "error")) {
+ if (IS_REPORTER) {
console[level]("[Vencord]", this.name + ":", ...args);
return;
}