diff --git a/lib/assets/src/_internal.ts b/lib/assets/src/_internal.ts index f1a29e4..7d0ad20 100644 --- a/lib/assets/src/_internal.ts +++ b/lib/assets/src/_internal.ts @@ -3,4 +3,7 @@ import type { Asset, AssetId } from './types' export const _customs = new Set() export const _overrides = new WeakMap() -export const _metas = new WeakMap() +export const _metas = new WeakMap< + Asset, + [assetId: AssetId, moduleId: Metro.ModuleID] +>() diff --git a/lib/assets/src/caches.ts b/lib/assets/src/caches.ts index 9e62747..6a02ec1 100644 --- a/lib/assets/src/caches.ts +++ b/lib/assets/src/caches.ts @@ -5,7 +5,6 @@ import { getStorage } from '@revenge-mod/storage' import { createLogger } from '@revenge-mod/utils/logger' import { mergeDeep } from '@revenge-mod/utils/objects' import { proxify } from '@revenge-mod/utils/proxy' - import type { Metro } from '@revenge-mod/modules/types' import type { Asset } from './types' diff --git a/lib/assets/src/index.ts b/lib/assets/src/index.ts index 4d5986b..b0b7f64 100644 --- a/lib/assets/src/index.ts +++ b/lib/assets/src/index.ts @@ -1,16 +1,15 @@ import { ReactNative } from '@revenge-mod/react' - import { _customs, _metas, _overrides } from './_internal' import { cache } from './caches' import { AssetRegistry } from './preinit' - import type { Metro } from '@revenge-mod/modules/types' import type { Asset, AssetId, RegisterableAsset } from './types' export { AssetRegistry, AssetRegistryModuleId } from './preinit' // iOS cannot display SVGs -let _preferredType: Asset['type'] = ReactNative.Platform.OS === 'ios' ? 'png' : 'svg' +let _preferredType: Asset['type'] = + ReactNative.Platform.OS === 'ios' ? 'png' : 'svg' /** * Set the preferred asset type. This is used to determine which asset to use when multiple types are available. @@ -26,7 +25,8 @@ export function setPreferredAssetType(type: Asset['type']) { */ export function* getAssets(): Generator { for (const name of Object.keys(cache!)) - for (const mid of Object.values(cache[name])) yield AssetRegistry.getAssetByID(__r(mid)) as Asset + for (const mid of Object.values(cache[name])) + yield AssetRegistry.getAssetByID(__r(mid)) as Asset for (const asset of _customs) yield asset } @@ -48,7 +48,9 @@ export function getAssetByName(name: string): Asset | undefined { * @param name The asset name. * @returns A record keyed by the type of the asset, with the value being the asset itself. */ -export function getAssetsByName(name: string): Record | undefined { +export function getAssetsByName( + name: string, +): Record | undefined { const reg = cache[name] if (!reg) return @@ -89,7 +91,9 @@ export function getAssetIdByName(name: string): AssetId | undefined { * * @param asset The asset to get the module ID for. */ -export function getAssetModuleId(asset: Asset): Metro.ModuleID | -1 | undefined { +export function getAssetModuleId( + asset: Asset, +): Metro.ModuleID | -1 | undefined { return _metas.get(asset)?.[1] } @@ -101,7 +105,9 @@ export function getAssetModuleId(asset: Asset): Metro.ModuleID | -1 | undefined */ export function registerAsset(asset: RegisterableAsset): AssetId { if (cache[asset.name]?.[asset.type] !== undefined) - throw new Error(`Asset with name ${asset.name} and type ${asset.type} already exists!`) + throw new Error( + `Asset with name ${asset.name} and type ${asset.type} already exists!`, + ) _customs.add(asset) diff --git a/lib/assets/src/preinit.ts b/lib/assets/src/preinit.ts index 8bed941..79c28b9 100644 --- a/lib/assets/src/preinit.ts +++ b/lib/assets/src/preinit.ts @@ -2,10 +2,8 @@ import { _initing, _uninits } from '@revenge-mod/modules/_/metro' import { byName, byProps } from '@revenge-mod/modules/finders/filters' import { waitForModules } from '@revenge-mod/modules/finders/wait' import { getModuleDependencies } from '@revenge-mod/modules/metro/utils' - import { _metas, _overrides } from './_internal' import { cacheAsset } from './caches' - import type { ReactNative } from '@revenge-mod/react/types' import type { Asset, ReactNativeAsset } from './types' @@ -13,52 +11,57 @@ export let AssetRegistry: ReactNative.AssetsRegistry export let AssetRegistryModuleId: number // Tracking/caching assets -const unsubAR = waitForModules(byProps('registerAsset'), (exports, id) => { - AssetRegistryModuleId = id - AssetRegistry = exports as ReactNative.AssetsRegistry +const unsubAR = waitForModules( + byProps('registerAsset'), + (exports, id) => { + AssetRegistryModuleId = id + AssetRegistry = exports as ReactNative.AssetsRegistry - // There are two matching exports. One is the original, and one is a re-export. - // The original asset-registry is simply required by the re-exported one with no changes. + // There are two matching exports. One is the original, and one is a re-export. + // The original asset-registry is simply required by the re-exported one with no changes. - // This is the re-exported registry, because it has dependencies. - // We can begin the caching process here, asset registrar modules have the reexported registry as a dependency. - if (getModuleDependencies(id)!.length) { - unsubAR() + // This is the re-exported registry, because it has dependencies. + // We can begin the caching process here, asset registrar modules have the reexported registry as a dependency. + if (getModuleDependencies(id)!.length) { + unsubAR() - // TODO(assets/patches): conditionally run this if cache does not exist - // More fragile way, but also more performant: - // There is exactly one asset before the reexported asset registry :/ - const firstAssetModuleId = id - 1 - for (const mId of _uninits) { - if (mId < firstAssetModuleId) continue + // TODO(assets/patches): conditionally run this if cache does not exist + // More fragile way, but also more performant: + // There is exactly one asset before the reexported asset registry :/ + const firstAssetModuleId = id - 1 + for (const mId of _uninits) { + if (mId < firstAssetModuleId) continue - const deps = getModuleDependencies(mId)! - if (deps.length === 1 && deps[0] === id) __r(mId) + const deps = getModuleDependencies(mId)! + if (deps.length === 1 && deps[0] === id) __r(mId) + } + + // We already patched the original asset registry, so we don't need to patch again. + return } - // We already patched the original asset registry, so we don't need to patch again. - return - } + const orig = exports.registerAsset + exports.registerAsset = (asset: Asset) => { + const result = orig(asset as ReactNativeAsset) - const orig = exports.registerAsset - exports.registerAsset = (asset: Asset) => { - const result = orig(asset as ReactNativeAsset) + // Cache packager assets only + if ((asset as ReactNativeAsset).__packager_asset) { + cacheAsset(asset, _initing) + // In-memory cache + _metas.set(asset, [result, _initing]) + } - // Cache packager assets only - if ((asset as ReactNativeAsset).__packager_asset) { - cacheAsset(asset, _initing) - // In-memory cache - _metas.set(asset, [result, _initing]) + return result } - - return result - } -}) + }, +) // Asset overrides const unsubRAS = waitForModules( byName<{ - addCustomSourceTransformer: (transformer: (arg: { asset: Asset }) => ReactNativeAsset) => void + addCustomSourceTransformer: ( + transformer: (arg: { asset: Asset }) => ReactNativeAsset, + ) => void }>('resolveAssetSource'), rAS => { unsubRAS() diff --git a/lib/assets/src/types.ts b/lib/assets/src/types.ts index bbcb60a..40a249a 100644 --- a/lib/assets/src/types.ts +++ b/lib/assets/src/types.ts @@ -4,7 +4,8 @@ export type Asset = ReactNativeAsset | RevengeAsset export type AssetId = number export type ReactNativeAsset = ReactNative.AssetsRegistry.PackagerAsset -export interface RevengeAsset extends Pick { +export interface RevengeAsset + extends Pick { uri: string } diff --git a/lib/discord/src/actions.ts b/lib/discord/src/actions.ts index 20b1339..1157fb8 100644 --- a/lib/discord/src/actions.ts +++ b/lib/discord/src/actions.ts @@ -6,80 +6,91 @@ import { relativeDep, withoutProps, } from '@revenge-mod/modules/finders/filters' -import { lookupModule, lookupModules } from '@revenge-mod/modules/finders/lookup' - +import { + lookupModule, + lookupModules, +} from '@revenge-mod/modules/finders/lookup' import { ReactJsxRuntimeModuleId, ReactModuleId } from '@revenge-mod/react' - import { proxify } from '@revenge-mod/utils/proxy' - import { DispatcherModuleId } from './common/flux' - import type { DiscordModules } from './types' -export let ActionSheetActionCreators: DiscordModules.Actions.ActionSheetActionCreators = proxify( - () => { - const [module] = lookupModule( +export let ActionSheetActionCreators: DiscordModules.Actions.ActionSheetActionCreators = + proxify( + () => { + const [module] = lookupModule( + preferExports( + byProps( + 'hideActionSheet', + ), + byDependencies([ + undefined, + ReactModuleId, + ReactJsxRuntimeModuleId, + DispatcherModuleId, + relativeDep(1), + relativeDep(2), + 2, + ]), + ), + { + includeUninitialized: true, + }, + ) + + if (module) return (ActionSheetActionCreators = module) + }, + { + hint: 'object', + }, + )! + +export let AlertActionCreators: DiscordModules.Actions.AlertActionCreators = + proxify( + () => { + const [module] = lookupModule( + preferExports( + byProps( + 'openAlert', + 'dismissAlert', + ), + byDependencies([ + ReactModuleId, + ReactJsxRuntimeModuleId, + undefined, + DispatcherModuleId, + relativeDep(1), + undefined, + 2, + ]), + ), + ) + + if (module) return (AlertActionCreators = module) + }, + { + hint: 'object', + }, + )! + +export let ToastActionCreators: DiscordModules.Actions.ToastActionCreators = + proxify(() => { + // Many other modules share the same dependencies, the second yielded should be the correct module. + // [Dispatcher, ImportTracker] + + const generator = lookupModules( preferExports( - byProps('hideActionSheet'), - byDependencies([ - undefined, - ReactModuleId, - ReactJsxRuntimeModuleId, - DispatcherModuleId, - relativeDep(1), - relativeDep(2), - 2, - ]), + every( + byProps('open'), + withoutProps('init'), + ), + byDependencies([DispatcherModuleId, 2]), ), { includeUninitialized: true, }, ) - if (module) return (ActionSheetActionCreators = module) - }, - { - hint: 'object', - }, -)! - -export let AlertActionCreators: DiscordModules.Actions.AlertActionCreators = proxify( - () => { - const [module] = lookupModule( - preferExports( - byProps('openAlert', 'dismissAlert'), - byDependencies([ - ReactModuleId, - ReactJsxRuntimeModuleId, - undefined, - DispatcherModuleId, - relativeDep(1), - undefined, - 2, - ]), - ), - ) - - if (module) return (AlertActionCreators = module) - }, - { - hint: 'object', - }, -)! - -export let ToastActionCreators: DiscordModules.Actions.ToastActionCreators = proxify(() => { - // Many other modules share the same dependencies, the second yielded should be the correct module. - // [Dispatcher, ImportTracker] - - const generator = lookupModules( - preferExports( - every(byProps('open'), withoutProps('init')), - byDependencies([DispatcherModuleId, 2]), - ), - { - includeUninitialized: true, - }, - ) - - for (const [module] of generator) if (module.open.length === 1) return (ToastActionCreators = module) -})! + for (const [module] of generator) + if (module.open.length === 1) return (ToastActionCreators = module) + })! diff --git a/lib/discord/src/common/flux.ts b/lib/discord/src/common/flux.ts index 9aad188..330c526 100644 --- a/lib/discord/src/common/flux.ts +++ b/lib/discord/src/common/flux.ts @@ -1,5 +1,4 @@ import { - type Filter, byDependencies, byProps, createFilterGenerator, @@ -9,7 +8,7 @@ import { import { lookupModule } from '@revenge-mod/modules/finders/lookup' import { waitForModules } from '@revenge-mod/modules/finders/wait' import { noopFalse } from '@revenge-mod/utils/callbacks' - +import type { Filter } from '@revenge-mod/modules/finders/filters' import type { Metro } from '@revenge-mod/modules/types' import type { DiscordModules } from '../types' @@ -18,7 +17,14 @@ import type { DiscordModules } from '../types' export const [Dispatcher, DispatcherModuleId] = lookupModule( preferExports( byProps('_interceptors'), - byDependencies([relativeDep(1), undefined, undefined, undefined, undefined, 2]), + byDependencies([ + relativeDep(1), + undefined, + undefined, + undefined, + undefined, + 2, + ]), ), { includeUninitialized: true, @@ -37,7 +43,10 @@ export const Stores = new Proxy(_stores, { get: (_, name) => _stores[name as string], }) -export function getStore(name: string, callback: (store: DiscordModules.Flux.Store) => void) { +export function getStore( + name: string, + callback: (store: DiscordModules.Flux.Store) => void, +) { const store = Stores[name] if (store) { callback(store) @@ -47,9 +56,12 @@ export function getStore(name: string, callback: (store: DiscordModules.Flux. return waitForModules(byStoreName(name), callback) } -export type ByStoreName = (name: string) => Filter> +export type ByStoreName = ( + name: string, +) => Filter> export const byStoreName = createFilterGenerator<[name: string]>( - ([name], _, exports) => exports.getName?.length === 0 && exports.getName() === name, + ([name], _, exports) => + exports.getName?.length === 0 && exports.getName() === name, ([name]) => `revenge.discord.byStoreName(${name})`, ) as ByStoreName diff --git a/lib/discord/src/common/index.ts b/lib/discord/src/common/index.ts index 06118f7..af5a0fe 100644 --- a/lib/discord/src/common/index.ts +++ b/lib/discord/src/common/index.ts @@ -1,15 +1,18 @@ import { byName, byProps } from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' - import type { Metro } from '@revenge-mod/modules/types' import type { DiscordModules } from '../types' export { AppStartPerformance } from '../preinit' - export * as Flux from './flux' // ../discord_common/js/shared/Logger.tsx -export const [Logger] = lookupModule(byName('Logger')) as [DiscordModules.Logger, Metro.ModuleID] +export const [Logger] = lookupModule( + byName('Logger'), +) as [DiscordModules.Logger, Metro.ModuleID] // ../discord_common/js/packages/tokens/native.tsx -export const [Tokens, TokensModuleId] = lookupModule(byProps('RawColor')) as [any, Metro.ModuleID] +export const [Tokens, TokensModuleId] = lookupModule(byProps('RawColor')) as [ + any, + Metro.ModuleID, +] diff --git a/lib/discord/src/design.ts b/lib/discord/src/design.ts index 175fa18..d1f13b8 100644 --- a/lib/discord/src/design.ts +++ b/lib/discord/src/design.ts @@ -7,11 +7,12 @@ import { relativeDep, } from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' - -import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react' - +import { + ReactJsxRuntimeModuleId, + ReactModuleId, + ReactNativeModuleId, +} from '@revenge-mod/react' import { proxify } from '@revenge-mod/utils/proxy' - import type { DiscordModules } from './types' // design/native.tsx @@ -22,7 +23,15 @@ export let Design: Design = proxify( const [module] = lookupModule( preferExports( byProps('TableRow', 'Button'), - byDependencies(looseDeps([relativeDep(1), undefined, relativeDep(2), relativeDep(3), 2])), + byDependencies( + looseDeps([ + relativeDep(1), + undefined, + relativeDep(2), + relativeDep(3), + 2, + ]), + ), ), { includeUninitialized: true, @@ -45,7 +54,9 @@ export let FormSwitch: DiscordModules.Components.FormSwitch = proxify(() => { const [module] = lookupModule( preferExports( - bySingleProp<{ FormSwitch: DiscordModules.Components.FormSwitch }>('FormSwitch'), + bySingleProp<{ FormSwitch: DiscordModules.Components.FormSwitch }>( + 'FormSwitch', + ), byDependencies([ [relativeDep(1), relativeDep(2), undefined, relativeDep(3)], ReactModuleId, diff --git a/lib/discord/src/init.ts b/lib/discord/src/init.ts index 3a784a2..4f99e96 100644 --- a/lib/discord/src/init.ts +++ b/lib/discord/src/init.ts @@ -1,8 +1,6 @@ import { _initExts, _uapi } from '@revenge-mod/plugins/_' import { defineLazyProperty } from '@revenge-mod/utils/objects' - import { Logger } from './common' - import type { UnscopedInitPluginApi } from '@revenge-mod/plugins/types' import type { PluginApiDiscord } from './types/revenge' @@ -10,10 +8,18 @@ const uapi = _uapi as UnscopedInitPluginApi const discord = (uapi.discord = {} as PluginApiDiscord) // TODO: Rolldown issue: Bug requires us to do { ...require('...') } instead of just require('...') -defineLazyProperty(discord, 'actions', () => ({ ...require('@revenge-mod/discord/actions') })) -defineLazyProperty(discord, 'common', () => ({ ...require('@revenge-mod/discord/common') })) -defineLazyProperty(discord, 'design', () => ({ ...require('@revenge-mod/discord/design') })) -defineLazyProperty(discord, 'native', () => ({ ...require('@revenge-mod/discord/native') })) +defineLazyProperty(discord, 'actions', () => ({ + ...require('@revenge-mod/discord/actions'), +})) +defineLazyProperty(discord, 'common', () => ({ + ...require('@revenge-mod/discord/common'), +})) +defineLazyProperty(discord, 'design', () => ({ + ...require('@revenge-mod/discord/design'), +})) +defineLazyProperty(discord, 'native', () => ({ + ...require('@revenge-mod/discord/native'), +})) defineLazyProperty(discord, 'modules', () => ({ settings: { ...require('@revenge-mod/discord/modules/settings'), @@ -22,5 +28,9 @@ defineLazyProperty(discord, 'modules', () => ({ })) _initExts.push((api, { manifest: { id } }) => - defineLazyProperty(api, 'logger', () => new Logger(`Revenge > Plugins (${id})`)), + defineLazyProperty( + api, + 'logger', + () => new Logger(`Revenge > Plugins (${id})`), + ), ) diff --git a/lib/discord/src/modules/settings/_internal.ts b/lib/discord/src/modules/settings/_internal.ts index 76657d7..fa0ca22 100644 --- a/lib/discord/src/modules/settings/_internal.ts +++ b/lib/discord/src/modules/settings/_internal.ts @@ -1,4 +1,8 @@ -import type { SettingsItem, SettingsModulesLoadedSubscription, SettingsSection } from '.' +import type { + SettingsItem, + SettingsModulesLoadedSubscription, + SettingsSection, +} from '.' export const _data = [ // Sections to splice in the SettingsOverviewScreen @@ -6,6 +10,10 @@ export const _data = [ // SETTING_RENDERER_CONFIG settings {}, false, -] as [sections: Record, config: Record, loaded: boolean] +] as [ + sections: Record, + config: Record, + loaded: boolean, +] export const _subs = new Set() diff --git a/lib/discord/src/modules/settings/index.ts b/lib/discord/src/modules/settings/index.ts index 68f51c4..8c81218 100644 --- a/lib/discord/src/modules/settings/index.ts +++ b/lib/discord/src/modules/settings/index.ts @@ -1,5 +1,4 @@ import { _data, _subs } from './_internal' - import type { DiscordModules } from '../../types' export type SettingsItem = DiscordModules.Modules.Settings.SettingsItem @@ -22,7 +21,9 @@ export function isSettingsModulesLoaded() { * @returns A function to unsubscribe from the event. * @throws Throws an error if the settings modules are already loaded. Check with {@link isSettingsModulesLoaded} first. */ -export function onSettingsModulesLoaded(subcription: SettingsModulesLoadedSubscription) { +export function onSettingsModulesLoaded( + subcription: SettingsModulesLoadedSubscription, +) { if (_data[2]) throw new Error('Settings modules already loaded') _subs.add(subcription) diff --git a/lib/discord/src/modules/settings/renderer.ts b/lib/discord/src/modules/settings/renderer.ts index e379d69..1b6e860 100644 --- a/lib/discord/src/modules/settings/renderer.ts +++ b/lib/discord/src/modules/settings/renderer.ts @@ -1,13 +1,21 @@ -import { byDependencies, byProps, looseDeps, preferExports, relativeDep } from '@revenge-mod/modules/finders/filters' +import { + byDependencies, + byProps, + looseDeps, + preferExports, + relativeDep, +} from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' - -import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react' - +import { + ReactJsxRuntimeModuleId, + ReactModuleId, + ReactNativeModuleId, +} from '@revenge-mod/react' import { proxify } from '@revenge-mod/utils/proxy' - import type { DiscordModules } from '../../types' -export type SettingListRenderer = DiscordModules.Modules.Settings.SettingListRenderer +export type SettingListRenderer = + DiscordModules.Modules.Settings.SettingListRenderer export let SettingListRenderer: SettingListRenderer = proxify( () => { diff --git a/lib/discord/src/native.ts b/lib/discord/src/native.ts index b540fd7..5373070 100644 --- a/lib/discord/src/native.ts +++ b/lib/discord/src/native.ts @@ -11,9 +11,15 @@ import type { DiscordNativeModules } from './types/native' const nmp = nativeModuleProxy -export const CacheModule = nmp.NativeCacheModule as DiscordNativeModules.CacheModule -export const FileModule = nmp.NativeFileModule as DiscordNativeModules.FileModule -export const ClientInfoModule = nmp.NativeClientInfoModule as DiscordNativeModules.ClientInfoModule -export const DeviceModule = nmp.NativeDeviceModule as DiscordNativeModules.DeviceModule -export const BundleUpdaterManager = nmp.BundleUpdaterManager as DiscordNativeModules.BundleUpdaterManager -export const ThemeModule = nmp.NativeThemeModule as DiscordNativeModules.ThemeModule +export const CacheModule = + nmp.NativeCacheModule as DiscordNativeModules.CacheModule +export const FileModule = + nmp.NativeFileModule as DiscordNativeModules.FileModule +export const ClientInfoModule = + nmp.NativeClientInfoModule as DiscordNativeModules.ClientInfoModule +export const DeviceModule = + nmp.NativeDeviceModule as DiscordNativeModules.DeviceModule +export const BundleUpdaterManager = + nmp.BundleUpdaterManager as DiscordNativeModules.BundleUpdaterManager +export const ThemeModule = + nmp.NativeThemeModule as DiscordNativeModules.ThemeModule diff --git a/lib/discord/src/preinit.ts b/lib/discord/src/preinit.ts index 047d591..6b8ea90 100644 --- a/lib/discord/src/preinit.ts +++ b/lib/discord/src/preinit.ts @@ -1,6 +1,10 @@ -import { byDependencies, byProps, preferExports, relativeDep } from '@revenge-mod/modules/finders/filters' +import { + byDependencies, + byProps, + preferExports, + relativeDep, +} from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' - import type { Metro } from '@revenge-mod/modules/types' import type { DiscordModules } from './types' diff --git a/lib/discord/src/types/index.ts b/lib/discord/src/types/index.ts index 61017f7..6a57cbf 100644 --- a/lib/discord/src/types/index.ts +++ b/lib/discord/src/types/index.ts @@ -51,12 +51,20 @@ export namespace DiscordModules { export interface Dispatcher { _actionHandlers: unknown - _interceptors?: ((payload: DispatcherPayload) => undefined | boolean)[] + _interceptors?: (( + payload: DispatcherPayload, + ) => undefined | boolean)[] _currentDispatchActionType: undefined | string _processingWaitQueue: boolean - _subscriptions: Record void>> + _subscriptions: Record< + string, + Set<(payload: DispatcherPayload) => void> + > _waitQueue: unknown[] - addDependencies(node1: DispatcherDependency, node2: DispatcherDependency): void + addDependencies( + node1: DispatcherDependency, + node2: DispatcherDependency, + ): void dispatch(payload: DispatcherPayload): Promise flushWaitQueue(): void isDispatching(): boolean @@ -65,19 +73,29 @@ export namespace DiscordModules { actionHandler: Record void>, storeDidChange: (e: DispatcherPayload) => boolean, ): string - setInterceptor(interceptor?: (payload: DispatcherPayload) => undefined | boolean): void + setInterceptor( + interceptor?: ( + payload: DispatcherPayload, + ) => undefined | boolean, + ): void /** * Subscribes to an action type * @param actionType The action type to subscribe to * @param callback The callback to call when the action is dispatched */ - subscribe(actionType: string, callback: (payload: DispatcherPayload) => void): void + subscribe( + actionType: string, + callback: (payload: DispatcherPayload) => void, + ): void /** * Unsubscribes from an action type * @param actionType The action type to unsubscribe from * @param callback The callback to remove */ - unsubscribe(actionType: string, callback: (payload: DispatcherPayload) => void): void + unsubscribe( + actionType: string, + callback: (payload: DispatcherPayload) => void, + ): void wait(cb: () => void): void } } @@ -88,7 +106,10 @@ export namespace DiscordModules { export interface AppStartPerformance { mark(...args: AppStartPerformance.MarkArgs): void - markAndLog(logger: InstanceType, ...args: AppStartPerformance.MarkArgs): void + markAndLog( + logger: InstanceType, + ...args: AppStartPerformance.MarkArgs + ): void [index: string]: unknown } @@ -132,7 +153,9 @@ export namespace DiscordModules { | 'eyebrow' export type TextStyleSheet = Record - export type CreateStylesFunction = >( + export type CreateStylesFunction = < + const S extends Record, + >( styles: S, ) => () => S } @@ -303,7 +326,8 @@ export namespace DiscordModules { label?: string } - export interface TextAreaProps extends Omit {} + export interface TextAreaProps + extends Omit {} export type TextInput = FC export type TextField = FC @@ -326,7 +350,8 @@ export namespace DiscordModules { export type ActionSheet = FC - export interface ActionSheetCloseButtonProps extends Pick, 'variant' | 'onPress'> {} + export interface ActionSheetCloseButtonProps + extends Pick, 'variant' | 'onPress'> {} export type ActionSheetCloseButton = FC @@ -374,7 +399,8 @@ export namespace DiscordModules { Icon: TableRowIcon } - export interface TableSwitchRowProps extends Omit { + export interface TableSwitchRowProps + extends Omit { accessibilityHint?: string value: boolean onValueChange(value: boolean): void @@ -496,7 +522,11 @@ export namespace DiscordModules { export interface SettingsListProps { ListHeaderComponent?: ComponentType - sections: Array<{ label?: string | ReactNode; settings: string[]; subLabel?: string | ReactNode }> + sections: Array<{ + label?: string | ReactNode + settings: string[] + subLabel?: string | ReactNode + }> } export type SettingsList = FC diff --git a/lib/discord/src/types/native.ts b/lib/discord/src/types/native.ts index 7c3ec45..203fbfc 100644 --- a/lib/discord/src/types/native.ts +++ b/lib/discord/src/types/native.ts @@ -42,7 +42,10 @@ export namespace DiscordNativeModules { * @param encoding The encoding to read the asset with * @returns */ - readAsset: (nameOrUri: string, encoding: 'base64' | 'utf8') => Promise + readAsset: ( + nameOrUri: string, + encoding: 'base64' | 'utf8', + ) => Promise /** * Allowed URI schemes on Android: `file://`, `content://` ([See here](https://developer.android.com/reference/android/content/ContentResolver#accepts-the-following-uri-schemes:_3)) */ @@ -52,7 +55,11 @@ export namespace DiscordNativeModules { * @param encoding Set to `base64` in order to encode response */ readFile(path: string, encoding: 'base64' | 'utf8'): Promise - saveFileToGallery?(uri: string, fileName: string, fileType: 'PNG' | 'JPEG'): Promise + saveFileToGallery?( + uri: string, + fileName: string, + fileType: 'PNG' | 'JPEG', + ): Promise /** * @param storageDir Either `cache` or `documents`. * @param path Path in `storageDir`, parents are recursively created. @@ -71,7 +78,10 @@ export namespace DiscordNativeModules { * @param storageDir Either `cache` or `documents` * @param path Path to the file to be removed */ - removeFile(storageDir: 'cache' | 'documents', path: string): Promise + removeFile( + storageDir: 'cache' | 'documents', + path: string, + ): Promise /** * Clear the folder from the path given * (!) On Android, this only clears all *files* and not subdirectories! @@ -79,7 +89,10 @@ export namespace DiscordNativeModules { * @param path Path to the folder to be cleared * @returns Whether the clearance succeeded */ - clearFolder(storageDir: 'cache' | 'documents', path: string): Promise + clearFolder( + storageDir: 'cache' | 'documents', + path: string, + ): Promise getConstants: () => { /** * The path the `documents` storage dir (see {@link writeFile}) represents. diff --git a/lib/externals/src/browserify.ts b/lib/externals/src/browserify.ts index fa639e3..98bd35a 100644 --- a/lib/externals/src/browserify.ts +++ b/lib/externals/src/browserify.ts @@ -1,11 +1,19 @@ -import { byDependencies, byProps, preferExports, relativeDep } from '@revenge-mod/modules/finders/filters' +import { + byDependencies, + byProps, + preferExports, + relativeDep, +} from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' import { proxify } from '@revenge-mod/utils/proxy' export let nodeUtil: typeof import('node:util') = proxify( () => { const [module] = lookupModule( - preferExports(byProps('inspect'), byDependencies([relativeDep(1), [], []])), + preferExports( + byProps('inspect'), + byDependencies([relativeDep(1), [], []]), + ), { includeUninitialized: true, }, diff --git a/lib/externals/src/react-native-clipboard.ts b/lib/externals/src/react-native-clipboard.ts index fa8a1d1..a36281d 100644 --- a/lib/externals/src/react-native-clipboard.ts +++ b/lib/externals/src/react-native-clipboard.ts @@ -1,43 +1,54 @@ -import { byDependencies, byProps, every, preferExports, relativeDep } from '@revenge-mod/modules/finders/filters' +import { + byDependencies, + byProps, + every, + preferExports, + relativeDep, +} from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' import { ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react' import { destructure, proxify } from '@revenge-mod/utils/proxy' -let ClipboardModule: typeof import('@react-native-clipboard/clipboard') = proxify( - () => { - // ID: 4790 +let ClipboardModule: typeof import('@react-native-clipboard/clipboard') = + proxify( + () => { + // ID: 4790 - // r6 = 4790; - // r5 = [4791, 4792]; + // r6 = 4790; + // r5 = [4791, 4792]; - // r6 = 4791; - // r5 = [175, 4792]; + // r6 = 4791; + // r5 = [175, 4792]; - // r6 = 4792; - // r5 = [27, 4793]; + // r6 = 4792; + // r5 = [27, 4793]; - const [module] = lookupModule( - preferExports( - byProps('useClipboard'), - every( - byDependencies([relativeDep(1), relativeDep(2)]), - byDependencies([ - [ReactModuleId, relativeDep(2, true)], - [ReactNativeModuleId, relativeDep(3, true)], - ]), + const [module] = lookupModule( + preferExports( + byProps('useClipboard'), + every( + byDependencies([relativeDep(1), relativeDep(2)]), + byDependencies([ + [ReactModuleId, relativeDep(2, true)], + [ReactNativeModuleId, relativeDep(3, true)], + ]), + ), ), - ), - { - includeUninitialized: true, - }, - ) + { + includeUninitialized: true, + }, + ) - if (module) return (ClipboardModule = module) - }, - { - hint: 'object', - }, -)! + if (module) return (ClipboardModule = module) + }, + { + hint: 'object', + }, + )! -export const { useClipboard } = destructure(ClipboardModule, { hint: 'function' }) -export const { default: Clipboard } = destructure(ClipboardModule, { hint: 'object' }) +export const { useClipboard } = destructure(ClipboardModule, { + hint: 'function', +}) +export const { default: Clipboard } = destructure(ClipboardModule, { + hint: 'object', +}) diff --git a/lib/externals/src/react-navigation.ts b/lib/externals/src/react-navigation.ts index 737584f..14521c6 100644 --- a/lib/externals/src/react-navigation.ts +++ b/lib/externals/src/react-navigation.ts @@ -1,47 +1,71 @@ -import { byDependencies, byName, byProps, looseDeps, preferExports } from '@revenge-mod/modules/finders/filters' +import { + byDependencies, + byName, + byProps, + looseDeps, + preferExports, +} from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' import { proxify } from '@revenge-mod/utils/proxy' const [, _createClassModuleId] = lookupModule(byName('_createClass')) const [, _classCallCheckModuleId] = lookupModule(byName('_classCallCheck')) -export let ReactNavigationNative: typeof import('@react-navigation/native') = proxify( - () => { - const [module] = lookupModule( - preferExports( - byProps('useLinkTo'), - byDependencies(looseDeps([[], looseDeps([[_createClassModuleId, _classCallCheckModuleId]])])), - ), - { - includeUninitialized: true, - }, - ) +export let ReactNavigationNative: typeof import('@react-navigation/native') = + proxify( + () => { + const [module] = lookupModule( + preferExports( + byProps('useLinkTo'), + byDependencies( + looseDeps([ + [], + looseDeps([ + [_createClassModuleId, _classCallCheckModuleId], + ]), + ]), + ), + ), + { + includeUninitialized: true, + }, + ) - if (module) return (ReactNavigationNative = module) - }, - { - hint: 'object', - }, -)! + if (module) return (ReactNavigationNative = module) + }, + { + hint: 'object', + }, + )! -export let ReactNavigationStack: typeof import('@react-navigation/stack') = proxify( - () => { - const [module] = lookupModule( - preferExports( - byProps('createStackNavigator'), - byDependencies(looseDeps([[], looseDeps([[_createClassModuleId, _classCallCheckModuleId]])])), - ), - { - includeUninitialized: true, - }, - ) +export let ReactNavigationStack: typeof import('@react-navigation/stack') = + proxify( + () => { + const [module] = lookupModule( + preferExports( + byProps( + 'createStackNavigator', + ), + byDependencies( + looseDeps([ + [], + looseDeps([ + [_createClassModuleId, _classCallCheckModuleId], + ]), + ]), + ), + ), + { + includeUninitialized: true, + }, + ) - if (module) return (ReactNavigationStack = module) - }, - { - hint: 'object', - }, -)! + if (module) return (ReactNavigationStack = module) + }, + { + hint: 'object', + }, + )! export interface ReactNavigationParamList { [Page: string]: any diff --git a/lib/externals/src/shopify.ts b/lib/externals/src/shopify.ts index ddc7523..9e067c4 100644 --- a/lib/externals/src/shopify.ts +++ b/lib/externals/src/shopify.ts @@ -1,9 +1,16 @@ -import { byDependencies, byProps, preferExports } from '@revenge-mod/modules/finders/filters' +import { + byDependencies, + byProps, + preferExports, +} from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' +import { + ReactJsxRuntimeModuleId, + ReactModuleId, + ReactNativeModuleId, +} from '@revenge-mod/react' import { proxify } from '@revenge-mod/utils/proxy' -import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react' - export let FlashList: typeof import('@shopify/flash-list') = proxify( () => { const [module] = lookupModule( diff --git a/lib/modules/src/finders/_internal.ts b/lib/modules/src/finders/_internal.ts index 3dbeaa2..369dc67 100644 --- a/lib/modules/src/finders/_internal.ts +++ b/lib/modules/src/finders/_internal.ts @@ -1,5 +1,4 @@ import { isModuleExportBad } from '../metro/utils' - import type { If } from '@revenge-mod/utils/types' import type { Metro } from '../types' import type { Filter } from './filters' @@ -13,7 +12,9 @@ export interface RunFilterOptions { skipDefault?: boolean } -export type RunFilterReturnExportsOptions = RunFilterOptions & +export type RunFilterReturnExportsOptions< + ReturnNamespace extends boolean = boolean, +> = RunFilterOptions & If< ReturnNamespace, { @@ -44,14 +45,18 @@ const FilterResultFlags = { Namespace: 3, } -export type FilterResultFlag = (typeof FilterResultFlags)[keyof typeof FilterResultFlags] +export type FilterResultFlag = + (typeof FilterResultFlags)[keyof typeof FilterResultFlags] // The reason this returns a flag is because flags are never falsy, while exports may be falsy when using ID-only filters (eg. `byDependencies`). // Currently, we only have options that are relevant for checking exports // If we add more options later on, do NOT forget about // adding them here, and passing them in the lookup* functions -export function runFilter(filter: Filter, id: Metro.ModuleID): FilterResultFlag | undefined +export function runFilter( + filter: Filter, + id: Metro.ModuleID, +): FilterResultFlag | undefined export function runFilter( filter: Filter, @@ -81,7 +86,11 @@ export function runFilter( } const defaultExport = exports.default - if (!options?.skipDefault && !isModuleExportBad(defaultExport) && filter(id, defaultExport)) { + if ( + !options?.skipDefault && + !isModuleExportBad(defaultExport) && + filter(id, defaultExport) + ) { // TODO(modules/finders/caches::default) return FilterResultFlags.Default } @@ -92,6 +101,7 @@ export function exportsFromFilterResultFlag( exports: Metro.ModuleExports, options?: RunFilterReturnExportsOptions, ) { - if (flag === FilterResultFlags.Default && !options?.returnNamespace) return exports.default + if (flag === FilterResultFlags.Default && !options?.returnNamespace) + return exports.default return exports } diff --git a/lib/modules/src/finders/filters.ts b/lib/modules/src/finders/filters.ts index 6326fa0..5bcef27 100644 --- a/lib/modules/src/finders/filters.ts +++ b/lib/modules/src/finders/filters.ts @@ -1,15 +1,22 @@ import { _inits } from '../metro/_internal' - -import { getModuleDependencies, initializedModuleHasBadExports, isModuleInitialized } from '../metro/utils' - +import { + getModuleDependencies, + initializedModuleHasBadExports, + isModuleInitialized, +} from '../metro/utils' import type { If, LogicalOr } from '@revenge-mod/utils/types' import type { Metro } from '../types' export type FilterResult = F extends Filter ? R : never -export type IsFilterWithExports = F extends Filter ? WE : never +export type IsFilterWithExports = F extends Filter + ? WE + : never -export interface Filter<_Inferable = any, WithExports extends boolean = boolean> { +export interface Filter< + _Inferable = any, + WithExports extends boolean = boolean, +> { ( ...args: If< WithExports, @@ -41,7 +48,11 @@ export interface Filter<_Inferable = any, WithExports extends boolean = boolean> * @see {@link byProps} for an example on custom-typed filters. */ export function createFilterGenerator( - filter: (args: A, id: Metro.ModuleID, exports: Metro.ModuleExports) => boolean, + filter: ( + args: A, + id: Metro.ModuleID, + exports: Metro.ModuleExports, + ) => boolean, keyFor: (args: A) => string, ): (...args: A) => Filter @@ -55,7 +66,8 @@ export function createFilterGenerator( keyFor: (args: A) => string, ): (...args: any[]) => Filter { return (...args: A) => { - const filter = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => f(args, id, exports) + const filter = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => + f(args, id, exports) filter.key = keyFor(args) return filter } @@ -94,7 +106,10 @@ export const byProps = createFilterGenerator>( props => `revenge.props(${props.join(',')})`, ) as ByProps -export type WithoutProps = >(prop: string, ...props: string[]) => Filter +export type WithoutProps = >( + prop: string, + ...props: string[] +) => Filter /** * Filter modules by their exports having none of the specified properties. @@ -112,7 +127,9 @@ export const withoutProps = createFilterGenerator>( props => `revenge.withoutProps(${props.join(',')})`, ) as WithoutProps -export type BySingleProp = >(prop: keyof T) => Filter +export type BySingleProp = >( + prop: keyof T, +) => Filter /** * Filter modules by their exports having only the specified property. @@ -127,11 +144,16 @@ export type BySingleProp = >(prop: keyof T) => Fil */ export const bySingleProp = createFilterGenerator>( // We don't use Reflect.ownKeys here because __esModule is not enumerable, and we don't want to include it in the check - ([prop], _, exports) => typeof exports === 'object' && Object.keys(exports).length === 1 && prop in exports, + ([prop], _, exports) => + typeof exports === 'object' && + Object.keys(exports).length === 1 && + prop in exports, ([prop]) => `revenge.singleProp(${prop})`, ) as BySingleProp -export type ByName = (name: string) => Filter +export type ByName = ( + name: string, +) => Filter /** * Filter modules by their exports having the specified name. @@ -174,11 +196,19 @@ export interface RelativeDependency { } export interface ComparableDependencyMap - extends Array { + extends Array< + | Metro.ModuleID + | RelativeDependency + | undefined + | ComparableDependencyMap + > { l?: boolean } -type ComputedComparableDependencyMap = Exclude> +type ComputedComparableDependencyMap = Exclude< + ComparableDependencyMap, + Array +> type ByDependencies = (deps: ComparableDependencyMap) => Filter @@ -229,22 +259,39 @@ export function looseDeps(deps: ComparableDependencyMap) { * @param id The dependency ID to mark as relative. * @param root Whether this dependency should be relatively to the root module ID. Useless for single-depth comparisons. */ -export function relativeDep(id: Metro.ModuleID, root?: boolean): RelativeDependency { +export function relativeDep( + id: Metro.ModuleID, + root?: boolean, +): RelativeDependency { const o = Object(id) as RelativeDependency if (root) o.r = true return o } -function compareDeps(rootOf: Metro.ModuleID, compare: ComparableDependencyMap, loose = false): boolean { +function compareDeps( + rootOf: Metro.ModuleID, + compare: ComparableDependencyMap, + loose = false, +): boolean { const stack: Array< - [of: Metro.ModuleID, deps: Metro.ModuleID[], compare: ComparableDependencyMap, loose?: boolean] + [ + of: Metro.ModuleID, + deps: Metro.ModuleID[], + compare: ComparableDependencyMap, + loose?: boolean, + ] > = [] stack.push([rootOf, getModuleDependencies(rootOf)!, compare, loose]) while (stack.length) { const [of, deps, compare, loose] = stack.pop()! - if (loose ? deps.length < compare.length : deps.length !== compare.length) return false + if ( + loose + ? deps.length < compare.length + : deps.length !== compare.length + ) + return false const ccmp: ComputedComparableDependencyMap = [] for (let i = 0; i < compare.length; i++) { @@ -252,7 +299,8 @@ function compareDeps(rootOf: Metro.ModuleID, compare: ComparableDependencyMap, l if (cmp === undefined) continue if (Array.isArray(cmp)) ccmp[i] = cmp - else if (typeof cmp === 'object') ccmp[i] = cmp.r ? rootOf + cmp.valueOf() : of + cmp.valueOf() + else if (typeof cmp === 'object') + ccmp[i] = cmp.r ? rootOf + cmp.valueOf() : of + cmp.valueOf() else ccmp[i] = cmp } @@ -280,7 +328,8 @@ function genDepsKey(deps: ComparableDependencyMap): string { else if (Array.isArray(dep)) { if (dep.l) key += '#' key += `[${genDepsKey(dep)}],` - } else key += `${(dep as RelativeDependency).r ? `r${dep.valueOf()}` : dep.valueOf()},` + } else + key += `${(dep as RelativeDependency).r ? `r${dep.valueOf()}` : dep.valueOf()},` return key.substring(0, key.length - 1) } @@ -289,14 +338,20 @@ export type Every = { ( f1: F1, f2: F2, - ): Filter & FilterResult, LogicalOr, IsFilterWithExports>> + ): Filter< + FilterResult & FilterResult, + LogicalOr, IsFilterWithExports> + > ( f1: F1, f2: F2, f3: F3, ): Filter< FilterResult & FilterResult & FilterResult, - LogicalOr, IsFilterWithExports>, IsFilterWithExports> + LogicalOr< + LogicalOr, IsFilterWithExports>, + IsFilterWithExports + > > (...filters: Filter[]): Filter } @@ -331,14 +386,19 @@ export type Some = { ( f1: F1, f2: F2, - ): Filter | FilterResult, IsFilterWithExports | IsFilterWithExports> + ): Filter< + FilterResult | FilterResult, + IsFilterWithExports | IsFilterWithExports + > ( f1: F1, f2: F2, f3: F3, ): Filter< FilterResult | FilterResult | FilterResult, - IsFilterWithExports | IsFilterWithExports | IsFilterWithExports + | IsFilterWithExports + | IsFilterWithExports + | IsFilterWithExports > (...filters: Filter[]): Filter } @@ -392,10 +452,13 @@ export type ModuleStateAware = ( * )) * ``` */ -export const moduleStateAware = createFilterGenerator>( +export const moduleStateAware = createFilterGenerator< + Parameters +>( ([initializedFilter, uninitializedFilter], id, exports) => { if (isModuleInitialized(id)) { - if (!initializedModuleHasBadExports(id)) return initializedFilter(id, exports) + if (!initializedModuleHasBadExports(id)) + return initializedFilter(id, exports) return false } diff --git a/lib/modules/src/finders/get.ts b/lib/modules/src/finders/get.ts index c3e9073..76bbb85 100644 --- a/lib/modules/src/finders/get.ts +++ b/lib/modules/src/finders/get.ts @@ -1,22 +1,24 @@ import { noopFalse } from '@revenge-mod/utils/callbacks' - -import { type LookupModulesOptions, lookupModule, lookupModuleByImportedPath } from './lookup' -import { type WaitForModulesOptions, waitForModuleByImportedPath, waitForModules } from './wait' - -import type { MaybeDefaultExportMatched } from '../types' -import type { Metro } from '../types' +import { lookupModule, lookupModuleByImportedPath } from './lookup' +import { waitForModuleByImportedPath, waitForModules } from './wait' +import type { MaybeDefaultExportMatched, Metro } from '../types' import type { RunFilterReturnExportsOptions } from './_internal' import type { Filter, FilterResult } from './filters' +import type { LookupModulesOptions } from './lookup' +import type { WaitForModulesOptions } from './wait' export type GetModuleOptions< ReturnNamespace extends boolean = boolean, IncludeUninitialized extends boolean = boolean, -> = WaitForModulesOptions & LookupModulesOptions +> = WaitForModulesOptions & + LookupModulesOptions export type GetModuleResult< F extends Filter, O extends GetModuleOptions, -> = O extends RunFilterReturnExportsOptions ? MaybeDefaultExportMatched> : FilterResult +> = O extends RunFilterReturnExportsOptions + ? MaybeDefaultExportMatched> + : FilterResult export type GetModuleCallback = (exports: T, id: Metro.ModuleID) => any @@ -48,11 +50,21 @@ export function getModule( ): GetModuleUnsubscribeFunction export function getModule< - F extends O extends GetModuleOptions ? Filter : Filter, + F extends O extends GetModuleOptions + ? Filter + : Filter, O extends GetModuleOptions, ->(filter: F, callback: GetModuleCallback>, options: O): GetModuleUnsubscribeFunction +>( + filter: F, + callback: GetModuleCallback>, + options: O, +): GetModuleUnsubscribeFunction -export function getModule(filter: Filter, callback: GetModuleCallback, options?: GetModuleOptions) { +export function getModule( + filter: Filter, + callback: GetModuleCallback, + options?: GetModuleOptions, +) { const [exports, id] = lookupModule(filter, options!) if (id != null) { callback(exports, id) @@ -85,7 +97,10 @@ export function getModule(filter: Filter, callback: GetModuleCallback, opti * }) * ``` */ -export function getModuleByImportedPath(path: string, callback: GetModuleCallback): GetModuleUnsubscribeFunction { +export function getModuleByImportedPath( + path: string, + callback: GetModuleCallback, +): GetModuleUnsubscribeFunction { const [exports, id] = lookupModuleByImportedPath(path) if (id != null) { callback(exports, id) diff --git a/lib/modules/src/finders/lookup.ts b/lib/modules/src/finders/lookup.ts index dcc5b98..7cd7e5a 100644 --- a/lib/modules/src/finders/lookup.ts +++ b/lib/modules/src/finders/lookup.ts @@ -1,19 +1,17 @@ -import { _inits, _metas, _paths, _uninits } from '../metro/_internal' -import { - type RunFilterOptions, - type RunFilterReturnExportsOptions, - exportsFromFilterResultFlag, - runFilter, -} from './_internal' - +import { _inits, _paths, _uninits } from '../metro/_internal' import { getInitializedModuleExports } from '../metro/utils' - +import { exportsFromFilterResultFlag, runFilter } from './_internal' import type { If } from '@revenge-mod/utils/types' -import type { MaybeDefaultExportMatched } from '../types' -import type { Metro } from '../types' +import type { MaybeDefaultExportMatched, Metro } from '../types' +import type { + RunFilterOptions, + RunFilterReturnExportsOptions, +} from './_internal' import type { Filter, FilterResult } from './filters' -export interface BaseLookupModulesOptions extends RunFilterOptions { +export interface BaseLookupModulesOptions< + IncludeUninitialized extends boolean = boolean, +> extends RunFilterOptions { /** * Whether to include initialized modules in the lookup. * @@ -35,9 +33,13 @@ export interface BaseLookupModulesOptions = RunFilterReturnExportsOptions & BaseLookupModulesOptions +> = RunFilterReturnExportsOptions & + BaseLookupModulesOptions -export type LookupModulesResult = [ +export type LookupModulesResult< + F extends Filter, + O extends LookupModulesOptions, +> = [ exports: O extends RunFilterReturnExportsOptions ? MaybeDefaultExportMatched> : FilterResult, @@ -46,7 +48,11 @@ export type LookupModulesResult = If, + IncludeAll extends If = If< + IncludeUninitialized, + false, + boolean + >, > = RunFilterOptions & ( | (BaseLookupModulesOptions & { @@ -82,10 +88,14 @@ export type LookupModuleIdsOptions< * for (const exports of lookup) console.log(exports) * ``` */ -export function lookupModules(filter: F): Generator, undefined> +export function lookupModules( + filter: F, +): Generator, undefined> export function lookupModules< - F extends O extends BaseLookupModulesOptions ? Filter : Filter, + F extends O extends BaseLookupModulesOptions + ? Filter + : Filter, O extends LookupModulesOptions, >(filter: F, options: O): Generator, undefined> @@ -94,7 +104,8 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) { for (const id of _inits) { const exports = getInitializedModuleExports(id) const flag = runFilter(filter, id, exports, options) - if (flag) yield [exportsFromFilterResultFlag(flag, exports, options), id] + if (flag) + yield [exportsFromFilterResultFlag(flag, exports, options), id] } if (options?.includeUninitialized) @@ -103,7 +114,11 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) { // Run the filter again to ensure we have the correct exports const exports = __r(id) const flag = runFilter(filter, id, exports, options) - if (flag) yield [exportsFromFilterResultFlag(flag, exports, options), id] + if (flag) + yield [ + exportsFromFilterResultFlag(flag, exports, options), + id, + ] else warnDeveloperAboutAPartialFilterMatch(id, filter.key) } } @@ -122,7 +137,9 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) { * const React = lookupModule(byProps('createElement')) * ``` */ -export function lookupModule(filter: F): LookupModulesResult | [] +export function lookupModule( + filter: F, +): LookupModulesResult | [] export function lookupModule( filter: F, @@ -134,7 +151,8 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) { for (const id of _inits) { const exports = getInitializedModuleExports(id) const flag = runFilter(filter, id, exports, options) - if (flag) return [exportsFromFilterResultFlag(flag, exports, options), id] + if (flag) + return [exportsFromFilterResultFlag(flag, exports, options), id] } if (options?.includeUninitialized) @@ -143,7 +161,11 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) { const exports = __r(id) // Run the filter again to ensure we have the correct exports const flag = runFilter(filter, id, exports, options) - if (flag) return [exportsFromFilterResultFlag(flag, exports, options), id] + if (flag) + return [ + exportsFromFilterResultFlag(flag, exports, options), + id, + ] warnDeveloperAboutAPartialFilterMatch(id, filter.key) } @@ -163,7 +185,9 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) { * const [{ default: Logger }] = lookupModuleByImportedPath<{ default: typeof DiscordModules.Logger }>('modules/debug/Logger.tsx') * ``` */ -export function lookupModuleByImportedPath(path: string): [exports: T, id: Metro.ModuleID] | [] { +export function lookupModuleByImportedPath( + path: string, +): [exports: T, id: Metro.ModuleID] | [] { const id = _paths.get(path) if (id == null) return [] return [getInitializedModuleExports(id), id] @@ -174,7 +198,10 @@ export function lookupModuleByImportedPath(path: string): [exports: T, * This will cause modules to be initialized unnecessarily, and may cause issues. * @internal */ -function warnDeveloperAboutAPartialFilterMatch(id: Metro.ModuleID, key: string) { +function warnDeveloperAboutAPartialFilterMatch( + id: Metro.ModuleID, + key: string, +) { console.warn( `[revenge.modules.finders.lookup] Module ${id} matched ${key} during uninitialized lookup, but did not match the full filter.`, ) diff --git a/lib/modules/src/finders/wait.ts b/lib/modules/src/finders/wait.ts index 92a651d..50343fe 100644 --- a/lib/modules/src/finders/wait.ts +++ b/lib/modules/src/finders/wait.ts @@ -1,12 +1,19 @@ -import { onAnyModuleInitialized, onModuleFinishedImporting } from '../metro/subscriptions' -import { getInitializedModuleExports, initializedModuleHasBadExports } from '../metro/utils' -import { type RunFilterReturnExportsOptions, exportsFromFilterResultFlag, runFilter } from './_internal' - -import type { MaybeDefaultExportMatched } from '../types' -import type { Metro } from '../types' +import { + onAnyModuleInitialized, + onModuleFinishedImporting, +} from '../metro/subscriptions' +import { + getInitializedModuleExports, + initializedModuleHasBadExports, +} from '../metro/utils' +import { exportsFromFilterResultFlag, runFilter } from './_internal' +import type { MaybeDefaultExportMatched, Metro } from '../types' +import type { RunFilterReturnExportsOptions } from './_internal' import type { Filter, FilterResult } from './filters' -export interface BaseWaitForModulesOptions { +export interface BaseWaitForModulesOptions< + IncludeAll extends boolean = boolean, +> { /** * Whether to include all modules, including ones with bad exports. * @@ -22,12 +29,15 @@ export type WaitForModulesCallback = (exports: T, id: Metro.ModuleID) => any export type WaitForModulesOptions< ReturnNamespace extends boolean = boolean, IncludeBadExports extends boolean = boolean, -> = RunFilterReturnExportsOptions & BaseWaitForModulesOptions +> = RunFilterReturnExportsOptions & + BaseWaitForModulesOptions export type WaitForModulesResult< F extends Filter, O extends WaitForModulesOptions, -> = O extends RunFilterReturnExportsOptions ? MaybeDefaultExportMatched> : FilterResult +> = O extends RunFilterReturnExportsOptions + ? MaybeDefaultExportMatched> + : FilterResult /** * Wait for modules to initialize. **Callback won't be called if the module is already initialized!** @@ -55,7 +65,9 @@ export function waitForModules( ): WaitForModulesUnsubscribeFunction export function waitForModules< - F extends O extends WaitForModulesOptions ? Filter : Filter, + F extends O extends WaitForModulesOptions + ? Filter + : Filter, O extends WaitForModulesOptions, >( filter: F, @@ -63,17 +75,29 @@ export function waitForModules< options: O, ): WaitForModulesUnsubscribeFunction -export function waitForModules(filter: Filter, callback: WaitForModulesCallback, options?: WaitForModulesOptions) { +export function waitForModules( + filter: Filter, + callback: WaitForModulesCallback, + options?: WaitForModulesOptions, +) { return onAnyModuleInitialized( options?.includeAll ? (id, exports) => { const flag = runFilter(filter, id, exports, options) - if (flag) callback(exportsFromFilterResultFlag(flag, exports, options), id) + if (flag) + callback( + exportsFromFilterResultFlag(flag, exports, options), + id, + ) } : (id, exports) => { if (initializedModuleHasBadExports(id)) return const flag = runFilter(filter, id, exports, options) - if (flag) callback(exportsFromFilterResultFlag(flag, exports, options), id) + if (flag) + callback( + exportsFromFilterResultFlag(flag, exports, options), + id, + ) }, ) } diff --git a/lib/modules/src/metro/_internal.ts b/lib/modules/src/metro/_internal.ts index 97b6b72..80783fc 100644 --- a/lib/modules/src/metro/_internal.ts +++ b/lib/modules/src/metro/_internal.ts @@ -1,6 +1,5 @@ import { _execInitSubs, _execReqSubs } from './subscriptions/_internal' import { isModuleExportsBad } from './utils' - import type { Metro } from '../types' /** Initializing ID */ @@ -19,7 +18,12 @@ export const _metas = new Map< export function patchMetroDefine(metroDefine: Metro.DefineFn) { return ((origFactory, id, deps) => { // deps won't be undefined last time I checked - const metadata = [deps!, false] as typeof _metas extends Map ? V : never + const metadata = [deps!, false] as typeof _metas extends Map< + any, + infer V + > + ? V + : never _metas.set(id, metadata) _uninits.add(id) @@ -33,7 +37,15 @@ export function patchMetroDefine(metroDefine: Metro.DefineFn) { _execReqSubs(id) try { - origFactory(global, req, importDefault, importAll, module, exports, deps) + origFactory( + global, + req, + importDefault, + importAll, + module, + exports, + deps, + ) metadata[1] = true // Add the module to the initialized set only if the factory doesn't error or the exports aren't bad diff --git a/lib/modules/src/metro/patches.ts b/lib/modules/src/metro/patches.ts index d4d03ad..d4b44c2 100644 --- a/lib/modules/src/metro/patches.ts +++ b/lib/modules/src/metro/patches.ts @@ -1,9 +1,7 @@ -import { _initing, _paths } from './_internal' - -import { _execPathSubs } from './subscriptions/_internal' - import { byProps } from '../finders/filters' import { waitForModules } from '../finders/wait' +import { _initing, _paths } from './_internal' +import { _execPathSubs } from './subscriptions/_internal' const unsubFFI = waitForModules(byProps('fileFinishedImporting'), exports => { unsubFFI() diff --git a/lib/modules/src/metro/subscriptions/_internal.ts b/lib/modules/src/metro/subscriptions/_internal.ts index 1c0ca7a..af3b7be 100644 --- a/lib/modules/src/metro/subscriptions/_internal.ts +++ b/lib/modules/src/metro/subscriptions/_internal.ts @@ -1,5 +1,9 @@ -import type { ModuleFinishedImportingCallback, ModuleFirstRequiredCallback, ModuleInitializedCallback } from '.' import type { Metro } from '../../types' +import type { + ModuleFinishedImportingCallback, + ModuleFirstRequiredCallback, + ModuleInitializedCallback, +} from '.' export const _reqAll = new Set() export const _req = new Map>() @@ -15,7 +19,10 @@ export function _execReqSubs(id: Metro.ModuleID) { } } -export function _execInitSubs(id: Metro.ModuleID, exports: Metro.ModuleExports) { +export function _execInitSubs( + id: Metro.ModuleID, + exports: Metro.ModuleExports, +) { for (const cb of _initAll) cb(id, exports) if (_init.has(id)) { for (const cb of _init.get(id)!) cb(id, exports) diff --git a/lib/modules/src/metro/subscriptions/index.ts b/lib/modules/src/metro/subscriptions/index.ts index 079d0f2..8eb604e 100644 --- a/lib/modules/src/metro/subscriptions/index.ts +++ b/lib/modules/src/metro/subscriptions/index.ts @@ -1,11 +1,15 @@ import { _init, _initAll, _path, _req, _reqAll } from './_internal' - import type { Metro } from '../../types' -import type { initializedModuleHasBadExports } from '../utils' export type ModuleFirstRequiredCallback = (id: Metro.ModuleID) => void -export type ModuleInitializedCallback = (id: Metro.ModuleID, exports: Metro.ModuleExports) => void -export type ModuleFinishedImportingCallback = (id: Metro.ModuleID, path: string) => void +export type ModuleInitializedCallback = ( + id: Metro.ModuleID, + exports: Metro.ModuleExports, +) => void +export type ModuleFinishedImportingCallback = ( + id: Metro.ModuleID, + path: string, +) => void /** * Registers a callback to be called when any module is initialized. @@ -35,7 +39,10 @@ export function onAnyModuleInitialized(callback: ModuleInitializedCallback) { * @param callback The callback to be called. * @returns A function that unregisters the callback. */ -export function onModuleInitialized(id: Metro.ModuleID, callback: ModuleInitializedCallback) { +export function onModuleInitialized( + id: Metro.ModuleID, + callback: ModuleInitializedCallback, +) { let set = _init.get(id) if (!set) { set = new Set() @@ -54,7 +61,9 @@ export function onModuleInitialized(id: Metro.ModuleID, callback: ModuleInitiali * @param callback The callback to be called. * @returns A function that unregisters the callback. */ -export function onModuleFinishedImporting(callback: ModuleFinishedImportingCallback) { +export function onModuleFinishedImporting( + callback: ModuleFinishedImportingCallback, +) { _path.add(callback) return () => _path.delete(callback) } @@ -69,7 +78,9 @@ export function onModuleFinishedImporting(callback: ModuleFinishedImportingCallb * @param callback The callback to be called. * @returns A function that unregisters the callback. */ -export function onAnyModuleFirstRequired(callback: ModuleFirstRequiredCallback) { +export function onAnyModuleFirstRequired( + callback: ModuleFirstRequiredCallback, +) { _reqAll.add(callback) return () => _reqAll.delete(callback) } @@ -85,7 +96,10 @@ export function onAnyModuleFirstRequired(callback: ModuleFirstRequiredCallback) * @param callback The callback to be called. * @returns A function that unregisters the callback. */ -export function onModuleFirstRequired(id: Metro.ModuleID, callback: ModuleFirstRequiredCallback) { +export function onModuleFirstRequired( + id: Metro.ModuleID, + callback: ModuleFirstRequiredCallback, +) { let set = _req.get(id) if (!set) { set = new Set() diff --git a/lib/modules/src/metro/utils.ts b/lib/modules/src/metro/utils.ts index e5efd98..2b3683f 100644 --- a/lib/modules/src/metro/utils.ts +++ b/lib/modules/src/metro/utils.ts @@ -1,6 +1,5 @@ import { isProxy } from '@revenge-mod/utils/proxy' import { _inits, _metas, _uninits } from './_internal' - import type { Metro } from '../types' /** @@ -29,7 +28,9 @@ export function initializedModuleHasBadExports(id: Metro.ModuleID): boolean { * Returns the dependencies of a module. * @param id The module ID. */ -export function getModuleDependencies(id: Metro.ModuleID): Metro.DependencyMap | undefined { +export function getModuleDependencies( + id: Metro.ModuleID, +): Metro.DependencyMap | undefined { return _metas.get(id)?.[0] } @@ -45,7 +46,9 @@ export function isModuleInitialized(id: Metro.ModuleID): boolean { * Returns the exports of an initialized module. * @param id The module ID. */ -export function getInitializedModuleExports(id: Metro.ModuleID): Metro.ModuleExports | undefined { +export function getInitializedModuleExports( + id: Metro.ModuleID, +): Metro.ModuleExports | undefined { return _metas.get(id)?.[2]?.exports } @@ -53,7 +56,9 @@ export function getInitializedModuleExports(id: Metro.ModuleID): Metro.ModuleExp * Returns whether a particular module export is bad. This is used for filter functions to check whether an export is filterable. * @param exp The export to check. */ -export function isModuleExportBad(exp: Metro.ModuleExports[PropertyKey]): boolean { +export function isModuleExportBad( + exp: Metro.ModuleExports[PropertyKey], +): boolean { return ( // Nullish? exp == null || @@ -78,7 +83,8 @@ export function isModuleExportsBad(exports: Metro.ModuleExports): boolean { // - String, Boolean, Symbol, BigInt exports are not useful (who would do `module.exports = ...`?) !(typeof exports === 'object' || typeof exports === 'function') || // Checking if the object is empty - (exports.__proto__ === Object.prototype && !Reflect.ownKeys(exports).length) || + (exports.__proto__ === Object.prototype && + !Reflect.ownKeys(exports).length) || // Can't run isProxy() on this because this isn't your typical proxy: // https://github.com/facebook/react-native/blob/master/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp exports === nativeModuleProxy diff --git a/lib/modules/src/types.ts b/lib/modules/src/types.ts index 14a2a1d..7b102d3 100644 --- a/lib/modules/src/types.ts +++ b/lib/modules/src/types.ts @@ -55,7 +55,11 @@ export namespace Metro { export type RequireFn = (id: ModuleID) => ModuleExports - export type DefineFn = (factory: FactoryFn, moduleId: ModuleID, dependencyMap?: DependencyMap | undefined) => void + export type DefineFn = ( + factory: FactoryFn, + moduleId: ModuleID, + dependencyMap?: DependencyMap | undefined, + ) => void export type ModuleDefiner = (moduleId: ModuleID) => void diff --git a/lib/patcher/src/hooks/after.ts b/lib/patcher/src/hooks/after.ts index 56338a6..0e8c786 100644 --- a/lib/patcher/src/hooks/after.ts +++ b/lib/patcher/src/hooks/after.ts @@ -1,11 +1,9 @@ import { createPatchedFunctionProxy, - type HookNode, - type PatchedFunctionProxyState, patchedFunctionProxyStates, unproxy, } from '../_internal' - +import type { HookNode, PatchedFunctionProxyState } from '../_internal' import type { AfterHook, BeforeHook, diff --git a/lib/patcher/src/hooks/before.ts b/lib/patcher/src/hooks/before.ts index 5e5525f..d144ea2 100644 --- a/lib/patcher/src/hooks/before.ts +++ b/lib/patcher/src/hooks/before.ts @@ -1,11 +1,9 @@ import { createPatchedFunctionProxy, - type HookNode, - type PatchedFunctionProxyState, patchedFunctionProxyStates, unproxy, } from '../_internal' - +import type { HookNode, PatchedFunctionProxyState } from '../_internal' import type { BeforeHook, FiniteDomain, UnknownFunction } from '../types' function unpatchBefore( diff --git a/lib/patcher/src/hooks/instead.ts b/lib/patcher/src/hooks/instead.ts index 36bdc4c..71b4ee5 100644 --- a/lib/patcher/src/hooks/instead.ts +++ b/lib/patcher/src/hooks/instead.ts @@ -1,13 +1,14 @@ import { createPatchedFunctionProxy, - type FunctionProxyState, - type InsteadHookNode, - type PatchedFunctionProxyState, patchedFunctionProxyHandler, patchedFunctionProxyStates, unproxy, } from '../_internal' - +import type { + FunctionProxyState, + InsteadHookNode, + PatchedFunctionProxyState, +} from '../_internal' import type { AbstractNewable, Callable, diff --git a/lib/plugins/src/_internal.ts b/lib/plugins/src/_internal.ts index a5c5dd9..e430800 100644 --- a/lib/plugins/src/_internal.ts +++ b/lib/plugins/src/_internal.ts @@ -1,11 +1,13 @@ -import { getStorage, type StorageOptions } from '@revenge-mod/storage' +import { getStorage } from '@revenge-mod/storage' import { defineLazyProperty } from '@revenge-mod/utils/objects' import { allSettled, sleepReject } from '@revenge-mod/utils/promises' - import { _uapi as uapi } from './apis' - -import { PluginFlags as Flag, PluginsStorageDirectory, PluginStatus as Status } from './constants' - +import { + PluginFlags as Flag, + PluginsStorageDirectory, + PluginStatus as Status, +} from './constants' +import type { StorageOptions } from '@revenge-mod/storage' import type { AnyObject } from '@revenge-mod/utils/types' import type { InitPluginApi, @@ -19,9 +21,15 @@ import type { export const _uapi = uapi -export const _preInitExts: Array<(api: PreInitPluginApi, plugin: InternalPlugin) => void> = [] -export const _initExts: Array<(api: InitPluginApi, plugin: InternalPlugin) => void> = [] -export const _startExts: Array<(api: PluginApi, plugin: InternalPlugin) => void> = [] +export const _preInitExts: Array< + (api: PreInitPluginApi, plugin: InternalPlugin) => void +> = [] +export const _initExts: Array< + (api: InitPluginApi, plugin: InternalPlugin) => void +> = [] +export const _startExts: Array< + (api: PluginApi, plugin: InternalPlugin) => void +> = [] export const _plugins = new Map() export const _metas = new Map< @@ -41,7 +49,8 @@ export function registerPlugin( iflags: number, ) { // TODO(plugins): verify plugin manifest - if (_plugins.has(manifest.id)) throw new Error(`Plugin with ID "${manifest.id}" already registered`) + if (_plugins.has(manifest.id)) + throw new Error(`Plugin with ID "${manifest.id}" already registered`) const plugin: InternalPlugin = { _c: [], @@ -95,17 +104,19 @@ function preparePluginPreInit(plugin: InternalPlugin) { meta[3] = PluginApiLevel.PreInit } -function preparePluginInit(plugin: InternalPlugin, storageOptions?: StorageOptions) { +function preparePluginInit( + plugin: InternalPlugin, + storageOptions?: StorageOptions, +) { const meta = _metas.get(plugin.manifest.id)! const api = meta[0] as InitPluginApi - defineLazyProperty(api, 'storage', () => getStorage( - `${PluginsStorageDirectory}/${plugin.manifest.id}.json`, - { + defineLazyProperty(api, 'storage', () => + getStorage(`${PluginsStorageDirectory}/${plugin.manifest.id}.json`, { ...storageOptions, directory: 'documents', - }, - )) + }), + ) for (const ext of _initExts) ext(api, plugin) @@ -126,10 +137,13 @@ function preparePluginStart(plugin: InternalPlugin) { async function disablePlugin(plugin: InternalPlugin) { const iflags = _metas.get(plugin.manifest.id)![2] ?? 0 if (iflags & InternalPluginFlags.Essential) - throw new Error(`Plugin "${plugin.manifest.id}" is essential and cannot be disabled`) + throw new Error( + `Plugin "${plugin.manifest.id}" is essential and cannot be disabled`, + ) // If plugin is not stopped, and is also not stopping, we need to stop it - if (plugin.status && !(plugin.status & Status.Stopping)) await stopPlugin(plugin) + if (plugin.status && !(plugin.status & Status.Stopping)) + await stopPlugin(plugin) // TODO(plugins): write to storage plugin.flags &= ~Flag.Enabled @@ -153,9 +167,12 @@ export async function preInitPlugin(plugin: InternalPlugin) { preparePluginPreInit(plugin) - if (!(plugin.flags & Flag.Enabled)) throw new Error(`Plugin "${id}" is not enabled`) + if (!(plugin.flags & Flag.Enabled)) + throw new Error(`Plugin "${id}" is not enabled`) if (plugin.status & (Status.PreIniting | Status.PreInited)) - throw new Error(`Plugin preInit lifecycle for "${id}" is already running`) + throw new Error( + `Plugin preInit lifecycle for "${id}" is already running`, + ) plugin.status |= Status.PreIniting @@ -182,7 +199,8 @@ export async function initPlugin(plugin: InternalPlugin) { const meta = _metas.get(id)! const [, promises, , apiLevel] = meta - if (!(plugin.flags & Flag.Enabled)) throw new Error(`Plugin "${id}" is not enabled`) + if (!(plugin.flags & Flag.Enabled)) + throw new Error(`Plugin "${id}" is not enabled`) if (plugin.status & (Status.Initing | Status.Inited)) throw new Error(`Plugin init lifecycle for "${id}" is already running`) @@ -212,7 +230,8 @@ export async function startPlugin(plugin: InternalPlugin) { const meta = _metas.get(id)! const [, promises, , apiLevel] = meta - if (!(plugin.flags & Flag.Enabled)) throw new Error(`Plugin "${id}" is not enabled`) + if (!(plugin.flags & Flag.Enabled)) + throw new Error(`Plugin "${id}" is not enabled`) if (plugin.status & (Status.Starting | Status.Started)) throw new Error(`Plugin start lifecycle for "${id}" is already running`) @@ -245,24 +264,32 @@ export async function stopPlugin(plugin: InternalPlugin) { const meta = _metas.get(id)! const [, promises, iflags, apiLevel] = meta - if (iflags & InternalPluginFlags.Essential) throw new Error(`Plugin "${id}" is essential and cannot be stopped`) + if (iflags & InternalPluginFlags.Essential) + throw new Error(`Plugin "${id}" is essential and cannot be stopped`) - if (!(plugin.flags & Flag.Enabled)) throw new Error(`Plugin "${id}" is not enabled`) - if (plugin.status & Status.Stopping) throw new Error(`Plugin "${id}" is stopping`) + if (!(plugin.flags & Flag.Enabled)) + throw new Error(`Plugin "${id}" is not enabled`) + if (plugin.status & Status.Stopping) + throw new Error(`Plugin "${id}" is stopping`) // If the plugin is running its lifecycles, we need to wait for it to finish, then we'll stop it // We want to wait at max 5 seconds for the lifecycles to finish if (plugin.status & (Status.PreIniting | Status.Initing | Status.Starting)) await Promise.race([ Promise.all(promises), - sleepReject(MaxWaitTime, 'Plugin lifecycles timed out, force stopping'), + sleepReject( + MaxWaitTime, + 'Plugin lifecycles timed out, force stopping', + ), ]) .then(finished => { // If the lifecycles don't finish in 5 seconds, a reload is probably required to unapply the changes if (!finished) plugin.flags |= Flag.ReloadRequired }) .catch(e => handlePluginError(e, plugin)) - else if (!(plugin.status & (Status.PreInited | Status.Inited | Status.Started))) + else if ( + !(plugin.status & (Status.PreInited | Status.Inited | Status.Started)) + ) throw new Error(`Plugin "${id}" is not running`) if (apiLevel < PluginApiLevel.PreInit) preparePluginPreInit(plugin) @@ -275,7 +302,10 @@ export async function stopPlugin(plugin: InternalPlugin) { if (lifecycles.stop) await Promise.race([ lifecycles.stop(meta[0] as PluginApi), - sleepReject(MaxWaitTime, 'Plugin stop lifecycle timed out, force stopping'), + sleepReject( + MaxWaitTime, + 'Plugin stop lifecycle timed out, force stopping', + ), ]) } catch (e) { await handlePluginError(e, plugin) diff --git a/lib/plugins/src/apis/externals.ts b/lib/plugins/src/apis/externals.ts index 7aedec5..379a1d3 100644 --- a/lib/plugins/src/apis/externals.ts +++ b/lib/plugins/src/apis/externals.ts @@ -10,9 +10,15 @@ export interface PluginApiExternals { export const externals = {} as PluginApiExternals // TODO: Rolldown issue: Bug requires us to do { ...require('...') } instead of just require('...') -defineLazyProperty(externals, 'Browserify', () => ({ ...require('@revenge-mod/externals/browserify') })) +defineLazyProperty(externals, 'Browserify', () => ({ + ...require('@revenge-mod/externals/browserify'), +})) defineLazyProperty(externals, 'ReactNativeClipboard', () => ({ ...require('@revenge-mod/externals/react-native-clipboard'), })) -defineLazyProperty(externals, 'ReactNavigation', () => ({ ...require('@revenge-mod/externals/react-navigation') })) -defineLazyProperty(externals, 'Shopify', () => ({ ...require('@revenge-mod/externals/shopify') })) +defineLazyProperty(externals, 'ReactNavigation', () => ({ + ...require('@revenge-mod/externals/react-navigation'), +})) +defineLazyProperty(externals, 'Shopify', () => ({ + ...require('@revenge-mod/externals/shopify'), +})) diff --git a/lib/plugins/src/apis/index.ts b/lib/plugins/src/apis/index.ts index 49c58f0..cfe7650 100644 --- a/lib/plugins/src/apis/index.ts +++ b/lib/plugins/src/apis/index.ts @@ -1,7 +1,14 @@ import * as PatcherLibrary from '@revenge-mod/patcher' -import type { UnscopedInitPluginApi, UnscopedPluginApi, UnscopedPreInitPluginApi } from '../types' +import type { + UnscopedInitPluginApi, + UnscopedPluginApi, + UnscopedPreInitPluginApi, +} from '../types' -export const _uapi: UnscopedPreInitPluginApi | UnscopedInitPluginApi | UnscopedPluginApi = { +export const _uapi: + | UnscopedPreInitPluginApi + | UnscopedInitPluginApi + | UnscopedPluginApi = { modules: require('./modules').modules, plugins: require('./plugins').plugins, patcher: PatcherLibrary, diff --git a/lib/plugins/src/apis/modules.ts b/lib/plugins/src/apis/modules.ts index 015edc9..3ad1945 100644 --- a/lib/plugins/src/apis/modules.ts +++ b/lib/plugins/src/apis/modules.ts @@ -4,7 +4,8 @@ export interface PluginApiModules { native: PluginApiModulesNative } -export type PluginApiModulesNative = typeof import('@revenge-mod/modules/native') +export type PluginApiModulesNative = + typeof import('@revenge-mod/modules/native') export type PluginApiModulesMetro = // biome-ignore format: Don't diff --git a/lib/plugins/src/init.ts b/lib/plugins/src/init.ts index c7a38d6..25c57e1 100644 --- a/lib/plugins/src/init.ts +++ b/lib/plugins/src/init.ts @@ -1,14 +1,10 @@ -import { onRunApplication } from '@revenge-mod/react/native' - -import { _uapi } from './apis' - import * as AssetsLibrary from '@revenge-mod/assets' +import { onRunApplication } from '@revenge-mod/react/native' +import { _plugins, initPlugin, startPlugin } from './_internal' +import { _uapi } from './apis' import { externals } from './apis/externals' import { react } from './apis/react' - -import { _plugins, initPlugin, startPlugin } from './_internal' import { PluginFlags } from './constants' - import type { UnscopedInitPluginApi } from './types' // Setup init plugin APIs @@ -17,7 +13,8 @@ uapi.assets = AssetsLibrary uapi.externals = externals uapi.react = react -for (const plugin of _plugins.values()) if (plugin.flags & PluginFlags.Enabled) initPlugin(plugin) +for (const plugin of _plugins.values()) + if (plugin.flags & PluginFlags.Enabled) initPlugin(plugin) const unsub = onRunApplication(() => { unsub() @@ -26,5 +23,6 @@ const unsub = onRunApplication(() => { // const UILibrary = require('@revenge-mod/ui') // uapi.ui = UiLibrary - for (const plugin of _plugins.values()) if (plugin.flags & PluginFlags.Enabled) startPlugin(plugin) + for (const plugin of _plugins.values()) + if (plugin.flags & PluginFlags.Enabled) startPlugin(plugin) }) diff --git a/lib/plugins/src/preinit.ts b/lib/plugins/src/preinit.ts index 3d6654a..0cad370 100644 --- a/lib/plugins/src/preinit.ts +++ b/lib/plugins/src/preinit.ts @@ -1,4 +1,5 @@ import { _plugins, preInitPlugin } from './_internal' import { PluginFlags } from './constants' -for (const plugin of _plugins.values()) if (plugin.flags & PluginFlags.Enabled) preInitPlugin(plugin) +for (const plugin of _plugins.values()) + if (plugin.flags & PluginFlags.Enabled) preInitPlugin(plugin) diff --git a/lib/plugins/src/types.ts b/lib/plugins/src/types.ts index 1626dad..878df98 100644 --- a/lib/plugins/src/types.ts +++ b/lib/plugins/src/types.ts @@ -1,12 +1,10 @@ -import type { PluginFlags, PluginStatus } from './constants' - import type { Storage, StorageOptions } from '@revenge-mod/storage' import type { AnyObject } from '@revenge-mod/utils/types' - import type { PluginApiExternals } from './apis/externals' import type { PluginApiModules } from './apis/modules' import type { PluginApiPlugins } from './apis/plugins' import type { PluginApiReact } from './apis/react' +import type { PluginFlags, PluginStatus } from './constants' /** * The unscoped plugin API (very limited). This API is available as a global for plugins. @@ -54,7 +52,8 @@ export interface PreInitPluginApi { * The plugin API (limited). * Available in the `init` phase. */ -export interface InitPluginApi extends PreInitPluginApi { +export interface InitPluginApi + extends PreInitPluginApi { unscoped: UnscopedInitPluginApi /** * The plugin storage. @@ -71,7 +70,8 @@ export interface InitPluginApi extends PreInitP * The plugin API. * Available in the `start` and `stop` phase. */ -export interface PluginApi extends InitPluginApi { +export interface PluginApi + extends InitPluginApi { unscoped: UnscopedPluginApi } @@ -114,7 +114,8 @@ export interface PluginManifest { icon?: string } -export interface PluginOptions extends PluginLifecycles { +export interface PluginOptions + extends PluginLifecycles { storage?: Omit, 'directory'> } diff --git a/lib/react/src/index.ts b/lib/react/src/index.ts index b303e98..c3d96de 100644 --- a/lib/react/src/index.ts +++ b/lib/react/src/index.ts @@ -1,6 +1,5 @@ import { byProps } from '@revenge-mod/modules/finders/filters' import { waitForModules } from '@revenge-mod/modules/finders/wait' - import type { Metro } from '@revenge-mod/modules/types' export let ReactModuleId: Metro.ModuleID @@ -13,25 +12,34 @@ export let ReactJsxRuntime: typeof import('react/jsx-runtime') let RtCount = 0 -const unsubRt = waitForModules(byProps('useState'), (exports, id) => { - if (RtCount++ === 2) return unsubRt() +const unsubRt = waitForModules( + byProps('useState'), + (exports, id) => { + if (RtCount++ === 2) return unsubRt() - ReactModuleId = id - React = exports -}) + ReactModuleId = id + React = exports + }, +) -const unsubRN = waitForModules(byProps('AppRegistry'), (exports, id) => { - unsubRN() +const unsubRN = waitForModules( + byProps('AppRegistry'), + (exports, id) => { + unsubRN() - ReactNativeModuleId = id - ReactNative = exports -}) + ReactNativeModuleId = id + ReactNative = exports + }, +) let RJsxRCount = 0 -const unsubRJsxR = waitForModules(byProps('jsxs'), (exports, id) => { - if (RJsxRCount++ === 2) return unsubRJsxR() +const unsubRJsxR = waitForModules( + byProps('jsxs'), + (exports, id) => { + if (RJsxRCount++ === 2) return unsubRJsxR() - ReactJsxRuntimeModuleId = id - ReactJsxRuntime = exports -}) + ReactJsxRuntimeModuleId = id + ReactJsxRuntime = exports + }, +) diff --git a/lib/react/src/native/index.ts b/lib/react/src/native/index.ts index e219487..4951b8d 100644 --- a/lib/react/src/native/index.ts +++ b/lib/react/src/native/index.ts @@ -1,7 +1,5 @@ import { _ara, _bra } from './patches' -import type { AppRegistry } from 'react-native' - /** * Registers a callback to be run when a call to {@link AppRegistry.runApplication} is made. * diff --git a/lib/react/src/native/patches.ts b/lib/react/src/native/patches.ts index fe3786e..6242559 100644 --- a/lib/react/src/native/patches.ts +++ b/lib/react/src/native/patches.ts @@ -1,9 +1,7 @@ -import { after, before } from '@revenge-mod/patcher' -import { ReactNative } from '..' - import { byProps } from '@revenge-mod/modules/finders/filters' import { waitForModules } from '@revenge-mod/modules/finders/wait' - +import { after, before } from '@revenge-mod/patcher' +import { ReactNative } from '..' import type { RunApplicationCallback } from '.' export const _bra = new Set() diff --git a/lib/storage/src/index.ts b/lib/storage/src/index.ts index b0763ce..bc5e59a 100644 --- a/lib/storage/src/index.ts +++ b/lib/storage/src/index.ts @@ -4,7 +4,6 @@ import { FileModule } from '@revenge-mod/discord/native' import { React } from '@revenge-mod/react' import { mergeDeep } from '@revenge-mod/utils/objects' import { useReRender } from '@revenge-mod/utils/react' - import type { AnyObject, DeepPartial } from '@revenge-mod/utils/types' /** @@ -13,7 +12,10 @@ import type { AnyObject, DeepPartial } from '@revenge-mod/utils/types' * @param path Path relative to the directory. * @param directory Directory to use. Can be either 'cache' or 'documents'. */ -export function getStorage(path: string, options?: StorageOptions): Storage { +export function getStorage( + path: string, + options?: StorageOptions, +): Storage { const { CacheDirPath, DocumentsDirPath } = FileModule.getConstants() const directory = options?.directory ?? 'documents' @@ -71,7 +73,12 @@ export function getStorage(path: string, option for (const sub of subs) sub(cache) return cache } catch (e) { - console.error('Failed to parse storage file (most likely corrupted)', directory, path, e) + console.error( + 'Failed to parse storage file (most likely corrupted)', + directory, + path, + e, + ) } } }, @@ -85,7 +92,12 @@ export function getStorage(path: string, option for (const sub of subs) sub(value) } catch (e) { - console.error('Failed to write storage file', directory, path, e) + console.error( + 'Failed to write storage file', + directory, + path, + e, + ) } }, } @@ -110,7 +122,9 @@ export interface StorageOptions { load?: boolean } -export type UseStorageFilter = (newValue: DeepPartial) => any +export type UseStorageFilter = ( + newValue: DeepPartial, +) => any export interface Storage { /** diff --git a/lib/types/types.d.ts b/lib/types/types.d.ts index 9d497e5..5f776fc 100644 --- a/lib/types/types.d.ts +++ b/lib/types/types.d.ts @@ -5,7 +5,10 @@ import type { Metro } from '@revenge-mod/modules/types' /// HERMES declare global { - function setTimeout(cb: (...args: unknown[]) => unknown, timeout?: number): number + function setTimeout( + cb: (...args: unknown[]) => unknown, + timeout?: number, + ): number /** * Calls the garbage collector */ @@ -28,13 +31,17 @@ declare global { /// HERMES PROMISES declare global { + // biome-ignore lint/correctness/noUnusedVariables: Type parameter names must match interface Promise { /// PROMISE POLYFILLS FROM: https://github.com/then/promise /// AND: https://github.com/facebook/hermes/blob/main/lib/InternalBytecode/01-Promise.js _h: 0 | 1 | 2 } - type HermesPromiseRejectionHandler = (promise: Promise, error: any) => void + type HermesPromiseRejectionHandler = ( + promise: Promise, + error: any, + ) => void interface PromiseConstructor { _m: HermesPromiseRejectionHandler diff --git a/lib/utils/src/callbacks.ts b/lib/utils/src/callbacks.ts index 09dddfa..0533900 100644 --- a/lib/utils/src/callbacks.ts +++ b/lib/utils/src/callbacks.ts @@ -1,4 +1,7 @@ -export function debounce any>(func: F, timeout: number) { +export function debounce any>( + func: F, + timeout: number, +) { let timer: Parameters[0] return (...args: Parameters) => new Promise(rs => { diff --git a/lib/utils/src/discord.ts b/lib/utils/src/discord.ts index 0b98e37..b81130a 100644 --- a/lib/utils/src/discord.ts +++ b/lib/utils/src/discord.ts @@ -1,16 +1,24 @@ import { getAssetByName, getAssetModuleId } from '@revenge-mod/assets' import { TokensModuleId } from '@revenge-mod/discord/common' - import { byDependencies, byProps } from '@revenge-mod/modules/finders/filters' import { lookupModule } from '@revenge-mod/modules/finders/lookup' - -import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react' - +import { + ReactJsxRuntimeModuleId, + ReactModuleId, + ReactNativeModuleId, +} from '@revenge-mod/react' import type { FC } from 'react' // [React, ReactJsxRuntime, (Tokens), (BaseIconImage), (Asset), 2] // Asset = relativeDep(1) -const IconComponentFilter = [ReactModuleId, ReactJsxRuntimeModuleId, TokensModuleId, undefined, undefined, 2] +const IconComponentFilter = [ + ReactModuleId, + ReactJsxRuntimeModuleId, + TokensModuleId, + undefined, + undefined, + 2, +] // Generated IconComponents that have multiple assets, there is no specific length, so the filter has to be generated on-the-fly. // [React, ReactNative, ReactJsxRuntime, (Tokens), (BaseIconImage), (...Assets), 2] @@ -24,7 +32,10 @@ const MultiIconComponentFilterBase = [ ] // TODO(utils/discord/lookupGeneratedIconComponent): Make this into a filter? -export function lookupGeneratedIconComponent(compName: N, ...assetNames: string[]) { +export function lookupGeneratedIconComponent( + compName: N, + ...assetNames: string[] +) { const icon = lookupModule(byProps(compName))[0]?.[compName] if (icon) return icon diff --git a/lib/utils/src/generators.ts b/lib/utils/src/generators.ts index 0be78fb..85c474a 100644 --- a/lib/utils/src/generators.ts +++ b/lib/utils/src/generators.ts @@ -23,7 +23,9 @@ export function yielded(generator: Generator, skip = 0): T { if (skip) for (let i = 0; i < skip; i++) if (generator.next().done) - throw new Error(`Generator has no more values to drop (dropped ${i + 1} out of ${skip})`) + throw new Error( + `Generator has no more values to drop (dropped ${i + 1} out of ${skip})`, + ) return generator.next().value } diff --git a/lib/utils/src/logger.ts b/lib/utils/src/logger.ts index 9fc2bed..fbfc30a 100644 --- a/lib/utils/src/logger.ts +++ b/lib/utils/src/logger.ts @@ -3,7 +3,8 @@ export function createLogger(tag: string) { log: (message: string) => console.log(`[${tag}] ${message}`), warn: (message: string) => console.warn(`[${tag}] ${message}`), error: (message: string) => console.error(`[${tag}] ${message}`), - wtf: (message: string) => console.error(`\u001b[31m[${tag}] ${message}\u001b[0m`), + wtf: (message: string) => + console.error(`\u001b[31m[${tag}] ${message}\u001b[0m`), } satisfies BasicLogger } diff --git a/lib/utils/src/objects.ts b/lib/utils/src/objects.ts index cda7da7..190f2eb 100644 --- a/lib/utils/src/objects.ts +++ b/lib/utils/src/objects.ts @@ -31,8 +31,12 @@ export type InterceptPropertyCallback = (target: any, value: any) => any * @param callback The callback to call when the property is set, can return a non-null value to set the property to. * @returns The function to unintercept the property. */ -export function interceptProperty(prop: PropertyKey, callback: (target: object, value: any) => any) { - if (_intercepting.has(prop)) throw new Error(`Property ${String(prop)} is already being intercepted`) +export function interceptProperty( + prop: PropertyKey, + callback: (target: object, value: any) => any, +) { + if (_intercepting.has(prop)) + throw new Error(`Property ${String(prop)} is already being intercepted`) const proto = Object.prototype _intercepting.set(prop, Object.getOwnPropertyDescriptor(proto, prop)) @@ -102,7 +106,11 @@ export function mergeDeep(target: AnyObject, source: AnyObject) { * @param property The property key to define. * @param loader The function that will be called to load the property value when accessed. */ -export function defineLazyProperty(target: T, property: K, loader: () => T[K]) { +export function defineLazyProperty( + target: T, + property: K, + loader: () => T[K], +) { Object.defineProperty(target, property, { configurable: true, get() { diff --git a/lib/utils/src/promises.ts b/lib/utils/src/promises.ts index 6b012a1..7c340f5 100644 --- a/lib/utils/src/promises.ts +++ b/lib/utils/src/promises.ts @@ -1,4 +1,6 @@ -export function allSettled(promises: Promise[]): Promise[]> { +export function allSettled( + promises: Promise[], +): Promise[]> { const mapped = promises.map(p => p instanceof Promise ? p diff --git a/lib/utils/src/proxy.ts b/lib/utils/src/proxy.ts index b1c9617..5a9e9a3 100644 --- a/lib/utils/src/proxy.ts +++ b/lib/utils/src/proxy.ts @@ -45,7 +45,10 @@ export function getProxyTarget(obj: object) { // Heavily inspired by Wintry's lazy utils, but more optimized and stripped down, with a few fixes. // https://github.com/pylixonly/wintry/blob/main/src/utils/lazy.ts -const _metas = new WeakMap unknown, cacheable: boolean, cache?: unknown]>() +const _metas = new WeakMap< + object, + [factory: () => unknown, cacheable: boolean, cache?: unknown] +>() const _handler = { ...Object.fromEntries( @@ -64,7 +67,12 @@ const _handler = { if (typeof val === 'function') return new Proxy(val, { // If thisArg happens to be a proxified value, we will use the target object instead - apply: (fn, thisArg, args) => Reflect.apply(fn, thisArg === recv ? target : thisArg, args), + apply: (fn, thisArg, args) => + Reflect.apply( + fn, + thisArg === recv ? target : thisArg, + args, + ), }) return val @@ -73,7 +81,8 @@ const _handler = { // TypeError: getOwnPropertyDescriptor trap result is not configurable but target property '...' is configurable or non-existent getOwnPropertyDescriptor: (hint, p) => { const d = Reflect.getOwnPropertyDescriptor(unproxifyFromHint(hint)!, p) - if (d && !Reflect.getOwnPropertyDescriptor(hint, p)) Object.defineProperty(hint, p, d) + if (d && !Reflect.getOwnPropertyDescriptor(hint, p)) + Object.defineProperty(hint, p, d) return d }, } as ProxyHandler @@ -151,7 +160,8 @@ export function proxify(signal: () => T, options?: ProxifyOptions): T { */ export function unproxify(proxified: T): T { const hint = getProxyTarget(proxified) - if (!hint) throw new TypeError(`${typeof proxified} is not a proxified value`) + if (!hint) + throw new TypeError(`${typeof proxified} is not a proxified value`) return unproxifyFromHint(hint) } @@ -188,16 +198,24 @@ function unproxifyFromHint(hint: object) { * z // TypeError: Cannot destructure and proxify null (reading 'z') * ``` */ -export function destructure(proxified: T, options?: ProxifyOptions): T { +export function destructure( + proxified: T, + options?: ProxifyOptions, +): T { return new Proxy({} as T, { get: (_, p) => proxify(() => { // @ts-expect-error const v = unproxify(proxified)[p] - if (v == null) throw new TypeError(`Cannot destructure and proxify ${v} (reading '${String(p)}')`) + if (v == null) + throw new TypeError( + `Cannot destructure and proxify ${v} (reading '${String(p)}')`, + ) if (typeof v === 'function' || typeof v === 'object') return v - throw new TypeError(`Cannot destructure and proxify a primitive (reading '${String(p)}')`) + throw new TypeError( + `Cannot destructure and proxify a primitive (reading '${String(p)}')`, + ) }, options), }) } diff --git a/lib/utils/src/react.ts b/lib/utils/src/react.ts index 1810e1b..5951fc8 100644 --- a/lib/utils/src/react.ts +++ b/lib/utils/src/react.ts @@ -1,8 +1,7 @@ import { React } from '@revenge-mod/react' - -import { type SearchFilter, findInTree } from './trees' - +import { findInTree } from './trees' import type { ReactNode } from 'react' +import type { SearchFilter } from './trees' export function useIsFirstRender() { let firstRender = false @@ -21,7 +20,10 @@ export function useReRender() { const ReactFiberWalkable = new Set(['props', 'children', 'child', 'sibling']) -export function findInReactFiber(tree: Extract, filter: SearchFilter): any { +export function findInReactFiber( + tree: Extract, + filter: SearchFilter, +): any { return findInTree(tree, filter, { walkable: ReactFiberWalkable, }) diff --git a/lib/utils/src/trees.ts b/lib/utils/src/trees.ts index a1c777f..225939d 100644 --- a/lib/utils/src/trees.ts +++ b/lib/utils/src/trees.ts @@ -18,7 +18,11 @@ export interface FindInTreeOptions { maxDepth?: number } -export function findInTree(tree: SearchTree, filter: SearchFilter, opts?: FindInTreeOptions): any | undefined { +export function findInTree( + tree: SearchTree, + filter: SearchFilter, + opts?: FindInTreeOptions, +): any | undefined { type StackItem = [node: any, depth: number] const stack: StackItem[] = [[tree, 0]] const maxDepth = opts?.maxDepth ?? 100 @@ -37,7 +41,8 @@ export function findInTree(tree: SearchTree, filter: SearchFilter, opts?: FindIn if (typeof item !== 'object' || item == null) continue - if (!isArray && opts?.walkable?.size && !opts.walkable?.has(key)) continue + if (!isArray && opts?.walkable?.size && !opts.walkable?.has(key)) + continue if (!isArray && opts?.ignore?.has(key)) continue stack.push([item, depth + 1]) diff --git a/lib/utils/src/types.ts b/lib/utils/src/types.ts index 285bfba..1ff757c 100644 --- a/lib/utils/src/types.ts +++ b/lib/utils/src/types.ts @@ -1,7 +1,11 @@ export type Nullish = null | undefined export type If = T extends true ? Then : Else export type AnyObject = Record -export type LogicalOr = T1 extends true ? true : T2 extends true ? true : false +export type LogicalOr = T1 extends true + ? true + : T2 extends true + ? true + : false export type DeepPartial = { [K in keyof T]?: T[K] extends AnyObject ? DeepPartial : T[K] } diff --git a/package.json b/package.json index 6080a2d..c2a31f8 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,14 @@ "build": "bun --bun run scripts/build.ts", "dev": "bun --bun run scripts/dev.ts" }, - "trustedDependencies": ["@biomejs/biome", "@parcel/watcher", "@swc/core"], + "trustedDependencies": [ + "@biomejs/biome", + "@parcel/watcher", + "@swc/core" + ], "type": "module", - "workspaces": ["lib/*", "plugins/*"] + "workspaces": [ + "lib/*", + "plugins/*" + ] } diff --git a/scripts/build.ts b/scripts/build.ts index b23a7f9..5c0ed08 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -1,12 +1,12 @@ -import { parse } from 'path' import { transform } from '@swc/core' import { $, main } from 'bun' import chalk from 'chalk' import { exists, mkdir, readdir, rm, writeFile } from 'fs/promises' -import { type OutputChunk, type RolldownPlugin, rolldown } from 'rolldown' +import { parse } from 'path' +import { rolldown } from 'rolldown' import { aliasPlugin, importGlobPlugin } from 'rolldown/experimental' - import pkg from '../package.json' +import type { OutputChunk, RolldownPlugin } from 'rolldown' const ShimsDir = `${import.meta.dir}/../shims` const AssetsDir = `${import.meta.dir}/../src/assets` @@ -45,8 +45,12 @@ export default async function build(dev = false, log = true) { }, define: { __BUILD_VERSION__: JSON.stringify(pkg.version), - __BUILD_COMMIT__: JSON.stringify((await $`git rev-parse HEAD`.text()).trim().substring(0, 7)), - __BUILD_BRANCH__: JSON.stringify((await $`git rev-parse --abbrev-ref HEAD`.text()).trim()), + __BUILD_COMMIT__: JSON.stringify( + (await $`git rev-parse HEAD`.text()).trim().substring(0, 7), + ), + __BUILD_BRANCH__: JSON.stringify( + (await $`git rev-parse --abbrev-ref HEAD`.text()).trim(), + ), __BUILD_ENV__: JSON.stringify(dev ? 'development' : 'production'), __BUILD_FLAG_LOG_PROMISE_REJECTIONS__: String(dev), }, @@ -71,11 +75,24 @@ export default async function build(dev = false, log = true) { '-Wno-undefined-variable', ], before() { - if (log) console.debug(chalk.cyanBright('\u{1F5CE} JS compilation finished...')) - if (log) console.debug(chalk.gray('\u{1F5CE} Compiling bytecode...')) + if (log) + console.debug( + chalk.cyanBright( + '\u{1F5CE} JS compilation finished...', + ), + ) + if (log) + console.debug( + chalk.gray('\u{1F5CE} Compiling bytecode...'), + ) }, after() { - if (log) console.debug(chalk.cyanBright('\u{1F5CE} Bytecode compilation finished')) + if (log) + console.debug( + chalk.cyanBright( + '\u{1F5CE} Bytecode compilation finished', + ), + ) }, }), ], @@ -122,7 +139,7 @@ function swcPlugin() { }, }, env: { - // https://github.com/discord/hermes/blob/main/doc/Features.md + // https://github.com/facebook/hermes/blob/main/doc/Features.md targets: 'fully supports es6', include: [ 'transform-async-generator-functions', @@ -152,14 +169,23 @@ function swcPlugin() { } satisfies RolldownPlugin } -function hermesCPlugin({ after, before, flags }: { flags?: string[]; before?: () => void; after?: () => void } = {}) { +function hermesCPlugin({ + after, + before, + flags, +}: { + flags?: string[] + before?: () => void + after?: () => void +} = {}) { const paths = { win32: 'hermesc.exe', darwin: 'hermesc', linux: 'hermesc', } - if (!(process.platform in paths)) throw new Error(`Unsupported platform: ${process.platform}`) + if (!(process.platform in paths)) + throw new Error(`Unsupported platform: ${process.platform}`) const binPath = paths[process.platform as keyof typeof paths] @@ -201,7 +227,8 @@ function hermesCPlugin({ after, before, flags }: { flags?: string[]; before?: () } async function generateAssets() { - if (!(await exists(GeneratedAssetsDir))) await mkdir(GeneratedAssetsDir, { recursive: true }) + if (!(await exists(GeneratedAssetsDir))) + await mkdir(GeneratedAssetsDir, { recursive: true }) const promises: Promise[] = [] diff --git a/scripts/dev.ts b/scripts/dev.ts index 3b873e5..4027f4d 100644 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -1,8 +1,8 @@ -import os from 'os' -import { join } from 'path' import watcher from '@parcel/watcher' import { debounce } from '@revenge-mod/utils/callbacks' import chalk from 'chalk' +import os from 'os' +import { join } from 'path' import pkg from '../package.json' import build from './build' @@ -13,9 +13,18 @@ console.info(chalk.redBright(`\nRevenge ${chalk.white(`v${pkg.version}`)}\n`)) const cwdify = (path: string) => join(process.cwd(), path) const Sources = ['src', 'lib', 'plugins'].map(cwdify) -const ExitTriggers = ['scripts', 'shims', 'package.json', 'bun.lock', 'tsconfig.json'].map(cwdify) +const ExitTriggers = [ + 'scripts', + 'shims', + 'package.json', + 'bun.lock', + 'tsconfig.json', +].map(cwdify) -const debouncedBuildDev = debounce(() => ((needRebuild = false), build(true).catch(console.error)), 250) +const debouncedBuildDev = debounce( + () => ((needRebuild = false), build(true).catch(console.error)), + 250, +) let needRebuild = true @@ -23,25 +32,40 @@ watcher.subscribe(process.cwd(), (err, events) => { if (err) return console.error(err) if (events.some(it => ExitTriggers.some(se => it.path.startsWith(se)))) { - console.error(chalk.redBright('\u26A0 Scripts, packages, shims, or tsconfig.json has changed, exiting!')) + console.error( + chalk.redBright( + '\u26A0 Scripts, packages, shims, or tsconfig.json has changed, exiting!', + ), + ) process.exit() } - needRebuild ||= events.some(it => Sources.some(src => it.path.startsWith(src))) + needRebuild ||= events.some(it => + Sources.some(src => it.path.startsWith(src)), + ) }) const server = Bun.serve({ hostname: lanHost ? '0.0.0.0' : '127.0.0.1', async fetch(req, srv) { if (needRebuild) await debouncedBuildDev() - console.debug(chalk.gray(`\u{1F79B} Receiving request from ${srv.requestIP(req)!.address}`)) + console.debug( + chalk.gray( + `\u{1F79B} Receiving request from ${srv.requestIP(req)!.address}`, + ), + ) return new Response(Bun.file('./dist/revenge.bundle')) }, port: 4040, }) if (lanHost) console.info(chalk.gray('\u24D8 Listening on all interfaces...')) -else console.info(chalk.gray('\u24D8 Listening locally... Use --lan to listen on all interfaces')) +else + console.info( + chalk.gray( + '\u24D8 Listening locally... Use --lan to listen on all interfaces', + ), + ) if (!prod) console.info(chalk.gray('\u24D8 Use --prod to build for production')) else console.info(chalk.gray('\u24D8 Building for production...')) diff --git a/shims/react~jsx-runtime.ts b/shims/react~jsx-runtime.ts index 567e72a..555ed21 100644 --- a/shims/react~jsx-runtime.ts +++ b/shims/react~jsx-runtime.ts @@ -1,13 +1,22 @@ import { ReactJsxRuntime } from '@revenge-mod/react' import { isProxified, unproxify } from '@revenge-mod/utils/proxy' - import type { ElementType } from 'react' const { jsx: _jsx, jsxs: _jsxs, Fragment } = ReactJsxRuntime const jsx = ((type, ...args) => - _jsx(isProxified(type as object) ? (unproxify(type as object) as ElementType) : type, ...args)) as typeof _jsx + _jsx( + isProxified(type as object) + ? (unproxify(type as object) as ElementType) + : type, + ...args, + )) as typeof _jsx const jsxs = ((type, ...args) => - _jsxs(isProxified(type as object) ? (unproxify(type as object) as ElementType) : type, ...args)) as typeof _jsxs + _jsxs( + isProxified(type as object) + ? (unproxify(type as object) as ElementType) + : type, + ...args, + )) as typeof _jsxs export { jsx, jsxs, Fragment } diff --git a/src/components/FormSwitch.tsx b/src/components/FormSwitch.tsx index 0b930df..2faa857 100644 --- a/src/components/FormSwitch.tsx +++ b/src/components/FormSwitch.tsx @@ -1,12 +1,13 @@ import { FormSwitch as Switch } from '@revenge-mod/discord/design' import { ReactNative } from '@revenge-mod/react' - import type { DiscordModules } from '@revenge-mod/discord/types' /** * A switch component that is styled to match Discord's configuration */ -export default function FormSwitch(props: DiscordModules.Components.FormSwitchProps) { +export default function FormSwitch( + props: DiscordModules.Components.FormSwitchProps, +) { return ( diff --git a/src/components/Page.tsx b/src/components/Page.tsx index 66c1a5f..d417289 100644 --- a/src/components/Page.tsx +++ b/src/components/Page.tsx @@ -1,10 +1,10 @@ import { Design } from '@revenge-mod/discord/design' -import type { DiscordModules } from '@revenge-mod/discord/types' import { ReactNative } from '@revenge-mod/react' +import type { DiscordModules } from '@revenge-mod/discord/types' export default function Page(props: DiscordModules.Components.StackProps) { return ( - + {props.children} ) diff --git a/src/components/SearchInput.tsx b/src/components/SearchInput.tsx index a92a70a..a08067d 100644 --- a/src/components/SearchInput.tsx +++ b/src/components/SearchInput.tsx @@ -1,17 +1,18 @@ import { Design } from '@revenge-mod/discord/design' import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord' - import type { DiscordModules } from '@revenge-mod/discord/types' const MagnifyingGlassIcon = lookupGeneratedIconComponent('MagnifyingGlassIcon') -export default function SearchInput(props: DiscordModules.Components.TextInputProps) { +export default function SearchInput( + props: DiscordModules.Components.TextInputProps, +) { return ( ) diff --git a/src/components/TableRowAssetIcon.tsx b/src/components/TableRowAssetIcon.tsx index dc7794c..e36307a 100644 --- a/src/components/TableRowAssetIcon.tsx +++ b/src/components/TableRowAssetIcon.tsx @@ -1,13 +1,20 @@ import { getAssetIdByName } from '@revenge-mod/assets' import { Design } from '@revenge-mod/discord/design' - import type { DiscordModules } from '@revenge-mod/discord/types' export default function TableRowAssetIcon(props: TableRowAssetIconProps) { - return + return ( + + ) } -export type TableRowAssetIconProps = Omit & +export type TableRowAssetIconProps = Omit< + DiscordModules.Components.TableRowIconProps, + 'source' +> & ( | { name: string diff --git a/src/index.ts b/src/index.ts index cb4b3e7..1604e80 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,16 +4,23 @@ import { interceptProperty } from '@revenge-mod/utils/objects' // By doing this, we are assuming __METRO_GLOBAL_PREFIX__ is an empty string and globalThis.__d isn't already set. // But both should be true either way. -const unintercept = interceptProperty('__d', (_, mDefine) => (unintercept(), patchMetroDefine(mDefine))) +const unintercept = interceptProperty( + '__d', + (_, mDefine) => (unintercept(), patchMetroDefine(mDefine)), +) -import { onModuleFirstRequired, onModuleInitialized } from '@revenge-mod/modules/metro/subscriptions' +import { + onModuleFirstRequired, + onModuleInitialized, +} from '@revenge-mod/modules/metro/subscriptions' import { getErrorStack } from '@revenge-mod/utils/errors' const IndexModuleId = 0 onModuleFirstRequired(IndexModuleId, function onIndexRequired() { runCatching(() => { - if (__BUILD_FLAG_LOG_PROMISE_REJECTIONS__) require('./patches/log-promise-rejections') + if (__BUILD_FLAG_LOG_PROMISE_REJECTIONS__) + require('./patches/log-promise-rejections') // Initialize preinit libraries require('@revenge-mod/modules/preinit') @@ -44,12 +51,10 @@ function runCatching(fn: () => void) { } catch (e) { // TODO(init): Move to use native provided alert function, which will accept a string stack trace // Above will reduce the need for runCatching() to exist, as the code won't be able to be deduped any further - const { ClientInfoModule, DeviceModule } = require('@revenge-mod/discord/native') as - // biome-ignore format: Don't format this please - typeof import('@revenge-mod/discord/native') + const { ClientInfoModule, DeviceModule } = + require('@revenge-mod/discord/native') as typeof import('@revenge-mod/discord/native') alert( - // biome-ignore lint/style/useTemplate: I want this to be readable, thank you `Failed to load Revenge (${__BUILD_VERSION__}-${__BUILD_COMMIT__}-${__BUILD_BRANCH__} (${__BUILD_ENV__}))\n` + `Discord: ${ClientInfoModule.Version} (${ClientInfoModule.Build})\n` + `Device: ${DeviceModule.deviceManufacturer} ${DeviceModule.deviceModel}\n\n` + diff --git a/src/patches/log-promise-rejections.ts b/src/patches/log-promise-rejections.ts index 55eca65..dd80e14 100644 --- a/src/patches/log-promise-rejections.ts +++ b/src/patches/log-promise-rejections.ts @@ -16,7 +16,10 @@ Promise._m = (promise, err) => { if (err) setTimeout( () => { - if (promise._h === 0) logger.error(`Unhandled promise rejection: ${getErrorStack(err)}`) + if (promise._h === 0) + logger.error( + `Unhandled promise rejection: ${getErrorStack(err)}`, + ) }, ErrorTypeWhitelist.some(it => err instanceof it) ? 0 : 2000, // The time is completely arbitary. I've picked what Hermes chose. diff --git a/src/plugins/init/developer-settings/definitions/AssetBrowserSetting.tsx b/src/plugins/init/developer-settings/definitions/AssetBrowserSetting.tsx index 75e21ad..7b3d130 100644 --- a/src/plugins/init/developer-settings/definitions/AssetBrowserSetting.tsx +++ b/src/plugins/init/developer-settings/definitions/AssetBrowserSetting.tsx @@ -1,7 +1,5 @@ import TableRowAssetIcon from '~/components/TableRowAssetIcon' - import { MobileSetting, UserSettingsSections } from '../constants' - import type { SettingsItem } from '@revenge-mod/discord/modules/settings' const AssetBrowserSetting: SettingsItem = { @@ -11,7 +9,8 @@ const AssetBrowserSetting: SettingsItem = { title: () => 'Asset Browser', screen: { route: UserSettingsSections[MobileSetting.ASSET_BROWSER], - getComponent: () => require('../screens/AssetBrowserSettingScreen').default, + getComponent: () => + require('../screens/AssetBrowserSettingScreen').default, }, } diff --git a/src/plugins/init/developer-settings/definitions/EvaluateJavaScriptSetting.tsx b/src/plugins/init/developer-settings/definitions/EvaluateJavaScriptSetting.tsx index 96a1b41..95b6546 100644 --- a/src/plugins/init/developer-settings/definitions/EvaluateJavaScriptSetting.tsx +++ b/src/plugins/init/developer-settings/definitions/EvaluateJavaScriptSetting.tsx @@ -1,17 +1,11 @@ -import { React } from '@revenge-mod/react' - import { AlertActionCreators } from '@revenge-mod/discord/actions' import { Design } from '@revenge-mod/discord/design' - import { nodeUtil } from '@revenge-mod/externals/browserify' - +import { React } from '@revenge-mod/react' import { getErrorStack } from '@revenge-mod/utils/errors' - import TableRowAssetIcon from '~/components/TableRowAssetIcon' - import { api } from '..' import { MobileSetting } from '../constants' - import type { SettingsItem } from '@revenge-mod/discord/modules/settings' const ALERT_KEY = 'evaluate-javascript' @@ -21,7 +15,8 @@ const EvaluateJavaScriptSetting: SettingsItem = { IconComponent: () => , title: () => 'Evaluate JavaScript', useDescription: () => 'Runs a JavaScript code snippet.', - onPress: () => AlertActionCreators.openAlert(ALERT_KEY, ), + onPress: () => + AlertActionCreators.openAlert(ALERT_KEY, ), type: 'pressable', } @@ -47,60 +42,21 @@ function EvaluateJavaScriptAlert() { return ( -