From 6573c4757cc1b2e3847c037d254cbdd11653b579 Mon Sep 17 00:00:00 2001 From: Korbo Date: Tue, 28 Nov 2023 12:32:29 -0600 Subject: [PATCH 1/4] fix: strikethrough in SilentMessageToggle's disabled SVG (#2004) --- src/plugins/silentMessageToggle/index.tsx | 19 +++++++++---------- src/utils/constants.ts | 4 ++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/plugins/silentMessageToggle/index.tsx b/src/plugins/silentMessageToggle/index.tsx index a1ee8de89..b7b33826d 100644 --- a/src/plugins/silentMessageToggle/index.tsx +++ b/src/plugins/silentMessageToggle/index.tsx @@ -80,16 +80,15 @@ function SilentMessageToggle(chatBoxProps: { style={{ padding: "0 6px" }} >
- - - - - {!enabled && } - + + + {!enabled && <> + + + + + + }
diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 7f555d322..0ff7da72a 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -387,6 +387,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "ant0n", id: 145224646868860928n }, + Korbo: { + name: "Korbo", + id: 455856406420258827n + }, } satisfies Record); // iife so #__PURE__ works correctly From 1b179f3c6d2b109251a9abcedfa90666ba0989dd Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Fri, 24 Nov 2023 23:14:18 -0300 Subject: [PATCH 2/4] Simplify some components finds; Make undo of patch groups more clear --- src/plugins/typingIndicator/index.tsx | 9 ++------- src/plugins/vencordToolbox/index.tsx | 7 ++----- src/webpack/patchWebpack.ts | 4 ++-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/plugins/typingIndicator/index.tsx b/src/plugins/typingIndicator/index.tsx index e35eb9b6e..c5cf5a9d0 100644 --- a/src/plugins/typingIndicator/index.tsx +++ b/src/plugins/typingIndicator/index.tsx @@ -20,17 +20,12 @@ import { definePluginSettings, Settings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import { find, findStoreLazy, LazyComponentWebpack } from "@webpack"; +import { findExportedComponentLazy, findStoreLazy } from "@webpack"; import { ChannelStore, GuildMemberStore, i18n, RelationshipStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common"; import { buildSeveralUsers } from "../typingTweaks"; -const ThreeDots = LazyComponentWebpack(() => { - // This doesn't really need to explicitly find Dots' own module, but it's fine - const res = find(m => m.Dots && !m.Menu); - - return res?.Dots; -}); +const ThreeDots = findExportedComponentLazy("Dots", "AnimatedDots"); const TypingStore = findStoreLazy("TypingStore"); const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore"); diff --git a/src/plugins/vencordToolbox/index.tsx b/src/plugins/vencordToolbox/index.tsx index bb63a86b8..2b0ce14e6 100644 --- a/src/plugins/vencordToolbox/index.tsx +++ b/src/plugins/vencordToolbox/index.tsx @@ -23,14 +23,11 @@ import { Settings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; -import { filters, find, LazyComponentWebpack } from "@webpack"; +import { findExportedComponentLazy } from "@webpack"; import { Menu, Popout, useState } from "@webpack/common"; import type { ReactNode } from "react"; -const HeaderBarIcon = LazyComponentWebpack(() => { - const filter = filters.byCode(".HEADER_BAR_BADGE"); - return find(m => m.Icon && filter(m.Icon))?.Icon; -}); +const HeaderBarIcon = findExportedComponentLazy("Icon", "Divider"); function VencordPopout(onClose: () => void) { const pluginEntries = [] as ReactNode[]; diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index b992cfdea..76a9fb0f5 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -212,7 +212,7 @@ function patchFactories(factories: Record Date: Mon, 27 Nov 2023 02:56:57 -0300 Subject: [PATCH 3/4] Utility function for loading Discord chunks (#2017) --- scripts/generateReport.ts | 8 ++- src/utils/lazyReact.tsx | 2 +- src/webpack/patchWebpack.ts | 8 +-- src/webpack/webpack.ts | 127 ++++++++++++++++++++++++++++++------ 4 files changed, 118 insertions(+), 27 deletions(-) diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts index 540976714..719a84568 100644 --- a/scripts/generateReport.ts +++ b/scripts/generateReport.ts @@ -406,15 +406,21 @@ function runTime(token: string) { if (method === "proxyLazyWebpack" || method === "LazyComponentWebpack") { const [factory] = args; result = factory(); + } else if (method === "extractAndLoadChunks") { + const [code, matcher] = args; + + const module = Vencord.Webpack.findModuleFactory(...code); + if (module) result = module.toString().match(matcher); } else { // @ts-ignore result = Vencord.Webpack[method](...args); } - if (result == null || ("$$get" in result && result.$$get() == null)) throw "a rock at ben shapiro"; + if (result == null || ("$$vencordInternal" in result && result.$$vencordInternal() == null)) throw "a rock at ben shapiro"; } catch (e) { let logMessage = searchType; if (method === "find" || method === "proxyLazyWebpack" || method === "LazyComponentWebpack") logMessage += `(${args[0].toString().slice(0, 147)}...)`; + else if (method === "extractAndLoadChunks") logMessage += `([${args[0].map(arg => `"${arg}"`).join(", ")}], ${args[1].toString()})`; else logMessage += `(${args.map(arg => `"${arg}"`).join(", ")})`; console.log("[PUP_WEBPACK_FIND_FAIL]", logMessage); diff --git a/src/utils/lazyReact.tsx b/src/utils/lazyReact.tsx index da36d4e79..4896a0581 100644 --- a/src/utils/lazyReact.tsx +++ b/src/utils/lazyReact.tsx @@ -23,7 +23,7 @@ export function LazyComponent(factory: () => React.Compo return ; }; - LazyComponent.$$get = get; + LazyComponent.$$vencordInternal = get; return LazyComponent as ComponentType; } diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 76a9fb0f5..f131471bf 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -152,11 +152,9 @@ function patchFactories(factories: Record(); export const listeners = new Set(); -export type CallbackFn = (mod: any, id: number) => void; +export type CallbackFn = (mod: any, id: string) => void; export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) { if (cache !== void 0) throw "no."; @@ -111,12 +112,12 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn if (!mod?.exports) continue; if (filter(mod.exports)) { - return isWaitFor ? [mod.exports, Number(key)] : mod.exports; + return isWaitFor ? [mod.exports, key] : mod.exports; } if (mod.exports.default && filter(mod.exports.default)) { const found = mod.exports.default; - return isWaitFor ? [found, Number(key)] : found; + return isWaitFor ? [found, key] : found; } } @@ -214,18 +215,21 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns }); /** - * Find the id of a module by its code - * @param code Code - * @returns number or null + * Find the id of the first module factory that includes all the given code + * @returns string or null */ -export const findModuleId = traceFunction("findModuleId", function findModuleId(code: string) { +export const findModuleId = traceFunction("findModuleId", function findModuleId(...code: string[]) { + outer: for (const id in wreq.m) { - if (wreq.m[id].toString().includes(code)) { - return Number(id); + const str = wreq.m[id].toString(); + + for (const c of code) { + if (!str.includes(c)) continue outer; } + return id; } - const err = new Error("Didn't find module with code:\n" + code); + const err = new Error("Didn't find module with code(s):\n" + code.join("\n")); if (IS_DEV) { if (!devToolsOpen) // Strict behaviour in DevBuilds to fail early and make sure the issue is found @@ -237,7 +241,18 @@ export const findModuleId = traceFunction("findModuleId", function findModuleId( return null; }); -export const lazyWebpackSearchHistory = [] as Array<["find" | "findByProps" | "findByCode" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack", any[]]>; +/** + * Find the first module factory that includes all the given code + * @returns The module factory or null + */ +export function findModuleFactory(...code: string[]) { + const id = findModuleId(...code); + if (!id) return null; + + return wreq.m[id]; +} + +export const lazyWebpackSearchHistory = [] as Array<["find" | "findByProps" | "findByCode" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack" | "extractAndLoadChunks", any[]]>; /** * This is just a wrapper around {@link proxyLazy} to make our reporter test for your webpack finds. @@ -272,7 +287,7 @@ export function LazyComponentWebpack(factory: () => any, } /** - * find but lazy + * Find the first module that matches the filter, lazily */ export function findLazy(filter: FilterFn) { if (IS_DEV) lazyWebpackSearchHistory.push(["find", [filter]]); @@ -291,7 +306,7 @@ export function findByProps(...props: string[]) { } /** - * findByProps but lazy + * Find the first module that has the specified properties, lazily */ export function findByPropsLazy(...props: string[]) { if (IS_DEV) lazyWebpackSearchHistory.push(["findByProps", props]); @@ -300,7 +315,7 @@ export function findByPropsLazy(...props: string[]) { } /** - * Find a function by its code + * Find the first function that includes all the given code */ export function findByCode(...code: string[]) { const res = find(filters.byCode(...code), { isIndirect: true }); @@ -310,7 +325,7 @@ export function findByCode(...code: string[]) { } /** - * findByCode but lazy + * Find the first function that includes all the given code, lazily */ export function findByCodeLazy(...code: string[]) { if (IS_DEV) lazyWebpackSearchHistory.push(["findByCode", code]); @@ -329,7 +344,7 @@ export function findStore(name: string) { } /** - * findStore but lazy + * Find a store by its displayName, lazily */ export function findStoreLazy(name: string) { if (IS_DEV) lazyWebpackSearchHistory.push(["findStore", [name]]); @@ -353,7 +368,13 @@ export function findComponentByCode(...code: string[]) { export function findComponentLazy(filter: FilterFn) { if (IS_DEV) lazyWebpackSearchHistory.push(["findComponent", [filter]]); - return LazyComponent(() => find(filter)); + + return LazyComponent(() => { + const res = find(filter, { isIndirect: true }); + if (!res) + handleModuleNotFound("findComponent", filter); + return res; + }); } /** @@ -362,7 +383,12 @@ export function findComponentLazy(filter: FilterFn) { export function findComponentByCodeLazy(...code: string[]) { if (IS_DEV) lazyWebpackSearchHistory.push(["findComponentByCode", code]); - return LazyComponent(() => findComponentByCode(...code)); + return LazyComponent(() => { + const res = find(filters.componentByCode(...code), { isIndirect: true }); + if (!res) + handleModuleNotFound("findComponentByCode", ...code); + return res; + }); } /** @@ -371,7 +397,68 @@ export function findComponentByCodeLazy(...code: string[ export function findExportedComponentLazy(...props: string[]) { if (IS_DEV) lazyWebpackSearchHistory.push(["findExportedComponent", props]); - return LazyComponent(() => findByProps(...props)?.[props[0]]); + return LazyComponent(() => { + const res = find(filters.byProps(...props), { isIndirect: true }); + if (!res) + handleModuleNotFound("findExportedComponent", ...props); + return res[props[0]]; + }); +} + +/** + * Extract and load chunks using their entry point + * @param code An array of all the code the module factory containing the entry point (as of using it to load chunks) must include + * @param matcher A RegExp that returns the entry point id as the first capture group. Defaults to a matcher that captures the first entry point found in the module factory + */ +export async function extractAndLoadChunks(code: string[], matcher: RegExp = /\.el\("(.+?)"\)(?<=(\i)\.el.+?)\.then\(\2\.bind\(\2,"\1"\)\)/) { + const module = findModuleFactory(...code); + if (!module) { + const err = new Error("extractAndLoadChunks: Couldn't find module factory"); + logger.warn(err, "Code:", code, "Matcher:", matcher); + + return; + } + + const match = module.toString().match(canonicalizeMatch(matcher)); + if (!match) { + const err = new Error("extractAndLoadChunks: Couldn't find entry point id in module factory code"); + logger.warn(err, "Code:", code, "Matcher:", matcher); + + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + if (IS_DEV && !devToolsOpen) + throw err; + + return; + } + + const [, id] = match; + if (!id || !Number(id)) { + const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the entry point, or the entry point returned wasn't a number"); + logger.warn(err, "Code:", code, "Matcher:", matcher); + + // Strict behaviour in DevBuilds to fail early and make sure the issue is found + if (IS_DEV && !devToolsOpen) + throw err; + + return; + } + + await (wreq as any).el(id); + return wreq(id as any); +} + +/** + * This is just a wrapper around {@link extractAndLoadChunks} to make our reporter test for your webpack finds. + * + * Extract and load chunks using their entry point + * @param code An array of all the code the module factory containing the entry point (as of using it to load chunks) must include + * @param matcher A RegExp that returns the entry point id as the first capture group. Defaults to a matcher that captures the first entry point found in the module factory + * @returns A function that loads the chunks on first call + */ +export function extractAndLoadChunksLazy(code: string[], matcher: RegExp = /\.el\("(.+?)"\)(?<=(\i)\.el.+?)\.then\(\2\.bind\(\2,"\1"\)\)/) { + if (IS_DEV) lazyWebpackSearchHistory.push(["extractAndLoadChunks", [code, matcher]]); + + return () => extractAndLoadChunks(code, matcher); } /** @@ -433,7 +520,7 @@ export function search(...filters: Array) { * so putting breakpoints or similar will have no effect. * @param id The id of the module to extract */ -export function extract(id: number) { +export function extract(id: string | number) { const mod = wreq.m[id] as Function; if (!mod) return null; From f814eeb74c3a562b0ad632c808f63dfddd53f59b Mon Sep 17 00:00:00 2001 From: V Date: Mon, 27 Nov 2023 16:05:25 +0100 Subject: [PATCH 4/4] VoiceMessages: fix preview being blank --- src/plugins/voiceMessages/VoicePreview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/voiceMessages/VoicePreview.tsx b/src/plugins/voiceMessages/VoicePreview.tsx index 0976f7946..9c77d8329 100644 --- a/src/plugins/voiceMessages/VoicePreview.tsx +++ b/src/plugins/voiceMessages/VoicePreview.tsx @@ -25,7 +25,7 @@ interface VoiceMessageProps { src: string; waveform: string; } -const VoiceMessage = findComponentByCodeLazy("waveform:"); +const VoiceMessage = findComponentByCodeLazy("waveform:", "onVolumeChange"); export type VoicePreviewOptions = { src?: string;