diff --git a/lib/discord/package.json b/lib/discord/package.json index 199e4da..182fc88 100644 --- a/lib/discord/package.json +++ b/lib/discord/package.json @@ -16,13 +16,7 @@ "default": "./src/common/flux.ts" }, "./design": { - "default": "./src/design/index.ts" - }, - "./design/components": { - "default": "./src/design/components/index.ts" - }, - "./design/components/Icon": { - "default": "./src/design/components/Icon.ts" + "default": "./src/design.ts" }, "./native": { "default": "./src/native.ts" @@ -30,14 +24,14 @@ "./preinit": { "default": "./src/preinit.ts" }, - "./modules": { - "default": "./src/modules/index.ts" - }, "./modules/settings": { "default": "./src/modules/settings/index.ts" }, + "./modules/settings/renderer": { + "default": "./src/modules/settings/renderer.ts" + }, "./types": { - "types": "./types/index.ts" + "types": "./src/types/index.ts" }, "./_/modules/settings": { "default": "./src/modules/settings/_internal.ts" diff --git a/lib/discord/src/actions.ts b/lib/discord/src/actions.ts index c1780c1..6da5e3d 100644 --- a/lib/discord/src/actions.ts +++ b/lib/discord/src/actions.ts @@ -1,12 +1,12 @@ -import { lookupModule, lookupModules } from '@revenge-mod/modules/finders' import { byDependencies, byProps, every, - moduleStateAware, + preferExports, relativeDep, withoutProps, } from '@revenge-mod/modules/finders/filters' +import { lookupModule, lookupModules } from '@revenge-mod/modules/finders/lookup' import { ReactJsxRuntimeModuleId, ReactModuleId } from '@revenge-mod/react' @@ -14,12 +14,12 @@ import { proxify } from '@revenge-mod/utils/proxy' import { DispatcherModuleId } from './common/flux' -import type { DiscordModules } from '../types' +import type { DiscordModules } from './types' export let ActionSheetActionCreators: DiscordModules.Actions.ActionSheetActionCreators = proxify( () => { const module = lookupModule( - moduleStateAware( + preferExports( byProps('hideActionSheet'), byDependencies([ undefined, @@ -36,13 +36,7 @@ export let ActionSheetActionCreators: DiscordModules.Actions.ActionSheetActionCr }, ) - if (module) { - // This allows the Proxy instance to be garbage collected - // after the module is initialized. - ActionSheetActionCreators = module - gc() - return module - } + if (module) return (ActionSheetActionCreators = module) }, { hint: 'object', @@ -52,7 +46,7 @@ export let ActionSheetActionCreators: DiscordModules.Actions.ActionSheetActionCr export let AlertActionCreators: DiscordModules.Actions.AlertActionCreators = proxify( () => { const module = lookupModule( - moduleStateAware( + preferExports( byProps('openAlert', 'dismissAlert'), byDependencies([ ReactModuleId, @@ -66,13 +60,7 @@ export let AlertActionCreators: DiscordModules.Actions.AlertActionCreators = pro ), ) - if (module) { - // This allows the Proxy instance to be garbage collected - // after the module is initialized. - AlertActionCreators = module - gc() - return module - } + if (module) return (AlertActionCreators = module) }, { hint: 'object', @@ -84,7 +72,7 @@ export let ToastActionCreators: DiscordModules.Actions.ToastActionCreators = pro // [Dispatcher, ImportTracker] const generator = lookupModules( - moduleStateAware( + preferExports( every(byProps('open'), withoutProps('init')), byDependencies([DispatcherModuleId, 2]), ), @@ -93,12 +81,5 @@ export let ToastActionCreators: DiscordModules.Actions.ToastActionCreators = pro }, ) - for (const module of generator) - if (module.open.length === 1) { - // This allows the Proxy instance to be garbage collected - // after the module is initialized. - ToastActionCreators = module - gc() - return 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 e809190..460031f 100644 --- a/lib/discord/src/common/flux.ts +++ b/lib/discord/src/common/flux.ts @@ -1,10 +1,13 @@ -import { lookupModuleId, waitForModules } from '@revenge-mod/modules/finders' -import { byDependencies, byProps, moduleStateAware, relativeDep } from '@revenge-mod/modules/finders/filters' +import { byDependencies, byProps, preferExports, relativeDep } from '@revenge-mod/modules/finders/filters' +import { lookupModuleId } from '@revenge-mod/modules/finders/lookup' +import { waitForModules } from '@revenge-mod/modules/finders/wait' -import type { DiscordModules } from '../../types' +import type { DiscordModules } from '../types' + +// ../discord_common/js/packages/flux export const DispatcherModuleId = lookupModuleId( - moduleStateAware( + preferExports( byProps('_interceptors'), byDependencies([relativeDep(1), undefined, undefined, undefined, undefined, 2]), ), @@ -22,7 +25,7 @@ waitForModules(byProps('_dispatchToken'), (_, store) const _stores: Record = {} -export const stores = new Proxy(_stores, { +export const Stores = new Proxy(_stores, { ownKeys: () => Reflect.ownKeys(_stores), - get: (_, name) => stores[name as string], + get: (_, name) => Stores[name as string], }) diff --git a/lib/discord/src/common/index.ts b/lib/discord/src/common/index.ts index 399c227..02951a6 100644 --- a/lib/discord/src/common/index.ts +++ b/lib/discord/src/common/index.ts @@ -1,15 +1,15 @@ -import { lookupModule, lookupModuleId } from '@revenge-mod/modules/finders' import { byName, byProps } from '@revenge-mod/modules/finders/filters' +import { lookupModule, lookupModuleId } from '@revenge-mod/modules/finders/lookup' -import type { DiscordModules } from '../../types' +import type { DiscordModules } from '../types' -// ../discord_common/js/packages/flux -export * as flux from './flux' +export { AppStartPerformance } from '../preinit' + +export * as Flux from './flux' // ../discord_common/js/shared/Logger.tsx export const Logger = lookupModule(byName('Logger'))! -// ../discord_common/js/packages/tokens/native.tsx -export const tokensModuleId = lookupModuleId(byProps('RawColor'))! -export const tokens = __r(tokensModuleId) -export { AppStartPerformance } from '../preinit' +// ../discord_common/js/packages/tokens/native.tsx +export const TokensModuleId = lookupModuleId(byProps('RawColor'))! +export const Tokens = __r(TokensModuleId) diff --git a/lib/discord/src/design/components/index.ts b/lib/discord/src/design.ts similarity index 75% rename from lib/discord/src/design/components/index.ts rename to lib/discord/src/design.ts index a3b1e0d..654b24f 100644 --- a/lib/discord/src/design/components/index.ts +++ b/lib/discord/src/design.ts @@ -1,17 +1,17 @@ -import { lookupModule } from '@revenge-mod/modules/finders' -import { byDependencies, byProps, looseDeps, moduleStateAware, 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 { proxify } from '@revenge-mod/utils/proxy' -import type { DiscordModules } from '../../../types' +import type { DiscordModules } from './types' // design/native.tsx -let components: Components = proxify( +export let Components: Components = proxify( () => { // ID: 3236 // [3237, 1366, 3238, 3239, 2, ...]; const module = lookupModule( - moduleStateAware( + preferExports( byProps('TableRow', 'Button'), byDependencies(looseDeps([relativeDep(1), undefined, relativeDep(2), relativeDep(3), 2])), ), @@ -20,21 +20,13 @@ let components: Components = proxify( }, ) - if (module) { - // This allows the Proxy instance to be garbage collected - // after the module is initialized. - components = module - gc() - return module - } + if (module) return (Components = module) }, { hint: 'object', }, )! -export default components - export interface Components { ActionSheet: DiscordModules.Components.ActionSheet ActionSheetRow: DiscordModules.Components.ActionSheetRow diff --git a/lib/discord/src/design/components/_exports.ts b/lib/discord/src/design/components/_exports.ts deleted file mode 100644 index afcb485..0000000 --- a/lib/discord/src/design/components/_exports.ts +++ /dev/null @@ -1 +0,0 @@ -export * as Icon from './Icon' diff --git a/lib/discord/src/design/index.ts b/lib/discord/src/design/index.ts deleted file mode 100644 index a910ab8..0000000 --- a/lib/discord/src/design/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import components_ from './components' -import * as components_exports from './components/_exports' - -const components = { - ...components_, - ...components_exports, -} - -export { components } diff --git a/lib/discord/src/index.ts b/lib/discord/src/index.ts deleted file mode 100644 index 8f021ee..0000000 --- a/lib/discord/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * as actions from './actions' -export * as common from './common' -export * as design from './design' -export * as modules from './modules' -export * as native from './native' diff --git a/lib/discord/src/modules/index.ts b/lib/discord/src/modules/index.ts deleted file mode 100644 index 6813118..0000000 --- a/lib/discord/src/modules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * as settings from './settings' diff --git a/lib/discord/src/modules/settings/_internal.ts b/lib/discord/src/modules/settings/_internal.ts index 5701644..76657d7 100644 --- a/lib/discord/src/modules/settings/_internal.ts +++ b/lib/discord/src/modules/settings/_internal.ts @@ -1,4 +1,4 @@ -import type { SettingsItem, SettingsModulesLoadedSubscription, SettingsSection } from './api' +import type { SettingsItem, SettingsModulesLoadedSubscription, SettingsSection } from '.' export const _data = [ // Sections to splice in the SettingsOverviewScreen diff --git a/lib/discord/src/modules/settings/api.ts b/lib/discord/src/modules/settings/api.ts deleted file mode 100644 index 5b23349..0000000 --- a/lib/discord/src/modules/settings/api.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { _data, _subs } from './_internal' - -import type { ComponentType, ReactNode } from 'react' -import type { DiscordModules } from '../../../types' - -export type SettingsModulesLoadedSubscription = () => void - -/** - * Checks if the settings modules are loaded. - */ -export function isSettingsModulesLoaded() { - return _data[2] -} - -/** - * Subscribes to when settings modules are loaded. - * Plugins should ideally register their settings in the given callback to ensure fast startup time. - * - * @param subcription The subscription function to call when the settings modules are loaded. - * @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 onceSettingsModulesLoaded(subcription: SettingsModulesLoadedSubscription) { - if (_data[2]) throw new Error('Settings modules already loaded') - - _subs.add(subcription) - return () => _subs.delete(subcription) -} - -/** - * Registers a settings section with a given key. - * - * @param key The key to register the settings section with. - * @param section The settings section to register. - * @returns A function to unregister the settings section. - */ -export function registerSettingsSection(key: string, section: SettingsSection) { - _data[0][key] = section - return () => delete _data[0][key] -} - -/** - * Registers a settings item with a given key. - * - * @param key The key to register the settings item with. - * @param item The settings item to register. - * @returns A function to unregister the settings item. - */ -export function registerSettingsItem(key: string, item: SettingsItem) { - _data[1][key] = item - return () => delete _data[1][key] -} - -/** - * Registers multiple settings items at once. - * - * @param record The settings items to register. - * @returns A function to unregister the settings items. - */ -export function registerSettingsItems(record: Record) { - Object.assign(_data[1], record) - return () => { - for (const key in record) delete _data[1][key] - } -} - -/** - * Adds a settings item to an existing section. - * - * @param key The section to add the settings item to. - * @param item The settings item to add. - * @returns A function to remove the settings item from the section. - */ -export function addSettingsItemToSection(key: string, item: string) { - const section = _data[0][key] - if (!section) throw new Error(`Section "${key}" does not exist`) - - const newLength = section.settings.push(item) - return () => delete section.settings[newLength - 1] -} - -export interface SettingsSection { - label: string - settings: string[] - index?: number -} - -interface BaseSettingsItem { - title: () => string - parent: string | null - unsearchable?: boolean - variant?: DiscordModules.Components.TableRowProps['variant'] - IconComponent?: () => ReactNode - usePredicate?: () => boolean - useTrailing?: () => ReactNode - useDescription?: () => string - useIsDisabled?: () => boolean -} - -export interface PressableSettingsItem extends BaseSettingsItem { - type: 'pressable' - onPress?: () => void -} - -export interface ToggleSettingsItem extends BaseSettingsItem { - type: 'toggle' - useValue: () => boolean - onValueChange?: (value: boolean) => void -} - -export interface RouteSettingsItem extends BaseSettingsItem { - type: 'route' - screen: { route: string; getComponent(): ComponentType } -} - -export interface StaticSettingsItem extends BaseSettingsItem { - type: 'static' -} - -export type SettingsItem = PressableSettingsItem | ToggleSettingsItem | RouteSettingsItem | StaticSettingsItem diff --git a/lib/discord/src/modules/settings/index.ts b/lib/discord/src/modules/settings/index.ts index de4615a..9f890a2 100644 --- a/lib/discord/src/modules/settings/index.ts +++ b/lib/discord/src/modules/settings/index.ts @@ -1,6 +1,82 @@ -import { _data } from './_internal' +import { _data, _subs } from './_internal' -export * from './api' -export * from './common' +import type { DiscordModules } from '../../types' -// Patching in done in src/plugins/settings +export type SettingsItem = DiscordModules.Modules.Settings.SettingsItem +export type SettingsSection = DiscordModules.Modules.Settings.SettingsSection + +export type SettingsModulesLoadedSubscription = () => void + +/** + * Checks if the settings modules are loaded. + */ +export function isSettingsModulesLoaded() { + return _data[2] +} + +/** + * Subscribes to when settings modules are loaded. + * Plugins should ideally register their settings in the given callback to ensure fast startup time. + * + * @param subcription The subscription function to call when the settings modules are loaded. + * @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 onceSettingsModulesLoaded(subcription: SettingsModulesLoadedSubscription) { + if (_data[2]) throw new Error('Settings modules already loaded') + + _subs.add(subcription) + return () => _subs.delete(subcription) +} + +/** + * Registers a settings section with a given key. + * + * @param key The key to register the settings section with. + * @param section The settings section to register. + * @returns A function to unregister the settings section. + */ +export function registerSettingsSection(key: string, section: SettingsSection) { + _data[0][key] = section + return () => delete _data[0][key] +} + +/** + * Registers a settings item with a given key. + * + * @param key The key to register the settings item with. + * @param item The settings item to register. + * @returns A function to unregister the settings item. + */ +export function registerSettingsItem(key: string, item: SettingsItem) { + _data[1][key] = item + return () => delete _data[1][key] +} + +/** + * Registers multiple settings items at once. + * + * @param record The settings items to register. + * @returns A function to unregister the settings items. + */ +export function registerSettingsItems(record: Record) { + Object.assign(_data[1], record) + return () => { + for (const key in record) delete _data[1][key] + } +} + +/** + * Adds a settings item to an existing section. + * + * @param key The section to add the settings item to. + * @param item The settings item to add. + * @returns A function to remove the settings item from the section. + */ +export function addSettingsItemToSection(key: string, item: string) { + const section = _data[0][key] + if (!section) throw new Error(`Section "${key}" does not exist`) + + const newLength = section.settings.push(item) + return () => delete section.settings[newLength - 1] +} diff --git a/lib/discord/src/modules/settings/common.ts b/lib/discord/src/modules/settings/renderer.ts similarity index 53% rename from lib/discord/src/modules/settings/common.ts rename to lib/discord/src/modules/settings/renderer.ts index 7a9b6c0..461ecb7 100644 --- a/lib/discord/src/modules/settings/common.ts +++ b/lib/discord/src/modules/settings/renderer.ts @@ -1,16 +1,18 @@ -import { lookupModule } from '@revenge-mod/modules/finders' -import { byDependencies, byProps, looseDeps, moduleStateAware, 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 { proxify } from '@revenge-mod/utils/proxy' -import type { ComponentType, ReactNode } from 'react' +import type { DiscordModules } from '../../types' + +export type SettingListRenderer = DiscordModules.Modules.Settings.SettingListRenderer export let SettingListRenderer: SettingListRenderer = proxify( () => { const module = lookupModule( - moduleStateAware( + preferExports( byProps('SettingsList'), byDependencies( looseDeps([ @@ -28,22 +30,9 @@ export let SettingListRenderer: SettingListRenderer = proxify( }, ) - if (module) { - // This allows the Proxy instance to be garbage collected - // after the module is initialized. - SettingListRenderer = module - gc() - return module - } + if (module) return (SettingListRenderer = module) }, { hint: 'object', }, )! - -export interface SettingListRenderer { - SettingsList: ComponentType<{ - ListHeaderComponent?: ComponentType - sections: Array<{ label?: string | ReactNode; settings: string[]; subLabel?: string | ReactNode }> - }> -} diff --git a/lib/discord/src/native.ts b/lib/discord/src/native.ts index 7615feb..b540fd7 100644 --- a/lib/discord/src/native.ts +++ b/lib/discord/src/native.ts @@ -1,4 +1,4 @@ -import type { DiscordNativeModules } from '../types/native' +import type { DiscordNativeModules } from './types/native' /** * Naming conventions: diff --git a/lib/discord/src/preinit.ts b/lib/discord/src/preinit.ts index 3abf2d9..dea1dcb 100644 --- a/lib/discord/src/preinit.ts +++ b/lib/discord/src/preinit.ts @@ -1,11 +1,11 @@ -import { lookupModule } from '@revenge-mod/modules/finders' -import { byDependencies, byProps, moduleStateAware, 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 { DiscordModules } from '../types' +import type { DiscordModules } from './types' // ../discord_common/js/shared/AppStartPerformance.tsx export const AppStartPerformance = lookupModule( - moduleStateAware( + preferExports( byProps('markAndLog'), // biome-ignore lint/suspicious/noSparseArray: Nah byDependencies([relativeDep(-1), , , 2]), diff --git a/lib/discord/types/index.ts b/lib/discord/src/types/index.ts similarity index 88% rename from lib/discord/types/index.ts rename to lib/discord/src/types/index.ts index bacd026..e5b8330 100644 --- a/lib/discord/types/index.ts +++ b/lib/discord/src/types/index.ts @@ -1,5 +1,3 @@ -import type { Buffer as _Buffer } from 'buffer' - import type { ComponentProps, ComponentType, FC, ReactNode } from 'react' import type { ImageSourcePropType, @@ -13,6 +11,7 @@ import type { } from 'react-native' export * from './native' +export * from './polyfills' export namespace DiscordModules { export namespace Flux { @@ -251,7 +250,6 @@ export namespace DiscordModules { end?: boolean variant?: 'primary' | 'secondary' | 'transparent' border?: 'faint' | 'normal' | 'strong' | 'subtle' | 'none' - // TODO shadow?: 'none' | 'low' | 'medium' | 'high' | 'border' | 'ledge' children: ReactNode } @@ -488,10 +486,63 @@ export namespace DiscordModules { export type Slider = FC } -} -/// POLYFILLS + export namespace Modules { + export namespace Settings { + export interface SettingListRenderer { + SettingsList: SettingsList + } -declare global { - var Buffer: typeof _Buffer + export interface SettingsListProps { + ListHeaderComponent?: ComponentType + sections: Array<{ label?: string | ReactNode; settings: string[]; subLabel?: string | ReactNode }> + } + + export type SettingsList = FC + + export interface SettingsSection { + label: string + settings: string[] + index?: number + } + + interface BaseSettingsItem { + title: () => string + parent: string | null + unsearchable?: boolean + variant?: DiscordModules.Components.TableRowProps['variant'] + IconComponent?: () => ReactNode + usePredicate?: () => boolean + useTrailing?: () => ReactNode + useDescription?: () => string + useIsDisabled?: () => boolean + } + + export interface PressableSettingsItem extends BaseSettingsItem { + type: 'pressable' + onPress?: () => void + } + + export interface ToggleSettingsItem extends BaseSettingsItem { + type: 'toggle' + useValue: () => boolean + onValueChange?: (value: boolean) => void + } + + export interface RouteSettingsItem extends BaseSettingsItem { + type: 'route' + screen: { route: string; getComponent(): ComponentType } + } + + export interface StaticSettingsItem extends BaseSettingsItem { + type: 'static' + } + + export type SettingsItem = + | PressableSettingsItem + | ToggleSettingsItem + | RouteSettingsItem + | StaticSettingsItem + } + } } diff --git a/lib/discord/types/native.ts b/lib/discord/src/types/native.ts similarity index 100% rename from lib/discord/types/native.ts rename to lib/discord/src/types/native.ts diff --git a/lib/discord/src/types/polyfills.ts b/lib/discord/src/types/polyfills.ts new file mode 100644 index 0000000..5ad0e41 --- /dev/null +++ b/lib/discord/src/types/polyfills.ts @@ -0,0 +1,5 @@ +import type { Buffer as _Buffer } from 'buffer' + +declare global { + var Buffer: typeof _Buffer +} diff --git a/lib/utils/package.json b/lib/utils/package.json index 660c9d8..9d37aba 100644 --- a/lib/utils/package.json +++ b/lib/utils/package.json @@ -6,6 +6,9 @@ "./callbacks": { "default": "./src/callbacks.ts" }, + "./discord": { + "default": "./src/discord.ts" + }, "./errors": { "default": "./src/errors.ts" }, diff --git a/lib/discord/src/design/components/Icon.ts b/lib/utils/src/discord.ts similarity index 58% rename from lib/discord/src/design/components/Icon.ts rename to lib/utils/src/discord.ts index 19c16cf..b7bd14b 100644 --- a/lib/discord/src/design/components/Icon.ts +++ b/lib/utils/src/discord.ts @@ -1,17 +1,16 @@ import { getAssetByName, getAssetModuleId } from '@revenge-mod/assets' +import { TokensModuleId } from '@revenge-mod/discord/common' -import { lookupModule } from '@revenge-mod/modules/finders' import { byDependencies, byProps } from '@revenge-mod/modules/finders/filters' +import { lookupModule } from '@revenge-mod/modules/finders/lookup' import { ReactJsxRuntimeModuleId, ReactModuleId } from '@revenge-mod/react' -import { tokensModuleId } from '../../common' - import type { FC } from 'react' -// [React, ReactJsxRuntime, (BaseIconImage), (Tokens), (Asset), 2] +// [React, ReactJsxRuntime, (BaseIconImage), (Tokens), (...), (Asset), 2] // Asset = relativeDep(1) -const filter = [ReactModuleId, ReactJsxRuntimeModuleId, tokensModuleId, undefined, undefined, 2] +const IconComponentFilter = [ReactModuleId, ReactJsxRuntimeModuleId, TokensModuleId, undefined, undefined, 2] export function lookupGeneratedIconComponent(name: N) { const icon = lookupModule(byProps(name))?.[name] @@ -20,9 +19,9 @@ export function lookupGeneratedIconComponent(name: N) { const mid = getAssetModuleId(getAssetByName(name)!)! if (!mid) return - filter[4] = mid + IconComponentFilter[4] = mid - return lookupModule(byDependencies<{ [K in N]: FC }>(filter), { + return lookupModule(byDependencies<{ [K in N]: FC }>(IconComponentFilter), { includeInitialized: false, includeUninitialized: true, })?.[name]