/** * ErrorCapture — hooks into the RN global error handler and unhandled promise * rejections to automatically forward errors to BugCollect.captureError. */ // React Native exposes ErrorUtils on the global object declare const ErrorUtils: { getGlobalHandler(): ((error: Error, isFatal?: boolean) => void) | null setGlobalHandler(handler: (error: Error, isFatal?: boolean) => void): void } // React Native / Hermes exposes onunhandledrejection on globalThis type UnhandledRejectionHandler = ((event: { reason: unknown }) => void) | null | undefined let previousErrorHandler: ((error: Error, isFatal?: boolean) => void) | null = null let previousUnhandledHandler: UnhandledRejectionHandler = null let started = false export const ErrorCapture = { start(onError: (error: unknown, meta?: Record) => void): void { if (started) return started = true // JS global error handler previousErrorHandler = typeof ErrorUtils !== 'undefined' ? ErrorUtils.getGlobalHandler() : null if (typeof ErrorUtils !== 'undefined') { ErrorUtils.setGlobalHandler((error, isFatal) => { onError(error, { isFatal: isFatal ?? false }) previousErrorHandler?.(error, isFatal) }) } // Unhandled Promise rejection const g = globalThis as unknown as Record previousUnhandledHandler = (g['onunhandledrejection'] as UnhandledRejectionHandler) ?? null g['onunhandledrejection'] = (event: { reason: unknown }) => { onError(event.reason, { type: 'unhandledRejection' }) previousUnhandledHandler?.(event) } }, stop(): void { if (!started) return if (typeof ErrorUtils !== 'undefined') { ErrorUtils.setGlobalHandler(previousErrorHandler ?? (() => undefined)) } const g = globalThis as unknown as Record g['onunhandledrejection'] = previousUnhandledHandler ?? null previousErrorHandler = null previousUnhandledHandler = null started = false }, }