From b9a29aaddd383056ec275794aeaf69b9520c8e3b Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:04:11 +0800 Subject: [PATCH] Typings rework --- package.json | 1 + packages/bunny-types/def.tt | 4 +- packages/bunny-types/package.json | 7 +- packages/bunny-types/pnpm-lock.yaml | 8 + packages/bunny-types/prepare.mjs | 10 +- packages/bunny-types/tsconfig.json | 7 +- pnpm-lock.yaml | 8 + src/core/ui/settings/index.ts | 1 + src/core/ui/settings/pages/General.tsx | 4 +- src/core/vendettaObject.ts | 288 +++++++++++++------------ src/global.d.ts | 2 +- src/index.ts | 44 ++-- src/lib/api/assets.ts | 5 +- src/lib/api/commands/index.ts | 5 +- src/lib/api/flux/index.ts | 5 +- src/lib/api/patcher.ts | 2 + src/lib/debug.ts | 21 +- src/lib/index.ts | 16 ++ src/lib/managers/plugins.ts | 12 +- src/lib/managers/themes.ts | 19 +- src/lib/metro/common.ts | 2 - src/lib/metro/filters.ts | 6 +- src/lib/metro/index.ts | 1 - src/lib/ui/safeMode.tsx | 4 +- src/lib/ui/settings/index.tsx | 8 +- src/lib/utils/types.ts | 10 +- src/lib/windowObject.ts | 6 - tsconfig.json | 1 + 28 files changed, 293 insertions(+), 214 deletions(-) delete mode 100644 src/lib/windowObject.ts diff --git a/package.json b/package.json index cbc01d7..f009de4 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "eslint-plugin-unused-imports": "^3.1.0", "intl-messageformat": "^10.5.11", "moment": "2.22.2", + "type-fest": "^4.12.0", "typescript": "^5.4.2", "typescript-transform-paths": "^3.4.7" }, diff --git a/packages/bunny-types/def.tt b/packages/bunny-types/def.tt index 83ac7ce..f6f25c4 100644 --- a/packages/bunny-types/def.tt +++ b/packages/bunny-types/def.tt @@ -1,5 +1,5 @@ -\source ./dist/wrap.ts -\import ./wrap +\source ./dist/index.d.ts +\import ./index @bunny from BunnyObject { api { diff --git a/packages/bunny-types/package.json b/packages/bunny-types/package.json index 7653fa4..cd84156 100644 --- a/packages/bunny-types/package.json +++ b/packages/bunny-types/package.json @@ -1,6 +1,6 @@ { "name": "bunny-types", - "version": "0.0.8", + "version": "0.0.9", "description": "Types for Bunny, a mod for Discord's mobile apps", "author": "pylixonly", "publishConfig": { @@ -16,13 +16,14 @@ ], "license": "BSD-3-Clause", "dependencies": { + "@react-native-clipboard/clipboard": "1.10.0", "@types/chroma-js": "^2.4.0", "@types/lodash": "^4.14.191", "@types/react": "18.2.60", "@types/react-native": "0.72.3", - "@react-native-clipboard/clipboard": "1.10.0", "moment": "2.22.2", - "spitroast": "^1.4.2" + "spitroast": "^1.4.2", + "type-fest": "^4.12.0" }, "devDependencies": { "@uwu/treetype": "^1.1.0", diff --git a/packages/bunny-types/pnpm-lock.yaml b/packages/bunny-types/pnpm-lock.yaml index 5ab457b..5f6b24a 100644 --- a/packages/bunny-types/pnpm-lock.yaml +++ b/packages/bunny-types/pnpm-lock.yaml @@ -26,6 +26,9 @@ dependencies: spitroast: specifier: ^1.4.2 version: 1.4.2 + type-fest: + specifier: ^4.12.0 + version: 4.12.0 devDependencies: '@uwu/treetype': @@ -4451,6 +4454,11 @@ packages: engines: {node: '>=8'} dev: false + /type-fest@4.12.0: + resolution: {integrity: sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ==} + engines: {node: '>=16'} + dev: false + /typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} diff --git a/packages/bunny-types/prepare.mjs b/packages/bunny-types/prepare.mjs index 056a442..6ca13f3 100644 --- a/packages/bunny-types/prepare.mjs +++ b/packages/bunny-types/prepare.mjs @@ -12,8 +12,14 @@ const exec = util.promisify(childProcess.exec); await fs.copyFile("package.json", "./dist/package.json"); await fs.copyFile("LICENSE", "./dist/LICENSE"); -await exec("pnpm dts-bundle-generator -o dist/index.d.ts --project ../../tsconfig.json ../../src/lib/index.ts --no-check --sort --no-banner"); +await exec("pnpm dts-bundle-generator -o dist/object.d.ts --project ../../tsconfig.json ../../src/lib/index.ts --no-check --sort"); -await fs.writeFile("./dist/wrap.ts", "export type BunnyObject = typeof import(\".\")"); +await fs.writeFile("./dist/index.d.ts", ` +declare global { + var bunny: BunnyObject; +} + +export type BunnyObject = typeof import("./object"); +`.trim()); await exec("pnpm treetype def.tt dist/treetype.d.ts"); diff --git a/packages/bunny-types/tsconfig.json b/packages/bunny-types/tsconfig.json index cc4c95e..fe85f16 100644 --- a/packages/bunny-types/tsconfig.json +++ b/packages/bunny-types/tsconfig.json @@ -1,3 +1,8 @@ { - "include": ["dist"] + "include": [ + "dist" + ], + "compilerOptions": { + "stripInternal": true + } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0558f81..5e9429a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,6 +70,9 @@ devDependencies: moment: specifier: 2.22.2 version: 2.22.2 + type-fest: + specifier: ^4.12.0 + version: 4.12.0 typescript: specifier: ^5.4.2 version: 5.4.2 @@ -2247,6 +2250,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@4.12.0: + resolution: {integrity: sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ==} + engines: {node: '>=16'} + dev: true + /typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} diff --git a/src/core/ui/settings/index.ts b/src/core/ui/settings/index.ts index 8580bd2..9b57cb6 100644 --- a/src/core/ui/settings/index.ts +++ b/src/core/ui/settings/index.ts @@ -7,6 +7,7 @@ import { registerSection } from "@lib/ui/settings"; import { version } from "bunny-build"; // @ts-ignore +// eslint-disable-next-line import-alias/import-alias import _PyoncordIcon from "../../../assets/icons/pyon64.png"; export const PyoncordIcon = _PyoncordIcon as string; diff --git a/src/core/ui/settings/pages/General.tsx b/src/core/ui/settings/pages/General.tsx index 1bf3e39..6aeed02 100644 --- a/src/core/ui/settings/pages/General.tsx +++ b/src/core/ui/settings/pages/General.tsx @@ -2,7 +2,7 @@ import { Strings } from "@core/i18n"; import { PyoncordIcon } from "@core/ui/settings"; import { getAssetIDByName } from "@lib/api/assets"; import { useProxy } from "@lib/api/storage"; -import { _toggleSafeMode, getDebugInfo } from "@lib/debug"; +import { getDebugInfo, toggleSafeMode } from "@lib/debug"; import { settings } from "@lib/settings"; import { Stack, TableRow, TableRowGroup, TableSwitchRow, useNavigation } from "@lib/ui/components/discord/Redesign"; import { DISCORD_SERVER, GITHUB } from "@lib/utils/constants"; @@ -66,7 +66,7 @@ export default function General() { label={settings.safeMode?.enabled ? Strings.RELOAD_IN_NORMAL_MODE : Strings.RELOAD_IN_SAFE_MODE} subLabel={settings.safeMode?.enabled ? Strings.RELOAD_IN_NORMAL_MODE_DESC : Strings.RELOAD_IN_SAFE_MODE_DESC} icon={} - onPress={_toggleSafeMode} + onPress={toggleSafeMode} /> ({ - patcher: { - before: patcher.before, - after: patcher.after, - instead: patcher.instead - }, - metro: { - find: (filter: (m: any) => boolean) => metro.find(filter), - findAll: (filter: (m: any) => boolean) => metro.findAll(filter), - findByProps: (...props: any) => metro.findByProps(...props), - findByPropsAll: (...props: any) => metro.findByPropsAll(...props), - findByName: (name: string, defaultExp?: boolean | undefined) => metro.findByName(name, defaultExp), - findByNameAll: (name: string, defaultExp?: boolean | undefined) => metro.findByNameAll(name, defaultExp), - findByDisplayName: (displayName: string, defaultExp?: boolean | undefined) => metro.findByDisplayName(displayName, defaultExp), - findByDisplayNameAll: (displayName: string, defaultExp?: boolean | undefined) => metro.findByDisplayNameAll(displayName, defaultExp), - findByTypeName: (typeName: string, defaultExp?: boolean | undefined) => metro.findByTypeName(typeName, defaultExp), - findByTypeNameAll: (typeName: string, defaultExp?: boolean | undefined) => metro.findByTypeNameAll(typeName, defaultExp), - findByStoreName: (name: string) => metro.findByStoreName(name), - common: { - constants: common.constants, - channels: common.channels, - i18n: common.i18n, - url: common.url, - toasts: common.toasts, - stylesheet: { - ...CompatfulRedesign, - createThemedStyleSheet +export const initVendettaObject = (): any => { + const api = window.vendetta = { + patcher: { + before: patcher.before, + after: patcher.after, + instead: patcher.instead + }, + metro: { + modules: window.modules, + find: (filter: (m: any) => boolean) => metro.find(filter), + findAll: (filter: (m: any) => boolean) => metro.findAll(filter), + findByProps: (...props: any) => metro.findByProps(...props), + findByPropsAll: (...props: any) => metro.findByPropsAll(...props), + findByName: (name: string, defaultExp?: boolean | undefined) => metro.findByName(name, defaultExp), + findByNameAll: (name: string, defaultExp?: boolean | undefined) => metro.findByNameAll(name, defaultExp), + findByDisplayName: (displayName: string, defaultExp?: boolean | undefined) => metro.findByDisplayName(displayName, defaultExp), + findByDisplayNameAll: (displayName: string, defaultExp?: boolean | undefined) => metro.findByDisplayNameAll(displayName, defaultExp), + findByTypeName: (typeName: string, defaultExp?: boolean | undefined) => metro.findByTypeName(typeName, defaultExp), + findByTypeNameAll: (typeName: string, defaultExp?: boolean | undefined) => metro.findByTypeNameAll(typeName, defaultExp), + findByStoreName: (name: string) => metro.findByStoreName(name), + common: { + constants: common.constants, + channels: common.channels, + i18n: common.i18n, + url: common.url, + toasts: common.toasts, + stylesheet: { + ...CompatfulRedesign, + createThemedStyleSheet + }, + clipboard: common.clipboard, + assets: common.assets, + invites: common.invites, + commands: common.commands, + navigation: common.navigation, + navigationStack: common.navigationStack, + NavigationNative: common.NavigationNative, + Flux: common.Flux, + FluxDispatcher: common.FluxDispatcher, + React: common.React, + ReactNative: common.ReactNative, + moment: common.moment, + chroma: common.chroma, + lodash: common.lodash, + util: common.util + } + }, + constants: { + DISCORD_SERVER: "https://discord.gg/n9QQ4XhhJP", + GITHUB: "https://github.com/vendetta-mod", + PROXY_PREFIX: "https://vd-plugins.github.io/proxy", + HTTP_REGEX: /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/, + HTTP_REGEX_MULTI: /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&//=]*)/g, + DISCORD_SERVER_ID: "1015931589865246730", + PLUGINS_CHANNEL_ID: "1091880384561684561", + THEMES_CHANNEL_ID: "1091880434939482202", + }, + utils: { + findInReactTree: (tree: { [key: string]: any; }, filter: any) => utils.findInReactTree(tree, filter), + findInTree: (tree: any, filter: any, options: any) => utils.findInTree(tree, filter, options), + safeFetch: (input: RequestInfo | URL, options?: RequestInit | undefined, timeout?: number | undefined) => utils.safeFetch(input, options, timeout), + unfreeze: (obj: object) => ({ ...obj }), + without: (object: any, ...keys: any) => utils.without(object, ...keys) + }, + debug: { + connectToDebugger: (url: string) => debug.connectToDebugger(url), + getDebugInfo: () => debug.getDebugInfo() + }, + ui: { + components: { + Forms, + General: common.ReactNative, + Alert: components.discord.Alert, + Button: components.discord.Button, + HelpMessage: components.discord.HelpMessage, + SafeAreaView: components.discord.SafeAreaView, + Summary: components.Summary, + ErrorBoundary: components.ErrorBoundary, + Codeblock: components.Codeblock, + Search: components.Search }, - clipboard: common.clipboard, - assets: common.assets, - invites: common.invites, - commands: common.commands, - navigation: common.navigation, - navigationStack: common.navigationStack, - NavigationNative: common.NavigationNative, - Flux: common.Flux, - FluxDispatcher: common.FluxDispatcher, - React: common.React, - ReactNative: common.ReactNative, - moment: common.moment, - chroma: common.chroma, - lodash: common.lodash, - util: common.util - } - }, - constants: { - DISCORD_SERVER: "https://discord.gg/n9QQ4XhhJP", - GITHUB: "https://github.com/vendetta-mod", - PROXY_PREFIX: "https://vd-plugins.github.io/proxy", - HTTP_REGEX: /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/, - HTTP_REGEX_MULTI: /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&//=]*)/g, - DISCORD_SERVER_ID: "1015931589865246730", - PLUGINS_CHANNEL_ID: "1091880384561684561", - THEMES_CHANNEL_ID: "1091880434939482202", - }, - utils: { - findInReactTree: (tree: { [key: string]: any; }, filter: any) => utils.findInReactTree(tree, filter), - findInTree: (tree: any, filter: any, options: any) => utils.findInTree(tree, filter, options), - safeFetch: (input: RequestInfo | URL, options?: RequestInit | undefined, timeout?: number | undefined) => utils.safeFetch(input, options, timeout), - unfreeze: (obj: object) => ({ ...obj }), - without: (object: any, ...keys: any) => utils.without(object, ...keys) - }, - debug: { - connectToDebugger: (url: string) => debug.connectToDebugger(url), - getDebugInfo: () => debug.getDebugInfo() - }, - ui: { - components: { - Forms, - General: common.ReactNative, - Alert: components.discord.Alert, - Button: components.discord.Button, - HelpMessage: components.discord.HelpMessage, - SafeAreaView: components.discord.SafeAreaView, - Summary: components.Summary, - ErrorBoundary: components.ErrorBoundary, - Codeblock: components.Codeblock, - Search: components.Search + toasts: { + showToast: (content: string, asset?: number) => toasts.showToast(content, asset) + }, + alerts: { + showConfirmationAlert: (options: any) => alerts.showConfirmationAlert(options), + showCustomAlert: (component: React.ComponentType, props: any) => alerts.showCustomAlert(component, props), + showInputAlert: (options: any) => alerts.showInputAlert(options) + }, + assets: { + all: assets.all, + find: (filter: (a: any) => void) => assets.find(filter), + getAssetByName: (name: string) => assets.getAssetByName(name), + getAssetByID: (id: number) => assets.getAssetByID(id), + getAssetIDByName: (name: string) => assets.getAssetIDByName(name) + }, + semanticColors: color.semanticColors, + rawColors: color.rawColors }, - toasts: { - showToast: (content: string, asset?: number) => toasts.showToast(content, asset) + plugins: { + plugins: plugins.plugins, + fetchPlugin: (id: string) => plugins.fetchPlugin(id), + installPlugin: (id: string, enabled?: boolean | undefined) => plugins.installPlugin(id, enabled), + startPlugin: (id: string) => plugins.startPlugin(id), + stopPlugin: (id: string, disable?: boolean | undefined) => plugins.stopPlugin(id, disable), + removePlugin: (id: string) => plugins.removePlugin(id), + getSettings: (id: string) => plugins.getSettings(id) }, - alerts: { - showConfirmationAlert: (options: any) => alerts.showConfirmationAlert(options), - showCustomAlert: (component: React.ComponentType, props: any) => alerts.showCustomAlert(component, props), - showInputAlert: (options: any) => alerts.showInputAlert(options) + themes: { + themes: themes.themes, + fetchTheme: (id: string, selected?: boolean) => themes.fetchTheme(id, selected), + installTheme: (id: string) => themes.installTheme(id), + selectTheme: (id: string) => themes.selectTheme(id === "default" ? null : id), + removeTheme: (id: string) => themes.removeTheme(id), + getCurrentTheme: () => themes.getThemeFromLoader(), + updateThemes: () => themes.updateThemes() }, - assets: { - all: assets.all, - find: (filter: (a: any) => void) => assets.find(filter), - getAssetByName: (name: string) => assets.getAssetByName(name), - getAssetByID: (id: number) => assets.getAssetByID(id), - getAssetIDByName: (name: string) => assets.getAssetIDByName(name) + commands: { + registerCommand: commands.registerCommand }, - semanticColors: color.semanticColors, - rawColors: color.rawColors - }, - plugins: { - plugins: plugins.plugins, - fetchPlugin: (id: string) => plugins.fetchPlugin(id), - installPlugin: (id: string, enabled?: boolean | undefined) => plugins.installPlugin(id, enabled), - startPlugin: (id: string) => plugins.startPlugin(id), - stopPlugin: (id: string, disable?: boolean | undefined) => plugins.stopPlugin(id, disable), - removePlugin: (id: string) => plugins.removePlugin(id), - getSettings: (id: string) => plugins.getSettings(id) - }, - themes: { - themes: themes.themes, - fetchTheme: (id: string, selected?: boolean) => themes.fetchTheme(id, selected), - installTheme: (id: string) => themes.installTheme(id), - selectTheme: (id: string) => themes.selectTheme(id === "default" ? null : id), - removeTheme: (id: string) => themes.removeTheme(id), - getCurrentTheme: () => themes._getThemeFromLoader(), - updateThemes: () => themes.updateThemes() - }, - commands: { - registerCommand: commands.registerCommand - }, - storage: { - createProxy: (target: any) => storage.createProxy(target), - useProxy: (_storage: T) => storage.useProxy(_storage), - createStorage: (backend: any) => storage.createStorage(backend), - wrapSync: (store: any) => storage.wrapSync(store), - awaitSyncWrapper: (store: any) => storage.awaitSyncWrapper(store), - createMMKVBackend: (store: string) => storage.createMMKVBackend(store), - createFileBackend: (file: string) => storage.createFileBackend(file) - }, - settings, - loader: { - identity: getVendettaLoaderIdentity() ?? void 0, - config: loaderConfig, - }, - logger: { - log: (...message: any) => console.log(...message), - info: (...message: any) => console.info(...message), - warn: (...message: any) => console.warn(...message), - error: (...message: any) => console.error(...message), - time: (...message: any) => console.time(...message), - trace: (...message: any) => console.trace(...message), - verbose: (...message: any) => console.log(...message) - }, - version: debug._versionHash, - unload: () => { - unloads.filter(i => typeof i === "function").forEach(p => p()); - delete window.vendetta; - }, -}); + storage: { + createProxy: (target: any) => storage.createProxy(target), + useProxy: (_storage: T) => storage.useProxy(_storage), + createStorage: (backend: any) => storage.createStorage(backend), + wrapSync: (store: any) => storage.wrapSync(store), + awaitSyncWrapper: (store: any) => storage.awaitSyncWrapper(store), + createMMKVBackend: (store: string) => storage.createMMKVBackend(store), + createFileBackend: (file: string) => storage.createFileBackend(file) + }, + settings, + loader: { + identity: getVendettaLoaderIdentity() ?? void 0, + config: loaderConfig, + }, + logger: { + log: (...message: any) => console.log(...message), + info: (...message: any) => console.info(...message), + warn: (...message: any) => console.warn(...message), + error: (...message: any) => console.error(...message), + time: (...message: any) => console.time(...message), + trace: (...message: any) => console.trace(...message), + verbose: (...message: any) => console.log(...message) + }, + version: debug.versionHash, + unload: () => { + delete window.vendetta; + }, + }; + + return () => api.unload(); +}; diff --git a/src/global.d.ts b/src/global.d.ts index 7aa4ec6..fcb5c42 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -2,7 +2,7 @@ import { MetroModules } from "@lib/metro/filters"; import { BunnyObject } from "@lib/windowObject"; declare global { - type React = typeof import("react"); + var React: typeof import("react"); interface Window { [key: string]: any; diff --git a/src/index.ts b/src/index.ts index addb35e..cc7585e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,48 +2,54 @@ import initFixes from "@core/fixes"; import { initFetchI18nStrings } from "@core/i18n"; import { initCorePlugins } from "@core/plugins"; import initSettings from "@core/ui/settings"; -import { _patchAssets } from "@lib/api/assets"; -import { _patchCommands } from "@lib/api/commands"; -import { _injectFluxInterceptor } from "@lib/api/flux"; +import { initVendettaObject } from "@core/vendettaObject"; +import { patchAssets } from "@lib/api/assets"; +import { patchCommands } from "@lib/api/commands"; +import { injectFluxInterceptor } from "@lib/api/flux"; import { isThemeSupported } from "@lib/api/native/loader"; -import { _patchLogHook } from "@lib/debug"; -import { _initPlugins } from "@lib/managers/plugins"; -import { _initThemes, _patchChatBackground } from "@lib/managers/themes"; -import { _patchSettings } from "@lib/ui/settings"; +import { patchLogHook } from "@lib/debug"; +import { initPlugins } from "@lib/managers/plugins"; +import { initThemes, patchChatBackground } from "@lib/managers/themes"; +import { patchSettings } from "@lib/ui/settings"; import { logger } from "@lib/utils/logger"; -import initWindowObject from "@lib/windowObject"; import initSafeMode from "@ui/safeMode"; +import * as lib from "./lib"; + export default async () => { // Themes if (isThemeSupported()) { try { - _initThemes(); + initThemes(); } catch (e) { console.error("[Bunny] Failed to initialize themes...", e); } } // Load everything in parallel - const unloads = await Promise.all([ - _injectFluxInterceptor(), - _patchSettings(), - _patchLogHook(), - _patchAssets(), - _patchCommands(), - _patchChatBackground(), + await Promise.all([ + injectFluxInterceptor(), + patchSettings(), + patchLogHook(), + patchAssets(), + patchCommands(), + patchChatBackground(), + initVendettaObject(), initFetchI18nStrings(), initSettings(), initFixes(), initSafeMode(), initCorePlugins(), - ]); + ]).then( + // Push them all to unloader + u => u.forEach(f => f && lib.unload.push(f)) + ); // Assign window object - initWindowObject(unloads); + window.bunny = lib; // Once done, load plugins - unloads.push(await _initPlugins()); + lib.unload.push(await initPlugins()); // We good :) logger.log("Bunny is ready!"); diff --git a/src/lib/api/assets.ts b/src/lib/api/assets.ts index 9c86256..0ac07be 100644 --- a/src/lib/api/assets.ts +++ b/src/lib/api/assets.ts @@ -8,7 +8,10 @@ export interface Asset { id: number; } -export function _patchAssets() { +/** + * @internal + */ +export function patchAssets() { const unpatch = after("registerAsset", assets, (args: Asset[], id: number) => { const asset = args[0]; all[asset.name] = { ...asset, id: id }; diff --git a/src/lib/api/commands/index.ts b/src/lib/api/commands/index.ts index e52e9a9..c63f2a4 100644 --- a/src/lib/api/commands/index.ts +++ b/src/lib/api/commands/index.ts @@ -4,7 +4,10 @@ import { commands as commandsModule } from "@metro/common"; let commands: ApplicationCommand[] = []; -export function _patchCommands() { +/** + * @internal + */ +export function patchCommands() { const unpatch = after("getBuiltInCommands", commandsModule, ([type], res: ApplicationCommand[]) => { if (type === ApplicationCommandType.CHAT) return res.concat(commands); }); diff --git a/src/lib/api/flux/index.ts b/src/lib/api/flux/index.ts index bf731a5..5814666 100644 --- a/src/lib/api/flux/index.ts +++ b/src/lib/api/flux/index.ts @@ -9,7 +9,10 @@ export const dispatcher = FluxDispatcher; type Intercept = (payload: Record & { type: string; }) => any; let intercepts: Intercept[] = []; -export function _injectFluxInterceptor() { +/** + * @internal + */ +export function injectFluxInterceptor() { const cb = (payload: any) => { for (const intercept of intercepts) { const res = intercept(payload); diff --git a/src/lib/api/patcher.ts b/src/lib/api/patcher.ts index c3784a6..2fabfda 100644 --- a/src/lib/api/patcher.ts +++ b/src/lib/api/patcher.ts @@ -3,4 +3,6 @@ export { before, instead } from "spitroast"; + +/** @internal */ export * as default from "spitroast"; diff --git a/src/lib/debug.ts b/src/lib/debug.ts index b1c3da4..ec3a258 100644 --- a/src/lib/debug.ts +++ b/src/lib/debug.ts @@ -2,7 +2,7 @@ import { getAssetIDByName } from "@lib/api/assets"; import { getLoaderName, isThemeSupported } from "@lib/api/native/loader"; import { BundleUpdaterManager, ClientInfoManager, DeviceManager } from "@lib/api/native/modules"; import { after } from "@lib/api/patcher"; -import { _getThemeFromLoader, selectTheme } from "@lib/managers/themes"; +import { getThemeFromLoader, selectTheme } from "@lib/managers/themes"; import { settings } from "@lib/settings"; import { logger } from "@lib/utils/logger"; import { showToast } from "@ui/toasts"; @@ -28,10 +28,13 @@ export interface RNConstants extends PlatformConstants { systemName: string; } -export async function _toggleSafeMode() { +/** + * @internal + */ +export async function toggleSafeMode() { settings.safeMode = { ...settings.safeMode, enabled: !settings.safeMode?.enabled }; if (isThemeSupported()) { - if (_getThemeFromLoader()?.id) settings.safeMode!.currentThemeId = _getThemeFromLoader()!.id; + if (getThemeFromLoader()?.id) settings.safeMode!.currentThemeId = getThemeFromLoader()!.id; if (settings.safeMode?.enabled) { await selectTheme("default"); } else if (settings.safeMode?.currentThemeId) { @@ -66,7 +69,10 @@ export function connectToDebugger(url: string) { }); } -export function _patchLogHook() { +/** + * @internal + */ +export function patchLogHook() { const unpatch = after("nativeLoggingHook", globalThis, args => { if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify({ message: args[0], level: args[1] })); logger.log(args[0]); @@ -78,7 +84,8 @@ export function _patchLogHook() { }; } -export const _versionHash = version; +/** @internal */ +export const versionHash = version; export function getDebugInfo() { // Hermes @@ -93,11 +100,11 @@ export function getDebugInfo() { return { /** @deprecated */ vendetta: { - version: _versionHash, + version: versionHash, loader: getLoaderName(), }, bunny: { - version: _versionHash, + version: versionHash, loader: getLoaderName(), }, discord: { diff --git a/src/lib/index.ts b/src/lib/index.ts index e7a669b..82ca517 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import-alias/import-alias import "../global.d.ts"; export * as api from "./api"; @@ -7,3 +8,18 @@ export * as metro from "./metro"; export * as settings from "./settings"; export * as ui from "./ui"; export * as utils from "./utils"; + +const _disposer = new Array<() => unknown>; + +export function unload() { + for (const d of _disposer) if (typeof d === "function") d(); + delete window.bunny; +} + +/** + * For internal use only, do not use! + * @internal + */ +unload.push = (fn: typeof _disposer[number]) => { + _disposer.push(fn); +}; diff --git a/src/lib/managers/plugins.ts b/src/lib/managers/plugins.ts index 159caeb..28b7d89 100644 --- a/src/lib/managers/plugins.ts +++ b/src/lib/managers/plugins.ts @@ -74,7 +74,10 @@ export async function installPlugin(id: string, enabled = true) { if (enabled) await startPlugin(id); } -export async function _evalPlugin(plugin: BunnyPlugin) { +/** + * @internal + */ +export async function evalPlugin(plugin: BunnyPlugin) { const vendettaForPlugins = { ...window.vendetta, plugin: { @@ -99,7 +102,7 @@ export async function startPlugin(id: string) { try { if (!settings.safeMode?.enabled) { - const pluginRet: EvaledPlugin = await _evalPlugin(plugin); + const pluginRet: EvaledPlugin = await evalPlugin(plugin); loadedPlugins[id] = pluginRet; pluginRet.onLoad?.(); } @@ -145,7 +148,10 @@ export async function removePlugin(id: string) { await purgeStorage(id); } -export async function _initPlugins() { +/** + * @internal + */ +export async function initPlugins() { await awaitSyncWrapper(settings); await awaitSyncWrapper(plugins); const allIds = Object.keys(plugins); diff --git a/src/lib/managers/themes.ts b/src/lib/managers/themes.ts index 0244c50..331e4fa 100644 --- a/src/lib/managers/themes.ts +++ b/src/lib/managers/themes.ts @@ -69,7 +69,10 @@ async function writeTheme(theme: Theme | {}) { await createFileBackend(getThemeFilePath() || "theme.json").set(theme); } -export function _patchChatBackground() { +/** + * @internal + */ +export function patchChatBackground() { const MessagesWrapperConnected = findByName("MessagesWrapperConnected", false); if (!MessagesWrapperConnected) return; const { MessagesWrapper } = findByProps("MessagesWrapper"); @@ -204,13 +207,16 @@ export async function removeTheme(id: string) { return theme.selected; } -export function _getThemeFromLoader(): Theme | null { +/** + * @internal + */ +export function getThemeFromLoader(): Theme | null { return getStoredTheme(); } export async function updateThemes() { await awaitSyncWrapper(themes); - const currentTheme = _getThemeFromLoader(); + const currentTheme = getThemeFromLoader(); await Promise.allSettled(Object.keys(themes).map(id => fetchTheme(id, currentTheme?.id === id))); } @@ -380,8 +386,11 @@ export function applyTheme(appliedTheme: Theme | null, fallbackTheme?: string, u } } -export async function _initThemes() { - const currentTheme = _getThemeFromLoader(); +/** + * @internal + */ +export async function initThemes() { + const currentTheme = getThemeFromLoader(); enabled = !!currentTheme; patchColor(); diff --git a/src/lib/metro/common.ts b/src/lib/metro/common.ts index b1d1a3f..cf03a5f 100644 --- a/src/lib/metro/common.ts +++ b/src/lib/metro/common.ts @@ -1,8 +1,6 @@ import { find, findByProps } from "@metro/filters"; import { Dispatcher } from "@metro/types"; -const colorModule = findByProps("colors", "unsafe_rawColors"); - // Discord export const constants = findByProps("Fonts", "Permissions"); export const channels = findByProps("getVoiceChannelId"); diff --git a/src/lib/metro/filters.ts b/src/lib/metro/filters.ts index 39aa864..b26e5e5 100644 --- a/src/lib/metro/filters.ts +++ b/src/lib/metro/filters.ts @@ -6,8 +6,9 @@ export type PropIntellisense

= Record & Recor export type PropsFinder = (...props: T[]) => PropIntellisense; export type PropsFinderAll = (...props: T[]) => PropIntellisense[]; -// Metro require -declare const __r: (moduleId: string) => any; +// Metro global vars +declare var __r: (moduleId: string) => any; +declare var modules: MetroModules; // Function to blacklist a module, preventing it from being searched again const blacklist = (id: string) => Object.defineProperty(window.modules, id, { @@ -102,7 +103,6 @@ const filterModules = (modules: MetroModules, single = false) => (filter: (m: an if (!single) return found; }; -export const { modules } = window; export const find = filterModules(modules, true); export const findAll = filterModules(modules); diff --git a/src/lib/metro/index.ts b/src/lib/metro/index.ts index ebe4004..bc2ad68 100644 --- a/src/lib/metro/index.ts +++ b/src/lib/metro/index.ts @@ -11,6 +11,5 @@ export { findByStoreName, findByTypeName, findByTypeNameAll, - modules } from "./filters"; export * as filters from "./filters"; diff --git a/src/lib/ui/safeMode.tsx b/src/lib/ui/safeMode.tsx index 4318093..025ce96 100644 --- a/src/lib/ui/safeMode.tsx +++ b/src/lib/ui/safeMode.tsx @@ -1,7 +1,7 @@ import { Strings } from "@core/i18n"; import { DeviceManager } from "@lib/api/native/modules"; import { after } from "@lib/api/patcher"; -import { _toggleSafeMode } from "@lib/debug"; +import { toggleSafeMode } from "@lib/debug"; import { settings } from "@lib/settings"; import { ButtonColors } from "@lib/utils/types"; import { findByName, findByProps } from "@metro/filters"; @@ -78,7 +78,7 @@ export default () => after("render", ErrorBoundary.prototype, function (this: an // This is in the patch and not outside of it so that we can use `this`, e.g. for setting state const buttons: Button[] = [ { text: Strings.RELOAD_DISCORD, onPress: this.handleReload }, - ...!settings.safeMode?.enabled ? [{ text: Strings.RELOAD_IN_SAFE_MODE, onPress: _toggleSafeMode }] : [], + ...!settings.safeMode?.enabled ? [{ text: Strings.RELOAD_IN_SAFE_MODE, onPress: toggleSafeMode }] : [], { text: Strings.RETRY_RENDER, color: ButtonColors.RED, onPress: () => this.setState({ info: null, error: null }) }, ]; diff --git a/src/lib/ui/settings/index.tsx b/src/lib/ui/settings/index.tsx index f9e2480..0948249 100644 --- a/src/lib/ui/settings/index.tsx +++ b/src/lib/ui/settings/index.tsx @@ -1,4 +1,5 @@ // Good luck reading this! +import { lazy } from "react"; import type { ImageURISource } from "react-native"; import { patchPanelUI } from "./patches/panel"; @@ -8,7 +9,7 @@ export interface RowConfig { key: string; title: () => string; onPress?: () => any; - render?: Parameters[0]; + render?: Parameters[0]; icon?: ImageURISource | number; usePredicate?: () => boolean, rawTabsConfig?: Record; @@ -23,7 +24,10 @@ export function registerSection(section: { name: string; items: RowConfig[]; }) return () => delete registeredSections[section.name]; } -export function _patchSettings() { +/** + * @internal + */ +export function patchSettings() { const unpatches = new Array<() => boolean>; patchPanelUI(unpatches); diff --git a/src/lib/utils/types.ts b/src/lib/utils/types.ts index 50a4aef..cc257cd 100644 --- a/src/lib/utils/types.ts +++ b/src/lib/utils/types.ts @@ -1,12 +1,6 @@ +import { LiteralUnion } from "type-fest"; -export type StringUnion = T | (string & {}); -export type OptionalKeys> = StringUnion; - -export type ExcludeInternalProperties = - T extends (...args: any[]) => any - ? T : { - [K in keyof T as K extends `_${string}` ? never : K]: T[K] extends object ? ExcludeInternalProperties : T[K]; - }; +export type OptionalKeys> = LiteralUnion; export interface Author { name: string; diff --git a/src/lib/windowObject.ts b/src/lib/windowObject.ts deleted file mode 100644 index e63d32b..0000000 --- a/src/lib/windowObject.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createVendettaObject } from "@core/vendettaObject"; - -export default function initWindowObject(unloads: any[]) { - window.vendetta = createVendettaObject(unloads); - window.bunny = require("."); -} diff --git a/tsconfig.json b/tsconfig.json index 4b6caa8..d36f21a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,7 @@ "esModuleInterop": true, "jsx": "react", "strict": true, + "stripInternal": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "skipLibCheck": true,