@goliapkg/sentori-react-native 5.1.0 → 5.1.2
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/ios/SentoriScreenshotCapture.swift +16 -1
- package/lib/init.d.ts.map +1 -1
- package/lib/init.js +9 -20
- package/lib/init.js.map +1 -1
- package/lib/mask.d.ts.map +1 -1
- package/lib/mask.js +4 -1
- package/lib/mask.js.map +1 -1
- package/lib/transport.d.ts +19 -1
- package/lib/transport.d.ts.map +1 -1
- package/lib/transport.js +51 -9
- package/lib/transport.js.map +1 -1
- package/lib/verbs.d.ts.map +1 -1
- package/lib/verbs.js +37 -1
- package/lib/verbs.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/transport.test.ts +6 -0
- package/src/__tests__/verbs.test.ts +43 -0
- package/src/init.ts +9 -31
- package/src/mask.ts +4 -1
- package/src/transport.ts +67 -10
- package/src/verbs.ts +41 -1
|
@@ -275,8 +275,23 @@ import UIKit
|
|
|
275
275
|
ids: Set<String>
|
|
276
276
|
) -> [UIView] {
|
|
277
277
|
var found: [UIView] = []
|
|
278
|
-
func
|
|
278
|
+
func matches(_ v: UIView) -> Bool {
|
|
279
|
+
// RN maps `testID` to accessibilityIdentifier on iOS,
|
|
280
|
+
// and keeps `nativeID` as its own property on the view —
|
|
281
|
+
// accept either so a host masks with one prop on both
|
|
282
|
+
// platforms (Android matches nativeID via the view tag).
|
|
279
283
|
if let id = v.accessibilityIdentifier, ids.contains(id) {
|
|
284
|
+
return true
|
|
285
|
+
}
|
|
286
|
+
if v.responds(to: NSSelectorFromString("nativeID")),
|
|
287
|
+
let nid = v.value(forKey: "nativeID") as? String,
|
|
288
|
+
ids.contains(nid) {
|
|
289
|
+
return true
|
|
290
|
+
}
|
|
291
|
+
return false
|
|
292
|
+
}
|
|
293
|
+
func walk(_ v: UIView) {
|
|
294
|
+
if matches(v) {
|
|
280
295
|
found.append(v)
|
|
281
296
|
return
|
|
282
297
|
}
|
package/lib/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,eAAO,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,eAAO,MAAM,IAAI,0CAsFf,CAAC;AAGH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
|
package/lib/init.js
CHANGED
|
@@ -15,7 +15,7 @@ import { markNativeJsBridgeReady, setNativeConfig } from './native';
|
|
|
15
15
|
import { shipNativePending } from './native-pending';
|
|
16
16
|
import { drainReplay, startReplay } from './replay';
|
|
17
17
|
import { drainScreenReplay, startScreenReplay } from './replay-screens';
|
|
18
|
-
import { drainOfflineQueue,
|
|
18
|
+
import { drainOfflineQueue, queueAttachment, startTransport } from './transport';
|
|
19
19
|
let _initialized = false;
|
|
20
20
|
export const init = safeFn('init', (config) => {
|
|
21
21
|
if (_initialized)
|
|
@@ -72,17 +72,17 @@ export const init = safeFn('init', (config) => {
|
|
|
72
72
|
return;
|
|
73
73
|
const lines = drainReplay();
|
|
74
74
|
if (lines) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
75
|
+
queueAttachment(event.id, 'replay', {
|
|
76
|
+
text: lines,
|
|
77
|
+
mediaType: 'application/x-sentori-replay',
|
|
78
|
+
});
|
|
79
79
|
}
|
|
80
80
|
const frames = drainScreenReplay();
|
|
81
81
|
if (frames) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
82
|
+
queueAttachment(event.id, 'screens', {
|
|
83
|
+
text: frames,
|
|
84
|
+
mediaType: 'application/x-sentori-screens',
|
|
85
|
+
});
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
}
|
|
@@ -101,17 +101,6 @@ export const init = safeFn('init', (config) => {
|
|
|
101
101
|
void shipNativePending().catch(() => undefined);
|
|
102
102
|
void drainOfflineQueue();
|
|
103
103
|
});
|
|
104
|
-
/** RN's Hermes has no btoa in older releases; go through base64.ts. */
|
|
105
|
-
const base64Encode = (text) => {
|
|
106
|
-
try {
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
108
|
-
const { encodeBase64 } = require('./base64');
|
|
109
|
-
return encodeBase64(text);
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
104
|
export const __resetForTests = () => {
|
|
116
105
|
_initialized = false;
|
|
117
106
|
};
|
package/lib/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,mEAAmE;AACnE,6DAA6D;AAC7D,iCAAiC;AAEjC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG7D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/lib/mask.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAkBA,KAAK,SAAS,GAAG,MAAM,MAAM,EAAE,CAAC;AAIhC,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,UAAW,SAAS,GAAG,IAAI,KAAG,IAE3D,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,eAAe,QAAO,MAAM,EASxC,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
|
package/lib/mask.js
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The host registers a query returning the `nativeID`s of views
|
|
4
4
|
// that must never appear in a screenshot (camera feeds, user
|
|
5
|
-
// identity, payment fields).
|
|
5
|
+
// identity, payment fields). On iOS the native matcher accepts the
|
|
6
|
+
// same value via either `nativeID` or `testID` (RN maps testID to
|
|
7
|
+
// accessibilityIdentifier); on Android `nativeID` rides the view
|
|
8
|
+
// tag. One prop, both platforms: use `nativeID`. Native paints black rectangles over
|
|
6
9
|
// those subtrees in the same render pass, so the pixels never
|
|
7
10
|
// leave the device.
|
|
8
11
|
//
|
package/lib/mask.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mask.js","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,gEAAgE;AAChE,6DAA6D;AAC7D,iEAAiE;AACjE,8DAA8D;AAC9D,oBAAoB;AACpB,EAAE;AACF,8DAA8D;AAC9D,iEAAiE;AACjE,+DAA+D;AAC/D,2DAA2D;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIxD,IAAI,MAAM,GAAqB,IAAI,CAAC;AAEpC,uDAAuD;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAuB,EAAQ,EAAE;IACjE,MAAM,GAAG,KAAK,CAAC;AACjB,CAAC,CAAC;AAEF,kEAAkE;AAClE,MAAM,CAAC,MAAM,eAAe,GAAG,GAAa,EAAE;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE;IACxC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"mask.js","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,gEAAgE;AAChE,6DAA6D;AAC7D,mEAAmE;AACnE,kEAAkE;AAClE,iEAAiE;AACjE,qFAAqF;AACrF,8DAA8D;AAC9D,oBAAoB;AACpB,EAAE;AACF,8DAA8D;AAC9D,iEAAiE;AACjE,+DAA+D;AAC/D,2DAA2D;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIxD,IAAI,MAAM,GAAqB,IAAI,CAAC;AAEpC,uDAAuD;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAuB,EAAQ,EAAE;IACjE,MAAM,GAAG,KAAK,CAAC;AACjB,CAAC,CAAC;AAEF,kEAAkE;AAClE,MAAM,CAAC,MAAM,eAAe,GAAG,GAAa,EAAE;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE;IACxC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC,CAAC"}
|
package/lib/transport.d.ts
CHANGED
|
@@ -8,6 +8,21 @@ export declare const enqueue: (event: WireEvent) => void;
|
|
|
8
8
|
export declare const countAssert: (name: string, ok: boolean, release: string) => void;
|
|
9
9
|
export declare const startTransport: () => void;
|
|
10
10
|
export declare const flush: () => Promise<void>;
|
|
11
|
+
type QueuedAttachment = {
|
|
12
|
+
kind: import('@goliapkg/sentori-core').AttachmentKind;
|
|
13
|
+
blob: {
|
|
14
|
+
base64?: string;
|
|
15
|
+
text?: string;
|
|
16
|
+
mediaType: string;
|
|
17
|
+
};
|
|
18
|
+
source: 'android' | 'ios' | 'js';
|
|
19
|
+
};
|
|
20
|
+
/** Attach a blob to an event that is still in the batch queue. It
|
|
21
|
+
* uploads right after the batch containing the event lands, so the
|
|
22
|
+
* server always already knows the event. */
|
|
23
|
+
export declare const queueAttachment: (eventId: string, kind: QueuedAttachment['kind'], blob: QueuedAttachment['blob'], opts?: {
|
|
24
|
+
source?: QueuedAttachment['source'];
|
|
25
|
+
}) => void;
|
|
11
26
|
export declare const drainOfflineQueue: () => Promise<void>;
|
|
12
27
|
/**
|
|
13
28
|
* Upload one attachment for an already-enqueued event. Returns null
|
|
@@ -15,7 +30,8 @@ export declare const drainOfflineQueue: () => Promise<void>;
|
|
|
15
30
|
* attachment so the crash itself is never lost.
|
|
16
31
|
*/
|
|
17
32
|
export declare const uploadAttachment: (eventId: string, kind: import('@goliapkg/sentori-core').AttachmentKind, blob: {
|
|
18
|
-
base64
|
|
33
|
+
base64?: string;
|
|
34
|
+
text?: string;
|
|
19
35
|
mediaType: string;
|
|
20
36
|
}, opts?: {
|
|
21
37
|
source?: 'android' | 'ios' | 'js';
|
|
@@ -24,5 +40,7 @@ export declare const uploadAttachment: (eventId: string, kind: import('@goliapkg
|
|
|
24
40
|
} | null>;
|
|
25
41
|
export declare const __resetForTests: () => void;
|
|
26
42
|
export declare const __peekQueue: () => readonly WireEvent[];
|
|
43
|
+
export declare const __sdkVersion: () => string;
|
|
27
44
|
export declare const __peekAssertStats: () => readonly AssertStat[];
|
|
45
|
+
export {};
|
|
28
46
|
//# sourceMappingURL=transport.d.ts.map
|
package/lib/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAiB,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAiB,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAoBnF,eAAO,MAAM,OAAO,UAAW,SAAS,KAAG,IAU1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,SAAU,MAAM,MAAM,OAAO,WAAW,MAAM,KAAG,IAcxE,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,IAEjC,CAAC;AAEF,eAAO,MAAM,KAAK,QAAa,OAAO,CAAC,IAAI,CA+B1C,CAAC;AAIF,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,OAAO,wBAAwB,EAAE,cAAc,CAAC;IACtD,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;CAClC,CAAC;AAIF;;6CAE6C;AAC7C,eAAO,MAAM,eAAe,YACjB,MAAM,QACT,gBAAgB,CAAC,MAAM,CAAC,QACxB,gBAAgB,CAAC,MAAM,CAAC,SACxB;IAAE,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;CAAE,KAC5C,IAIF,CAAC;AA0GF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,IAAI,CAatD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,YAClB,MAAM,QACT,OAAO,wBAAwB,EAAE,cAAc,QAC/C;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,SACrD;IAAE,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,IAAI,CAAA;CAAE,KAC1C,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA8ChC,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAMlC,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,SAAS,SAAS,EAAY,CAAC;AAC9D,eAAO,MAAM,YAAY,QAAO,MAAqB,CAAC;AACtD,eAAO,MAAM,iBAAiB,QAAO,SAAS,UAAU,EAAgC,CAAC"}
|
package/lib/transport.js
CHANGED
|
@@ -14,7 +14,8 @@ const BATCH_SIZE = 10;
|
|
|
14
14
|
const MAX_RETRY = 3;
|
|
15
15
|
const STORAGE_KEY = '@sentori/pending';
|
|
16
16
|
const MAX_PERSISTED = 1000;
|
|
17
|
-
|
|
17
|
+
// Pinned to package.json by a test — bump both together.
|
|
18
|
+
const SDK_VERSION = '5.1.2';
|
|
18
19
|
let _queue = [];
|
|
19
20
|
let _assertStats = new Map();
|
|
20
21
|
let _flushTimer = null;
|
|
@@ -76,12 +77,39 @@ export const flush = async () => {
|
|
|
76
77
|
envelope.assertStats = stats;
|
|
77
78
|
try {
|
|
78
79
|
await sendWithRetry(envelope, config.ingestUrl, config.token);
|
|
80
|
+
// Only now do the events exist server-side — release their
|
|
81
|
+
// queued attachments. Uploading before this point 404s: the
|
|
82
|
+
// attachment races the 5s event batch and always wins.
|
|
83
|
+
for (const ev of events) {
|
|
84
|
+
if (ev.id)
|
|
85
|
+
void sendQueuedAttachments(ev.id);
|
|
86
|
+
}
|
|
79
87
|
}
|
|
80
88
|
catch {
|
|
81
89
|
// Events survive offline; assert deltas are cheap enough to lose.
|
|
90
|
+
// Their attachments are memory-only and lost with the process —
|
|
91
|
+
// documented; a replay is context, not the crash report itself.
|
|
82
92
|
await persist(events);
|
|
83
93
|
}
|
|
84
94
|
};
|
|
95
|
+
const _pendingAttachments = new Map();
|
|
96
|
+
/** Attach a blob to an event that is still in the batch queue. It
|
|
97
|
+
* uploads right after the batch containing the event lands, so the
|
|
98
|
+
* server always already knows the event. */
|
|
99
|
+
export const queueAttachment = (eventId, kind, blob, opts = {}) => {
|
|
100
|
+
const list = _pendingAttachments.get(eventId) ?? [];
|
|
101
|
+
list.push({ kind, blob, source: opts.source ?? 'js' });
|
|
102
|
+
_pendingAttachments.set(eventId, list);
|
|
103
|
+
};
|
|
104
|
+
const sendQueuedAttachments = async (eventId) => {
|
|
105
|
+
const list = _pendingAttachments.get(eventId);
|
|
106
|
+
if (!list)
|
|
107
|
+
return;
|
|
108
|
+
_pendingAttachments.delete(eventId);
|
|
109
|
+
for (const a of list) {
|
|
110
|
+
await uploadAttachment(eventId, a.kind, a.blob, { source: a.source });
|
|
111
|
+
}
|
|
112
|
+
};
|
|
85
113
|
const sendWithRetry = async (envelope, ingestUrl, token) => {
|
|
86
114
|
let attempt = 0;
|
|
87
115
|
let delayMs = 1000;
|
|
@@ -190,18 +218,31 @@ export const uploadAttachment = async (eventId, kind, blob, opts = {}) => {
|
|
|
190
218
|
if (!config)
|
|
191
219
|
return null;
|
|
192
220
|
const url = `${config.ingestUrl}/v1/events/${encodeURIComponent(eventId)}/attachments/${encodeURIComponent(kind)}`;
|
|
193
|
-
|
|
194
|
-
form
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
221
|
+
// Hand-built multipart. React Native's FormData file part wants a
|
|
222
|
+
// `uri`, and its `data:` URI form throws a bare network error on
|
|
223
|
+
// iOS — this shipped untested and every JS attachment silently
|
|
224
|
+
// died. Text payloads (replay/screens NDJSON) embed directly;
|
|
225
|
+
// base64 payloads embed as base64 with the transfer-encoding
|
|
226
|
+
// header so the server knows to decode.
|
|
227
|
+
const boundary = `----sentori-${eventId}`;
|
|
228
|
+
const isText = typeof blob.text === 'string';
|
|
229
|
+
const content = isText ? (blob.text ?? '') : (blob.base64 ?? '');
|
|
230
|
+
const encodingHeader = isText ? '' : 'Content-Transfer-Encoding: base64\r\n';
|
|
231
|
+
const wireBody = `--${boundary}\r\n` +
|
|
232
|
+
`Content-Disposition: form-data; name="file"; filename="${kind}.bin"\r\n` +
|
|
233
|
+
`Content-Type: ${blob.mediaType}\r\n` +
|
|
234
|
+
encodingHeader +
|
|
235
|
+
`\r\n${content}\r\n` +
|
|
236
|
+
`--${boundary}\r\n` +
|
|
237
|
+
`Content-Disposition: form-data; name="source"\r\n` +
|
|
238
|
+
`\r\n${opts.source ?? 'js'}\r\n` +
|
|
239
|
+
`--${boundary}--\r\n`;
|
|
200
240
|
try {
|
|
201
241
|
const resp = await fetch(url, {
|
|
202
|
-
body:
|
|
242
|
+
body: wireBody,
|
|
203
243
|
headers: {
|
|
204
244
|
Authorization: `Bearer ${config.token}`,
|
|
245
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
205
246
|
'Sentori-Sdk': `react-native/${SDK_VERSION}`,
|
|
206
247
|
},
|
|
207
248
|
method: 'POST',
|
|
@@ -227,5 +268,6 @@ export const __resetForTests = () => {
|
|
|
227
268
|
_started = false;
|
|
228
269
|
};
|
|
229
270
|
export const __peekQueue = () => _queue;
|
|
271
|
+
export const __sdkVersion = () => SDK_VERSION;
|
|
230
272
|
export const __peekAssertStats = () => [..._assertStats.values()];
|
|
231
273
|
//# sourceMappingURL=transport.js.map
|
package/lib/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/lib/verbs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verbs.d.ts","sourceRoot":"","sources":["../src/verbs.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,SAAS,EAGT,OAAO,EACP,YAAY,EAGb,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"verbs.d.ts","sourceRoot":"","sources":["../src/verbs.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,SAAS,EAGT,OAAO,EACP,YAAY,EAGb,MAAM,wBAAwB,CAAC;AAgJhC,eAAO,MAAM,KAAK,oEAOhB,CAAC;AAEH,eAAO,MAAM,IAAI,oEAWhB,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,YAAY,aACb,MAAM,WACP,OAAO,SACT,SAAS,KACf,MACiE,CAAC;AAErE,eAAO,MAAM,KAAK,qGAQjB,CAAC;AAEF,eAAO,MAAM,MAAM,iFAQlB,CAAC;AAEF,eAAO,MAAM,KAAK,mEAIhB,CAAC;AAKH,eAAO,MAAM,KAAK;IAChB,KAAK,QAAQ,OAAO,SAAS,SAAS,KAAG,MAAM;IAC/C,IAAI,SAAS,MAAM,SAAS,SAAS,KAAG,MAAM;IAC9C,KAAK,SAAS,MAAM,SAAS,SAAS,SAAS,YAAY,KAAG,MAAM;IAEpE,MAAM,SAAS,MAAM,MAAM,OAAO,SAAS,SAAS,KAAG,MAAM;IAE7D,KAAK,QAAQ,MAAM,SAAS,SAAS,KAAG,MAAM;CAC/C,CAAC"}
|
package/lib/verbs.js
CHANGED
|
@@ -11,6 +11,7 @@ import { coerceError, parseStack, pushSignal, safeFn, snapshotSignals, uuidV7, }
|
|
|
11
11
|
import { getConfig } from './config';
|
|
12
12
|
import { collectDevice } from './device';
|
|
13
13
|
import { onEventEmitted } from './emit-hooks';
|
|
14
|
+
import { symbolicateErrorViaMetro } from './handlers/dev-symbolicate';
|
|
14
15
|
import { currentContext, currentUserKey } from './scope';
|
|
15
16
|
import { countAssert, enqueue } from './transport';
|
|
16
17
|
/** Serialize any Error instances found in the data argument — the
|
|
@@ -97,10 +98,45 @@ const emit = (kind, opts) => {
|
|
|
97
98
|
// not cost them the crash report.
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
|
|
101
|
+
// In dev there is no uploaded source map, so without local
|
|
102
|
+
// symbolication errors land as `entry.bundle:721724`. Hold the
|
|
103
|
+
// event out of the batch until Metro's /symbolicate answers
|
|
104
|
+
// (bounded at 2 s inside, never throws) — mutating it after
|
|
105
|
+
// enqueue would race the flush timer. Release builds and
|
|
106
|
+
// error-free events enqueue synchronously as before.
|
|
107
|
+
if (isDevRuntime() && hasErrorShape(payload)) {
|
|
108
|
+
void devSymbolicateThenEnqueue(event);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
enqueue(event);
|
|
112
|
+
}
|
|
101
113
|
onEventEmitted(event);
|
|
102
114
|
return id;
|
|
103
115
|
};
|
|
116
|
+
const isDevRuntime = () => typeof __DEV__ !== 'undefined' && !!__DEV__;
|
|
117
|
+
const hasErrorShape = (payload) => {
|
|
118
|
+
if (payload.error)
|
|
119
|
+
return true;
|
|
120
|
+
return Object.values(payload.data ?? {}).some((v) => !!v && typeof v === 'object' && Array.isArray(v.stack));
|
|
121
|
+
};
|
|
122
|
+
const devSymbolicateThenEnqueue = async (event) => {
|
|
123
|
+
try {
|
|
124
|
+
const { error: err, data } = event.payload;
|
|
125
|
+
if (err)
|
|
126
|
+
await symbolicateErrorViaMetro(err);
|
|
127
|
+
for (const v of Object.values(data ?? {})) {
|
|
128
|
+
// The error-in-data convention: serialized errors riding warn/
|
|
129
|
+
// trace data get the same treatment as the headline error.
|
|
130
|
+
if (!!v && typeof v === 'object' && Array.isArray(v.stack)) {
|
|
131
|
+
await symbolicateErrorViaMetro(v);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Symbolication is garnish; delivery is the contract.
|
|
137
|
+
}
|
|
138
|
+
enqueue(event);
|
|
139
|
+
};
|
|
104
140
|
// ── the verbs ──────────────────────────────────────────────────────
|
|
105
141
|
export const error = safeFn('error', (err, data) => {
|
|
106
142
|
const coerced = coerceError(err);
|
package/lib/verbs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verbs.js","sourceRoot":"","sources":["../src/verbs.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,oEAAoE;AACpE,uCAAuC;AACvC,EAAE;AACF,iCAAiC;AACjC,mCAAmC;AACnC,mCAAmC;AACnC,mCAAmC;AACnC,uCAAuC;AAEvC,OAAO,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,MAAM,EACN,eAAe,EACf,MAAM,GACP,MAAM,wBAAwB,CAAC;AAWhC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"verbs.js","sourceRoot":"","sources":["../src/verbs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goliapkg/sentori-react-native",
|
|
3
|
-
"version": "5.1.
|
|
4
|
-
"description": "Sentori SDK for React Native
|
|
3
|
+
"version": "5.1.2",
|
|
4
|
+
"description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"author": "GOLIA K.K. <takagi@golia.jp> (https://golia.jp)",
|
|
7
7
|
"homepage": "https://sentori.golia.jp",
|
|
@@ -98,3 +98,9 @@ describe('transport (v1 wire)', () => {
|
|
|
98
98
|
expect(__peekQueue().length).toBe(1);
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
|
+
|
|
102
|
+
it('SDK_VERSION constant matches package.json (staleness gate)', async () => {
|
|
103
|
+
const { __sdkVersion } = await import('../transport');
|
|
104
|
+
const pkg = (await import('../../package.json')) as { default?: { version?: string }; version?: string };
|
|
105
|
+
expect(__sdkVersion()).toBe(pkg.default?.version ?? pkg.version);
|
|
106
|
+
});
|
|
@@ -89,3 +89,46 @@ describe('the five verbs', () => {
|
|
|
89
89
|
expect(__peekQueue().length).toBe(0);
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
|
+
|
|
93
|
+
describe('dev symbolication wiring', () => {
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
resetTransport();
|
|
96
|
+
resetConfig();
|
|
97
|
+
resetScope();
|
|
98
|
+
clearSignals();
|
|
99
|
+
setConfig(baseConfig);
|
|
100
|
+
startTransport();
|
|
101
|
+
});
|
|
102
|
+
afterEach(() => {
|
|
103
|
+
resetTransport();
|
|
104
|
+
resetConfig();
|
|
105
|
+
resetScope();
|
|
106
|
+
clearSignals();
|
|
107
|
+
delete (globalThis as { __DEV__?: boolean }).__DEV__;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('in __DEV__ an error is enqueued asynchronously, never lost', async () => {
|
|
111
|
+
(globalThis as { __DEV__?: boolean }).__DEV__ = true;
|
|
112
|
+
const id = verbs.error(new Error('dev boom'));
|
|
113
|
+
expect(typeof id).toBe('string');
|
|
114
|
+
// Held out of the batch while Metro symbolication settles…
|
|
115
|
+
expect(__peekQueue().length).toBe(0);
|
|
116
|
+
// …and lands afterwards (no Metro in tests → original stack).
|
|
117
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
118
|
+
expect(__peekQueue().length).toBe(1);
|
|
119
|
+
expect(__peekQueue()[0]?.payload.error?.message).toBe('dev boom');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('outside __DEV__ the error path stays fully synchronous', () => {
|
|
123
|
+
verbs.error(new Error('prod boom'));
|
|
124
|
+
expect(__peekQueue().length).toBe(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('a warn carrying error-in-data also takes the deferred path in dev', async () => {
|
|
128
|
+
(globalThis as { __DEV__?: boolean }).__DEV__ = true;
|
|
129
|
+
verbs.warn('pay.retry', { error: new TypeError('gateway 503') });
|
|
130
|
+
expect(__peekQueue().length).toBe(0);
|
|
131
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
132
|
+
expect(__peekQueue().length).toBe(1);
|
|
133
|
+
});
|
|
134
|
+
});
|
package/src/init.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { markNativeJsBridgeReady, setNativeConfig } from './native';
|
|
|
18
18
|
import { shipNativePending } from './native-pending';
|
|
19
19
|
import { drainReplay, startReplay } from './replay';
|
|
20
20
|
import { drainScreenReplay, startScreenReplay } from './replay-screens';
|
|
21
|
-
import { drainOfflineQueue,
|
|
21
|
+
import { drainOfflineQueue, queueAttachment, startTransport } from './transport';
|
|
22
22
|
|
|
23
23
|
let _initialized = false;
|
|
24
24
|
|
|
@@ -78,27 +78,17 @@ export const init = safeFn('init', (config: InitConfig): void => {
|
|
|
78
78
|
if (!event.id) return;
|
|
79
79
|
const lines = drainReplay();
|
|
80
80
|
if (lines) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
'replay',
|
|
86
|
-
{ base64, mediaType: 'application/x-sentori-replay' },
|
|
87
|
-
{ source: 'js' },
|
|
88
|
-
);
|
|
89
|
-
}
|
|
81
|
+
queueAttachment(event.id, 'replay', {
|
|
82
|
+
text: lines,
|
|
83
|
+
mediaType: 'application/x-sentori-replay',
|
|
84
|
+
});
|
|
90
85
|
}
|
|
91
86
|
const frames = drainScreenReplay();
|
|
92
87
|
if (frames) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
'screens',
|
|
98
|
-
{ base64, mediaType: 'application/x-sentori-screens' },
|
|
99
|
-
{ source: 'js' },
|
|
100
|
-
);
|
|
101
|
-
}
|
|
88
|
+
queueAttachment(event.id, 'screens', {
|
|
89
|
+
text: frames,
|
|
90
|
+
mediaType: 'application/x-sentori-screens',
|
|
91
|
+
});
|
|
102
92
|
}
|
|
103
93
|
});
|
|
104
94
|
}
|
|
@@ -120,18 +110,6 @@ export const init = safeFn('init', (config: InitConfig): void => {
|
|
|
120
110
|
void drainOfflineQueue();
|
|
121
111
|
});
|
|
122
112
|
|
|
123
|
-
/** RN's Hermes has no btoa in older releases; go through base64.ts. */
|
|
124
|
-
const base64Encode = (text: string): string | null => {
|
|
125
|
-
try {
|
|
126
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
127
|
-
const { encodeBase64 } = require('./base64') as {
|
|
128
|
-
encodeBase64: (s: string) => string;
|
|
129
|
-
};
|
|
130
|
-
return encodeBase64(text);
|
|
131
|
-
} catch {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
113
|
|
|
136
114
|
export const __resetForTests = (): void => {
|
|
137
115
|
_initialized = false;
|
package/src/mask.ts
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The host registers a query returning the `nativeID`s of views
|
|
4
4
|
// that must never appear in a screenshot (camera feeds, user
|
|
5
|
-
// identity, payment fields).
|
|
5
|
+
// identity, payment fields). On iOS the native matcher accepts the
|
|
6
|
+
// same value via either `nativeID` or `testID` (RN maps testID to
|
|
7
|
+
// accessibilityIdentifier); on Android `nativeID` rides the view
|
|
8
|
+
// tag. One prop, both platforms: use `nativeID`. Native paints black rectangles over
|
|
6
9
|
// those subtrees in the same render pass, so the pixels never
|
|
7
10
|
// leave the device.
|
|
8
11
|
//
|
package/src/transport.ts
CHANGED
|
@@ -19,7 +19,8 @@ const MAX_RETRY = 3;
|
|
|
19
19
|
const STORAGE_KEY = '@sentori/pending';
|
|
20
20
|
const MAX_PERSISTED = 1000;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// Pinned to package.json by a test — bump both together.
|
|
23
|
+
const SDK_VERSION = '5.1.2';
|
|
23
24
|
|
|
24
25
|
let _queue: WireEvent[] = [];
|
|
25
26
|
let _assertStats = new Map<string, AssertStat>();
|
|
@@ -82,12 +83,53 @@ export const flush = async (): Promise<void> => {
|
|
|
82
83
|
|
|
83
84
|
try {
|
|
84
85
|
await sendWithRetry(envelope, config.ingestUrl, config.token);
|
|
86
|
+
// Only now do the events exist server-side — release their
|
|
87
|
+
// queued attachments. Uploading before this point 404s: the
|
|
88
|
+
// attachment races the 5s event batch and always wins.
|
|
89
|
+
for (const ev of events) {
|
|
90
|
+
if (ev.id) void sendQueuedAttachments(ev.id);
|
|
91
|
+
}
|
|
85
92
|
} catch {
|
|
86
93
|
// Events survive offline; assert deltas are cheap enough to lose.
|
|
94
|
+
// Their attachments are memory-only and lost with the process —
|
|
95
|
+
// documented; a replay is context, not the crash report itself.
|
|
87
96
|
await persist(events);
|
|
88
97
|
}
|
|
89
98
|
};
|
|
90
99
|
|
|
100
|
+
// ── attachments (deferred until their event is delivered) ─────────
|
|
101
|
+
|
|
102
|
+
type QueuedAttachment = {
|
|
103
|
+
kind: import('@goliapkg/sentori-core').AttachmentKind;
|
|
104
|
+
blob: { base64?: string; text?: string; mediaType: string };
|
|
105
|
+
source: 'android' | 'ios' | 'js';
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const _pendingAttachments = new Map<string, QueuedAttachment[]>();
|
|
109
|
+
|
|
110
|
+
/** Attach a blob to an event that is still in the batch queue. It
|
|
111
|
+
* uploads right after the batch containing the event lands, so the
|
|
112
|
+
* server always already knows the event. */
|
|
113
|
+
export const queueAttachment = (
|
|
114
|
+
eventId: string,
|
|
115
|
+
kind: QueuedAttachment['kind'],
|
|
116
|
+
blob: QueuedAttachment['blob'],
|
|
117
|
+
opts: { source?: QueuedAttachment['source'] } = {},
|
|
118
|
+
): void => {
|
|
119
|
+
const list = _pendingAttachments.get(eventId) ?? [];
|
|
120
|
+
list.push({ kind, blob, source: opts.source ?? 'js' });
|
|
121
|
+
_pendingAttachments.set(eventId, list);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const sendQueuedAttachments = async (eventId: string): Promise<void> => {
|
|
125
|
+
const list = _pendingAttachments.get(eventId);
|
|
126
|
+
if (!list) return;
|
|
127
|
+
_pendingAttachments.delete(eventId);
|
|
128
|
+
for (const a of list) {
|
|
129
|
+
await uploadAttachment(eventId, a.kind, a.blob, { source: a.source });
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
91
133
|
const sendWithRetry = async (
|
|
92
134
|
envelope: BatchEnvelope,
|
|
93
135
|
ingestUrl: string,
|
|
@@ -206,26 +248,40 @@ export const drainOfflineQueue = async (): Promise<void> => {
|
|
|
206
248
|
export const uploadAttachment = async (
|
|
207
249
|
eventId: string,
|
|
208
250
|
kind: import('@goliapkg/sentori-core').AttachmentKind,
|
|
209
|
-
blob: { base64
|
|
251
|
+
blob: { base64?: string; text?: string; mediaType: string },
|
|
210
252
|
opts: { source?: 'android' | 'ios' | 'js' } = {},
|
|
211
253
|
): Promise<{ ref: string } | null> => {
|
|
212
254
|
const config = getConfig();
|
|
213
255
|
if (!config) return null;
|
|
214
256
|
const url = `${config.ingestUrl}/v1/events/${encodeURIComponent(eventId)}/attachments/${encodeURIComponent(kind)}`;
|
|
215
257
|
|
|
216
|
-
|
|
217
|
-
form
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
258
|
+
// Hand-built multipart. React Native's FormData file part wants a
|
|
259
|
+
// `uri`, and its `data:` URI form throws a bare network error on
|
|
260
|
+
// iOS — this shipped untested and every JS attachment silently
|
|
261
|
+
// died. Text payloads (replay/screens NDJSON) embed directly;
|
|
262
|
+
// base64 payloads embed as base64 with the transfer-encoding
|
|
263
|
+
// header so the server knows to decode.
|
|
264
|
+
const boundary = `----sentori-${eventId}`;
|
|
265
|
+
const isText = typeof blob.text === 'string';
|
|
266
|
+
const content = isText ? (blob.text ?? '') : (blob.base64 ?? '');
|
|
267
|
+
const encodingHeader = isText ? '' : 'Content-Transfer-Encoding: base64\r\n';
|
|
268
|
+
const wireBody =
|
|
269
|
+
`--${boundary}\r\n` +
|
|
270
|
+
`Content-Disposition: form-data; name="file"; filename="${kind}.bin"\r\n` +
|
|
271
|
+
`Content-Type: ${blob.mediaType}\r\n` +
|
|
272
|
+
encodingHeader +
|
|
273
|
+
`\r\n${content}\r\n` +
|
|
274
|
+
`--${boundary}\r\n` +
|
|
275
|
+
`Content-Disposition: form-data; name="source"\r\n` +
|
|
276
|
+
`\r\n${opts.source ?? 'js'}\r\n` +
|
|
277
|
+
`--${boundary}--\r\n`;
|
|
223
278
|
|
|
224
279
|
try {
|
|
225
280
|
const resp = await fetch(url, {
|
|
226
|
-
body:
|
|
281
|
+
body: wireBody,
|
|
227
282
|
headers: {
|
|
228
283
|
Authorization: `Bearer ${config.token}`,
|
|
284
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
229
285
|
'Sentori-Sdk': `react-native/${SDK_VERSION}`,
|
|
230
286
|
},
|
|
231
287
|
method: 'POST',
|
|
@@ -251,4 +307,5 @@ export const __resetForTests = (): void => {
|
|
|
251
307
|
};
|
|
252
308
|
|
|
253
309
|
export const __peekQueue = (): readonly WireEvent[] => _queue;
|
|
310
|
+
export const __sdkVersion = (): string => SDK_VERSION;
|
|
254
311
|
export const __peekAssertStats = (): readonly AssertStat[] => [..._assertStats.values()];
|
package/src/verbs.ts
CHANGED
|
@@ -29,9 +29,12 @@ import type {
|
|
|
29
29
|
import { getConfig } from './config';
|
|
30
30
|
import { collectDevice } from './device';
|
|
31
31
|
import { onEventEmitted } from './emit-hooks';
|
|
32
|
+
import { symbolicateErrorViaMetro } from './handlers/dev-symbolicate';
|
|
32
33
|
import { currentContext, currentUserKey } from './scope';
|
|
33
34
|
import { countAssert, enqueue } from './transport';
|
|
34
35
|
|
|
36
|
+
declare const __DEV__: boolean | undefined;
|
|
37
|
+
|
|
35
38
|
/** Serialize any Error instances found in the data argument — the
|
|
36
39
|
* error-in-data convention (design.md §4): a caught-but-noteworthy
|
|
37
40
|
* exception needs no special API. One level deep is enough; nested
|
|
@@ -121,11 +124,48 @@ const emit = (kind: EventKind, opts: EmitOptions): string => {
|
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
|
|
127
|
+
// In dev there is no uploaded source map, so without local
|
|
128
|
+
// symbolication errors land as `entry.bundle:721724`. Hold the
|
|
129
|
+
// event out of the batch until Metro's /symbolicate answers
|
|
130
|
+
// (bounded at 2 s inside, never throws) — mutating it after
|
|
131
|
+
// enqueue would race the flush timer. Release builds and
|
|
132
|
+
// error-free events enqueue synchronously as before.
|
|
133
|
+
if (isDevRuntime() && hasErrorShape(payload)) {
|
|
134
|
+
void devSymbolicateThenEnqueue(event);
|
|
135
|
+
} else {
|
|
136
|
+
enqueue(event);
|
|
137
|
+
}
|
|
125
138
|
onEventEmitted(event);
|
|
126
139
|
return id;
|
|
127
140
|
};
|
|
128
141
|
|
|
142
|
+
const isDevRuntime = (): boolean =>
|
|
143
|
+
typeof __DEV__ !== 'undefined' && !!__DEV__;
|
|
144
|
+
|
|
145
|
+
const hasErrorShape = (payload: WirePayload): boolean => {
|
|
146
|
+
if (payload.error) return true;
|
|
147
|
+
return Object.values(payload.data ?? {}).some(
|
|
148
|
+
(v) => !!v && typeof v === 'object' && Array.isArray((v as SentoriError).stack),
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const devSymbolicateThenEnqueue = async (event: WireEvent): Promise<void> => {
|
|
153
|
+
try {
|
|
154
|
+
const { error: err, data } = event.payload;
|
|
155
|
+
if (err) await symbolicateErrorViaMetro(err);
|
|
156
|
+
for (const v of Object.values(data ?? {})) {
|
|
157
|
+
// The error-in-data convention: serialized errors riding warn/
|
|
158
|
+
// trace data get the same treatment as the headline error.
|
|
159
|
+
if (!!v && typeof v === 'object' && Array.isArray((v as SentoriError).stack)) {
|
|
160
|
+
await symbolicateErrorViaMetro(v as SentoriError);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
// Symbolication is garnish; delivery is the contract.
|
|
165
|
+
}
|
|
166
|
+
enqueue(event);
|
|
167
|
+
};
|
|
168
|
+
|
|
129
169
|
// ── the verbs ──────────────────────────────────────────────────────
|
|
130
170
|
|
|
131
171
|
export const error = safeFn('error', (err: unknown, data?: EventData): string => {
|