& { 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,