feat(lib/modules/native): API for calling custom native methods

This commit is contained in:
PalmDevs 2025-08-17 00:55:36 +07:00
parent a9f04b2bc6
commit e689976e28
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA

View file

@ -20,3 +20,71 @@ export function getNativeModule<T>(name: string): T | null {
throw new Error(`Unable to access native module: ${name}`)
}
const Bridge = getNativeModule<{
getBBox(handle: number, options: object): object
}>('RNSVGRenderableModule')!
const BridgePromise = getNativeModule<{
readAsDataURL(map: object): Promise<any>
}>('FileReaderModule')!
/**
* HashMap conversion in native would make you lose the order of the arguments once the keys get more complicated than a single character
*/
function guardMaxArgs(args: any[]) {
if (args.length > 9)
throw new Error(
'Passing more than 9 arguments to a native method is not supported.',
)
}
/**
* Calls a method on the native module and returns a promise that resolves with the result.
*
* @param name The name of the native method to call.
* @param args The arguments to pass to the native method.
* @returns A promise that resolves with the result of the native method call.
*/
export async function callMethod<T>(name: string, args: any[]): Promise<T> {
guardMaxArgs(args)
const result = await BridgePromise.readAsDataURL({
revenge: name,
...args,
})
if ('error' in result)
throw new Error(`Call failed: ${result.error as string}`)
if ('result' in result) return result.result as T
throw new Error(
'Call failed: The module did not return a valid result. The native hook must have failed.',
)
}
/**
* Calls a method on the native module synchronously and returns the result.
*
* Only use synchronous methods when absolutely necessary, as they block JS execution until the native method returns.
*
* @param name The name of the native method to call.
* @param args The arguments to pass to the native method.
* @returns The result of the native method call.
*/
export function callMethodSync<T>(name: string, args: any[]): T {
guardMaxArgs(args)
try {
const result = Bridge.getBBox(0, { ...args, revenge: name })
if ('error' in result) throw result.error
if ('result' in result) return result.result as T
throw 'The module did not return a valid result. The native hook must have failed.'
} catch (error) {
throw new Error(
`Call failed: ${error instanceof Error ? error.message : String(error)}`,
)
}
}