@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
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Resolve the device's stable install id, generating one if absent.
3
+ * Cached in memory after first resolve so subsequent calls are sync-
4
+ * adjacent (no storage I/O). Idempotent under concurrent calls — a
5
+ * second caller during the first resolve awaits the same promise.
6
+ */
7
+ export declare function getInstallId(): Promise<string>;
8
+ /** Sync read of the currently-cached install id. `null` before the
9
+ * first `getInstallId()` resolves. Use this in hot paths (event
10
+ * payload assembly) that can't await storage; callers should kick
11
+ * off `getInstallId()` once at startup to warm the cache. */
12
+ export declare function peekInstallId(): null | string;
13
+ export declare function __resetInstallIdForTests(): void;
14
+ /** For tests + advanced operator flows that need to seed an id from
15
+ * an external secure-storage migration. */
16
+ export declare function __setInstallIdForTests(id: string): void;
17
+ //# sourceMappingURL=install-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-id.d.ts","sourceRoot":"","sources":["../src/install-id.ts"],"names":[],"mappings":"AA0EA;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CA8CpD;AAED;;;8DAG8D;AAC9D,wBAAgB,aAAa,IAAI,IAAI,GAAG,MAAM,CAE7C;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C;AAED;4CAC4C;AAC5C,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEvD"}
@@ -0,0 +1,125 @@
1
+ // v1.1 chunk S1 — stable per-install identifier.
2
+ //
3
+ // `getInstallId()` returns a UUIDv7 generated on first call and
4
+ // persisted to device storage. The id survives app restarts and, on
5
+ // iOS specifically, app reinstalls (because the Keychain backend is
6
+ // preserved across uninstall — that's the whole point).
7
+ //
8
+ // Storage tier order:
9
+ // 1. `react-native-keychain` (optional peer; iOS + Android Keystore)
10
+ // 2. AsyncStorage (host already needs this for launch-crash-guard /
11
+ // offline queue, so we don't add a hard new peer dep)
12
+ // 3. Process-memory only (no persistence — covers SSR / tests)
13
+ //
14
+ // Opaque to the host. The id is NOT tied to a `setUser` call; the
15
+ // server doesn't auto-correlate to user identity. It exists purely
16
+ // as a stable device key so the security posture engine (S3) can
17
+ // score per-install signals independently of authentication state.
18
+ import { uuidV7 } from '@goliapkg/sentori-core';
19
+ import { isAnyNativeModuleLinked } from './native-loader';
20
+ const KEYCHAIN_SERVICE = 'sentori.install-id';
21
+ const ASYNC_STORAGE_KEY = '@sentori/install-id';
22
+ let _cached = null;
23
+ let _inflight = null;
24
+ function loadKeychain() {
25
+ // react-native-keychain is the recommended secure-storage peer.
26
+ // Optional: if the host hasn't installed it we fall through to
27
+ // AsyncStorage. The Keychain backend is what gives the iOS
28
+ // "survives reinstall" guarantee.
29
+ try {
30
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
31
+ const mod = require('react-native-keychain');
32
+ if (typeof mod.getGenericPassword !== 'function')
33
+ return null;
34
+ return mod;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function loadAsyncStorage() {
41
+ if (!isAnyNativeModuleLinked(['RNCAsyncStorage', 'AsyncStorageModule'])) {
42
+ return null;
43
+ }
44
+ try {
45
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
46
+ const mod = require('@react-native-async-storage/async-storage');
47
+ return mod.default ?? mod;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ /**
54
+ * Resolve the device's stable install id, generating one if absent.
55
+ * Cached in memory after first resolve so subsequent calls are sync-
56
+ * adjacent (no storage I/O). Idempotent under concurrent calls — a
57
+ * second caller during the first resolve awaits the same promise.
58
+ */
59
+ export async function getInstallId() {
60
+ if (_cached !== null)
61
+ return _cached;
62
+ if (_inflight !== null)
63
+ return _inflight;
64
+ _inflight = (async () => {
65
+ try {
66
+ const kc = loadKeychain();
67
+ if (kc) {
68
+ const existing = await kc
69
+ .getGenericPassword({ service: KEYCHAIN_SERVICE })
70
+ .catch(() => false);
71
+ if (existing && existing.password) {
72
+ _cached = existing.password;
73
+ return existing.password;
74
+ }
75
+ const fresh = uuidV7();
76
+ await kc
77
+ .setGenericPassword('sentori', fresh, { service: KEYCHAIN_SERVICE })
78
+ .catch(() => undefined);
79
+ _cached = fresh;
80
+ return fresh;
81
+ }
82
+ const storage = loadAsyncStorage();
83
+ if (storage) {
84
+ const existing = await storage
85
+ .getItem(ASYNC_STORAGE_KEY)
86
+ .catch(() => null);
87
+ if (existing) {
88
+ _cached = existing;
89
+ return existing;
90
+ }
91
+ const fresh = uuidV7();
92
+ await storage.setItem(ASYNC_STORAGE_KEY, fresh).catch(() => undefined);
93
+ _cached = fresh;
94
+ return fresh;
95
+ }
96
+ // No storage available — generate but don't persist. The id is
97
+ // still stable for the lifetime of the process which is good
98
+ // enough for tests / SSR / no-native-modules contexts.
99
+ const fresh = uuidV7();
100
+ _cached = fresh;
101
+ return fresh;
102
+ }
103
+ finally {
104
+ _inflight = null;
105
+ }
106
+ })();
107
+ return _inflight;
108
+ }
109
+ /** Sync read of the currently-cached install id. `null` before the
110
+ * first `getInstallId()` resolves. Use this in hot paths (event
111
+ * payload assembly) that can't await storage; callers should kick
112
+ * off `getInstallId()` once at startup to warm the cache. */
113
+ export function peekInstallId() {
114
+ return _cached;
115
+ }
116
+ export function __resetInstallIdForTests() {
117
+ _cached = null;
118
+ _inflight = null;
119
+ }
120
+ /** For tests + advanced operator flows that need to seed an id from
121
+ * an external secure-storage migration. */
122
+ export function __setInstallIdForTests(id) {
123
+ _cached = id;
124
+ }
125
+ //# sourceMappingURL=install-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-id.js","sourceRoot":"","sources":["../src/install-id.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ export type NavigationRefLike = {
7
7
  name: string;
8
8
  } | undefined;
9
9
  };
10
+ export declare function getLastRoute(): null | string;
10
11
  /**
11
12
  * Subscribe to react-navigation state changes and emit a
12
13
  * `react.navigation` span per screen (including the initial one),
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAgCA;;kDAEkD;AAClD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAClE,eAAe,EAAE,MAAM;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACrD,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,iBAAiB,GAAG,IAAI,CA2FzE"}
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAiCA;;kDAEkD;AAClD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAClE,eAAe,EAAE,MAAM;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACrD,CAAC;AASF,wBAAgB,YAAY,IAAI,IAAI,GAAG,MAAM,CAE5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,iBAAiB,GAAG,IAAI,CAyGzE"}
package/lib/navigation.js CHANGED
@@ -22,7 +22,17 @@
22
22
  import { useEffect, useRef } from 'react';
23
23
  import { setActiveSpan, startSpan } from '@goliapkg/sentori-core';
24
24
  import { getNativeFrameCounters, resetNativeFrameCounters, } from './native';
25
+ import { track } from './track';
25
26
  import { captureStep } from './trail';
27
+ /** Process-global last-known route — populated by the navigation
28
+ * span path below, read by the analytics heartbeat so its per-tick
29
+ * payload includes the screen the user is on right now. Initial null
30
+ * when no nav has happened yet (app just launched, dev-launcher,
31
+ * splash). */
32
+ let _lastRoute = null;
33
+ export function getLastRoute() {
34
+ return _lastRoute;
35
+ }
26
36
  /**
27
37
  * Subscribe to react-navigation state changes and emit a
28
38
  * `react.navigation` span per screen (including the initial one),
@@ -66,6 +76,7 @@ export function useTraceNavigation(navigationRef) {
66
76
  openSpanRef.current = span;
67
77
  setActiveSpan(span);
68
78
  lastRouteRef.current = to;
79
+ _lastRoute = to;
69
80
  lastRouteEnteredAtRef.current = Date.now();
70
81
  // v0.8.0-b — dwell on the previous screen surfaces in the
71
82
  // session trail. The leaving span's `durationMs` already
@@ -79,6 +90,15 @@ export function useTraceNavigation(navigationRef) {
79
90
  type: 'navigation',
80
91
  },
81
92
  });
93
+ // v1.1 chunk B — auto-pageview. Pushed into the track ring
94
+ // alongside the navigation span so the analytics path sees
95
+ // every screen entry without app code needing to wire its own
96
+ // pageview calls. `from`/`dwellMsPrev` ride in props so the
97
+ // Behavior view (chunk D) can reconstruct the user journey
98
+ // even when only the track stream is queried.
99
+ track('$pageview', prevDwellMs !== null
100
+ ? { from: from ?? null, dwellMsPrev: prevDwellMs }
101
+ : { from: from ?? null }, to);
82
102
  };
83
103
  const finishOpenSpanWithDwell = () => {
84
104
  const span = openSpanRef.current;
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"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"}
package/lib/replay.d.ts CHANGED
@@ -1,19 +1,37 @@
1
+ type Node = {
2
+ x: number;
3
+ y: number;
4
+ w: number;
5
+ h: number;
6
+ kind?: string;
7
+ text?: string;
8
+ color?: string;
9
+ };
1
10
  export type ReplayOptions = {
2
11
  mode?: 'off' | 'wireframe';
3
- /** Ticks per second. Default 1. */
12
+ /** Ticks per second. Default 2. Opt into 4 (or 8) for
13
+ * motion-heavy apps where playback smoothness matters more than
14
+ * the marginal CPU saving. */
4
15
  hz?: number;
16
+ /** Keyframe cadence in ms. Default 4000. */
17
+ keyframeMs?: number;
5
18
  };
6
19
  export declare function startReplay(opts: ReplayOptions): void;
7
20
  export declare function stopReplay(): void;
8
- /** rc.4 surface "is replay subsystem alive" so the captureException
9
- * debug log can label `wantReplay` alongside `wantScreenshot` /
10
- * `wantSessionTrail`. Insight 2026-05-18 verify flagged that the
11
- * pre-rc.4 log line was missing `wantReplay`, leaving the failure
12
- * shape ambiguous (config-off vs. ring-empty vs. attach-failed). */
21
+ type Delta = {
22
+ added: Node[];
23
+ changed: Node[];
24
+ removed: Pick<Node, 'x' | 'y' | 'w' | 'h'>[];
25
+ };
26
+ export declare function computeDelta(prev: Map<string, Node>, curr: Map<string, Node>): Delta;
13
27
  export declare function isReplayRunning(): boolean;
14
- /** Drain the ring as NDJSON (one snapshot per line). Empty string
15
- * when the ring is empty. Also clears the ring so the next session's
16
- * replay starts fresh. */
28
+ /** Drain the ring as NDJSON (keyframe or delta per line). Empty
29
+ * string when the ring is empty. Resets state so the next session's
30
+ * replay starts with a fresh keyframe. */
17
31
  export declare function drainReplay(): string;
18
32
  export declare function __resetReplayForTests(): void;
33
+ /** rc.9 — test seam. Lets unit tests drive the encoder without a
34
+ * native module; pretends we received `frameJson` on the tick. */
35
+ export declare function __feedTickForTests(frameJson: string): void;
36
+ export {};
19
37
  //# sourceMappingURL=replay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAkEA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;IAC3B,mCAAmC;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CA+CrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAUjC;AAuKD;;;;qEAIqE;AACrE,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;2BAE2B;AAC3B,wBAAgB,WAAW,IAAI,MAAM,CAMpC;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C"}
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AA0DA,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,CAmCrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAajC;AAmID,KAAK,KAAK,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,OAAO,EAAE,IAAI,EAAE,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,CAAA;CAAE,CAAC;AAE9F,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,KAAK,CAsBpF;AAuED,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"}