From c3bbc92fa2ee19080c8b52dec09e67b15837ab41 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:30:26 -0300 Subject: [PATCH 1/4] Decouple factoryListeners from patchFactory --- src/webpack/patchWebpack.ts | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 7ac7cac00..47373acc9 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -84,6 +84,7 @@ define(Function.prototype, "O", { continue; } + notifyFactoryListeners(this.m[id]); defineModulesFactoryGetter(id, Settings.eagerPatches ? patchFactory(id, this.m[id]) : this.m[id]); } @@ -168,6 +169,20 @@ function updateExistingFactory(moduleFactoriesTarget: AnyWebpackRequire["m"], id return false; } +/** + * Notify all factory listeners + * @param factory The original factory to notify for + */ +function notifyFactoryListeners(factory: AnyModuleFactory) { + for (const factoryListener of factoryListeners) { + try { + factoryListener(factory); + } catch (err) { + logger.error("Error in Webpack factory listener:\n", err, factoryListener); + } + } +} + const moduleFactoriesHandler: ProxyHandler = { /* If Discord ever decides to set module factories using the variable of the modules object directly instead of wreq.m, we need to switch the proxy to the prototype @@ -195,18 +210,8 @@ const moduleFactoriesHandler: ProxyHandler = { return true; } - if (!Settings.eagerPatches) { - // eagerPatches are disabled, so the factory argument should be the original - defineModulesFactoryGetter(p, newValue); - return true; - } - - const patchedFactory = patchFactory(p, newValue); - - // If multiple Webpack instances exist, when new a new module is loaded, it will be set in all the module factories objects. - // Because patches are only executed once, we need to set the patched version in all of them, to avoid the Webpack instance - // that uses the factory to contain the original factory instead of the patched, in case it was set first in another instance - defineModulesFactoryGetter(p, patchedFactory); + notifyFactoryListeners(newValue); + defineModulesFactoryGetter(p, Settings.eagerPatches ? patchFactory(p, newValue) : newValue); return true; } @@ -223,14 +228,6 @@ const moduleFactoriesHandler: ProxyHandler = { function patchFactory(id: PropertyKey, factory: AnyModuleFactory) { const originalFactory = factory; - for (const factoryListener of factoryListeners) { - try { - factoryListener(originalFactory); - } catch (err) { - logger.error("Error in Webpack factory listener:\n", err, factoryListener); - } - } - const patchedBy = new Set(); // 0, prefix to turn it into an expression: 0,function(){} would be invalid syntax without the 0, From 6826fe003cb6c68f1c683cbed5b10f6a5959ce66 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:31:05 -0300 Subject: [PATCH 2/4] guh --- src/webpack/patchWebpack.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 47373acc9..769c713f5 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -170,7 +170,8 @@ function updateExistingFactory(moduleFactoriesTarget: AnyWebpackRequire["m"], id } /** - * Notify all factory listeners + * Notify all factory listeners. + * * @param factory The original factory to notify for */ function notifyFactoryListeners(factory: AnyModuleFactory) { From 853585c0bc76feeadae3b80de1a475e3ea833e66 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:33:26 -0300 Subject: [PATCH 3/4] move down --- src/webpack/patchWebpack.ts | 68 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 769c713f5..78ef03595 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -104,6 +104,40 @@ define(Function.prototype, "O", { } }); +const moduleFactoriesHandler: ProxyHandler = { + /* + If Discord ever decides to set module factories using the variable of the modules object directly instead of wreq.m, we need to switch the proxy to the prototype + and that requires defining additional traps for keeping the object working + + // Proxies on the prototype dont intercept "get" when the property is in the object itself. But in case it isn't we need to return undefined, + // to avoid Reflect.get having no effect and causing a stack overflow + get: (target, p, receiver) => { + return undefined; + }, + // Same thing as get + has: (target, p) => { + return false; + } + */ + + // The set trap for patching or defining getters for the module factories when new module factories are loaded + set: (target, p, newValue, receiver) => { + // If the property is not a number, we are not dealing with a module factory + if (Number.isNaN(Number(p))) { + return define(target, p, { value: newValue }); + } + + if (updateExistingFactory(target, p, newValue)) { + return true; + } + + notifyFactoryListeners(newValue); + defineModulesFactoryGetter(p, Settings.eagerPatches ? patchFactory(p, newValue) : newValue); + + return true; + } +}; + /** * Define the getter for returning the patched version of the module factory. * @@ -184,40 +218,6 @@ function notifyFactoryListeners(factory: AnyModuleFactory) { } } -const moduleFactoriesHandler: ProxyHandler = { - /* - If Discord ever decides to set module factories using the variable of the modules object directly instead of wreq.m, we need to switch the proxy to the prototype - and that requires defining additional traps for keeping the object working - - // Proxies on the prototype dont intercept "get" when the property is in the object itself. But in case it isn't we need to return undefined, - // to avoid Reflect.get having no effect and causing a stack overflow - get: (target, p, receiver) => { - return undefined; - }, - // Same thing as get - has: (target, p) => { - return false; - } - */ - - // The set trap for patching or defining getters for the module factories when new module factories are loaded - set: (target, p, newValue, receiver) => { - // If the property is not a number, we are not dealing with a module factory - if (Number.isNaN(Number(p))) { - return define(target, p, { value: newValue }); - } - - if (updateExistingFactory(target, p, newValue)) { - return true; - } - - notifyFactoryListeners(newValue); - defineModulesFactoryGetter(p, Settings.eagerPatches ? patchFactory(p, newValue) : newValue); - - return true; - } -}; - /** * Patches a module factory. * From 6d587e6530c2134aef9a7402a9ec3a99f02712b0 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:36:43 -0300 Subject: [PATCH 4/4] More re-ordering --- src/webpack/patchWebpack.ts | 66 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 78ef03595..1394d7fac 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -138,39 +138,6 @@ const moduleFactoriesHandler: ProxyHandler = { } }; -/** - * Define the getter for returning the patched version of the module factory. - * - * If eagerPatches is enabled, the factory argument should already be the patched version, else it will be the original - * and only be patched when accessed for the first time. - * - * @param id The id of the module - * @param factory The original or patched module factory - */ -function defineModulesFactoryGetter(id: PropertyKey, factory: PatchedModuleFactory) { - // Define the getter in all the module factories objects. Patches are only executed once, so make sure all module factories object - // have the patched version - for (const wreq of allWebpackInstances) { - define(wreq.m, id, { - get() { - // $$vencordOriginal means the factory is already patched - if (factory.$$vencordOriginal != null) { - return factory; - } - - return (factory = patchFactory(id, factory)); - }, - set(v: AnyModuleFactory) { - if (factory.$$vencordOriginal != null) { - factory.$$vencordOriginal = v; - } else { - factory = v; - } - } - }); - } -} - /** * Update a factory that exists in any Webpack instance with a new original factory. * @@ -218,6 +185,39 @@ function notifyFactoryListeners(factory: AnyModuleFactory) { } } +/** + * Define the getter for returning the patched version of the module factory. + * + * If eagerPatches is enabled, the factory argument should already be the patched version, else it will be the original + * and only be patched when accessed for the first time. + * + * @param id The id of the module + * @param factory The original or patched module factory + */ +function defineModulesFactoryGetter(id: PropertyKey, factory: PatchedModuleFactory) { + // Define the getter in all the module factories objects. Patches are only executed once, so make sure all module factories object + // have the patched version + for (const wreq of allWebpackInstances) { + define(wreq.m, id, { + get() { + // $$vencordOriginal means the factory is already patched + if (factory.$$vencordOriginal != null) { + return factory; + } + + return (factory = patchFactory(id, factory)); + }, + set(v: AnyModuleFactory) { + if (factory.$$vencordOriginal != null) { + factory.$$vencordOriginal = v; + } else { + factory = v; + } + } + }); + } +} + /** * Patches a module factory. *