@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/android/src/main/java/com/sentori/SentoriCrashHandler.kt +11 -1
- package/android/src/main/java/com/sentori/SentoriMobileVitals.kt +100 -0
- package/android/src/main/java/com/sentori/SentoriModule.kt +23 -0
- package/android/src/main/java/com/sentori/SentoriNativeExceptionBridge.kt +75 -0
- package/android/src/main/java/com/sentori/SentoriNativeSignals.kt +32 -0
- package/ios/SentoriMobileVitals.swift +104 -0
- package/ios/SentoriModule.swift +23 -0
- package/ios/SentoriNativeExceptionBridge.swift +90 -0
- package/lib/capture.d.ts.map +1 -1
- package/lib/capture.js +21 -0
- package/lib/capture.js.map +1 -1
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -1
- package/lib/init.d.ts.map +1 -1
- package/lib/init.js +21 -1
- package/lib/init.js.map +1 -1
- package/lib/mobile-vitals.d.ts +35 -0
- package/lib/mobile-vitals.d.ts.map +1 -0
- package/lib/mobile-vitals.js +89 -0
- package/lib/mobile-vitals.js.map +1 -0
- package/lib/native.d.ts +20 -0
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +48 -0
- package/lib/native.js.map +1 -1
- package/lib/navigation.d.ts.map +1 -1
- package/lib/navigation.js +14 -2
- package/lib/navigation.js.map +1 -1
- package/package.json +1 -1
- package/src/capture.ts +22 -0
- package/src/index.ts +12 -0
- package/src/init.ts +21 -1
- package/src/mobile-vitals.ts +114 -0
- package/src/native.ts +88 -0
- package/src/navigation.ts +16 -2
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":"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,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
package/lib/native.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
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;
|
|
1
|
+
{"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}
|
package/lib/navigation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"
|
|
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
|
-
|
|
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
|
package/lib/navigation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,oEAAoE;AACpE,0DAA0D;AAC1D,qEAAqE;AACrE,iEAAiE;AACjE,EAAE;AACF,yDAAyD;AACzD,8DAA8D;AAC9D,mEAAmE;AACnE,4CAA4C;AAC5C,EAAE;AACF,oEAAoE;AACpE,gEAAgE;AAChE,mEAAmE;AACnE,kEAAkE;AAClE,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,sEAAsE;AACtE,gEAAgE;AAChE,6CAA6C;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAmB,MAAM,wBAAwB,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAUtC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAgC;IACjE,oCAAoC;IACpC,MAAM,YAAY,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IACjD,oEAAoE;IACpE,kEAAkE;IAClE,MAAM,qBAAqB,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC1D,kEAAkE;IAClE,0CAA0C;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAEpD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,aAAa,CAAC,WAAW,KAAK,UAAU;YAAE,OAAO;QAC5D,IAAI,OAAO,aAAa,CAAC,eAAe,KAAK,UAAU;YAAE,OAAO;QAEhE,iEAAiE;QACjE,4DAA4D;QAC5D,mDAAmD;QACnD,MAAM,cAAc,GAAG,CACrB,IAAmB,EACnB,EAAU,EACV,WAA0B,EAC1B,EAAE;YACF,MAAM,IAAI,GAAG,SAAS,CAAC,kBAAkB,EAAE;gBACzC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;aAC/C,CAAC,CAAC;YACH,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,aAAa,CAAC,IAAI,CAAC,CAAC;YACpB,YAAY,CAAC,OAAO,GAAG,EAAE,CAAC;YAC1B,qBAAqB,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3C,0DAA0D;YAC1D,yDAAyD;YACzD,6DAA6D;YAC7D,kEAAkE;YAClE,wDAAwD;YACxD,WAAW,CAAC,UAAU,EAAE,EAAE,EAAE;gBAC1B,UAAU,EAAE;oBACV,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;oBACrE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;oBACtC,IAAI,EAAE,YAAY;iBACnB;aACF,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,uBAAuB,GAAG,GAAkB,EAAE;YAClD,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC;YACjC,MAAM,SAAS,GAAG,qBAAqB,CAAC,OAAO,CAAC;YAChD,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YACvB,MAAM,OAAO,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAChF,
|
|
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.
|
|
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
|
+
}
|