react-native-inapp-inspector 1.1.25 → 1.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +36 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +114 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +28 -0
- package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
- package/dist/commonjs/components/ErrorBoundary.js +9 -145
- package/dist/commonjs/components/Inspector/CrashDetail.d.ts +3 -0
- package/dist/commonjs/components/Inspector/CrashDetail.js +796 -0
- package/dist/commonjs/components/Inspector/CrashFilterModal.d.ts +20 -0
- package/dist/commonjs/components/Inspector/CrashFilterModal.js +597 -0
- package/dist/commonjs/components/Inspector/CrashTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/CrashTab.js +727 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +52 -23
- package/dist/commonjs/components/Inspector/LogDetail.js +4 -3
- package/dist/commonjs/components/Inspector/MainScreen.js +12 -3
- package/dist/commonjs/components/Inspector/SettingsPanel.js +90 -1
- package/dist/commonjs/components/Inspector/TabBar.js +15 -3
- package/dist/commonjs/components/NetworkIcons.d.ts +11 -0
- package/dist/commonjs/components/NetworkIcons.js +96 -1
- package/dist/commonjs/components/SegmentedTabs.js +2 -1
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.js +70 -44
- package/dist/commonjs/customHooks/consoleLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/consoleLogger.js +70 -6
- package/dist/commonjs/customHooks/crashHandler.d.ts +64 -0
- package/dist/commonjs/customHooks/crashHandler.js +681 -0
- package/dist/commonjs/customHooks/networkLogger.js +64 -48
- package/dist/commonjs/helpers/gaAnalyticsRegistry.js +1 -1
- package/dist/commonjs/i18n/locales/en.json +131 -0
- package/dist/commonjs/index.d.ts +3 -1
- package/dist/commonjs/index.js +95 -1
- package/dist/commonjs/types/enums.d.ts +41 -0
- package/dist/commonjs/types/enums.js +37 -1
- package/dist/commonjs/types/interfaces.d.ts +51 -1
- package/dist/esm/components/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/ErrorBoundary.js +10 -113
- package/dist/esm/components/Inspector/CrashDetail.d.ts +3 -0
- package/dist/esm/components/Inspector/CrashDetail.js +758 -0
- package/dist/esm/components/Inspector/CrashFilterModal.d.ts +20 -0
- package/dist/esm/components/Inspector/CrashFilterModal.js +557 -0
- package/dist/esm/components/Inspector/CrashTab.d.ts +3 -0
- package/dist/esm/components/Inspector/CrashTab.js +689 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +52 -23
- package/dist/esm/components/Inspector/LogDetail.js +4 -3
- package/dist/esm/components/Inspector/MainScreen.js +12 -3
- package/dist/esm/components/Inspector/SettingsPanel.js +91 -2
- package/dist/esm/components/Inspector/TabBar.js +16 -4
- package/dist/esm/components/NetworkIcons.d.ts +11 -0
- package/dist/esm/components/NetworkIcons.js +83 -0
- package/dist/esm/components/SegmentedTabs.js +2 -1
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.js +70 -44
- package/dist/esm/customHooks/consoleLogger.d.ts +1 -0
- package/dist/esm/customHooks/consoleLogger.js +68 -5
- package/dist/esm/customHooks/crashHandler.d.ts +64 -0
- package/dist/esm/customHooks/crashHandler.js +659 -0
- package/dist/esm/customHooks/networkLogger.js +64 -48
- package/dist/esm/helpers/gaAnalyticsRegistry.js +1 -1
- package/dist/esm/i18n/locales/en.json +131 -0
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +73 -1
- package/dist/esm/types/enums.d.ts +41 -0
- package/dist/esm/types/enums.js +36 -0
- package/dist/esm/types/interfaces.d.ts +51 -1
- package/ios/NetworkInspectorModule.h +6 -0
- package/ios/NetworkInspectorModule.m +125 -0
- package/package.json +5 -2
- package/react-native-inapp-inspector.podspec +18 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupGlobalCrashHandler = exports.exportCrashReport = exports.simulateTestCrash = exports.recordCustomCrash = exports.handleInterceptedCrash = exports.emitCrashEvent = exports.subscribeCrashEvents = exports.clearCrashRecords = exports.getCrashRecords = exports.computeCrashFingerprint = exports.parseCrashStackTrace = exports.getCrashBreadcrumbs = exports.clearCrashBreadcrumbs = exports.recordUserActionBreadcrumb = exports.recordReduxBreadcrumb = exports.recordNetworkBreadcrumb = exports.recordNavigationBreadcrumb = exports.addCrashBreadcrumb = exports.setMaxCrashLogsLimit = exports.CrashExportFormat = void 0;
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const enums_1 = require("../types/enums");
|
|
6
|
+
Object.defineProperty(exports, "CrashExportFormat", { enumerable: true, get: function () { return enums_1.CrashExportFormat; } });
|
|
7
|
+
const consoleLogger_1 = require("./consoleLogger");
|
|
8
|
+
const i18n_1 = require("../i18n");
|
|
9
|
+
let crashListeners = [];
|
|
10
|
+
let isCrashHandlerInitialized = false;
|
|
11
|
+
let lastHandledErrorTimestamp = 0;
|
|
12
|
+
let crashRecordsStore = [];
|
|
13
|
+
let breadcrumbsStore = [];
|
|
14
|
+
const MAX_BREADCRUMBS = 50;
|
|
15
|
+
let maxStoredCrashes = 100;
|
|
16
|
+
const appStartTime = Date.now();
|
|
17
|
+
// ─── BREADCRUMB MANAGERS ───────────────────────────────────────────────────────
|
|
18
|
+
const setMaxCrashLogsLimit = (max) => {
|
|
19
|
+
maxStoredCrashes = Math.max(10, max);
|
|
20
|
+
if (crashRecordsStore.length > maxStoredCrashes) {
|
|
21
|
+
crashRecordsStore = crashRecordsStore.slice(0, maxStoredCrashes);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
exports.setMaxCrashLogsLimit = setMaxCrashLogsLimit;
|
|
25
|
+
const addCrashBreadcrumb = (type, message, data) => {
|
|
26
|
+
try {
|
|
27
|
+
const entry = {
|
|
28
|
+
type,
|
|
29
|
+
message,
|
|
30
|
+
timestamp: Date.now(),
|
|
31
|
+
data,
|
|
32
|
+
};
|
|
33
|
+
breadcrumbsStore.unshift(entry);
|
|
34
|
+
if (breadcrumbsStore.length > MAX_BREADCRUMBS) {
|
|
35
|
+
breadcrumbsStore = breadcrumbsStore.slice(0, MAX_BREADCRUMBS);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch { }
|
|
39
|
+
};
|
|
40
|
+
exports.addCrashBreadcrumb = addCrashBreadcrumb;
|
|
41
|
+
const recordNavigationBreadcrumb = (fromRoute, toRoute) => {
|
|
42
|
+
(0, exports.addCrashBreadcrumb)('navigation', (0, i18n_1.t)('crash.breadcrumbNavigation', { from: fromRoute || '/', to: toRoute || '/' }), {
|
|
43
|
+
from: fromRoute,
|
|
44
|
+
to: toRoute,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
exports.recordNavigationBreadcrumb = recordNavigationBreadcrumb;
|
|
48
|
+
const recordNetworkBreadcrumb = (url, method, status, duration) => {
|
|
49
|
+
const statusStr = status != null ? ` [${status}]` : '';
|
|
50
|
+
const durStr = duration != null ? ` (${Math.round(duration)}ms)` : '';
|
|
51
|
+
(0, exports.addCrashBreadcrumb)('network', `${method.toUpperCase()} ${url}${statusStr}${durStr}`, {
|
|
52
|
+
url,
|
|
53
|
+
method,
|
|
54
|
+
status,
|
|
55
|
+
duration,
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
exports.recordNetworkBreadcrumb = recordNetworkBreadcrumb;
|
|
59
|
+
const recordReduxBreadcrumb = (actionType, payload) => {
|
|
60
|
+
(0, exports.addCrashBreadcrumb)('redux', (0, i18n_1.t)('crash.breadcrumbAction', { actionType }), {
|
|
61
|
+
type: actionType,
|
|
62
|
+
payloadSummary: typeof payload === 'object' && payload !== null
|
|
63
|
+
? Object.keys(payload)
|
|
64
|
+
: typeof payload,
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
exports.recordReduxBreadcrumb = recordReduxBreadcrumb;
|
|
68
|
+
const recordUserActionBreadcrumb = (action, metadata) => {
|
|
69
|
+
(0, exports.addCrashBreadcrumb)('user', action, metadata);
|
|
70
|
+
};
|
|
71
|
+
exports.recordUserActionBreadcrumb = recordUserActionBreadcrumb;
|
|
72
|
+
const clearCrashBreadcrumbs = () => {
|
|
73
|
+
breadcrumbsStore = [];
|
|
74
|
+
};
|
|
75
|
+
exports.clearCrashBreadcrumbs = clearCrashBreadcrumbs;
|
|
76
|
+
const getCrashBreadcrumbs = () => {
|
|
77
|
+
return [...breadcrumbsStore];
|
|
78
|
+
};
|
|
79
|
+
exports.getCrashBreadcrumbs = getCrashBreadcrumbs;
|
|
80
|
+
// ─── STACK TRACE PARSING & INTELLIGENT SOURCE DETECTION ───────────────────────
|
|
81
|
+
/**
|
|
82
|
+
* Intelligent stack trace parser with multi-engine support:
|
|
83
|
+
* - Hermes bytecode & source maps
|
|
84
|
+
* - Android Java / Kotlin native frames
|
|
85
|
+
* - iOS Objective-C / Swift symbols
|
|
86
|
+
* - JavaScript standard V8 & SpiderMonkey
|
|
87
|
+
*/
|
|
88
|
+
const parseCrashStackTrace = (stack) => {
|
|
89
|
+
if (!stack || typeof stack !== 'string')
|
|
90
|
+
return [];
|
|
91
|
+
const lines = stack.split('\n');
|
|
92
|
+
const frames = [];
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
const trimmed = line.trim();
|
|
95
|
+
if (!trimmed)
|
|
96
|
+
continue;
|
|
97
|
+
// Filter out internal wrapper noise
|
|
98
|
+
if (trimmed.includes('crashHandler.ts') ||
|
|
99
|
+
trimmed.includes('handleInterceptedCrash') ||
|
|
100
|
+
trimmed.includes('addLogFromCrash') ||
|
|
101
|
+
trimmed.includes('setupGlobalCrashHandler')) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Pattern 1: iOS/Hermes format: method@file:line:column or method@url:line:col
|
|
105
|
+
const iosMatch = trimmed.match(/^([^@]+)@(.*):(\d+):(\d+)$/);
|
|
106
|
+
if (iosMatch) {
|
|
107
|
+
const [, method, file, lineNum, colNum] = iosMatch;
|
|
108
|
+
const cleanFile = file.split('?')[0].split('/').pop() || file;
|
|
109
|
+
const isAppCode = !file.includes('node_modules') &&
|
|
110
|
+
!file.includes('react-native') &&
|
|
111
|
+
!file.includes('react-dom') &&
|
|
112
|
+
!file.includes('hermes') &&
|
|
113
|
+
!file.includes('internal');
|
|
114
|
+
frames.push({
|
|
115
|
+
method: method.trim(),
|
|
116
|
+
file: cleanFile,
|
|
117
|
+
lineNumber: parseInt(lineNum, 10),
|
|
118
|
+
column: parseInt(colNum, 10),
|
|
119
|
+
raw: trimmed,
|
|
120
|
+
isAppCode,
|
|
121
|
+
});
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Pattern 2: V8/Android JS format: at method (file:line:column)
|
|
125
|
+
const androidMatch = trimmed.match(/^at\s+(.+)\s+\((.+):(\d+):(\d+)\)$/);
|
|
126
|
+
if (androidMatch) {
|
|
127
|
+
const [, method, file, lineNum, colNum] = androidMatch;
|
|
128
|
+
const cleanFile = file.split('?')[0].split('/').pop() || file;
|
|
129
|
+
const isAppCode = !file.includes('node_modules') &&
|
|
130
|
+
!file.includes('react-native') &&
|
|
131
|
+
!file.includes('react-dom') &&
|
|
132
|
+
!file.includes('internal');
|
|
133
|
+
frames.push({
|
|
134
|
+
method: method.trim(),
|
|
135
|
+
file: cleanFile,
|
|
136
|
+
lineNumber: parseInt(lineNum, 10),
|
|
137
|
+
column: parseInt(colNum, 10),
|
|
138
|
+
raw: trimmed,
|
|
139
|
+
isAppCode,
|
|
140
|
+
});
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Pattern 3: Simple at file:line:column
|
|
144
|
+
const simpleMatch = trimmed.match(/^at\s+(.+):(\d+):(\d+)$/);
|
|
145
|
+
if (simpleMatch) {
|
|
146
|
+
const [, file, lineNum, colNum] = simpleMatch;
|
|
147
|
+
const cleanFile = file.split('?')[0].split('/').pop() || file;
|
|
148
|
+
const isAppCode = !file.includes('node_modules') && !file.includes('react-native');
|
|
149
|
+
frames.push({
|
|
150
|
+
method: '<anonymous>',
|
|
151
|
+
file: cleanFile,
|
|
152
|
+
lineNumber: parseInt(lineNum, 10),
|
|
153
|
+
column: parseInt(colNum, 10),
|
|
154
|
+
raw: trimmed,
|
|
155
|
+
isAppCode,
|
|
156
|
+
});
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
// Pattern 4: Java / Android Native Frame: at com.pkg.Class.method(Class.java:123)
|
|
160
|
+
const javaMatch = trimmed.match(/^at\s+([a-zA-Z0-9_$.]+)\(([a-zA-Z0-9_$]+\.java):(\d+)\)$/);
|
|
161
|
+
if (javaMatch) {
|
|
162
|
+
const [, methodPath, fileName, lineNum] = javaMatch;
|
|
163
|
+
const isAppCode = !methodPath.startsWith('com.facebook.react') &&
|
|
164
|
+
!methodPath.startsWith('android.');
|
|
165
|
+
frames.push({
|
|
166
|
+
method: methodPath,
|
|
167
|
+
file: fileName,
|
|
168
|
+
lineNumber: parseInt(lineNum, 10),
|
|
169
|
+
column: 0,
|
|
170
|
+
raw: trimmed,
|
|
171
|
+
isAppCode,
|
|
172
|
+
});
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
// Pattern 5: iOS Mach-O Symbol: 0 AppName 0x000000010... -[ViewController method] + 48
|
|
176
|
+
const machOMatch = trimmed.match(/^\d+\s+([^\s]+)\s+(0x[0-9a-fA-F]+)\s+(.+)$/);
|
|
177
|
+
if (machOMatch) {
|
|
178
|
+
const [, binaryName, address, symbol] = machOMatch;
|
|
179
|
+
const isAppCode = !binaryName.startsWith('lib') &&
|
|
180
|
+
!binaryName.startsWith('Core') &&
|
|
181
|
+
!binaryName.startsWith('React');
|
|
182
|
+
frames.push({
|
|
183
|
+
method: symbol,
|
|
184
|
+
file: binaryName,
|
|
185
|
+
lineNumber: 0,
|
|
186
|
+
column: 0,
|
|
187
|
+
raw: trimmed,
|
|
188
|
+
isAppCode,
|
|
189
|
+
});
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
// Pattern 6: Fallback for generic frame lines
|
|
193
|
+
frames.push({
|
|
194
|
+
method: trimmed.startsWith('at ') ? trimmed.slice(3) : trimmed,
|
|
195
|
+
file: 'runtime',
|
|
196
|
+
lineNumber: 0,
|
|
197
|
+
column: 0,
|
|
198
|
+
raw: trimmed,
|
|
199
|
+
isAppCode: false,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return frames;
|
|
203
|
+
};
|
|
204
|
+
exports.parseCrashStackTrace = parseCrashStackTrace;
|
|
205
|
+
// ─── DIAGNOSTICS & SYSTEM METRICS ─────────────────────────────────────────────
|
|
206
|
+
const getMemoryDiagnostics = () => {
|
|
207
|
+
try {
|
|
208
|
+
const performance = globalThis.performance;
|
|
209
|
+
if (performance && performance.memory) {
|
|
210
|
+
return {
|
|
211
|
+
usedJSHeapSize: Math.round(performance.memory.usedJSHeapSize / (1024 * 1024)),
|
|
212
|
+
totalJSHeapSize: Math.round(performance.memory.totalJSHeapSize / (1024 * 1024)),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch { }
|
|
217
|
+
return undefined;
|
|
218
|
+
};
|
|
219
|
+
const getScreenDimensions = () => {
|
|
220
|
+
try {
|
|
221
|
+
const window = react_native_1.Dimensions.get('window');
|
|
222
|
+
return `${Math.round(window.width)}x${Math.round(window.height)} (${window.scale}x)`;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return (0, i18n_1.t)('crash.unknown');
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Computes a unique fingerprint signature to group recurring crash occurrences.
|
|
230
|
+
*/
|
|
231
|
+
const computeCrashFingerprint = (crash) => {
|
|
232
|
+
const type = crash.type || 'js';
|
|
233
|
+
const name = crash.name || 'Error';
|
|
234
|
+
const topFrame = crash.parsedStack && crash.parsedStack.length > 0
|
|
235
|
+
? crash.parsedStack[0]
|
|
236
|
+
: null;
|
|
237
|
+
const location = topFrame
|
|
238
|
+
? `${topFrame.file}:${topFrame.lineNumber}`
|
|
239
|
+
: 'unknown';
|
|
240
|
+
return `${type}_${name}_${location}`;
|
|
241
|
+
};
|
|
242
|
+
exports.computeCrashFingerprint = computeCrashFingerprint;
|
|
243
|
+
// ─── CRASH RECORD MANAGEMENT & INTERCEPTION ───────────────────────────────────
|
|
244
|
+
const getCrashRecords = () => {
|
|
245
|
+
return [...crashRecordsStore];
|
|
246
|
+
};
|
|
247
|
+
exports.getCrashRecords = getCrashRecords;
|
|
248
|
+
const clearCrashRecords = () => {
|
|
249
|
+
crashRecordsStore = [];
|
|
250
|
+
(0, exports.emitCrashEvent)({
|
|
251
|
+
error: null,
|
|
252
|
+
message: '__CLEARED__',
|
|
253
|
+
timestamp: Date.now(),
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
exports.clearCrashRecords = clearCrashRecords;
|
|
257
|
+
const subscribeCrashEvents = (listener) => {
|
|
258
|
+
crashListeners.push(listener);
|
|
259
|
+
return () => {
|
|
260
|
+
crashListeners = crashListeners.filter(l => l !== listener);
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
exports.subscribeCrashEvents = subscribeCrashEvents;
|
|
264
|
+
const emitCrashEvent = (payload) => {
|
|
265
|
+
if (payload.message !== '__CLEARED__') {
|
|
266
|
+
const now = Date.now();
|
|
267
|
+
// Throttle duplicate rapid crash emissions within 250ms
|
|
268
|
+
if (now - lastHandledErrorTimestamp < 250) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
lastHandledErrorTimestamp = now;
|
|
272
|
+
}
|
|
273
|
+
crashListeners.forEach(listener => {
|
|
274
|
+
try {
|
|
275
|
+
listener(payload);
|
|
276
|
+
}
|
|
277
|
+
catch { }
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
exports.emitCrashEvent = emitCrashEvent;
|
|
281
|
+
/**
|
|
282
|
+
* Core exception interceptor. Ingests all forms of errors, parses call stacks,
|
|
283
|
+
* collects device telemetry, records breadcrumbs, and updates the store.
|
|
284
|
+
*/
|
|
285
|
+
const handleInterceptedCrash = (errorOrTitle, rawStack, isFatal = false, customType, componentStack) => {
|
|
286
|
+
try {
|
|
287
|
+
const errorObj = errorOrTitle instanceof Error
|
|
288
|
+
? errorOrTitle
|
|
289
|
+
: typeof errorOrTitle === 'object' && errorOrTitle !== null
|
|
290
|
+
? errorOrTitle
|
|
291
|
+
: new Error(String(errorOrTitle || (0, i18n_1.t)('crash.runtimeException')));
|
|
292
|
+
const rawMsg = errorObj.message ||
|
|
293
|
+
(typeof errorOrTitle === 'string' ? errorOrTitle : (0, i18n_1.t)('crash.runtimeException'));
|
|
294
|
+
let stackString = '';
|
|
295
|
+
if (typeof rawStack === 'string') {
|
|
296
|
+
stackString = rawStack;
|
|
297
|
+
}
|
|
298
|
+
else if (Array.isArray(rawStack)) {
|
|
299
|
+
stackString = rawStack
|
|
300
|
+
.map(f => `at ${f.methodName || '<anonymous>'} (${f.file || 'unknown'}:${f.lineNumber || 0}:${f.column || 0})`)
|
|
301
|
+
.join('\n');
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
stackString = errorObj.stack || new Error().stack || '';
|
|
305
|
+
}
|
|
306
|
+
// Determine Crash Type
|
|
307
|
+
let inferredType = customType || enums_1.CrashType.Js;
|
|
308
|
+
const lowMsg = rawMsg.toLowerCase();
|
|
309
|
+
if (!customType) {
|
|
310
|
+
if (lowMsg.includes('native') ||
|
|
311
|
+
lowMsg.includes('sigsegv') ||
|
|
312
|
+
lowMsg.includes('nsrange') ||
|
|
313
|
+
lowMsg.includes('nullpointerexception') ||
|
|
314
|
+
lowMsg.includes('fatal signal')) {
|
|
315
|
+
inferredType = enums_1.CrashType.Native;
|
|
316
|
+
}
|
|
317
|
+
else if (lowMsg.includes('promise') ||
|
|
318
|
+
lowMsg.includes('unhandled rejection') ||
|
|
319
|
+
lowMsg.includes('unhandledrejection')) {
|
|
320
|
+
inferredType = enums_1.CrashType.Promise;
|
|
321
|
+
}
|
|
322
|
+
else if (lowMsg.includes('render') ||
|
|
323
|
+
lowMsg.includes('errorboundary') ||
|
|
324
|
+
componentStack) {
|
|
325
|
+
inferredType = enums_1.CrashType.Render;
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
inferredType = enums_1.CrashType.Js;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const now = new Date();
|
|
332
|
+
const dateStr = now.toLocaleDateString();
|
|
333
|
+
const timeStr = now.toLocaleTimeString();
|
|
334
|
+
const parsedStack = (0, exports.parseCrashStackTrace)(stackString);
|
|
335
|
+
const log = (0, consoleLogger_1.addLogFromCrash)(errorObj, `[${isFatal ? (0, i18n_1.t)('crash.logFatalCrash') : (0, i18n_1.t)('crash.logUnhandledError')}] ${rawMsg}`, stackString, isFatal);
|
|
336
|
+
const isHermes = typeof globalThis.HermesInternal !== 'undefined';
|
|
337
|
+
const isFabric = typeof globalThis.nativeFabricUIManager !== 'undefined';
|
|
338
|
+
const crashRecord = {
|
|
339
|
+
id: `crash_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
|
|
340
|
+
error: errorObj,
|
|
341
|
+
isFatal,
|
|
342
|
+
type: inferredType,
|
|
343
|
+
message: rawMsg,
|
|
344
|
+
name: errorObj.name || (isFatal ? (0, i18n_1.t)('crash.errorNameFatal') : (0, i18n_1.t)('crash.errorNameUnhandled')),
|
|
345
|
+
stack: stackString,
|
|
346
|
+
parsedStack,
|
|
347
|
+
componentStack: componentStack || undefined,
|
|
348
|
+
timestamp: Date.now(),
|
|
349
|
+
dateStr,
|
|
350
|
+
timeStr,
|
|
351
|
+
deviceInfo: {
|
|
352
|
+
platform: react_native_1.Platform.OS,
|
|
353
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
354
|
+
rnVersion: react_native_1.Platform.constants?.reactNativeVersion
|
|
355
|
+
? `${react_native_1.Platform.constants.reactNativeVersion.major}.${react_native_1.Platform.constants.reactNativeVersion.minor}.${react_native_1.Platform.constants.reactNativeVersion.patch}`
|
|
356
|
+
: (0, i18n_1.t)('crash.unknown'),
|
|
357
|
+
isHermes,
|
|
358
|
+
isFabric,
|
|
359
|
+
appState: react_native_1.AppState.currentState || 'active',
|
|
360
|
+
},
|
|
361
|
+
memoryInfo: getMemoryDiagnostics(),
|
|
362
|
+
breadcrumbs: [...breadcrumbsStore],
|
|
363
|
+
logId: log?.id,
|
|
364
|
+
};
|
|
365
|
+
crashRecordsStore.unshift(crashRecord);
|
|
366
|
+
if (crashRecordsStore.length > maxStoredCrashes) {
|
|
367
|
+
crashRecordsStore = crashRecordsStore.slice(0, maxStoredCrashes);
|
|
368
|
+
}
|
|
369
|
+
(0, exports.emitCrashEvent)({
|
|
370
|
+
error: errorObj,
|
|
371
|
+
isFatal,
|
|
372
|
+
message: `[${isFatal ? (0, i18n_1.t)('crash.logFatalCrash') : (0, i18n_1.t)('crash.logUnhandledError')}] ${rawMsg}`,
|
|
373
|
+
stack: stackString,
|
|
374
|
+
timestamp: Date.now(),
|
|
375
|
+
logId: log?.id,
|
|
376
|
+
crashRecord,
|
|
377
|
+
});
|
|
378
|
+
return crashRecord;
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
const fallbackRecord = {
|
|
382
|
+
id: `crash_${Date.now()}`,
|
|
383
|
+
isFatal: true,
|
|
384
|
+
type: enums_1.CrashType.Js,
|
|
385
|
+
message: String(errorOrTitle || (0, i18n_1.t)('crash.unknownException')),
|
|
386
|
+
timestamp: Date.now(),
|
|
387
|
+
dateStr: new Date().toLocaleDateString(),
|
|
388
|
+
timeStr: new Date().toLocaleTimeString(),
|
|
389
|
+
};
|
|
390
|
+
return fallbackRecord;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
exports.handleInterceptedCrash = handleInterceptedCrash;
|
|
394
|
+
/**
|
|
395
|
+
* Manually report a caught error with custom metadata.
|
|
396
|
+
*/
|
|
397
|
+
const recordCustomCrash = (error, options) => {
|
|
398
|
+
return (0, exports.handleInterceptedCrash)(error, typeof error === 'object' ? error.stack : undefined, options?.isFatal ?? false, options?.type || enums_1.CrashType.Custom, options?.componentStack);
|
|
399
|
+
};
|
|
400
|
+
exports.recordCustomCrash = recordCustomCrash;
|
|
401
|
+
/**
|
|
402
|
+
* Simulates a crash for developer testing without crashing the host app.
|
|
403
|
+
* Uses real runtime Error objects — no mocked file paths or fake stacks.
|
|
404
|
+
*/
|
|
405
|
+
const simulateTestCrash = (type = enums_1.CrashType.Js, customMessage, customStack) => {
|
|
406
|
+
const err = new Error(customMessage || _defaultSimMessage(type));
|
|
407
|
+
return (0, exports.handleInterceptedCrash)(type === enums_1.CrashType.Native ? err.message : err, customStack || err.stack, type === enums_1.CrashType.Native, type, type === enums_1.CrashType.Render ? _buildComponentStack() : undefined);
|
|
408
|
+
};
|
|
409
|
+
exports.simulateTestCrash = simulateTestCrash;
|
|
410
|
+
/** Generates a generic error message per type — no fake references. */
|
|
411
|
+
const _defaultSimMessage = (type) => {
|
|
412
|
+
switch (type) {
|
|
413
|
+
case 'native':
|
|
414
|
+
return (0, i18n_1.t)('crash.simNativeMessage');
|
|
415
|
+
case 'promise':
|
|
416
|
+
return (0, i18n_1.t)('crash.simPromiseMessage');
|
|
417
|
+
case 'render':
|
|
418
|
+
return (0, i18n_1.t)('crash.simRenderMessage');
|
|
419
|
+
default:
|
|
420
|
+
return (0, i18n_1.t)('crash.simJsMessage');
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
/** Builds a component stack from the real React tree if possible. */
|
|
424
|
+
const _buildComponentStack = () => {
|
|
425
|
+
try {
|
|
426
|
+
const err = new Error();
|
|
427
|
+
if (err.stack) {
|
|
428
|
+
// Return the live stack as a pseudo component-stack
|
|
429
|
+
return err.stack
|
|
430
|
+
.split('\n')
|
|
431
|
+
.slice(1, 6)
|
|
432
|
+
.map(line => ` ${line.trim()}`)
|
|
433
|
+
.join('\n');
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch { }
|
|
437
|
+
return undefined;
|
|
438
|
+
};
|
|
439
|
+
// ─── EXPORT & REPORTING UTILITIES ─────────────────────────────────────────────
|
|
440
|
+
/**
|
|
441
|
+
* Formats a crash into Text, Markdown, or JSON.
|
|
442
|
+
*/
|
|
443
|
+
const exportCrashReport = (crash, format = 'text') => {
|
|
444
|
+
if (format === 'json') {
|
|
445
|
+
return JSON.stringify(crash, null, 2);
|
|
446
|
+
}
|
|
447
|
+
const uptimeSec = Math.round((crash.timestamp - appStartTime) / 1000);
|
|
448
|
+
if (format === 'markdown') {
|
|
449
|
+
const lines = [];
|
|
450
|
+
lines.push(`## ${(0, i18n_1.t)('crash.mdReportTitle', { name: crash.name || 'Error' })}`);
|
|
451
|
+
lines.push(`> **${crash.message}**`);
|
|
452
|
+
lines.push('');
|
|
453
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportType')}** \`${crash.type.toUpperCase()}\``);
|
|
454
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportFatal')}** \`${crash.isFatal
|
|
455
|
+
? (0, i18n_1.t)('crash.mdSeverityFatal')
|
|
456
|
+
: (0, i18n_1.t)('crash.mdSeverityHandled')}\``);
|
|
457
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportTimestamp')}** ${crash.dateStr} ${crash.timeStr}`);
|
|
458
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportUptime')}** ${uptimeSec}s`);
|
|
459
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportPlatform')}** ${crash.deviceInfo?.platform?.toUpperCase()} (v${crash.deviceInfo?.osVersion})`);
|
|
460
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportReactNative')}** v${crash.deviceInfo?.rnVersion || 'N/A'}`);
|
|
461
|
+
lines.push(`- **${(0, i18n_1.t)('crash.jsEngine')}** ${crash.deviceInfo?.isHermes ? (0, i18n_1.t)('crash.hermesEngine') : (0, i18n_1.t)('crash.jsc')}`);
|
|
462
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportArchitecture')}** ${crash.deviceInfo?.isFabric
|
|
463
|
+
? (0, i18n_1.t)('crash.reportFabricNew')
|
|
464
|
+
: (0, i18n_1.t)('crash.reportPaperLegacy')}`);
|
|
465
|
+
if (crash.memoryInfo) {
|
|
466
|
+
lines.push(`- **${(0, i18n_1.t)('crash.reportJsMemory')}** ${crash.memoryInfo.usedJSHeapSize} MB / ${crash.memoryInfo.totalJSHeapSize} MB`);
|
|
467
|
+
}
|
|
468
|
+
lines.push('');
|
|
469
|
+
lines.push(`### ${(0, i18n_1.t)('crash.mdStackTrace')}`);
|
|
470
|
+
lines.push('```');
|
|
471
|
+
lines.push(crash.stack || (0, i18n_1.t)('crash.reportNoStackTrace'));
|
|
472
|
+
lines.push('```');
|
|
473
|
+
if (crash.componentStack) {
|
|
474
|
+
lines.push('');
|
|
475
|
+
lines.push(`### ${(0, i18n_1.t)('crash.mdComponentHierarchy')}`);
|
|
476
|
+
lines.push('```');
|
|
477
|
+
lines.push(crash.componentStack);
|
|
478
|
+
lines.push('```');
|
|
479
|
+
}
|
|
480
|
+
if (crash.breadcrumbs && crash.breadcrumbs.length > 0) {
|
|
481
|
+
lines.push('');
|
|
482
|
+
lines.push(`### ${(0, i18n_1.t)('crash.mdRecentBreadcrumbs')}`);
|
|
483
|
+
crash.breadcrumbs.forEach(b => {
|
|
484
|
+
const time = new Date(b.timestamp).toLocaleTimeString();
|
|
485
|
+
lines.push(`- \`[${time}]\` **[${b.type.toUpperCase()}]** ${b.message}`);
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
return lines.join('\n');
|
|
489
|
+
}
|
|
490
|
+
// Standard Text format
|
|
491
|
+
const lines = [];
|
|
492
|
+
lines.push('====================================================');
|
|
493
|
+
lines.push(` ${(0, i18n_1.t)('crash.reportTitle')} `);
|
|
494
|
+
lines.push('====================================================');
|
|
495
|
+
lines.push(`${(0, i18n_1.t)('crash.reportErrorName')} ${crash.name || 'Error'}`);
|
|
496
|
+
lines.push(`${(0, i18n_1.t)('crash.reportMessage')} ${crash.message}`);
|
|
497
|
+
lines.push(`${(0, i18n_1.t)('crash.reportType')} ${crash.type.toUpperCase()}`);
|
|
498
|
+
lines.push(`${(0, i18n_1.t)('crash.reportFatal')} ${crash.isFatal ? (0, i18n_1.t)('crash.reportFatalYes') : (0, i18n_1.t)('crash.reportFatalNo')}`);
|
|
499
|
+
lines.push(`${(0, i18n_1.t)('crash.reportTimestamp')} ${crash.dateStr} ${crash.timeStr} (${crash.timestamp})`);
|
|
500
|
+
lines.push(`${(0, i18n_1.t)('crash.reportUptime')} ${(0, i18n_1.t)('crash.reportUptimeValue', {
|
|
501
|
+
seconds: uptimeSec,
|
|
502
|
+
})}`);
|
|
503
|
+
lines.push(`${(0, i18n_1.t)('crash.reportPlatform')} ${crash.deviceInfo?.platform?.toUpperCase()} (v${crash.deviceInfo?.osVersion})`);
|
|
504
|
+
lines.push(`${(0, i18n_1.t)('crash.reportReactNative')} ${crash.deviceInfo?.rnVersion || 'N/A'}`);
|
|
505
|
+
lines.push(`${(0, i18n_1.t)('crash.reportHermes')} ${crash.deviceInfo?.isHermes
|
|
506
|
+
? (0, i18n_1.t)('crash.reportEnabled')
|
|
507
|
+
: (0, i18n_1.t)('crash.reportDisabled')}`);
|
|
508
|
+
lines.push(`${(0, i18n_1.t)('crash.reportArchitecture')} ${crash.deviceInfo?.isFabric
|
|
509
|
+
? (0, i18n_1.t)('crash.reportFabricNew')
|
|
510
|
+
: (0, i18n_1.t)('crash.reportPaperLegacy')}`);
|
|
511
|
+
lines.push(`${(0, i18n_1.t)('crash.reportScreenSize')} ${getScreenDimensions()}`);
|
|
512
|
+
lines.push(`${(0, i18n_1.t)('crash.reportAppState')} ${crash.deviceInfo?.appState || 'active'}`);
|
|
513
|
+
if (crash.memoryInfo) {
|
|
514
|
+
lines.push(`${(0, i18n_1.t)('crash.reportJsMemory')} ${crash.memoryInfo.usedJSHeapSize} MB / ${crash.memoryInfo.totalJSHeapSize} MB`);
|
|
515
|
+
}
|
|
516
|
+
lines.push('----------------------------------------------------');
|
|
517
|
+
lines.push(`${(0, i18n_1.t)('crash.reportStackTrace')}`);
|
|
518
|
+
lines.push(crash.stack || (0, i18n_1.t)('crash.reportNoStackTrace'));
|
|
519
|
+
if (crash.componentStack) {
|
|
520
|
+
lines.push('----------------------------------------------------');
|
|
521
|
+
lines.push(`${(0, i18n_1.t)('crash.reportComponentHierarchy')}`);
|
|
522
|
+
lines.push(crash.componentStack);
|
|
523
|
+
}
|
|
524
|
+
if (crash.breadcrumbs && crash.breadcrumbs.length > 0) {
|
|
525
|
+
lines.push('----------------------------------------------------');
|
|
526
|
+
lines.push(`${(0, i18n_1.t)('crash.reportRecentBreadcrumbs')}`);
|
|
527
|
+
crash.breadcrumbs.forEach(b => {
|
|
528
|
+
const time = new Date(b.timestamp).toLocaleTimeString();
|
|
529
|
+
lines.push(` [${time}] [${b.type.toUpperCase()}] ${b.message}`);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
lines.push('====================================================');
|
|
533
|
+
return lines.join('\n');
|
|
534
|
+
};
|
|
535
|
+
exports.exportCrashReport = exportCrashReport;
|
|
536
|
+
// ─── GLOBAL HANDLER INITIALIZATION ────────────────────────────────────────────
|
|
537
|
+
/**
|
|
538
|
+
* Natively intercepts and prevents crashes, native RedBox dialogues,
|
|
539
|
+
* unhandled JS errors, and unhandled promise rejections.
|
|
540
|
+
*/
|
|
541
|
+
const setupGlobalCrashHandler = () => {
|
|
542
|
+
if (isCrashHandlerInitialized)
|
|
543
|
+
return;
|
|
544
|
+
isCrashHandlerInitialized = true;
|
|
545
|
+
// 1. Completely silence React Native LogBox & RedBox overlays
|
|
546
|
+
try {
|
|
547
|
+
if (react_native_1.LogBox && typeof react_native_1.LogBox.ignoreAllLogs === 'function') {
|
|
548
|
+
react_native_1.LogBox.ignoreAllLogs(true);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
catch { }
|
|
552
|
+
try {
|
|
553
|
+
// @ts-ignore
|
|
554
|
+
const LogBoxData = require('react-native/Libraries/LogBox/Data/LogBoxData');
|
|
555
|
+
if (LogBoxData && typeof LogBoxData.setDisabled === 'function') {
|
|
556
|
+
LogBoxData.setDisabled(true);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch { }
|
|
560
|
+
// 2. Intercept Native Module: NetworkInspectorModule (Android & iOS)
|
|
561
|
+
try {
|
|
562
|
+
const networkInspectorModule = react_native_1.NativeModules?.NetworkInspectorModule;
|
|
563
|
+
if (networkInspectorModule) {
|
|
564
|
+
if (typeof networkInspectorModule.enableNativeCrashProtection === 'function') {
|
|
565
|
+
networkInspectorModule.enableNativeCrashProtection();
|
|
566
|
+
}
|
|
567
|
+
const nativeEmitter = new react_native_1.NativeEventEmitter(networkInspectorModule);
|
|
568
|
+
nativeEmitter.addListener('onNativeCrash', (event) => {
|
|
569
|
+
const platform = event?.platform || react_native_1.Platform.OS;
|
|
570
|
+
const msg = `[${platform.toUpperCase()} ${(0, i18n_1.t)('crash.nativeCrashTitle')}] ${event?.message || (0, i18n_1.t)('crash.nativeUncaughtException')}`;
|
|
571
|
+
const stack = event?.stack || '';
|
|
572
|
+
(0, exports.handleInterceptedCrash)(msg, stack, true, 'native');
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
catch { }
|
|
577
|
+
// 3. Intercept Native ExceptionsManager & RedBox modules (Bridge & TurboModules)
|
|
578
|
+
try {
|
|
579
|
+
const tmReg = react_native_1.TurboModuleRegistry || globalThis.__turboModuleProxy;
|
|
580
|
+
const nativeExceptionsManager = react_native_1.NativeModules?.ExceptionsManager ||
|
|
581
|
+
(tmReg?.get ? tmReg.get('ExceptionsManager') : null);
|
|
582
|
+
if (nativeExceptionsManager) {
|
|
583
|
+
nativeExceptionsManager.reportFatalException = (title, stack, exceptionId) => {
|
|
584
|
+
(0, exports.handleInterceptedCrash)(title, stack, true, 'native');
|
|
585
|
+
try {
|
|
586
|
+
if (typeof nativeExceptionsManager.dismissRedbox === 'function') {
|
|
587
|
+
nativeExceptionsManager.dismissRedbox();
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
catch { }
|
|
591
|
+
};
|
|
592
|
+
nativeExceptionsManager.reportSoftException = (title, stack, exceptionId) => {
|
|
593
|
+
(0, exports.handleInterceptedCrash)(title, stack, false, 'js');
|
|
594
|
+
try {
|
|
595
|
+
if (typeof nativeExceptionsManager.dismissRedbox === 'function') {
|
|
596
|
+
nativeExceptionsManager.dismissRedbox();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
catch { }
|
|
600
|
+
};
|
|
601
|
+
nativeExceptionsManager.reportException = (data) => {
|
|
602
|
+
const msg = data?.message || data?.title || (0, i18n_1.t)('crash.nativeException');
|
|
603
|
+
const stack = data?.stack || data?.rawStack;
|
|
604
|
+
(0, exports.handleInterceptedCrash)(msg, stack, data?.isFatal ?? true, 'js');
|
|
605
|
+
try {
|
|
606
|
+
if (typeof nativeExceptionsManager.dismissRedbox === 'function') {
|
|
607
|
+
nativeExceptionsManager.dismissRedbox();
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
catch { }
|
|
611
|
+
};
|
|
612
|
+
nativeExceptionsManager.updateExceptionMessage = () => { };
|
|
613
|
+
try {
|
|
614
|
+
if (typeof nativeExceptionsManager.dismissRedbox === 'function') {
|
|
615
|
+
nativeExceptionsManager.dismissRedbox();
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
catch { }
|
|
619
|
+
}
|
|
620
|
+
const nativeRedBox = react_native_1.NativeModules?.RedBox ||
|
|
621
|
+
react_native_1.NativeModules?.RCTRedBox ||
|
|
622
|
+
(tmReg?.get ? tmReg.get('RedBox') || tmReg.get('RCTRedBox') : null);
|
|
623
|
+
if (nativeRedBox) {
|
|
624
|
+
if (typeof nativeRedBox.showErrorMessage === 'function') {
|
|
625
|
+
nativeRedBox.showErrorMessage = () => { };
|
|
626
|
+
}
|
|
627
|
+
if (typeof nativeRedBox.showUserError === 'function') {
|
|
628
|
+
nativeRedBox.showUserError = () => { };
|
|
629
|
+
}
|
|
630
|
+
if (typeof nativeRedBox.dismiss === 'function') {
|
|
631
|
+
nativeRedBox.dismiss();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
catch { }
|
|
636
|
+
// 4. Hook React Native ErrorUtils
|
|
637
|
+
try {
|
|
638
|
+
const globalObj = globalThis;
|
|
639
|
+
const errorUtils = globalObj.ErrorUtils;
|
|
640
|
+
if (errorUtils) {
|
|
641
|
+
if (typeof errorUtils.setGlobalHandler === 'function') {
|
|
642
|
+
errorUtils.setGlobalHandler((error, isFatal) => {
|
|
643
|
+
(0, exports.handleInterceptedCrash)(error, error?.stack, isFatal ?? false, 'js');
|
|
644
|
+
// Suppress calling default crashing handler to prevent termination & RedBox
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
if (typeof errorUtils.reportFatalError === 'function') {
|
|
648
|
+
errorUtils.reportFatalError = (error) => {
|
|
649
|
+
(0, exports.handleInterceptedCrash)(error, error?.stack, true, 'js');
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
if (typeof errorUtils.reportError === 'function') {
|
|
653
|
+
errorUtils.reportError = (error) => {
|
|
654
|
+
(0, exports.handleInterceptedCrash)(error, error?.stack, false, 'js');
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
catch { }
|
|
660
|
+
// 5. Hook global Promise unhandled rejections
|
|
661
|
+
try {
|
|
662
|
+
const globalObj = globalThis;
|
|
663
|
+
const handleUnhandledPromise = (eventOrError) => {
|
|
664
|
+
try {
|
|
665
|
+
const reason = eventOrError?.reason || eventOrError?.detail?.reason || eventOrError;
|
|
666
|
+
const message = reason?.message || String(reason || (0, i18n_1.t)('crash.unhandledPromiseRejection'));
|
|
667
|
+
const stack = reason?.stack || (eventOrError?.stack ?? new Error().stack);
|
|
668
|
+
(0, exports.handleInterceptedCrash)(reason, stack, false, 'promise');
|
|
669
|
+
}
|
|
670
|
+
catch { }
|
|
671
|
+
};
|
|
672
|
+
if (typeof globalObj.addEventListener === 'function') {
|
|
673
|
+
globalObj.addEventListener('unhandledrejection', handleUnhandledPromise);
|
|
674
|
+
}
|
|
675
|
+
if (typeof globalObj.onunhandledrejection !== 'undefined') {
|
|
676
|
+
globalObj.onunhandledrejection = handleUnhandledPromise;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
catch { }
|
|
680
|
+
};
|
|
681
|
+
exports.setupGlobalCrashHandler = setupGlobalCrashHandler;
|