@goliapkg/sentori-react-native 5.6.0 → 5.7.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.
package/README.md CHANGED
@@ -5,11 +5,24 @@ self-hosted crash + warning monitor for mobile apps. JS layer +
5
5
  iOS Swift + Android Kotlin native, distributed as an Expo module
6
6
  (works on bare RN too).
7
7
 
8
- Eight verbs are the whole API. Every one is synchronous, returns
9
- immediately, and can never throw into your app.
8
+ Eight verbs are the whole API.
10
9
 
11
10
  Upgrading from 4.x? See [MIGRATION.md](./MIGRATION.md).
12
11
 
12
+ ## The zero-cost contract
13
+
14
+ Sentori must only ever be a free upgrade for your app:
15
+
16
+ - **Every call is synchronous, O(1), and can never throw.** Not on
17
+ garbage input, not when the network is down, not when the server
18
+ is gone. You never need a try/catch around a Sentori call.
19
+ - `init()` failure (bad token, missing URL) degrades every verb to
20
+ a no-op with one console.warn — never a crash, never a red box.
21
+ - Nothing leaves the device until an error/warn actually fires;
22
+ then one batched request carries the event with its context.
23
+ - Buffers (signal ring, replay rings, offline queue) are all
24
+ hard-bounded.
25
+
13
26
  ## Install
14
27
 
15
28
  ```sh
@@ -26,11 +39,15 @@ sentori.init({
26
39
  token: 'st_…', // ingest token, Settings → Tokens
27
40
  ingestUrl: 'https://sentori.example.com',
28
41
  release: 'my-app@1.2.3',
29
- environment: 'prod',
42
+ environment: 'production', // the DEPLOYMENT environment
43
+ replayScreens: true, // opt-in visual replay (v5.1)
44
+ backendHealthUrl: 'https://api.example.com/healthz', // v5.2, see below
30
45
  })
31
46
 
32
47
  sentori.user({ id, email, name }) // drives breadth × depth stats
33
- sentori.context({ tenant: 'acme' }) // ambient tags on every event
48
+ sentori.context({ build: 'release', tenant: 'acme' }) // ambient tags;
49
+ // every key becomes a queue
50
+ // slicing dimension on the board
34
51
 
35
52
  sentori.error(new Error('boom')) // what broke
36
53
  sentori.warn('pay.gateway-retry', data) // where users hurt
@@ -45,14 +62,59 @@ Auto-wired (no configuration):
45
62
  - iOS `NSException` + Android uncaught-exception handlers
46
63
  - Warn scenario detectors: rage taps, long freezes, slow cold start
47
64
  (slow API stays opt-in) — tune with `init({ detect })`
48
- - Signal ring: recent taps, navigation, traces ride along on every
49
- error/warn as the "what the user was doing" timeline
65
+ - Signal ring: the last 60 s of taps (with coordinates), navigation,
66
+ http and traces ride along on every error/warn as the "what the
67
+ user was doing" timeline
50
68
  - B-type replay: rolling wireframe buffer, shipped only when an
51
- error/warn actually fires (`init({ replaySeconds })`)
69
+ error/warn actually fires (`init({ replaySeconds })`); opt-in
70
+ pixel replay via `replayScreens: true`, with native-side masking
71
+ (`registerMaskQuery`) so tagged views never exist in any frame
72
+ - Cold-start measurement with a pre-warm guard: processes started
73
+ in the background (FCM, JobScheduler, iOS prewarming) are flagged
74
+ and never counted as slow starts
52
75
 
53
76
  Identity is hashed on-device with a salted hash — the server never
54
77
  sees the raw email.
55
78
 
79
+ ## Launch measurement (v5.6)
80
+
81
+ One number ending at `init()` cannot represent user-perceived
82
+ launch. Stage it instead:
83
+
84
+ ```tsx
85
+ sentori.launch.mark('bootstrap') // optional waypoints, anywhere
86
+ sentori.launch.mark('first-tree')
87
+ sentori.launch.complete() // when YOUR app counts as usable
88
+ ```
89
+
90
+ `complete()` emits one `app.launch` trace with segment durations
91
+ (native span → each waypoint → complete). The dashboard's
92
+ Instruments page aggregates p50/p90/p95 per release from it. Apps
93
+ that never call the marks keep the plain cold-start behaviour.
94
+
95
+ ## Custom breadcrumbs (v5.5)
96
+
97
+ Feed your own context into the signal ring — same fire-and-forget
98
+ guarantees as the verbs:
99
+
100
+ ```tsx
101
+ import { pushSignal } from '@goliapkg/sentori-react-native'
102
+
103
+ // in your API interceptor — the one place that knows which
104
+ // requests matter (Sentori deliberately does not patch fetch/XHR):
105
+ pushSignal('http', { method, url, status, ms }) // status 0 = no response
106
+ ```
107
+
108
+ `http` entries render as request lines on the case timeline; any
109
+ other kind renders with its data as key=value pairs.
110
+
111
+ ## Backend availability (v5.2)
112
+
113
+ `init({ backendHealthUrl })` — the URL rides along with event
114
+ batches (the app itself never pings anything); the Sentori server
115
+ probes it once a minute and shows uptime + latency on the project
116
+ card.
117
+
56
118
  ## React extras
57
119
 
58
120
  ```tsx
@@ -60,14 +122,16 @@ import {
60
122
  ErrorBoundary, // React idiom for the error verb
61
123
  RageTapCapture, // wrap your root to feed the rage-tap detector
62
124
  useTraceNavigation, // pass your react-navigation ref
125
+ registerMaskQuery, // nativeIDs to black out in every captured frame
63
126
  } from '@goliapkg/sentori-react-native'
64
127
  ```
65
128
 
66
129
  ## Build pipeline
67
130
 
68
- `@goliapkg/sentori-cli` uploads sourcemaps (failures never block a
69
- release — friendly notice, exit 0) and registers `probe()`
70
- tripwires per release. See MIGRATION.md §6.
131
+ `@goliapkg/sentori-cli` uploads sourcemaps, dSYMs, Proguard maps
132
+ and native source bundles (failures never block a release —
133
+ friendly notice, exit 0) and registers `probe()` tripwires per
134
+ release. See MIGRATION.md §6.
71
135
 
72
136
  ## License
73
137
 
package/lib/init.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAmBzD,eAAO,MAAM,IAAI,0CAwFf,CAAC;AAGH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAwBzD,eAAO,MAAM,IAAI,0CAqGf,CAAC;AAGH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
package/lib/init.js CHANGED
@@ -15,7 +15,7 @@ import { armLaunch } from './launch';
15
15
  import { markNativeJsBridgeReady, setNativeConfig } from './native';
16
16
  import { shipNativePending } from './native-pending';
17
17
  import { drainReplay, startReplay } from './replay';
18
- import { drainScreenReplay, startScreenReplay } from './replay-screens';
18
+ import { drainScreenReplay, screenReplayArmed, screenReplayCaptured, startScreenReplay, } from './replay-screens';
19
19
  import { drainOfflineQueue, queueAttachment, startTransport } from './transport';
20
20
  let _initialized = false;
21
21
  export const init = safeFn('init', (config) => {
@@ -86,6 +86,20 @@ export const init = safeFn('init', (config) => {
86
86
  mediaType: 'application/x-sentori-screens',
87
87
  });
88
88
  }
89
+ else if (screenReplayArmed()) {
90
+ // Asked for, produced nothing. Without this the dashboard
91
+ // cannot tell that from "never enabled", and it was telling
92
+ // readers to switch on a setting that was already on. A
93
+ // handful of bytes on an event already going out — no extra
94
+ // request, and nothing at all when the feature is off.
95
+ event.payload = {
96
+ ...(event.payload ?? {}),
97
+ replay: {
98
+ screens: 'empty',
99
+ captured: screenReplayCaptured(),
100
+ },
101
+ };
102
+ }
89
103
  });
90
104
  }
91
105
  // Native side: hand over release/environment for the crash-file
package/lib/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,17 @@ export declare const startScreenReplay: (windowSeconds: number) => void;
8
8
  * reads "-42.5s → 0s"). Returns null when empty. The ring is NOT
9
9
  * cleared — a second error two seconds later should still see
10
10
  * the minute before it. */
11
+ /** Has the ring been asked to run this session? Distinguishes "the
12
+ * host never turned pixel replay on" from "it is on and produced
13
+ * nothing", which look identical from the server and which the
14
+ * dashboard was guessing between — it told readers to enable a
15
+ * setting that may already be enabled. */
16
+ export declare const screenReplayArmed: () => boolean;
17
+ /** Frames captured since start. Zero while armed means every tick
18
+ * returned nothing: an older native binary, or a capture that keeps
19
+ * failing. Either way the host should hear it from the event rather
20
+ * than from a console line on a device nobody is holding. */
21
+ export declare const screenReplayCaptured: () => number;
11
22
  export declare const drainScreenReplay: () => null | string;
12
23
  export declare const __resetForTests: () => void;
13
24
  export declare const __setCaptureForTests: (fn: CaptureFn) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"replay-screens.d.ts","sourceRoot":"","sources":["../src/replay-screens.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEpD,KAAK,SAAS,GAAG,OAAO,wBAAwB,CAAC;AA6BjD;mCACmC;AACnC,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,IAOzD,CAAC;AAkBF;;;;4BAI4B;AAC5B,eAAO,MAAM,iBAAiB,QAAO,IAAI,GAAG,MAe3C,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAOlC,CAAC;AAEF,eAAO,MAAM,oBAAoB,OAAQ,SAAS,KAAG,IAEpD,CAAC"}
1
+ {"version":3,"file":"replay-screens.d.ts","sourceRoot":"","sources":["../src/replay-screens.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEpD,KAAK,SAAS,GAAG,OAAO,wBAAwB,CAAC;AA8BjD;mCACmC;AACnC,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,IAOzD,CAAC;AAmBF;;;;4BAI4B;AAC5B;;;;2CAI2C;AAC3C,eAAO,MAAM,iBAAiB,QAAO,OAA0B,CAAC;AAEhE;;;8DAG8D;AAC9D,eAAO,MAAM,oBAAoB,QAAO,MAAmB,CAAC;AAE5D,eAAO,MAAM,iBAAiB,QAAO,IAAI,GAAG,MAe3C,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAQlC,CAAC;AAEF,eAAO,MAAM,oBAAoB,OAAQ,SAAS,KAAG,IAEpD,CAAC"}
@@ -26,6 +26,7 @@ let _ring = [];
26
26
  let _capacity = 0;
27
27
  let _timer = null;
28
28
  let _capturing = false;
29
+ let _captured = 0;
29
30
  /** Start the ring. `windowSeconds` is how far back the replay
30
31
  * reaches when an event fires. */
31
32
  export const startScreenReplay = (windowSeconds) => {
@@ -46,6 +47,7 @@ const tick = async () => {
46
47
  try {
47
48
  const frame = await _capture(maskedNativeIds(), FRAME_LONG_EDGE_PX, FRAME_QUALITY);
48
49
  if (frame) {
50
+ _captured += 1;
49
51
  _ring.push({ t: Date.now(), ...frame });
50
52
  if (_ring.length > _capacity)
51
53
  _ring.splice(0, _ring.length - _capacity);
@@ -60,6 +62,17 @@ const tick = async () => {
60
62
  * reads "-42.5s → 0s"). Returns null when empty. The ring is NOT
61
63
  * cleared — a second error two seconds later should still see
62
64
  * the minute before it. */
65
+ /** Has the ring been asked to run this session? Distinguishes "the
66
+ * host never turned pixel replay on" from "it is on and produced
67
+ * nothing", which look identical from the server and which the
68
+ * dashboard was guessing between — it told readers to enable a
69
+ * setting that may already be enabled. */
70
+ export const screenReplayArmed = () => _timer !== null;
71
+ /** Frames captured since start. Zero while armed means every tick
72
+ * returned nothing: an older native binary, or a capture that keeps
73
+ * failing. Either way the host should hear it from the event rather
74
+ * than from a console line on a device nobody is holding. */
75
+ export const screenReplayCaptured = () => _captured;
63
76
  export const drainScreenReplay = () => {
64
77
  if (_ring.length === 0)
65
78
  return null;
@@ -79,6 +92,7 @@ export const __resetForTests = () => {
79
92
  if (_timer !== null)
80
93
  clearInterval(_timer);
81
94
  _timer = null;
95
+ _captured = 0;
82
96
  _ring = [];
83
97
  _capacity = 0;
84
98
  _capturing = false;
@@ -1 +1 @@
1
- {"version":3,"file":"replay-screens.js","sourceRoot":"","sources":["../src/replay-screens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replay-screens.js","sourceRoot":"","sources":["../src/replay-screens.ts"],"names":[],"mappings":"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"}
package/lib/transport.js CHANGED
@@ -15,7 +15,7 @@ const MAX_RETRY = 3;
15
15
  const STORAGE_KEY = '@sentori/pending';
16
16
  const MAX_PERSISTED = 1000;
17
17
  // Pinned to package.json by a test — bump both together.
18
- const SDK_VERSION = '5.6.0';
18
+ const SDK_VERSION = '5.7.0';
19
19
  let _queue = [];
20
20
  let _assertStats = new Map();
21
21
  let _flushTimer = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "5.6.0",
3
+ "version": "5.7.0",
4
4
  "description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "author": "GOLIA K.K. <takagi@golia.jp> (https://golia.jp)",
@@ -8,6 +8,8 @@ import {
8
8
  __resetForTests as resetRing,
9
9
  __setCaptureForTests,
10
10
  drainScreenReplay,
11
+ screenReplayArmed,
12
+ screenReplayCaptured,
11
13
  startScreenReplay,
12
14
  } from '../replay-screens';
13
15
 
@@ -69,3 +71,30 @@ describe('screens ring', () => {
69
71
  expect(drainScreenReplay()).not.toBeNull();
70
72
  }, 10_000);
71
73
  });
74
+
75
+ describe('armed but empty', () => {
76
+ test('off: not armed, nothing captured', () => {
77
+ expect(screenReplayArmed()).toBe(false);
78
+ expect(screenReplayCaptured()).toBe(0);
79
+ });
80
+
81
+ test('armed with a native that captures nothing stays at zero', async () => {
82
+ // An older native binary returns null forever. The ring must
83
+ // report "on, and producing nothing" — the dashboard used to
84
+ // read that state as "the host never turned this on" and told
85
+ // people to enable a setting that was already enabled.
86
+ __setCaptureForTests(async () => null);
87
+ startScreenReplay(30);
88
+ expect(screenReplayArmed()).toBe(true);
89
+ await new Promise((r) => setTimeout(r, 10));
90
+ expect(screenReplayCaptured()).toBe(0);
91
+ expect(drainScreenReplay()).toBeNull();
92
+ });
93
+
94
+ test('reset disarms and clears the count', () => {
95
+ startScreenReplay(30);
96
+ resetRing();
97
+ expect(screenReplayArmed()).toBe(false);
98
+ expect(screenReplayCaptured()).toBe(0);
99
+ });
100
+ });
package/src/init.ts CHANGED
@@ -18,7 +18,12 @@ import { armLaunch } from './launch';
18
18
  import { markNativeJsBridgeReady, setNativeConfig } from './native';
19
19
  import { shipNativePending } from './native-pending';
20
20
  import { drainReplay, startReplay } from './replay';
21
- import { drainScreenReplay, startScreenReplay } from './replay-screens';
21
+ import {
22
+ drainScreenReplay,
23
+ screenReplayArmed,
24
+ screenReplayCaptured,
25
+ startScreenReplay,
26
+ } from './replay-screens';
22
27
  import { drainOfflineQueue, queueAttachment, startTransport } from './transport';
23
28
 
24
29
  let _initialized = false;
@@ -91,6 +96,19 @@ export const init = safeFn('init', (config: InitConfig): void => {
91
96
  text: frames,
92
97
  mediaType: 'application/x-sentori-screens',
93
98
  });
99
+ } else if (screenReplayArmed()) {
100
+ // Asked for, produced nothing. Without this the dashboard
101
+ // cannot tell that from "never enabled", and it was telling
102
+ // readers to switch on a setting that was already on. A
103
+ // handful of bytes on an event already going out — no extra
104
+ // request, and nothing at all when the feature is off.
105
+ event.payload = {
106
+ ...(event.payload ?? {}),
107
+ replay: {
108
+ screens: 'empty',
109
+ captured: screenReplayCaptured(),
110
+ },
111
+ };
94
112
  }
95
113
  });
96
114
  }
@@ -43,6 +43,7 @@ let _ring: ScreenFrame[] = [];
43
43
  let _capacity = 0;
44
44
  let _timer: ReturnType<typeof setInterval> | null = null;
45
45
  let _capturing = false;
46
+ let _captured = 0;
46
47
 
47
48
  /** Start the ring. `windowSeconds` is how far back the replay
48
49
  * reaches when an event fires. */
@@ -63,6 +64,7 @@ const tick = async (): Promise<void> => {
63
64
  try {
64
65
  const frame = await _capture(maskedNativeIds(), FRAME_LONG_EDGE_PX, FRAME_QUALITY);
65
66
  if (frame) {
67
+ _captured += 1;
66
68
  _ring.push({ t: Date.now(), ...frame });
67
69
  if (_ring.length > _capacity) _ring.splice(0, _ring.length - _capacity);
68
70
  }
@@ -76,6 +78,19 @@ const tick = async (): Promise<void> => {
76
78
  * reads "-42.5s → 0s"). Returns null when empty. The ring is NOT
77
79
  * cleared — a second error two seconds later should still see
78
80
  * the minute before it. */
81
+ /** Has the ring been asked to run this session? Distinguishes "the
82
+ * host never turned pixel replay on" from "it is on and produced
83
+ * nothing", which look identical from the server and which the
84
+ * dashboard was guessing between — it told readers to enable a
85
+ * setting that may already be enabled. */
86
+ export const screenReplayArmed = (): boolean => _timer !== null;
87
+
88
+ /** Frames captured since start. Zero while armed means every tick
89
+ * returned nothing: an older native binary, or a capture that keeps
90
+ * failing. Either way the host should hear it from the event rather
91
+ * than from a console line on a device nobody is holding. */
92
+ export const screenReplayCaptured = (): number => _captured;
93
+
79
94
  export const drainScreenReplay = (): null | string => {
80
95
  if (_ring.length === 0) return null;
81
96
  const now = Date.now();
@@ -96,6 +111,7 @@ export const drainScreenReplay = (): null | string => {
96
111
  export const __resetForTests = (): void => {
97
112
  if (_timer !== null) clearInterval(_timer);
98
113
  _timer = null;
114
+ _captured = 0;
99
115
  _ring = [];
100
116
  _capacity = 0;
101
117
  _capturing = false;
package/src/transport.ts CHANGED
@@ -20,7 +20,7 @@ const STORAGE_KEY = '@sentori/pending';
20
20
  const MAX_PERSISTED = 1000;
21
21
 
22
22
  // Pinned to package.json by a test — bump both together.
23
- const SDK_VERSION = '5.6.0';
23
+ const SDK_VERSION = '5.7.0';
24
24
 
25
25
  let _queue: WireEvent[] = [];
26
26
  let _assertStats = new Map<string, AssertStat>();