From 40a1f48267679ac242a6a134f6d1a920ec5a9ebb Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Thu, 23 May 2024 03:10:59 -0300 Subject: [PATCH] boops --- src/webpack/index.ts | 1 + src/webpack/patchWebpack.ts | 23 ++++++++-------- src/webpack/webpack.ts | 15 ++++++----- src/webpack/wreq.d.ts | 54 ++++++++++++++++++------------------- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/webpack/index.ts b/src/webpack/index.ts index 036c2a3fc..6f1fd25b8 100644 --- a/src/webpack/index.ts +++ b/src/webpack/index.ts @@ -18,3 +18,4 @@ export * as Common from "./common"; export * from "./webpack"; +export * from "./wreq.d"; diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 71348b889..b79bec46e 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -8,20 +8,19 @@ import { Logger } from "@utils/Logger"; import { UNCONFIGURABLE_PROPERTIES } from "@utils/misc"; import { canonicalizeMatch, canonicalizeReplacement } from "@utils/patches"; import { PatchReplacement } from "@utils/types"; -import { WebpackInstance } from "discord-types/other"; import { traceFunction } from "../debug/Tracer"; import { patches } from "../plugins"; -import { _initWebpack, beforeInitListeners, factoryListeners, moduleListeners, subscriptions, wreq } from "."; +import { _initWebpack, beforeInitListeners, factoryListeners, ModuleFactory, moduleListeners, subscriptions, WebpackRequire, wreq } from "."; const logger = new Logger("WebpackInterceptor", "#8caaee"); const initCallbackRegex = canonicalizeMatch(/{return \i\(".+?"\)}/); -const modulesProxyhandler: ProxyHandler = { +const modulesProxyhandler: ProxyHandler = { ...Object.fromEntries(Object.getOwnPropertyNames(Reflect).map(propName => - [propName, (target: any, ...args: any[]) => Reflect[propName](target, ...args)] + [propName, (target: WebpackRequire["m"], ...args: any[]) => Reflect[propName](target, ...args)] )), - get: (target, p: string) => { + get: (target, p) => { const mod = Reflect.get(target, p); // If the property is not a module id, return the value of it without trying to patch @@ -48,7 +47,7 @@ const modulesProxyhandler: ProxyHandler = { Object.defineProperty(Function.prototype, "O", { configurable: true, - set(onChunksLoaded: any) { + set(onChunksLoaded: WebpackRequire["O"]) { // When using react devtools or other extensions, or even when discord loads the sentry, we may also catch their webpack here. // This ensures we actually got the right one // this.e (wreq.e) is the method for loading a chunk, and only the main webpack has it @@ -59,14 +58,14 @@ Object.defineProperty(Function.prototype, "O", { delete (Function.prototype as any).O; const originalOnChunksLoaded = onChunksLoaded; - onChunksLoaded = function (this: unknown, result: any, chunkIds: string[], callback: () => any, priority: number) { + onChunksLoaded = function (result, chunkIds, callback, priority) { if (callback != null && initCallbackRegex.test(callback.toString())) { Object.defineProperty(this, "O", { value: originalOnChunksLoaded, configurable: true }); - const wreq = this as WebpackInstance; + const wreq = this; const originalCallback = callback; callback = function (this: unknown) { @@ -85,7 +84,7 @@ Object.defineProperty(Function.prototype, "O", { } originalOnChunksLoaded.apply(this, arguments as any); - }; + } as WebpackRequire["O"]; onChunksLoaded.toString = originalOnChunksLoaded.toString.bind(originalOnChunksLoaded); } @@ -131,7 +130,7 @@ Object.defineProperty(Function.prototype, "m", { let webpackNotInitializedLogged = false; -function patchFactory(id: string, mod: (module: any, exports: any, require: WebpackInstance) => void) { +function patchFactory(id: string | number, mod: ModuleFactory) { for (const factoryListener of factoryListeners) { try { factoryListener(mod); @@ -255,7 +254,7 @@ function patchFactory(id: string, mod: (module: any, exports: any, require: Webp if (!patch.all) patches.splice(i--, 1); } - function patchedFactory(module: any, exports: any, require: WebpackInstance) { + const patchedFactory: ModuleFactory = (module, exports, require) => { if (wreq == null && IS_DEV) { if (!webpackNotInitializedLogged) { webpackNotInitializedLogged = true; @@ -312,7 +311,7 @@ function patchFactory(id: string, mod: (module: any, exports: any, require: Webp logger.error("Error while firing callback for Webpack subscription:\n", err, filter, callback); } } - } + }; patchedFactory.toString = originalMod.toString.bind(originalMod); // @ts-ignore diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index 854820851..7cd28866e 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -20,9 +20,9 @@ import { makeLazy, proxyLazy } from "@utils/lazy"; import { LazyComponent } from "@utils/lazyReact"; import { Logger } from "@utils/Logger"; import { canonicalizeMatch } from "@utils/patches"; -import type { WebpackInstance } from "discord-types/other"; import { traceFunction } from "../debug/Tracer"; +import { ModuleExports, ModuleFactory, WebpackRequire } from "./wreq"; const logger = new Logger("Webpack"); @@ -33,8 +33,8 @@ export let _resolveReady: () => void; */ export const onceReady = new Promise(r => _resolveReady = r); -export let wreq: WebpackInstance; -export let cache: WebpackInstance["c"]; +export let wreq: WebpackRequire; +export let cache: WebpackRequire["c"]; export type FilterFn = (mod: any) => boolean; @@ -68,14 +68,14 @@ export const filters = { } }; -export type CallbackFn = (mod: any, id: string) => void; +export type CallbackFn = (module: ModuleExports, id: PropertyKey) => void; export const subscriptions = new Map(); export const moduleListeners = new Set(); -export const factoryListeners = new Set<(factory: (module: any, exports: any, require: WebpackInstance) => void) => void>(); -export const beforeInitListeners = new Set<(wreq: WebpackInstance) => void>(); +export const factoryListeners = new Set<(factory: ModuleFactory) => void>(); +export const beforeInitListeners = new Set<(wreq: WebpackRequire) => void>(); -export function _initWebpack(webpackRequire: WebpackInstance) { +export function _initWebpack(webpackRequire: WebpackRequire) { wreq = webpackRequire; cache = webpackRequire.c; } @@ -500,6 +500,7 @@ export function search(...filters: Array) { const factories = wreq.m; outer: for (const id in factories) { + // @ts-ignore const factory = factories[id].original ?? factories[id]; const str: string = factory.toString(); for (const filter of filters) { diff --git a/src/webpack/wreq.d.ts b/src/webpack/wreq.d.ts index c396e615d..d3d38127f 100644 --- a/src/webpack/wreq.d.ts +++ b/src/webpack/wreq.d.ts @@ -4,46 +4,46 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -type AnyRecord = Record; +export type AnyRecord = Record; -type ModuleExports = any; +export type ModuleExports = any; -type Module = { +export type Module = { id: PropertyKey; loaded: boolean; exports: ModuleExports; }; /** exports ({@link ModuleExports}) can be anything, however initially it is always an empty object */ -type ModuleFactory = (module: Module, exports: AnyRecord, require: WebpackRequire) => void; +export type ModuleFactory = (module: Module, exports: AnyRecord, require: WebpackRequire) => void; -type AsyncModuleBody = ( +export type AsyncModuleBody = ( handleDependencies: (deps: Promise[]) => Promise & (() => void) ) => Promise; -type ChunkHandlers = { +export type ChunkHandlers = { /** * Ensures the js file for this chunk is loaded, or starts to load if it's not * @param chunkId The chunk id * @param promises The promises array to add the loading promise to. */ - j: (chunkId: string | number, promises: Promise) => void, + j: (this: ChunkHandlers, chunkId: PropertyKey, promises: Promise) => void, /** * Ensures the css file for this chunk is loaded, or starts to load if it's not * @param chunkId The chunk id * @param promises The promises array to add the loading promise to. This array will likely contain the promise of the js file too. */ - css: (chunkId: string | number, promises: Promise) => void, + css: (this: ChunkHandlers, chunkId: PropertyKey, promises: Promise) => void, }; -type ScriptLoadDone = (event: Event) => void; +export type ScriptLoadDone = (event: Event) => void; -type OnChunksLoaded = ((result: any, chunkIds: (string | number)[] | undefined, callback: () => any, priority: number) => any) & { +export type OnChunksLoaded = ((this: WebpackRequire, result: any, chunkIds: PropertyKey[] | undefined | null, callback: () => any, priority: number) => any) & { /** Check if a chunk has been loaded */ - j: (chunkId: string | number) => boolean; + j: (chunkId: PropertyKey) => boolean; }; -type WebpackRequire = ((moduleId: PropertyKey) => Module) & { +export type WebpackRequire = ((moduleId: PropertyKey) => Module) & { /** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */ m: Record; /** The module cache, where all modules which have been WebpackRequire'd are stored */ @@ -52,12 +52,12 @@ type WebpackRequire = ((moduleId: PropertyKey) => Module) & { * Export star. Sets properties of "fromObject" to "toObject" as getters that return the value from "fromObject", like this: * @example * const fromObject = { a: 1 }; - * Object.defineProperty(to, "a", { - * get: () => fromObject.a + * Object.defineProperty(fromObject, "a", { + * get: () => fromObject["a"] * }); * @returns fromObject */ - es: (fromObject: AnyRecord, toObject: AnyRecord) => AnyRecord; + es: (this: WebpackRequire, fromObject: AnyRecord, toObject: AnyRecord) => AnyRecord; /** * Creates an async module. The body function must be a async function. * "module.exports" will be decorated with an AsyncModulePromise. @@ -65,9 +65,9 @@ type WebpackRequire = ((moduleId: PropertyKey) => Module) & { * To handle async dependencies correctly do this inside the body: "([a, b, c] = await handleDependencies([a, b, c]));". * If "hasAwaitAfterDependencies" is truthy, "handleDependencies()" must be called at the end of the body function. */ - a: (module: Module, body: AsyncModuleBody, hasAwaitAfterDependencies?: boolean) => void; + a: (this: WebpackRequire, module: Module, body: AsyncModuleBody, hasAwaitAfterDependencies?: boolean) => void; /** getDefaultExport function for compatibility with non-harmony modules */ - n: (module: Module) => () => ModuleExports; + n: (this: WebpackRequire, module: Module) => () => ModuleExports; /** * Create a fake namespace object, useful for faking an __esModule with a default export. * @@ -81,7 +81,7 @@ type WebpackRequire = ((moduleId: PropertyKey) => Module) & { * * mode & (8|1): Behave like require */ - t: (value: any, mode: number) => any; + t: (this: WebpackRequire, value: any, mode: number) => any; /** * Define property getters. For every prop in "definiton", set a getter in "exports" for the value in "definitiion", like this: * @example @@ -91,22 +91,22 @@ type WebpackRequire = ((moduleId: PropertyKey) => Module) & { * Object.defineProperty(exports, key, { get: definition[key] } * } */ - d: (exports: AnyRecord, definiton: AnyRecord) => void; + d: (this: WebpackRequire, exports: AnyRecord, definiton: AnyRecord) => void; /** The chunk handlers, which are used to ensure the files of the chunks are loaded, or load if necessary */ f: ChunkHandlers; /** * The ensure chunk function, it ensures a chunk is loaded, or loads if needed. * Internally it uses the handlers in {@link WebpackRequire.f} to load/ensure the chunk is loaded. */ - e: (chunkId: string | number) => Promise; + e: (this: WebpackRequire, chunkId: PropertyKey) => Promise; /** Get the filename name for the css part of a chunk */ - k: (chunkId: string | number) => `${chunkId}.css`; + k: (this: WebpackRequire, chunkId: PropertyKey) => `${chunkId}.css`; /** Get the filename for the js part of a chunk */ - u: (chunkId: string | number) => string; + u: (this: WebpackRequire, chunkId: PropertyKey) => string; /** The global object, will likely always be the window */ g: Window; /** Harmony module decorator. Decorates a module as an ES Module, and prevents Node.js "module.exports" from being set */ - hmd: (module: Module) => any; + hmd: (this: WebpackRequire, module: Module) => any; /** Shorthand for Object.prototype.hasOwnProperty */ o: typeof Object.prototype.hasOwnProperty; /** @@ -114,11 +114,11 @@ type WebpackRequire = ((moduleId: PropertyKey) => Module) & { * "done" will be attached to existing scripts loading if src === url or data-webpack === `${uniqueName}:${key}`, * so it will be called when that existing script finishes loading. */ - l: (url: string, done: ScriptLoadDone, key?: string | number, chunkId?: string | number) => void; + l: (this: WebpackRequire, url: string, done: ScriptLoadDone, key?: string | number, chunkId?: PropertyKey) => void; /** Defines __esModule on the exports, marking ES Modules compatibility as true */ - r: (exports: AnyRecord) => void; + r: (this: WebpackRequire, exports: AnyRecord) => void; /** Node.js module decorator. Decorates a module as a Node.js module */ - nmd: (module: Module) => any; + nmd: (this: WebpackRequire, module: Module) => any; /** * Register deferred code which will be executed when the passed chunks are loaded. * @@ -135,7 +135,7 @@ type WebpackRequire = ((moduleId: PropertyKey) => Module) & { * Instantiate a wasm instance with source using "wasmModuleHash", and importObject "importsObj", and then assign the exports of its instance to "exports" * @returns The exports argument, but now assigned with the exports of the wasm instance */ - v: (exports: AnyRecord, wasmModuleId: any, wasmModuleHash: string, importsObj?: WebAssembly.Imports) => Promise; + v: (this: WebpackRequire, exports: AnyRecord, wasmModuleId: any, wasmModuleHash: string, importsObj?: WebAssembly.Imports) => Promise; /** Bundle public path, where chunk files are stored. Used by other methods which load chunks to obtain the full asset url */ p: string; /** Document baseURI or WebWorker location.href */