@goliapkg/sentori-react-native 0.8.5 → 0.9.1

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/lib/init.js CHANGED
@@ -6,7 +6,9 @@ import { installNetworkHandler } from './handlers/network';
6
6
  import { getBundleInfo } from './bundle-info';
7
7
  import { markLaunchCompleted, runLaunchCrashGuard, } from './launch-crash-guard';
8
8
  import { startMetricsTimer } from './metrics';
9
- import { drainNativePending, setNativeConfig } from './native';
9
+ import { drainNativePending, markNativeJsBridgeReady, setNativeConfig } from './native';
10
+ import { getColdStartMs } from './mobile-vitals';
11
+ import { startSpan } from '@goliapkg/sentori-core';
10
12
  import { startNetworkTypeWatch } from './netinfo';
11
13
  import { startPreCrashSentinel } from './pre-crash-sentinel';
12
14
  import { startSession } from './session-tracker';
@@ -47,6 +49,24 @@ export const init = (options) => {
47
49
  release: options.release,
48
50
  environment: env,
49
51
  });
52
+ // v0.9.4 #1 — finalize cold-start measurement. iOS uses the
53
+ // delta from `applicationDidFinishLaunching` to this call;
54
+ // Android uses Process.getStartElapsedRealtime() so the value is
55
+ // computed at this point and cached.
56
+ markNativeJsBridgeReady();
57
+ // Emit a one-off cold-start span. Server aggregates these per
58
+ // release for the Mobile Vitals dashboard. No-op when native
59
+ // module isn't linked.
60
+ const coldMs = getColdStartMs();
61
+ if (coldMs !== null && coldMs > 0 && coldMs < 60_000) {
62
+ const span = startSpan('sentori.cold_start', {
63
+ name: 'cold-start',
64
+ parent: null,
65
+ startNowMs: Date.now() - coldMs,
66
+ tags: { 'vital.kind': 'cold_start' },
67
+ });
68
+ span.finish({ status: 'ok' });
69
+ }
50
70
  startTransport();
51
71
  // v0.8.0-c — start watching network class. No-op if NetInfo isn't
52
72
  // installed; events just won't carry `device.networkType` in that
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":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAwB,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AA8ErB,MAAM,kBAAkB,GAAG,iCAAiC,CAAC;AAE7D,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAoB,EAAQ,EAAE;IACjD,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,GAAG,GACP,OAAO,CAAC,WAAW;QACnB,CAAC,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAE/D,oEAAoE;IACpE,gEAAgE;IAChE,oEAAoE;IACpE,2BAA2B;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC;IAC9C,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC;QACjB,KAAK,mBAAmB,CACtB,GAAG,EACH,OAAO,CAAC,OAAO,EACf,aAAa,EAAE,EAAE,EAAE,IAAI,IAAI,CAC5B,CAAC;IACJ,CAAC;IAED,SAAS,CAAC;QACR,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,kBAAkB;QAClD,OAAO,EAAE,IAAI;QACb,kBAAkB,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI;QACxD,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;QACjD,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;QACjD,mBAAmB,EAAE,OAAO,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI;KAC5D,CAAC,CAAC;IAEH,uEAAuE;IACvE,iEAAiE;IACjE,eAAe,CAAC;QACd,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IACH,4DAA4D;IAC5D,2DAA2D;IAC3D,iEAAiE;IACjE,qCAAqC;IACrC,uBAAuB,EAAE,CAAC;IAC1B,8DAA8D;IAC9D,6DAA6D;IAC7D,uBAAuB;IACvB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,MAAM,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,SAAS,CAAC,oBAAoB,EAAE;YAC3C,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM;YAC/B,IAAI,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,cAAc,EAAE,CAAC;IACjB,kEAAkE;IAClE,kEAAkE;IAClE,QAAQ;IACR,qBAAqB,EAAE,CAAC;IACxB,gDAAgD;IAChD,iBAAiB,EAAE,CAAC;IACpB,8DAA8D;IAC9D,oCAAoC;IACpC,IAAI,OAAO,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,EAAE,CAAC;QAC/C,qBAAqB,CAAC;YACpB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,gBAAgB;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK;QAAE,oBAAoB,EAAE,CAAC;IAC3D,IAAI,OAAO,CAAC,iBAAiB,KAAK,KAAK;QAAE,qBAAqB,EAAE,CAAC;IACjE,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,qBAAqB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC/B,+DAA+D;QAC/D,kEAAkE;QAClE,gEAAgE;QAChE,YAAY,EAAE,CAAC;QACf,uBAAuB,EAAE,CAAC;IAC5B,CAAC;IAED,8DAA8D;IAC9D,2DAA2D;IAC3D,iDAAiD;IACjD,kBAAkB,EAAE;SACjB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAE5B,CAAC;gBACF,8DAA8D;gBAC9D,2DAA2D;gBAC3D,0DAA0D;gBAC1D,6DAA6D;gBAC7D,2DAA2D;gBAC3D,IAAI,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;wBAC1C,MAAM,IAAI,GAAG,MAAM,gBAAgB,CACjC,KAAK,CAAC,EAAE,EACR,CAAC,CAAC,IAAI,EACN,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,EAC5C,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CACrB,CAAC;wBACF,IAAI,IAAI,EAAE,CAAC;4BACT,IAAI,CAAC,KAAK,CAAC,WAAW;gCAAE,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;4BAC/C,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC;oBACD,OAAO,KAAK,CAAC,mBAAmB,CAAC;gBACnC,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,iBAAiB;YACnB,CAAC;QACH,CAAC;IACH,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnB,iBAAiB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEpC,kEAAkE;IAClE,mEAAmE;IACnE,qEAAqE;IACrE,uEAAuE;IACvE,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC;QACjB,UAAU,CAAC,GAAG,EAAE;YACd,KAAK,mBAAmB,CAAC,aAAa,EAAE,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC;QACxD,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,35 @@
1
+ /** Read the native-side cold start measurement once. Cached. Returns
2
+ * null when the native module isn't linked (Expo Go / tests). */
3
+ export declare function getColdStartMs(): null | number;
4
+ /**
5
+ * v0.9.4 #1 — Time-To-Full-Display marker. Host calls this at the
6
+ * point the screen is functionally "ready" (data fetched, images
7
+ * loaded, etc.) so the dashboard can show real perceived load time
8
+ * vs auto-detected TTID.
9
+ *
10
+ * const h = sentori.markTimeToFullDisplay('Home');
11
+ * // ...data fetched, images rendered...
12
+ * h.end();
13
+ *
14
+ * If `.end()` is never called, the handle's span is finished as
15
+ * `cancelled` at the next `markTimeToFullDisplay` call (one TTFD in
16
+ * flight at a time is the typical case).
17
+ */
18
+ export type TimeToFullDisplayHandle = {
19
+ end: (opts?: {
20
+ status?: 'cancelled' | 'error' | 'ok';
21
+ }) => void;
22
+ cancel: () => void;
23
+ };
24
+ export declare function markTimeToFullDisplay(route: string): TimeToFullDisplayHandle;
25
+ /** v0.9.4 #1 — read the per-screen slow/frozen frame counts since
26
+ * the most recent navigation transition. Native module reads
27
+ * CADisplayLink / Choreographer counters; returns null when not
28
+ * linked. */
29
+ export declare function getFrameCounters(): null | {
30
+ slow: number;
31
+ frozen: number;
32
+ };
33
+ /** Test-only. */
34
+ export declare function __resetMobileVitalsForTests(): void;
35
+ //# sourceMappingURL=mobile-vitals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-vitals.d.ts","sourceRoot":"","sources":["../src/mobile-vitals.ts"],"names":[],"mappings":"AA6BA;kEACkE;AAClE,wBAAgB,cAAc,IAAI,IAAI,GAAG,MAAM,CAS9C;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAOF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,uBAAuB,CAqB5E;AAED;;;cAGc;AACd,wBAAgB,gBAAgB,IAAI,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAY1E;AAED,iBAAiB;AACjB,wBAAgB,2BAA2B,IAAI,IAAI,CAKlD"}
@@ -0,0 +1,89 @@
1
+ // v0.9.4 #1 — Mobile Vitals.
2
+ //
3
+ // Three measurements, three call paths, one server schema:
4
+ //
5
+ // • Cold start: native side measures at app launch (iOS
6
+ // mach_absolute_time / Android Process.getStartElapsedRealtime)
7
+ // and exposes via the bundled native module — read once on JS
8
+ // side at init() and ride along on the first event.
9
+ // • TTID (Time-To-Initial-Display): automatic via
10
+ // useTraceNavigation extension — span from navigation.dispatch
11
+ // to first frame after route mount.
12
+ // • TTFD (Time-To-Full-Display): manual. Host calls
13
+ // sentori.markTimeToFullDisplay('Home').end() when the screen's
14
+ // data has loaded.
15
+ // • Slow / frozen frame counts: native side hooks CADisplayLink /
16
+ // Choreographer.FrameCallback; counters flush per navigation
17
+ // span.
18
+ //
19
+ // JS-side first: TTFD API + bundle-level vital captures. Native
20
+ // pieces ship as a separate native module method `getColdStartMs`
21
+ // + `getFrameCounts()` — graceful no-op if not linked.
22
+ import { startSpan } from '@goliapkg/sentori-core';
23
+ import { getNativeColdStartMs } from './native';
24
+ let _coldStartMs = null;
25
+ let _coldStartCaptured = false;
26
+ /** Read the native-side cold start measurement once. Cached. Returns
27
+ * null when the native module isn't linked (Expo Go / tests). */
28
+ export function getColdStartMs() {
29
+ if (_coldStartCaptured)
30
+ return _coldStartMs;
31
+ _coldStartCaptured = true;
32
+ try {
33
+ _coldStartMs = getNativeColdStartMs();
34
+ }
35
+ catch {
36
+ _coldStartMs = null;
37
+ }
38
+ return _coldStartMs;
39
+ }
40
+ let _activeTtfd = null;
41
+ export function markTimeToFullDisplay(route) {
42
+ if (_activeTtfd && _activeTtfd.route !== route) {
43
+ _activeTtfd.finish('cancelled');
44
+ }
45
+ const span = startSpan('react.navigation.ttfd', {
46
+ name: route,
47
+ tags: { 'nav.route': route, 'vital.kind': 'ttfd' },
48
+ });
49
+ let finished = false;
50
+ const finish = (status) => {
51
+ if (finished)
52
+ return;
53
+ finished = true;
54
+ span.finish({ status });
55
+ if (_activeTtfd && _activeTtfd.route === route)
56
+ _activeTtfd = null;
57
+ };
58
+ _activeTtfd = { finish, route };
59
+ return {
60
+ cancel: () => finish('cancelled'),
61
+ end: (opts) => finish(opts?.status ?? 'ok'),
62
+ };
63
+ }
64
+ /** v0.9.4 #1 — read the per-screen slow/frozen frame counts since
65
+ * the most recent navigation transition. Native module reads
66
+ * CADisplayLink / Choreographer counters; returns null when not
67
+ * linked. */
68
+ export function getFrameCounters() {
69
+ try {
70
+ // native binding lazily required in native.ts
71
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
72
+ const nativeMod = require('./native');
73
+ if (typeof nativeMod.getNativeFrameCounters !== 'function')
74
+ return null;
75
+ return nativeMod.getNativeFrameCounters();
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ }
81
+ /** Test-only. */
82
+ export function __resetMobileVitalsForTests() {
83
+ if (_activeTtfd)
84
+ _activeTtfd.finish('cancelled');
85
+ _activeTtfd = null;
86
+ _coldStartCaptured = false;
87
+ _coldStartMs = null;
88
+ }
89
+ //# sourceMappingURL=mobile-vitals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-vitals.js","sourceRoot":"","sources":["../src/mobile-vitals.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,EAAE;AACF,2DAA2D;AAC3D,EAAE;AACF,0DAA0D;AAC1D,oEAAoE;AACpE,kEAAkE;AAClE,wDAAwD;AACxD,oDAAoD;AACpD,mEAAmE;AACnE,wCAAwC;AACxC,sDAAsD;AACtD,oEAAoE;AACpE,uBAAuB;AACvB,oEAAoE;AACpE,iEAAiE;AACjE,YAAY;AACZ,EAAE;AACF,gEAAgE;AAChE,kEAAkE;AAClE,uDAAuD;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEhD,IAAI,YAAY,GAAkB,IAAI,CAAC;AACvC,IAAI,kBAAkB,GAAG,KAAK,CAAC;AAE/B;kEACkE;AAClE,MAAM,UAAU,cAAc;IAC5B,IAAI,kBAAkB;QAAE,OAAO,YAAY,CAAC;IAC5C,kBAAkB,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC;QACH,YAAY,GAAG,oBAAoB,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAqBD,IAAI,WAAW,GAGX,IAAI,CAAC;AAET,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,IAAI,WAAW,IAAI,WAAW,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC/C,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,uBAAuB,EAAE;QAC9C,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE;KACnD,CAAC,CAAC;IACH,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,MAAM,GAAG,CAAC,MAAoC,EAAQ,EAAE;QAC5D,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACxB,IAAI,WAAW,IAAI,WAAW,CAAC,KAAK,KAAK,KAAK;YAAE,WAAW,GAAG,IAAI,CAAC;IACrE,CAAC,CAAC;IACF,WAAW,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAChC,OAAO;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;QACjC,GAAG,EAAE,CAAC,IAAgD,EAAE,EAAE,CACxD,MAAM,CAAC,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;;cAGc;AACd,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,8CAA8C;QAC9C,iEAAiE;QACjE,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAEnC,CAAC;QACF,IAAI,OAAO,SAAS,CAAC,sBAAsB,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC;QACxE,OAAO,SAAS,CAAC,sBAAsB,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iBAAiB;AACjB,MAAM,UAAU,2BAA2B;IACzC,IAAI,WAAW;QAAE,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACjD,WAAW,GAAG,IAAI,CAAC;IACnB,kBAAkB,GAAG,KAAK,CAAC;IAC3B,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC"}
package/lib/native.d.ts CHANGED
@@ -37,6 +37,26 @@ export declare function startAnrWatchdog(options?: {
37
37
  timeoutMs?: number;
38
38
  }): void;
39
39
  export declare function stopAnrWatchdog(): void;
40
+ /** v0.9.4 #1 — finalize cold-start measurement. Idempotent. */
41
+ export declare function markNativeJsBridgeReady(): void;
42
+ /** v0.9.4 #1 — read cold start ms once. null when native unavailable. */
43
+ export declare function getNativeColdStartMs(): null | number;
44
+ /** v0.9.4 #1 — read slow/frozen frame counters since last reset. */
45
+ export declare function getNativeFrameCounters(): null | {
46
+ frozen: number;
47
+ slow: number;
48
+ };
49
+ /** v0.9.4 #1 — reset frame counters on navigation transition. */
50
+ export declare function resetNativeFrameCounters(): void;
51
+ /** v0.9.5 #8 — fetch the most-recent native exception from
52
+ * SentoriNativeExceptionBridge (within last ~1 s). null if none or
53
+ * bridge not linked. */
54
+ export declare function getRecentNativeException(): null | {
55
+ ageMs: number;
56
+ name: string;
57
+ reason: string;
58
+ stack: string[];
59
+ };
40
60
  /**
41
61
  * v0.7.3 — drives the native screenshot path. JS side passes the
42
62
  * current list of mask `nativeID`s (read from the consumer's
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsDH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,IAAI,CAMP;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAQ5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IACzC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,IAAI,CAMP;AAED,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CACnD,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvD"}
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAyFH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,IAAI,CAMP;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAQ5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IACzC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,IAAI,CAMP;AAED,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED,+DAA+D;AAC/D,wBAAgB,uBAAuB,IAAI,IAAI,CAM9C;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,IAAI,IAAI,GAAG,MAAM,CAOpD;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,IAAI,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMhF;AAED,iEAAiE;AACjE,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAED;;yBAEyB;AACzB,wBAAgB,wBAAwB,IAAI,IAAI,GAAG;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAMA;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CACnD,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvD"}
package/lib/native.js CHANGED
@@ -80,6 +80,54 @@ export function stopAnrWatchdog() {
80
80
  // ignore
81
81
  }
82
82
  }
83
+ /** v0.9.4 #1 — finalize cold-start measurement. Idempotent. */
84
+ export function markNativeJsBridgeReady() {
85
+ try {
86
+ native()?.markJsBridgeReady?.();
87
+ }
88
+ catch {
89
+ // ignore
90
+ }
91
+ }
92
+ /** v0.9.4 #1 — read cold start ms once. null when native unavailable. */
93
+ export function getNativeColdStartMs() {
94
+ try {
95
+ const v = native()?.getColdStartMs?.();
96
+ return typeof v === 'number' && Number.isFinite(v) ? v : null;
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ /** v0.9.4 #1 — read slow/frozen frame counters since last reset. */
103
+ export function getNativeFrameCounters() {
104
+ try {
105
+ return native()?.getFrameCounters?.() ?? null;
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ }
111
+ /** v0.9.4 #1 — reset frame counters on navigation transition. */
112
+ export function resetNativeFrameCounters() {
113
+ try {
114
+ native()?.resetFrameCounters?.();
115
+ }
116
+ catch {
117
+ // ignore
118
+ }
119
+ }
120
+ /** v0.9.5 #8 — fetch the most-recent native exception from
121
+ * SentoriNativeExceptionBridge (within last ~1 s). null if none or
122
+ * bridge not linked. */
123
+ export function getRecentNativeException() {
124
+ try {
125
+ return native()?.getRecentNativeException?.() ?? null;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
83
131
  /**
84
132
  * v0.7.3 — drives the native screenshot path. JS side passes the
85
133
  * current list of mask `nativeID`s (read from the consumer's
package/lib/native.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuCH,IAAI,OAA+C,CAAA;AAEnD,SAAS,MAAM;IACb,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAA;IACzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,mBAAmB,CAEvC,CAAA;QACD,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAsB,SAAS,CAAC,CAAA;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,IAAI,CAAA;IAChB,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAI/B;IACC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACjB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,YAAY,EAAE,CAAA;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,sBAAsB,EAAE,EAAE,CAAA;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAIhC;IACC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,gBAAgB,EAAE,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,eAAe,EAAE,EAAE,CAAA;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,SAAmB;IAEnB,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,EAAE,yBAAyB;QAAE,OAAO,IAAI,CAAA;IAC9C,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAA;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AA4BA;;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,CAiFzE"}
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"}
package/lib/navigation.js CHANGED
@@ -21,6 +21,7 @@
21
21
  // `startSpan(op, { parent: activeSpan() })`.
22
22
  import { useEffect, useRef } from 'react';
23
23
  import { setActiveSpan, startSpan } from '@goliapkg/sentori-core';
24
+ import { getNativeFrameCounters, resetNativeFrameCounters, } from './native';
24
25
  import { captureStep } from './trail';
25
26
  /**
26
27
  * Subscribe to react-navigation state changes and emit a
@@ -85,11 +86,22 @@ export function useTraceNavigation(navigationRef) {
85
86
  if (!span)
86
87
  return null;
87
88
  const dwellMs = enteredAt !== null ? Math.max(0, Date.now() - enteredAt) : null;
89
+ // v0.9.4 #1 — drain native frame counters at screen-leave.
90
+ // Empty/null when native module not linked; tags omitted.
91
+ const fc = getNativeFrameCounters();
92
+ const finishTags = {};
93
+ if (dwellMs !== null)
94
+ finishTags['nav.dwell_ms'] = String(dwellMs);
95
+ if (fc) {
96
+ finishTags['vital.slow_frames'] = String(fc.slow);
97
+ finishTags['vital.frozen_frames'] = String(fc.frozen);
98
+ }
88
99
  span.finish({
89
100
  status: 'ok',
90
- // Tag values are strings on the wire — cast at finish-time.
91
- tags: dwellMs !== null ? { 'nav.dwell_ms': String(dwellMs) } : undefined,
101
+ tags: Object.keys(finishTags).length > 0 ? finishTags : undefined,
92
102
  });
103
+ // Reset counters for the next screen.
104
+ resetNativeFrameCounters();
93
105
  return dwellMs;
94
106
  };
95
107
  // Open a span for the initial screen so its requests are grouped
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "0.8.5",
3
+ "version": "0.9.1",
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": "MIT",
6
6
  "homepage": "https://sentori.golia.jp",
package/src/capture.ts CHANGED
@@ -13,6 +13,7 @@ import { getTrailBuffer } from './trail';
13
13
  import { enqueue, sendUserReport, uploadAttachment } from './transport';
14
14
  import { uuidV7 } from './uuid';
15
15
  import { getCachedNetworkType } from './netinfo';
16
+ import { getRecentNativeException } from './native';
16
17
  import type { App, AttachmentMeta, Device, Event, SentoriError, Tags, User } from './types';
17
18
 
18
19
  export { captureStep, __resetTrailForTests } from './trail';
@@ -271,6 +272,27 @@ const errorToObject = (error: Error): SentoriError => {
271
272
  cause = errorToObject(causeRaw);
272
273
  }
273
274
 
275
+ // v0.9.5 #8 — TurboModule swallowed-exception bridge. If the host
276
+ // wrapped a native call with `@try @catch + recordException`, the
277
+ // native ring may hold a fresh entry (< 1 s old). Synthesize that
278
+ // as a `cause` so the JS event includes the original native stack.
279
+ if (cause === null) {
280
+ const recent = getRecentNativeException();
281
+ if (recent && recent.ageMs <= 1500) {
282
+ cause = {
283
+ type: recent.name || 'NativeException',
284
+ message: recent.reason,
285
+ stack: recent.stack.map((line, i) => ({
286
+ function: line.trim(),
287
+ file: '<native>',
288
+ inApp: false,
289
+ line: i + 1,
290
+ })),
291
+ cause: null,
292
+ };
293
+ }
294
+ }
295
+
274
296
  return {
275
297
  type: error.name || 'Error',
276
298
  message: error.message,
package/src/index.ts CHANGED
@@ -18,6 +18,11 @@ import {
18
18
  } from './feature-flags';
19
19
  import { clearMaskQuery, registerMaskQuery } from './mask';
20
20
  import { measureFn } from './measure';
21
+ import {
22
+ getColdStartMs,
23
+ markTimeToFullDisplay,
24
+ type TimeToFullDisplayHandle,
25
+ } from './mobile-vitals';
21
26
  import { bindState, recordState, unbindState } from './state-snapshots';
22
27
  import { startMoment } from '@goliapkg/sentori-core';
23
28
  import { flushMetrics, recordMetric } from './metrics';
@@ -44,6 +49,8 @@ export const sentori = {
44
49
  bindState,
45
50
  recordState,
46
51
  unbindState,
52
+ markTimeToFullDisplay,
53
+ getColdStartMs,
47
54
  setFeatureFlag,
48
55
  clearFeatureFlag,
49
56
  clearAllFeatureFlags,
@@ -81,6 +88,11 @@ export {
81
88
  export { clearMaskQuery, registerMaskQuery } from './mask';
82
89
  export { flushMetrics, recordMetric } from './metrics';
83
90
  export { measureFn } from './measure';
91
+ export {
92
+ getColdStartMs,
93
+ markTimeToFullDisplay,
94
+ type TimeToFullDisplayHandle,
95
+ } from './mobile-vitals';
84
96
  export { MomentHandle, type MomentProperties, startMoment } from '@goliapkg/sentori-core';
85
97
  export {
86
98
  bindState,
package/src/init.ts CHANGED
@@ -9,7 +9,9 @@ import {
9
9
  runLaunchCrashGuard,
10
10
  } from './launch-crash-guard';
11
11
  import { startMetricsTimer } from './metrics';
12
- import { drainNativePending, setNativeConfig } from './native';
12
+ import { drainNativePending, markNativeJsBridgeReady, setNativeConfig } from './native';
13
+ import { getColdStartMs } from './mobile-vitals';
14
+ import { startSpan } from '@goliapkg/sentori-core';
13
15
  import { startNetworkTypeWatch } from './netinfo';
14
16
  import { startPreCrashSentinel, type PreCrashChannel } from './pre-crash-sentinel';
15
17
  import { startSession } from './session-tracker';
@@ -142,6 +144,24 @@ export const init = (options: InitOptions): void => {
142
144
  release: options.release,
143
145
  environment: env,
144
146
  });
147
+ // v0.9.4 #1 — finalize cold-start measurement. iOS uses the
148
+ // delta from `applicationDidFinishLaunching` to this call;
149
+ // Android uses Process.getStartElapsedRealtime() so the value is
150
+ // computed at this point and cached.
151
+ markNativeJsBridgeReady();
152
+ // Emit a one-off cold-start span. Server aggregates these per
153
+ // release for the Mobile Vitals dashboard. No-op when native
154
+ // module isn't linked.
155
+ const coldMs = getColdStartMs();
156
+ if (coldMs !== null && coldMs > 0 && coldMs < 60_000) {
157
+ const span = startSpan('sentori.cold_start', {
158
+ name: 'cold-start',
159
+ parent: null,
160
+ startNowMs: Date.now() - coldMs,
161
+ tags: { 'vital.kind': 'cold_start' },
162
+ });
163
+ span.finish({ status: 'ok' });
164
+ }
145
165
 
146
166
  startTransport();
147
167
  // v0.8.0-c — start watching network class. No-op if NetInfo isn't
@@ -0,0 +1,114 @@
1
+ // v0.9.4 #1 — Mobile Vitals.
2
+ //
3
+ // Three measurements, three call paths, one server schema:
4
+ //
5
+ // • Cold start: native side measures at app launch (iOS
6
+ // mach_absolute_time / Android Process.getStartElapsedRealtime)
7
+ // and exposes via the bundled native module — read once on JS
8
+ // side at init() and ride along on the first event.
9
+ // • TTID (Time-To-Initial-Display): automatic via
10
+ // useTraceNavigation extension — span from navigation.dispatch
11
+ // to first frame after route mount.
12
+ // • TTFD (Time-To-Full-Display): manual. Host calls
13
+ // sentori.markTimeToFullDisplay('Home').end() when the screen's
14
+ // data has loaded.
15
+ // • Slow / frozen frame counts: native side hooks CADisplayLink /
16
+ // Choreographer.FrameCallback; counters flush per navigation
17
+ // span.
18
+ //
19
+ // JS-side first: TTFD API + bundle-level vital captures. Native
20
+ // pieces ship as a separate native module method `getColdStartMs`
21
+ // + `getFrameCounts()` — graceful no-op if not linked.
22
+
23
+ import { startSpan } from '@goliapkg/sentori-core';
24
+
25
+ import { getNativeColdStartMs } from './native';
26
+
27
+ let _coldStartMs: null | number = null;
28
+ let _coldStartCaptured = false;
29
+
30
+ /** Read the native-side cold start measurement once. Cached. Returns
31
+ * null when the native module isn't linked (Expo Go / tests). */
32
+ export function getColdStartMs(): null | number {
33
+ if (_coldStartCaptured) return _coldStartMs;
34
+ _coldStartCaptured = true;
35
+ try {
36
+ _coldStartMs = getNativeColdStartMs();
37
+ } catch {
38
+ _coldStartMs = null;
39
+ }
40
+ return _coldStartMs;
41
+ }
42
+
43
+ /**
44
+ * v0.9.4 #1 — Time-To-Full-Display marker. Host calls this at the
45
+ * point the screen is functionally "ready" (data fetched, images
46
+ * loaded, etc.) so the dashboard can show real perceived load time
47
+ * vs auto-detected TTID.
48
+ *
49
+ * const h = sentori.markTimeToFullDisplay('Home');
50
+ * // ...data fetched, images rendered...
51
+ * h.end();
52
+ *
53
+ * If `.end()` is never called, the handle's span is finished as
54
+ * `cancelled` at the next `markTimeToFullDisplay` call (one TTFD in
55
+ * flight at a time is the typical case).
56
+ */
57
+ export type TimeToFullDisplayHandle = {
58
+ end: (opts?: { status?: 'cancelled' | 'error' | 'ok' }) => void;
59
+ cancel: () => void;
60
+ };
61
+
62
+ let _activeTtfd: null | {
63
+ finish: (status: 'cancelled' | 'error' | 'ok') => void;
64
+ route: string;
65
+ } = null;
66
+
67
+ export function markTimeToFullDisplay(route: string): TimeToFullDisplayHandle {
68
+ if (_activeTtfd && _activeTtfd.route !== route) {
69
+ _activeTtfd.finish('cancelled');
70
+ }
71
+ const span = startSpan('react.navigation.ttfd', {
72
+ name: route,
73
+ tags: { 'nav.route': route, 'vital.kind': 'ttfd' },
74
+ });
75
+ let finished = false;
76
+ const finish = (status: 'cancelled' | 'error' | 'ok'): void => {
77
+ if (finished) return;
78
+ finished = true;
79
+ span.finish({ status });
80
+ if (_activeTtfd && _activeTtfd.route === route) _activeTtfd = null;
81
+ };
82
+ _activeTtfd = { finish, route };
83
+ return {
84
+ cancel: () => finish('cancelled'),
85
+ end: (opts?: { status?: 'cancelled' | 'error' | 'ok' }) =>
86
+ finish(opts?.status ?? 'ok'),
87
+ };
88
+ }
89
+
90
+ /** v0.9.4 #1 — read the per-screen slow/frozen frame counts since
91
+ * the most recent navigation transition. Native module reads
92
+ * CADisplayLink / Choreographer counters; returns null when not
93
+ * linked. */
94
+ export function getFrameCounters(): null | { slow: number; frozen: number } {
95
+ try {
96
+ // native binding lazily required in native.ts
97
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
98
+ const nativeMod = require('./native') as {
99
+ getNativeFrameCounters?: () => null | { frozen: number; slow: number };
100
+ };
101
+ if (typeof nativeMod.getNativeFrameCounters !== 'function') return null;
102
+ return nativeMod.getNativeFrameCounters();
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+
108
+ /** Test-only. */
109
+ export function __resetMobileVitalsForTests(): void {
110
+ if (_activeTtfd) _activeTtfd.finish('cancelled');
111
+ _activeTtfd = null;
112
+ _coldStartCaptured = false;
113
+ _coldStartMs = null;
114
+ }