diff --git a/src/metro/caches.ts b/src/metro/caches.ts index 1706335..11cfac5 100644 --- a/src/metro/caches.ts +++ b/src/metro/caches.ts @@ -1,28 +1,40 @@ import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules"; import { throttle } from "@lib/utils/throttle"; +const CACHE_VERSION = 12; +const BUNNY_METRO_CACHE_KEY = `__bunny_metro_cache_key_v${CACHE_VERSION}__`; + +export enum ExportsFlags { + EXISTS = 1 << 0, + ES_MODULE = 1 << 1, + BLACKLISTED = 1 << 2, + FUNCTION = 1 << 3, + PRIMITIVE = 1 << 4, +} + type ModulesMap = { _?: 1; - [id: number]: 1 | void; + [id: number]: number; }; interface MetroCacheStore { - _v: 10; + _v: typeof CACHE_VERSION; _buildNumber: number; + exportsIndex: Record; findIndex: Record; polyfillIndex: Record; assetsIndex: Record; } -const BUNNY_METRO_CACHE_KEY = "__bunny_metro_cache_key_v10__"; let _metroCache = null as unknown as MetroCacheStore; export const getMetroCache = window.__getMetroCache = () => _metroCache; function buildInitCache() { _metroCache = { - _v: 10, + _v: CACHE_VERSION, _buildNumber: ClientInfoManager.Build, + exportsIndex: {}, findIndex: {}, polyfillIndex: {}, assetsIndex: {} @@ -54,13 +66,37 @@ export async function initMetroCache() { const saveCache = throttle(() => MMKVManager.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(_metroCache))); +function extractExportsFlags(moduleExports: any) { + if (!moduleExports) return 0; + + let bit = ExportsFlags.EXISTS; + bit |= moduleExports.__esModule ? ExportsFlags.ES_MODULE : 0; + bit |= typeof moduleExports === "function" ? ExportsFlags.FUNCTION : 0; + if (typeof moduleExports === "string" || typeof moduleExports === "number") { + bit |= ExportsFlags.PRIMITIVE; + } + + return bit; +} + +export function indexExportsFlags(moduleId: number, moduleExports: any) { + _metroCache.exportsIndex[moduleId] ??= moduleExports.default && moduleExports.__esModule + ? [extractExportsFlags(moduleExports), extractExportsFlags(moduleExports.default)] + : [extractExportsFlags(moduleExports), 0]; +} + +export function indexBlacklistFlag(id: number) { + _metroCache.exportsIndex[id] ??= [ExportsFlags.BLACKLISTED, ExportsFlags.BLACKLISTED]; +} + export function getCacherForUniq(uniq: string, allFind: boolean) { let indexObject = _metroCache.findIndex[uniq]; return { - cacheId(moduleId: number) { + cacheId(moduleId: number, exports: any) { indexObject ??= _metroCache.findIndex[uniq] ??= {}; - indexObject[moduleId] = 1; + indexObject[moduleId] ??= extractExportsFlags(exports); + saveCache(); }, finish() { diff --git a/src/metro/finders.ts b/src/metro/finders.ts index cff3f2b..76d8d54 100644 --- a/src/metro/finders.ts +++ b/src/metro/finders.ts @@ -24,7 +24,7 @@ export function findModule(filter: FilterFn) { for (const [id, moduleExports] of getModules(filter.uniq, false)) { const [testedExports, defaultExp] = testExports(moduleExports, id, filter); if (testedExports !== undefined) { - cacheId(id); + cacheId(id, testedExports); return [id, defaultExp]; } } @@ -63,7 +63,7 @@ export function findAllModule(filter: FilterFn) { const [testedExports, defaultExp] = testExports(moduleExports, id, filter); if (testedExports !== undefined) { foundExports.push([id, defaultExp]); - cacheId(id); + cacheId(id, testedExports); } } diff --git a/src/metro/modules.ts b/src/metro/modules.ts index d4e57d6..8eb7721 100644 --- a/src/metro/modules.ts +++ b/src/metro/modules.ts @@ -1,4 +1,4 @@ -import { getMetroCache } from "@metro/caches"; +import { ExportsFlags, getMetroCache, indexBlacklistFlag, indexExportsFlags } from "@metro/caches"; import { Metro } from "@metro/types"; import { before, instead } from "spitroast"; @@ -16,6 +16,12 @@ let _importingModuleId: string | null = null; for (const id in metroModules) { const metroModule = metroModules[id]; + const cache = getMetroCache().exportsIndex[id]; + if (cache?.[0] & ExportsFlags.BLACKLISTED) { + blacklistModule(id); + continue; + } + if (metroModule!.factory) { instead("factory", metroModule, ((args: Parameters, origFunc: Metro.FactoryFn) => { _importingModuleId = id; @@ -51,6 +57,7 @@ for (const id in metroModules) { function blacklistModule(id: string) { Object.defineProperty(metroModules, id, { enumerable: false }); blacklistedIds.add(id); + indexBlacklistFlag(Number(id)); } function isBadExports(exports: any) { @@ -58,6 +65,8 @@ function isBadExports(exports: any) { } function onModuleRequire(moduleExports: any, id: Metro.ModuleID) { + indexExportsFlags(Number(id), moduleExports); + // Temporary moduleExports.initSentry &&= () => undefined; if (moduleExports.default?.track && moduleExports.default.trackMaker)