@goliapkg/sentori-react-native 5.5.0 → 5.6.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/README.md +74 -10
- package/android/src/main/java/com/sentori/SentoriForegroundActivity.kt +3 -0
- package/android/src/main/java/com/sentori/SentoriMobileVitals.kt +31 -0
- package/android/src/main/java/com/sentori/SentoriModule.kt +6 -0
- package/ios/SentoriMobileVitals.swift +9 -0
- package/ios/SentoriModule.swift +6 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/init.d.ts.map +1 -1
- package/lib/init.js +2 -0
- package/lib/init.js.map +1 -1
- package/lib/launch.d.ts +10 -0
- package/lib/launch.d.ts.map +1 -0
- package/lib/launch.js +75 -0
- package/lib/launch.js.map +1 -0
- package/lib/mobile-vitals.d.ts +4 -1
- package/lib/mobile-vitals.d.ts.map +1 -1
- package/lib/mobile-vitals.js +26 -4
- package/lib/mobile-vitals.js.map +1 -1
- package/lib/native.d.ts +4 -0
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +11 -0
- package/lib/native.js.map +1 -1
- package/lib/transport.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/launch.test.ts +90 -0
- package/src/index.ts +1 -0
- package/src/init.ts +2 -0
- package/src/launch.ts +79 -0
- package/src/mobile-vitals.ts +27 -4
- package/src/native.ts +12 -0
- package/src/transport.ts +1 -1
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.
|
|
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: '
|
|
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' })
|
|
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:
|
|
49
|
-
error/warn as the "what the
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
|
@@ -82,6 +82,9 @@ object SentoriForegroundActivity {
|
|
|
82
82
|
fun set(activity: Activity, source: String) {
|
|
83
83
|
lastActivity = WeakReference(activity)
|
|
84
84
|
lastPath = source
|
|
85
|
+
// First Activity sighting anchors the pre-warm discriminator
|
|
86
|
+
// (idempotent; reflection back-fill counts too).
|
|
87
|
+
SentoriMobileVitals.markFirstActivity()
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
fun current(): Activity? {
|
|
@@ -26,6 +26,14 @@ object SentoriMobileVitals {
|
|
|
26
26
|
|
|
27
27
|
private val jsBridgeReadyAt = AtomicLong(0)
|
|
28
28
|
private val coldStartMs = AtomicLong(-1)
|
|
29
|
+
private val firstActivityAt = AtomicLong(0)
|
|
30
|
+
|
|
31
|
+
/** A process started in the background (FCM data message,
|
|
32
|
+
* JobScheduler, broadcast) and opened by the user minutes later
|
|
33
|
+
* must not report the whole gap as "cold start" — the Firebase
|
|
34
|
+
* Performance bug class. Discriminator: the first Activity was
|
|
35
|
+
* created more than this long after the process start. */
|
|
36
|
+
private const val PREWARM_GAP_MS: Long = 5_000
|
|
29
37
|
|
|
30
38
|
private val slowFrames = AtomicInteger(0)
|
|
31
39
|
private val frozenFrames = AtomicInteger(0)
|
|
@@ -54,6 +62,29 @@ object SentoriMobileVitals {
|
|
|
54
62
|
return if (v < 0) null else v
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
/** Called by [SentoriForegroundActivity] on the first Activity
|
|
66
|
+
* sighting (lifecycle or reflection back-fill). Idempotent. */
|
|
67
|
+
@JvmStatic
|
|
68
|
+
fun markFirstActivity() {
|
|
69
|
+
firstActivityAt.compareAndSet(0, SystemClock.elapsedRealtime())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** True when the measured "cold start" is a phantom: the process
|
|
73
|
+
* was pre-warmed in the background and the user arrived much
|
|
74
|
+
* later (or no Activity exists at all — headless start). The
|
|
75
|
+
* sample still ships, flagged, so the dashboard can exclude it;
|
|
76
|
+
* the slow-start warn skips it entirely. */
|
|
77
|
+
@JvmStatic
|
|
78
|
+
fun isColdStartPrewarmed(): Boolean {
|
|
79
|
+
val first = firstActivityAt.get()
|
|
80
|
+
if (first == 0L) return true
|
|
81
|
+
return try {
|
|
82
|
+
first - Process.getStartElapsedRealtime() > PREWARM_GAP_MS
|
|
83
|
+
} catch (_: Throwable) {
|
|
84
|
+
false
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
57
88
|
@JvmStatic
|
|
58
89
|
fun startFrameWatch() {
|
|
59
90
|
if (frameWatchRunning) return
|
|
@@ -54,6 +54,12 @@ class SentoriModule : Module() {
|
|
|
54
54
|
Function("getColdStartMs") {
|
|
55
55
|
SentoriMobileVitals.getColdStartMs()
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
// v5.6 — phantom-sample discriminator (ActivePrewarm on iOS,
|
|
59
|
+
// process-to-first-Activity gap on Android).
|
|
60
|
+
Function("isColdStartPrewarmed") {
|
|
61
|
+
SentoriMobileVitals.isColdStartPrewarmed()
|
|
62
|
+
}
|
|
57
63
|
Function("getFrameCounters") {
|
|
58
64
|
SentoriMobileVitals.getFrameCounters()
|
|
59
65
|
}
|
|
@@ -53,6 +53,15 @@ import QuartzCore
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/// iOS 15+ pre-warms processes ahead of user intent; a launch
|
|
57
|
+
/// measured from a pre-warmed anchor is a phantom sample (the
|
|
58
|
+
/// same bug class Firebase Performance shipped and later
|
|
59
|
+
/// guarded). Apple's own discriminator: the ActivePrewarm
|
|
60
|
+
/// environment flag, set only in pre-warmed processes.
|
|
61
|
+
@objc public static func isColdStartPrewarmed() -> Bool {
|
|
62
|
+
return ProcessInfo.processInfo.environment["ActivePrewarm"] == "1"
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
@objc public static func getColdStartMs() -> NSNumber? {
|
|
57
66
|
if let ms = coldStartMs {
|
|
58
67
|
return NSNumber(value: ms)
|
package/ios/SentoriModule.swift
CHANGED
|
@@ -52,6 +52,12 @@ public class SentoriModule: Module {
|
|
|
52
52
|
Function("getColdStartMs") { () -> Double? in
|
|
53
53
|
return SentoriMobileVitals.getColdStartMs()?.doubleValue
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
// v5.6 — phantom-sample discriminator (ActivePrewarm on iOS,
|
|
57
|
+
// process-to-first-Activity gap on Android).
|
|
58
|
+
Function("isColdStartPrewarmed") { () -> Bool in
|
|
59
|
+
return SentoriMobileVitals.isColdStartPrewarmed()
|
|
60
|
+
}
|
|
55
61
|
Function("getFrameCounters") { () -> [String: Any]? in
|
|
56
62
|
return SentoriMobileVitals.getFrameCounters() as? [String: Any]
|
|
57
63
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export { init } from './init';
|
|
|
31
31
|
export { ErrorBoundary } from './error-boundary';
|
|
32
32
|
export { RageTapCapture } from './rage-tap';
|
|
33
33
|
export { registerMaskQuery } from './mask';
|
|
34
|
+
export { launch } from './launch';
|
|
34
35
|
export { triggerNativeCrash } from './native';
|
|
35
36
|
export { type NavigationRefLike, useTraceNavigation } from './navigation';
|
|
36
37
|
export type { AssertStat, Device, EventData, EventKind, Frame, InitConfig, SentoriApi, SentoriError, Signal, Surface, TraceOptions, User, WireEvent, WirePayload, } from '@goliapkg/sentori-core';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,IAAI,EACL,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,OAAO;IAClB,2DAA2D;IAC3D,IAAI,WAAW,UAAU,KAAG,IAAI;IAGhC;;4CAEwC;IACxC,IAAI,MAAM,IAAI,GAAG,IAAI,KAAG,IAAI;IAG5B;8CAC0C;IAC1C,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;IAI/C;sEACkE;IAClE,KAAK,QAAQ,OAAO,SAAS,SAAS,KAAG,MAAM;IAC/C,kDAAkD;IAClD,IAAI,SAAS,MAAM,SAAS,SAAS,KAAG,MAAM;IAC9C;6DACyD;IACzD,KAAK,SAAS,MAAM,SAAS,SAAS,SAAS,YAAY,KAAG,MAAM;IAEpE;;mDAE+C;IAC/C,MAAM,SAAS,MAAM,MAAM,OAAO,SAAS,SAAS,KAAG,MAAM;IAE7D;;qCAEiC;IACjC,KAAK,QAAQ,MAAM,SAAS,SAAS,KAAG,MAAM;CAC/C,CAAC;eAEa,OAAO;AAEtB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,IAAI,EACL,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,OAAO;IAClB,2DAA2D;IAC3D,IAAI,WAAW,UAAU,KAAG,IAAI;IAGhC;;4CAEwC;IACxC,IAAI,MAAM,IAAI,GAAG,IAAI,KAAG,IAAI;IAG5B;8CAC0C;IAC1C,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;IAI/C;sEACkE;IAClE,KAAK,QAAQ,OAAO,SAAS,SAAS,KAAG,MAAM;IAC/C,kDAAkD;IAClD,IAAI,SAAS,MAAM,SAAS,SAAS,KAAG,MAAM;IAC9C;6DACyD;IACzD,KAAK,SAAS,MAAM,SAAS,SAAS,SAAS,YAAY,KAAG,MAAM;IAEpE;;mDAE+C;IAC/C,MAAM,SAAS,MAAM,MAAM,OAAO,SAAS,SAAS,KAAG,MAAM;IAE7D;;qCAEiC;IACjC,KAAK,QAAQ,MAAM,SAAS,SAAS,KAAG,MAAM;CAC/C,CAAC;eAEa,OAAO;AAEtB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAG1E,YAAY,EACV,UAAU,EACV,MAAM,EACN,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,EACV,UAAU,EACV,YAAY,EACZ,MAAM,EACN,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,WAAW,EACX,KAAK,QAAQ,EACb,WAAW,EACX,KAAK,YAAY,EACjB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAYhC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -51,6 +51,7 @@ export { RageTapCapture } from './rage-tap';
|
|
|
51
51
|
// Privacy: register a query returning nativeIDs that must be
|
|
52
52
|
// blacked out in every captured frame (visual replay, screenshots).
|
|
53
53
|
export { registerMaskQuery } from './mask';
|
|
54
|
+
export { launch } from './launch';
|
|
54
55
|
// Dev-panel helper: crash the native layer on purpose to exercise
|
|
55
56
|
// the pending-crash upload pipeline. Not part of the 8-verb surface.
|
|
56
57
|
export { triggerNativeCrash } from './native';
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,8CAA8C;AAC9C,EAAE;AACF,gEAAgE;AAChE,oEAAoE;AACpE,qEAAqE;AACrE,8DAA8D;AAE9D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAShC,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,2DAA2D;IAC3D,IAAI,EAAE,CAAC,MAAkB,EAAQ,EAAE;QACjC,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC;IACD;;4CAEwC;IACxC,IAAI,EAAE,CAAC,CAAc,EAAQ,EAAE;QAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;IACD;8CAC0C;IAC1C,OAAO,EAAE,CAAC,KAA8B,EAAQ,EAAE;QAChD,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED;sEACkE;IAClE,KAAK,EAAE,CAAC,GAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;IACzE,kDAAkD;IAClD,IAAI,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;IACxE;6DACyD;IACzD,KAAK,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAE,IAAmB,EAAU,EAAE,CACrE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC/B;;mDAE+C;IAC/C,MAAM,EAAE,CAAC,IAAY,EAAE,EAAW,EAAE,IAAgB,EAAU,EAAE,CAC9D,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC;IAC9B;;qCAEiC;IACjC,KAAK,EAAE,CAAC,GAAW,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;CACzE,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,6DAA6D;AAC7D,oEAAoE;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,kEAAkE;AAClE,qEAAqE;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAoB1E,mDAAmD;AACnD,OAAO,EACL,WAAW,EAEX,WAAW,EAEX,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,mEAAmE;AACnE,+DAA+D;AAC/D,oEAAoE;AACpE,6DAA6D;AAC7D,EAAE;AACF,+CAA+C;AAC/C,mEAAmE;AACnE,iEAAiE;AACjE,wDAAwD;AACxD,yDAAyD;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,qEAAqE;AACrE,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,8CAA8C;AAC9C,EAAE;AACF,gEAAgE;AAChE,oEAAoE;AACpE,qEAAqE;AACrE,8DAA8D;AAE9D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAShC,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,2DAA2D;IAC3D,IAAI,EAAE,CAAC,MAAkB,EAAQ,EAAE;QACjC,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC;IACD;;4CAEwC;IACxC,IAAI,EAAE,CAAC,CAAc,EAAQ,EAAE;QAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;IACD;8CAC0C;IAC1C,OAAO,EAAE,CAAC,KAA8B,EAAQ,EAAE;QAChD,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED;sEACkE;IAClE,KAAK,EAAE,CAAC,GAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;IACzE,kDAAkD;IAClD,IAAI,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;IACxE;6DACyD;IACzD,KAAK,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAE,IAAmB,EAAU,EAAE,CACrE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC/B;;mDAE+C;IAC/C,MAAM,EAAE,CAAC,IAAY,EAAE,EAAW,EAAE,IAAgB,EAAU,EAAE,CAC9D,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC;IAC9B;;qCAEiC;IACjC,KAAK,EAAE,CAAC,GAAW,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;CACzE,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,6DAA6D;AAC7D,oEAAoE;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,kEAAkE;AAClE,qEAAqE;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAoB1E,mDAAmD;AACnD,OAAO,EACL,WAAW,EAEX,WAAW,EAEX,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,mEAAmE;AACnE,+DAA+D;AAC/D,oEAAoE;AACpE,6DAA6D;AAC7D,EAAE;AACF,+CAA+C;AAC/C,mEAAmE;AACnE,iEAAiE;AACjE,wDAAwD;AACxD,yDAAyD;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,qEAAqE;AACrE,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
|
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;
|
|
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"}
|
package/lib/init.js
CHANGED
|
@@ -11,6 +11,7 @@ import { installNetworkHandler } from './handlers/network';
|
|
|
11
11
|
import { installPromiseHandler } from './handlers/promise';
|
|
12
12
|
import { startLongTaskMonitor } from './long-task-monitor';
|
|
13
13
|
import { checkColdStart } from './mobile-vitals';
|
|
14
|
+
import { armLaunch } from './launch';
|
|
14
15
|
import { markNativeJsBridgeReady, setNativeConfig } from './native';
|
|
15
16
|
import { shipNativePending } from './native-pending';
|
|
16
17
|
import { drainReplay, startReplay } from './replay';
|
|
@@ -99,6 +100,7 @@ export const init = safeFn('init', (config) => {
|
|
|
99
100
|
markNativeJsBridgeReady();
|
|
100
101
|
startTransport();
|
|
101
102
|
checkColdStart(config.detect?.slowColdStart !== false);
|
|
103
|
+
armLaunch();
|
|
102
104
|
void shipNativePending().catch(() => undefined);
|
|
103
105
|
void drainOfflineQueue();
|
|
104
106
|
});
|
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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"}
|
package/lib/launch.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Called from init(): anchors the JS side of the staged timeline. */
|
|
2
|
+
export declare function armLaunch(): void;
|
|
3
|
+
/** The staged-launch surface: `sentori.launch.mark/complete`. */
|
|
4
|
+
export declare const launch: {
|
|
5
|
+
complete: () => void | undefined;
|
|
6
|
+
mark: (name: string) => void | undefined;
|
|
7
|
+
};
|
|
8
|
+
/** Test-only. */
|
|
9
|
+
export declare function __resetLaunchForTests(): void;
|
|
10
|
+
//# sourceMappingURL=launch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../src/launch.ts"],"names":[],"mappings":"AA8BA,sEAAsE;AACtE,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAqCD,iEAAiE;AACjE,eAAO,MAAM,MAAM;;;CAAqB,CAAC;AAEzC,iBAAiB;AACjB,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C"}
|
package/lib/launch.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Staged launch measurement (insight QIP-8 #2).
|
|
2
|
+
//
|
|
3
|
+
// One scalar closing at JS init() cannot represent user-perceived
|
|
4
|
+
// launch: apps that defer init() off the critical path get a number
|
|
5
|
+
// that is neither time-to-first-frame nor time-to-usable, and
|
|
6
|
+
// everything after init (bootstrap, splash-hide, first data) is
|
|
7
|
+
// invisible. This is the staged shape instead:
|
|
8
|
+
//
|
|
9
|
+
// native anchors (process start → JS ready, from mobile vitals)
|
|
10
|
+
// + sentori.launch.mark(name) — app-defined waypoints
|
|
11
|
+
// + sentori.launch.complete() — the app's own "usable now"
|
|
12
|
+
//
|
|
13
|
+
// complete() emits ONE `app.launch` trace event with segment
|
|
14
|
+
// durations — it rides the existing event channel (batched, quiet
|
|
15
|
+
// network posture untouched) and aggregates like any trace. Apps
|
|
16
|
+
// that never call the marks keep today's behaviour exactly: no
|
|
17
|
+
// marks, no event.
|
|
18
|
+
//
|
|
19
|
+
// Same iron-rule surface as every verb: synchronous, O(1), never
|
|
20
|
+
// throws (safeFn), init-failure degrades to no-op.
|
|
21
|
+
import { safeFn } from '@goliapkg/sentori-core';
|
|
22
|
+
import { getColdStartMs, isColdStartPrewarmed } from './mobile-vitals';
|
|
23
|
+
import { trace } from './verbs';
|
|
24
|
+
let _armedAt = null;
|
|
25
|
+
let _marks = [];
|
|
26
|
+
let _completed = false;
|
|
27
|
+
/** Called from init(): anchors the JS side of the staged timeline. */
|
|
28
|
+
export function armLaunch() {
|
|
29
|
+
if (_armedAt === null)
|
|
30
|
+
_armedAt = Date.now();
|
|
31
|
+
}
|
|
32
|
+
const mark = safeFn('launch.mark', (name) => {
|
|
33
|
+
if (_completed || typeof name !== 'string' || name.length === 0)
|
|
34
|
+
return;
|
|
35
|
+
if (_marks.length >= 32)
|
|
36
|
+
return; // bounded, like every buffer
|
|
37
|
+
_marks.push({ at: Date.now(), name });
|
|
38
|
+
});
|
|
39
|
+
const complete = safeFn('launch.complete', () => {
|
|
40
|
+
if (_completed || _armedAt === null)
|
|
41
|
+
return;
|
|
42
|
+
_completed = true;
|
|
43
|
+
const completeAt = Date.now();
|
|
44
|
+
const coldMs = getColdStartMs();
|
|
45
|
+
const prewarmed = isColdStartPrewarmed();
|
|
46
|
+
// Segment durations, in narrative order: the native span first
|
|
47
|
+
// (process start → JS ready), then each waypoint since init, then
|
|
48
|
+
// the tail up to complete().
|
|
49
|
+
const segments = [];
|
|
50
|
+
if (coldMs !== null)
|
|
51
|
+
segments.push({ ms: Math.round(coldMs), name: 'native' });
|
|
52
|
+
let prev = _armedAt;
|
|
53
|
+
for (const m of _marks.sort((a, b) => a.at - b.at)) {
|
|
54
|
+
segments.push({ ms: Math.max(0, m.at - prev), name: m.name });
|
|
55
|
+
prev = m.at;
|
|
56
|
+
}
|
|
57
|
+
segments.push({ ms: Math.max(0, completeAt - prev), name: 'complete' });
|
|
58
|
+
const jsMs = completeAt - _armedAt;
|
|
59
|
+
const totalMs = Math.round((coldMs ?? 0) + jsMs);
|
|
60
|
+
trace('app.launch', {
|
|
61
|
+
totalMs,
|
|
62
|
+
...(coldMs !== null ? { coldStartMs: Math.round(coldMs) } : { jsOnly: true }),
|
|
63
|
+
...(prewarmed ? { prewarmed: true } : {}),
|
|
64
|
+
segments,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
/** The staged-launch surface: `sentori.launch.mark/complete`. */
|
|
68
|
+
export const launch = { complete, mark };
|
|
69
|
+
/** Test-only. */
|
|
70
|
+
export function __resetLaunchForTests() {
|
|
71
|
+
_armedAt = null;
|
|
72
|
+
_marks = [];
|
|
73
|
+
_completed = false;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=launch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.js","sourceRoot":"","sources":["../src/launch.ts"],"names":[],"mappings":"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"}
|
package/lib/mobile-vitals.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** Read the native-side cold start measurement once. Cached. */
|
|
2
2
|
export declare function getColdStartMs(): null | number;
|
|
3
|
-
/**
|
|
3
|
+
/** Whether the cached measurement is a pre-warmed phantom. Only
|
|
4
|
+
* meaningful after getColdStartMs() ran. */
|
|
5
|
+
export declare function isColdStartPrewarmed(): boolean;
|
|
6
|
+
/** Called once from init(): signal always, warn when slow AND real. */
|
|
4
7
|
export declare function checkColdStart(detectEnabled: boolean): void;
|
|
5
8
|
/** Test-only. */
|
|
6
9
|
export declare function __resetMobileVitalsForTests(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-vitals.d.ts","sourceRoot":"","sources":["../src/mobile-vitals.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mobile-vitals.d.ts","sourceRoot":"","sources":["../src/mobile-vitals.ts"],"names":[],"mappings":"AA+BA,gEAAgE;AAChE,wBAAgB,cAAc,IAAI,IAAI,GAAG,MAAM,CAU9C;AAED;6CAC6C;AAC7C,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,aAAa,EAAE,OAAO,GAAG,IAAI,CAY3D;AAED,iBAAiB;AACjB,wBAAgB,2BAA2B,IAAI,IAAI,CAIlD"}
|
package/lib/mobile-vitals.js
CHANGED
|
@@ -6,13 +6,23 @@
|
|
|
6
6
|
// init() calls checkColdStart() once. > 3 s ⇒ one `warn` event,
|
|
7
7
|
// scenario `slow_cold_start`, with the measured ms. Always pushes a
|
|
8
8
|
// `lifecycle` signal so even a fast start shows on the timeline.
|
|
9
|
+
//
|
|
10
|
+
// Pre-warmed processes (iOS ActivePrewarm; Android background start
|
|
11
|
+
// — FCM data message, JobScheduler — with the first Activity
|
|
12
|
+
// arriving much later) produce phantom samples: the measured span
|
|
13
|
+
// is mostly idle background time, not launch. Those samples still
|
|
14
|
+
// ship, flagged `prewarmed: true`, so the field data stays honest
|
|
15
|
+
// and slicable — but they never fire the slow-start warn (insight
|
|
16
|
+
// QIP-8 #1; the Firebase Performance bug class).
|
|
17
|
+
//
|
|
9
18
|
// Graceful no-op when the native module isn't linked (Expo Go,
|
|
10
19
|
// tests).
|
|
11
20
|
import { pushSignal } from '@goliapkg/sentori-core';
|
|
12
|
-
import { getNativeColdStartMs } from './native';
|
|
21
|
+
import { getNativeColdStartMs, getNativeColdStartPrewarmed } from './native';
|
|
13
22
|
import { warnDetected } from './verbs';
|
|
14
23
|
const SLOW_COLD_START_MS = 3_000;
|
|
15
24
|
let _coldStartMs = null;
|
|
25
|
+
let _coldStartPrewarmed = false;
|
|
16
26
|
let _coldStartCaptured = false;
|
|
17
27
|
/** Read the native-side cold start measurement once. Cached. */
|
|
18
28
|
export function getColdStartMs() {
|
|
@@ -21,19 +31,30 @@ export function getColdStartMs() {
|
|
|
21
31
|
_coldStartCaptured = true;
|
|
22
32
|
try {
|
|
23
33
|
_coldStartMs = getNativeColdStartMs();
|
|
34
|
+
_coldStartPrewarmed = getNativeColdStartPrewarmed();
|
|
24
35
|
}
|
|
25
36
|
catch {
|
|
26
37
|
_coldStartMs = null;
|
|
27
38
|
}
|
|
28
39
|
return _coldStartMs;
|
|
29
40
|
}
|
|
30
|
-
/**
|
|
41
|
+
/** Whether the cached measurement is a pre-warmed phantom. Only
|
|
42
|
+
* meaningful after getColdStartMs() ran. */
|
|
43
|
+
export function isColdStartPrewarmed() {
|
|
44
|
+
return _coldStartPrewarmed;
|
|
45
|
+
}
|
|
46
|
+
/** Called once from init(): signal always, warn when slow AND real. */
|
|
31
47
|
export function checkColdStart(detectEnabled) {
|
|
32
48
|
const ms = getColdStartMs();
|
|
33
49
|
if (ms === null)
|
|
34
50
|
return;
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
const prewarmed = isColdStartPrewarmed();
|
|
52
|
+
pushSignal('lifecycle', {
|
|
53
|
+
phase: 'cold_start',
|
|
54
|
+
ms,
|
|
55
|
+
...(prewarmed ? { prewarmed: true } : {}),
|
|
56
|
+
});
|
|
57
|
+
if (detectEnabled && !prewarmed && ms > SLOW_COLD_START_MS) {
|
|
37
58
|
warnDetected('slow_cold_start', {}, { coldStartMs: ms, thresholdMs: SLOW_COLD_START_MS });
|
|
38
59
|
}
|
|
39
60
|
}
|
|
@@ -41,5 +62,6 @@ export function checkColdStart(detectEnabled) {
|
|
|
41
62
|
export function __resetMobileVitalsForTests() {
|
|
42
63
|
_coldStartCaptured = false;
|
|
43
64
|
_coldStartMs = null;
|
|
65
|
+
_coldStartPrewarmed = false;
|
|
44
66
|
}
|
|
45
67
|
//# sourceMappingURL=mobile-vitals.js.map
|
package/lib/mobile-vitals.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-vitals.js","sourceRoot":"","sources":["../src/mobile-vitals.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,cAAc;AACd,EAAE;AACF,6DAA6D;AAC7D,iEAAiE;AACjE,gEAAgE;AAChE,oEAAoE;AACpE,iEAAiE;AACjE,+DAA+D;AAC/D,UAAU;AAEV,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"mobile-vitals.js","sourceRoot":"","sources":["../src/mobile-vitals.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,cAAc;AACd,EAAE;AACF,6DAA6D;AAC7D,iEAAiE;AACjE,gEAAgE;AAChE,oEAAoE;AACpE,iEAAiE;AACjE,EAAE;AACF,oEAAoE;AACpE,6DAA6D;AAC7D,kEAAkE;AAClE,kEAAkE;AAClE,kEAAkE;AAClE,kEAAkE;AAClE,iDAAiD;AACjD,EAAE;AACF,+DAA+D;AAC/D,UAAU;AAEV,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,IAAI,YAAY,GAAkB,IAAI,CAAC;AACvC,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAChC,IAAI,kBAAkB,GAAG,KAAK,CAAC;AAE/B,gEAAgE;AAChE,MAAM,UAAU,cAAc;IAC5B,IAAI,kBAAkB;QAAE,OAAO,YAAY,CAAC;IAC5C,kBAAkB,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC;QACH,YAAY,GAAG,oBAAoB,EAAE,CAAC;QACtC,mBAAmB,GAAG,2BAA2B,EAAE,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;6CAC6C;AAC7C,MAAM,UAAU,oBAAoB;IAClC,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,aAAsB;IACnD,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC5B,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO;IACxB,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,UAAU,CAAC,WAAW,EAAE;QACtB,KAAK,EAAE,YAAY;QACnB,EAAE;QACF,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1C,CAAC,CAAC;IACH,IAAI,aAAa,IAAI,CAAC,SAAS,IAAI,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAC3D,YAAY,CAAC,iBAAiB,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,iBAAiB;AACjB,MAAM,UAAU,2BAA2B;IACzC,kBAAkB,GAAG,KAAK,CAAC;IAC3B,YAAY,GAAG,IAAI,CAAC;IACpB,mBAAmB,GAAG,KAAK,CAAC;AAC9B,CAAC"}
|
package/lib/native.d.ts
CHANGED
|
@@ -58,6 +58,10 @@ export declare function stopAnrWatchdog(): void;
|
|
|
58
58
|
export declare function markNativeJsBridgeReady(): void;
|
|
59
59
|
/** v0.9.4 #1 — read cold start ms once. null when native unavailable. */
|
|
60
60
|
export declare function getNativeColdStartMs(): null | number;
|
|
61
|
+
/** v5.6 — phantom-sample discriminator: the process was pre-warmed
|
|
62
|
+
* (iOS ActivePrewarm; Android background start with the first
|
|
63
|
+
* Activity arriving much later). Older binaries: false. */
|
|
64
|
+
export declare function getNativeColdStartPrewarmed(): boolean;
|
|
61
65
|
/** v0.9.4 #1 — read slow/frozen frame counters since last reset. */
|
|
62
66
|
export declare function getNativeFrameCounters(): null | {
|
|
63
67
|
frozen: number;
|
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":"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"}
|
package/lib/native.js
CHANGED
|
@@ -167,6 +167,17 @@ export function getNativeColdStartMs() {
|
|
|
167
167
|
return null;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
+
/** v5.6 — phantom-sample discriminator: the process was pre-warmed
|
|
171
|
+
* (iOS ActivePrewarm; Android background start with the first
|
|
172
|
+
* Activity arriving much later). Older binaries: false. */
|
|
173
|
+
export function getNativeColdStartPrewarmed() {
|
|
174
|
+
try {
|
|
175
|
+
return native()?.isColdStartPrewarmed?.() === true;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
170
181
|
/** v0.9.4 #1 — read slow/frozen frame counters since last reset. */
|
|
171
182
|
export function getNativeFrameCounters() {
|
|
172
183
|
try {
|
package/lib/native.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.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.
|
|
18
|
+
const SDK_VERSION = '5.6.1';
|
|
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.
|
|
3
|
+
"version": "5.6.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": "Apache-2.0 OR MIT",
|
|
6
6
|
"author": "GOLIA K.K. <takagi@golia.jp> (https://golia.jp)",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Staged launch measurement (QIP-8 #2): marks + complete emit ONE
|
|
2
|
+
// app.launch trace with segment durations; never before arm, never
|
|
3
|
+
// twice, never a throw.
|
|
4
|
+
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
|
6
|
+
|
|
7
|
+
import { clearSignals } from '@goliapkg/sentori-core';
|
|
8
|
+
|
|
9
|
+
import { __resetForTests as resetConfig, setConfig } from '../config';
|
|
10
|
+
import { __resetLaunchForTests, armLaunch, launch } from '../launch';
|
|
11
|
+
import { __resetMobileVitalsForTests } from '../mobile-vitals';
|
|
12
|
+
import { __resetForTests as resetScope } from '../scope';
|
|
13
|
+
import {
|
|
14
|
+
__peekQueue,
|
|
15
|
+
__resetForTests as resetTransport,
|
|
16
|
+
startTransport,
|
|
17
|
+
} from '../transport';
|
|
18
|
+
|
|
19
|
+
const baseConfig = {
|
|
20
|
+
token: 'st_test',
|
|
21
|
+
ingestUrl: 'http://localhost:18080',
|
|
22
|
+
release: 'app@1.0.0',
|
|
23
|
+
environment: 'test',
|
|
24
|
+
enabled: true,
|
|
25
|
+
detect: { rageTap: true, longFreeze: true, slowColdStart: true, slowApi: false },
|
|
26
|
+
replaySeconds: 30,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
describe('launch marks', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
resetTransport();
|
|
32
|
+
resetConfig();
|
|
33
|
+
resetScope();
|
|
34
|
+
clearSignals();
|
|
35
|
+
__resetLaunchForTests();
|
|
36
|
+
__resetMobileVitalsForTests();
|
|
37
|
+
setConfig(baseConfig);
|
|
38
|
+
startTransport();
|
|
39
|
+
});
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
resetTransport();
|
|
42
|
+
resetConfig();
|
|
43
|
+
resetScope();
|
|
44
|
+
clearSignals();
|
|
45
|
+
__resetLaunchForTests();
|
|
46
|
+
__resetMobileVitalsForTests();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const launchEvents = () =>
|
|
50
|
+
__peekQueue().filter((e) => e.kind === 'trace' && e.name === 'app.launch');
|
|
51
|
+
|
|
52
|
+
it('complete() before arm is a no-op (init never ran)', () => {
|
|
53
|
+
launch.mark('bootstrap');
|
|
54
|
+
launch.complete();
|
|
55
|
+
expect(launchEvents()).toHaveLength(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('arm → marks → complete emits one app.launch trace with ordered segments', () => {
|
|
59
|
+
armLaunch();
|
|
60
|
+
launch.mark('bootstrap');
|
|
61
|
+
launch.mark('first-tree');
|
|
62
|
+
launch.complete();
|
|
63
|
+
const evs = launchEvents();
|
|
64
|
+
expect(evs).toHaveLength(1);
|
|
65
|
+
const data = (evs[0]!.payload as { data?: Record<string, unknown> })?.data ?? {};
|
|
66
|
+
expect(typeof data.totalMs).toBe('number');
|
|
67
|
+
const segs = data.segments as { ms: number; name: string }[];
|
|
68
|
+
// no native module in tests → jsOnly, segments are the marks + tail
|
|
69
|
+
expect(data.jsOnly).toBe(true);
|
|
70
|
+
expect(segs.map((s) => s.name)).toEqual(['bootstrap', 'first-tree', 'complete']);
|
|
71
|
+
for (const s of segs) expect(s.ms).toBeGreaterThanOrEqual(0);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('complete() is once — the second call emits nothing', () => {
|
|
75
|
+
armLaunch();
|
|
76
|
+
launch.complete();
|
|
77
|
+
launch.mark('late'); // ignored after complete
|
|
78
|
+
launch.complete();
|
|
79
|
+
expect(launchEvents()).toHaveLength(1);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('never throws on garbage input', () => {
|
|
83
|
+
armLaunch();
|
|
84
|
+
expect(() => {
|
|
85
|
+
launch.mark(undefined as unknown as string);
|
|
86
|
+
launch.mark('');
|
|
87
|
+
launch.complete();
|
|
88
|
+
}).not.toThrow();
|
|
89
|
+
});
|
|
90
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -65,6 +65,7 @@ export { RageTapCapture } from './rage-tap';
|
|
|
65
65
|
// Privacy: register a query returning nativeIDs that must be
|
|
66
66
|
// blacked out in every captured frame (visual replay, screenshots).
|
|
67
67
|
export { registerMaskQuery } from './mask';
|
|
68
|
+
export { launch } from './launch';
|
|
68
69
|
// Dev-panel helper: crash the native layer on purpose to exercise
|
|
69
70
|
// the pending-crash upload pipeline. Not part of the 8-verb surface.
|
|
70
71
|
export { triggerNativeCrash } from './native';
|
package/src/init.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { installNetworkHandler } from './handlers/network';
|
|
|
14
14
|
import { installPromiseHandler } from './handlers/promise';
|
|
15
15
|
import { startLongTaskMonitor } from './long-task-monitor';
|
|
16
16
|
import { checkColdStart } from './mobile-vitals';
|
|
17
|
+
import { armLaunch } from './launch';
|
|
17
18
|
import { markNativeJsBridgeReady, setNativeConfig } from './native';
|
|
18
19
|
import { shipNativePending } from './native-pending';
|
|
19
20
|
import { drainReplay, startReplay } from './replay';
|
|
@@ -107,6 +108,7 @@ export const init = safeFn('init', (config: InitConfig): void => {
|
|
|
107
108
|
|
|
108
109
|
startTransport();
|
|
109
110
|
checkColdStart(config.detect?.slowColdStart !== false);
|
|
111
|
+
armLaunch();
|
|
110
112
|
void shipNativePending().catch(() => undefined);
|
|
111
113
|
void drainOfflineQueue();
|
|
112
114
|
});
|
package/src/launch.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Staged launch measurement (insight QIP-8 #2).
|
|
2
|
+
//
|
|
3
|
+
// One scalar closing at JS init() cannot represent user-perceived
|
|
4
|
+
// launch: apps that defer init() off the critical path get a number
|
|
5
|
+
// that is neither time-to-first-frame nor time-to-usable, and
|
|
6
|
+
// everything after init (bootstrap, splash-hide, first data) is
|
|
7
|
+
// invisible. This is the staged shape instead:
|
|
8
|
+
//
|
|
9
|
+
// native anchors (process start → JS ready, from mobile vitals)
|
|
10
|
+
// + sentori.launch.mark(name) — app-defined waypoints
|
|
11
|
+
// + sentori.launch.complete() — the app's own "usable now"
|
|
12
|
+
//
|
|
13
|
+
// complete() emits ONE `app.launch` trace event with segment
|
|
14
|
+
// durations — it rides the existing event channel (batched, quiet
|
|
15
|
+
// network posture untouched) and aggregates like any trace. Apps
|
|
16
|
+
// that never call the marks keep today's behaviour exactly: no
|
|
17
|
+
// marks, no event.
|
|
18
|
+
//
|
|
19
|
+
// Same iron-rule surface as every verb: synchronous, O(1), never
|
|
20
|
+
// throws (safeFn), init-failure degrades to no-op.
|
|
21
|
+
|
|
22
|
+
import { safeFn } from '@goliapkg/sentori-core';
|
|
23
|
+
|
|
24
|
+
import { getColdStartMs, isColdStartPrewarmed } from './mobile-vitals';
|
|
25
|
+
import { trace } from './verbs';
|
|
26
|
+
|
|
27
|
+
let _armedAt: null | number = null;
|
|
28
|
+
let _marks: { name: string; at: number }[] = [];
|
|
29
|
+
let _completed = false;
|
|
30
|
+
|
|
31
|
+
/** Called from init(): anchors the JS side of the staged timeline. */
|
|
32
|
+
export function armLaunch(): void {
|
|
33
|
+
if (_armedAt === null) _armedAt = Date.now();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const mark = safeFn('launch.mark', (name: string): void => {
|
|
37
|
+
if (_completed || typeof name !== 'string' || name.length === 0) return;
|
|
38
|
+
if (_marks.length >= 32) return; // bounded, like every buffer
|
|
39
|
+
_marks.push({ at: Date.now(), name });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const complete = safeFn('launch.complete', (): void => {
|
|
43
|
+
if (_completed || _armedAt === null) return;
|
|
44
|
+
_completed = true;
|
|
45
|
+
const completeAt = Date.now();
|
|
46
|
+
const coldMs = getColdStartMs();
|
|
47
|
+
const prewarmed = isColdStartPrewarmed();
|
|
48
|
+
|
|
49
|
+
// Segment durations, in narrative order: the native span first
|
|
50
|
+
// (process start → JS ready), then each waypoint since init, then
|
|
51
|
+
// the tail up to complete().
|
|
52
|
+
const segments: { ms: number; name: string }[] = [];
|
|
53
|
+
if (coldMs !== null) segments.push({ ms: Math.round(coldMs), name: 'native' });
|
|
54
|
+
let prev = _armedAt;
|
|
55
|
+
for (const m of _marks.sort((a, b) => a.at - b.at)) {
|
|
56
|
+
segments.push({ ms: Math.max(0, m.at - prev), name: m.name });
|
|
57
|
+
prev = m.at;
|
|
58
|
+
}
|
|
59
|
+
segments.push({ ms: Math.max(0, completeAt - prev), name: 'complete' });
|
|
60
|
+
|
|
61
|
+
const jsMs = completeAt - _armedAt;
|
|
62
|
+
const totalMs = Math.round((coldMs ?? 0) + jsMs);
|
|
63
|
+
trace('app.launch', {
|
|
64
|
+
totalMs,
|
|
65
|
+
...(coldMs !== null ? { coldStartMs: Math.round(coldMs) } : { jsOnly: true }),
|
|
66
|
+
...(prewarmed ? { prewarmed: true } : {}),
|
|
67
|
+
segments,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
/** The staged-launch surface: `sentori.launch.mark/complete`. */
|
|
72
|
+
export const launch = { complete, mark };
|
|
73
|
+
|
|
74
|
+
/** Test-only. */
|
|
75
|
+
export function __resetLaunchForTests(): void {
|
|
76
|
+
_armedAt = null;
|
|
77
|
+
_marks = [];
|
|
78
|
+
_completed = false;
|
|
79
|
+
}
|
package/src/mobile-vitals.ts
CHANGED
|
@@ -6,17 +6,27 @@
|
|
|
6
6
|
// init() calls checkColdStart() once. > 3 s ⇒ one `warn` event,
|
|
7
7
|
// scenario `slow_cold_start`, with the measured ms. Always pushes a
|
|
8
8
|
// `lifecycle` signal so even a fast start shows on the timeline.
|
|
9
|
+
//
|
|
10
|
+
// Pre-warmed processes (iOS ActivePrewarm; Android background start
|
|
11
|
+
// — FCM data message, JobScheduler — with the first Activity
|
|
12
|
+
// arriving much later) produce phantom samples: the measured span
|
|
13
|
+
// is mostly idle background time, not launch. Those samples still
|
|
14
|
+
// ship, flagged `prewarmed: true`, so the field data stays honest
|
|
15
|
+
// and slicable — but they never fire the slow-start warn (insight
|
|
16
|
+
// QIP-8 #1; the Firebase Performance bug class).
|
|
17
|
+
//
|
|
9
18
|
// Graceful no-op when the native module isn't linked (Expo Go,
|
|
10
19
|
// tests).
|
|
11
20
|
|
|
12
21
|
import { pushSignal } from '@goliapkg/sentori-core';
|
|
13
22
|
|
|
14
|
-
import { getNativeColdStartMs } from './native';
|
|
23
|
+
import { getNativeColdStartMs, getNativeColdStartPrewarmed } from './native';
|
|
15
24
|
import { warnDetected } from './verbs';
|
|
16
25
|
|
|
17
26
|
const SLOW_COLD_START_MS = 3_000;
|
|
18
27
|
|
|
19
28
|
let _coldStartMs: null | number = null;
|
|
29
|
+
let _coldStartPrewarmed = false;
|
|
20
30
|
let _coldStartCaptured = false;
|
|
21
31
|
|
|
22
32
|
/** Read the native-side cold start measurement once. Cached. */
|
|
@@ -25,18 +35,30 @@ export function getColdStartMs(): null | number {
|
|
|
25
35
|
_coldStartCaptured = true;
|
|
26
36
|
try {
|
|
27
37
|
_coldStartMs = getNativeColdStartMs();
|
|
38
|
+
_coldStartPrewarmed = getNativeColdStartPrewarmed();
|
|
28
39
|
} catch {
|
|
29
40
|
_coldStartMs = null;
|
|
30
41
|
}
|
|
31
42
|
return _coldStartMs;
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
/**
|
|
45
|
+
/** Whether the cached measurement is a pre-warmed phantom. Only
|
|
46
|
+
* meaningful after getColdStartMs() ran. */
|
|
47
|
+
export function isColdStartPrewarmed(): boolean {
|
|
48
|
+
return _coldStartPrewarmed;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Called once from init(): signal always, warn when slow AND real. */
|
|
35
52
|
export function checkColdStart(detectEnabled: boolean): void {
|
|
36
53
|
const ms = getColdStartMs();
|
|
37
54
|
if (ms === null) return;
|
|
38
|
-
|
|
39
|
-
|
|
55
|
+
const prewarmed = isColdStartPrewarmed();
|
|
56
|
+
pushSignal('lifecycle', {
|
|
57
|
+
phase: 'cold_start',
|
|
58
|
+
ms,
|
|
59
|
+
...(prewarmed ? { prewarmed: true } : {}),
|
|
60
|
+
});
|
|
61
|
+
if (detectEnabled && !prewarmed && ms > SLOW_COLD_START_MS) {
|
|
40
62
|
warnDetected('slow_cold_start', {}, { coldStartMs: ms, thresholdMs: SLOW_COLD_START_MS });
|
|
41
63
|
}
|
|
42
64
|
}
|
|
@@ -45,4 +67,5 @@ export function checkColdStart(detectEnabled: boolean): void {
|
|
|
45
67
|
export function __resetMobileVitalsForTests(): void {
|
|
46
68
|
_coldStartCaptured = false;
|
|
47
69
|
_coldStartMs = null;
|
|
70
|
+
_coldStartPrewarmed = false;
|
|
48
71
|
}
|
package/src/native.ts
CHANGED
|
@@ -22,6 +22,7 @@ type SentoriNativeModule = {
|
|
|
22
22
|
* Returns null when native side hasn't captured yet.
|
|
23
23
|
*/
|
|
24
24
|
getColdStartMs?: () => null | number
|
|
25
|
+
isColdStartPrewarmed?: () => boolean
|
|
25
26
|
/**
|
|
26
27
|
* v0.9.4 #1 — call once at JS init() to finalize the cold-start
|
|
27
28
|
* measurement. iOS subtracts from the app-delegate anchor;
|
|
@@ -349,6 +350,17 @@ export function getNativeColdStartMs(): null | number {
|
|
|
349
350
|
}
|
|
350
351
|
}
|
|
351
352
|
|
|
353
|
+
/** v5.6 — phantom-sample discriminator: the process was pre-warmed
|
|
354
|
+
* (iOS ActivePrewarm; Android background start with the first
|
|
355
|
+
* Activity arriving much later). Older binaries: false. */
|
|
356
|
+
export function getNativeColdStartPrewarmed(): boolean {
|
|
357
|
+
try {
|
|
358
|
+
return native()?.isColdStartPrewarmed?.() === true
|
|
359
|
+
} catch {
|
|
360
|
+
return false
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
352
364
|
/** v0.9.4 #1 — read slow/frozen frame counters since last reset. */
|
|
353
365
|
export function getNativeFrameCounters(): null | { frozen: number; slow: number } {
|
|
354
366
|
try {
|
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.
|
|
23
|
+
const SDK_VERSION = '5.6.1';
|
|
24
24
|
|
|
25
25
|
let _queue: WireEvent[] = [];
|
|
26
26
|
let _assertStats = new Map<string, AssertStat>();
|