From 4ffebc86717a069c3c2a8a35acbe49e46f1f8afc Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Thu, 7 Mar 2024 21:46:55 +0800 Subject: [PATCH] Introduce shelter inspired `api/flux` This shows a good example of adding to the Bunny APIs --- packages/bunny-types/def.tt | 1 + packages/bunny-types/package.json | 2 +- src/index.ts | 2 ++ src/lib/api/flux/index.ts | 42 +++++++++++++++++++++++++++++++ src/lib/api/index.ts | 1 + src/lib/metro/common.ts | 3 ++- src/lib/metro/types.ts | 19 ++++++++++++++ src/lib/windowObject.ts | 5 ++-- 8 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/lib/api/flux/index.ts create mode 100644 src/lib/metro/types.ts diff --git a/packages/bunny-types/def.tt b/packages/bunny-types/def.tt index 74c0b4c..67a7d38 100644 --- a/packages/bunny-types/def.tt +++ b/packages/bunny-types/def.tt @@ -4,6 +4,7 @@ @bunny from BunnyObject { api { commands + flux native { fs modules diff --git a/packages/bunny-types/package.json b/packages/bunny-types/package.json index 0aebcaa..b81e139 100644 --- a/packages/bunny-types/package.json +++ b/packages/bunny-types/package.json @@ -1,6 +1,6 @@ { "name": "bunny-types", - "version": "0.0.5", + "version": "0.0.6", "description": "Types for Bunny, a mod for Discord's mobile apps", "author": "pylixonly", "publishConfig": { diff --git a/src/index.ts b/src/index.ts index ace0ee0..3f7e740 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,7 @@ 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 { isThemeSupported } from "@lib/api/native/loader"; import { patchLogHook } from "@lib/debug"; import { initPlugins } from "@lib/managers/plugins"; @@ -23,6 +24,7 @@ export default async () => { // Load everything in parallel const unloads = await Promise.all([ + injectFluxInterceptor(), patchLogHook(), patchAssets(), patchCommands(), diff --git a/src/lib/api/flux/index.ts b/src/lib/api/flux/index.ts new file mode 100644 index 0000000..ca59496 --- /dev/null +++ b/src/lib/api/flux/index.ts @@ -0,0 +1,42 @@ +// shelter-mod inspired +import { FluxDispatcher } from "@lib/metro/common"; + +const blockedSym = Symbol.for("bunny.flux.blocked"); +const modifiedSym = Symbol.for("bunny.flux.modified"); + +export const dispatcher = FluxDispatcher; + +type Intercept = (payload: Record & { type: string; }) => any; +let intercepts: Intercept[] = []; + +export function injectFluxInterceptor() { + const cb = (payload: any) => { + for (const intercept of intercepts) { + const res = intercept(payload); + + // nullish -> nothing, falsy -> block, object -> modify + if (res == null) { + continue; + } else if (!res) { + payload[blockedSym] = true; + } else if (typeof res === "object") { + Object.assign(payload, res); + payload[modifiedSym] = true; + } + } + + return blockedSym in payload; + }; + + (dispatcher._interceptors ??= []).unshift(cb); + + return () => dispatcher._interceptors &&= dispatcher._interceptors.filter(v => v !== cb); +} + +export function intercept(cb: Intercept) { + intercepts.push(cb); + + return () => { + intercepts = intercepts.filter(i => i !== cb); + }; +} diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 80e1a0e..f003af3 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -1,5 +1,6 @@ export * as assets from "./assets"; export * as commands from "./commands"; +export * as flux from "./flux"; export * as native from "./native"; export * as patcher from "./patcher"; export * as storage from "./storage"; diff --git a/src/lib/metro/common.ts b/src/lib/metro/common.ts index 41a0b59..b1d1a3f 100644 --- a/src/lib/metro/common.ts +++ b/src/lib/metro/common.ts @@ -1,4 +1,5 @@ import { find, findByProps } from "@metro/filters"; +import { Dispatcher } from "@metro/types"; const colorModule = findByProps("colors", "unsafe_rawColors"); @@ -19,7 +20,7 @@ export const NavigationNative = findByProps("NavigationContainer"); // Flux export const Flux = findByProps("connectStores"); -export const FluxDispatcher = findByProps("_currentDispatchActionType"); +export const FluxDispatcher = findByProps("_currentDispatchActionType") as Dispatcher; // React export const React = window.React = findByProps("createElement") as typeof import("react"); diff --git a/src/lib/metro/types.ts b/src/lib/metro/types.ts new file mode 100644 index 0000000..acf6ef9 --- /dev/null +++ b/src/lib/metro/types.ts @@ -0,0 +1,19 @@ +export interface Dispatcher { + _actionHandlers: unknown; + _interceptors?: ((payload: any) => void | boolean)[]; + _currentDispatchActionType: undefined | string; + _processingWaitQueue: boolean; + _subscriptions: Record void>>; + _waitQueue: unknown[]; + + addDependencies(node1: any, node2: any): void; + dispatch(payload: any): Promise; + flushWaitQueue(): void; + isDispatching(): boolean; + register(name: string, actionHandler: Record void>, storeDidChange: (e: any) => boolean): string; + setInterceptor(interceptor?: (payload: any) => void | boolean): void; + subscribe(actionType: string, callback: (payload: any) => void): () => void; + unsubscribe(actionType: string, callback: (payload: any) => void): () => void; + wait(cb: () => void): void; +} + diff --git a/src/lib/windowObject.ts b/src/lib/windowObject.ts index 8d5333d..f659193 100644 --- a/src/lib/windowObject.ts +++ b/src/lib/windowObject.ts @@ -48,6 +48,7 @@ export type BunnyObject = ReturnType; const _bunnyObject = () => ({ // this function is never used, only exists for typings api: { ...api, + flux: utils.without({ ...api.flux }, "injectFluxInterceptor"), commands: { ...api.commands }, native: { ...api.native, @@ -59,7 +60,7 @@ const _bunnyObject = () => ({ // this function is never used, only exists for ty assets: { ...api.assets }, patcher: utils.without({ ...patcher, - unpatchAll: () => {} + unpatchAll: () => { } }, "unpatchAll") }, managers: { @@ -101,5 +102,5 @@ const _bunnyObject = () => ({ // this function is never used, only exists for ty }, debug: { ...debug }, version: debug.versionHash, - unload: () => {}, + unload: () => { }, });