@goliapkg/sentori-react-native 5.1.3 → 5.1.4
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/lib/replay.d.ts +32 -4
- package/lib/replay.d.ts.map +1 -1
- package/lib/replay.js +33 -13
- package/lib/replay.js.map +1 -1
- package/lib/transport.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/replay-encoding.test.ts +30 -3
- package/src/replay.ts +50 -18
- package/src/transport.ts +1 -1
package/lib/replay.d.ts
CHANGED
|
@@ -18,12 +18,40 @@ export type ReplayOptions = {
|
|
|
18
18
|
};
|
|
19
19
|
export declare function startReplay(opts: ReplayOptions): void;
|
|
20
20
|
export declare function stopReplay(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Identity = geometry + occurrence index in walk order.
|
|
23
|
+
*
|
|
24
|
+
* Geometry alone is NOT identity: a page root and the fullscreen
|
|
25
|
+
* overlay covering it share x/y/w/h, and keying a Map on that
|
|
26
|
+
* collapsed them into one node — the overlay inherited the root's
|
|
27
|
+
* z-position and the replay drew the page THROUGH it (insight
|
|
28
|
+
* 2026-08-01). The occurrence suffix keeps every stacked layer its
|
|
29
|
+
* own entry, and stays stable across ticks because the native walk
|
|
30
|
+
* order is deterministic for a stable tree.
|
|
31
|
+
*/
|
|
32
|
+
export declare function indexNodes(nodes: Node[]): Map<string, {
|
|
33
|
+
node: Node;
|
|
34
|
+
at: number;
|
|
35
|
+
}>;
|
|
21
36
|
type Delta = {
|
|
22
|
-
added: Node
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
added: (Node & {
|
|
38
|
+
at: number;
|
|
39
|
+
id: string;
|
|
40
|
+
})[];
|
|
41
|
+
changed: (Node & {
|
|
42
|
+
id: string;
|
|
43
|
+
})[];
|
|
44
|
+
removed: (Pick<Node, 'x' | 'y' | 'w' | 'h'> & {
|
|
45
|
+
id: string;
|
|
46
|
+
})[];
|
|
25
47
|
};
|
|
26
|
-
export declare function computeDelta(prev: Map<string,
|
|
48
|
+
export declare function computeDelta(prev: Map<string, {
|
|
49
|
+
node: Node;
|
|
50
|
+
at: number;
|
|
51
|
+
}>, curr: Map<string, {
|
|
52
|
+
node: Node;
|
|
53
|
+
at: number;
|
|
54
|
+
}>): Delta;
|
|
27
55
|
export declare function isReplayRunning(): boolean;
|
|
28
56
|
/** Drain the ring as NDJSON (keyframe or delta per line). Empty
|
|
29
57
|
* string when the ring is empty. Resets state so the next session's
|
package/lib/replay.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAyDA,KAAK,IAAI,GAAG;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkBF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;IAC3B;;mCAE+B;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CA2BrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAajC;
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAyDA,KAAK,IAAI,GAAG;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkBF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;IAC3B;;mCAE+B;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CA2BrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAajC;AAmHD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAUjF;AAED,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,CAAC,IAAI,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAC7C,OAAO,EAAE,CAAC,IAAI,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IACnC,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CACjE,CAAC;AAEF,wBAAgB,YAAY,CAC1B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7C,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5C,KAAK,CAsBP;AA8DD,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;2CAE2C;AAC3C,wBAAgB,WAAW,IAAI,MAAM,CAOpC;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAK5C;AAED;mEACmE;AACnE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAO1D"}
|
package/lib/replay.js
CHANGED
|
@@ -129,9 +129,7 @@ function captureTick() {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
function encodeAndPush(snapshot) {
|
|
132
|
-
const currentState =
|
|
133
|
-
for (const n of snapshot.nodes)
|
|
134
|
-
currentState.set(fingerprint(n), n);
|
|
132
|
+
const currentState = indexNodes(snapshot.nodes);
|
|
135
133
|
const ts = snapshot.ts;
|
|
136
134
|
const isCold = _lastFrameState === null;
|
|
137
135
|
const keyframeOverdue = ts - _lastKeyframeTs >= _keyframeIntervalMs;
|
|
@@ -190,25 +188,47 @@ function evictRing(nowTs) {
|
|
|
190
188
|
function fingerprint(n) {
|
|
191
189
|
return `${n.x | 0},${n.y | 0},${n.w | 0},${n.h | 0}`;
|
|
192
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Identity = geometry + occurrence index in walk order.
|
|
193
|
+
*
|
|
194
|
+
* Geometry alone is NOT identity: a page root and the fullscreen
|
|
195
|
+
* overlay covering it share x/y/w/h, and keying a Map on that
|
|
196
|
+
* collapsed them into one node — the overlay inherited the root's
|
|
197
|
+
* z-position and the replay drew the page THROUGH it (insight
|
|
198
|
+
* 2026-08-01). The occurrence suffix keeps every stacked layer its
|
|
199
|
+
* own entry, and stays stable across ticks because the native walk
|
|
200
|
+
* order is deterministic for a stable tree.
|
|
201
|
+
*/
|
|
202
|
+
export function indexNodes(nodes) {
|
|
203
|
+
const out = new Map();
|
|
204
|
+
const seen = new Map();
|
|
205
|
+
nodes.forEach((n, at) => {
|
|
206
|
+
const base = fingerprint(n);
|
|
207
|
+
const occ = seen.get(base) ?? 0;
|
|
208
|
+
seen.set(base, occ + 1);
|
|
209
|
+
out.set(`${base}#${occ}`, { node: n, at });
|
|
210
|
+
});
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
193
213
|
export function computeDelta(prev, curr) {
|
|
194
214
|
const added = [];
|
|
195
215
|
const changed = [];
|
|
196
216
|
const removed = [];
|
|
197
|
-
for (const [
|
|
198
|
-
const p = prev.get(
|
|
217
|
+
for (const [id, { node, at }] of curr) {
|
|
218
|
+
const p = prev.get(id);
|
|
199
219
|
if (!p) {
|
|
200
|
-
added.push(node);
|
|
220
|
+
added.push({ ...node, at, id });
|
|
201
221
|
continue;
|
|
202
222
|
}
|
|
203
|
-
if ((p.kind ?? '') !== (node.kind ?? '') ||
|
|
204
|
-
(p.color ?? '') !== (node.color ?? '') ||
|
|
205
|
-
(p.text ?? '') !== (node.text ?? '')) {
|
|
206
|
-
changed.push(node);
|
|
223
|
+
if ((p.node.kind ?? '') !== (node.kind ?? '') ||
|
|
224
|
+
(p.node.color ?? '') !== (node.color ?? '') ||
|
|
225
|
+
(p.node.text ?? '') !== (node.text ?? '')) {
|
|
226
|
+
changed.push({ ...node, id });
|
|
207
227
|
}
|
|
208
228
|
}
|
|
209
|
-
for (const [
|
|
210
|
-
if (!curr.has(
|
|
211
|
-
removed.push({ x: node.x, y: node.y, w: node.w, h: node.h });
|
|
229
|
+
for (const [id, { node }] of prev) {
|
|
230
|
+
if (!curr.has(id))
|
|
231
|
+
removed.push({ x: node.x, y: node.y, w: node.w, h: node.h, id });
|
|
212
232
|
}
|
|
213
233
|
return { added, changed, removed };
|
|
214
234
|
}
|
package/lib/replay.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,wEAAwE;AACxE,uEAAuE;AACvE,qEAAqE;AACrE,+CAA+C;AAC/C,mEAAmE;AACnE,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,qEAAqE;AACrE,gCAAgC;AAChC,EAAE;AACF,2CAA2C;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAInD;;;;;uEAKuE;AACvE,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;+DAC+D;AAC/D,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC;;+DAE+D;AAC/D,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAEpC;;0DAE0D;AAC1D,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAEpC,sEAAsE;AACtE,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEhC;;8BAE8B;AAC9B,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B;yCACyC;AACzC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAgB/B,IAAI,KAAK,GAAe,EAAE,CAAC;AAC3B,IAAI,MAAM,GAA0C,IAAI,CAAC;AACzD,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB;;oCAEoC;AACpC,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
|
package/lib/transport.js
CHANGED
|
@@ -15,7 +15,7 @@ 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.
|
|
18
|
+
const SDK_VERSION = '5.1.4';
|
|
19
19
|
let _queue = [];
|
|
20
20
|
let _assertStats = new Map();
|
|
21
21
|
let _flushTimer = null;
|
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.4",
|
|
4
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)",
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
__resetReplayForTests,
|
|
6
6
|
computeDelta,
|
|
7
7
|
drainReplay,
|
|
8
|
+
indexNodes,
|
|
8
9
|
} from '../replay';
|
|
9
10
|
|
|
10
11
|
// Unit coverage for the rc.9 v2 replay encoder.
|
|
@@ -206,9 +207,7 @@ describe('rc.9 encoder — keyframe vs delta', () => {
|
|
|
206
207
|
});
|
|
207
208
|
|
|
208
209
|
describe('computeDelta', () => {
|
|
209
|
-
|
|
210
|
-
return new Map(nodes.map((n) => [`${n.x | 0},${n.y | 0},${n.w | 0},${n.h | 0}`, n]));
|
|
211
|
-
}
|
|
210
|
+
const asMap = (nodes: Node[]) => indexNodes(nodes);
|
|
212
211
|
|
|
213
212
|
test('empty-vs-empty produces all-empty delta', () => {
|
|
214
213
|
const d = computeDelta(new Map(), new Map());
|
|
@@ -234,4 +233,32 @@ describe('computeDelta', () => {
|
|
|
234
233
|
expect(d.changed.length).toBe(0);
|
|
235
234
|
expect(d.removed.length).toBe(0);
|
|
236
235
|
});
|
|
236
|
+
|
|
237
|
+
test('stacked same-geometry layers keep separate identities (insight overlay bug)', () => {
|
|
238
|
+
// A page root and a fullscreen opaque overlay: identical x/y/w/h.
|
|
239
|
+
const pageRoot: Node = { x: 0, y: 0, w: 400, h: 800, kind: 'rect', color: '#101014FF' };
|
|
240
|
+
const overlay: Node = { x: 0, y: 0, w: 400, h: 800, kind: 'rect', color: '#FFFFFFFF' };
|
|
241
|
+
const m = indexNodes([pageRoot, overlay]);
|
|
242
|
+
// Both survive indexing…
|
|
243
|
+
expect(m.size).toBe(2);
|
|
244
|
+
expect([...m.keys()]).toEqual(['0,0,400,800#0', '0,0,400,800#1']);
|
|
245
|
+
// …and z-order info rides along.
|
|
246
|
+
expect(m.get('0,0,400,800#1')?.at).toBe(1);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('delta entries carry ids; overlay removal targets the right layer', () => {
|
|
250
|
+
const pageRoot: Node = { x: 0, y: 0, w: 400, h: 800, kind: 'rect', color: '#101014FF' };
|
|
251
|
+
const overlay: Node = { x: 0, y: 0, w: 400, h: 800, kind: 'rect', color: '#FFFFFFFF' };
|
|
252
|
+
const withOverlay = indexNodes([pageRoot, overlay]);
|
|
253
|
+
const without = indexNodes([pageRoot]);
|
|
254
|
+
|
|
255
|
+
const closed = computeDelta(withOverlay, without);
|
|
256
|
+
expect(closed.removed.length).toBe(1);
|
|
257
|
+
expect(closed.removed[0]?.id).toBe('0,0,400,800#1');
|
|
258
|
+
|
|
259
|
+
const opened = computeDelta(without, withOverlay);
|
|
260
|
+
expect(opened.added.length).toBe(1);
|
|
261
|
+
expect(opened.added[0]?.id).toBe('0,0,400,800#1');
|
|
262
|
+
expect(opened.added[0]?.at).toBe(1);
|
|
263
|
+
});
|
|
237
264
|
});
|
package/src/replay.ts
CHANGED
|
@@ -76,7 +76,7 @@ let _running = false;
|
|
|
76
76
|
/** Last emit's reconstructed state — fingerprint → node. Null until
|
|
77
77
|
* the first keyframe lands; reset on drain so the next session
|
|
78
78
|
* starts with a fresh keyframe. */
|
|
79
|
-
let _lastFrameState: Map<string, Node> | null = null;
|
|
79
|
+
let _lastFrameState: Map<string, { node: Node; at: number }> | null = null;
|
|
80
80
|
let _lastKeyframeTs = 0;
|
|
81
81
|
|
|
82
82
|
let _nativeMod: ReplayNativeModule | null = null;
|
|
@@ -182,8 +182,7 @@ function captureTick(): void {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function encodeAndPush(snapshot: NativeFrame): void {
|
|
185
|
-
const currentState =
|
|
186
|
-
for (const n of snapshot.nodes) currentState.set(fingerprint(n), n);
|
|
185
|
+
const currentState = indexNodes(snapshot.nodes);
|
|
187
186
|
|
|
188
187
|
const ts = snapshot.ts;
|
|
189
188
|
const isCold = _lastFrameState === null;
|
|
@@ -195,7 +194,10 @@ function encodeAndPush(snapshot: NativeFrame): void {
|
|
|
195
194
|
line = encodeKeyframe(snapshot);
|
|
196
195
|
_lastKeyframeTs = ts;
|
|
197
196
|
} else {
|
|
198
|
-
const delta = computeDelta(
|
|
197
|
+
const delta = computeDelta(
|
|
198
|
+
_lastFrameState as Map<string, { node: Node; at: number }>,
|
|
199
|
+
currentState,
|
|
200
|
+
);
|
|
199
201
|
const totalChanged = delta.added.length + delta.changed.length + delta.removed.length;
|
|
200
202
|
if (totalChanged === 0) {
|
|
201
203
|
// No-op heartbeat — drop. Keep _lastFrameState as-is (identical).
|
|
@@ -248,28 +250,58 @@ function fingerprint(n: Node): string {
|
|
|
248
250
|
return `${n.x | 0},${n.y | 0},${n.w | 0},${n.h | 0}`;
|
|
249
251
|
}
|
|
250
252
|
|
|
251
|
-
|
|
253
|
+
/**
|
|
254
|
+
* Identity = geometry + occurrence index in walk order.
|
|
255
|
+
*
|
|
256
|
+
* Geometry alone is NOT identity: a page root and the fullscreen
|
|
257
|
+
* overlay covering it share x/y/w/h, and keying a Map on that
|
|
258
|
+
* collapsed them into one node — the overlay inherited the root's
|
|
259
|
+
* z-position and the replay drew the page THROUGH it (insight
|
|
260
|
+
* 2026-08-01). The occurrence suffix keeps every stacked layer its
|
|
261
|
+
* own entry, and stays stable across ticks because the native walk
|
|
262
|
+
* order is deterministic for a stable tree.
|
|
263
|
+
*/
|
|
264
|
+
export function indexNodes(nodes: Node[]): Map<string, { node: Node; at: number }> {
|
|
265
|
+
const out = new Map<string, { node: Node; at: number }>();
|
|
266
|
+
const seen = new Map<string, number>();
|
|
267
|
+
nodes.forEach((n, at) => {
|
|
268
|
+
const base = fingerprint(n);
|
|
269
|
+
const occ = seen.get(base) ?? 0;
|
|
270
|
+
seen.set(base, occ + 1);
|
|
271
|
+
out.set(`${base}#${occ}`, { node: n, at });
|
|
272
|
+
});
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
type Delta = {
|
|
277
|
+
added: (Node & { at: number; id: string })[];
|
|
278
|
+
changed: (Node & { id: string })[];
|
|
279
|
+
removed: (Pick<Node, 'x' | 'y' | 'w' | 'h'> & { id: string })[];
|
|
280
|
+
};
|
|
252
281
|
|
|
253
|
-
export function computeDelta(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
282
|
+
export function computeDelta(
|
|
283
|
+
prev: Map<string, { node: Node; at: number }>,
|
|
284
|
+
curr: Map<string, { node: Node; at: number }>,
|
|
285
|
+
): Delta {
|
|
286
|
+
const added: Delta['added'] = [];
|
|
287
|
+
const changed: Delta['changed'] = [];
|
|
288
|
+
const removed: Delta['removed'] = [];
|
|
289
|
+
for (const [id, { node, at }] of curr) {
|
|
290
|
+
const p = prev.get(id);
|
|
259
291
|
if (!p) {
|
|
260
|
-
added.push(node);
|
|
292
|
+
added.push({ ...node, at, id });
|
|
261
293
|
continue;
|
|
262
294
|
}
|
|
263
295
|
if (
|
|
264
|
-
(p.kind ?? '') !== (node.kind ?? '') ||
|
|
265
|
-
(p.color ?? '') !== (node.color ?? '') ||
|
|
266
|
-
(p.text ?? '') !== (node.text ?? '')
|
|
296
|
+
(p.node.kind ?? '') !== (node.kind ?? '') ||
|
|
297
|
+
(p.node.color ?? '') !== (node.color ?? '') ||
|
|
298
|
+
(p.node.text ?? '') !== (node.text ?? '')
|
|
267
299
|
) {
|
|
268
|
-
changed.push(node);
|
|
300
|
+
changed.push({ ...node, id });
|
|
269
301
|
}
|
|
270
302
|
}
|
|
271
|
-
for (const [
|
|
272
|
-
if (!curr.has(
|
|
303
|
+
for (const [id, { node }] of prev) {
|
|
304
|
+
if (!curr.has(id)) removed.push({ x: node.x, y: node.y, w: node.w, h: node.h, id });
|
|
273
305
|
}
|
|
274
306
|
return { added, changed, removed };
|
|
275
307
|
}
|
package/src/transport.ts
CHANGED
|
@@ -20,7 +20,7 @@ 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.
|
|
23
|
+
const SDK_VERSION = '5.1.4';
|
|
24
24
|
|
|
25
25
|
let _queue: WireEvent[] = [];
|
|
26
26
|
let _assertStats = new Map<string, AssertStat>();
|