@goliapkg/sentori-react-native 3.1.0 → 5.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 (284) hide show
  1. package/android/build.gradle +21 -0
  2. package/android/src/main/java/com/sentori/SentoriCrashHandler.kt +29 -0
  3. package/android/src/test/java/com/sentori/SentoriCrashHandlerTest.kt +7 -2
  4. package/android/src/test/resources/robolectric.properties +10 -0
  5. package/lib/config.d.ts +16 -47
  6. package/lib/config.d.ts.map +1 -1
  7. package/lib/config.js +3 -0
  8. package/lib/config.js.map +1 -1
  9. package/lib/device.d.ts +5 -0
  10. package/lib/device.d.ts.map +1 -0
  11. package/lib/device.js +29 -0
  12. package/lib/device.js.map +1 -0
  13. package/lib/emit-hooks.d.ts +7 -0
  14. package/lib/emit-hooks.d.ts.map +1 -0
  15. package/lib/emit-hooks.js +24 -0
  16. package/lib/emit-hooks.js.map +1 -0
  17. package/lib/error-boundary.d.ts.map +1 -1
  18. package/lib/error-boundary.js +1 -1
  19. package/lib/error-boundary.js.map +1 -1
  20. package/lib/feature-flags.d.ts.map +1 -1
  21. package/lib/handlers/dev-symbolicate.d.ts +1 -1
  22. package/lib/handlers/dev-symbolicate.d.ts.map +1 -1
  23. package/lib/handlers/dev-symbolicate.js +2 -0
  24. package/lib/handlers/dev-symbolicate.js.map +1 -1
  25. package/lib/handlers/global.js +1 -1
  26. package/lib/handlers/global.js.map +1 -1
  27. package/lib/handlers/lifecycle.js +3 -3
  28. package/lib/handlers/lifecycle.js.map +1 -1
  29. package/lib/handlers/network.d.ts +2 -2
  30. package/lib/handlers/network.d.ts.map +1 -1
  31. package/lib/handlers/network.js +69 -187
  32. package/lib/handlers/network.js.map +1 -1
  33. package/lib/handlers/promise.js +1 -1
  34. package/lib/handlers/promise.js.map +1 -1
  35. package/lib/handlers/screenshot.d.ts.map +1 -1
  36. package/lib/handlers/screenshot.js +3 -12
  37. package/lib/handlers/screenshot.js.map +1 -1
  38. package/lib/index.d.ts +31 -109
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +51 -103
  41. package/lib/index.js.map +1 -1
  42. package/lib/init.d.ts +3 -150
  43. package/lib/init.d.ts.map +1 -1
  44. package/lib/init.js +88 -261
  45. package/lib/init.js.map +1 -1
  46. package/lib/long-task-monitor.d.ts +1 -7
  47. package/lib/long-task-monitor.d.ts.map +1 -1
  48. package/lib/long-task-monitor.js +37 -58
  49. package/lib/long-task-monitor.js.map +1 -1
  50. package/lib/mobile-vitals.d.ts +3 -31
  51. package/lib/mobile-vitals.d.ts.map +1 -1
  52. package/lib/mobile-vitals.js +22 -61
  53. package/lib/mobile-vitals.js.map +1 -1
  54. package/lib/native-pending.d.ts +3 -0
  55. package/lib/native-pending.d.ts.map +1 -0
  56. package/lib/native-pending.js +64 -0
  57. package/lib/native-pending.js.map +1 -0
  58. package/lib/navigation.d.ts +3 -17
  59. package/lib/navigation.d.ts.map +1 -1
  60. package/lib/navigation.js +32 -133
  61. package/lib/navigation.js.map +1 -1
  62. package/lib/netinfo.d.ts +1 -1
  63. package/lib/netinfo.d.ts.map +1 -1
  64. package/lib/netinfo.js +2 -2
  65. package/lib/netinfo.js.map +1 -1
  66. package/lib/push.d.ts.map +1 -1
  67. package/lib/push.js +2 -4
  68. package/lib/push.js.map +1 -1
  69. package/lib/rage-tap.d.ts.map +1 -1
  70. package/lib/rage-tap.js +28 -23
  71. package/lib/rage-tap.js.map +1 -1
  72. package/lib/replay.d.ts.map +1 -1
  73. package/lib/replay.js +3 -24
  74. package/lib/replay.js.map +1 -1
  75. package/lib/scope.d.ts +7 -0
  76. package/lib/scope.d.ts.map +1 -0
  77. package/lib/scope.js +41 -0
  78. package/lib/scope.js.map +1 -0
  79. package/lib/transport.d.ts +19 -92
  80. package/lib/transport.d.ts.map +1 -1
  81. package/lib/transport.js +75 -288
  82. package/lib/transport.js.map +1 -1
  83. package/lib/verbs.d.ts +16 -0
  84. package/lib/verbs.d.ts.map +1 -0
  85. package/lib/verbs.js +153 -0
  86. package/lib/verbs.js.map +1 -0
  87. package/package.json +5 -5
  88. package/src/__tests__/iron-rule.test.ts +128 -0
  89. package/src/__tests__/screenshot.test.ts +0 -2
  90. package/src/__tests__/transport.test.ts +66 -213
  91. package/src/__tests__/verbs.test.ts +91 -0
  92. package/src/config.ts +19 -47
  93. package/src/device.ts +36 -0
  94. package/src/emit-hooks.ts +30 -0
  95. package/src/error-boundary.tsx +1 -1
  96. package/src/handlers/dev-symbolicate.ts +2 -1
  97. package/src/handlers/global.ts +1 -1
  98. package/src/handlers/lifecycle.ts +3 -3
  99. package/src/handlers/network.ts +95 -211
  100. package/src/handlers/promise.ts +1 -1
  101. package/src/handlers/screenshot.ts +3 -11
  102. package/src/index.ts +81 -215
  103. package/src/init.ts +94 -446
  104. package/src/long-task-monitor.ts +42 -64
  105. package/src/mobile-vitals.ts +22 -82
  106. package/src/native-pending.ts +92 -0
  107. package/src/navigation.ts +34 -142
  108. package/src/netinfo.ts +3 -3
  109. package/src/push.ts +2 -5
  110. package/src/rage-tap.tsx +29 -26
  111. package/src/replay.ts +3 -20
  112. package/src/scope.ts +50 -0
  113. package/src/transport.ts +84 -371
  114. package/src/verbs.ts +198 -0
  115. package/lib/breadcrumbs.d.ts +0 -18
  116. package/lib/breadcrumbs.d.ts.map +0 -1
  117. package/lib/breadcrumbs.js +0 -42
  118. package/lib/breadcrumbs.js.map +0 -1
  119. package/lib/bundle-info.d.ts +0 -12
  120. package/lib/bundle-info.d.ts.map +0 -1
  121. package/lib/bundle-info.js +0 -73
  122. package/lib/bundle-info.js.map +0 -1
  123. package/lib/capture.d.ts +0 -140
  124. package/lib/capture.d.ts.map +0 -1
  125. package/lib/capture.js +0 -511
  126. package/lib/capture.js.map +0 -1
  127. package/lib/compat/sentry.d.ts +0 -126
  128. package/lib/compat/sentry.d.ts.map +0 -1
  129. package/lib/compat/sentry.js +0 -332
  130. package/lib/compat/sentry.js.map +0 -1
  131. package/lib/control-channel.d.ts +0 -6
  132. package/lib/control-channel.d.ts.map +0 -1
  133. package/lib/control-channel.js +0 -96
  134. package/lib/control-channel.js.map +0 -1
  135. package/lib/expo-compat.d.ts +0 -270
  136. package/lib/expo-compat.d.ts.map +0 -1
  137. package/lib/expo-compat.js +0 -500
  138. package/lib/expo-compat.js.map +0 -1
  139. package/lib/feedback-widget.d.ts +0 -35
  140. package/lib/feedback-widget.d.ts.map +0 -1
  141. package/lib/feedback-widget.js +0 -193
  142. package/lib/feedback-widget.js.map +0 -1
  143. package/lib/feedback.d.ts +0 -2
  144. package/lib/feedback.d.ts.map +0 -1
  145. package/lib/feedback.js +0 -17
  146. package/lib/feedback.js.map +0 -1
  147. package/lib/heartbeat.d.ts +0 -9
  148. package/lib/heartbeat.d.ts.map +0 -1
  149. package/lib/heartbeat.js +0 -138
  150. package/lib/heartbeat.js.map +0 -1
  151. package/lib/index.js.bak +0 -64
  152. package/lib/install-id.d.ts +0 -17
  153. package/lib/install-id.d.ts.map +0 -1
  154. package/lib/install-id.js +0 -125
  155. package/lib/install-id.js.map +0 -1
  156. package/lib/lifecycle.d.ts +0 -28
  157. package/lib/lifecycle.d.ts.map +0 -1
  158. package/lib/lifecycle.js +0 -73
  159. package/lib/lifecycle.js.map +0 -1
  160. package/lib/mask.d.ts +0 -16
  161. package/lib/mask.d.ts.map +0 -1
  162. package/lib/mask.js +0 -36
  163. package/lib/mask.js.map +0 -1
  164. package/lib/measure.d.ts +0 -4
  165. package/lib/measure.d.ts.map +0 -1
  166. package/lib/measure.js +0 -25
  167. package/lib/measure.js.map +0 -1
  168. package/lib/metrics.d.ts +0 -24
  169. package/lib/metrics.d.ts.map +0 -1
  170. package/lib/metrics.js +0 -81
  171. package/lib/metrics.js.map +0 -1
  172. package/lib/pre-crash-sentinel.d.ts +0 -12
  173. package/lib/pre-crash-sentinel.d.ts.map +0 -1
  174. package/lib/pre-crash-sentinel.js +0 -116
  175. package/lib/pre-crash-sentinel.js.map +0 -1
  176. package/lib/report-security.d.ts +0 -40
  177. package/lib/report-security.d.ts.map +0 -1
  178. package/lib/report-security.js +0 -159
  179. package/lib/report-security.js.map +0 -1
  180. package/lib/runtime-metrics-fps.d.ts +0 -19
  181. package/lib/runtime-metrics-fps.d.ts.map +0 -1
  182. package/lib/runtime-metrics-fps.js +0 -128
  183. package/lib/runtime-metrics-fps.js.map +0 -1
  184. package/lib/runtime-metrics-heap.d.ts +0 -13
  185. package/lib/runtime-metrics-heap.d.ts.map +0 -1
  186. package/lib/runtime-metrics-heap.js +0 -67
  187. package/lib/runtime-metrics-heap.js.map +0 -1
  188. package/lib/runtime-metrics-network.d.ts +0 -23
  189. package/lib/runtime-metrics-network.d.ts.map +0 -1
  190. package/lib/runtime-metrics-network.js +0 -99
  191. package/lib/runtime-metrics-network.js.map +0 -1
  192. package/lib/runtime-metrics.d.ts +0 -43
  193. package/lib/runtime-metrics.d.ts.map +0 -1
  194. package/lib/runtime-metrics.js +0 -115
  195. package/lib/runtime-metrics.js.map +0 -1
  196. package/lib/sample-profiler.d.ts +0 -21
  197. package/lib/sample-profiler.d.ts.map +0 -1
  198. package/lib/sample-profiler.js +0 -152
  199. package/lib/sample-profiler.js.map +0 -1
  200. package/lib/sentinel-context.d.ts +0 -4
  201. package/lib/sentinel-context.d.ts.map +0 -1
  202. package/lib/sentinel-context.js +0 -52
  203. package/lib/sentinel-context.js.map +0 -1
  204. package/lib/session-tracker.d.ts +0 -6
  205. package/lib/session-tracker.d.ts.map +0 -1
  206. package/lib/session-tracker.js +0 -50
  207. package/lib/session-tracker.js.map +0 -1
  208. package/lib/stack.d.ts +0 -3
  209. package/lib/stack.d.ts.map +0 -1
  210. package/lib/stack.js +0 -7
  211. package/lib/stack.js.map +0 -1
  212. package/lib/state-snapshots.d.ts +0 -33
  213. package/lib/state-snapshots.d.ts.map +0 -1
  214. package/lib/state-snapshots.js +0 -109
  215. package/lib/state-snapshots.js.map +0 -1
  216. package/lib/track.d.ts +0 -34
  217. package/lib/track.d.ts.map +0 -1
  218. package/lib/track.js +0 -107
  219. package/lib/track.js.map +0 -1
  220. package/lib/trail.d.ts +0 -12
  221. package/lib/trail.d.ts.map +0 -1
  222. package/lib/trail.js +0 -28
  223. package/lib/trail.js.map +0 -1
  224. package/lib/trust-score.d.ts +0 -20
  225. package/lib/trust-score.d.ts.map +0 -1
  226. package/lib/trust-score.js +0 -151
  227. package/lib/trust-score.js.map +0 -1
  228. package/lib/types.d.ts +0 -2
  229. package/lib/types.d.ts.map +0 -1
  230. package/lib/types.js +0 -4
  231. package/lib/types.js.map +0 -1
  232. package/lib/uuid.d.ts +0 -2
  233. package/lib/uuid.d.ts.map +0 -1
  234. package/lib/uuid.js +0 -3
  235. package/lib/uuid.js.map +0 -1
  236. package/src/__tests__/before-send.test.ts +0 -72
  237. package/src/__tests__/breadcrumbs.test.ts +0 -44
  238. package/src/__tests__/capture-replay.test.ts +0 -150
  239. package/src/__tests__/compat-sentry.test.ts +0 -121
  240. package/src/__tests__/control-channel.test.ts +0 -111
  241. package/src/__tests__/install-id.test.ts +0 -60
  242. package/src/__tests__/long-task-monitor.test.ts +0 -59
  243. package/src/__tests__/measure.test.ts +0 -45
  244. package/src/__tests__/navigation.test.ts +0 -175
  245. package/src/__tests__/push.test.ts +0 -238
  246. package/src/__tests__/report-security.test.ts +0 -106
  247. package/src/__tests__/runtime-metrics-instruments.test.ts +0 -109
  248. package/src/__tests__/runtime-metrics-network.test.ts +0 -78
  249. package/src/__tests__/sample-profiler.test.ts +0 -59
  250. package/src/__tests__/stack.test.ts +0 -45
  251. package/src/__tests__/state-snapshots.test.ts +0 -119
  252. package/src/__tests__/tracing.test.ts +0 -201
  253. package/src/__tests__/track.test.ts +0 -91
  254. package/src/__tests__/uuid.test.ts +0 -41
  255. package/src/breadcrumbs.ts +0 -57
  256. package/src/bundle-info.ts +0 -95
  257. package/src/capture.ts +0 -660
  258. package/src/compat/sentry.ts +0 -490
  259. package/src/control-channel.ts +0 -98
  260. package/src/expo-compat.ts +0 -698
  261. package/src/feedback-widget.tsx +0 -316
  262. package/src/feedback.ts +0 -21
  263. package/src/heartbeat.ts +0 -157
  264. package/src/install-id.ts +0 -146
  265. package/src/lifecycle.ts +0 -76
  266. package/src/mask.ts +0 -41
  267. package/src/measure.ts +0 -28
  268. package/src/metrics.ts +0 -94
  269. package/src/pre-crash-sentinel.ts +0 -140
  270. package/src/report-security.ts +0 -165
  271. package/src/runtime-metrics-fps.ts +0 -137
  272. package/src/runtime-metrics-heap.ts +0 -78
  273. package/src/runtime-metrics-network.ts +0 -103
  274. package/src/runtime-metrics.ts +0 -122
  275. package/src/sample-profiler.ts +0 -169
  276. package/src/sentinel-context.ts +0 -60
  277. package/src/session-tracker.ts +0 -53
  278. package/src/stack.ts +0 -10
  279. package/src/state-snapshots.ts +0 -133
  280. package/src/track.ts +0 -123
  281. package/src/trail.ts +0 -32
  282. package/src/trust-score.ts +0 -176
  283. package/src/types.ts +0 -21
  284. package/src/uuid.ts +0 -2
@@ -0,0 +1,91 @@
1
+ // The five verbs: synchronous, never throw, id out, correct wire.
2
+
3
+ import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
4
+
5
+ import { clearSignals } from '@goliapkg/sentori-core';
6
+
7
+ import { __resetForTests as resetConfig, setConfig } from '../config';
8
+ import { __resetForTests as resetScope } from '../scope';
9
+ import {
10
+ __peekAssertStats,
11
+ __peekQueue,
12
+ __resetForTests as resetTransport,
13
+ startTransport,
14
+ } from '../transport';
15
+ import { verbs } from '../verbs';
16
+
17
+ const baseConfig = {
18
+ token: 'st_test',
19
+ ingestUrl: 'http://localhost:18080',
20
+ release: 'app@1.0.0',
21
+ environment: 'test',
22
+ enabled: true,
23
+ detect: { rageTap: true, longFreeze: true, slowColdStart: true, slowApi: false },
24
+ replaySeconds: 30,
25
+ };
26
+
27
+ describe('the five verbs', () => {
28
+ beforeEach(() => {
29
+ resetTransport();
30
+ resetConfig();
31
+ resetScope();
32
+ clearSignals();
33
+ setConfig(baseConfig);
34
+ startTransport();
35
+ });
36
+ afterEach(() => {
37
+ resetTransport();
38
+ resetConfig();
39
+ resetScope();
40
+ clearSignals();
41
+ });
42
+
43
+ it('error coerces anything and enqueues with a stack', () => {
44
+ const id = verbs.error(new Error('boom'));
45
+ expect(typeof id).toBe('string');
46
+ const q = __peekQueue();
47
+ expect(q.length).toBe(1);
48
+ expect(q[0]?.kind).toBe('error');
49
+ expect(q[0]?.payload.error?.type).toBe('Error');
50
+ expect(q[0]?.payload.error?.message).toBe('boom');
51
+ });
52
+
53
+ it('error serializes Error instances found in data (error-in-data)', () => {
54
+ verbs.warn('pay.retry', { attempt: 2, error: new TypeError('nope') });
55
+ const q = __peekQueue();
56
+ const data = q[0]?.payload.data as { error?: { type?: string } };
57
+ expect(data.error?.type).toBe('TypeError');
58
+ });
59
+
60
+ it('warn carries name; trace quiet stays out of the queue', () => {
61
+ verbs.warn('rage_tap');
62
+ expect(__peekQueue().length).toBe(1);
63
+ verbs.trace('checkout.start', undefined, { quiet: true });
64
+ expect(__peekQueue().length).toBe(1); // unchanged
65
+ verbs.trace('checkout.start');
66
+ expect(__peekQueue().length).toBe(2);
67
+ });
68
+
69
+ it('assert pass aggregates without an event; fail is an event', () => {
70
+ verbs.assert('total-positive', true);
71
+ expect(__peekQueue().length).toBe(0);
72
+ expect(__peekAssertStats()[0]?.passDelta).toBe(1);
73
+ verbs.assert('total-positive', false);
74
+ expect(__peekQueue().length).toBe(1);
75
+ expect(__peekQueue()[0]?.kind).toBe('assert');
76
+ });
77
+
78
+ it('probe never throws and reports the ref as name', () => {
79
+ const id = verbs.probe('SENT-123');
80
+ expect(typeof id).toBe('string');
81
+ expect(__peekQueue()[0]?.kind).toBe('probe');
82
+ expect(__peekQueue()[0]?.name).toBe('SENT-123');
83
+ });
84
+
85
+ it('before init everything is a silent no-op that still returns an id', () => {
86
+ resetConfig();
87
+ const id = verbs.error(new Error('x'));
88
+ expect(typeof id).toBe('string');
89
+ expect(__peekQueue().length).toBe(0);
90
+ });
91
+ });
package/src/config.ts CHANGED
@@ -1,58 +1,30 @@
1
- import type { BeforeSendHook, LogLevel, ReadyInfo } from '@goliapkg/sentori-core';
1
+ // SDK-internal runtime config, set once by init(). Everything else
2
+ // reads through getConfig() and treats null as "not initialized →
3
+ // every verb is a no-op" (the failure-isolation iron rule).
2
4
 
3
- /**
4
- * v2.3 — `ReadyInfo` is shared across SDKs via `@goliapkg/sentori-core`
5
- * so a host that switches from web to RN reads the same shape. The RN
6
- * SDK always populates `native` + `coldStartMs`; the core type marks
7
- * both optional for the web SDK's benefit (web has no native module).
8
- */
9
- export type { ReadyInfo };
5
+ import type { LogLevel, WireEvent } from '@goliapkg/sentori-core';
10
6
 
11
7
  export type Config = {
12
8
  token: string;
9
+ ingestUrl: string;
13
10
  release: string;
14
11
  environment: string;
15
- ingestUrl: string;
16
12
  enabled: boolean;
17
- /** Phase 42 sub-D.07: opt-in screenshot capture on captureException. */
18
- screenshotsEnabled: boolean;
19
- /** Phase 44 sub-B: per-event-class sampling rates 0..1.
20
- * `null` = keep everything (default). */
21
- errorSampleRate: null | number;
22
- traceSampleRate: null | number;
23
- /** v2.0 — sampling rate for `kind: 'message'` events emitted via
24
- * `captureMessage`. `null` = keep all (default). */
25
- messageSampleRate: null | number;
26
- /** Phase 46: when true, every `captureException` seals the
27
- * session-trail buffer and uploads it as a `sessionTrail`
28
- * attachment. Defaults to false. */
29
- sessionTrailEnabled: boolean;
30
- /** v2.0 W3 — when true, every `track(name, props)` call also
31
- * pushes a `{ type: 'track', data: { name, props } }` breadcrumb
32
- * so a subsequent capture carries the customer journey. Defaults
33
- * to false to preserve v1 customer breadcrumb shape on upgrade. */
34
- trackAutoBreadcrumb: boolean;
35
- /** v2.3 — Sentori console output gate.
36
- *
37
- * Default `warn`: SDK is silent on host's console unless
38
- * something is genuinely broken (transport sustained failure,
39
- * native module not found, internal SDK exception). No
40
- * per-tick / per-init / per-breadcrumb noise.
41
- *
42
- * Set `'silent'` for absolute silence (e.g. CI smoke runs);
43
- * set `'info'` or `'debug'` when debugging Sentori itself. */
13
+ /** Warn-scenario auto-detection switches (conservative defaults). */
14
+ detect: {
15
+ rageTap: boolean;
16
+ longFreeze: boolean;
17
+ slowColdStart: boolean;
18
+ slowApi: boolean;
19
+ };
20
+ /** B-type replay rolling buffer, seconds. 0 disables. */
21
+ replaySeconds: number;
22
+ /** Sentori console output gate. Default `warn`: silent on the
23
+ * host's console unless something is genuinely broken. */
44
24
  logLevel?: LogLevel;
45
- /** v2.3 — fires once after init completes. Use this to know the
46
- * SDK is live instead of scanning the console. `info` carries
47
- * the native-module bind status + cold-start timing. Host
48
- * wraps any host-side logging here. */
49
- onReady?: (info: ReadyInfo) => void;
50
- /** v2.3 — host-side mutate-or-drop hook called once per event
51
- * just before transport enqueue. Return the event to send it,
52
- * `null` to drop. Sync only. If the hook throws or returns a
53
- * non-event, SDK falls back to the un-mutated event and emits
54
- * one one-shot warn. */
55
- beforeSend?: BeforeSendHook;
25
+ /** Host-side mutate-or-drop hook, sync only. Throw / bad return →
26
+ * the un-mutated event ships and one warn is emitted. */
27
+ beforeSend?: (event: WireEvent) => WireEvent | null;
56
28
  };
57
29
 
58
30
  let _config: Config | null = null;
package/src/device.ts ADDED
@@ -0,0 +1,36 @@
1
+ // Synchronous device snapshot — what the JS layer can know without
2
+ // crossing the bridge. The native module enriches asynchronously via
3
+ // setNativeDeviceInfo at init; until then the JS-visible subset
4
+ // ships (an event with a thin device beats a delayed event).
5
+
6
+ import type { Device } from '@goliapkg/sentori-core';
7
+
8
+ let _native: Partial<Device> | null = null;
9
+
10
+ export const setNativeDeviceInfo = (info: Partial<Device>): void => {
11
+ _native = info;
12
+ };
13
+
14
+ export const collectDevice = (): Device | undefined => {
15
+ let base: Device | undefined;
16
+ try {
17
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
18
+ const RN = require('react-native') as {
19
+ Platform?: { OS?: string; Version?: number | string };
20
+ Dimensions?: { get(dim: string): { width: number; height: number; scale: number } };
21
+ };
22
+ const os = RN.Platform?.OS ?? 'unknown';
23
+ base = { os, osVersion: RN.Platform?.Version?.toString() };
24
+ const win = RN.Dimensions?.get('window');
25
+ if (win) {
26
+ base.screen = { width: win.width, height: win.height, scale: win.scale };
27
+ }
28
+ } catch {
29
+ return _native ? ({ os: 'unknown', ..._native } as Device) : undefined;
30
+ }
31
+ return _native ? { ...base, ..._native } : base;
32
+ };
33
+
34
+ export const __resetForTests = (): void => {
35
+ _native = null;
36
+ };
@@ -0,0 +1,30 @@
1
+ // Post-emit hooks — how B-type replay (and future reactions) learn
2
+ // "an event just went out" without the verbs knowing about them.
3
+ //
4
+ // Hooks run inside their own try/catch: a broken subscriber must
5
+ // never take the emit path down with it (failure isolation).
6
+
7
+ import type { WireEvent } from '@goliapkg/sentori-core';
8
+ import { reportInternal } from '@goliapkg/sentori-core';
9
+
10
+ type EmitHook = (event: WireEvent) => void;
11
+
12
+ const hooks: EmitHook[] = [];
13
+
14
+ export const registerEmitHook = (hook: EmitHook): void => {
15
+ hooks.push(hook);
16
+ };
17
+
18
+ export const onEventEmitted = (event: WireEvent): void => {
19
+ for (const hook of hooks) {
20
+ try {
21
+ hook(event);
22
+ } catch (e) {
23
+ reportInternal('emit-hook', e);
24
+ }
25
+ }
26
+ };
27
+
28
+ export const __resetForTests = (): void => {
29
+ hooks.length = 0;
30
+ };
@@ -1,6 +1,6 @@
1
1
  import React, { Component, type ErrorInfo, type ReactNode } from 'react';
2
2
 
3
- import { captureError } from './capture';
3
+ import { error as captureError } from "./verbs";
4
4
 
5
5
  export type ErrorBoundaryProps = {
6
6
  fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
@@ -7,7 +7,7 @@
7
7
  // Best-effort and dev-only: any failure (Metro not running, timeout,
8
8
  // bad response) leaves the stack untouched. Never throws.
9
9
 
10
- import type { Frame, SentoriError } from '../types';
10
+ import type { Frame, SentoriError } from '@goliapkg/sentori-core';
11
11
 
12
12
  const TIMEOUT_MS = 2000;
13
13
 
@@ -132,6 +132,7 @@ export async function symbolicateErrorViaMetro(
132
132
  err: SentoriError,
133
133
  opts: { url?: string } = {},
134
134
  ): Promise<void> {
135
+ if (!err.stack) return;
135
136
  const sym = await symbolicateStackViaMetro(err.stack, opts);
136
137
  if (sym) err.stack = sym;
137
138
  if (err.cause) await symbolicateErrorViaMetro(err.cause, opts);
@@ -1,4 +1,4 @@
1
- import { captureError } from '../capture';
1
+ import { error as captureError } from '../verbs';
2
2
 
3
3
  type ErrorUtilsHandler = (error: Error, isFatal?: boolean) => void;
4
4
 
@@ -12,7 +12,7 @@
12
12
  * twice". Sentry historically did the opposite (treat inactive as
13
13
  * still alive), but that lets a swiped-away session never end.
14
14
  */
15
- import { endSession, startSession } from '../session-tracker';
15
+ import { pushSignal } from '@goliapkg/sentori-core';
16
16
 
17
17
  let _installed = false;
18
18
  let _subscription: { remove: () => void } | null = null;
@@ -40,9 +40,9 @@ export const installLifecycleHandler = (): void => {
40
40
 
41
41
  _subscription = AppState.addEventListener('change', (state) => {
42
42
  if (state === 'active') {
43
- startSession();
43
+ pushSignal('lifecycle', { state: 'active' });
44
44
  } else if (state === 'background' || state === 'inactive') {
45
- endSession();
45
+ pushSignal('lifecycle', { state: 'background' });
46
46
  }
47
47
  });
48
48
  };