@goliapkg/sentori-react-native 1.0.0-rc.8 → 1.0.0

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.
Files changed (60) hide show
  1. package/bin/sentori-rn-upload-source-bundle.cjs +193 -0
  2. package/lib/capture.d.ts.map +1 -1
  3. package/lib/capture.js +9 -0
  4. package/lib/capture.js.map +1 -1
  5. package/lib/heartbeat.d.ts +9 -0
  6. package/lib/heartbeat.d.ts.map +1 -0
  7. package/lib/heartbeat.js +140 -0
  8. package/lib/heartbeat.js.map +1 -0
  9. package/lib/index.d.ts +15 -0
  10. package/lib/index.d.ts.map +1 -1
  11. package/lib/index.js +15 -0
  12. package/lib/index.js.map +1 -1
  13. package/lib/init.d.ts +6 -0
  14. package/lib/init.d.ts.map +1 -1
  15. package/lib/init.js +18 -0
  16. package/lib/init.js.map +1 -1
  17. package/lib/install-id.d.ts +17 -0
  18. package/lib/install-id.d.ts.map +1 -0
  19. package/lib/install-id.js +125 -0
  20. package/lib/install-id.js.map +1 -0
  21. package/lib/navigation.d.ts +1 -0
  22. package/lib/navigation.d.ts.map +1 -1
  23. package/lib/navigation.js +20 -0
  24. package/lib/navigation.js.map +1 -1
  25. package/lib/replay.d.ts +27 -9
  26. package/lib/replay.d.ts.map +1 -1
  27. package/lib/replay.js +209 -167
  28. package/lib/replay.js.map +1 -1
  29. package/lib/report-security.d.ts +40 -0
  30. package/lib/report-security.d.ts.map +1 -0
  31. package/lib/report-security.js +159 -0
  32. package/lib/report-security.js.map +1 -0
  33. package/lib/track.d.ts +34 -0
  34. package/lib/track.d.ts.map +1 -0
  35. package/lib/track.js +98 -0
  36. package/lib/track.js.map +1 -0
  37. package/lib/transport.d.ts +15 -0
  38. package/lib/transport.d.ts.map +1 -1
  39. package/lib/transport.js +23 -0
  40. package/lib/transport.js.map +1 -1
  41. package/lib/trust-score.d.ts +20 -0
  42. package/lib/trust-score.d.ts.map +1 -0
  43. package/lib/trust-score.js +151 -0
  44. package/lib/trust-score.js.map +1 -0
  45. package/package.json +6 -2
  46. package/src/__tests__/install-id.test.ts +60 -0
  47. package/src/__tests__/replay-encoding.test.ts +237 -0
  48. package/src/__tests__/report-security.test.ts +106 -0
  49. package/src/__tests__/track.test.ts +91 -0
  50. package/src/capture.ts +8 -0
  51. package/src/heartbeat.ts +158 -0
  52. package/src/index.ts +24 -0
  53. package/src/init.ts +23 -0
  54. package/src/install-id.ts +146 -0
  55. package/src/navigation.ts +26 -0
  56. package/src/replay.ts +258 -176
  57. package/src/report-security.ts +165 -0
  58. package/src/track.ts +114 -0
  59. package/src/transport.ts +35 -0
  60. package/src/trust-score.ts +176 -0
package/lib/replay.js CHANGED
@@ -1,70 +1,64 @@
1
- // v0.9.6 #2 — wireframe Session Replay (SDK side).
1
+ // rc.9 — wireframe Session Replay v2 encoding.
2
2
  //
3
- // 60-slot ring buffer of native-captured wireframe snapshots. Each
4
- // tick calls into `SentoriReplayCapture.captureWireframe(maskIds)`
5
- // which walks the iOS UIView / Android View hierarchy and returns
6
- // one JSON string per snapshot. captureException flushes the ring
7
- // as a `replay` attachment (NDJSON: one snapshot per line).
3
+ // Replaces rc.8's "one full snapshot per tick" with keyframe + delta:
4
+ // - Native walker still emits a full snapshot string every tick.
5
+ // - JS parses the snapshot, builds a fingerprint→node map, and either
6
+ // emits a keyframe (cold start / every KEYFRAME_INTERVAL_MS / when
7
+ // the delta would be bigger than a fresh key) OR a delta against
8
+ // the previous emit's reconstructed state.
9
+ // - Static-UI ticks produce zero-delta heartbeats which we drop.
8
10
  //
9
- // Why wireframe and not raster:
10
- // Storage: 80 nodes × ~80 bytes 6 KB per snapshot vs ~50 KB
11
- // for a downsampled JPEG. 60-slot ring 400 KB raw / ~80 KB
12
- // gzipped fits comfortably in the 500 KB attachment cap.
13
- // • Privacy: no pixels means no accidental PII leaks; mask
14
- // registry decides what text to replace with "***".
15
- // • Replay fidelity: less faithful to pixels but enough to see
16
- // which screen the user was on and what was on it. Dashboard
17
- // player renders SVG rects — denser-looking than a 1 Hz
18
- // screenshot strip.
11
+ // At 4 Hz capture / 4 s keyframes the wire bytes drop ~50 % vs rc.8 at
12
+ // 1 Hz for the same 60 s pre-error window, and the dashboard player
13
+ // cross-fades between captures at 24 fps so playback reads as motion
14
+ // rather than a 1 Hz slideshow.
15
+ //
16
+ // Wire schema: docs/replay-encoding-v2.md.
19
17
  import { startSpan } from '@goliapkg/sentori-core';
20
18
  import { getRegisteredMaskQuery } from './mask';
21
19
  import { describeWireframeNative } from './native';
22
- const TICK_INTERVAL_MS = 1000;
23
- const RING_SIZE = 60;
24
- /** Floor on tick period. < 250 ms (4 Hz) the native view-tree walk
25
- * dominates the JS thread on mid-tier Android, especially with mask
26
- * consultation. The default is 1 Hz; the option exists for
27
- * benchmarking, not for production. */
28
- const MIN_TICK_PERIOD_MS = 250;
20
+ /** Default capture interval (2 Hz). Override via `replay.hz`. rc.10
21
+ * rolled this back from rc.9's 4 Hz default: iOS sim measured 1 ms
22
+ * per tick on a thin dev panel but extrapolation to a 200-node
23
+ * Insight-class UI on Android pushes JS-thread occupancy past 1 %,
24
+ * which violates the "几乎不能造成性能抖动" rule. Apps that want
25
+ * smoother playback motion can opt into `replay.hz: 4` explicitly. */
26
+ const TICK_INTERVAL_MS = 500;
27
+ /** How often to emit a fresh keyframe — caps reconstruction chain
28
+ * length and lets the player re-sync after a dropped line. */
29
+ const KEYFRAME_INTERVAL_MS = 4_000;
30
+ /** When the delta against the previous frame would carry ≥ this
31
+ * fraction of the current node count, prefer a fresh keyframe —
32
+ * emits roughly the same bytes but doesn't grow the chain. */
33
+ const DELTA_TO_KEYFRAME_RATIO = 0.4;
34
+ /** Floor under which the keyframe-vs-delta ratio heuristic does
35
+ * not apply. Trivial UIs (≤ 10 nodes — boot splash, dev panel,
36
+ * tests) shouldn't drop to keyframes on every change. */
37
+ const KEYFRAME_RATIO_MIN_NODES = 10;
38
+ /** Replay window kept in the ring buffer. captureException drains. */
39
+ const REPLAY_WINDOW_MS = 60_000;
40
+ /** Hard ceiling on ring item count — defence against a wedged tick
41
+ * clock filling memory; under normal capture rates we evict by time
42
+ * long before this fires. */
43
+ const MAX_RING_ITEMS = 1000;
44
+ /** Floor on tick period. < 100 ms the native view-tree walk dominates
45
+ * the JS thread on mid-tier Android. */
46
+ const MIN_TICK_PERIOD_MS = 100;
29
47
  let _ring = [];
30
48
  let _timer = null;
31
49
  let _running = false;
32
- /**
33
- * v0.9.13 frame-level delta encoding: when the new snapshot matches
34
- * the last one byte-for-byte (static UI, no animation, off-screen
35
- * app), skip pushing it. The ring stays meaningful (one frame =
36
- * one *change*), the attachment shrinks proportionally, and a real
37
- * idle phase no longer evicts a useful pre-error frame.
38
- *
39
- * We only check against the most-recently-pushed snapshot, not the
40
- * whole ring — that's cheap (one string comparison per tick) and
41
- * catches the dominant case (idle screens). True content changes
42
- * fall through and push as before.
43
- *
44
- * Budget verification on the iOS showcase (apps/ios-showcase): 60
45
- * frames at ~120 bytes each → ≈ 7 KB raw NDJSON, well under the
46
- * 500 KB attachment cap. Heavier RN apps with 200+ visible nodes
47
- * per frame can land in the 400 KB band; future work in v1.x adds
48
- * native gzip on upload if real-world traffic ever pushes the cap.
49
- */
50
- let _lastPushed = null;
51
- /** Native module ref, resolved once on first start. Caching here
52
- * avoids the cost of `requireNativeModule('Sentori')` on every
53
- * capture tick (Metro's require cache makes this cheap, but the
54
- * per-tick string lookup and possible throw still cost more than
55
- * reading a closed-over variable). */
50
+ /** Last emit's reconstructed state — fingerprint → node. Null until
51
+ * the first keyframe lands; reset on drain so the next session
52
+ * starts with a fresh keyframe. */
53
+ let _lastFrameState = null;
54
+ let _lastKeyframeTs = 0;
56
55
  let _nativeMod = null;
56
+ let _keyframeIntervalMs = KEYFRAME_INTERVAL_MS;
57
57
  export function startReplay(opts) {
58
58
  if (_running)
59
59
  return;
60
60
  if (opts.mode !== 'wireframe')
61
61
  return;
62
- // v0.9.10 — gate via expo-modules-core's registry (same path the
63
- // screenshot capture uses). The previous `isNativeModuleLinked`
64
- // check looked at the legacy `RN.NativeModules` map, but the
65
- // Sentori module is registered through expo-modules-core; the
66
- // legacy map never sees it, so this branch returned "not linked"
67
- // forever even with the pod correctly attached (Insight 2026-05-17).
68
62
  const info = describeWireframeNative();
69
63
  if (!info.bound) {
70
64
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
@@ -79,23 +73,15 @@ export function startReplay(opts) {
79
73
  }
80
74
  _running = true;
81
75
  _nativeMod = loadNativeReplay();
82
- const period = Math.max(MIN_TICK_PERIOD_MS, Math.floor(TICK_INTERVAL_MS / (opts.hz ?? 1)));
76
+ _keyframeIntervalMs = opts.keyframeMs ?? KEYFRAME_INTERVAL_MS;
77
+ const hz = opts.hz ?? 2;
78
+ const period = Math.max(MIN_TICK_PERIOD_MS, Math.round(1000 / hz));
83
79
  _timer = setInterval(() => {
84
80
  captureTick();
85
81
  }, period);
86
- // v0.9.12 — Insight 2026-05-17 report: 0.9.11 emitted the
87
- // "starting bound=true" line then went silent. Root cause was the
88
- // `.unref?.()` call that used to live here. Hermes 0.81 doesn't
89
- // ship a Timer object with the Node-style `unref` method, and the
90
- // optional-chained call ended up dereferencing a `prototype`
91
- // property on `undefined` — throwing synchronously inside
92
- // startReplay, which RN's bridge swallowed silently. Net effect:
93
- // setInterval registered, captureTick never invoked. Drop the
94
- // call; replay tick lifecycle is bound to the app process, no
95
- // event-loop tweak needed.
96
82
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
97
83
  // eslint-disable-next-line no-console
98
- console.warn('[sentori] replay: scheduled tick period=', period, 'ms');
84
+ console.warn('[sentori] replay: scheduled tick period=', period, 'ms keyframe=', _keyframeIntervalMs, 'ms');
99
85
  }
100
86
  }
101
87
  export function stopReplay() {
@@ -108,6 +94,9 @@ export function stopReplay() {
108
94
  _emptyTickCount = 0;
109
95
  _emptyTickLogStride = 1;
110
96
  _firstTickLogged = false;
97
+ _okTickCount = 0;
98
+ _thinTickCount = 0;
99
+ _thinTickLogStride = 1;
111
100
  }
112
101
  let _emptyTickCount = 0;
113
102
  let _emptyTickLogStride = 1;
@@ -115,30 +104,15 @@ let _thinTickCount = 0;
115
104
  let _thinTickLogStride = 1;
116
105
  let _okTickCount = 0;
117
106
  let _firstTickLogged = false;
118
- /** Anything below this many nodes is suspicious — likely the
119
- * walker bailed early (zero-size parent, masked root, etc.).
120
- * Insight 2026-05-18 verify event saw 800-node payloads on some
121
- * ticks and 1-3-node payloads on others; this threshold flags
122
- * the latter without spamming on small-but-valid screens. */
123
107
  const THIN_RESULT_NODES = 6;
124
108
  function captureTick() {
125
109
  if (!_running)
126
110
  return;
127
- // v0.9.12 — UNCONDITIONAL first-tick log. Proves the setInterval
128
- // callback is firing at all, before any other code that could
129
- // throw. 0.9.11's diagnostic was inside a `else if (snapshot==null)`
130
- // branch that could only surface AFTER the native call returned;
131
- // useless when the bug is that the tick body never enters.
132
111
  if (typeof __DEV__ !== 'undefined' && __DEV__ && !_firstTickLogged) {
133
112
  // eslint-disable-next-line no-console
134
113
  console.warn('[sentori] replay tick: FIRST INVOCATION');
135
114
  _firstTickLogged = true;
136
115
  }
137
- // 0.9.11 called startSpan OUTSIDE the catch block. If
138
- // `@goliapkg/sentori-core` failed to initialise (or startSpan
139
- // threw for any other reason on the first tick) the whole tick
140
- // callback died silently. Wrap so worst case is "no span for this
141
- // tick" not "no ticks for the session".
142
116
  let tickSpan = null;
143
117
  try {
144
118
  tickSpan = startSpan('sentori.replay.tick', { name: 'tick' });
@@ -148,64 +122,29 @@ function captureTick() {
148
122
  }
149
123
  try {
150
124
  const maskIds = readMaskIds();
151
- const snapshot = _nativeMod?.captureWireframe?.(maskIds);
152
- if (typeof snapshot === 'string' && snapshot.length > 0) {
153
- // v0.9.13 — skip pushing if the frame is identical to the last
154
- // pushed one. See _lastPushed comment for the rationale.
155
- if (snapshot !== _lastPushed) {
156
- _ring.push(snapshot);
157
- _lastPushed = snapshot;
158
- while (_ring.length > RING_SIZE) {
159
- _ring.shift();
160
- }
161
- }
162
- _emptyTickCount = 0;
163
- _emptyTickLogStride = 1;
164
- // v1.0.0-rc.3 — Insight 2026-05-18 report: some ticks land
165
- // valid non-empty JSON but with only the root View + 1-2 wrappers
166
- // (the Android zero-size-bails-subtree bug, now fixed natively;
167
- // this log catches similar regressions). Cheap node-count parse
168
- // — we only look at one digit-level character class.
169
- _okTickCount += 1;
170
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
171
- const nodeCount = countNodesQuick(snapshot);
172
- const sizeBytes = snapshot.length;
173
- const isThin = nodeCount < THIN_RESULT_NODES;
174
- if (isThin) {
175
- _thinTickCount += 1;
176
- if (_thinTickCount === 1 || _thinTickCount === _thinTickLogStride) {
177
- // eslint-disable-next-line no-console
178
- console.warn(`[sentori] replay tick: thin result nodes=${nodeCount} sizeBytes=${sizeBytes} (thin ticks so far: ${_thinTickCount})`);
179
- _thinTickLogStride = Math.max(_thinTickLogStride * 10, 10);
180
- }
181
- }
182
- else {
183
- _thinTickCount = 0;
184
- _thinTickLogStride = 1;
185
- }
186
- // First good tick logs the shape so devs see it once.
187
- if (_okTickCount === 1) {
188
- // eslint-disable-next-line no-console
189
- console.warn(`[sentori] replay tick: first ok — nodes=${nodeCount} sizeBytes=${sizeBytes}`);
190
- }
191
- }
125
+ const snapshotJson = _nativeMod?.captureWireframe?.(maskIds);
126
+ if (typeof snapshotJson !== 'string' || snapshotJson.length === 0) {
127
+ handleEmptyTick(snapshotJson);
128
+ tickSpan?.finish({ status: 'ok' });
129
+ return;
130
+ }
131
+ let snapshot;
132
+ try {
133
+ snapshot = JSON.parse(snapshotJson);
192
134
  }
193
- else if (typeof __DEV__ !== 'undefined' && __DEV__) {
194
- // v0.9.11 Insight 2026-05-17 Finding 6: tick fires hundreds
195
- // of times but ring stays empty → native returned null/empty.
196
- // Log on a back-off schedule (1st, 10th, 100th, …) so the
197
- // diagnostic is visible without spamming Metro at 1 Hz for a
198
- // 15-minute session.
199
- _emptyTickCount += 1;
200
- if (_emptyTickCount === 1 || _emptyTickCount === _emptyTickLogStride) {
135
+ catch (e) {
136
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
201
137
  // eslint-disable-next-line no-console
202
- console.warn('[sentori] replay tick: native returned', snapshot === null
203
- ? 'null'
204
- : typeof snapshot === 'string'
205
- ? `empty (length=${snapshot.length})`
206
- : typeof snapshot, `(empty ticks so far: ${_emptyTickCount})`);
207
- _emptyTickLogStride = Math.max(_emptyTickLogStride * 10, 10);
138
+ console.warn('[sentori] replay tick: native JSON parse failed', e);
208
139
  }
140
+ tickSpan?.finish({ status: 'error' });
141
+ return;
142
+ }
143
+ _emptyTickCount = 0;
144
+ _emptyTickLogStride = 1;
145
+ encodeAndPush(snapshot);
146
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
147
+ diagnosticForTick(snapshot, snapshotJson.length);
209
148
  }
210
149
  tickSpan?.finish({ status: 'ok' });
211
150
  }
@@ -219,28 +158,124 @@ function captureTick() {
219
158
  }
220
159
  }
221
160
  }
222
- /**
223
- * Approximate node-count parse — counts occurrences of the
224
- * `"x":` key in the serialised payload. Every node JSON object
225
- * starts with `{"x":<n>,"y":<n>,"w":<n>,"h":<n>...}` so the
226
- * occurrence count matches the array length without paying for a
227
- * full `JSON.parse`. Cheap enough to run inside the 1 Hz tick.
228
- */
229
- function countNodesQuick(payload) {
230
- let count = 0;
231
- let i = 0;
232
- // Skip the outer {"ts":..,"width":..,"height":..,"nodes":[
233
- // and count `"x":` thereafter. The outer payload doesn't contain
234
- // a top-level "x" key so any match must be a node.
235
- const needle = '"x":';
236
- while (true) {
237
- const at = payload.indexOf(needle, i);
238
- if (at < 0)
239
- break;
240
- count += 1;
241
- i = at + needle.length;
161
+ function encodeAndPush(snapshot) {
162
+ const currentState = new Map();
163
+ for (const n of snapshot.nodes)
164
+ currentState.set(fingerprint(n), n);
165
+ const ts = snapshot.ts;
166
+ const isCold = _lastFrameState === null;
167
+ const keyframeOverdue = ts - _lastKeyframeTs >= _keyframeIntervalMs;
168
+ let line;
169
+ if (isCold || keyframeOverdue) {
170
+ line = encodeKeyframe(snapshot);
171
+ _lastKeyframeTs = ts;
172
+ }
173
+ else {
174
+ const delta = computeDelta(_lastFrameState, currentState);
175
+ const totalChanged = delta.added.length + delta.changed.length + delta.removed.length;
176
+ if (totalChanged === 0) {
177
+ // No-op heartbeat — drop. Keep _lastFrameState as-is (identical).
178
+ return;
179
+ }
180
+ if (currentState.size >= KEYFRAME_RATIO_MIN_NODES &&
181
+ totalChanged >= currentState.size * DELTA_TO_KEYFRAME_RATIO) {
182
+ // Big screen transition on a substantial UI — emit a fresh
183
+ // keyframe so reconstruction doesn't carry a near-rewrite delta.
184
+ line = encodeKeyframe(snapshot);
185
+ _lastKeyframeTs = ts;
186
+ }
187
+ else {
188
+ line = JSON.stringify({
189
+ ts,
190
+ kind: 'delta',
191
+ added: delta.added,
192
+ changed: delta.changed,
193
+ removed: delta.removed,
194
+ });
195
+ }
196
+ }
197
+ _ring.push({ ts, line });
198
+ evictRing(ts);
199
+ _lastFrameState = currentState;
200
+ }
201
+ function encodeKeyframe(snapshot) {
202
+ return JSON.stringify({
203
+ ts: snapshot.ts,
204
+ kind: 'key',
205
+ width: snapshot.width,
206
+ height: snapshot.height,
207
+ nodes: snapshot.nodes,
208
+ });
209
+ }
210
+ function evictRing(nowTs) {
211
+ const cutoff = nowTs - REPLAY_WINDOW_MS;
212
+ while (_ring.length > 0 && _ring[0].ts < cutoff)
213
+ _ring.shift();
214
+ while (_ring.length > MAX_RING_ITEMS)
215
+ _ring.shift();
216
+ }
217
+ /** Fingerprint integer-rounds before joining so sub-pixel jitter from
218
+ * RN's Fabric layout (occasionally floats) doesn't break stable
219
+ * matching across ticks. */
220
+ function fingerprint(n) {
221
+ return `${n.x | 0},${n.y | 0},${n.w | 0},${n.h | 0}`;
222
+ }
223
+ export function computeDelta(prev, curr) {
224
+ const added = [];
225
+ const changed = [];
226
+ const removed = [];
227
+ for (const [fp, node] of curr) {
228
+ const p = prev.get(fp);
229
+ if (!p) {
230
+ added.push(node);
231
+ continue;
232
+ }
233
+ if ((p.kind ?? '') !== (node.kind ?? '') ||
234
+ (p.color ?? '') !== (node.color ?? '') ||
235
+ (p.text ?? '') !== (node.text ?? '')) {
236
+ changed.push(node);
237
+ }
238
+ }
239
+ for (const [fp, node] of prev) {
240
+ if (!curr.has(fp))
241
+ removed.push({ x: node.x, y: node.y, w: node.w, h: node.h });
242
+ }
243
+ return { added, changed, removed };
244
+ }
245
+ function handleEmptyTick(snapshot) {
246
+ if (typeof __DEV__ === 'undefined' || !__DEV__)
247
+ return;
248
+ _emptyTickCount += 1;
249
+ if (_emptyTickCount === 1 || _emptyTickCount === _emptyTickLogStride) {
250
+ // eslint-disable-next-line no-console
251
+ console.warn('[sentori] replay tick: native returned', snapshot === null
252
+ ? 'null'
253
+ : typeof snapshot === 'string'
254
+ ? `empty (length=${snapshot.length})`
255
+ : typeof snapshot, `(empty ticks so far: ${_emptyTickCount})`);
256
+ _emptyTickLogStride = Math.max(_emptyTickLogStride * 10, 10);
257
+ }
258
+ }
259
+ function diagnosticForTick(snapshot, snapshotBytes) {
260
+ _okTickCount += 1;
261
+ const nodeCount = snapshot.nodes.length;
262
+ const isThin = nodeCount < THIN_RESULT_NODES;
263
+ if (isThin) {
264
+ _thinTickCount += 1;
265
+ if (_thinTickCount === 1 || _thinTickCount === _thinTickLogStride) {
266
+ // eslint-disable-next-line no-console
267
+ console.warn(`[sentori] replay tick: thin result nodes=${nodeCount} sizeBytes=${snapshotBytes} (thin ticks so far: ${_thinTickCount})`);
268
+ _thinTickLogStride = Math.max(_thinTickLogStride * 10, 10);
269
+ }
270
+ }
271
+ else {
272
+ _thinTickCount = 0;
273
+ _thinTickLogStride = 1;
274
+ }
275
+ if (_okTickCount === 1) {
276
+ // eslint-disable-next-line no-console
277
+ console.warn(`[sentori] replay tick: first ok — nodes=${nodeCount} sizeBytes=${snapshotBytes}`);
242
278
  }
243
- return count;
244
279
  }
245
280
  function readMaskIds() {
246
281
  const q = getRegisteredMaskQuery();
@@ -263,28 +298,35 @@ function loadNativeReplay() {
263
298
  return null;
264
299
  }
265
300
  }
266
- /** rc.4 — surface "is replay subsystem alive" so the captureException
267
- * debug log can label `wantReplay` alongside `wantScreenshot` /
268
- * `wantSessionTrail`. Insight 2026-05-18 verify flagged that the
269
- * pre-rc.4 log line was missing `wantReplay`, leaving the failure
270
- * shape ambiguous (config-off vs. ring-empty vs. attach-failed). */
271
301
  export function isReplayRunning() {
272
302
  return _running;
273
303
  }
274
- /** Drain the ring as NDJSON (one snapshot per line). Empty string
275
- * when the ring is empty. Also clears the ring so the next session's
276
- * replay starts fresh. */
304
+ /** Drain the ring as NDJSON (keyframe or delta per line). Empty
305
+ * string when the ring is empty. Resets state so the next session's
306
+ * replay starts with a fresh keyframe. */
277
307
  export function drainReplay() {
278
308
  if (_ring.length === 0)
279
309
  return '';
280
- const out = _ring.join('\n');
310
+ const out = _ring.map((r) => r.line).join('\n');
281
311
  _ring = [];
282
- _lastPushed = null;
312
+ _lastFrameState = null;
313
+ _lastKeyframeTs = 0;
283
314
  return out;
284
315
  }
285
316
  export function __resetReplayForTests() {
286
317
  stopReplay();
287
318
  _ring = [];
288
- _lastPushed = null;
319
+ _lastFrameState = null;
320
+ _lastKeyframeTs = 0;
321
+ }
322
+ /** rc.9 — test seam. Lets unit tests drive the encoder without a
323
+ * native module; pretends we received `frameJson` on the tick. */
324
+ export function __feedTickForTests(frameJson) {
325
+ if (!_running) {
326
+ // Simulate "running" without an actual setInterval — caller drives.
327
+ _running = true;
328
+ }
329
+ const snapshot = JSON.parse(frameJson);
330
+ encodeAndPush(snapshot);
289
331
  }
290
332
  //# sourceMappingURL=replay.js.map
package/lib/replay.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ export type SecurityReportData = Record<string, unknown>;
2
+ /**
3
+ * Report an arbitrary security signal. Fire-and-forget; resolves
4
+ * with the server-assigned event id on success or `null` on any
5
+ * failure (network down, server unhappy, SDK not initialised).
6
+ *
7
+ * Use the dedicated helpers (`reportPinMismatch`, future
8
+ * `reportRootDetected`, …) when their shape applies — the dashboard
9
+ * renders kind-specific panels off the well-known kinds.
10
+ */
11
+ export declare function reportSecurity(kind: string, data?: SecurityReportData): Promise<null | string>;
12
+ /**
13
+ * v1.1 chunk S4 — link the current device's user / install to a
14
+ * federated identity (e.g. a Google sub or Apple `sub`). Idempotent;
15
+ * call on every sign-in. Posts to `/v1/security/link`. The dashboard
16
+ * uses this to stitch the same user across projects in the Posture
17
+ * cross-project view.
18
+ *
19
+ * Privacy: only the opaque OAuth `subject` value travels. Never pass
20
+ * the email, display name, avatar, or any other identity attribute.
21
+ */
22
+ export declare function linkFederatedIdentity(args: {
23
+ provider: string;
24
+ subject: string;
25
+ userId?: string;
26
+ }): Promise<boolean>;
27
+ /**
28
+ * TLS certificate pin mismatch — caller observed a server cert that
29
+ * didn't match the configured pin set. Posts `kind = 'pin.mismatch'`
30
+ * with the expected + observed pin (or hash) so the dashboard's
31
+ * Pin anomaly panel can cluster reports by server.
32
+ */
33
+ export declare function reportPinMismatch(args: {
34
+ expected: string;
35
+ observed: string;
36
+ /** Hostname the SDK was connecting to. Used by the dashboard to
37
+ * cluster reports per server. */
38
+ serverName: string;
39
+ }): Promise<null | string>;
40
+ //# sourceMappingURL=report-security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-security.d.ts","sourceRoot":"","sources":["../src/report-security.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAkCxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CA2BnB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB;sCACkC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAuCzB"}