chore: refactor project structure

This commit is contained in:
amsyarasyiq 2024-07-30 00:18:01 +08:00
parent d6376513f0
commit ccb49cb1af
71 changed files with 249 additions and 438 deletions

View file

@ -1,4 +1,4 @@
import { findByPropsLazy } from "@metro";
import { findByPropsLazy } from "@metro/wrappers";
module.exports = {
"react": findByPropsLazy("createElement"),

View file

@ -1,5 +1,5 @@
import { getProxyFactory } from "@lib/utils/lazy";
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
const jsxRuntime = findByPropsLazy("jsx", "jsxs", "Fragment");

View file

@ -1,6 +1,6 @@
import { Strings } from "@core/i18n";
import { ApplicationCommand, ApplicationCommandOptionType } from "@lib/api/commands/types";
import { getDebugInfo } from "@lib/debug";
import { getDebugInfo } from "@lib/api/debug";
import { messageUtil } from "@metro/common";
export default () => <ApplicationCommand>{

View file

@ -1,8 +1,8 @@
import { Strings } from "@core/i18n";
import { ApplicationCommand, ApplicationCommandOptionType } from "@lib/api/commands/types";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { messageUtil } from "@metro/common";
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
const util = findByPropsLazy("inspect");
const AsyncFunction = (async () => void 0).constructor;

View file

@ -1,5 +1,5 @@
import { FluxDispatcher } from "@metro/common";
import { findByNameLazy } from "@metro/utils";
import { findByNameLazy } from "@metro/wrappers";
import { PrimitiveType } from "intl-messageformat";
import langDefault from "./default.json";

View file

@ -1,10 +1,20 @@
import { PluginInstanceInternal } from "@lib/plugins/types";
export function initCorePlugins() {
const unloads = [
require("./quickInstall")
].map(p => {
return p.default();
});
return () => unloads.forEach(m => typeof m === "function" && m());
interface CorePlugin {
default: PluginInstanceInternal;
preenabled: boolean;
}
// Called from @lib/plugins
export const getCorePlugins = (): Record<string, CorePlugin> => ({
"vd-quick-install": require("./vd-quick-install")
});
/**
* @internal
*/
export function defineCorePlugin(instance: PluginInstanceInternal): PluginInstanceInternal {
// @ts-expect-error
instance[Symbol.for("bunny.core.plugin")] = true;
return instance;
}

View file

@ -1,11 +0,0 @@
import patchForumPost from "./forumPost";
import patchUrl from "./url";
export default function onLoad() {
const patches = new Array<Function>;
patches.push(patchForumPost());
patches.push(patchUrl());
return () => patches.forEach(p => p());
}

View file

@ -4,11 +4,11 @@ import { findAssetId } from "@lib/api/assets";
import { isThemeSupported } from "@lib/api/native/loader";
import { after } from "@lib/api/patcher";
import { useProxy } from "@lib/api/storage";
import { installTheme, removeTheme, themes } from "@lib/managers/themes";
import { installTheme, removeTheme, themes } from "@lib/themes";
import { DISCORD_SERVER_ID, HTTP_REGEX_MULTI, PLUGINS_CHANNEL_ID, THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants";
import { lazyDestructure } from "@lib/utils/lazy";
import { Button } from "@metro/common/components";
import { findByProps, findByPropsLazy } from "@metro/utils";
import { findByProps, findByPropsLazy } from "@metro/wrappers";
import { ErrorBoundary } from "@ui/components";
import { showToast } from "@ui/toasts";

View file

@ -0,0 +1,21 @@
import { defineCorePlugin } from "..";
import patchForumPost from "./forumPost";
import patchUrl from "./url";
let patches = [] as (() => unknown)[];
export default defineCorePlugin({
manifest: {
id: "bunny.quick.install",
name: "QuickInstall",
version: "1.0.0",
description: "Quickly install Vendetta plugins and themes",
authors: [{ name: "pylixonly" }]
},
start() {
patches = [patchForumPost(), patchUrl()];
},
stop() {
patches.forEach(p => p());
}
});

View file

@ -3,13 +3,13 @@ import { VdPluginManager } from "@core/vendetta/plugins";
import { findAssetId } from "@lib/api/assets";
import { isThemeSupported } from "@lib/api/native/loader";
import { after, instead } from "@lib/api/patcher";
import { installTheme } from "@lib/managers/themes";
import { installTheme } from "@lib/themes";
import { THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants";
import { lazyDestructure } from "@lib/utils/lazy";
import { channels, url } from "@metro/common";
import { byMutableProp } from "@metro/filters";
import { findExports } from "@metro/finders";
import { findByProps, findByPropsLazy } from "@metro/utils";
import { findByProps, findByPropsLazy } from "@metro/wrappers";
import { showConfirmationAlert } from "@ui/alerts";
import { showToast } from "@ui/toasts";

View file

@ -1,8 +0,0 @@
//! Around 202.4, Promise.allSettled was undefined due to conflicting then/promise versions(?), so we use our own.
const allSettledFulfill = <T>(value: T) => ({ status: "fulfilled", value });
const allSettledReject = <T>(reason: T) => ({ status: "rejected", reason });
const mapAllSettled = <T>(item: T) => Promise.resolve(item).then(allSettledFulfill, allSettledReject);
export const allSettled = <T extends unknown[]>(iterator: T) => Promise.all(Array.from(iterator).map(mapAllSettled));
// @ts-ignore
Promise.allSettled ??= allSettled;

View file

@ -0,0 +1,7 @@
const allSettledFulfill = <T>(value: T) => ({ status: "fulfilled", value } as const);
const allSettledReject = <T>(reason: T) => ({ status: "rejected", reason } as const);
const mapAllSettled = <T>(item: T) => Promise.resolve(item).then(allSettledFulfill, allSettledReject);
Promise.allSettled ??= <T extends unknown[]>(iterator: T) => {
return Promise.all(Array.from(iterator).map(mapAllSettled));
};

View file

@ -1,7 +1,7 @@
import { findAssetId } from "@lib/api/assets";
import { lazyDestructure } from "@lib/utils/lazy";
import { Card, FormRadio, FormSwitch, IconButton, LegacyFormRow, Stack, Text } from "@metro/common/components";
import { findByProps } from "@metro/utils";
import { findByProps } from "@metro/wrappers";
import { semanticColors } from "@ui/color";
import { createStyles, TextStyleSheet } from "@ui/styles";
import { TouchableOpacity, View } from "react-native";

View file

@ -2,7 +2,7 @@ import { Strings } from "@core/i18n";
import { CardWrapper } from "@core/ui/components/AddonCard";
import { findAssetId } from "@lib/api/assets";
import { useProxy } from "@lib/api/storage";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { HTTP_REGEX_MULTI } from "@lib/utils/constants";
import { findByProps } from "@metro";
import { clipboard } from "@metro/common";

View file

@ -3,7 +3,7 @@ import { Strings } from "@core/i18n";
import { findAssetId } from "@lib/api/assets";
import { isFontSupported, isThemeSupported } from "@lib/api/native/loader";
import { useProxy } from "@lib/api/storage";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { registerSection } from "@ui/settings";
import { version } from "bunny-build-info";

View file

@ -4,12 +4,12 @@ import AssetBrowser from "@core/ui/settings/pages/Developer/AssetBrowser";
import { findAssetId } from "@lib/api/assets";
import { getReactDevToolsProp, getReactDevToolsVersion, isLoaderConfigSupported, isReactDevToolsPreloaded, isVendettaLoader } from "@lib/api/native/loader";
import { useProxy } from "@lib/api/storage";
import { connectToDebugger } from "@lib/debug";
import { loaderConfig, settings } from "@lib/settings";
import { connectToDebugger } from "@lib/api/debug";
import { loaderConfig, settings } from "@lib/api/settings";
import { lazyDestructure } from "@lib/utils/lazy";
import { NavigationNative } from "@metro/common";
import { Button, LegacyFormText, Stack, TableRow, TableRowGroup, TableSwitchRow, TextInput } from "@metro/common/components";
import { findByProps } from "@metro/utils";
import { findByProps } from "@metro/wrappers";
import { semanticColors } from "@ui/color";
import { ErrorBoundary } from "@ui/components";
import { createStyles, TextStyleSheet } from "@ui/styles";

View file

@ -3,9 +3,9 @@ import { CardWrapper } from "@core/ui/components/AddonCard";
import { findAssetId } from "@lib/api/assets";
import { BundleUpdaterManager } from "@lib/api/native/modules";
import { useProxy } from "@lib/api/storage";
import { FontDefinition, fonts, selectFont } from "@lib/managers/fonts";
import { showConfirmationAlert } from "@lib/ui/alerts";
import { TextStyleSheet } from "@lib/ui/styles";
import { FontDefinition, fonts, selectFont } from "@lib/fonts";
import { showConfirmationAlert } from "@ui/alerts";
import { TextStyleSheet } from "@ui/styles";
import { lazyDestructure } from "@lib/utils/lazy";
import { ButtonColors } from "@lib/utils/types";
import { findByProps } from "@metro";

View file

@ -1,12 +1,12 @@
import { formatString, Strings } from "@core/i18n";
import { findAssetId } from "@lib/api/assets";
import { createProxy, useProxy } from "@lib/api/storage";
import { FontDefinition, fonts, removeFont, saveFont, validateFont } from "@lib/managers/fonts";
import { getCurrentTheme } from "@lib/managers/themes";
import { FontDefinition, fonts, removeFont, saveFont, validateFont } from "@lib/fonts";
import { getCurrentTheme } from "@lib/themes";
import { safeFetch } from "@lib/utils";
import { NavigationNative } from "@metro/common";
import { ActionSheet, BottomSheetTitleHeader, Button, IconButton, Stack, TableRow, TableRowGroup, Text, TextInput } from "@metro/common/components";
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
import { ErrorBoundary } from "@ui/components";
import { useMemo, useRef, useState } from "react";
import { ScrollView, View } from "react-native";

View file

@ -2,8 +2,8 @@ import { Strings } from "@core/i18n";
import AddonPage from "@core/ui/components/AddonPage";
import FontEditor from "@core/ui/settings/pages/Fonts/FontEditor";
import { useProxy } from "@lib/api/storage";
import { FontDefinition, fonts, installFont } from "@lib/managers/fonts";
import { settings } from "@lib/settings";
import { FontDefinition, fonts, installFont } from "@lib/fonts";
import { settings } from "@lib/api/settings";
import { NavigationNative } from "@metro/common";
import FontCard from "./FontCard";

View file

@ -1,8 +1,8 @@
import { Strings } from "@core/i18n";
import Version from "@core/ui/settings/pages/General/Version";
import { useProxy } from "@lib/api/storage";
import { getDebugInfo } from "@lib/debug";
import { settings } from "@lib/settings";
import { getDebugInfo } from "@lib/api/debug";
import { settings } from "@lib/api/settings";
import { Stack, TableRowGroup } from "@metro/common/components";
import { Platform, ScrollView } from "react-native";

View file

@ -3,8 +3,8 @@ import { PyoncordIcon } from "@core/ui/settings";
import About from "@core/ui/settings/pages/General/About";
import { findAssetId } from "@lib/api/assets";
import { useProxy } from "@lib/api/storage";
import { getDebugInfo, toggleSafeMode } from "@lib/debug";
import { settings } from "@lib/settings";
import { getDebugInfo, toggleSafeMode } from "@lib/api/debug";
import { settings } from "@lib/api/settings";
import { DISCORD_SERVER, GITHUB } from "@lib/utils/constants";
import { NavigationNative, url } from "@metro/common";
import { Stack, TableRow, TableRowGroup, TableSwitchRow } from "@metro/common/components";

View file

@ -2,7 +2,7 @@ import { CardWrapper } from "@core/ui/components/AddonCard";
import { VdPluginManager, VendettaPlugin } from "@core/vendetta/plugins";
import { findAssetId } from "@lib/api/assets";
import { useProxy } from "@lib/api/storage";
import { showSheet } from "@lib/ui/sheets";
import { showSheet } from "@ui/sheets";
import { lazyDestructure } from "@lib/utils/lazy";
import { findByProps } from "@metro";
import { NavigationNative } from "@metro/common";

View file

@ -3,7 +3,7 @@ import AddonPage from "@core/ui/components/AddonPage";
import PluginCard from "@core/ui/settings/pages/Plugins/PluginCard";
import { VdPluginManager, VendettaPlugin } from "@core/vendetta/plugins";
import { useProxy } from "@lib/api/storage";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { Author } from "@lib/utils/types";
export default function Plugins() {

View file

@ -2,9 +2,9 @@ import { formatString, Strings } from "@core/i18n";
import { VdPluginManager, VendettaPlugin } from "@core/vendetta/plugins";
import { findAssetId } from "@lib/api/assets";
import { purgeStorage, useProxy } from "@lib/api/storage";
import { showConfirmationAlert } from "@lib/ui/alerts";
import { hideSheet } from "@lib/ui/sheets";
import { showToast } from "@lib/ui/toasts";
import { showConfirmationAlert } from "@ui/alerts";
import { hideSheet } from "@ui/sheets";
import { showToast } from "@ui/toasts";
import { ButtonColors } from "@lib/utils/types";
import { clipboard } from "@metro/common";
import { ActionSheet, ActionSheetRow, Button, TableRow, Text } from "@metro/common/components";

View file

@ -1,4 +1,4 @@
import { createStyles } from "@lib/ui/styles";
import { createStyles } from "@ui/styles";
import { tokens } from "@metro/common";
export const usePluginCardStyles = createStyles({

View file

@ -2,8 +2,8 @@ import { formatString, Strings } from "@core/i18n";
import AddonCard, { CardWrapper } from "@core/ui/components/AddonCard";
import { findAssetId } from "@lib/api/assets";
import { useProxy } from "@lib/api/storage";
import { applyTheme, fetchTheme, removeTheme, selectTheme, Theme, themes } from "@lib/managers/themes";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { applyTheme, fetchTheme, removeTheme, selectTheme, Theme, themes } from "@lib/themes";
import { ButtonColors } from "@lib/utils/types";
import { clipboard } from "@metro/common";
import { showConfirmationAlert } from "@ui/alerts";
@ -18,7 +18,7 @@ function selectAndApply(value: boolean, theme: Theme) {
}
}
export default function ThemeCard({ item: theme, index }: CardWrapper<Theme>) {
export default function ThemeCard({ item: theme }: CardWrapper<Theme>) {
useProxy(theme);
const [removed, setRemoved] = React.useState(false);
@ -30,7 +30,6 @@ export default function ThemeCard({ item: theme, index }: CardWrapper<Theme>) {
return (
<AddonCard
index={index}
headerLabel={theme.data.name}
headerSublabel={authors ? `by ${authors.map(i => i.name).join(", ")}` : ""}
descriptionLabel={theme.data.description ?? "No description."}

View file

@ -2,8 +2,8 @@ import { formatString, Strings } from "@core/i18n";
import AddonPage from "@core/ui/components/AddonPage";
import ThemeCard from "@core/ui/settings/pages/Themes/ThemeCard";
import { useProxy } from "@lib/api/storage";
import { installTheme, Theme, themes } from "@lib/managers/themes";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { installTheme, Theme, themes } from "@lib/themes";
import { Author } from "@lib/utils/types";
import { Button } from "@metro/common/components";

View file

@ -4,9 +4,9 @@ import { getVendettaLoaderIdentity, isPyonLoader } from "@lib/api/native/loader"
import patcher from "@lib/api/patcher";
import * as storage from "@lib/api/storage";
import { createStorage } from "@lib/api/storage";
import * as debug from "@lib/debug";
import * as themes from "@lib/managers/themes";
import { loaderConfig, settings } from "@lib/settings";
import * as debug from "@lib/api/debug";
import { loaderConfig, settings } from "@lib/api/settings";
import * as themes from "@lib/themes";
import * as utils from "@lib/utils";
import { cyrb64Hash } from "@lib/utils/cyrb64";
import { DiscordLogger } from "@lib/utils/logger";
@ -39,6 +39,15 @@ export async function createVdPluginObject(plugin: VendettaPlugin) {
}
export const initVendettaObject = (): any => {
// pitfall: this assumes the returning module(s) are the same within the same location
// find(m => m.render?.name === "ActionSheet") - would work fine
// ["trackThis", "trackThat"].forEach(p => find(m => m[p])) - would not
const createStackBasedFilter = (fn: any) => {
return (filter: (m: any) => boolean) => {
return fn(metro.factories.createSimpleFilter(filter, cyrb64Hash(new Error().stack!)));
};
};
const api = window.vendetta = {
patcher: {
before: patcher.before,
@ -47,12 +56,8 @@ export const initVendettaObject = (): any => {
},
metro: {
modules: window.modules,
find: (filter: (m: any) => boolean) => {
return metro.findExports(metro.createSimpleFilter(filter, cyrb64Hash(new Error().stack!)));
},
findAll: (filter: (m: any) => boolean) => {
return metro.findAllExports(metro.createSimpleFilter(filter, cyrb64Hash(new Error().stack!)));
},
find: createStackBasedFilter(metro.findExports),
findAll: createStackBasedFilter(metro.findAllExports),
findByProps: (...props: any[]) => {
// TODO: remove this hack to fix Decor
if (props.length === 1 && props[0] === "KeyboardAwareScrollView") {

View file

@ -1,6 +1,5 @@
import { allSettled } from "@core/polyfills/allSettled";
import { awaitStorage, createMMKVBackend, createStorage, purgeStorage, wrapSync } from "@lib/api/storage";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { safeFetch } from "@lib/utils";
import { BUNNY_PROXY_PREFIX, VD_PROXY_PREFIX } from "@lib/utils/constants";
import { DiscordLogger, logger } from "@lib/utils/logger";
@ -168,7 +167,7 @@ export const VdPluginManager = {
if (!settings.safeMode?.enabled) {
// Loop over any plugin that is enabled, update it if allowed, then start it.
await allSettled(allIds.filter(pl => plugins[pl].enabled).map(async pl => (plugins[pl].update && await this.fetchPlugin(pl).catch((e: Error) => logger.error(e.message)), await this.startPlugin(pl))));
await Promise.allSettled(allIds.filter(pl => plugins[pl].enabled).map(async pl => (plugins[pl].update && await this.fetchPlugin(pl).catch((e: Error) => logger.error(e.message)), await this.startPlugin(pl))));
// Wait for the above to finish, then update all disabled plugins that are allowed to.
allIds.filter(pl => !plugins[pl].enabled && plugins[pl].update).forEach(pl => this.fetchPlugin(pl));
}

View file

@ -9,7 +9,10 @@ async function initializeBunny() {
// Make 'freeze' and 'seal' do nothing
Object.freeze = Object.seal = Object;
await require("@metro/caches").initMetroCache();
// Polyfill Promise.allSettled
require("@core/polyfills/promise-all-settled");
await require("@metro/internals/caches").initMetroCache();
await require(".").default();
} catch (e) {
const { ClientInfoManager } = require("@lib/api/native/modules");

View file

@ -1,6 +1,5 @@
import initFixes from "@core/fixes";
import { initFetchI18nStrings } from "@core/i18n";
import { initCorePlugins } from "@core/plugins";
import initSettings from "@core/ui/settings";
import { initVendettaObject } from "@core/vendetta/api";
import { VdPluginManager } from "@core/vendetta/plugins";
@ -9,10 +8,10 @@ import { injectFluxInterceptor } from "@lib/api/flux";
import { removeFile, writeFile } from "@lib/api/native/fs";
import { isPyonLoader, isThemeSupported } from "@lib/api/native/loader";
import { FileManager } from "@lib/api/native/modules";
import { patchLogHook } from "@lib/debug";
import { updateFonts } from "@lib/managers/fonts";
import { initThemes, patchChatBackground } from "@lib/managers/themes";
import { patchLogHook } from "@lib/api/debug";
import { updateFonts } from "@lib/fonts";
import { checkAndRegisterUpdates, initPlugins } from "@lib/plugins";
import { initThemes, patchChatBackground } from "@lib/themes";
import { logger } from "@lib/utils/logger";
import initSafeMode from "@ui/safeMode";
import { patchSettings } from "@ui/settings";
@ -48,7 +47,6 @@ export default async () => {
initSettings(),
initFixes(),
initSafeMode(),
initCorePlugins(),
checkAndRegisterUpdates()
]).then(
// Push them all to unloader

View file

@ -1,6 +1,6 @@
import { after } from "@lib/api/patcher";
import { getMetroCache, indexAssetName } from "@metro/caches";
import { getImportingModuleId, requireModule } from "@metro/modules";
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
/**
@ -78,7 +78,7 @@ 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: any) => void)) {
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);

View file

@ -2,8 +2,8 @@ import { findAssetId } from "@lib/api/assets";
import { getLoaderName, getLoaderVersion, isThemeSupported } from "@lib/api/native/loader";
import { BundleUpdaterManager, ClientInfoManager, DeviceManager } from "@lib/api/native/modules";
import { after } from "@lib/api/patcher";
import { getThemeFromLoader, selectTheme, themes } from "@lib/managers/themes";
import { settings } from "@lib/settings";
import { settings } from "@lib/api/settings";
import { getThemeFromLoader, selectTheme, themes } from "@lib/themes";
import { logger } from "@lib/utils/logger";
import { showToast } from "@ui/toasts";
import { version } from "bunny-build-info";
@ -98,9 +98,11 @@ export function getDebugInfo() {
const rnVer = PlatformConstants.reactNativeVersion;
return {
/** @deprecated */
/**
* @deprecated use `bunny` field
* */
vendetta: {
version: versionHash,
version: versionHash.split("-")[0],
loader: getLoaderName(),
},
bunny: {

View file

@ -1,4 +1,4 @@
import { Theme } from "@lib/managers/themes";
import { Theme } from "@lib/themes";
// @ts-ignore
const pyonLoaderIdentity = globalThis.__PYON_LOADER__;
@ -58,7 +58,7 @@ function polyfillVendettaLoaderIdentity() {
const id = getStoredTheme()?.id;
if (!id) return null;
const { themes } = require("@lib/managers/themes");
const { themes } = require("@lib/themes");
return themes[id] ?? getStoredTheme() ?? null;
},
configurable: true

View file

@ -1,5 +1,5 @@
import { StorageBackend } from "@lib/api/storage/backends";
import { Emitter } from "@lib/utils/emitter";
import { Emitter } from "@lib/utils/Emitter";
const emitterSymbol = Symbol.for("vendetta.storage.emitter");
const syncAwaitSymbol = Symbol.for("vendetta.storage.accessor");

View file

@ -1,6 +1,6 @@
// New iteration of storage API, mostly yoinked from unreleased pyoncord (and sunrise?)
import { fileExists, readFile, writeFile } from "@lib/api/native/fs";
import { Emitter } from "@lib/utils/emitter";
import { Emitter } from "@lib/utils/Emitter";
import invariant from "@lib/utils/invariant";
interface StorageBackend<T = unknown> {

View file

@ -2,15 +2,16 @@ import "../global.d.ts"; // eslint-disable-line import-alias/import-alias
import "../modules.d.ts"; // eslint-disable-line import-alias/import-alias
export * as api from "./api";
export * as debug from "./debug";
export * as managers from "./managers";
export * as debug from "./api/debug.js";
export * as settings from "./api/settings.js";
export * as fonts from "./fonts";
export * as plugins from "./plugins";
export * as settings from "./settings";
export * as themes from "./themes";
export * as ui from "./ui";
export * as utils from "./utils";
export * as metro from "@metro";
const _disposer = new Array<() => unknown>;
const _disposer = [] as Array<() => unknown>;
export function unload() {
for (const d of _disposer) if (typeof d === "function") d();

View file

@ -1,3 +0,0 @@
export * as fonts from "./fonts";
export * as plugins from "./plugins";
export * as themes from "./themes";

View file

@ -1,228 +0,0 @@
import { allSettled } from "@core/polyfills/allSettled";
import { createVdPluginObject } from "@core/vendetta/api";
import { awaitStorage, createMMKVBackend, createStorage, purgeStorage, wrapSync } from "@lib/api/storage";
import { settings } from "@lib/settings";
import { safeFetch } from "@lib/utils";
import { BUNNY_PROXY_PREFIX, OLD_BUNNY_PROXY_PREFIX, VD_PROXY_PREFIX } from "@lib/utils/constants";
import invariant from "@lib/utils/invariant";
import { logger } from "@lib/utils/logger";
import { Author } from "@lib/utils/types";
import { isNotNil, uniqWith } from "es-toolkit";
type EvaledPlugin = {
onLoad?(): void;
onUnload(): void;
settings: () => JSX.Element;
};
interface PluginManifest {
id: string;
name: string;
description: string;
authors: Author[];
main: string;
hash: string;
// Vendor-specific field, contains our own data
vendetta?: {
icon?: string;
};
bunny?: {};
}
export interface BunnyPlugin {
id: string;
source: string;
manifest: PluginManifest;
enabled: boolean;
update: boolean;
/**
* Message of plugin startup error. Gone after plugin boots successfully
* */
error?: string;
// TODO: Use fs to avoid unnecessary memory usage
js: string;
}
const arePluginsEnabled = () => !settings.safeMode?.enabled;
const _pluginInstances: Record<string, EvaledPlugin> = {};
export const sourceStore = wrapSync(createStorage<{ [id in string]?: BunnyPlugin }>(createMMKVBackend("PLUGIN_SOURCES_STORE")));
export const preferredSourceStore = wrapSync(createStorage<{ [id in string]?: string }>(createMMKVBackend("PREFERRED_PLUGIN_SOURCE")));
export function getPluginById(id: string) {
if (!id) return undefined;
if (!preferredSourceStore[id]) {
for (const plugin of Object.values(sourceStore)) {
if (plugin?.id === id) {
return plugin;
}
}
}
return sourceStore[preferredSourceStore[id]!];
}
export async function fetchAndStorePlugin(source: string) {
if (!source.endsWith("/")) source += "/";
const existingPlugin = sourceStore[source];
const fetch = (url: string) => safeFetch(
url
.replace(VD_PROXY_PREFIX, BUNNY_PROXY_PREFIX)
.replace(OLD_BUNNY_PROXY_PREFIX, BUNNY_PROXY_PREFIX),
{ cache: "no-store" }
);
let pluginManifest: PluginManifest;
try {
pluginManifest = await (await fetch(source + "manifest.json")).json();
} catch {
throw new Error(`Failed to fetch manifest for ${source}`);
}
for (const f of ["id", "main", "hash", "bunny"] as const)
invariant(pluginManifest[f], `Plugin manifest does not contain mandatory field: '${f}'`);
let pluginJs: string | undefined;
if (existingPlugin?.manifest.hash !== pluginManifest.hash) {
try {
pluginJs = await (await fetch(source + pluginManifest.main)).text();
} catch { } // Empty catch, checked below
}
invariant(pluginJs || existingPlugin, `Failed to fetch JS from ${source}`);
return sourceStore[source] = {
id: pluginManifest.id,
source: source,
manifest: pluginManifest,
enabled: existingPlugin?.enabled ?? false,
update: existingPlugin?.update ?? true,
js: pluginJs ?? existingPlugin!.js,
error: existingPlugin?.error
};
}
export async function installPlugin(source: string, enabled = true) {
if (!source.endsWith("/")) source += "/";
invariant(!(source in sourceStore), "Source was already installed");
const plugin = await fetchAndStorePlugin(source);
if (enabled) await startPlugin(plugin.id);
}
/**
* @internal
*/
async function evalPlugin(plugin: BunnyPlugin) {
const vdObject = await createVdPluginObject(plugin);
const pluginString = `vendetta=>{return ${plugin.js}}\n//# sourceURL=${plugin.source}?hash=${plugin.manifest.hash}`;
const raw = (0, eval)(pluginString)(vdObject);
const ret = typeof raw === "function" ? raw() : raw;
return ret?.default ?? ret ?? {};
}
export async function startPlugin(id: string) {
const plugin = getPluginById(id);
invariant(plugin, "Attempted to start non-existent plugin");
try {
if (arePluginsEnabled()) {
const pluginRet: EvaledPlugin = await evalPlugin(plugin);
_pluginInstances[id] = pluginRet;
pluginRet.onLoad?.();
}
delete plugin.error;
plugin.enabled = true;
} catch (e) {
logger.error(`Plugin ${plugin.source} errored whilst loading, and will be unloaded`, e);
plugin.error = e instanceof Error ? e.stack : String(e);
try {
_pluginInstances[id]?.onUnload?.();
} catch (e2) {
logger.error(`Plugin ${plugin.source} errored whilst unloading`, e2);
}
delete _pluginInstances[id];
plugin.enabled = false;
}
}
export function stopPlugin(id: string, disable = true) {
const plugin = getPluginById(id);
const pluginInstance = _pluginInstances[id];
invariant(plugin, "Attempted to stop non-existent plugin");
if (arePluginsEnabled()) {
try {
pluginInstance?.onUnload?.();
} catch (e) {
logger.error(`Plugin ${plugin.source} errored whilst unloading`, e);
}
delete _pluginInstances[id];
}
if (disable) plugin.enabled = false;
}
export async function removePlugin(id: string) {
const plugin = getPluginById(id);
invariant(plugin, "Removing non-existent plugin");
if (plugin.enabled) stopPlugin(id);
delete sourceStore[plugin.source];
await purgeStorage(plugin.source);
}
/**
* @internal
*/
export async function initPlugins() {
await awaitStorage(sourceStore, preferredSourceStore, settings);
if (arePluginsEnabled()) {
const plugins = uniqWith(
Object.values(sourceStore)
.map(s => getPluginById(s!.id))
.filter(isNotNil),
(a, b) => a?.id === b?.id
);
const updatePromise: Promise<unknown>[] = [];
const updateAndStart = async (plugin: BunnyPlugin) => {
if (plugin.update) {
try {
await fetchAndStorePlugin(plugin.id);
} catch (e) {
logger.error(e);
}
}
await startPlugin(plugin.id);
};
for (const plugin of plugins) {
if (plugin.enabled) {
updatePromise.push(updateAndStart(plugin));
} else if (plugin.update) {
fetchAndStorePlugin(plugin.id);
}
}
await allSettled(updatePromise);
}
return () => Object.keys(_pluginInstances).forEach(p => stopPlugin(p, false));
}
export function getSettingsComponent(id: string) {
return _pluginInstances[id]?.settings;
}

View file

@ -1,4 +1,4 @@
import { allSettled } from "@core/polyfills/allSettled";
import { getCorePlugins } from "@core/plugins";
import { readFile, removeFile, writeFile } from "@lib/api/native/fs";
import { awaitStorage, createStorage, preloadStorageIfExists, updateStorageAsync } from "@lib/api/storage/new";
import { safeFetch } from "@lib/utils";
@ -344,7 +344,7 @@ export function stopPlugin(id: string) {
export async function checkAndRegisterUpdates() {
await awaitStorage(pluginRepositories, pluginSettings);
const corePlugins = {} as Record<string, any>; // TODO: getCorePlugins();
const corePlugins = getCorePlugins();
for (const id in corePlugins) {
const {
default: instance,
@ -361,7 +361,7 @@ export async function checkAndRegisterUpdates() {
corePluginInstances.set(id, instance);
}
await allSettled(Object.keys(pluginRepositories).map(async repo => {
await Promise.allSettled(Object.keys(pluginRepositories).map(async repo => {
await updateRepository(repo);
}));
}
@ -373,7 +373,7 @@ export async function initPlugins() {
await awaitStorage(pluginRepositories, pluginSettings);
// Now, start all enabled plugins...
await allSettled([...registeredPlugins.keys()].map(async id => {
await Promise.allSettled([...registeredPlugins.keys()].map(async id => {
if (isPluginEnabled(id)) {
await startPlugin(id);
}

View file

@ -22,6 +22,7 @@ export interface PluginSettingsStorage {
}
export interface BunnyPluginManifest {
readonly id: string;
readonly name: string;
readonly description: string;
readonly version: string;

View file

@ -2,7 +2,6 @@
* Theming system in Bunny is currently a prototype, expect an unreadable theme implementation below
*/
import { allSettled } from "@core/polyfills/allSettled";
import { getStoredTheme, getThemeFilePath } from "@lib/api/native/loader";
import { ThemeManager } from "@lib/api/native/modules";
import { after, before, instead } from "@lib/api/patcher";
@ -12,7 +11,7 @@ import { lazyDestructure, proxyLazy } from "@lib/utils/lazy";
import { Author } from "@lib/utils/types";
import { byMutableProp } from "@metro/filters";
import { createLazyModule } from "@metro/lazy";
import { findByNameLazy, findByProps, findByPropsLazy, findByStoreNameLazy } from "@metro/utils";
import { findByNameLazy, findByProps, findByPropsLazy, findByStoreNameLazy } from "@metro/wrappers";
import chroma from "chroma-js";
import { ImageBackground, Platform, processColor } from "react-native";
@ -232,7 +231,7 @@ export function getThemeFromLoader(): Theme | null {
export async function updateThemes() {
await awaitStorage(themes);
const currentTheme = getThemeFromLoader();
await allSettled(Object.keys(themes).map(id => fetchTheme(id, currentTheme?.id === id)));
await Promise.allSettled(Object.keys(themes).map(id => fetchTheme(id, currentTheme?.id === id)));
}
export function getCurrentTheme() {

View file

@ -1,5 +1,5 @@
import { ButtonColors } from "@lib/utils/types";
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
import InputAlert, { InputAlertProps } from "@ui/components/InputAlert";
const Alerts = findByPropsLazy("openLazy", "close");

View file

@ -1,6 +1,6 @@
import { color } from "@lib/managers/themes";
import { color } from "@lib/themes";
import { constants } from "@metro/common";
import { findByStoreNameLazy } from "@metro/utils";
import { findByStoreNameLazy } from "@metro/wrappers";
//! This module is only found on 165.0+, under the assumption that iOS 165.0 is the same as Android 165.0.
//* In 167.1, most if not all traces of the old color modules were removed.

View file

@ -1,7 +1,7 @@
import { instead } from "@lib/api/patcher";
import { lazyDestructure } from "@lib/utils/lazy";
import { OptionalKeys } from "@lib/utils/types";
import { findByProps } from "@metro/utils";
import { findByProps } from "@metro/wrappers";
import { AccessibilityInfo, Platform, View } from "react-native";
const { ContextMenu: _ContextMenu } = lazyDestructure(() => findByProps("ContextMenu"));

View file

@ -1,6 +1,6 @@
import { ButtonColors } from "@lib/utils/types";
import { LegacyAlert, LegacyFormInput } from "@metro/common/components";
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
const Alerts = findByPropsLazy("openLazy", "close");

View file

@ -1,14 +1,14 @@
import { Strings } from "@core/i18n";
import { DeviceManager } from "@lib/api/native/modules";
import { after } from "@lib/api/patcher";
import { toggleSafeMode } from "@lib/debug";
import { settings } from "@lib/settings";
import { toggleSafeMode } from "@lib/api/debug";
import { settings } from "@lib/api/settings";
import { lazyDestructure } from "@lib/utils/lazy";
import { ButtonColors } from "@lib/utils/types";
import { Button, CompatButton, SafeAreaView } from "@metro/common/components";
import { _lazyContextSymbol } from "@metro/lazy";
import { LazyModuleContext } from "@metro/types";
import { findByNameLazy, findByProps } from "@metro/utils";
import { findByNameLazy, findByProps } from "@metro/wrappers";
import { semanticColors } from "@ui/color";
import { Codeblock, ErrorBoundary as _ErrorBoundary } from "@ui/components";
import { createThemedStyleSheet, TextStyleSheet } from "@ui/styles";

View file

@ -2,7 +2,7 @@ import { after } from "@lib/api/patcher";
import { findInReactTree } from "@lib/utils";
import { i18n, NavigationNative } from "@metro/common";
import { LegacyFormIcon, LegacyFormRow, LegacyFormSection } from "@metro/common/components";
import { findByNameLazy } from "@metro/utils";
import { findByNameLazy } from "@metro/wrappers";
import { registeredSections } from "@ui/settings";
import { CustomPageRenderer, wrapOnPress } from "./shared";

View file

@ -1,5 +1,5 @@
import { NavigationNative } from "@metro/common";
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
import { ErrorBoundary } from "@ui/components";
import { RowConfig } from "@ui/settings";

View file

@ -1,7 +1,7 @@
import { after } from "@lib/api/patcher";
import { findInReactTree } from "@lib/utils";
import { i18n } from "@metro/common";
import { findByNameLazy, findByPropsLazy } from "@metro/utils";
import { findByNameLazy, findByPropsLazy } from "@metro/wrappers";
import { registeredSections } from "@ui/settings";
import { CustomPageRenderer, wrapOnPress } from "./shared";

View file

@ -1,4 +1,4 @@
import { findByPropsLazy } from "@metro/utils";
import { findByPropsLazy } from "@metro/wrappers";
const actionSheet = findByPropsLazy("openLazy", "hideActionSheet");

View file

@ -1,5 +1,5 @@
import { lazyDestructure, proxyLazy } from "@lib/utils/lazy";
import { findByProps, findByPropsLazy } from "@metro/utils";
import { findByProps, findByPropsLazy } from "@metro/wrappers";
import { isSemanticColor, resolveSemanticColor } from "@ui/color";
import { DiscordTextStyles } from "@ui/types";
import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from "react-native";

View file

@ -2,7 +2,7 @@ import { Strings } from "@core/i18n";
import { findAssetId } from "@lib/api/assets";
import { lazyDestructure } from "@lib/utils/lazy";
import { toasts } from "@metro/common";
import { findByProps } from "@metro/utils";
import { findByProps } from "@metro/wrappers";
const { uuid4 } = lazyDestructure(() => findByProps("uuid4"));

View file

@ -1,7 +1,7 @@
// Makes mass-importing utils cleaner, chosen over moving utils to one file
export * as constants from "@lib/utils/constants";
export { Emitter } from "@lib/utils/emitter";
export { Emitter } from "@lib/utils/Emitter";
export { findInReactTree } from "@lib/utils/findInReactTree";
export { findInTree } from "@lib/utils/findInTree";
export * as logger from "@lib/utils/logger";

View file

@ -1,4 +1,4 @@
import { findByNameLazy } from "@metro/utils";
import { findByNameLazy } from "@metro/wrappers";
export type LoggerFunction = (...messages: any[]) => void;
export interface Logger {

View file

@ -1,7 +1,8 @@
/* eslint-disable prefer-destructuring */
import { lazyDestructure, proxyLazy } from "@lib/utils/lazy";
import { createFilterDefinition } from "@metro/factories";
import { findExports } from "@metro/finders";
import { createFilterDefinition, findByDisplayNameLazy, findByNameLazy, findByProps, findByPropsLazy } from "@metro/utils";
import { findByDisplayNameLazy, findByNameLazy, findByProps, findByPropsLazy } from "@metro/wrappers";
import * as t from "./types/components";

View file

@ -1,7 +1,6 @@
import { proxyLazy } from "@lib/utils/lazy";
import { findByFilePath, findByProps, findByPropsLazy } from "@metro/utils";
import { findByFilePathLazy, findByProps, findByPropsLazy } from "@metro/wrappers";
import { Dispatcher } from "./types";
import type { Dispatcher } from "./types/flux";
// Discord
export const constants = findByPropsLazy("Fonts", "Permissions");
@ -13,7 +12,7 @@ export const assets = findByPropsLazy("registerAsset");
export const invites = findByPropsLazy("acceptInviteAndTransitionToInviteChannel");
export const commands = findByPropsLazy("getBuiltInCommands");
export const navigation = findByPropsLazy("pushLazy");
export const toasts = proxyLazy(() => findByFilePath("modules/toast/native/ToastActionCreators.tsx").default);
export const toasts = findByFilePathLazy("modules/toast/native/ToastActionCreators.tsx", true);
export const messageUtil = findByPropsLazy("sendBotMessage");
export const navigationStack = findByPropsLazy("createStackNavigator");
export const NavigationNative = findByPropsLazy("NavigationContainer");

41
src/metro/factories.ts Normal file
View file

@ -0,0 +1,41 @@
import { FilterCheckDef, FilterDefinition, ModuleExports } from "./types";
export function createFilterDefinition<A extends unknown[]>(
fn: FilterCheckDef<A>,
uniqMaker: (args: A) => string
): FilterDefinition<A> {
function createHolder<T extends Function>(func: T, args: A, raw: boolean) {
return Object.assign(func, {
filter: fn,
raw,
uniq: [
raw && "raw::",
uniqMaker(args)
].filter(Boolean).join("")
});
}
const curry = (raw: boolean) => (...args: A) => {
return createHolder((m: ModuleExports, id: number, defaultCheck: boolean) => {
return fn(args, m, id, defaultCheck);
}, args, raw);
};
return Object.assign(curry(false), {
byRaw: curry(true),
uniqMaker
});
}
export function createSimpleFilter(
filter: (m: ModuleExports) => boolean,
uniq: string
) {
return createFilterDefinition(
(_, m) => filter(m),
() => `dynamic::${uniq}`
)();
}

View file

@ -1,5 +1,5 @@
import { metroModules } from "./modules";
import { createFilterDefinition } from "./utils";
import { createFilterDefinition } from "./factories";
import { metroModules } from "./internals/modules";
export const byProps = createFilterDefinition<string[]>(
(props, m) => props.length === 0 ? m[props[0]] : props.every(p => m[p]),
@ -26,9 +26,12 @@ export const byStoreName = createFilterDefinition<[string]>(
name => `bunny.metro.byStoreName(${name})`
);
export const byFilePath = createFilterDefinition<[string]>(
([path], _, id, defaultCheck) => !defaultCheck && metroModules[id]?.__filePath === path,
path => `bunny.metro.byFilePath(${path})`
export const byFilePath = createFilterDefinition<[string, boolean]>(
// module return depends on defaultCheck. if true, it'll return module.default, otherwise the whole module
// unlike filters like byName, defaultCheck doesn't affect the return since we don't rely on exports, but only its ID
// one could say that this is technically a hack, since defaultCheck is meant for filtering exports
([path, exportDefault], _, id, defaultCheck) => (exportDefault === defaultCheck) && metroModules[id]?.__filePath === path,
([path, exportDefault]) => `bunny.metro.byFilePath(${path},${exportDefault})`
);
export const byMutableProp = createFilterDefinition<[string]>(

View file

@ -1,25 +1,28 @@
import { getCacherForUniq } from "./caches";
import { getModules, requireModule } from "./modules";
import { getCacherForUniq } from "./internals/caches";
import { getModules, requireModule } from "./internals/modules";
import { FilterFn } from "./types";
function filterExports<A extends unknown[]>(
moduleExports: any,
moduleId: number,
filter: FilterFn<A>,
): [any, boolean] | [void, false] {
) {
if (
moduleExports.default &&
moduleExports.__esModule &&
filter(moduleExports.default, moduleId, true)
) {
return [filter.raw ? moduleExports : moduleExports.default, !filter.raw];
return {
exports: filter.raw ? moduleExports : moduleExports.default,
defaultExport: !filter.raw
};
}
if (!filter.raw && filter(moduleExports, moduleId, false)) {
return [moduleExports, false];
return { exports: moduleExports, defaultExport: false };
}
return [undefined, false];
return {};
}
/**
@ -30,19 +33,19 @@ export function findModule<A extends unknown[]>(filter: FilterFn<A>) {
const { cacheId, finish } = getCacherForUniq(filter.uniq, false);
for (const [id, moduleExports] of getModules(filter.uniq, false)) {
const [testedExports, defaultExp] = filterExports(
const { exports: testedExports, defaultExport } = filterExports(
moduleExports,
id,
filter,
);
if (testedExports !== undefined) {
cacheId(id, testedExports);
return [id, defaultExp];
return { id, defaultExport };
}
}
finish(true);
return [];
return {};
}
/**
@ -50,7 +53,7 @@ export function findModule<A extends unknown[]>(filter: FilterFn<A>) {
* @param filter find calls filter once for each enumerable module's exports until it finds one where filter returns a thruthy value.
*/
export function findModuleId<A extends unknown[]>(filter: FilterFn<A>) {
return findModule(filter)?.[0];
return findModule(filter)?.id;
}
/**
@ -58,9 +61,9 @@ export function findModuleId<A extends unknown[]>(filter: FilterFn<A>) {
* @param filter find calls filter once for each enumerable module's exports until it finds one where filter returns a thruthy value.
*/
export function findExports<A extends unknown[]>(filter: FilterFn<A>) {
const [id, defaultExp] = findModule(filter);
const { id, defaultExport } = findModule(filter);
if (id == null) return;
return defaultExp ? requireModule(id).default : requireModule(id);
return defaultExport ? requireModule(id).default : requireModule(id);
}
/**
@ -69,16 +72,16 @@ export function findExports<A extends unknown[]>(filter: FilterFn<A>) {
*/
export function findAllModule<A extends unknown[]>(filter: FilterFn<A>) {
const { cacheId, finish } = getCacherForUniq(filter.uniq, true);
const foundExports: [id: number, defaultExp: boolean][] = [];
const foundExports: {id: number, defaultExport: boolean}[] = [];
for (const [id, moduleExports] of getModules(filter.uniq, true)) {
const [testedExports, defaultExp] = filterExports(
const { exports: testedExports, defaultExport } = filterExports(
moduleExports,
id,
filter,
);
if (testedExports !== undefined) {
foundExports.push([id, defaultExp]);
if (testedExports !== undefined && typeof defaultExport === "boolean") {
foundExports.push({ id, defaultExport });
cacheId(id, testedExports);
}
}
@ -92,7 +95,7 @@ export function findAllModule<A extends unknown[]>(filter: FilterFn<A>) {
* @param filter findAll calls filter once for each enumerable module's exports, adding the exports to the returned array when filter returns a thruthy value.
*/
export function findAllModuleId<A extends unknown[]>(filter: FilterFn<A>) {
return findAllModule(filter).map(e => e[0]);
return findAllModule(filter).map(e => e.id);
}
/**
@ -101,8 +104,9 @@ export function findAllModuleId<A extends unknown[]>(filter: FilterFn<A>) {
*/
export function findAllExports<A extends unknown[]>(filter: FilterFn<A>) {
return findAllModule(filter).map(ret => {
if (!ret.length) return;
const [id, defaultExp] = ret;
return defaultExp ? requireModule(id).default : requireModule(id);
if (!ret.id) return;
const { id, defaultExport } = ret;
return defaultExport ? requireModule(id).default : requireModule(id);
});
}

View file

@ -1,4 +1,6 @@
export * as common from "./common";
export * from "./filters";
export * as factories from "./factories";
export * as filters from "./filters";
export * from "./finders";
export * from "./utils";
export * as lazy from "./lazy";
export * from "./wrappers";

View file

@ -29,7 +29,7 @@ function buildInitCache() {
// because force loading it all will results in an unexpected crash.
setTimeout(() => {
for (const id in window.modules) {
require("@metro/modules").requireModule(id);
require("./modules").requireModule(id);
}
}, 100);
@ -37,7 +37,8 @@ function buildInitCache() {
return cache;
}
// Store in file system
// TODO: Store in file system... is a better idea?
/** @internal */
export async function initMetroCache() {
const rawCache = await MMKVManager.getItem(BUNNY_METRO_CACHE_KEY);
if (rawCache == null) return void buildInitCache();
@ -72,6 +73,7 @@ function extractExportsFlags(moduleExports: any) {
return bit;
}
/** @internal */
export function indexExportsFlags(moduleId: number, moduleExports: any) {
const flags = extractExportsFlags(moduleExports);
if (flags && flags !== ModuleFlags.EXISTS) {
@ -79,10 +81,12 @@ export function indexExportsFlags(moduleId: number, moduleExports: any) {
}
}
/** @internal */
export function indexBlacklistFlag(id: number) {
_metroCache.exportsIndex[id] |= ModuleFlags.BLACKLISTED;
}
/** @internal */
export function getCacherForUniq(uniq: string, allFind: boolean) {
const indexObject = _metroCache.findIndex[uniq] ??= {};
@ -102,12 +106,13 @@ export function getCacherForUniq(uniq: string, allFind: boolean) {
};
}
/** @internal */
export function getPolyfillModuleCacher(name: string) {
const indexObject = _metroCache.polyfillIndex[name] ??= {};
return {
getModules() {
return require("@metro/modules").getCachedPolyfillModules(name);
return require("@metro/internals/modules").getCachedPolyfillModules(name);
},
cacheId(moduleId: number) {
indexObject[moduleId] = 1;
@ -120,6 +125,7 @@ export function getPolyfillModuleCacher(name: string) {
};
}
/** @internal */
export function indexAssetName(name: string, moduleId: number) {
if (!isNaN(moduleId)) {
(_metroCache.assetsIndex[name] ??= {})[moduleId] = 1;

View file

@ -1,4 +1,4 @@
import { getMetroCache, indexBlacklistFlag, indexExportsFlags } from "@metro/caches";
import { getMetroCache, indexBlacklistFlag, indexExportsFlags } from "@metro/internals/caches";
import { Metro } from "@metro/types";
import { ModuleFlags, ModulesMapInternal } from "./enums";
@ -105,7 +105,7 @@ function onModuleRequire(moduleExports: any, id: Metro.ModuleID) {
get(target, property, receiver) {
if (property === "isDeveloper") {
// Hopefully won't explode accessing it here :3
const { settings } = require("@lib/settings");
const { settings } = require("@lib/api/settings");
return settings.enableDiscordDeveloperSettings ?? false;
}

View file

@ -1,9 +1,9 @@
import { _patcherDelaySymbol } from "@lib/api/patcher";
import { proxyLazy } from "@lib/utils/lazy";
import { getMetroCache } from "./caches";
import { findExports } from "./finders";
import { metroModules, subscribeModule } from "./modules";
import { getMetroCache } from "./internals/caches";
import { metroModules, subscribeModule } from "./internals/modules";
import type { FilterFn, LazyModuleContext } from "./types";
/** @internal */

View file

@ -1,4 +1,4 @@
import { getPolyfillModuleCacher } from "@metro/caches";
import { getPolyfillModuleCacher } from "@metro/internals/caches";
import { LiteralUnion } from "type-fest";
const redesignProps = new Set([

View file

@ -1,45 +1,6 @@
import { byDisplayName, byFilePath, byName, byProps, byStoreName, byTypeName } from "./filters";
import { findAllExports, findExports } from "./finders";
import { byDisplayName, byFilePath,byName, byProps, byStoreName, byTypeName } from "./filters";
import { findAllExports,findExports } from "./finders";
import { createLazyModule } from "./lazy";
import { FilterCheckDef, FilterDefinition, ModuleExports } from "./types";
export function createFilterDefinition<A extends unknown[]>(
fn: FilterCheckDef<A>,
uniqMaker: (args: A) => string
): FilterDefinition<A> {
function createHolder<T extends Function>(func: T, args: A, raw: boolean) {
return Object.assign(func, {
filter: fn,
raw,
uniq: [
raw && "raw::",
uniqMaker(args)
].filter(Boolean).join("")
});
}
const curry = (raw: boolean) => (...args: A) => {
return createHolder((m: ModuleExports, id: number, defaultCheck: boolean) => {
return fn(args, m, id, defaultCheck);
}, args, raw);
};
return Object.assign(curry(false), {
byRaw: curry(true),
uniqMaker
});
}
export function createSimpleFilter(
filter: (m: ModuleExports) => boolean,
uniq: string
) {
return createFilterDefinition(
(_, m) => filter(m),
() => `dynamic::${uniq}`
)();
}
export const findByProps = (...props: string[]) => findExports(byProps(...props));
export const findByPropsLazy = (...props: string[]) => createLazyModule(byProps(...props));
@ -60,6 +21,5 @@ export const findByTypeNameAll = (name: string, expDefault = true) => findAllExp
export const findByStoreName = (name: string) => findExports(byStoreName(name));
export const findByStoreNameLazy = (name: string) => createLazyModule(byStoreName(name));
export const findByFilePath = (path: string) => findExports(byFilePath(path));
export const findByFilePathLazy = (path: string) => createLazyModule(byFilePath(path));
export const findByFilePath = (path: string, expDefault = false) => findExports(byFilePath(path, expDefault));
export const findByFilePathLazy = (path: string, expDefault = false) => createLazyModule(byFilePath(path, expDefault));