feat: adopt dev metro
This commit is contained in:
parent
e56ec778e0
commit
cc879485ac
15 changed files with 168 additions and 129 deletions
|
|
@ -1,11 +1,13 @@
|
||||||
import AssetDisplay from "@core/ui/settings/pages/Developer/AssetDisplay";
|
import AssetDisplay from "@core/ui/settings/pages/Developer/AssetDisplay";
|
||||||
import { assetsMap } from "@lib/api/assets";
|
import { iterateAssets } from "@lib/api/assets";
|
||||||
import { LegacyFormDivider } from "@metro/common/components";
|
import { LegacyFormDivider } from "@metro/common/components";
|
||||||
import { ErrorBoundary, Search } from "@ui/components";
|
import { ErrorBoundary, Search } from "@ui/components";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { FlatList, View } from "react-native";
|
import { FlatList, View } from "react-native";
|
||||||
|
|
||||||
export default function AssetBrowser() {
|
export default function AssetBrowser() {
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
const all = useMemo(() => Array.from(iterateAssets()), []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
|
|
@ -15,7 +17,7 @@ export default function AssetBrowser() {
|
||||||
onChangeText={(v: string) => setSearch(v)}
|
onChangeText={(v: string) => setSearch(v)}
|
||||||
/>
|
/>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={Object.values(assetsMap).filter(a => a.name.includes(search) || a.id.toString() === search)}
|
data={all.filter(a => a.name.includes(search) || a.id.toString() === search)}
|
||||||
renderItem={({ item }) => <AssetDisplay asset={item} />}
|
renderItem={({ item }) => <AssetDisplay asset={item} />}
|
||||||
ItemSeparatorComponent={LegacyFormDivider}
|
ItemSeparatorComponent={LegacyFormDivider}
|
||||||
keyExtractor={item => item.name}
|
keyExtractor={item => item.name}
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,26 @@ export const initVendettaObject = (): any => {
|
||||||
showInputAlert: (options: any) => alerts.showInputAlert(options)
|
showInputAlert: (options: any) => alerts.showInputAlert(options)
|
||||||
},
|
},
|
||||||
assets: {
|
assets: {
|
||||||
all: assets.assetsMap,
|
all: new Proxy<any>({}, {
|
||||||
|
get(cache, p) {
|
||||||
|
if (typeof p !== "string") return undefined;
|
||||||
|
if (cache[p]) return cache[p];
|
||||||
|
|
||||||
|
for (const asset of assets.iterateAssets()) {
|
||||||
|
if (asset.name) return cache[p] = asset;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ownKeys(cache) {
|
||||||
|
const keys = new Set<string>();
|
||||||
|
|
||||||
|
for (const asset of assets.iterateAssets()) {
|
||||||
|
cache[asset.name] = asset;
|
||||||
|
keys.add(asset.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...keys];
|
||||||
|
},
|
||||||
|
}),
|
||||||
find: (filter: (a: any) => boolean) => assets.findAsset(filter),
|
find: (filter: (a: any) => boolean) => assets.findAsset(filter),
|
||||||
getAssetByName: (name: string) => assets.findAsset(name),
|
getAssetByName: (name: string) => assets.findAsset(name),
|
||||||
getAssetByID: (id: number) => assets.findAsset(id),
|
getAssetByID: (id: number) => assets.findAsset(id),
|
||||||
|
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
import { after } from "@lib/api/patcher";
|
|
||||||
import { getMetroCache, indexAssetName } from "@metro/internals/caches";
|
|
||||||
import { getImportingModuleId, requireModule } from "@metro/internals/modules";
|
|
||||||
|
|
||||||
// TODO: Deprecate this map, make another that maps to an array of assets (Asset[]) instead
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
* Pitfall: Multiple assets may have the same name, this is fine if we require the asset only for display,\
|
|
||||||
* but not when used to get the registered id/index. In some condition, this would break some plugins like HideGiftButton that gets id by name for patching.\
|
|
||||||
*/
|
|
||||||
export const assetsMap: Record<string, Asset> = new Proxy<any>({}, {
|
|
||||||
get(cache, p) {
|
|
||||||
if (typeof p !== "string") return undefined;
|
|
||||||
if (cache[p]) return cache[p];
|
|
||||||
|
|
||||||
const moduleIds = getMetroCache().assetsIndex[p];
|
|
||||||
if (moduleIds == null) return undefined;
|
|
||||||
|
|
||||||
for (const id in moduleIds) {
|
|
||||||
const assetIndex = requireModule(Number(id));
|
|
||||||
if (typeof assetIndex !== "number") continue;
|
|
||||||
|
|
||||||
const assetDefinition = assetsModule.getAssetByID(assetIndex);
|
|
||||||
if (!assetDefinition) continue;
|
|
||||||
|
|
||||||
assetDefinition.index ??= assetDefinition.id ??= assetIndex;
|
|
||||||
assetDefinition.moduleId ??= id;
|
|
||||||
|
|
||||||
// ??= is intended, we only assign to the first asset registered
|
|
||||||
cache[p] ??= assetDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache[p];
|
|
||||||
},
|
|
||||||
ownKeys(cache) {
|
|
||||||
const keys = [] as Array<string>;
|
|
||||||
for (const key in getMetroCache().assetsIndex) {
|
|
||||||
cache[key] = this.get!(cache, key, {});
|
|
||||||
if (cache[key]) keys.push(key);
|
|
||||||
}
|
|
||||||
return keys;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export interface Asset {
|
|
||||||
/** @deprecated */
|
|
||||||
id: number;
|
|
||||||
index: number;
|
|
||||||
name: string;
|
|
||||||
moduleId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AssetModule {
|
|
||||||
registerAsset(assetDefinition: any): number;
|
|
||||||
getAssetByID(id: number): any;
|
|
||||||
}
|
|
||||||
|
|
||||||
let assetsModule: AssetModule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export function patchAssets(module: AssetModule) {
|
|
||||||
if (assetsModule) return;
|
|
||||||
assetsModule = module;
|
|
||||||
|
|
||||||
const unpatch = after("registerAsset", assetsModule, ([asset]: Asset[]) => {
|
|
||||||
const moduleId = getImportingModuleId();
|
|
||||||
if (moduleId !== -1) indexAssetName(asset.name, moduleId);
|
|
||||||
});
|
|
||||||
|
|
||||||
return unpatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first asset registry by its registry id (number), name (string) or given filter (function)
|
|
||||||
*/
|
|
||||||
export function findAsset(id: number): Asset | undefined;
|
|
||||||
export function findAsset(name: string): Asset | undefined;
|
|
||||||
export function findAsset(filter: (a: Asset) => boolean): Asset | undefined;
|
|
||||||
|
|
||||||
export function findAsset(param: number | string | ((a: Asset) => boolean)) {
|
|
||||||
if (typeof param === "number") return assetsModule.getAssetByID(param);
|
|
||||||
if (typeof param === "string") return assetsMap[param];
|
|
||||||
return Object.values(assetsMap).find(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first asset ID in the registry with the given name
|
|
||||||
*/
|
|
||||||
export function findAssetId(name: string) {
|
|
||||||
return assetsMap[name]?.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
78
src/lib/api/assets/index.ts
Normal file
78
src/lib/api/assets/index.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { getMetroCache } from "@metro/internals/caches";
|
||||||
|
import { ModuleFlags } from "@metro/internals/enums";
|
||||||
|
import { requireModule } from "@metro/internals/modules";
|
||||||
|
|
||||||
|
import { assetsModule } from "./patches";
|
||||||
|
|
||||||
|
export interface Asset {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
moduleId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache common usage
|
||||||
|
const _nameToAssetCache = {} as Record<string, Asset>;
|
||||||
|
|
||||||
|
export function* iterateAssets() {
|
||||||
|
const { flagsIndex } = getMetroCache();
|
||||||
|
const yielded = new Set<number>();
|
||||||
|
|
||||||
|
for (const id in flagsIndex) {
|
||||||
|
if (flagsIndex[id] & ModuleFlags.ASSET) {
|
||||||
|
const assetId = requireModule(Number(id));
|
||||||
|
if (typeof assetId !== "number" || yielded.has(assetId)) continue;
|
||||||
|
yield getAssetById(assetId);
|
||||||
|
yielded.add(assetId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply additional properties for convenience
|
||||||
|
function getAssetById(id: number): Asset {
|
||||||
|
const asset = assetsModule.getAssetByID(id);
|
||||||
|
if (!asset) return asset;
|
||||||
|
return Object.assign(asset, { id });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first asset registry by its registry id (number), name (string) or given filter (function)
|
||||||
|
*/
|
||||||
|
export function findAsset(id: number): Asset | undefined;
|
||||||
|
export function findAsset(name: string): Asset | undefined;
|
||||||
|
export function findAsset(filter: (a: Asset) => boolean): Asset | undefined;
|
||||||
|
|
||||||
|
export function findAsset(param: number | string | ((a: Asset) => boolean)) {
|
||||||
|
if (typeof param === "number") return getAssetById(param);
|
||||||
|
|
||||||
|
if (typeof param === "string" && _nameToAssetCache[param]) {
|
||||||
|
return _nameToAssetCache[param];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const asset of iterateAssets()) {
|
||||||
|
if (typeof param === "string" && asset.name === param) {
|
||||||
|
_nameToAssetCache[param] = asset;
|
||||||
|
return asset;
|
||||||
|
} else if (typeof param === "function" && param(asset)) {
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function filterAssets(param: string | ((a: Asset) => boolean)) {
|
||||||
|
const filteredAssets = [] as Array<Asset>;
|
||||||
|
|
||||||
|
for (const asset of iterateAssets()) {
|
||||||
|
if (typeof param === "string" ? asset.name === param : param(asset)) {
|
||||||
|
filteredAssets.push(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredAssets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first asset ID in the registry with the given name
|
||||||
|
*/
|
||||||
|
export function findAssetId(name: string) {
|
||||||
|
return findAsset(name)?.id;
|
||||||
|
}
|
||||||
25
src/lib/api/assets/patches.ts
Normal file
25
src/lib/api/assets/patches.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { after } from "@lib/api/patcher";
|
||||||
|
import { indexAssetModuleFlag } from "@metro/internals/caches";
|
||||||
|
import { getImportingModuleId } from "@metro/internals/modules";
|
||||||
|
|
||||||
|
interface AssetModule {
|
||||||
|
registerAsset(assetDefinition: any): number;
|
||||||
|
getAssetByID(id: number): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let assetsModule: AssetModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function patchAssets(module: AssetModule) {
|
||||||
|
if (assetsModule) return;
|
||||||
|
assetsModule = module;
|
||||||
|
|
||||||
|
const unpatch = after("registerAsset", assetsModule, () => {
|
||||||
|
const moduleId = getImportingModuleId();
|
||||||
|
if (moduleId !== -1) indexAssetModuleFlag(moduleId);
|
||||||
|
});
|
||||||
|
|
||||||
|
return unpatch;
|
||||||
|
}
|
||||||
1
src/lib/utils/types.ts
Normal file
1
src/lib/utils/types.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export type Nullish = null | undefined;
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { lazyDestructure } from "@lib/utils/lazy";
|
||||||
import { findByFilePathLazy, findByProps, findByPropsLazy } from "@metro/wrappers";
|
import { findByFilePathLazy, findByProps, findByPropsLazy } from "@metro/wrappers";
|
||||||
|
|
||||||
import type { Dispatcher } from "./types/flux";
|
import type { Dispatcher } from "./types/flux";
|
||||||
|
|
@ -18,13 +19,16 @@ export const toasts = findByFilePathLazy("modules/toast/native/ToastActionCreato
|
||||||
export const messageUtil = findByPropsLazy("sendBotMessage");
|
export const messageUtil = findByPropsLazy("sendBotMessage");
|
||||||
export const navigationStack = findByPropsLazy("createStackNavigator");
|
export const navigationStack = findByPropsLazy("createStackNavigator");
|
||||||
export const NavigationNative = findByPropsLazy("NavigationContainer");
|
export const NavigationNative = findByPropsLazy("NavigationContainer");
|
||||||
export const tokens = findByPropsLazy("colors", "unsafe_rawColors");
|
|
||||||
export const semver = findByPropsLazy("parse", "clean");
|
export const semver = findByPropsLazy("parse", "clean");
|
||||||
|
|
||||||
|
export const tokens = findByPropsLazy("unsafe_rawColors", "colors");
|
||||||
|
export const { useToken } = lazyDestructure(() => findByProps("useToken"));
|
||||||
|
|
||||||
// Flux
|
// Flux
|
||||||
export const Flux = findByPropsLazy("connectStores");
|
export const Flux = findByPropsLazy("connectStores");
|
||||||
// TODO: Making this a proxy/lazy fuck things up for some reason
|
// TODO: Making this a proxy/lazy fuck things up for some reason
|
||||||
export const FluxDispatcher = findByProps("_interceptors") as Dispatcher;
|
export const FluxDispatcher = findByProps("_interceptors") as Dispatcher;
|
||||||
|
export const FluxUtils = findByProps("useStateFromStores");
|
||||||
|
|
||||||
// React
|
// React
|
||||||
export const React = window.React = findByPropsLazy("createElement") as typeof import("react");
|
export const React = window.React = findByPropsLazy("createElement") as typeof import("react");
|
||||||
|
|
|
||||||
3
src/metro/common/stores.ts
Normal file
3
src/metro/common/stores.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { findByStoreNameLazy } from "@metro/wrappers";
|
||||||
|
|
||||||
|
export const UserStore = findByStoreNameLazy("UserStore");
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { TextStyles, ThemeColors } from "@lib/ui/types";
|
import { Nullish } from "@lib/utils/types";
|
||||||
|
import { TextStyles, ThemeColors } from "@ui/types";
|
||||||
import { Falsey } from "lodash";
|
import { Falsey } from "lodash";
|
||||||
import { FC, MutableRefObject, PropsWithoutRef, ReactNode, RefObject } from "react";
|
import { FC, MutableRefObject, PropsWithoutRef, ReactNode, RefObject } from "react";
|
||||||
import type * as RN from "react-native";
|
import type * as RN from "react-native";
|
||||||
|
|
@ -110,7 +111,7 @@ interface TextInputProps extends Omit<RN.TextInputProps, "onChange" | "onChangeT
|
||||||
trailingIcon?: React.FC<any>;
|
trailingIcon?: React.FC<any>;
|
||||||
trailingPressableProps?: PressableProps;
|
trailingPressableProps?: PressableProps;
|
||||||
trailingText?: string;
|
trailingText?: string;
|
||||||
value?: string | Falsey;
|
value?: string | Nullish;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TextInput = React.FC<TextInputProps>;
|
export type TextInput = React.FC<TextInputProps>;
|
||||||
|
|
@ -141,6 +142,7 @@ interface FABProps {
|
||||||
style?: Style;
|
style?: Style;
|
||||||
onPress: () => void;
|
onPress: () => void;
|
||||||
positionBottom?: number;
|
positionBottom?: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FloatingActionButton = React.FC<FABProps>;
|
export type FloatingActionButton = React.FC<FABProps>;
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ export function findModuleId<A extends unknown[]>(filter: FilterFn<A>) {
|
||||||
export function findExports<A extends unknown[]>(filter: FilterFn<A>) {
|
export function findExports<A extends unknown[]>(filter: FilterFn<A>) {
|
||||||
const { id, defaultExport } = findModule(filter);
|
const { id, defaultExport } = findModule(filter);
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
|
|
||||||
return defaultExport ? requireModule(id).default : requireModule(id);
|
return defaultExport ? requireModule(id).default : requireModule(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { NativeCacheModule, NativeClientInfoModule } from "@lib/api/native/modules";
|
import { fileExists, readFile, writeFile } from "@lib/api/native/fs";
|
||||||
|
import { NativeClientInfoModule } from "@lib/api/native/modules";
|
||||||
import { debounce } from "es-toolkit";
|
import { debounce } from "es-toolkit";
|
||||||
|
|
||||||
import { ModuleFlags, ModulesMapInternal } from "./enums";
|
import { ModuleFlags, ModulesMapInternal } from "./enums";
|
||||||
|
|
||||||
const CACHE_VERSION = 52;
|
const CACHE_VERSION = 100;
|
||||||
const BUNNY_METRO_CACHE_KEY = "__bunny_metro_cache_key__";
|
const BUNNY_METRO_CACHE_PATH = "caches/metro_modules.json";
|
||||||
|
|
||||||
type ModulesMap = {
|
type ModulesMap = {
|
||||||
[flag in number | `_${ModulesMapInternal}`]?: ModuleFlags;
|
[flag in number | `_${ModulesMapInternal}`]?: ModuleFlags;
|
||||||
|
|
@ -19,14 +20,13 @@ function buildInitCache() {
|
||||||
_v: CACHE_VERSION,
|
_v: CACHE_VERSION,
|
||||||
_buildNumber: NativeClientInfoModule.Build as number,
|
_buildNumber: NativeClientInfoModule.Build as number,
|
||||||
_modulesCount: Object.keys(window.modules).length,
|
_modulesCount: Object.keys(window.modules).length,
|
||||||
exportsIndex: {} as Record<string, number>,
|
flagsIndex: {} as Record<string, number>,
|
||||||
findIndex: {} as Record<string, ModulesMap | undefined>,
|
findIndex: {} as Record<string, ModulesMap | undefined>,
|
||||||
polyfillIndex: {} as Record<string, ModulesMap | undefined>,
|
polyfillIndex: {} as Record<string, ModulesMap | undefined>
|
||||||
assetsIndex: {} as Record<string, ModulesMap | undefined>
|
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Force load all modules so useful modules are pre-cached. Delay by a second
|
// Force load all modules so useful modules are pre-cached. Add a minor
|
||||||
// because force loading it all will results in an unexpected crash.
|
// delay so the cache is initialized before the modules are loaded.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
for (const id in window.modules) {
|
for (const id in window.modules) {
|
||||||
require("./modules").requireModule(id);
|
require("./modules").requireModule(id);
|
||||||
|
|
@ -37,11 +37,10 @@ function buildInitCache() {
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Store in file system... is a better idea?
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export async function initMetroCache() {
|
export async function initMetroCache() {
|
||||||
const rawCache = await NativeCacheModule.getItem(BUNNY_METRO_CACHE_KEY);
|
if (!await fileExists(BUNNY_METRO_CACHE_PATH)) return void buildInitCache();
|
||||||
if (rawCache == null) return void buildInitCache();
|
const rawCache = await readFile(BUNNY_METRO_CACHE_PATH);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_metroCache = JSON.parse(rawCache);
|
_metroCache = JSON.parse(rawCache);
|
||||||
|
|
@ -63,7 +62,7 @@ export async function initMetroCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveCache = debounce(() => {
|
const saveCache = debounce(() => {
|
||||||
NativeCacheModule.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(_metroCache));
|
writeFile(BUNNY_METRO_CACHE_PATH, JSON.stringify(_metroCache));
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
function extractExportsFlags(moduleExports: any) {
|
function extractExportsFlags(moduleExports: any) {
|
||||||
|
|
@ -77,13 +76,18 @@ function extractExportsFlags(moduleExports: any) {
|
||||||
export function indexExportsFlags(moduleId: number, moduleExports: any) {
|
export function indexExportsFlags(moduleId: number, moduleExports: any) {
|
||||||
const flags = extractExportsFlags(moduleExports);
|
const flags = extractExportsFlags(moduleExports);
|
||||||
if (flags && flags !== ModuleFlags.EXISTS) {
|
if (flags && flags !== ModuleFlags.EXISTS) {
|
||||||
_metroCache.exportsIndex[moduleId] = flags;
|
_metroCache.flagsIndex[moduleId] = flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export function indexBlacklistFlag(id: number) {
|
export function indexBlacklistFlag(id: number) {
|
||||||
_metroCache.exportsIndex[id] |= ModuleFlags.BLACKLISTED;
|
_metroCache.flagsIndex[id] |= ModuleFlags.BLACKLISTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export function indexAssetModuleFlag(id: number) {
|
||||||
|
_metroCache.flagsIndex[id] |= ModuleFlags.ASSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
|
@ -124,11 +128,3 @@ export function getPolyfillModuleCacher(name: string) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function indexAssetName(name: string, moduleId: number) {
|
|
||||||
if (!isNaN(moduleId)) {
|
|
||||||
(_metroCache.assetsIndex[name] ??= {})[moduleId] = 1;
|
|
||||||
saveCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export enum ModuleFlags {
|
export enum ModuleFlags {
|
||||||
EXISTS = 1 << 0,
|
EXISTS = 1 << 0,
|
||||||
BLACKLISTED = 1 << 1
|
BLACKLISTED = 1 << 1,
|
||||||
|
ASSET = 1 << 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ModulesMapInternal {
|
export enum ModulesMapInternal {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ for (const key in metroModules) {
|
||||||
const id = Number(key);
|
const id = Number(key);
|
||||||
const metroModule = metroModules[id];
|
const metroModule = metroModules[id];
|
||||||
|
|
||||||
const cache = getMetroCache().exportsIndex[id];
|
const cache = getMetroCache().flagsIndex[id];
|
||||||
if (cache & ModuleFlags.BLACKLISTED) {
|
if (cache & ModuleFlags.BLACKLISTED) {
|
||||||
blacklistModule(id);
|
blacklistModule(id);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -86,7 +86,7 @@ function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
|
||||||
moduleExports.default.track = () => Promise.resolve();
|
moduleExports.default.track = () => Promise.resolve();
|
||||||
|
|
||||||
if (moduleExports.registerAsset) {
|
if (moduleExports.registerAsset) {
|
||||||
require("@lib/api/assets").patchAssets(moduleExports);
|
require("@lib/api/assets/patches").patchAssets(moduleExports);
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are modules registering the same native component
|
// There are modules registering the same native component
|
||||||
|
|
@ -100,6 +100,7 @@ function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
|
||||||
patchedNativeComponentRegistry = true;
|
patchedNativeComponentRegistry = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Hook DeveloperExperimentStore
|
// Hook DeveloperExperimentStore
|
||||||
if (moduleExports?.default?.constructor?.displayName === "DeveloperExperimentStore") {
|
if (moduleExports?.default?.constructor?.displayName === "DeveloperExperimentStore") {
|
||||||
moduleExports.default = new Proxy(moduleExports.default, {
|
moduleExports.default = new Proxy(moduleExports.default, {
|
||||||
|
|
@ -130,7 +131,7 @@ function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
|
||||||
patchedInspectSource = true;
|
patchedInspectSource = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explosion (no, I can't explain this, don't ask) ((hi rosie))
|
//
|
||||||
if (moduleExports.findHostInstance_DEPRECATED) {
|
if (moduleExports.findHostInstance_DEPRECATED) {
|
||||||
const prevExports = metroModules[id - 1]?.publicModule.exports;
|
const prevExports = metroModules[id - 1]?.publicModule.exports;
|
||||||
const inc = prevExports.default?.reactProfilingEnabled ? 1 : -1;
|
const inc = prevExports.default?.reactProfilingEnabled ? 1 : -1;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
type Nullish = null | undefined;
|
import { Nullish } from "@lib/utils/types";
|
||||||
|
|
||||||
/** @see {@link https://github.com/facebook/metro/blob/c2d7539dfc10aacb2f99fcc2f268a3b53e867a90/packages/metro-runtime/src/polyfills/require.js} */
|
/** @see {@link https://github.com/facebook/metro/blob/c2d7539dfc10aacb2f99fcc2f268a3b53e867a90/packages/metro-runtime/src/polyfills/require.js} */
|
||||||
export namespace Metro {
|
export namespace Metro {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { byDisplayName, byFilePath,byName, byProps, byStoreName, byTypeName } from "./filters";
|
import { byDisplayName, byFilePath, byName, byProps, byStoreName, byTypeName } from "./filters";
|
||||||
import { findAllExports,findExports } from "./finders";
|
import { findAllExports, findExports } from "./finders";
|
||||||
import { createLazyModule } from "./lazy";
|
import { createLazyModule } from "./lazy";
|
||||||
|
|
||||||
export const findByProps = (...props: string[]) => findExports(byProps(...props));
|
export const findByProps = (...props: string[]) => findExports(byProps(...props));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue