boops
This commit is contained in:
parent
bc367b1d2a
commit
40a1f48267
|
@ -18,3 +18,4 @@
|
|||
|
||||
export * as Common from "./common";
|
||||
export * from "./webpack";
|
||||
export * from "./wreq.d";
|
||||
|
|
|
@ -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<any> = {
|
||||
const modulesProxyhandler: ProxyHandler<WebpackRequire["m"]> = {
|
||||
...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<any> = {
|
|||
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
|
||||
|
|
|
@ -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<void>(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<FilterFn, CallbackFn>();
|
||||
export const moduleListeners = new Set<CallbackFn>();
|
||||
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<string | RegExp>) {
|
|||
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) {
|
||||
|
|
54
src/webpack/wreq.d.ts
vendored
54
src/webpack/wreq.d.ts
vendored
|
@ -4,46 +4,46 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
type AnyRecord = Record<PropertyKey, any>;
|
||||
export type AnyRecord = Record<PropertyKey, any>;
|
||||
|
||||
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<any>[]) => Promise<any[]> & (() => void)
|
||||
) => Promise<void>;
|
||||
|
||||
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[]>) => void,
|
||||
j: (this: ChunkHandlers, chunkId: PropertyKey, promises: Promise<void[]>) => 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[]>) => void,
|
||||
css: (this: ChunkHandlers, chunkId: PropertyKey, promises: Promise<void[]>) => 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<PropertyKey, ModuleFactory>;
|
||||
/** 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<void[]>;
|
||||
e: (this: WebpackRequire, chunkId: PropertyKey) => Promise<void[]>;
|
||||
/** 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<any>;
|
||||
v: (this: WebpackRequire, exports: AnyRecord, wasmModuleId: any, wasmModuleHash: string, importsObj?: WebAssembly.Imports) => Promise<any>;
|
||||
/** 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 */
|
||||
|
|
Loading…
Reference in a new issue