feat(lib): add externals

This commit is contained in:
PalmDevs 2025-05-08 18:53:30 +07:00
parent 15154c05fe
commit 98b84a43c7
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
7 changed files with 169 additions and 0 deletions

View file

@ -31,6 +31,9 @@
"lib/discord": {
"name": "@revenge-mod/discord",
},
"lib/externals": {
"name": "@revenge-mod/externals",
},
"lib/init": {
"name": "@revenge-mod/init",
},
@ -431,6 +434,8 @@
"@revenge-mod/discord": ["@revenge-mod/discord@workspace:lib/discord"],
"@revenge-mod/externals": ["@revenge-mod/externals@workspace:lib/externals"],
"@revenge-mod/init": ["@revenge-mod/init@workspace:lib/init"],
"@revenge-mod/modules": ["@revenge-mod/modules@workspace:lib/modules"],

18
lib/externals/README.md vendored Normal file
View file

@ -0,0 +1,18 @@
# @revenge-mod/externals
This package provides common external libraries bundled in React Native apps, but this does not guarantee that they will be available.
This is done to ensure that Revenge's core APIs won't change if the external libraries are removed from the app.
## Libraries
For obvious reasons, this package only maintains lookups for specific versions of libraries that Discord uses.
However, it can be adapted to work with any other React Native apps.
- `@react-navigation/native`
- `@react-navigation/stack`
- `@shopify/flash-list`
- `util` (`browserify/node-util`)

19
lib/externals/package.json vendored Normal file
View file

@ -0,0 +1,19 @@
{
"name": "@revenge-mod/externals",
"private": true,
"type": "module",
"exports": {
".": {
"default": "./src/index.ts"
},
"./browserify": {
"default": "./src/browserify.ts"
},
"./react-navigation": {
"default": "./src/react-navigation.ts"
},
"./shopify": {
"default": "./src/shopify.ts"
}
}
}

25
lib/externals/src/browserify.ts vendored Normal file
View file

@ -0,0 +1,25 @@
import { lookupModule } from '@revenge-mod/modules/finders'
import { byDependencies, byProps, moduleStateAware, relativeDep } from '@revenge-mod/modules/finders/filters'
import { proxify } from '@revenge-mod/utils/proxy'
export let nodeUtil: typeof import('node:util') = proxify(
() => {
const module = lookupModule(
moduleStateAware(byProps<typeof nodeUtil>('inspect'), byDependencies([relativeDep(1), [], []])),
{
includeUninitialized: true,
},
)
if (module) {
// This allows the Proxy instance to be garbage collected
// after the module is initialized.
nodeUtil = module
gc()
return module
}
},
{
hint: 'object',
},
)!

3
lib/externals/src/index.ts vendored Normal file
View file

@ -0,0 +1,3 @@
export * as browserify from './browserify'
export * as reactNavigation from './react-navigation'
export * as shopify from './shopify'

66
lib/externals/src/react-navigation.ts vendored Normal file
View file

@ -0,0 +1,66 @@
import { proxify } from '@revenge-mod/utils/proxy'
import { lookupModule, lookupModuleId } from '@revenge-mod/modules/finders'
import { byDependencies, byName, byProps, looseDeps, moduleStateAware } from '@revenge-mod/modules/finders/filters'
const _createClassModuleId = lookupModuleId(byName('_createClass'))
const _classCallCheckModuleId = lookupModuleId(byName('_classCallCheck'))
export let ReactNavigationNative: typeof import('@react-navigation/native') = proxify(
() => {
const module = lookupModule(
moduleStateAware(
byProps<typeof ReactNavigationNative>('useLinkTo'),
byDependencies(looseDeps([[], looseDeps([[_createClassModuleId, _classCallCheckModuleId]])])),
),
{
includeUninitialized: true,
},
)
if (module) {
// This allows the Proxy instance to be garbage collected
// after the module is initialized.
ReactNavigationNative = module
gc()
return module
}
},
{
hint: 'object',
},
)!
export let ReactNavigationStack: typeof import('@react-navigation/stack') = proxify(
() => {
const module = lookupModule(
moduleStateAware(
byProps<typeof ReactNavigationStack>('createStackNavigator'),
byDependencies(looseDeps([[], looseDeps([[_createClassModuleId, _classCallCheckModuleId]])])),
),
{
includeUninitialized: true,
},
)
if (module) {
// This allows the Proxy instance to be garbage collected
// after the module is initialized.
ReactNavigationStack = module
gc()
return module
}
},
{
hint: 'object',
},
)!
export interface ReactNavigationParamList {
[Page: string]: any
}
declare global {
namespace ReactNavigation {
interface RootParamList extends ReactNavigationParamList {}
}
}

33
lib/externals/src/shopify.ts vendored Normal file
View file

@ -0,0 +1,33 @@
import { byDependencies, byProps, moduleStateAware } from '@revenge-mod/modules/finders/filters'
import { lookupModule } from '@revenge-mod/modules/finders'
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(
moduleStateAware(
byProps<typeof FlashList>('FlashList'),
// biome-ignore lint/suspicious/noSparseArray: don't care
byDependencies([ReactModuleId, ReactNativeModuleId, ReactJsxRuntimeModuleId, , , , 2, ,]),
// Dependencies. One in brackets are dynamic or late initialized.
// [React, RN, JSXRuntime, (FlashListExports), (Reanimated), (RNBottomSheet), ImportTracker, (BottomSheetFlashList)]
),
{
includeUninitialized: true,
},
)
if (module) {
// This allows the Proxy instance to be garbage collected
// after the module is initialized.
FlashList = module
gc()
return module
}
},
{
hint: 'object',
},
)!