@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 CHANGED
@@ -5,11 +5,24 @@ self-hosted crash + warning monitor for mobile apps. JS layer +
5
5
  iOS Swift + Android Kotlin native, distributed as an Expo module
6
6
  (works on bare RN too).
7
7
 
8
- Eight verbs are the whole API. Every one is synchronous, returns
9
- immediately, and can never throw into your app.
8
+ Eight verbs are the whole API.
10
9
 
11
10
  Upgrading from 4.x? See [MIGRATION.md](./MIGRATION.md).
12
11
 
12
+ ## The zero-cost contract
13
+
14
+ Sentori must only ever be a free upgrade for your app:
15
+
16
+ - **Every call is synchronous, O(1), and can never throw.** Not on
17
+ garbage input, not when the network is down, not when the server
18
+ is gone. You never need a try/catch around a Sentori call.
19
+ - `init()` failure (bad token, missing URL) degrades every verb to
20
+ a no-op with one console.warn — never a crash, never a red box.
21
+ - Nothing leaves the device until an error/warn actually fires;
22
+ then one batched request carries the event with its context.
23
+ - Buffers (signal ring, replay rings, offline queue) are all
24
+ hard-bounded.
25
+
13
26
  ## Install
14
27
 
15
28
  ```sh
@@ -26,11 +39,15 @@ sentori.init({
26
39
  token: 'st_…', // ingest token, Settings → Tokens
27
40
  ingestUrl: 'https://sentori.example.com',
28
41
  release: 'my-app@1.2.3',
29
- environment: 'prod',
42
+ environment: 'production', // the DEPLOYMENT environment
43
+ replayScreens: true, // opt-in visual replay (v5.1)
44
+ backendHealthUrl: 'https://api.example.com/healthz', // v5.2, see below
30
45
  })
31
46
 
32
47
  sentori.user({ id, email, name }) // drives breadth × depth stats
33
- sentori.context({ tenant: 'acme' }) // ambient tags on every event
48
+ sentori.context({ build: 'release', tenant: 'acme' }) // ambient tags;
49
+ // every key becomes a queue
50
+ // slicing dimension on the board
34
51
 
35
52
  sentori.error(new Error('boom')) // what broke
36
53
  sentori.warn('pay.gateway-retry', data) // where users hurt
@@ -45,14 +62,59 @@ Auto-wired (no configuration):
45
62
  - iOS `NSException` + Android uncaught-exception handlers
46
63
  - Warn scenario detectors: rage taps, long freezes, slow cold start
47
64
  (slow API stays opt-in) — tune with `init({ detect })`
48
- - Signal ring: recent taps, navigation, traces ride along on every
49
- error/warn as the "what the user was doing" timeline
65
+ - Signal ring: the last 60 s of taps (with coordinates), navigation,
66
+ http and traces ride along on every error/warn as the "what the
67
+ user was doing" timeline
50
68
  - B-type replay: rolling wireframe buffer, shipped only when an
51
- error/warn actually fires (`init({ replaySeconds })`)
69
+ error/warn actually fires (`init({ replaySeconds })`); opt-in
70
+ pixel replay via `replayScreens: true`, with native-side masking
71
+ (`registerMaskQuery`) so tagged views never exist in any frame
72
+ - Cold-start measurement with a pre-warm guard: processes started
73
+ in the background (FCM, JobScheduler, iOS prewarming) are flagged
74
+ and never counted as slow starts
52
75
 
53
76
  Identity is hashed on-device with a salted hash — the server never
54
77
  sees the raw email.
55
78
 
79
+ ## Launch measurement (v5.6)
80
+
81
+ One number ending at `init()` cannot represent user-perceived
82
+ launch. Stage it instead:
83
+
84
+ ```tsx
85
+ sentori.launch.mark('bootstrap') // optional waypoints, anywhere
86
+ sentori.launch.mark('first-tree')
87
+ sentori.launch.complete() // when YOUR app counts as usable
88
+ ```
89
+
90
+ `complete()` emits one `app.launch` trace with segment durations
91
+ (native span → each waypoint → complete). The dashboard's
92
+ Instruments page aggregates p50/p90/p95 per release from it. Apps
93
+ that never call the marks keep the plain cold-start behaviour.
94
+
95
+ ## Custom breadcrumbs (v5.5)
96
+
97
+ Feed your own context into the signal ring — same fire-and-forget
98
+ guarantees as the verbs:
99
+
100
+ ```tsx
101
+ import { pushSignal } from '@goliapkg/sentori-react-native'
102
+
103
+ // in your API interceptor — the one place that knows which
104
+ // requests matter (Sentori deliberately does not patch fetch/XHR):
105
+ pushSignal('http', { method, url, status, ms }) // status 0 = no response
106
+ ```
107
+
108
+ `http` entries render as request lines on the case timeline; any
109
+ other kind renders with its data as key=value pairs.
110
+
111
+ ## Backend availability (v5.2)
112
+
113
+ `init({ backendHealthUrl })` — the URL rides along with event
114
+ batches (the app itself never pings anything); the Sentori server
115
+ probes it once a minute and shows uptime + latency on the project
116
+ card.
117
+
56
118
  ## React extras
57
119
 
58
120
  ```tsx
@@ -60,14 +122,16 @@ import {
60
122
  ErrorBoundary, // React idiom for the error verb
61
123
  RageTapCapture, // wrap your root to feed the rage-tap detector
62
124
  useTraceNavigation, // pass your react-navigation ref
125
+ registerMaskQuery, // nativeIDs to black out in every captured frame
63
126
  } from '@goliapkg/sentori-react-native'
64
127
  ```
65
128
 
66
129
  ## Build pipeline
67
130
 
68
- `@goliapkg/sentori-cli` uploads sourcemaps (failures never block a
69
- release — friendly notice, exit 0) and registers `probe()`
70
- tripwires per release. See MIGRATION.md §6.
131
+ `@goliapkg/sentori-cli` uploads sourcemaps, dSYMs, Proguard maps
132
+ and native source bundles (failures never block a release —
133
+ friendly notice, exit 0) and registers `probe()` tripwires per
134
+ release. See MIGRATION.md §6.
71
135
 
72
136
  ## License
73
137
 
@@ -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)
@@ -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';
@@ -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;AAG3C,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"}
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;AAkBzD,eAAO,MAAM,IAAI,0CAuFf,CAAC;AAGH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;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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"}
@@ -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":"AAAA,gDAAgD;AAChD,EAAE;AACF,kEAAkE;AAClE,oEAAoE;AACpE,8DAA8D;AAC9D,gEAAgE;AAChE,+CAA+C;AAC/C,EAAE;AACF,kEAAkE;AAClE,0DAA0D;AAC1D,+DAA+D;AAC/D,EAAE;AACF,6DAA6D;AAC7D,kEAAkE;AAClE,iEAAiE;AACjE,+DAA+D;AAC/D,mBAAmB;AACnB,EAAE;AACF,iEAAiE;AACjE,mDAAmD;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,IAAI,QAAQ,GAAkB,IAAI,CAAC;AACnC,IAAI,MAAM,GAAmC,EAAE,CAAC;AAChD,IAAI,UAAU,GAAG,KAAK,CAAC;AAEvB,sEAAsE;AACtE,MAAM,UAAU,SAAS;IACvB,IAAI,QAAQ,KAAK,IAAI;QAAE,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,IAAY,EAAQ,EAAE;IACxD,IAAI,UAAU,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACxE,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,CAAC,6BAA6B;IAC9D,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,iBAAiB,EAAE,GAAS,EAAE;IACpD,IAAI,UAAU,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO;IAC5C,UAAU,GAAG,IAAI,CAAC;IAClB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IAEzC,+DAA+D;IAC/D,kEAAkE;IAClE,6BAA6B;IAC7B,MAAM,QAAQ,GAAmC,EAAE,CAAC;IACpD,IAAI,MAAM,KAAK,IAAI;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/E,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;IACd,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAExE,MAAM,IAAI,GAAG,UAAU,GAAG,QAAQ,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjD,KAAK,CAAC,YAAY,EAAE;QAClB,OAAO;QACP,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC7E,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,QAAQ;KACT,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAEzC,iBAAiB;AACjB,MAAM,UAAU,qBAAqB;IACnC,QAAQ,GAAG,IAAI,CAAC;IAChB,MAAM,GAAG,EAAE,CAAC;IACZ,UAAU,GAAG,KAAK,CAAC;AACrB,CAAC"}
@@ -1,6 +1,9 @@
1
1
  /** Read the native-side cold start measurement once. Cached. */
2
2
  export declare function getColdStartMs(): null | number;
3
- /** Called once from init(): signal always, warn when slow. */
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":"AAqBA,gEAAgE;AAChE,wBAAgB,cAAc,IAAI,IAAI,GAAG,MAAM,CAS9C;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,aAAa,EAAE,OAAO,GAAG,IAAI,CAO3D;AAED,iBAAiB;AACjB,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}
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"}
@@ -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
- /** Called once from init(): signal always, warn when slow. */
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
- pushSignal('lifecycle', { phase: 'cold_start', ms });
36
- if (detectEnabled && ms > SLOW_COLD_START_MS) {
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
@@ -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;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,IAAI,YAAY,GAAkB,IAAI,CAAC;AACvC,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;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,aAAsB;IACnD,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC5B,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO;IACxB,UAAU,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;IACrD,IAAI,aAAa,IAAI,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAC7C,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;AACtB,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;
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkMH,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;AAID;gEACgE;AAChE,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAQ5D;AAED;yCACyC;AACzC,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAQpE;AAED,wBAAgB,YAAY,IAAI,IAAI,CAMnC;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC7C,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACrC,CAAA;AAED;8CAC8C;AAC9C,wBAAsB,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC,CAU9D;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;AAiBD,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB/E;AAED,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,CAoBvD;AAED;;sEAEsE;AACtE,wBAAgB,uBAAuB,IAAI;IACzC,KAAK,EAAE,OAAO,CAAA;IACd,mBAAmB,EAAE,OAAO,CAAA;IAC5B,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAOA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB;;+DAE2D;IAC3D,YAAY,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAA;IACrB;2CACuC;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B,CA+CA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,IAAI;IACvC,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B,CAeA"}
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":"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"}
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.5.0';
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.5.0",
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
+ }
@@ -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
- /** Called once from init(): signal always, warn when slow. */
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
- pushSignal('lifecycle', { phase: 'cold_start', ms });
39
- if (detectEnabled && ms > SLOW_COLD_START_MS) {
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.5.0';
23
+ const SDK_VERSION = '5.6.1';
24
24
 
25
25
  let _queue: WireEvent[] = [];
26
26
  let _assertStats = new Map<string, AssertStat>();