brick-module
Version:
Better React Native native module development
106 lines (104 loc) • 3.72 kB
JavaScript
import { BrickError } from "./BrickError.js";
import { TurboModuleRegistry } from "react-native";
//#region src/BrickModule.ts
const moduleCache = /* @__PURE__ */ new Map();
let nativeModule = null;
/**
* Gets the native TurboModule instance
* @private
*/
function getNativeModule() {
if (!nativeModule) nativeModule = TurboModuleRegistry.getEnforcing("BrickModule");
return nativeModule;
}
/**
* Gets a typed module instance by name with explicit type parameter
* @param moduleName - The exact name of the module as defined in its spec
* @returns Typed module interface with all methods, constants, and event listeners
*/
function get(moduleName) {
const cacheKey = moduleName;
if (moduleCache.has(cacheKey)) return moduleCache.get(cacheKey);
const nativeModuleInstance = getNativeModule();
let constantsCache = null;
const moduleProxy = new Proxy({}, {
get: (_target, property) => {
if (typeof property !== "string") return;
if (property.startsWith("on") && property.length > 2 && property[2] === property[2].toUpperCase()) return (listener) => {
const nativeEventMethod = `${moduleName}_${property}`;
const nativeFn = nativeModuleInstance[nativeEventMethod];
if (typeof nativeFn === "function") return nativeFn(listener);
throw new Error(`${nativeEventMethod} is not available. Did you run RN codegen?`);
};
if (property === "getConstants") return () => {
if (constantsCache !== null) return constantsCache;
const allConstants = nativeModuleInstance?.getConstants?.() ?? {};
const moduleConstants = {};
const constantPrefix = `${moduleName}_`;
for (const key in allConstants) if (key.startsWith(constantPrefix)) {
const propName = key.substring(constantPrefix.length);
moduleConstants[propName] = allConstants[key];
}
constantsCache = moduleConstants;
return moduleConstants;
};
return (...args) => {
const methodKey = `${moduleName}_${property}`;
if (typeof nativeModuleInstance[methodKey] === "function") {
const result = nativeModuleInstance[methodKey](...args);
if (result && typeof result === "object" && result["~sync"] === true) if (result.success === true) return result.value;
else {
const errorInfo = result.error || {};
const message = errorInfo.message || errorInfo.errorMessage || "Unknown error";
const code = errorInfo.code || errorInfo.errorCode || "BRICK_ERROR";
const userInfo = { code };
for (const key of Object.keys(errorInfo)) if (key !== "code" && key !== "message" && key !== "errorCode" && key !== "errorMessage") userInfo[key] = errorInfo[key];
throw new BrickError(message, code, userInfo, moduleName);
}
if (result && typeof result.then === "function") return result.catch((error) => {
throw BrickError.from(error, moduleName);
});
return result;
}
throw new Error(`Method ${methodKey} not found`);
};
},
has: (_target, property) => {
return typeof property === "string";
},
ownKeys: (_target) => {
return [];
}
});
moduleCache.set(cacheKey, moduleProxy);
return moduleProxy;
}
/**
* Gets list of all registered modules
* @returns Promise resolving to array of module names
*/
function getRegisteredModules() {
return getNativeModule()?.getRegisteredModules() ?? [];
}
/**
* Clears the module cache (useful for testing or hot reloading)
* @internal
*/
function clearCache() {
moduleCache.clear();
}
/**
* Main Brick Module API object
* Provides type-safe access to native modules
*/
const BrickModule = {
get,
getRegisteredModules,
clearCache
};
/**
* Default export for convenience
*/
var BrickModule_default = BrickModule;
//#endregion
export { BrickModule_default as default };