@scalebun/react-native 1.10.2 → 1.10.3
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/src/main/java/com/scalebun/rn/crash/ScaleBunCrashModule.kt +24 -0
- package/android/src/oldarch/java/com/scalebun/rn/crash/ScaleBunCrashSpec.kt +3 -0
- package/dist/scalebun.full.js +811 -768
- package/dist/scalebun.full.js.map +1 -1
- package/dist/scalebun.slim.js +825 -782
- package/dist/scalebun.slim.js.map +1 -1
- package/ios/Crash/ScaleBunCrashBridge.mm +5 -0
- package/ios/Crash/ScaleBunCrashModule.swift +15 -0
- package/lib/commonjs/core/constants/version.js +1 -1
- package/lib/commonjs/features/crash/CrashFeature.js +17 -1
- package/lib/commonjs/features/crash/CrashFeature.js.map +1 -1
- package/lib/commonjs/features/crash/nativeCrashBridge.js +61 -3
- package/lib/commonjs/features/crash/nativeCrashBridge.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunCrash.js.map +1 -1
- package/lib/module/core/constants/version.js +1 -1
- package/lib/module/features/crash/CrashFeature.js +17 -1
- package/lib/module/features/crash/CrashFeature.js.map +1 -1
- package/lib/module/features/crash/nativeCrashBridge.js +60 -3
- package/lib/module/features/crash/nativeCrashBridge.js.map +1 -1
- package/lib/module/specs/NativeScaleBunCrash.js.map +1 -1
- package/lib/typescript/core/constants/version.d.ts +1 -1
- package/lib/typescript/features/crash/CrashFeature.d.ts.map +1 -1
- package/lib/typescript/features/crash/nativeCrashBridge.d.ts +24 -0
- package/lib/typescript/features/crash/nativeCrashBridge.d.ts.map +1 -1
- package/lib/typescript/specs/NativeScaleBunCrash.d.ts +11 -0
- package/lib/typescript/specs/NativeScaleBunCrash.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/constants/version.ts +1 -1
- package/src/features/crash/CrashFeature.ts +17 -1
- package/src/features/crash/nativeCrashBridge.ts +69 -3
- package/src/specs/NativeScaleBunCrash.ts +12 -0
|
@@ -31,6 +31,11 @@ RCT_EXTERN_METHOD(setActiveSessionId:(NSString *)sessionId
|
|
|
31
31
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
32
32
|
reject:(RCTPromiseRejectBlock)reject)
|
|
33
33
|
|
|
34
|
+
|
|
35
|
+
// Blocking synchronous: a fatal JS crash unwinds the process before an async
|
|
36
|
+
// promise resolves, so the write must finish before this returns. Mirrors the
|
|
37
|
+
// OTA/Storage sync methods. Selector matches @objc(persistJsCrash:) in Swift.
|
|
38
|
+
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(persistJsCrash:(NSString *)recordJson)
|
|
34
39
|
@end
|
|
35
40
|
|
|
36
41
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
@@ -80,4 +80,19 @@ class ScaleBunCrashModule: NSObject, RCTBridgeModule {
|
|
|
80
80
|
|
|
81
81
|
resolve(result)
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Persist a FATAL JS crash to the same store native crashes use.
|
|
86
|
+
*
|
|
87
|
+
* Blocking synchronous: the write must land on disk before the fatal JS
|
|
88
|
+
* handler returns and the process dies. drainPendingCrash reads it back on
|
|
89
|
+
* the next launch like any native crash. Returns a boolean to JS.
|
|
90
|
+
*/
|
|
91
|
+
@objc(persistJsCrash:)
|
|
92
|
+
func persistJsCrash(_ recordJson: NSString) -> NSNumber {
|
|
93
|
+
let s = recordJson as String
|
|
94
|
+
if s.isEmpty { return NSNumber(value: false) }
|
|
95
|
+
ScaleBunCrashStorage.write(s)
|
|
96
|
+
return NSNumber(value: true)
|
|
97
|
+
}
|
|
83
98
|
}
|
|
@@ -9,5 +9,5 @@ exports.SDK_VERSION = void 0;
|
|
|
9
9
|
* can attribute telemetry to the SDK build that produced it.
|
|
10
10
|
* Keep in sync with package.json "version".
|
|
11
11
|
*/
|
|
12
|
-
const SDK_VERSION = exports.SDK_VERSION = '1.10.
|
|
12
|
+
const SDK_VERSION = exports.SDK_VERSION = '1.10.3';
|
|
13
13
|
//# sourceMappingURL=version.js.map
|
|
@@ -7,6 +7,8 @@ exports.CrashFeature = void 0;
|
|
|
7
7
|
var _index = require("./index");
|
|
8
8
|
var _rejectionHandler = require("./rejectionHandler");
|
|
9
9
|
var _CrashReporter = require("./CrashReporter");
|
|
10
|
+
var _nativeCrashBridge = require("./nativeCrashBridge");
|
|
11
|
+
var _reactNative = require("react-native");
|
|
10
12
|
/**
|
|
11
13
|
* ScaleBun SDK — Crash Feature
|
|
12
14
|
*
|
|
@@ -35,7 +37,21 @@ class CrashFeature {
|
|
|
35
37
|
stack: error.stack
|
|
36
38
|
});
|
|
37
39
|
if (isFatal) {
|
|
38
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Persist to disk FIRST, synchronously, before anything else.
|
|
42
|
+
*
|
|
43
|
+
* A fatal JS crash tears the process down before an async POST
|
|
44
|
+
* can finish, so the report queued above can be lost. The native
|
|
45
|
+
* write below completes on disk before this handler returns, and
|
|
46
|
+
* the next launch drains and delivers it — the same guarantee
|
|
47
|
+
* native crashes already had, now extended to JS.
|
|
48
|
+
*/
|
|
49
|
+
(0, _nativeCrashBridge.persistFatalJsCrash)({
|
|
50
|
+
message: error.message,
|
|
51
|
+
stack: error.stack,
|
|
52
|
+
platform: _reactNative.Platform.OS
|
|
53
|
+
});
|
|
54
|
+
// Best-effort live delivery too, in case the process lingers.
|
|
39
55
|
this.flushFn();
|
|
40
56
|
}
|
|
41
57
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_index","require","_rejectionHandler","_CrashReporter","CrashFeature","name","active","constructor","flushFn","initialize","_context","installCrashReporting","error","isFatal","getCrashReporter","report","source","type","message","stack","installRejectionHandler","teardown","isActive","exports"],"sourceRoot":"../../../../src","sources":["features/crash/CrashFeature.ts"],"mappings":";;;;;;AAYA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA;
|
|
1
|
+
{"version":3,"names":["_index","require","_rejectionHandler","_CrashReporter","_nativeCrashBridge","_reactNative","CrashFeature","name","active","constructor","flushFn","initialize","_context","installCrashReporting","error","isFatal","getCrashReporter","report","source","type","message","stack","persistFatalJsCrash","platform","Platform","OS","installRejectionHandler","teardown","isActive","exports"],"sourceRoot":"../../../../src","sources":["features/crash/CrashFeature.ts"],"mappings":";;;;;;AAYA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAH,OAAA;AACA,IAAAI,YAAA,GAAAJ,OAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AASO,MAAMK,YAAY,CAAqB;EACjCC,IAAI,GAAG,OAAO;EACfC,MAAM,GAAG,KAAK;EAGtBC,WAAWA,CAACC,OAA4B,EAAE;IACtC,IAAI,CAACA,OAAO,GAAGA,OAAO;EAC1B;EAEAC,UAAUA,CAACC,QAAwB,EAAQ;IACvC,IAAI,IAAI,CAACJ,MAAM,EAAE;IACjB,IAAAK,4BAAqB,EAAC,CAACC,KAAY,EAAEC,OAAgB,KAAK;MACtD,IAAAC,+BAAgB,EAAC,CAAC,CAACC,MAAM,CAAC;QACtBC,MAAM,EAAE,IAAI;QACZC,IAAI,EAAEJ,OAAO,GAAG,OAAO,GAAG,SAAS;QACnCA,OAAO;QACPK,OAAO,EAAEN,KAAK,CAACM,OAAO;QACtBC,KAAK,EAAEP,KAAK,CAACO;MACjB,CAAC,CAAC;MAEF,IAAIN,OAAO,EAAE;QACT;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;QACgB,IAAAO,sCAAmB,EAAC;UAChBF,OAAO,EAAEN,KAAK,CAACM,OAAO;UACtBC,KAAK,EAAEP,KAAK,CAACO,KAAK;UAClBE,QAAQ,EAAEC,qBAAQ,CAACC;QACvB,CAAC,CAAC;QACF;QACA,IAAI,CAACf,OAAO,CAAC,CAAC;MAClB;IACJ,CAAC,CAAC;;IAEF;AACR;AACA;AACA;AACA;AACA;AACA;IACQ,IAAAgB,yCAAuB,EAAEZ,KAAY,IAAK;MACtC,IAAAE,+BAAgB,EAAC,CAAC,CAACC,MAAM,CAAC;QACtBC,MAAM,EAAE,IAAI;QACZC,IAAI,EAAE,SAAS;QACfJ,OAAO,EAAE,KAAK;QACdK,OAAO,EAAEN,KAAK,CAACM,OAAO;QACtBC,KAAK,EAAEP,KAAK,CAACO;MACjB,CAAC,CAAC;IACN,CAAC,CAAC;IAEF,IAAI,CAACb,MAAM,GAAG,IAAI;EACtB;EAEAmB,QAAQA,CAAA,EAAS;IACb;IACA,IAAI,CAACnB,MAAM,GAAG,KAAK;EACvB;EAEA,IAAIoB,QAAQA,CAAA,EAAY;IACpB,OAAO,IAAI,CAACpB,MAAM;EACtB;AACJ;AAACqB,OAAA,CAAAvB,YAAA,GAAAA,YAAA","ignoreList":[]}
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.drainNativeCrash = drainNativeCrash;
|
|
7
7
|
exports.installNativeCrashHandler = installNativeCrashHandler;
|
|
8
|
+
exports.persistFatalJsCrash = persistFatalJsCrash;
|
|
8
9
|
exports.setNativeActiveSession = setNativeActiveSession;
|
|
9
10
|
exports.triggerNativeCrash = triggerNativeCrash;
|
|
10
11
|
var _reactNative = require("react-native");
|
|
@@ -154,12 +155,18 @@ async function drainOne(seen) {
|
|
|
154
155
|
// 2) SaaS backend errors endpoint (dashboard Crashes view) — route the
|
|
155
156
|
// same normalized report through the central reporter. This is what
|
|
156
157
|
// makes native crashes visible in the dashboard, not just the desktop.
|
|
158
|
+
const recordType = typeof crash.type === 'string' ? crash.type : 'native';
|
|
159
|
+
const recordSource = typeof crash.source === 'string' ? crash.source : 'native';
|
|
157
160
|
(0, _CrashReporter.getCrashReporter)().report({
|
|
158
|
-
source:
|
|
159
|
-
type:
|
|
161
|
+
source: recordSource,
|
|
162
|
+
type: recordType,
|
|
160
163
|
isFatal: true,
|
|
161
164
|
message: crash.message ?? crash.exceptionType ?? 'Native crash',
|
|
162
|
-
stack: stackArr.length ? stackArr.join('\n') : undefined,
|
|
165
|
+
stack: stackArr.length ? stackArr.join('\n') : crash.stack ? String(crash.stack) : undefined,
|
|
166
|
+
// Set for a recovered JS crash; a native crash has no JS screen.
|
|
167
|
+
...(crash.screenName ? {
|
|
168
|
+
screenName: String(crash.screenName)
|
|
169
|
+
} : {}),
|
|
163
170
|
platform: crash.platform,
|
|
164
171
|
/**
|
|
165
172
|
* THE ORIGINAL SESSION — the entire point of the recovery path.
|
|
@@ -280,4 +287,55 @@ async function triggerNativeCrash() {
|
|
|
280
287
|
// The process is expected to die; nothing to handle.
|
|
281
288
|
}
|
|
282
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Persist a FATAL JS crash to disk BEFORE the process dies.
|
|
292
|
+
*
|
|
293
|
+
* A fatal JS error tears the process down almost immediately. The normal error
|
|
294
|
+
* path queues the crash and POSTs it asynchronously, which loses the race: the
|
|
295
|
+
* process is gone before the request finishes, and nothing is on disk to retry.
|
|
296
|
+
* This is why a JS crash could vanish while a native one always survived.
|
|
297
|
+
*
|
|
298
|
+
* The fix is the native module's SYNCHRONOUS persistJsCrash: it writes the
|
|
299
|
+
* record to the same store native crashes use and returns before this function
|
|
300
|
+
* returns — so by the time the JS handler unwinds, the crash is durable. The
|
|
301
|
+
* existing drain path then delivers it on the next launch, at least once,
|
|
302
|
+
* deduped on crashId.
|
|
303
|
+
*
|
|
304
|
+
* Synchronous and no-throw by construction: this runs inside the global error
|
|
305
|
+
* handler, where an exception would replace one crash with another.
|
|
306
|
+
*/
|
|
307
|
+
function persistFatalJsCrash(input) {
|
|
308
|
+
try {
|
|
309
|
+
const mod = getCrashModule();
|
|
310
|
+
if (!mod?.persistJsCrash) return false;
|
|
311
|
+
// Minted once, here, so a retry from disk dedupes on the backend rather
|
|
312
|
+
// than arriving as a fresh crash every launch.
|
|
313
|
+
const crashId = `jscrash-${nowMs()}-${counter()}`;
|
|
314
|
+
const record = {
|
|
315
|
+
crashId,
|
|
316
|
+
type: 'crash',
|
|
317
|
+
source: 'js',
|
|
318
|
+
isFatal: true,
|
|
319
|
+
message: input.message,
|
|
320
|
+
stack: input.stack,
|
|
321
|
+
screenName: input.screenName,
|
|
322
|
+
platform: input.platform,
|
|
323
|
+
sessionId: input.sessionId,
|
|
324
|
+
timestamp: new Date().toISOString()
|
|
325
|
+
};
|
|
326
|
+
return mod.persistJsCrash(JSON.stringify(record)) === true;
|
|
327
|
+
} catch {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Monotonic-ish parts for a unique id without pulling in a uuid dependency. */
|
|
333
|
+
let _seq = 0;
|
|
334
|
+
function counter() {
|
|
335
|
+
_seq = (_seq + 1) % 1_000_000;
|
|
336
|
+
return _seq;
|
|
337
|
+
}
|
|
338
|
+
function nowMs() {
|
|
339
|
+
return Date.now();
|
|
340
|
+
}
|
|
283
341
|
//# sourceMappingURL=nativeCrashBridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","_architecture","_internalLogger","_CrashReporter","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_crashModule","getCrashModule","mod","turbo","__DEV__","logger","debug","nativeModuleVia","legacy","NativeModules","ScaleBunCrash","setNativeActiveSession","sessionId","setActiveSessionId","installNativeCrashHandler","install","MAX_DRAIN_PER_LAUNCH","drainNativeCrash","found","seen","Set","outcome","drainOne","drainPendingCrash","crash","seenKey","crashId","add","stackArr","Array","isArray","stackTrace","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_architecture","_internalLogger","_CrashReporter","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_crashModule","getCrashModule","mod","turbo","__DEV__","logger","debug","nativeModuleVia","legacy","NativeModules","ScaleBunCrash","setNativeActiveSession","sessionId","setActiveSessionId","installNativeCrashHandler","install","MAX_DRAIN_PER_LAUNCH","drainNativeCrash","found","seen","Set","outcome","drainOne","drainPendingCrash","crash","seenKey","crashId","add","stackArr","Array","isArray","stackTrace","recordType","type","recordSource","source","getCrashReporter","report","isFatal","message","exceptionType","stack","length","join","String","undefined","screenName","platform","metadata","threadName","signal","clearPendingCrash","info","delivered","confirmDelivery","SessionManager","Promise","resolve","then","transport","getExistingInstance","getBackendTransport","flushErrors","triggerNativeCrash","crashNow","warn","persistFatalJsCrash","input","persistJsCrash","nowMs","counter","record","timestamp","Date","toISOString","JSON","stringify","_seq","now"],"sourceRoot":"../../../../src","sources":["features/crash/nativeCrashBridge.ts"],"mappings":";;;;;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,aAAA,GAAAD,OAAA;AACA,IAAAE,eAAA,GAAAF,OAAA;AACA,IAAAG,cAAA,GAAAH,OAAA;AAAmD,SAAAI,wBAAAC,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAH,uBAAA,YAAAA,CAAAC,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,IAAIkB,YAAsC;AAE1C,SAASC,cAAcA,CAAA,EAAQ;EAC3B,IAAID,YAAY,EAAE,OAAOA,YAAY,CAACE,GAAG;;EAEzC;EACA;EACA,IAAI;IACA;IACA,MAAMC,KAAK,GAAG3B,OAAO,CAAC,iCAAiC,CAAC,CAACe,OAAO;IAChE,IAAIY,KAAK,EAAE;MACPC,OAAO,IAAIC,sBAAM,CAACC,KAAK,CAAC,8BAA8B,IAAAC,6BAAe,EAAC,CAAC,EAAE,CAAC;MAC1EP,YAAY,GAAG;QAAEE,GAAG,EAAEC;MAAM,CAAC;MAC7B,OAAOA,KAAK;IAChB;EACJ,CAAC,CAAC,MAAM;IACJ;EAAA;;EAGJ;EACA,MAAMK,MAAM,GAAGC,0BAAa,EAAEC,aAAa,IAAI,IAAI;EACnD,IAAIF,MAAM,EAAEH,sBAAM,CAACC,KAAK,CAAC,iDAAiD,CAAC;EAC3EN,YAAY,GAAG;IAAEE,GAAG,EAAEM;EAAO,CAAC;EAC9B,OAAOA,MAAM;AACjB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeG,sBAAsBA,CAACC,SAAiB,EAAiB;EAC3E,IAAI;IACA,MAAMV,GAAG,GAAGD,cAAc,CAAC,CAAC;IAC5B,IAAI,CAACC,GAAG,EAAEW,kBAAkB,IAAI,CAACD,SAAS,EAAE;IAC5C,MAAMV,GAAG,CAACW,kBAAkB,CAACD,SAAS,CAAC;IACvCR,OAAO,IAAIC,sBAAM,CAACC,KAAK,CAAC,kCAAkCM,SAAS,EAAE,CAAC;EAC1E,CAAC,CAAC,MAAM;IACJ;EAAA;AAER;AAEO,eAAeE,yBAAyBA,CAAA,EAAkB;EAC7D,IAAI;IACA,MAAMZ,GAAG,GAAGD,cAAc,CAAC,CAAC;IAC5B,IAAI,CAACC,GAAG,EAAEa,OAAO,EAAE;MACfX,OAAO,IAAIC,sBAAM,CAACC,KAAK,CAAC,8DAA8D,CAAC;MACvF;IACJ;IACA,MAAMJ,GAAG,CAACa,OAAO,CAAC,CAAC;IACnBX,OAAO,IAAIC,sBAAM,CAACC,KAAK,CAAC,iCAAiC,CAAC;EAC9D,CAAC,CAAC,MAAM;IACJ;EAAA;AAER;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMU,oBAAoB,GAAG,CAAC;;AAE9B;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeC,gBAAgBA,CAAA,EAAqB;EACvD,IAAIC,KAAK,GAAG,KAAK;EACjB,MAAMC,IAAI,GAAG,IAAIC,GAAG,CAAS,CAAC;EAC9B,KAAK,IAAIhC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG4B,oBAAoB,EAAE5B,CAAC,EAAE,EAAE;IAC3C,MAAMiC,OAAO,GAAG,MAAMC,QAAQ,CAACH,IAAI,CAAC;IACpC,IAAIE,OAAO,KAAK,MAAM,EAAE;IACxBH,KAAK,GAAG,IAAI;IACZ;IACA;IACA,IAAIG,OAAO,KAAK,MAAM,EAAE;EAC5B;EACA,OAAOH,KAAK;AAChB;;AAEA;AACA,eAAeI,QAAQA,CAACH,IAAiB,EAAwC;EAC7E,IAAI;IACA,MAAMjB,GAAG,GAAGD,cAAc,CAAC,CAAC;IAC5B,IAAI,CAACC,GAAG,EAAEqB,iBAAiB,EAAE,OAAO,MAAM;IAE1C,MAAMC,KAAK,GAAG,MAAMtB,GAAG,CAACqB,iBAAiB,CAAC,CAAC;IAC3C,IAAI,CAACC,KAAK,EAAE,OAAO,MAAM;;IAEzB;AACR;AACA;AACA;AACA;IACQ,MAAMC,OAAO,GAAG,OAAOD,KAAK,CAACE,OAAO,KAAK,QAAQ,GAAGF,KAAK,CAACE,OAAO,GAAG,EAAE;IACtE;IACA;IACA;IACA,IAAIP,IAAI,CAAC3B,GAAG,CAACiC,OAAO,CAAC,EAAE,OAAO,MAAM;IACpCN,IAAI,CAACQ,GAAG,CAACF,OAAO,CAAC;IAEjB,MAAMG,QAAkB,GAAGC,KAAK,CAACC,OAAO,CAACN,KAAK,CAACO,UAAU,CAAC,GAAGP,KAAK,CAACO,UAAU,GAAG,EAAE;;IAElF;IACA;IACA;IACA;IACA;;IAEA;IACA;IACA;IACA,MAAMC,UAAU,GAAG,OAAOR,KAAK,CAACS,IAAI,KAAK,QAAQ,GAAGT,KAAK,CAACS,IAAI,GAAG,QAAQ;IACzE,MAAMC,YAAY,GAAG,OAAOV,KAAK,CAACW,MAAM,KAAK,QAAQ,GAAGX,KAAK,CAACW,MAAM,GAAG,QAAQ;IAC/E,IAAAC,+BAAgB,EAAC,CAAC,CAACC,MAAM,CAAC;MACtBF,MAAM,EAAED,YAAY;MACpBD,IAAI,EAAED,UAAU;MAChBM,OAAO,EAAE,IAAI;MACbC,OAAO,EAAEf,KAAK,CAACe,OAAO,IAAIf,KAAK,CAACgB,aAAa,IAAI,cAAc;MAC/DC,KAAK,EAAEb,QAAQ,CAACc,MAAM,GAChBd,QAAQ,CAACe,IAAI,CAAC,IAAI,CAAC,GACnBnB,KAAK,CAACiB,KAAK,GACTG,MAAM,CAACpB,KAAK,CAACiB,KAAK,CAAC,GACnBI,SAAS;MACjB;MACA,IAAIrB,KAAK,CAACsB,UAAU,GAAG;QAAEA,UAAU,EAAEF,MAAM,CAACpB,KAAK,CAACsB,UAAU;MAAE,CAAC,GAAG,CAAC,CAAC,CAAC;MACrEC,QAAQ,EAAEvB,KAAK,CAACuB,QAAQ;MACxB;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACY,IAAIvB,KAAK,CAACZ,SAAS,GAAG;QAAEA,SAAS,EAAEgC,MAAM,CAACpB,KAAK,CAACZ,SAAS;MAAE,CAAC,GAAG,CAAC,CAAC,CAAC;MAClE;AACZ;AACA;AACA;AACA;AACA;AACA;MACY,IAAIY,KAAK,CAACE,OAAO,GAAG;QAAEA,OAAO,EAAEkB,MAAM,CAACpB,KAAK,CAACE,OAAO;MAAE,CAAC,GAAG,CAAC,CAAC,CAAC;MAC5DsB,QAAQ,EAAE;QACNR,aAAa,EAAEhB,KAAK,CAACgB,aAAa;QAClCS,UAAU,EAAEzB,KAAK,CAACyB,UAAU;QAC5B,IAAIzB,KAAK,CAAC0B,MAAM,KAAKL,SAAS,GAAG;UAAEK,MAAM,EAAE1B,KAAK,CAAC0B;QAAO,CAAC,GAAG,CAAC,CAAC;MAClE;IACJ,CAAC,CAAC;;IAEF;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IACQ,MAAMxB,OAAO,GAAGD,OAAO;IACvB,IAAI,CAACC,OAAO,EAAE;MACV,MAAMxB,GAAG,CAACiD,iBAAiB,GAAG,EAAE,CAAC;MACjC/C,OAAO,IAAIC,sBAAM,CAAC+C,IAAI,CAAC,wDAAwD,CAAC;MAChF,OAAO,SAAS;IACpB;IAEA,MAAMC,SAAS,GAAG,MAAMC,eAAe,CAAC,CAAC;IACzC,IAAID,SAAS,EAAE;MACX,MAAMnD,GAAG,CAACiD,iBAAiB,GAAGzB,OAAO,CAAC;MACtCtB,OAAO,IAAIC,sBAAM,CAAC+C,IAAI,CAAC,uBAAuB1B,OAAO,sBAAsB,CAAC;MAC5E,OAAO,SAAS;IACpB;IACAtB,OAAO,IAAIC,sBAAM,CAAC+C,IAAI,CAAC,uBAAuB1B,OAAO,qCAAqC,CAAC;IAC3F,OAAO,MAAM;EACjB,CAAC,CAAC,MAAM;IACJ;IACA,OAAO,MAAM;EACjB;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe4B,eAAeA,CAAA,EAAqB;EAC/C,IAAI;IACA,MAAM;MAAEC;IAAe,CAAC,GAAG,MAAAC,OAAA,CAAAC,OAAA,GAAAC,IAAA,OAAA9E,uBAAA,CAAAJ,OAAA,CAAa,2BAA2B,GAAC;IACpE,MAAMmF,SAAS,GAAGJ,cAAc,CAACK,mBAAmB,CAAC,CAAC,EAAEC,mBAAmB,CAAC,CAAC;IAC7E;IACA;IACA;IACA,IAAI,CAACF,SAAS,EAAE,OAAO,KAAK;IAC5B;AACR;AACA;AACA;AACA;AACA;AACA;IACQ,OAAO,CAAC,MAAMA,SAAS,CAACG,WAAW,CAAC,CAAC,MAAM,IAAI;EACnD,CAAC,CAAC,MAAM;IACJ,OAAO,KAAK;EAChB;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACO,eAAeC,kBAAkBA,CAAA,EAAkB;EACtD,IAAI;IACA,MAAM7D,GAAG,GAAGD,cAAc,CAAC,CAAC;IAC5B,IAAI,CAACC,GAAG,EAAE8D,QAAQ,EAAE;MAChB3D,sBAAM,CAAC4D,IAAI,CAAC,mEAAmE,CAAC;MAChF;IACJ;IACA,MAAM/D,GAAG,CAAC8D,QAAQ,CAAC,CAAC;EACxB,CAAC,CAAC,MAAM;IACJ;EAAA;AAER;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,mBAAmBA,CAACC,KAMnC,EAAW;EACR,IAAI;IACA,MAAMjE,GAAG,GAAGD,cAAc,CAAC,CAAC;IAC5B,IAAI,CAACC,GAAG,EAAEkE,cAAc,EAAE,OAAO,KAAK;IACtC;IACA;IACA,MAAM1C,OAAO,GAAG,WAAW2C,KAAK,CAAC,CAAC,IAAIC,OAAO,CAAC,CAAC,EAAE;IACjD,MAAMC,MAAM,GAAG;MACX7C,OAAO;MACPO,IAAI,EAAE,OAAO;MACbE,MAAM,EAAE,IAAI;MACZG,OAAO,EAAE,IAAI;MACbC,OAAO,EAAE4B,KAAK,CAAC5B,OAAO;MACtBE,KAAK,EAAE0B,KAAK,CAAC1B,KAAK;MAClBK,UAAU,EAAEqB,KAAK,CAACrB,UAAU;MAC5BC,QAAQ,EAAEoB,KAAK,CAACpB,QAAQ;MACxBnC,SAAS,EAAEuD,KAAK,CAACvD,SAAS;MAC1B4D,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;IACtC,CAAC;IACD,OAAOxE,GAAG,CAACkE,cAAc,CAACO,IAAI,CAACC,SAAS,CAACL,MAAM,CAAC,CAAC,KAAK,IAAI;EAC9D,CAAC,CAAC,MAAM;IACJ,OAAO,KAAK;EAChB;AACJ;;AAEA;AACA,IAAIM,IAAI,GAAG,CAAC;AACZ,SAASP,OAAOA,CAAA,EAAW;EACvBO,IAAI,GAAG,CAACA,IAAI,GAAG,CAAC,IAAI,SAAS;EAC7B,OAAOA,IAAI;AACf;AACA,SAASR,KAAKA,CAAA,EAAW;EACrB,OAAOI,IAAI,CAACK,GAAG,CAAC,CAAC;AACrB","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","get"],"sourceRoot":"../../../src","sources":["specs/NativeScaleBunCrash.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","get"],"sourceRoot":"../../../src","sources":["specs/NativeScaleBunCrash.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAwCA;AACA;AACA;AACA;AACA;AACA;AALA,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAMeC,gCAAmB,CAACC,GAAG,CAAO,eAAe,CAAC","ignoreList":[]}
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import { installCrashReporting } from './index';
|
|
13
13
|
import { installRejectionHandler } from './rejectionHandler';
|
|
14
14
|
import { getCrashReporter } from './CrashReporter';
|
|
15
|
+
import { persistFatalJsCrash } from './nativeCrashBridge';
|
|
16
|
+
import { Platform } from 'react-native';
|
|
15
17
|
export class CrashFeature {
|
|
16
18
|
name = 'crash';
|
|
17
19
|
active = false;
|
|
@@ -29,7 +31,21 @@ export class CrashFeature {
|
|
|
29
31
|
stack: error.stack
|
|
30
32
|
});
|
|
31
33
|
if (isFatal) {
|
|
32
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Persist to disk FIRST, synchronously, before anything else.
|
|
36
|
+
*
|
|
37
|
+
* A fatal JS crash tears the process down before an async POST
|
|
38
|
+
* can finish, so the report queued above can be lost. The native
|
|
39
|
+
* write below completes on disk before this handler returns, and
|
|
40
|
+
* the next launch drains and delivers it — the same guarantee
|
|
41
|
+
* native crashes already had, now extended to JS.
|
|
42
|
+
*/
|
|
43
|
+
persistFatalJsCrash({
|
|
44
|
+
message: error.message,
|
|
45
|
+
stack: error.stack,
|
|
46
|
+
platform: Platform.OS
|
|
47
|
+
});
|
|
48
|
+
// Best-effort live delivery too, in case the process lingers.
|
|
33
49
|
this.flushFn();
|
|
34
50
|
}
|
|
35
51
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["installCrashReporting","installRejectionHandler","getCrashReporter","CrashFeature","name","active","constructor","flushFn","initialize","_context","error","isFatal","report","source","type","message","stack","teardown","isActive"],"sourceRoot":"../../../../src","sources":["features/crash/CrashFeature.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,SAASA,qBAAqB,QAAQ,SAAS;AAC/C,SAASC,uBAAuB,QAAQ,oBAAoB;AAC5D,SAASC,gBAAgB,QAAQ,iBAAiB;
|
|
1
|
+
{"version":3,"names":["installCrashReporting","installRejectionHandler","getCrashReporter","persistFatalJsCrash","Platform","CrashFeature","name","active","constructor","flushFn","initialize","_context","error","isFatal","report","source","type","message","stack","platform","OS","teardown","isActive"],"sourceRoot":"../../../../src","sources":["features/crash/CrashFeature.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,SAASA,qBAAqB,QAAQ,SAAS;AAC/C,SAASC,uBAAuB,QAAQ,oBAAoB;AAC5D,SAASC,gBAAgB,QAAQ,iBAAiB;AAClD,SAASC,mBAAmB,QAAQ,qBAAqB;AACzD,SAASC,QAAQ,QAAQ,cAAc;AAEvC,OAAO,MAAMC,YAAY,CAAqB;EACjCC,IAAI,GAAG,OAAO;EACfC,MAAM,GAAG,KAAK;EAGtBC,WAAWA,CAACC,OAA4B,EAAE;IACtC,IAAI,CAACA,OAAO,GAAGA,OAAO;EAC1B;EAEAC,UAAUA,CAACC,QAAwB,EAAQ;IACvC,IAAI,IAAI,CAACJ,MAAM,EAAE;IACjBP,qBAAqB,CAAC,CAACY,KAAY,EAAEC,OAAgB,KAAK;MACtDX,gBAAgB,CAAC,CAAC,CAACY,MAAM,CAAC;QACtBC,MAAM,EAAE,IAAI;QACZC,IAAI,EAAEH,OAAO,GAAG,OAAO,GAAG,SAAS;QACnCA,OAAO;QACPI,OAAO,EAAEL,KAAK,CAACK,OAAO;QACtBC,KAAK,EAAEN,KAAK,CAACM;MACjB,CAAC,CAAC;MAEF,IAAIL,OAAO,EAAE;QACT;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;QACgBV,mBAAmB,CAAC;UAChBc,OAAO,EAAEL,KAAK,CAACK,OAAO;UACtBC,KAAK,EAAEN,KAAK,CAACM,KAAK;UAClBC,QAAQ,EAAEf,QAAQ,CAACgB;QACvB,CAAC,CAAC;QACF;QACA,IAAI,CAACX,OAAO,CAAC,CAAC;MAClB;IACJ,CAAC,CAAC;;IAEF;AACR;AACA;AACA;AACA;AACA;AACA;IACQR,uBAAuB,CAAEW,KAAY,IAAK;MACtCV,gBAAgB,CAAC,CAAC,CAACY,MAAM,CAAC;QACtBC,MAAM,EAAE,IAAI;QACZC,IAAI,EAAE,SAAS;QACfH,OAAO,EAAE,KAAK;QACdI,OAAO,EAAEL,KAAK,CAACK,OAAO;QACtBC,KAAK,EAAEN,KAAK,CAACM;MACjB,CAAC,CAAC;IACN,CAAC,CAAC;IAEF,IAAI,CAACX,MAAM,GAAG,IAAI;EACtB;EAEAc,QAAQA,CAAA,EAAS;IACb;IACA,IAAI,CAACd,MAAM,GAAG,KAAK;EACvB;EAEA,IAAIe,QAAQA,CAAA,EAAY;IACpB,OAAO,IAAI,CAACf,MAAM;EACtB;AACJ","ignoreList":[]}
|
|
@@ -145,12 +145,18 @@ async function drainOne(seen) {
|
|
|
145
145
|
// 2) SaaS backend errors endpoint (dashboard Crashes view) — route the
|
|
146
146
|
// same normalized report through the central reporter. This is what
|
|
147
147
|
// makes native crashes visible in the dashboard, not just the desktop.
|
|
148
|
+
const recordType = typeof crash.type === 'string' ? crash.type : 'native';
|
|
149
|
+
const recordSource = typeof crash.source === 'string' ? crash.source : 'native';
|
|
148
150
|
getCrashReporter().report({
|
|
149
|
-
source:
|
|
150
|
-
type:
|
|
151
|
+
source: recordSource,
|
|
152
|
+
type: recordType,
|
|
151
153
|
isFatal: true,
|
|
152
154
|
message: crash.message ?? crash.exceptionType ?? 'Native crash',
|
|
153
|
-
stack: stackArr.length ? stackArr.join('\n') : undefined,
|
|
155
|
+
stack: stackArr.length ? stackArr.join('\n') : crash.stack ? String(crash.stack) : undefined,
|
|
156
|
+
// Set for a recovered JS crash; a native crash has no JS screen.
|
|
157
|
+
...(crash.screenName ? {
|
|
158
|
+
screenName: String(crash.screenName)
|
|
159
|
+
} : {}),
|
|
154
160
|
platform: crash.platform,
|
|
155
161
|
/**
|
|
156
162
|
* THE ORIGINAL SESSION — the entire point of the recovery path.
|
|
@@ -271,4 +277,55 @@ export async function triggerNativeCrash() {
|
|
|
271
277
|
// The process is expected to die; nothing to handle.
|
|
272
278
|
}
|
|
273
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Persist a FATAL JS crash to disk BEFORE the process dies.
|
|
282
|
+
*
|
|
283
|
+
* A fatal JS error tears the process down almost immediately. The normal error
|
|
284
|
+
* path queues the crash and POSTs it asynchronously, which loses the race: the
|
|
285
|
+
* process is gone before the request finishes, and nothing is on disk to retry.
|
|
286
|
+
* This is why a JS crash could vanish while a native one always survived.
|
|
287
|
+
*
|
|
288
|
+
* The fix is the native module's SYNCHRONOUS persistJsCrash: it writes the
|
|
289
|
+
* record to the same store native crashes use and returns before this function
|
|
290
|
+
* returns — so by the time the JS handler unwinds, the crash is durable. The
|
|
291
|
+
* existing drain path then delivers it on the next launch, at least once,
|
|
292
|
+
* deduped on crashId.
|
|
293
|
+
*
|
|
294
|
+
* Synchronous and no-throw by construction: this runs inside the global error
|
|
295
|
+
* handler, where an exception would replace one crash with another.
|
|
296
|
+
*/
|
|
297
|
+
export function persistFatalJsCrash(input) {
|
|
298
|
+
try {
|
|
299
|
+
const mod = getCrashModule();
|
|
300
|
+
if (!mod?.persistJsCrash) return false;
|
|
301
|
+
// Minted once, here, so a retry from disk dedupes on the backend rather
|
|
302
|
+
// than arriving as a fresh crash every launch.
|
|
303
|
+
const crashId = `jscrash-${nowMs()}-${counter()}`;
|
|
304
|
+
const record = {
|
|
305
|
+
crashId,
|
|
306
|
+
type: 'crash',
|
|
307
|
+
source: 'js',
|
|
308
|
+
isFatal: true,
|
|
309
|
+
message: input.message,
|
|
310
|
+
stack: input.stack,
|
|
311
|
+
screenName: input.screenName,
|
|
312
|
+
platform: input.platform,
|
|
313
|
+
sessionId: input.sessionId,
|
|
314
|
+
timestamp: new Date().toISOString()
|
|
315
|
+
};
|
|
316
|
+
return mod.persistJsCrash(JSON.stringify(record)) === true;
|
|
317
|
+
} catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Monotonic-ish parts for a unique id without pulling in a uuid dependency. */
|
|
323
|
+
let _seq = 0;
|
|
324
|
+
function counter() {
|
|
325
|
+
_seq = (_seq + 1) % 1_000_000;
|
|
326
|
+
return _seq;
|
|
327
|
+
}
|
|
328
|
+
function nowMs() {
|
|
329
|
+
return Date.now();
|
|
330
|
+
}
|
|
274
331
|
//# sourceMappingURL=nativeCrashBridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","nativeModuleVia","logger","getCrashReporter","_crashModule","getCrashModule","mod","turbo","require","default","__DEV__","debug","legacy","ScaleBunCrash","setNativeActiveSession","sessionId","setActiveSessionId","installNativeCrashHandler","install","MAX_DRAIN_PER_LAUNCH","drainNativeCrash","found","seen","Set","i","outcome","drainOne","drainPendingCrash","crash","seenKey","crashId","has","add","stackArr","Array","isArray","stackTrace","
|
|
1
|
+
{"version":3,"names":["NativeModules","nativeModuleVia","logger","getCrashReporter","_crashModule","getCrashModule","mod","turbo","require","default","__DEV__","debug","legacy","ScaleBunCrash","setNativeActiveSession","sessionId","setActiveSessionId","installNativeCrashHandler","install","MAX_DRAIN_PER_LAUNCH","drainNativeCrash","found","seen","Set","i","outcome","drainOne","drainPendingCrash","crash","seenKey","crashId","has","add","stackArr","Array","isArray","stackTrace","recordType","type","recordSource","source","report","isFatal","message","exceptionType","stack","length","join","String","undefined","screenName","platform","metadata","threadName","signal","clearPendingCrash","info","delivered","confirmDelivery","SessionManager","transport","getExistingInstance","getBackendTransport","flushErrors","triggerNativeCrash","crashNow","warn","persistFatalJsCrash","input","persistJsCrash","nowMs","counter","record","timestamp","Date","toISOString","JSON","stringify","_seq","now"],"sourceRoot":"../../../../src","sources":["features/crash/nativeCrashBridge.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","get"],"sourceRoot":"../../../src","sources":["specs/NativeScaleBunCrash.ts"],"mappings":"AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAElD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","get"],"sourceRoot":"../../../src","sources":["specs/NativeScaleBunCrash.ts"],"mappings":"AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAElD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAwCA;AACA;AACA;AACA;AACA;AACA;AACA,eAAeA,mBAAmB,CAACC,GAAG,CAAO,eAAe,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrashFeature.d.ts","sourceRoot":"","sources":["../../../../src/features/crash/CrashFeature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"CrashFeature.d.ts","sourceRoot":"","sources":["../../../../src/features/crash/CrashFeature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAO9E,qBAAa,YAAa,YAAW,QAAQ;IACzC,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAsB;gBAEzB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAIxC,UAAU,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAmD1C,QAAQ,IAAI,IAAI;IAKhB,IAAI,QAAQ,IAAI,OAAO,CAEtB;CACJ"}
|
|
@@ -29,4 +29,28 @@ export declare function drainNativeCrash(): Promise<boolean>;
|
|
|
29
29
|
* No-op when the native module or `crashNow` is unavailable.
|
|
30
30
|
*/
|
|
31
31
|
export declare function triggerNativeCrash(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Persist a FATAL JS crash to disk BEFORE the process dies.
|
|
34
|
+
*
|
|
35
|
+
* A fatal JS error tears the process down almost immediately. The normal error
|
|
36
|
+
* path queues the crash and POSTs it asynchronously, which loses the race: the
|
|
37
|
+
* process is gone before the request finishes, and nothing is on disk to retry.
|
|
38
|
+
* This is why a JS crash could vanish while a native one always survived.
|
|
39
|
+
*
|
|
40
|
+
* The fix is the native module's SYNCHRONOUS persistJsCrash: it writes the
|
|
41
|
+
* record to the same store native crashes use and returns before this function
|
|
42
|
+
* returns — so by the time the JS handler unwinds, the crash is durable. The
|
|
43
|
+
* existing drain path then delivers it on the next launch, at least once,
|
|
44
|
+
* deduped on crashId.
|
|
45
|
+
*
|
|
46
|
+
* Synchronous and no-throw by construction: this runs inside the global error
|
|
47
|
+
* handler, where an exception would replace one crash with another.
|
|
48
|
+
*/
|
|
49
|
+
export declare function persistFatalJsCrash(input: {
|
|
50
|
+
message: string;
|
|
51
|
+
stack?: string;
|
|
52
|
+
screenName?: string;
|
|
53
|
+
platform?: string;
|
|
54
|
+
sessionId?: string;
|
|
55
|
+
}): boolean;
|
|
32
56
|
//# sourceMappingURL=nativeCrashBridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativeCrashBridge.d.ts","sourceRoot":"","sources":["../../../../src/features/crash/nativeCrashBridge.ts"],"names":[],"mappings":"AAwCA;;;;GAIG;AACH;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7E;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAY/D;AAgBD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAYzD;
|
|
1
|
+
{"version":3,"file":"nativeCrashBridge.d.ts","sourceRoot":"","sources":["../../../../src/features/crash/nativeCrashBridge.ts"],"names":[],"mappings":"AAwCA;;;;GAIG;AACH;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7E;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAY/D;AAgBD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAYzD;AAgJD;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWxD;AACD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAuBV"}
|
|
@@ -35,6 +35,17 @@ export interface Spec extends TurboModule {
|
|
|
35
35
|
* can be the moment of deletion — a failed upload must leave the durable copy in place.
|
|
36
36
|
*/
|
|
37
37
|
clearPendingCrash(crashId: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Persist a FATAL JS crash to the same on-disk store native crashes use, so
|
|
40
|
+
* the next launch drains it. SYNCHRONOUS by design (returns a boolean, not a
|
|
41
|
+
* Promise): a fatal JS error tears the process down, and an async POST — or
|
|
42
|
+
* even an async native call — races that teardown and loses the crash. A
|
|
43
|
+
* blocking write completes on disk before the JS handler returns.
|
|
44
|
+
*
|
|
45
|
+
* recordJson is a JSON crash record: at least { crashId, type, message },
|
|
46
|
+
* plus stack / screenName / platform / sessionId / timestamp when known.
|
|
47
|
+
*/
|
|
48
|
+
persistJsCrash(recordJson: string): boolean;
|
|
38
49
|
}
|
|
39
50
|
/**
|
|
40
51
|
* Resolved via `get` (not `getEnforcing`) so the SDK degrades gracefully when
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeScaleBunCrash.d.ts","sourceRoot":"","sources":["../../../src/specs/NativeScaleBunCrash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,0EAA0E;IAC1E,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE5B,wEAAwE;IACxE,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7B;;;;;OAKG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAExD,uEAAuE;IACvE,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAErC;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"NativeScaleBunCrash.d.ts","sourceRoot":"","sources":["../../../src/specs/NativeScaleBunCrash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,0EAA0E;IAC1E,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE5B,wEAAwE;IACxE,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7B;;;;;OAKG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAExD,uEAAuE;IACvE,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAErC;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErD;;;;;;;;;OASG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC7C;AAED;;;;;GAKG;;AACH,wBAA8D"}
|
package/package.json
CHANGED
|
@@ -13,6 +13,8 @@ import type { IFeature, FeatureContext } from '../../core/contracts/IFeature';
|
|
|
13
13
|
import { installCrashReporting } from './index';
|
|
14
14
|
import { installRejectionHandler } from './rejectionHandler';
|
|
15
15
|
import { getCrashReporter } from './CrashReporter';
|
|
16
|
+
import { persistFatalJsCrash } from './nativeCrashBridge';
|
|
17
|
+
import { Platform } from 'react-native';
|
|
16
18
|
|
|
17
19
|
export class CrashFeature implements IFeature {
|
|
18
20
|
readonly name = 'crash';
|
|
@@ -35,7 +37,21 @@ export class CrashFeature implements IFeature {
|
|
|
35
37
|
});
|
|
36
38
|
|
|
37
39
|
if (isFatal) {
|
|
38
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Persist to disk FIRST, synchronously, before anything else.
|
|
42
|
+
*
|
|
43
|
+
* A fatal JS crash tears the process down before an async POST
|
|
44
|
+
* can finish, so the report queued above can be lost. The native
|
|
45
|
+
* write below completes on disk before this handler returns, and
|
|
46
|
+
* the next launch drains and delivers it — the same guarantee
|
|
47
|
+
* native crashes already had, now extended to JS.
|
|
48
|
+
*/
|
|
49
|
+
persistFatalJsCrash({
|
|
50
|
+
message: error.message,
|
|
51
|
+
stack: error.stack,
|
|
52
|
+
platform: Platform.OS,
|
|
53
|
+
});
|
|
54
|
+
// Best-effort live delivery too, in case the process lingers.
|
|
39
55
|
this.flushFn();
|
|
40
56
|
}
|
|
41
57
|
});
|
|
@@ -145,12 +145,20 @@ async function drainOne(seen: Set<string>): Promise<'none' | 'cleared' | 'kept'>
|
|
|
145
145
|
// 2) SaaS backend errors endpoint (dashboard Crashes view) — route the
|
|
146
146
|
// same normalized report through the central reporter. This is what
|
|
147
147
|
// makes native crashes visible in the dashboard, not just the desktop.
|
|
148
|
+
const recordType = typeof crash.type === 'string' ? crash.type : 'native';
|
|
149
|
+
const recordSource = typeof crash.source === 'string' ? crash.source : 'native';
|
|
148
150
|
getCrashReporter().report({
|
|
149
|
-
source:
|
|
150
|
-
type:
|
|
151
|
+
source: recordSource,
|
|
152
|
+
type: recordType,
|
|
151
153
|
isFatal: true,
|
|
152
154
|
message: crash.message ?? crash.exceptionType ?? 'Native crash',
|
|
153
|
-
stack: stackArr.length
|
|
155
|
+
stack: stackArr.length
|
|
156
|
+
? stackArr.join('\n')
|
|
157
|
+
: crash.stack
|
|
158
|
+
? String(crash.stack)
|
|
159
|
+
: undefined,
|
|
160
|
+
// Set for a recovered JS crash; a native crash has no JS screen.
|
|
161
|
+
...(crash.screenName ? { screenName: String(crash.screenName) } : {}),
|
|
154
162
|
platform: crash.platform,
|
|
155
163
|
/**
|
|
156
164
|
* THE ORIGINAL SESSION — the entire point of the recovery path.
|
|
@@ -264,3 +272,61 @@ export async function triggerNativeCrash(): Promise<void> {
|
|
|
264
272
|
// The process is expected to die; nothing to handle.
|
|
265
273
|
}
|
|
266
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Persist a FATAL JS crash to disk BEFORE the process dies.
|
|
277
|
+
*
|
|
278
|
+
* A fatal JS error tears the process down almost immediately. The normal error
|
|
279
|
+
* path queues the crash and POSTs it asynchronously, which loses the race: the
|
|
280
|
+
* process is gone before the request finishes, and nothing is on disk to retry.
|
|
281
|
+
* This is why a JS crash could vanish while a native one always survived.
|
|
282
|
+
*
|
|
283
|
+
* The fix is the native module's SYNCHRONOUS persistJsCrash: it writes the
|
|
284
|
+
* record to the same store native crashes use and returns before this function
|
|
285
|
+
* returns — so by the time the JS handler unwinds, the crash is durable. The
|
|
286
|
+
* existing drain path then delivers it on the next launch, at least once,
|
|
287
|
+
* deduped on crashId.
|
|
288
|
+
*
|
|
289
|
+
* Synchronous and no-throw by construction: this runs inside the global error
|
|
290
|
+
* handler, where an exception would replace one crash with another.
|
|
291
|
+
*/
|
|
292
|
+
export function persistFatalJsCrash(input: {
|
|
293
|
+
message: string;
|
|
294
|
+
stack?: string;
|
|
295
|
+
screenName?: string;
|
|
296
|
+
platform?: string;
|
|
297
|
+
sessionId?: string;
|
|
298
|
+
}): boolean {
|
|
299
|
+
try {
|
|
300
|
+
const mod = getCrashModule();
|
|
301
|
+
if (!mod?.persistJsCrash) return false;
|
|
302
|
+
// Minted once, here, so a retry from disk dedupes on the backend rather
|
|
303
|
+
// than arriving as a fresh crash every launch.
|
|
304
|
+
const crashId = `jscrash-${nowMs()}-${counter()}`;
|
|
305
|
+
const record = {
|
|
306
|
+
crashId,
|
|
307
|
+
type: 'crash',
|
|
308
|
+
source: 'js',
|
|
309
|
+
isFatal: true,
|
|
310
|
+
message: input.message,
|
|
311
|
+
stack: input.stack,
|
|
312
|
+
screenName: input.screenName,
|
|
313
|
+
platform: input.platform,
|
|
314
|
+
sessionId: input.sessionId,
|
|
315
|
+
timestamp: new Date().toISOString(),
|
|
316
|
+
};
|
|
317
|
+
return mod.persistJsCrash(JSON.stringify(record)) === true;
|
|
318
|
+
} catch {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** Monotonic-ish parts for a unique id without pulling in a uuid dependency. */
|
|
324
|
+
let _seq = 0;
|
|
325
|
+
function counter(): number {
|
|
326
|
+
_seq = (_seq + 1) % 1_000_000;
|
|
327
|
+
return _seq;
|
|
328
|
+
}
|
|
329
|
+
function nowMs(): number {
|
|
330
|
+
return Date.now();
|
|
331
|
+
}
|
|
332
|
+
|
|
@@ -41,6 +41,18 @@ export interface Spec extends TurboModule {
|
|
|
41
41
|
* can be the moment of deletion — a failed upload must leave the durable copy in place.
|
|
42
42
|
*/
|
|
43
43
|
clearPendingCrash(crashId: string): Promise<boolean>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Persist a FATAL JS crash to the same on-disk store native crashes use, so
|
|
47
|
+
* the next launch drains it. SYNCHRONOUS by design (returns a boolean, not a
|
|
48
|
+
* Promise): a fatal JS error tears the process down, and an async POST — or
|
|
49
|
+
* even an async native call — races that teardown and loses the crash. A
|
|
50
|
+
* blocking write completes on disk before the JS handler returns.
|
|
51
|
+
*
|
|
52
|
+
* recordJson is a JSON crash record: at least { crashId, type, message },
|
|
53
|
+
* plus stack / screenName / platform / sessionId / timestamp when known.
|
|
54
|
+
*/
|
|
55
|
+
persistJsCrash(recordJson: string): boolean;
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
/**
|