@goliapkg/sentori-react-native 4.0.0 → 5.1.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 (308) hide show
  1. package/MIGRATION.md +131 -0
  2. package/README.md +40 -30
  3. package/android/build.gradle +21 -0
  4. package/android/src/main/java/com/sentori/SentoriCrashHandler.kt +29 -0
  5. package/android/src/main/java/com/sentori/SentoriModule.kt +8 -0
  6. package/android/src/main/java/com/sentori/SentoriScreenshotCapture.kt +36 -4
  7. package/android/src/test/java/com/sentori/SentoriCrashHandlerTest.kt +7 -2
  8. package/android/src/test/resources/robolectric.properties +10 -0
  9. package/ios/SentoriCrashHandler.swift +48 -4
  10. package/ios/SentoriModule.swift +12 -0
  11. package/ios/SentoriScreenshotCapture.swift +34 -3
  12. package/lib/config.d.ts +17 -47
  13. package/lib/config.d.ts.map +1 -1
  14. package/lib/config.js +3 -0
  15. package/lib/config.js.map +1 -1
  16. package/lib/device.d.ts +5 -0
  17. package/lib/device.d.ts.map +1 -0
  18. package/lib/device.js +29 -0
  19. package/lib/device.js.map +1 -0
  20. package/lib/emit-hooks.d.ts +7 -0
  21. package/lib/emit-hooks.d.ts.map +1 -0
  22. package/lib/emit-hooks.js +24 -0
  23. package/lib/emit-hooks.js.map +1 -0
  24. package/lib/error-boundary.d.ts.map +1 -1
  25. package/lib/error-boundary.js +1 -1
  26. package/lib/error-boundary.js.map +1 -1
  27. package/lib/feature-flags.d.ts.map +1 -1
  28. package/lib/handlers/dev-symbolicate.d.ts +1 -1
  29. package/lib/handlers/dev-symbolicate.d.ts.map +1 -1
  30. package/lib/handlers/dev-symbolicate.js +2 -0
  31. package/lib/handlers/dev-symbolicate.js.map +1 -1
  32. package/lib/handlers/global.js +1 -1
  33. package/lib/handlers/global.js.map +1 -1
  34. package/lib/handlers/lifecycle.js +3 -3
  35. package/lib/handlers/lifecycle.js.map +1 -1
  36. package/lib/handlers/network.d.ts +2 -2
  37. package/lib/handlers/network.d.ts.map +1 -1
  38. package/lib/handlers/network.js +69 -187
  39. package/lib/handlers/network.js.map +1 -1
  40. package/lib/handlers/promise.js +1 -1
  41. package/lib/handlers/promise.js.map +1 -1
  42. package/lib/handlers/screenshot.d.ts.map +1 -1
  43. package/lib/handlers/screenshot.js +3 -12
  44. package/lib/handlers/screenshot.js.map +1 -1
  45. package/lib/index.d.ts +32 -109
  46. package/lib/index.d.ts.map +1 -1
  47. package/lib/index.js +54 -103
  48. package/lib/index.js.map +1 -1
  49. package/lib/init.d.ts +3 -150
  50. package/lib/init.d.ts.map +1 -1
  51. package/lib/init.js +100 -261
  52. package/lib/init.js.map +1 -1
  53. package/lib/long-task-monitor.d.ts +1 -7
  54. package/lib/long-task-monitor.d.ts.map +1 -1
  55. package/lib/long-task-monitor.js +37 -58
  56. package/lib/long-task-monitor.js.map +1 -1
  57. package/lib/mask.d.ts +5 -13
  58. package/lib/mask.d.ts.map +1 -1
  59. package/lib/mask.js +29 -30
  60. package/lib/mask.js.map +1 -1
  61. package/lib/mobile-vitals.d.ts +3 -31
  62. package/lib/mobile-vitals.d.ts.map +1 -1
  63. package/lib/mobile-vitals.js +22 -61
  64. package/lib/mobile-vitals.js.map +1 -1
  65. package/lib/native-pending.d.ts +3 -0
  66. package/lib/native-pending.d.ts.map +1 -0
  67. package/lib/native-pending.js +64 -0
  68. package/lib/native-pending.js.map +1 -0
  69. package/lib/native.d.ts +4 -11
  70. package/lib/native.d.ts.map +1 -1
  71. package/lib/native.js +23 -0
  72. package/lib/native.js.map +1 -1
  73. package/lib/navigation.d.ts +3 -17
  74. package/lib/navigation.d.ts.map +1 -1
  75. package/lib/navigation.js +32 -133
  76. package/lib/navigation.js.map +1 -1
  77. package/lib/netinfo.d.ts +1 -1
  78. package/lib/netinfo.d.ts.map +1 -1
  79. package/lib/netinfo.js +2 -2
  80. package/lib/netinfo.js.map +1 -1
  81. package/lib/push.d.ts.map +1 -1
  82. package/lib/push.js +2 -4
  83. package/lib/push.js.map +1 -1
  84. package/lib/rage-tap.d.ts.map +1 -1
  85. package/lib/rage-tap.js +56 -23
  86. package/lib/rage-tap.js.map +1 -1
  87. package/lib/replay-screens.d.ts +15 -0
  88. package/lib/replay-screens.d.ts.map +1 -0
  89. package/lib/replay-screens.js +87 -0
  90. package/lib/replay-screens.js.map +1 -0
  91. package/lib/replay.d.ts.map +1 -1
  92. package/lib/replay.js +3 -24
  93. package/lib/replay.js.map +1 -1
  94. package/lib/responsiveness-detector.d.ts +18 -0
  95. package/lib/responsiveness-detector.d.ts.map +1 -0
  96. package/lib/responsiveness-detector.js +55 -0
  97. package/lib/responsiveness-detector.js.map +1 -0
  98. package/lib/scope.d.ts +7 -0
  99. package/lib/scope.d.ts.map +1 -0
  100. package/lib/scope.js +41 -0
  101. package/lib/scope.js.map +1 -0
  102. package/lib/transport.d.ts +19 -92
  103. package/lib/transport.d.ts.map +1 -1
  104. package/lib/transport.js +75 -288
  105. package/lib/transport.js.map +1 -1
  106. package/lib/verbs.d.ts +16 -0
  107. package/lib/verbs.d.ts.map +1 -0
  108. package/lib/verbs.js +153 -0
  109. package/lib/verbs.js.map +1 -0
  110. package/package.json +4 -3
  111. package/src/__tests__/iron-rule.test.ts +128 -0
  112. package/src/__tests__/replay-screens.test.ts +63 -0
  113. package/src/__tests__/responsiveness-detector.test.ts +74 -0
  114. package/src/__tests__/screenshot.test.ts +0 -2
  115. package/src/__tests__/transport.test.ts +66 -213
  116. package/src/__tests__/verbs.test.ts +91 -0
  117. package/src/config.ts +20 -47
  118. package/src/device.ts +36 -0
  119. package/src/emit-hooks.ts +30 -0
  120. package/src/error-boundary.tsx +1 -1
  121. package/src/handlers/dev-symbolicate.ts +2 -1
  122. package/src/handlers/global.ts +1 -1
  123. package/src/handlers/lifecycle.ts +3 -3
  124. package/src/handlers/network.ts +95 -211
  125. package/src/handlers/promise.ts +1 -1
  126. package/src/handlers/screenshot.ts +3 -11
  127. package/src/index.ts +84 -215
  128. package/src/init.ts +115 -449
  129. package/src/long-task-monitor.ts +42 -64
  130. package/src/mask.ts +29 -31
  131. package/src/mobile-vitals.ts +22 -82
  132. package/src/native-pending.ts +92 -0
  133. package/src/native.ts +33 -0
  134. package/src/navigation.ts +34 -142
  135. package/src/netinfo.ts +3 -3
  136. package/src/push.ts +2 -5
  137. package/src/rage-tap.tsx +72 -25
  138. package/src/replay-screens.ts +95 -0
  139. package/src/replay.ts +3 -20
  140. package/src/responsiveness-detector.ts +66 -0
  141. package/src/scope.ts +50 -0
  142. package/src/transport.ts +84 -371
  143. package/src/verbs.ts +198 -0
  144. package/lib/breadcrumbs.d.ts +0 -18
  145. package/lib/breadcrumbs.d.ts.map +0 -1
  146. package/lib/breadcrumbs.js +0 -42
  147. package/lib/breadcrumbs.js.map +0 -1
  148. package/lib/bundle-info.d.ts +0 -12
  149. package/lib/bundle-info.d.ts.map +0 -1
  150. package/lib/bundle-info.js +0 -73
  151. package/lib/bundle-info.js.map +0 -1
  152. package/lib/capture.d.ts +0 -140
  153. package/lib/capture.d.ts.map +0 -1
  154. package/lib/capture.js +0 -511
  155. package/lib/capture.js.map +0 -1
  156. package/lib/compat/sentry.d.ts +0 -126
  157. package/lib/compat/sentry.d.ts.map +0 -1
  158. package/lib/compat/sentry.js +0 -332
  159. package/lib/compat/sentry.js.map +0 -1
  160. package/lib/control-channel.d.ts +0 -6
  161. package/lib/control-channel.d.ts.map +0 -1
  162. package/lib/control-channel.js +0 -96
  163. package/lib/control-channel.js.map +0 -1
  164. package/lib/expo-compat.d.ts +0 -270
  165. package/lib/expo-compat.d.ts.map +0 -1
  166. package/lib/expo-compat.js +0 -500
  167. package/lib/expo-compat.js.map +0 -1
  168. package/lib/feedback-widget.d.ts +0 -35
  169. package/lib/feedback-widget.d.ts.map +0 -1
  170. package/lib/feedback-widget.js +0 -193
  171. package/lib/feedback-widget.js.map +0 -1
  172. package/lib/feedback.d.ts +0 -2
  173. package/lib/feedback.d.ts.map +0 -1
  174. package/lib/feedback.js +0 -17
  175. package/lib/feedback.js.map +0 -1
  176. package/lib/heartbeat.d.ts +0 -9
  177. package/lib/heartbeat.d.ts.map +0 -1
  178. package/lib/heartbeat.js +0 -138
  179. package/lib/heartbeat.js.map +0 -1
  180. package/lib/index.js.bak +0 -64
  181. package/lib/install-id.d.ts +0 -17
  182. package/lib/install-id.d.ts.map +0 -1
  183. package/lib/install-id.js +0 -125
  184. package/lib/install-id.js.map +0 -1
  185. package/lib/lifecycle.d.ts +0 -28
  186. package/lib/lifecycle.d.ts.map +0 -1
  187. package/lib/lifecycle.js +0 -73
  188. package/lib/lifecycle.js.map +0 -1
  189. package/lib/measure.d.ts +0 -4
  190. package/lib/measure.d.ts.map +0 -1
  191. package/lib/measure.js +0 -25
  192. package/lib/measure.js.map +0 -1
  193. package/lib/metrics.d.ts +0 -24
  194. package/lib/metrics.d.ts.map +0 -1
  195. package/lib/metrics.js +0 -81
  196. package/lib/metrics.js.map +0 -1
  197. package/lib/pre-crash-sentinel.d.ts +0 -12
  198. package/lib/pre-crash-sentinel.d.ts.map +0 -1
  199. package/lib/pre-crash-sentinel.js +0 -116
  200. package/lib/pre-crash-sentinel.js.map +0 -1
  201. package/lib/report-security.d.ts +0 -40
  202. package/lib/report-security.d.ts.map +0 -1
  203. package/lib/report-security.js +0 -159
  204. package/lib/report-security.js.map +0 -1
  205. package/lib/runtime-metrics-fps.d.ts +0 -19
  206. package/lib/runtime-metrics-fps.d.ts.map +0 -1
  207. package/lib/runtime-metrics-fps.js +0 -128
  208. package/lib/runtime-metrics-fps.js.map +0 -1
  209. package/lib/runtime-metrics-heap.d.ts +0 -13
  210. package/lib/runtime-metrics-heap.d.ts.map +0 -1
  211. package/lib/runtime-metrics-heap.js +0 -67
  212. package/lib/runtime-metrics-heap.js.map +0 -1
  213. package/lib/runtime-metrics-network.d.ts +0 -23
  214. package/lib/runtime-metrics-network.d.ts.map +0 -1
  215. package/lib/runtime-metrics-network.js +0 -99
  216. package/lib/runtime-metrics-network.js.map +0 -1
  217. package/lib/runtime-metrics.d.ts +0 -43
  218. package/lib/runtime-metrics.d.ts.map +0 -1
  219. package/lib/runtime-metrics.js +0 -115
  220. package/lib/runtime-metrics.js.map +0 -1
  221. package/lib/sample-profiler.d.ts +0 -21
  222. package/lib/sample-profiler.d.ts.map +0 -1
  223. package/lib/sample-profiler.js +0 -152
  224. package/lib/sample-profiler.js.map +0 -1
  225. package/lib/sentinel-context.d.ts +0 -4
  226. package/lib/sentinel-context.d.ts.map +0 -1
  227. package/lib/sentinel-context.js +0 -52
  228. package/lib/sentinel-context.js.map +0 -1
  229. package/lib/session-tracker.d.ts +0 -6
  230. package/lib/session-tracker.d.ts.map +0 -1
  231. package/lib/session-tracker.js +0 -50
  232. package/lib/session-tracker.js.map +0 -1
  233. package/lib/stack.d.ts +0 -3
  234. package/lib/stack.d.ts.map +0 -1
  235. package/lib/stack.js +0 -7
  236. package/lib/stack.js.map +0 -1
  237. package/lib/state-snapshots.d.ts +0 -33
  238. package/lib/state-snapshots.d.ts.map +0 -1
  239. package/lib/state-snapshots.js +0 -109
  240. package/lib/state-snapshots.js.map +0 -1
  241. package/lib/track.d.ts +0 -34
  242. package/lib/track.d.ts.map +0 -1
  243. package/lib/track.js +0 -107
  244. package/lib/track.js.map +0 -1
  245. package/lib/trail.d.ts +0 -12
  246. package/lib/trail.d.ts.map +0 -1
  247. package/lib/trail.js +0 -28
  248. package/lib/trail.js.map +0 -1
  249. package/lib/trust-score.d.ts +0 -20
  250. package/lib/trust-score.d.ts.map +0 -1
  251. package/lib/trust-score.js +0 -151
  252. package/lib/trust-score.js.map +0 -1
  253. package/lib/types.d.ts +0 -2
  254. package/lib/types.d.ts.map +0 -1
  255. package/lib/types.js +0 -4
  256. package/lib/types.js.map +0 -1
  257. package/lib/uuid.d.ts +0 -2
  258. package/lib/uuid.d.ts.map +0 -1
  259. package/lib/uuid.js +0 -3
  260. package/lib/uuid.js.map +0 -1
  261. package/src/__tests__/before-send.test.ts +0 -72
  262. package/src/__tests__/breadcrumbs.test.ts +0 -44
  263. package/src/__tests__/capture-replay.test.ts +0 -150
  264. package/src/__tests__/compat-sentry.test.ts +0 -121
  265. package/src/__tests__/control-channel.test.ts +0 -111
  266. package/src/__tests__/install-id.test.ts +0 -60
  267. package/src/__tests__/long-task-monitor.test.ts +0 -59
  268. package/src/__tests__/measure.test.ts +0 -45
  269. package/src/__tests__/navigation.test.ts +0 -175
  270. package/src/__tests__/push.test.ts +0 -238
  271. package/src/__tests__/report-security.test.ts +0 -106
  272. package/src/__tests__/runtime-metrics-instruments.test.ts +0 -109
  273. package/src/__tests__/runtime-metrics-network.test.ts +0 -78
  274. package/src/__tests__/sample-profiler.test.ts +0 -59
  275. package/src/__tests__/stack.test.ts +0 -45
  276. package/src/__tests__/state-snapshots.test.ts +0 -119
  277. package/src/__tests__/tracing.test.ts +0 -201
  278. package/src/__tests__/track.test.ts +0 -91
  279. package/src/__tests__/uuid.test.ts +0 -41
  280. package/src/breadcrumbs.ts +0 -57
  281. package/src/bundle-info.ts +0 -95
  282. package/src/capture.ts +0 -660
  283. package/src/compat/sentry.ts +0 -490
  284. package/src/control-channel.ts +0 -98
  285. package/src/expo-compat.ts +0 -698
  286. package/src/feedback-widget.tsx +0 -316
  287. package/src/feedback.ts +0 -21
  288. package/src/heartbeat.ts +0 -157
  289. package/src/install-id.ts +0 -146
  290. package/src/lifecycle.ts +0 -76
  291. package/src/measure.ts +0 -28
  292. package/src/metrics.ts +0 -94
  293. package/src/pre-crash-sentinel.ts +0 -140
  294. package/src/report-security.ts +0 -165
  295. package/src/runtime-metrics-fps.ts +0 -137
  296. package/src/runtime-metrics-heap.ts +0 -78
  297. package/src/runtime-metrics-network.ts +0 -103
  298. package/src/runtime-metrics.ts +0 -122
  299. package/src/sample-profiler.ts +0 -169
  300. package/src/sentinel-context.ts +0 -60
  301. package/src/session-tracker.ts +0 -53
  302. package/src/stack.ts +0 -10
  303. package/src/state-snapshots.ts +0 -133
  304. package/src/track.ts +0 -123
  305. package/src/trail.ts +0 -32
  306. package/src/trust-score.ts +0 -176
  307. package/src/types.ts +0 -21
  308. package/src/uuid.ts +0 -2
@@ -1,133 +0,0 @@
1
- // v0.9.2 +S2 — State Time-travel (SDK side).
2
- //
3
- // `sentori.bindState({ redux, zustand })` subscribes to a store-like
4
- // object and records a shallow diff every time it emits a change.
5
- // A ring buffer of the last N snapshots travels with each
6
- // captureException as a `stateSnapshot` attachment — the dashboard's
7
- // time-travel viewer (v0.9.2.1) renders the timeline.
8
- //
9
- // Why diffs and not full snapshots:
10
- // • prod stores can be huge (carts, paginated lists, etc.)
11
- // • a diff drops to ~1% of full snapshot size in typical apps
12
- // • the viewer rehydrates by applying diffs forward from a baseline
13
- //
14
- // `recordState(obj)` is the manual escape hatch for state that isn't
15
- // in a redux/zustand store (e.g. `useState` in a deeply-nested
16
- // component, or React Context). The host calls it where it makes sense.
17
- //
18
- // Privacy: the same mask query that protects screenshots is consulted
19
- // before serializing — any path matching `nativeID` shape isn't yet,
20
- // but `mask.matchPath` can be added later. v0.9.2 ships without
21
- // path masking; consumers should keep PII out of bindState scopes.
22
-
23
- const MAX_SNAPSHOTS = 50;
24
-
25
- type StoreLike = {
26
- getState?: () => unknown;
27
- subscribe?: (cb: () => void) => () => void;
28
- };
29
-
30
- export type StateSnapshot = {
31
- /** Wall-clock when the diff fired. */
32
- ts: number;
33
- /** Top-level key/value diff vs the previous snapshot. Empty diff
34
- * doesn't get recorded. */
35
- diff: Record<string, unknown>;
36
- /** Source label so the viewer can show "Redux" / "Zustand" / "Manual". */
37
- source: string;
38
- };
39
-
40
- let _snapshots: StateSnapshot[] = [];
41
- let _unsubscribers: (() => void)[] = [];
42
- let _lastByLabel: Record<string, unknown> = {};
43
-
44
- export function bindState(opts: {
45
- redux?: StoreLike;
46
- zustand?: StoreLike;
47
- /** Additional named stores. The label is used as the snapshot's
48
- * `source` and as the diff bucket key. */
49
- custom?: Record<string, StoreLike>;
50
- }): void {
51
- unbindState();
52
- bindOne('redux', opts.redux);
53
- bindOne('zustand', opts.zustand);
54
- if (opts.custom) {
55
- for (const [label, store] of Object.entries(opts.custom)) {
56
- bindOne(label, store);
57
- }
58
- }
59
- }
60
-
61
- function bindOne(label: string, store?: StoreLike): void {
62
- if (!store) return;
63
- if (typeof store.getState !== 'function' || typeof store.subscribe !== 'function') return;
64
- try {
65
- _lastByLabel[label] = store.getState();
66
- const unsub = store.subscribe(() => {
67
- const next = store.getState!();
68
- const prev = _lastByLabel[label];
69
- const diff = shallowDiff(prev, next);
70
- if (diff && Object.keys(diff).length > 0) {
71
- push({ diff, source: label, ts: Date.now() });
72
- }
73
- _lastByLabel[label] = next;
74
- });
75
- _unsubscribers.push(unsub);
76
- } catch {
77
- // ignore bad stores
78
- }
79
- }
80
-
81
- export function unbindState(): void {
82
- for (const u of _unsubscribers) {
83
- try {
84
- u();
85
- } catch {
86
- // ignore
87
- }
88
- }
89
- _unsubscribers = [];
90
- _lastByLabel = {};
91
- }
92
-
93
- /** Manual recording for state not in a subscribed store. */
94
- export function recordState(snapshot: Record<string, unknown>, source = 'manual'): void {
95
- push({ diff: snapshot, source, ts: Date.now() });
96
- }
97
-
98
- export function getStateSnapshots(): StateSnapshot[] {
99
- return _snapshots.slice();
100
- }
101
-
102
- export function clearStateSnapshots(): void {
103
- _snapshots = [];
104
- }
105
-
106
- function push(s: StateSnapshot): void {
107
- _snapshots.push(s);
108
- while (_snapshots.length > MAX_SNAPSHOTS) _snapshots.shift();
109
- }
110
-
111
- /** Returns the top-level key/value diff (next has the value, prev
112
- * may not contain the key). Empty diff returns `{}` so callers can
113
- * no-op on empty. */
114
- export function shallowDiff(prev: unknown, next: unknown): null | Record<string, unknown> {
115
- if (typeof next !== 'object' || next === null) return null;
116
- const nObj = next as Record<string, unknown>;
117
- if (typeof prev !== 'object' || prev === null) {
118
- return { ...nObj };
119
- }
120
- const pObj = prev as Record<string, unknown>;
121
- const out: Record<string, unknown> = {};
122
- const keys = new Set([...Object.keys(pObj), ...Object.keys(nObj)]);
123
- for (const k of keys) {
124
- if (pObj[k] !== nObj[k]) out[k] = nObj[k];
125
- }
126
- return out;
127
- }
128
-
129
- /** Test-only. */
130
- export function __resetStateSnapshotsForTests(): void {
131
- unbindState();
132
- _snapshots = [];
133
- }
package/src/track.ts DELETED
@@ -1,123 +0,0 @@
1
- // v1.1 chunk B — analytics `track` events on the SDK side.
2
- //
3
- // `sentori.track(name, props?)` pushes a single typed analytics event
4
- // into a fixed-size ring. A timer flushes the ring every 30 s (or
5
- // when the buffer hits 500) to `POST /v1/track:batch`. Best-effort;
6
- // a flush failure drops the batch — analytics aren't critical
7
- // telemetry.
8
- //
9
- // Why not one fetch per event: a busy app emitting `$pageview` +
10
- // custom funnel events every nav would saturate the JS thread and
11
- // the host's outbound connection pool. The same batching shape the
12
- // metrics module uses keeps `track()` cheap to call from render
13
- // hooks.
14
- //
15
- // Auto-pageview (`$pageview`) is emitted from `useTraceNavigation`
16
- // in navigation.ts whenever react-navigation swaps the active route.
17
- // Hosts that don't use react-navigation can call
18
- // `sentori.track('$pageview', { route: 'Cart' })` themselves.
19
-
20
- import { addInternalBreadcrumb } from './breadcrumbs';
21
- import { getCurrentUserId } from './capture';
22
- import { getConfig, isInitialized } from './config';
23
- import { sendTrackBatch } from './transport';
24
-
25
- export type TrackProps = Record<string, unknown>;
26
-
27
- export type TrackEvent = {
28
- environment?: string;
29
- name: string;
30
- props?: TrackProps;
31
- release?: string;
32
- route?: string;
33
- sessionId?: string;
34
- ts: string;
35
- userId?: string;
36
- };
37
-
38
- const MAX_BUFFER = 500;
39
- const NAME_MAX = 200;
40
- const PROPS_KEYS_MAX = 40;
41
- const FLUSH_INTERVAL_MS = 30_000;
42
-
43
- let _buf: TrackEvent[] = [];
44
- let _timer: null | ReturnType<typeof setInterval> = null;
45
-
46
- /**
47
- * Record a typed analytics event. Cheap to call from render hooks —
48
- * pushes into a 500-slot ring drained every 30 s (or on overflow) by
49
- * the transport flusher.
50
- *
51
- * Reserved names start with `$` (e.g. `$pageview`) and are emitted by
52
- * the SDK itself; you can still call `track('$pageview', …)` from app
53
- * code to backfill routes the auto-instrumentation missed.
54
- *
55
- * Server caps: name ≤ 200 chars, ≤ 40 prop keys. Calls exceeding the
56
- * cap are dropped client-side (no throw) so app code can fire-and-
57
- * forget without try/catch.
58
- */
59
- export function track(name: string, props?: TrackProps, route?: string): void {
60
- if (!isInitialized()) return;
61
- if (typeof name !== 'string' || name.length === 0 || name.length > NAME_MAX) {
62
- return;
63
- }
64
- if (props && Object.keys(props).length > PROPS_KEYS_MAX) {
65
- return;
66
- }
67
- const config = getConfig();
68
- const ev: TrackEvent = {
69
- name,
70
- props,
71
- release: config?.release,
72
- environment: config?.environment,
73
- route,
74
- ts: new Date().toISOString(),
75
- userId: getCurrentUserId(),
76
- };
77
- _buf.push(ev);
78
- // v2.0 W3 — auto-breadcrumb. When `init.capture.trackAutoBreadcrumb`
79
- // is `true`, push a `{ type: 'track', data: { name, props } }`
80
- // breadcrumb so the customer journey leading up to a later
81
- // `captureException` / `captureMessage` is visible in the dashboard.
82
- // Defaults off — see Config.trackAutoBreadcrumb docstring.
83
- if (config?.trackAutoBreadcrumb === true) {
84
- addInternalBreadcrumb('track', props ? { name, props } : { name });
85
- }
86
- if (_buf.length >= MAX_BUFFER) {
87
- void flushTrack();
88
- }
89
- }
90
-
91
- export async function flushTrack(): Promise<void> {
92
- if (_buf.length === 0) return;
93
- const config = getConfig();
94
- if (!config) return;
95
- const batch = _buf;
96
- _buf = [];
97
- await sendTrackBatch(config.ingestUrl, config.token, batch);
98
- }
99
-
100
- /**
101
- * Start the 30 s flush timer. Called once from `init()`. Idempotent.
102
- * `__resetTrackForTests` is exposed for vitest / bun:test teardown.
103
- */
104
- export function startTrackTimer(): void {
105
- if (_timer !== null) return;
106
- _timer = setInterval(() => {
107
- void flushTrack();
108
- }, FLUSH_INTERVAL_MS);
109
- // Don't keep the process alive solely for this timer.
110
- (_timer as unknown as { unref?: () => void }).unref?.();
111
- }
112
-
113
- export function __peekTrackBuffer(): readonly TrackEvent[] {
114
- return _buf;
115
- }
116
-
117
- export function __resetTrackForTests(): void {
118
- if (_timer !== null) {
119
- clearInterval(_timer);
120
- _timer = null;
121
- }
122
- _buf = [];
123
- }
package/src/trail.ts DELETED
@@ -1,32 +0,0 @@
1
- // Phase 46 — singleton TrailBuffer for the RN SDK.
2
- //
3
- // Kept in its own module so callers (including navigation.ts, which
4
- // is intentionally lightweight) can record steps without pulling in
5
- // capture.ts → handlers/screenshot.ts → react-native. The buffer is
6
- // drained inside capture.ts when an event captures and
7
- // `sessionTrailEnabled` is on.
8
-
9
- import { TrailBuffer, type TrailStep } from '@goliapkg/sentori-core';
10
-
11
- const _trail = new TrailBuffer(30);
12
-
13
- /**
14
- * Phase 46 — record a step into the session-trail buffer. The buffer
15
- * is a fixed-size FIFO (default 30 steps); pushing past capacity
16
- * drops the oldest entry. Steps are only uploaded if
17
- * `init({ capture: { sessionTrail: true } })` is on AND a
18
- * `captureException` follows.
19
- */
20
- export const captureStep = (label: string, opts?: Partial<TrailStep>): void => {
21
- _trail.push({
22
- ts: Date.now(),
23
- label,
24
- ...(opts ?? {}),
25
- });
26
- };
27
-
28
- export const getTrailBuffer = (): TrailBuffer => _trail;
29
-
30
- export const __resetTrailForTests = (): void => {
31
- _trail.clear();
32
- };
@@ -1,176 +0,0 @@
1
- // v1.1 chunk S3 — `sentori.queryTrustScore()` for the host app.
2
- //
3
- // Returns the device's current trust score (0–100, higher = healthier)
4
- // plus the per-kind signal mix that produced it. The host app uses
5
- // this to decide whether to step up authentication, decline a
6
- // purchase, or simply log a soft warning.
7
- //
8
- // Caching:
9
- // L1 — process-memory, ~30 s. Same process should not re-fetch on
10
- // every screen render; the score moves on a "minutes" cadence.
11
- // L2 — install-id-derived AsyncStorage entry, ~5 minutes. Lets the
12
- // host paint a cached score on cold start without waiting for
13
- // the network. Stale entries are still served; the SDK
14
- // re-fetches in the background.
15
- //
16
- // Fail-soft posture: if the network's down or the SDK isn't
17
- // initialised, returns the cached value (if any), else the safe
18
- // default (score = 100). The host should never see a thrown error
19
- // from this call — the score system is supposed to be invisible.
20
-
21
- import { isAnyNativeModuleLinked } from './native-loader';
22
- import { getConfig, isInitialized } from './config';
23
- import { getInstallId } from './install-id';
24
-
25
- const SDK_VERSION = '0.0.0';
26
- const STORAGE_KEY = '@sentori/trust-score';
27
- const L1_TTL_MS = 30_000;
28
- const L2_TTL_MS = 5 * 60_000;
29
-
30
- export type TrustSignal = {
31
- count: number;
32
- kind: string;
33
- weight: number;
34
- };
35
-
36
- export type TrustScore = {
37
- computedAt: string;
38
- installId: string;
39
- score: number;
40
- signals: TrustSignal[];
41
- };
42
-
43
- type CacheEntry = { fetchedAt: number; score: TrustScore };
44
-
45
- type AsyncStorageLike = {
46
- getItem: (key: string) => Promise<null | string>;
47
- setItem: (key: string, value: string) => Promise<void>;
48
- };
49
-
50
- let _l1: null | CacheEntry = null;
51
- let _inflight: null | Promise<TrustScore> = null;
52
-
53
- function loadAsyncStorage(): AsyncStorageLike | null {
54
- if (!isAnyNativeModuleLinked(['RNCAsyncStorage', 'AsyncStorageModule'])) return null;
55
- try {
56
- // eslint-disable-next-line @typescript-eslint/no-require-imports
57
- const mod = require('@react-native-async-storage/async-storage') as {
58
- default?: AsyncStorageLike;
59
- };
60
- return mod.default ?? (mod as unknown as AsyncStorageLike);
61
- } catch {
62
- return null;
63
- }
64
- }
65
-
66
- function safeDefault(installId: string): TrustScore {
67
- return {
68
- computedAt: new Date().toISOString(),
69
- installId,
70
- score: 100,
71
- signals: [],
72
- };
73
- }
74
-
75
- async function readL2(): Promise<null | CacheEntry> {
76
- const storage = loadAsyncStorage();
77
- if (!storage) return null;
78
- try {
79
- const raw = await storage.getItem(STORAGE_KEY);
80
- if (!raw) return null;
81
- const parsed = JSON.parse(raw) as CacheEntry;
82
- if (
83
- typeof parsed?.fetchedAt !== 'number' ||
84
- typeof parsed?.score?.score !== 'number'
85
- ) {
86
- return null;
87
- }
88
- return parsed;
89
- } catch {
90
- return null;
91
- }
92
- }
93
-
94
- async function writeL2(entry: CacheEntry): Promise<void> {
95
- const storage = loadAsyncStorage();
96
- if (!storage) return;
97
- try {
98
- await storage.setItem(STORAGE_KEY, JSON.stringify(entry));
99
- } catch {
100
- // best-effort
101
- }
102
- }
103
-
104
- async function fetchFresh(installId: string): Promise<TrustScore> {
105
- const config = getConfig();
106
- if (!config) return safeDefault(installId);
107
- try {
108
- const resp = await fetch(
109
- `${config.ingestUrl}/v1/security/score?installId=${encodeURIComponent(installId)}`,
110
- {
111
- headers: {
112
- Authorization: `Bearer ${config.token}`,
113
- 'Sentori-Sdk': `react-native/${SDK_VERSION}`,
114
- },
115
- method: 'GET',
116
- }
117
- );
118
- if (!resp.ok) return safeDefault(installId);
119
- const parsed = (await resp.json()) as TrustScore;
120
- return parsed;
121
- } catch {
122
- return safeDefault(installId);
123
- }
124
- }
125
-
126
- /**
127
- * Resolve the device's trust score. Always resolves — never throws,
128
- * never rejects. The two-layer cache means the first call after cold
129
- * start usually serves a < 1 ms result while a background refresh
130
- * keeps the value current.
131
- */
132
- export async function queryTrustScore(): Promise<TrustScore> {
133
- if (!isInitialized()) {
134
- const id = await getInstallId();
135
- return safeDefault(id);
136
- }
137
- // L1 hit
138
- const now = Date.now();
139
- if (_l1 && now - _l1.fetchedAt < L1_TTL_MS) {
140
- return _l1.score;
141
- }
142
- // Coalesce concurrent calls onto the same inflight fetch.
143
- if (_inflight) return _inflight;
144
-
145
- _inflight = (async () => {
146
- try {
147
- const installId = await getInstallId();
148
- // L2 hit — serve immediately, kick off background refresh
149
- const l2 = await readL2();
150
- if (l2 && now - l2.fetchedAt < L2_TTL_MS && l2.score.installId === installId) {
151
- _l1 = l2;
152
- // background refresh (don't block caller)
153
- void (async () => {
154
- const fresh = await fetchFresh(installId);
155
- const entry: CacheEntry = { fetchedAt: Date.now(), score: fresh };
156
- _l1 = entry;
157
- await writeL2(entry);
158
- })();
159
- return l2.score;
160
- }
161
- const fresh = await fetchFresh(installId);
162
- const entry: CacheEntry = { fetchedAt: Date.now(), score: fresh };
163
- _l1 = entry;
164
- await writeL2(entry);
165
- return fresh;
166
- } finally {
167
- _inflight = null;
168
- }
169
- })();
170
- return _inflight;
171
- }
172
-
173
- export function __resetTrustScoreForTests(): void {
174
- _l1 = null;
175
- _inflight = null;
176
- }
package/src/types.ts DELETED
@@ -1,21 +0,0 @@
1
- // Phase 21: wire-format types moved to @goliapkg/sentori-core. Re-
2
- // exported here so existing relative imports keep working.
3
-
4
- export type {
5
- App,
6
- AttachmentKind,
7
- AttachmentMeta,
8
- AttachmentSource,
9
- Breadcrumb,
10
- BreadcrumbType,
11
- CaptureExtras,
12
- Device,
13
- DeviceOS,
14
- Event,
15
- EventKind,
16
- Frame,
17
- Platform,
18
- SentoriError,
19
- Tags,
20
- User,
21
- } from '@goliapkg/sentori-core'
package/src/uuid.ts DELETED
@@ -1,2 +0,0 @@
1
- // Phase 21: moved to @goliapkg/sentori-core.
2
- export { uuidV7 } from '@goliapkg/sentori-core'