@goliapkg/sentori-react-native 5.4.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,9 +31,11 @@ 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';
37
38
  export { getLogLevel, type LogLevel, setLogLevel, type LogTransport, setLogTransport, } from '@goliapkg/sentori-core';
39
+ export { pushSignal } from '@goliapkg/sentori-core';
38
40
  export * as push from './push';
39
41
  //# sourceMappingURL=index.d.ts.map
@@ -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;AAGhC,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,12 +51,24 @@ 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';
57
58
  export { useTraceNavigation } from './navigation';
58
59
  // Logger gate, for hosts debugging Sentori itself.
59
60
  export { getLogLevel, setLogLevel, setLogTransport, } from '@goliapkg/sentori-core';
61
+ // The signal channel, for hosts feeding their own breadcrumbs into
62
+ // the ring (insight round-4 §4). Same O(1) fire-and-forget the
63
+ // auto signals use; entries ride payload.signals when an error/warn
64
+ // fires and appear on the case timeline + user-events panel.
65
+ //
66
+ // Field conventions the dashboard understands:
67
+ // pushSignal('http', { method, url, status, ms }) — a request's
68
+ // outcome (host's own interceptor is the right producer; the
69
+ // SDK deliberately does not monkey-patch fetch/XHR)
70
+ // any other kind renders with its data as `k=v` pairs.
71
+ export { pushSignal } from '@goliapkg/sentori-core';
60
72
  // Push namespace — carried as-is; outside the v1 acceptance surface.
61
73
  export * as push from './push';
62
74
  //# sourceMappingURL=index.js.map
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,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":"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"}
@@ -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":"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"}
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":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAwK/C,IAAI,OAA+C,CAAA;AAEnD,SAAS,MAAM;IACb,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAA;IACzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,mBAAmB,CAEvC,CAAA;QACD,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAsB,SAAS,CAAC,CAAA;QAClE,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YAClE,8DAA8D;YAC9D,8DAA8D;YAC9D,8DAA8D;YAC9D,4DAA4D;YAC5D,+BAA+B;YAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAiB,CAAC,CAAC,IAAI,EAAE,CAAA;YAClD,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,wBAAwB,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,CAAA;QAC/E,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,GAAG,IAAI,CAAA;QACd,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,sCAAsC,EAAE,CAAC,CAAC,CAAA;IACnE,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAI/B;IACC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACjB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,YAAY,EAAE,CAAA;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,sBAAsB,EAAE,EAAE,CAAA;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAIhC;IACC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,gBAAgB,EAAE,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;AACH,CAAC;AAED,mEAAmE;AAEnE;gEACgE;AAChE,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,EAAE,aAAa;QAAE,OAAO,IAAI,CAAA;IAClC,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,aAAa,EAAE,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;yCACyC;AACzC,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,EAAE,qBAAqB;QAAE,OAAO,IAAI,CAAA;IAC1C,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,qBAAqB,EAAE,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,YAAY,EAAE,EAAE,CAAA;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,cAAc,EAAE,EAAE,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;AACH,CAAC;AASD;8CAC8C;AAC9C,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;QACvB,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;IACxC,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,cAAc,EAAE,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;IACxC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,eAAe,EAAE,EAAE,CAAA;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,uBAAuB;IACrC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,iBAAiB,EAAE,EAAE,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,oBAAoB;IAClC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,EAAE,EAAE,cAAc,EAAE,EAAE,CAAA;QACtC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;4DAE4D;AAC5D,MAAM,UAAU,2BAA2B;IACzC,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,oBAAoB,EAAE,EAAE,KAAK,IAAI,CAAA;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,sBAAsB;IACpC,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,gBAAgB,EAAE,EAAE,IAAI,IAAI,CAAA;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,wBAAwB;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,kBAAkB,EAAE,EAAE,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED;;yBAEyB;AACzB,MAAM,UAAU,wBAAwB;IAMtC,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,wBAAwB,EAAE,EAAE,IAAI,IAAI,CAAA;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH;;uEAEuE;AACvE,IAAI,mBAAmB,GAAG,KAAK,CAAA;AAC/B,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,SAAmB,EACnB,UAAkB,EAClB,OAAe;IAEf,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnB,IAAI,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC;QAC1B,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACzB,mBAAmB,GAAG,IAAI,CAAA;YAC1B,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,uEAAuE,CAAC,CAAA;QAChG,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,IAAI,CAAA;IAC7E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAA;QACpD,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,SAAmB;IAEnB,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,yDAAyD,CAAC,CAAA;QAChF,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC,CAAC,CAAC,yBAAyB,EAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,8DAA8D,CAAC,CAAA;QACrF,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAA;QACtD,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,0DAA0D,CAAC,CAAA;QACpF,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAA;QAC5C,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;sEAEsE;AACtE,MAAM,UAAU,uBAAuB;IAKrC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,OAAO;QACL,KAAK,EAAE,CAAC,KAAK,IAAI;QACjB,mBAAmB,EAAE,OAAO,CAAC,CAAC,EAAE,gBAAgB,CAAC;QACjD,iBAAiB,EAAE,OAAO,CAAC,CAAC,EAAE,cAAc,CAAC;KAC9C,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,oBAAoB;IAkBlC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,cAAc,KAAK,UAAU,EAAE,CAAC;QACjD,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,oBAAoB;YAC9B,aAAa,EAAE,CAAC;YAChB,GAAG,EAAE,EAAE;YACP,UAAU,EAAE,CAAC;YACb,qBAAqB,EAAE,CAAC;YACxB,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;SACf,CAAA;IACH,CAAC;IACD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,CAAA;QAC5B,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAA;QAChD,OAAO;YACL,SAAS,EAAE,IAAI;YACf,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACtE,SAAS,EAAE,OAAO,CAAC,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC7D,QAAQ,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAClE,aAAa,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACzE,GAAG;YACH,UAAU,EAAE,OAAO,CAAC,EAAE,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChE,qBAAqB,EACnB,OAAO,CAAC,EAAE,qBAAqB,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAC5E,UAAU,EAAE,OAAO,CAAC,EAAE,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChE,WAAW,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SACpE,CAAA;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAA;QAChD,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,cAAc;YACxB,aAAa,EAAE,CAAC;YAChB,GAAG,EAAE,EAAE;YACP,UAAU,EAAE,CAAC;YACb,qBAAqB,EAAE,CAAC;YACxB,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;SACf,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,qBAAqB;IAKnC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IAClB,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;QAClD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;IACtE,CAAC;IACD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,CAAA;QAC7B,MAAM,GAAG,GACP,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAA6B,CAAC,CAAC,CAAC,EAAE,CAAA;QACvF,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;QAC5E,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAA;IAC3C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAA;QACjD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;IAChE,CAAC;AACH,CAAC"}
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.4.0';
18
+ const SDK_VERSION = '5.6.0';
19
19
  let _queue = [];
20
20
  let _assertStats = new Map();
21
21
  let _flushTimer = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "5.4.0",
3
+ "version": "5.6.0",
4
4
  "description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "author": "GOLIA K.K. <takagi@golia.jp> (https://golia.jp)",
@@ -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';
@@ -97,5 +98,17 @@ export {
97
98
  setLogTransport,
98
99
  } from '@goliapkg/sentori-core';
99
100
 
101
+ // The signal channel, for hosts feeding their own breadcrumbs into
102
+ // the ring (insight round-4 §4). Same O(1) fire-and-forget the
103
+ // auto signals use; entries ride payload.signals when an error/warn
104
+ // fires and appear on the case timeline + user-events panel.
105
+ //
106
+ // Field conventions the dashboard understands:
107
+ // pushSignal('http', { method, url, status, ms }) — a request's
108
+ // outcome (host's own interceptor is the right producer; the
109
+ // SDK deliberately does not monkey-patch fetch/XHR)
110
+ // any other kind renders with its data as `k=v` pairs.
111
+ export { pushSignal } from '@goliapkg/sentori-core';
112
+
100
113
  // Push namespace — carried as-is; outside the v1 acceptance surface.
101
114
  export * as push from './push';
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.4.0';
23
+ const SDK_VERSION = '5.6.0';
24
24
 
25
25
  let _queue: WireEvent[] = [];
26
26
  let _assertStats = new Map<string, AssertStat>();