2025-10-29 19:34:38 +07:00
import { lookupModules , waitForModules } from '@revenge-mod/modules/finders'
2025-07-13 19:29:44 +07:00
import {
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
withDependencies ,
withName ,
withProps ,
2025-07-13 19:29:44 +07:00
} from '@revenge-mod/modules/finders/filters'
2025-07-17 16:55:08 +07:00
import {
mInitializingId ,
mUninitialized ,
} from '@revenge-mod/modules/metro/patches'
2025-05-09 19:05:31 +07:00
import { getModuleDependencies } from '@revenge-mod/modules/metro/utils'
2025-07-13 18:10:12 +07:00
import { proxify } from '@revenge-mod/utils/proxy'
2025-07-13 19:52:32 +07:00
import { aOverrides } from './_internal'
2025-08-19 22:05:24 +07:00
import { cache , cacheAsset , Uncached } from './caches'
2025-08-04 09:41:18 +07:00
import type { Metro } from '@revenge-mod/modules/types'
2025-05-08 23:41:55 +07:00
import type { ReactNative } from '@revenge-mod/react/types'
2025-06-07 15:14:28 +07:00
import type { Asset , PackagerAsset } from './types'
2025-05-08 23:41:55 +07:00
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
const { relative } = withDependencies
2025-07-13 19:29:44 +07:00
// https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Image/AssetSourceResolver.js
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
const withAssetSourceResolver = withDependencies ( [
2025-10-29 19:34:38 +07:00
withName ( '_classCallCheck' ) ,
withName ( '_createClass' ) ,
2025-07-13 19:29:44 +07:00
relative ( 1 ) ,
relative ( 2 ) ,
2025-08-25 20:55:01 +07:00
null ,
null ,
2025-07-13 19:29:44 +07:00
] )
2025-07-13 18:10:12 +07:00
2025-07-31 19:15:08 +07:00
const cachedOnly = { cached : true }
2025-05-08 23:41:55 +07:00
// Tracking/caching assets
2025-06-03 16:24:58 +07:00
const unsubAR = waitForModules (
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
withProps < ReactNative.AssetsRegistry > ( 'registerAsset' ) ,
2025-06-03 16:24:58 +07:00
( exports , id ) = > {
2025-06-07 15:14:28 +07:00
AssetsRegistryModuleId = id
AssetsRegistry = exports as ReactNative . AssetsRegistry
2025-06-03 16:24:58 +07:00
// 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.
2025-05-08 23:41:55 +07:00
2025-06-03 16:24:58 +07:00
// 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 ( )
2025-05-08 23:41:55 +07:00
2025-08-19 22:05:24 +07:00
if ( cache === Uncached ) {
// Resolve reference once and keep in closure
const metroRequire = __r
2025-08-22 02:37:18 +07:00
2025-08-19 22:05:24 +07:00
// 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 mUninitialized ) {
if ( mId < firstAssetModuleId ) continue
2025-06-08 21:37:54 +07:00
2025-08-19 22:05:24 +07:00
const deps = getModuleDependencies ( mId ) !
if ( deps . length === 1 && deps [ 0 ] === id ) metroRequire ( mId )
2025-06-08 21:37:54 +07:00
}
2025-08-19 22:05:24 +07:00
}
2025-05-08 23:41:55 +07:00
2025-06-03 16:24:58 +07:00
// We already patched the original asset registry, so we don't need to patch again.
return
2025-05-08 23:41:55 +07:00
}
2025-06-03 16:24:58 +07:00
const orig = exports . registerAsset
exports . registerAsset = ( asset : Asset ) = > {
2025-06-07 15:14:28 +07:00
const result = orig ( asset as PackagerAsset )
2025-05-08 23:41:55 +07:00
2025-06-07 15:14:28 +07:00
// Cache and set moduleId for packager assets only
if ( ( asset as PackagerAsset ) . __packager_asset ) {
2025-07-30 20:17:12 +07:00
asset . moduleId = mInitializingId
2025-07-05 13:12:57 +07:00
cacheAsset ( asset , mInitializingId ! )
2025-06-03 16:24:58 +07:00
}
2025-05-08 23:41:55 +07:00
2025-06-07 15:14:28 +07:00
return ( asset . id = result )
2025-05-08 23:41:55 +07:00
}
2025-06-03 16:24:58 +07:00
} ,
2025-07-31 19:15:08 +07:00
cachedOnly ,
2025-06-03 16:24:58 +07:00
)
2025-05-08 23:41:55 +07:00
2025-07-14 09:54:23 +07:00
/ * *
2026-08-01 14:49:54 +07:00
* If you need to use this ID during ` preInit ` , unproxify { @link AssetsRegistry } first .
2025-07-14 09:54:23 +07:00
*
* ` ` ` js
2026-08-01 14:49:54 +07:00
* preInit() {
2025-08-04 09:41:18 +07:00
* unproxify ( AssetsRegistry )
2025-07-14 09:54:23 +07:00
* // Module ID will now be set!
* AssetsRegistryModuleId // ...
* }
* ` ` `
* /
2025-08-04 09:41:18 +07:00
export let AssetsRegistryModuleId : Metro.ModuleID | undefined
2025-07-14 09:54:23 +07:00
export let AssetsRegistry : ReactNative.AssetsRegistry = proxify ( ( ) = > {
2026-07-28 12:12:22 +07:00
if ( AssetsRegistryModuleId !== undefined ) return __r ( AssetsRegistryModuleId )
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
for ( const [ , id ] of lookupModules ( withDependencies ( [ [ ] ] ) , {
2025-07-14 09:54:23 +07:00
initialize : false ,
} ) ) {
const deps = getModuleDependencies ( id ) !
// The module next to assets-registry is AssetSourceResolver
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
if ( withAssetSourceResolver ( deps [ 0 ] + 1 ) ) {
2025-07-14 09:54:23 +07:00
const module = __r ( id )
// ID will be set by the wait below
if ( module ? . registerAsset ) return ( AssetsRegistry = module )
}
}
throw new Error ( 'assets-registry not found' )
} )
2026-01-24 18:13:45 +07:00
// TODO: Native overrides?
2025-05-08 23:41:55 +07:00
// Asset overrides
const unsubRAS = waitForModules (
feat!: module finders refactor (#6)
- Renamed `byX` filters to `withX`.
It is more correct. For example: You don't lookup, wait for, or get modules **BY** props. You lookup, wait for, and get modules **WITH** props.
- Renamed `*byImportedPath` to `*withImportedPath`
For consistency with the above change.
- Renamed `getModule` to `getModules`.
The API allows getting multiple modules and not just a single one. Types are renamed as well.
`getModuleByImportedPath` remains the same as it only gets one single module with a unique imported path.
- `withX` filter **helpers** removed.
They can now be replaced with the new capability-based `and` filter.
- `preferExports` and `moduleStateAware` filters removed.
They can now be replaced with the new capability-based `and` filter.
- Composite finders renamed.
`some` -> `or`, `every` -> `and`
- Composite finders takes a capability-based approach.
- Filter generators now need to attach runtime flag to let the system know whether the generated filter can be used to filter modules without proper exports or not.
## Misc.
- Removed useless unsub call in Profile Badges
- Use `queueMicrotask` with `asap`
# Features
## Capability-based approach to composite filters
```js
// Old
byProps(...).withDependencies(...)
// Old, same as: preferExports(byProps(...), byDependencies(...))
every(byDependencies(...), byProps(...))
// Old, ordering matters, this would fail unexpectedly!
every(byProps(...), byDependencies(...))
// New
withProps(...).and(withDependencies(...))
// New (as well), ordering doesn't matter, this has the same result as above
withDependencies(...).and(withProps(...))
```
2025-08-30 09:19:57 +07:00
withName < {
2025-06-03 16:24:58 +07:00
addCustomSourceTransformer : (
2025-06-07 15:14:28 +07:00
transformer : ( arg : { asset : Asset } ) = > PackagerAsset ,
2025-06-03 16:24:58 +07:00
) = > void
2025-05-08 23:41:55 +07:00
} > ( 'resolveAssetSource' ) ,
2025-05-18 22:24:48 +07:00
rAS = > {
2025-05-08 23:41:55 +07:00
unsubRAS ( )
// Custom assets
2025-06-02 15:56:07 +07:00
// Why do we need to do this? Because RN/Discord (unsure which) will attempt to resolve the asset via its path, which we don't provide via custom assets.
2025-05-08 23:41:55 +07:00
// This will result in a crash, because it tries to read the path and run checks on it, but the path is undefined.
// @ts-expect-error
rAS . addCustomSourceTransformer ( ( { asset } ) = > {
2025-07-01 17:30:53 +07:00
if ( ! ( asset as PackagerAsset ) . __packager_asset ) return asset
2025-05-08 23:41:55 +07:00
} )
// Asset overrides
// @ts-expect-error
2025-07-05 13:12:57 +07:00
rAS . addCustomSourceTransformer ( ( { asset } ) = > aOverrides . get ( asset ) )
2025-05-08 23:41:55 +07:00
} ,
2025-07-31 19:15:08 +07:00
cachedOnly ,
2025-05-08 23:41:55 +07:00
)
2026-01-24 18:13:45 +07:00
if ( cache === Uncached ) {
// Initialize the module immediately, so we can cache assets ASAP
AssetsRegistry . getAssetByID ( 0 )
}