@goliapkg/sentori-react-native 5.1.0 → 5.1.1
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 +18 -1
- package/lib/transport.d.ts.map +1 -1
- package/lib/transport.js +48 -8
- package/lib/transport.js.map +1 -1
- package/package.json +1 -1
- package/src/init.ts +9 -31
- package/src/mask.ts +4 -1
- package/src/transport.ts +64 -9
|
@@ -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';
|
|
@@ -25,4 +41,5 @@ export declare const uploadAttachment: (eventId: string, kind: import('@goliapkg
|
|
|
25
41
|
export declare const __resetForTests: () => void;
|
|
26
42
|
export declare const __peekQueue: () => readonly WireEvent[];
|
|
27
43
|
export declare const __peekAssertStats: () => readonly AssertStat[];
|
|
44
|
+
export {};
|
|
28
45
|
//# 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;AAmBnF,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,
|
|
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;AAmBnF,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,iBAAiB,QAAO,SAAS,UAAU,EAAgC,CAAC"}
|
package/lib/transport.js
CHANGED
|
@@ -76,12 +76,39 @@ export const flush = async () => {
|
|
|
76
76
|
envelope.assertStats = stats;
|
|
77
77
|
try {
|
|
78
78
|
await sendWithRetry(envelope, config.ingestUrl, config.token);
|
|
79
|
+
// Only now do the events exist server-side — release their
|
|
80
|
+
// queued attachments. Uploading before this point 404s: the
|
|
81
|
+
// attachment races the 5s event batch and always wins.
|
|
82
|
+
for (const ev of events) {
|
|
83
|
+
if (ev.id)
|
|
84
|
+
void sendQueuedAttachments(ev.id);
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
87
|
catch {
|
|
81
88
|
// Events survive offline; assert deltas are cheap enough to lose.
|
|
89
|
+
// Their attachments are memory-only and lost with the process —
|
|
90
|
+
// documented; a replay is context, not the crash report itself.
|
|
82
91
|
await persist(events);
|
|
83
92
|
}
|
|
84
93
|
};
|
|
94
|
+
const _pendingAttachments = new Map();
|
|
95
|
+
/** Attach a blob to an event that is still in the batch queue. It
|
|
96
|
+
* uploads right after the batch containing the event lands, so the
|
|
97
|
+
* server always already knows the event. */
|
|
98
|
+
export const queueAttachment = (eventId, kind, blob, opts = {}) => {
|
|
99
|
+
const list = _pendingAttachments.get(eventId) ?? [];
|
|
100
|
+
list.push({ kind, blob, source: opts.source ?? 'js' });
|
|
101
|
+
_pendingAttachments.set(eventId, list);
|
|
102
|
+
};
|
|
103
|
+
const sendQueuedAttachments = async (eventId) => {
|
|
104
|
+
const list = _pendingAttachments.get(eventId);
|
|
105
|
+
if (!list)
|
|
106
|
+
return;
|
|
107
|
+
_pendingAttachments.delete(eventId);
|
|
108
|
+
for (const a of list) {
|
|
109
|
+
await uploadAttachment(eventId, a.kind, a.blob, { source: a.source });
|
|
110
|
+
}
|
|
111
|
+
};
|
|
85
112
|
const sendWithRetry = async (envelope, ingestUrl, token) => {
|
|
86
113
|
let attempt = 0;
|
|
87
114
|
let delayMs = 1000;
|
|
@@ -190,18 +217,31 @@ export const uploadAttachment = async (eventId, kind, blob, opts = {}) => {
|
|
|
190
217
|
if (!config)
|
|
191
218
|
return null;
|
|
192
219
|
const url = `${config.ingestUrl}/v1/events/${encodeURIComponent(eventId)}/attachments/${encodeURIComponent(kind)}`;
|
|
193
|
-
|
|
194
|
-
form
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
220
|
+
// Hand-built multipart. React Native's FormData file part wants a
|
|
221
|
+
// `uri`, and its `data:` URI form throws a bare network error on
|
|
222
|
+
// iOS — this shipped untested and every JS attachment silently
|
|
223
|
+
// died. Text payloads (replay/screens NDJSON) embed directly;
|
|
224
|
+
// base64 payloads embed as base64 with the transfer-encoding
|
|
225
|
+
// header so the server knows to decode.
|
|
226
|
+
const boundary = `----sentori-${eventId}`;
|
|
227
|
+
const isText = typeof blob.text === 'string';
|
|
228
|
+
const content = isText ? (blob.text ?? '') : (blob.base64 ?? '');
|
|
229
|
+
const encodingHeader = isText ? '' : 'Content-Transfer-Encoding: base64\r\n';
|
|
230
|
+
const wireBody = `--${boundary}\r\n` +
|
|
231
|
+
`Content-Disposition: form-data; name="file"; filename="${kind}.bin"\r\n` +
|
|
232
|
+
`Content-Type: ${blob.mediaType}\r\n` +
|
|
233
|
+
encodingHeader +
|
|
234
|
+
`\r\n${content}\r\n` +
|
|
235
|
+
`--${boundary}\r\n` +
|
|
236
|
+
`Content-Disposition: form-data; name="source"\r\n` +
|
|
237
|
+
`\r\n${opts.source ?? 'js'}\r\n` +
|
|
238
|
+
`--${boundary}--\r\n`;
|
|
200
239
|
try {
|
|
201
240
|
const resp = await fetch(url, {
|
|
202
|
-
body:
|
|
241
|
+
body: wireBody,
|
|
203
242
|
headers: {
|
|
204
243
|
Authorization: `Bearer ${config.token}`,
|
|
244
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
205
245
|
'Sentori-Sdk': `react-native/${SDK_VERSION}`,
|
|
206
246
|
},
|
|
207
247
|
method: 'POST',
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goliapkg/sentori-react-native",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"description": "Sentori SDK for React Native — 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)",
|
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
|
@@ -82,12 +82,53 @@ export const flush = async (): Promise<void> => {
|
|
|
82
82
|
|
|
83
83
|
try {
|
|
84
84
|
await sendWithRetry(envelope, config.ingestUrl, config.token);
|
|
85
|
+
// Only now do the events exist server-side — release their
|
|
86
|
+
// queued attachments. Uploading before this point 404s: the
|
|
87
|
+
// attachment races the 5s event batch and always wins.
|
|
88
|
+
for (const ev of events) {
|
|
89
|
+
if (ev.id) void sendQueuedAttachments(ev.id);
|
|
90
|
+
}
|
|
85
91
|
} catch {
|
|
86
92
|
// Events survive offline; assert deltas are cheap enough to lose.
|
|
93
|
+
// Their attachments are memory-only and lost with the process —
|
|
94
|
+
// documented; a replay is context, not the crash report itself.
|
|
87
95
|
await persist(events);
|
|
88
96
|
}
|
|
89
97
|
};
|
|
90
98
|
|
|
99
|
+
// ── attachments (deferred until their event is delivered) ─────────
|
|
100
|
+
|
|
101
|
+
type QueuedAttachment = {
|
|
102
|
+
kind: import('@goliapkg/sentori-core').AttachmentKind;
|
|
103
|
+
blob: { base64?: string; text?: string; mediaType: string };
|
|
104
|
+
source: 'android' | 'ios' | 'js';
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const _pendingAttachments = new Map<string, QueuedAttachment[]>();
|
|
108
|
+
|
|
109
|
+
/** Attach a blob to an event that is still in the batch queue. It
|
|
110
|
+
* uploads right after the batch containing the event lands, so the
|
|
111
|
+
* server always already knows the event. */
|
|
112
|
+
export const queueAttachment = (
|
|
113
|
+
eventId: string,
|
|
114
|
+
kind: QueuedAttachment['kind'],
|
|
115
|
+
blob: QueuedAttachment['blob'],
|
|
116
|
+
opts: { source?: QueuedAttachment['source'] } = {},
|
|
117
|
+
): void => {
|
|
118
|
+
const list = _pendingAttachments.get(eventId) ?? [];
|
|
119
|
+
list.push({ kind, blob, source: opts.source ?? 'js' });
|
|
120
|
+
_pendingAttachments.set(eventId, list);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const sendQueuedAttachments = async (eventId: string): Promise<void> => {
|
|
124
|
+
const list = _pendingAttachments.get(eventId);
|
|
125
|
+
if (!list) return;
|
|
126
|
+
_pendingAttachments.delete(eventId);
|
|
127
|
+
for (const a of list) {
|
|
128
|
+
await uploadAttachment(eventId, a.kind, a.blob, { source: a.source });
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
91
132
|
const sendWithRetry = async (
|
|
92
133
|
envelope: BatchEnvelope,
|
|
93
134
|
ingestUrl: string,
|
|
@@ -206,26 +247,40 @@ export const drainOfflineQueue = async (): Promise<void> => {
|
|
|
206
247
|
export const uploadAttachment = async (
|
|
207
248
|
eventId: string,
|
|
208
249
|
kind: import('@goliapkg/sentori-core').AttachmentKind,
|
|
209
|
-
blob: { base64
|
|
250
|
+
blob: { base64?: string; text?: string; mediaType: string },
|
|
210
251
|
opts: { source?: 'android' | 'ios' | 'js' } = {},
|
|
211
252
|
): Promise<{ ref: string } | null> => {
|
|
212
253
|
const config = getConfig();
|
|
213
254
|
if (!config) return null;
|
|
214
255
|
const url = `${config.ingestUrl}/v1/events/${encodeURIComponent(eventId)}/attachments/${encodeURIComponent(kind)}`;
|
|
215
256
|
|
|
216
|
-
|
|
217
|
-
form
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
257
|
+
// Hand-built multipart. React Native's FormData file part wants a
|
|
258
|
+
// `uri`, and its `data:` URI form throws a bare network error on
|
|
259
|
+
// iOS — this shipped untested and every JS attachment silently
|
|
260
|
+
// died. Text payloads (replay/screens NDJSON) embed directly;
|
|
261
|
+
// base64 payloads embed as base64 with the transfer-encoding
|
|
262
|
+
// header so the server knows to decode.
|
|
263
|
+
const boundary = `----sentori-${eventId}`;
|
|
264
|
+
const isText = typeof blob.text === 'string';
|
|
265
|
+
const content = isText ? (blob.text ?? '') : (blob.base64 ?? '');
|
|
266
|
+
const encodingHeader = isText ? '' : 'Content-Transfer-Encoding: base64\r\n';
|
|
267
|
+
const wireBody =
|
|
268
|
+
`--${boundary}\r\n` +
|
|
269
|
+
`Content-Disposition: form-data; name="file"; filename="${kind}.bin"\r\n` +
|
|
270
|
+
`Content-Type: ${blob.mediaType}\r\n` +
|
|
271
|
+
encodingHeader +
|
|
272
|
+
`\r\n${content}\r\n` +
|
|
273
|
+
`--${boundary}\r\n` +
|
|
274
|
+
`Content-Disposition: form-data; name="source"\r\n` +
|
|
275
|
+
`\r\n${opts.source ?? 'js'}\r\n` +
|
|
276
|
+
`--${boundary}--\r\n`;
|
|
223
277
|
|
|
224
278
|
try {
|
|
225
279
|
const resp = await fetch(url, {
|
|
226
|
-
body:
|
|
280
|
+
body: wireBody,
|
|
227
281
|
headers: {
|
|
228
282
|
Authorization: `Bearer ${config.token}`,
|
|
283
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
229
284
|
'Sentori-Sdk': `react-native/${SDK_VERSION}`,
|
|
230
285
|
},
|
|
231
286
|
method: 'POST',
|