import { HEAPSDKPayload, Heap, HeapLogger, InvocationHandler, SourceInfo, SourceManager, createBridgeInvocationHandler, createHeap, createLogger, isHeapSDKInvocation, } from '@heap/heap-javascript-bridge-support'; import type { CodegenTypes, NativeEventEmitter, NativeModule, Platform } from 'react-native'; type ResultHandler = (callbackId: string, data: any, error: string | undefined) => void; interface HeapReactNativeBridge extends NativeModule { handleInvocation?: InvocationHandler; handleResult?: ResultHandler; invocation?: CodegenTypes.EventEmitter; } import { version } from './version'; type NativeEventEmitterConstructor = new (nativeModule?: NativeModule) => NativeEventEmitter; function extractReactNativeVersion(Platform: Platform | undefined): string | null { const v = Platform?.constants?.reactNativeVersion; if (v) { return `${v.major}.${v.minor}.${v.patch}`; } else { return null; } } const message = ` Failed to find a suitable bridge for CSQ autocapture. All operations will be ignored. This usually means that the Native Bridge module has not been built into the project. If you are using Expo Go this issue will resolve itself when you eject the app. `.trim(); const createNoopBridge = (): InvocationHandler => { let logged = false; return () => { if (!logged) { logged = true; console.warn(message); } return Promise.resolve(null); }; }; export const createReactNativeHeap = ( HeapReactNativeBridge: HeapReactNativeBridge | undefined, Platform: Platform | undefined, NativeEventEmitter: NativeEventEmitterConstructor, ): [Heap, HeapLogger] => { const sourceInfo: SourceInfo = { name: 'react_native_bridge', version, platform: `React Native ${extractReactNativeVersion(Platform) || '(unknown version)'}`, }; const handleInvocation = HeapReactNativeBridge?.handleInvocation ?? createNoopBridge(); const handleResult = HeapReactNativeBridge?.handleResult; const logger = createLogger(handleInvocation); const sourceManager = new SourceManager(logger); if (handleResult) { const bridgeInvocationHandler = createBridgeInvocationHandler(sourceManager, logger); if (HeapReactNativeBridge?.invocation && typeof HeapReactNativeBridge.invocation === 'function') { HeapReactNativeBridge.invocation(async (event) => { if (isHeapSDKInvocation(event)) { const result = await bridgeInvocationHandler(event); if (result) { handleResult(result.callbackId, result.data, result.error); } } }); } else { const eventEmitter = new NativeEventEmitter(HeapReactNativeBridge); eventEmitter.addListener('Invocation', async (event) => { if (isHeapSDKInvocation(event)) { const result = await bridgeInvocationHandler(event); if (result) { handleResult(result.callbackId, result.data, result.error); } } }); } } const heap = createHeap(handleInvocation, logger, sourceInfo, sourceManager); return [heap, logger]; };