chore: refactor project structure
This commit is contained in:
parent
d6376513f0
commit
ccb49cb1af
71 changed files with 249 additions and 438 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { findByPropsLazy } from "@metro";
|
||||
import { findByPropsLazy } from "@metro/wrappers";
|
||||
|
||||
module.exports = {
|
||||
"react": findByPropsLazy("createElement"),
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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>{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
@ -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";
|
||||
|
||||
21
src/core/plugins/vd-quick-install/index.ts
Normal file
21
src/core/plugins/vd-quick-install/index.ts
Normal 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());
|
||||
}
|
||||
});
|
||||
|
|
@ -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";
|
||||
|
||||
|
|
@ -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;
|
||||
7
src/core/polyfills/promise-all-settled.ts
Normal file
7
src/core/polyfills/promise-all-settled.ts
Normal 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));
|
||||
};
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { createStyles } from "@lib/ui/styles";
|
||||
import { createStyles } from "@ui/styles";
|
||||
import { tokens } from "@metro/common";
|
||||
|
||||
export const usePluginCardStyles = createStyles({
|
||||
|
|
|
|||
|
|
@ -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."}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
export * as fonts from "./fonts";
|
||||
export * as plugins from "./plugins";
|
||||
export * as themes from "./themes";
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export interface PluginSettingsStorage {
|
|||
}
|
||||
|
||||
export interface BunnyPluginManifest {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly version: string;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { findByPropsLazy } from "@metro/utils";
|
||||
import { findByPropsLazy } from "@metro/wrappers";
|
||||
|
||||
const actionSheet = findByPropsLazy("openLazy", "hideActionSheet");
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { findByNameLazy } from "@metro/utils";
|
||||
import { findByNameLazy } from "@metro/wrappers";
|
||||
|
||||
export type LoggerFunction = (...messages: any[]) => void;
|
||||
export interface Logger {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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
41
src/metro/factories.ts
Normal 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}`
|
||||
)();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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]>(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { getPolyfillModuleCacher } from "@metro/caches";
|
||||
import { getPolyfillModuleCacher } from "@metro/internals/caches";
|
||||
import { LiteralUnion } from "type-fest";
|
||||
|
||||
const redesignProps = new Set([
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
Loading…
Add table
Reference in a new issue