diff --git a/src/lib/metro/filters.ts b/src/lib/metro/filters.ts
index b45b359..815ab05 100644
--- a/src/lib/metro/filters.ts
+++ b/src/lib/metro/filters.ts
@@ -6,9 +6,12 @@ export type PropIntellisense
= Record
& Record(...props: T[]) => PropIntellisense;
export type PropsFinderAll = (...props: T[]) => PropIntellisense[];
+const blacklistedIds = new Set();
+
/** Makes the module associated with the specified ID non-enumberable. */
function blacklistModule(id: Metro.ModuleID) {
Object.defineProperty(modules, id, { enumerable: false });
+ blacklistedIds.add(String(id));
}
const functionToString = Function.prototype.toString;
@@ -36,22 +39,24 @@ for (const id in modules) {
};
origFunc(...args);
- if (moduleObject.exports) onModuleRequire(moduleObject.exports);
+ if (moduleObject.exports) onModuleRequire(moduleObject.exports, id);
}) as any); // If only spitroast had better types
}
}
// Blacklist any "bad-actor" modules, e.g. the dreaded null proxy, the window itself, or undefined modules
for (const id in modules) {
+ if (blacklistedIds.has(id)) continue;
const moduleExports = requireModule(id);
- if (!moduleExports || moduleExports === window || moduleExports["Revenge EOL when?"] === null)
+ if (!moduleExports || moduleExports === window || moduleExports["i think pyoncord eol tomorrow idk tho"] === null)
blacklistModule(id);
}
+const noopHandler = () => undefined;
let patchedInspectSource = false;
-function onModuleRequire(moduleExports: any) {
+function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
// Temporary
moduleExports.initSentry &&= () => undefined;
if (moduleExports.default?.track && moduleExports.default.trackMaker)
@@ -89,9 +94,17 @@ function onModuleRequire(moduleExports: any) {
window["__core-js_shared__"].inspectSource = inspect;
patchedInspectSource = true;
}
-}
-const noopHandler = () => undefined;
+ // Explosion (no, I can't explain this, don't ask) ((hi rosie))
+ if (moduleExports.findHostInstance_DEPRECATED) {
+ const numberedId = Number(id);
+ const prevExports = modules[numberedId - 1]?.publicModule.exports;
+ const inc = prevExports.default?.reactProfilingEnabled ? 1 : -1;
+ if (!modules[numberedId + inc]?.isInitialized) {
+ blacklistModule(numberedId + inc);
+ }
+ }
+}
function requireModule(id: Metro.ModuleID) {
if (modules[id]!.isInitialized) return metroRequire(id);
diff --git a/src/lib/metro/types.ts b/src/lib/metro/types.ts
index 3b2d6b6..7e5f356 100644
--- a/src/lib/metro/types.ts
+++ b/src/lib/metro/types.ts
@@ -2,11 +2,11 @@ import type { Nullish } from "@types";
/** @see {@link https://github.com/facebook/metro/blob/c2d7539dfc10aacb2f99fcc2f268a3b53e867a90/packages/metro-runtime/src/polyfills/require.js} */
export namespace Metro {
- export interface DependencyMap {
- readonly [indexer: number]: ModuleID;
+ export type DependencyMap = Array & {
readonly paths?: Readonly> | undefined;
- }
+ };
+ /** Only available on Discord's development environment, will never be defined on release builds */
export type InverseDependencyMap = Record;
export type FactoryFn = (
@@ -21,6 +21,7 @@ export namespace Metro {
dependencyMap: DependencyMap | Nullish,
) => void;
+ /** Only available on Discord's development environment, will never be defined on release builds */
export interface HotModuleReloadingData {
_acceptCallback: (() => void) | Nullish;
_disposeCallback: (() => void) | Nullish;
@@ -38,16 +39,27 @@ export namespace Metro {
}
export interface ModuleDefinition {
+ /** Set to undefined once module is initialized */
dependencyMap: DependencyMap | Nullish;
+ /** Error.value thrown by the factory */
error?: any;
+ /** Set to undefined once module is initialized */
factory: FactoryFn | undefined;
+ /** If factory thrown any error */
hasError: boolean;
+ /** Only available on Discord's development environment, will never be defined on release builds */
hot?: HotModuleReloadingData | undefined;
+ /** Cached `import *` imports in Metro, always an empty object as Bunny prevents outdated import cache */
importedAll: any;
+ /** Cached `import module from "./module"` imports in Metro, always an empty object as Bunny prevents outdated import cache */
importedDefault: any;
+ /** If factory has been successfully called */
isInitialized: boolean;
+ /** Only available on Discord's development environment, will never be defined on release builds */
path?: string | undefined;
+ /** Acts as CJS module in the bundler */
publicModule: Module;
+ /** Only available on Discord's development environment, will never be defined on release builds */
verboseName?: string | undefined;
}
@@ -59,7 +71,9 @@ export namespace Metro {
factory: FactoryFn,
moduleId: ModuleID,
dependencyMap?: DependencyMap | undefined,
+ /** Only available on Discord's development environment, will never be defined on release builds */
verboseName?: string | undefined,
+ /** Only available on Discord's development environment, will never be defined on release builds */
inverseDependencies?: InverseDependencyMap | undefined
) => void;
@@ -76,9 +90,9 @@ export namespace Metro {
export interface Require extends RequireFn {
importDefault: RequireFn;
importAll: RequireFn;
- /** @throws {Error} */
+ /** @throws {Error} A macro, will always throws an error at runtime */
context: () => never;
- /** @throws {Error} */
+ /** @throws {Error} A macro, will always throws an error at runtime */
resolveWeak: () => never;
unpackModuleId: (moduleId: ModuleID) => {
localId: number;
diff --git a/src/lib/metro/utils.ts b/src/lib/metro/utils.ts
index e6cd4f7..3ffb54d 100644
--- a/src/lib/metro/utils.ts
+++ b/src/lib/metro/utils.ts
@@ -1,5 +1,6 @@
import type { Metro } from "@metro/types";
+// eslint-disable-next-line prefer-destructuring
export const modules: Metro.ModuleList = window.modules;
export const metroRequire: Metro.Require = window.__r;