Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/app/lib/internal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export * from './registry/namespace';
export * from './registry/nativeModule';
export { default as SharedEventEmitter } from './SharedEventEmitter';
export { Logger } from './logger';
export type { ModuleConfig } from '../types/internal';
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,48 @@
*
*/

import { firebase } from '@react-native-firebase/app';
import { firebase } from '.';
import { isError, once } from '@react-native-firebase/app/lib/common';
// @ts-ignore - No declaration file for promise/setimmediate/rejection-tracking
import tracking from 'promise/setimmediate/rejection-tracking';
import StackTrace from 'stacktrace-js';

export const FATAL_FLAG = 'com.firebase.crashlytics.reactnative.fatal';

export function createNativeErrorObj(error, stackFrames, isUnhandledRejection, jsErrorName) {
const nativeObj = {};
interface NativeErrorFrame {
src: string;
line: number;
col: number;
fn: string;
file: string;
}

interface NativeErrorObj {
message: string;
isUnhandledRejection: boolean;
frames: NativeErrorFrame[];
}

nativeObj.message = `${error.message}`;
nativeObj.isUnhandledRejection = isUnhandledRejection;
interface NativeModule {
isCrashlyticsCollectionEnabled: boolean;
isErrorGenerationOnJSCrashEnabled: boolean;
isCrashlyticsJavascriptExceptionHandlerChainingEnabled: boolean;
logPromise(message: string): Promise<void>;
setAttribute(name: string, value: string): Promise<void>;
recordErrorPromise(errorObj: NativeErrorObj): Promise<void>;
crashWithStackPromise(errorObj: NativeErrorObj): Promise<void>;
}

nativeObj.frames = [];
export function createNativeErrorObj(
error: Error,
stackFrames: StackTrace.StackFrame[],
isUnhandledRejection: boolean,
jsErrorName?: string,
): NativeErrorObj {
const nativeObj: NativeErrorObj = {
message: `${error.message}`,
isUnhandledRejection,
frames: [],
};

if (jsErrorName) {
// Option to fix crashlytics display and alerting. You can add an error name to the recordError function
Expand All @@ -42,7 +70,10 @@ export function createNativeErrorObj(error, stackFrames, isUnhandledRejection, j
}

for (let i = 0; i < stackFrames.length; i++) {
const { columnNumber, lineNumber, fileName, functionName, source } = stackFrames[i];
const frame = stackFrames[i];
if (!frame) continue;

const { columnNumber, lineNumber, fileName, functionName, source } = frame;
let fileNameParsed = '<unknown>';
if (fileName) {
const subStrLen = fileName.indexOf('?');
Expand All @@ -54,7 +85,7 @@ export function createNativeErrorObj(error, stackFrames, isUnhandledRejection, j
}

nativeObj.frames.push({
src: source,
src: source || '<unknown>',
line: lineNumber || 0,
col: columnNumber || 0,
fn: functionName || '<unknown>',
Expand All @@ -65,10 +96,10 @@ export function createNativeErrorObj(error, stackFrames, isUnhandledRejection, j
return nativeObj;
}

export const setGlobalErrorHandler = once(nativeModule => {
export const setGlobalErrorHandler = once((nativeModule: NativeModule) => {
const originalHandler = ErrorUtils.getGlobalHandler();

async function handler(error, fatal) {
async function handler(error: unknown, fatal?: boolean) {
// If collection is disabled, just forward to the original handler
if (!nativeModule.isCrashlyticsCollectionEnabled) {
return originalHandler(error, fatal);
Expand All @@ -89,7 +120,7 @@ export const setGlobalErrorHandler = once(nativeModule => {
// For that reason we always round up (`.ceil`) and add a second in case of latency
//
// Time is specified as seconds since start of Unix epoch as a baseline, as a string
const fatalTime = Math.ceil(new Date() / 1000) + 1 + '';
const fatalTime = Math.ceil(new Date().getTime() / 1000) + 1 + '';

// Flag the Crashlytics backend that we have a fatal error, they will transform it
await nativeModule.setAttribute(FATAL_FLAG, fatalTime);
Expand All @@ -107,6 +138,7 @@ export const setGlobalErrorHandler = once(nativeModule => {
// Did not matter if I did named imports above or dynamic require here.
// So temporarily reverting and silencing warnings instead
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = true;
// @ts-ignore - analytics types not available in crashlytics
await firebase.app().analytics().logEvent(
'app_exception', // 'app_exception' is reserved but we make an exception for JS->fatal transforms
{
Expand Down Expand Up @@ -143,8 +175,8 @@ export const setGlobalErrorHandler = once(nativeModule => {
return handler;
});

export const setOnUnhandledPromiseRejectionHandler = once(nativeModule => {
async function onUnhandled(_id, error) {
export const setOnUnhandledPromiseRejectionHandler = once((nativeModule: NativeModule) => {
async function onUnhandled(_id: number, error: Error) {
if (!__DEV__) {
// TODO(salakar): Option to disable
try {
Expand Down
Loading
Loading