@goliapkg/sentori-react-native 0.9.1 → 0.9.2

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.
@@ -47,6 +47,9 @@ object SentoriCrashHandler {
47
47
  // foreground Activity so it knows which Window to PixelCopy.
48
48
  (appCtx as? android.app.Application)?.let {
49
49
  SentoriScreenshotCapture.register(it)
50
+ // v0.9.6 #2 — replay capture also tracks the activity for
51
+ // wireframe view-tree walks.
52
+ SentoriReplayCapture.register(it)
50
53
  }
51
54
  }
52
55
 
@@ -29,6 +29,11 @@ class SentoriModule : Module() {
29
29
  SentoriNativeExceptionBridge.getRecent()
30
30
  }
31
31
 
32
+ // v0.9.6 #2 — wireframe session replay capture.
33
+ Function("captureWireframe") { maskedIds: List<String> ->
34
+ SentoriReplayCapture.captureWireframe(maskedIds)
35
+ }
36
+
32
37
  // v0.9.4 #1 — Mobile Vitals exposure.
33
38
  Function("markJsBridgeReady") {
34
39
  SentoriMobileVitals.markJsBridgeReady()
@@ -0,0 +1,153 @@
1
+ package com.sentori
2
+
3
+ import android.app.Activity
4
+ import android.graphics.Rect
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import android.widget.EditText
8
+ import android.widget.ImageView
9
+ import android.widget.TextView
10
+ import org.json.JSONArray
11
+ import org.json.JSONObject
12
+ import java.lang.ref.WeakReference
13
+
14
+ /**
15
+ * v0.9.6 #2 — wireframe session replay (Android side).
16
+ *
17
+ * Mirrors SentoriReplayCapture.swift. Walks View hierarchy from the
18
+ * current activity's decor view at 1 Hz. Each visible node becomes
19
+ * a JSON dict { kind, x, y, w, h, text?, color? }. Returns one JSON
20
+ * object string per snapshot.
21
+ *
22
+ * Mask: nodes whose `View.tag` (cast to String) matches `maskedIds`
23
+ * render as a single black "mask" rect. Descendants of a masked
24
+ * node are not emitted.
25
+ */
26
+ object SentoriReplayCapture {
27
+
28
+ private const val MAX_NODES = 800
29
+
30
+ @Volatile private var lastActivity: WeakReference<Activity>? = null
31
+
32
+ @JvmStatic
33
+ fun setActivity(activity: Activity?) {
34
+ lastActivity = activity?.let { WeakReference(it) }
35
+ }
36
+
37
+ /** Attach an ActivityLifecycleCallbacks so future
38
+ * `captureWireframe()` calls know which Activity to walk. */
39
+ @JvmStatic
40
+ fun register(application: android.app.Application) {
41
+ application.registerActivityLifecycleCallbacks(object :
42
+ android.app.Application.ActivityLifecycleCallbacks {
43
+ override fun onActivityCreated(a: Activity, b: android.os.Bundle?) { setActivity(a) }
44
+ override fun onActivityStarted(a: Activity) { setActivity(a) }
45
+ override fun onActivityResumed(a: Activity) { setActivity(a) }
46
+ override fun onActivityPaused(a: Activity) {}
47
+ override fun onActivityStopped(a: Activity) {}
48
+ override fun onActivitySaveInstanceState(a: Activity, b: android.os.Bundle) {}
49
+ override fun onActivityDestroyed(a: Activity) {}
50
+ })
51
+ }
52
+
53
+ @JvmStatic
54
+ fun captureWireframe(maskedIds: List<String>): String? {
55
+ val activity = lastActivity?.get() ?: return null
56
+ val root = activity.window?.decorView ?: return null
57
+ if (root.width <= 0 || root.height <= 0) return null
58
+
59
+ val maskedSet = maskedIds.toHashSet()
60
+ val nodes = JSONArray()
61
+ val rect = Rect()
62
+ val rootLoc = IntArray(2).also { root.getLocationInWindow(it) }
63
+ walk(root, false, maskedSet, rootLoc, rect, nodes)
64
+
65
+ val payload = JSONObject().apply {
66
+ put("ts", System.currentTimeMillis())
67
+ put("width", root.width)
68
+ put("height", root.height)
69
+ put("nodes", nodes)
70
+ }
71
+ return payload.toString()
72
+ }
73
+
74
+ private fun walk(
75
+ view: View,
76
+ parentMasked: Boolean,
77
+ maskedSet: Set<String>,
78
+ rootLoc: IntArray,
79
+ scratch: Rect,
80
+ nodes: JSONArray,
81
+ ) {
82
+ if (nodes.length() >= MAX_NODES) return
83
+ if (view.visibility != View.VISIBLE || view.alpha < 0.01) return
84
+
85
+ val viewTag = view.tag as? String
86
+ val isThisMasked = viewTag != null && maskedSet.contains(viewTag)
87
+ val masked = parentMasked || isThisMasked
88
+
89
+ val loc = IntArray(2)
90
+ view.getLocationInWindow(loc)
91
+ val x = loc[0] - rootLoc[0]
92
+ val y = loc[1] - rootLoc[1]
93
+ val w = view.width
94
+ val h = view.height
95
+ if (w <= 0 || h <= 0) return
96
+
97
+ val node = JSONObject().apply {
98
+ put("x", x)
99
+ put("y", y)
100
+ put("w", w)
101
+ put("h", h)
102
+ }
103
+
104
+ var kindEmitted = false
105
+ when {
106
+ masked -> {
107
+ node.put("kind", "mask")
108
+ kindEmitted = true
109
+ }
110
+ view is TextView && !view.text.isNullOrEmpty() -> {
111
+ node.put("kind", "text")
112
+ val text = view.text.toString().let { if (it.length > 200) it.substring(0, 200) else it }
113
+ node.put("text", text)
114
+ node.put("color", colorToHex(view.currentTextColor))
115
+ kindEmitted = true
116
+ }
117
+ view is EditText -> {
118
+ node.put("kind", "text")
119
+ val text = (view.text ?: "").toString().let { if (it.length > 200) it.substring(0, 200) else it }
120
+ node.put("text", text)
121
+ kindEmitted = true
122
+ }
123
+ view is ImageView -> {
124
+ node.put("kind", "image")
125
+ kindEmitted = true
126
+ }
127
+ view.background != null -> {
128
+ node.put("kind", "rect")
129
+ // Background drawables don't always expose color directly.
130
+ // Skip color for non-ColorDrawable; renderer falls back to neutral.
131
+ kindEmitted = true
132
+ }
133
+ }
134
+
135
+ if (kindEmitted) {
136
+ nodes.put(node)
137
+ }
138
+
139
+ if (!masked && view is ViewGroup) {
140
+ for (i in 0 until view.childCount) {
141
+ walk(view.getChildAt(i), masked, maskedSet, rootLoc, scratch, nodes)
142
+ }
143
+ }
144
+ }
145
+
146
+ private fun colorToHex(c: Int): String {
147
+ val a = (c shr 24) and 0xff
148
+ val r = (c shr 16) and 0xff
149
+ val g = (c shr 8) and 0xff
150
+ val b = c and 0xff
151
+ return String.format("#%02X%02X%02X%02X", r, g, b, a)
152
+ }
153
+ }
@@ -25,6 +25,11 @@ public class SentoriModule: Module {
25
25
  return SentoriNativeExceptionBridge.getRecentException()
26
26
  }
27
27
 
28
+ // v0.9.6 #2 — wireframe session replay capture.
29
+ Function("captureWireframe") { (maskedIds: [String]) -> String? in
30
+ return SentoriReplayCapture.captureWireframe(maskedIds: maskedIds)
31
+ }
32
+
28
33
  // v0.9.4 #1 — Mobile Vitals exposure.
29
34
  Function("markJsBridgeReady") {
30
35
  SentoriMobileVitals.markJsBridgeReady()
@@ -0,0 +1,147 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+ /// v0.9.6 #2 — wireframe session replay (iOS side).
5
+ ///
6
+ /// Walks the UIView hierarchy at 1 Hz and serializes each visible
7
+ /// node as a compact JSON dict:
8
+ /// { kind, x, y, w, h, text?, color? }
9
+ ///
10
+ /// Mask: nodes whose `accessibilityIdentifier` matches the JS-side
11
+ /// mask registry (passed in as `maskedIds`) have their text replaced
12
+ /// with "***" and the masked flag set so descendants render as
13
+ /// black-filled rects in the dashboard player.
14
+ ///
15
+ /// Output: one JSON object per snapshot, returned as a string. The
16
+ /// JS side appends each snapshot to a 60-slot ring buffer; on
17
+ /// `captureException` the ring is uploaded as a `replay` attachment
18
+ /// (NDJSON: one snapshot per line).
19
+ @objc public final class SentoriReplayCapture: NSObject {
20
+
21
+ @objc public static func captureWireframe(maskedIds: [String]) -> String? {
22
+ if Thread.isMainThread {
23
+ return captureSync(maskedIds: Set(maskedIds))
24
+ }
25
+ var result: String?
26
+ DispatchQueue.main.sync {
27
+ result = captureSync(maskedIds: Set(maskedIds))
28
+ }
29
+ return result
30
+ }
31
+
32
+ private static func captureSync(maskedIds: Set<String>) -> String? {
33
+ guard let window = keyWindow() else { return nil }
34
+ var nodes: [[String: Any]] = []
35
+ walk(
36
+ view: window,
37
+ parentMasked: false,
38
+ maskedIds: maskedIds,
39
+ window: window,
40
+ nodes: &nodes
41
+ )
42
+ let payload: [String: Any] = [
43
+ "ts": Int(Date().timeIntervalSince1970 * 1000),
44
+ "width": Double(window.bounds.width),
45
+ "height": Double(window.bounds.height),
46
+ "nodes": nodes,
47
+ ]
48
+ if let data = try? JSONSerialization.data(withJSONObject: payload, options: []) {
49
+ return String(data: data, encoding: .utf8)
50
+ }
51
+ return nil
52
+ }
53
+
54
+ private static func keyWindow() -> UIWindow? {
55
+ if #available(iOS 13.0, *) {
56
+ for scene in UIApplication.shared.connectedScenes {
57
+ guard let ws = scene as? UIWindowScene else { continue }
58
+ if let key = ws.windows.first(where: { $0.isKeyWindow }) {
59
+ return key
60
+ }
61
+ if let first = ws.windows.first {
62
+ return first
63
+ }
64
+ }
65
+ }
66
+ return UIApplication.shared.windows.first
67
+ }
68
+
69
+ /// Cap on nodes per snapshot — extremely deep / wide trees can
70
+ /// have thousands of subviews (UICollectionView recyclers).
71
+ private static let MAX_NODES = 800
72
+
73
+ private static func walk(
74
+ view: UIView,
75
+ parentMasked: Bool,
76
+ maskedIds: Set<String>,
77
+ window: UIWindow,
78
+ nodes: inout [[String: Any]]
79
+ ) {
80
+ if nodes.count >= MAX_NODES { return }
81
+ if view.isHidden || view.alpha < 0.01 { return }
82
+
83
+ let isThisMasked = view.accessibilityIdentifier
84
+ .map { maskedIds.contains($0) } ?? false
85
+ let masked = parentMasked || isThisMasked
86
+
87
+ let frame = view.convert(view.bounds, to: window)
88
+ // Skip nodes outside the window bounds (off-screen recyclers).
89
+ if !frame.intersects(window.bounds) {
90
+ return
91
+ }
92
+
93
+ var node: [String: Any] = [
94
+ "x": Double(frame.origin.x),
95
+ "y": Double(frame.origin.y),
96
+ "w": Double(frame.size.width),
97
+ "h": Double(frame.size.height),
98
+ ]
99
+
100
+ if masked {
101
+ node["kind"] = "mask"
102
+ } else if let label = view as? UILabel, let text = label.text, !text.isEmpty {
103
+ node["kind"] = "text"
104
+ node["text"] = text.count > 200 ? String(text.prefix(200)) : text
105
+ if let color = label.textColor.flatMap(colorToHex) {
106
+ node["color"] = color
107
+ }
108
+ } else if let textView = view as? UITextView, let text = textView.text, !text.isEmpty {
109
+ node["kind"] = "text"
110
+ node["text"] = text.count > 200 ? String(text.prefix(200)) : text
111
+ } else if view is UIImageView {
112
+ node["kind"] = "image"
113
+ } else if let bg = view.backgroundColor, let hex = colorToHex(bg), hex != "#00000000" {
114
+ node["kind"] = "rect"
115
+ node["color"] = hex
116
+ }
117
+ // else: invisible container — skip emitting but recurse.
118
+
119
+ if node["kind"] != nil {
120
+ nodes.append(node)
121
+ }
122
+
123
+ if !masked {
124
+ // Don't expose internals of masked subtrees.
125
+ for sub in view.subviews {
126
+ walk(
127
+ view: sub,
128
+ parentMasked: masked,
129
+ maskedIds: maskedIds,
130
+ window: window,
131
+ nodes: &nodes
132
+ )
133
+ }
134
+ }
135
+ }
136
+
137
+ private static func colorToHex(_ color: UIColor?) -> String? {
138
+ guard let c = color else { return nil }
139
+ var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
140
+ c.getRed(&r, green: &g, blue: &b, alpha: &a)
141
+ let ri = max(0, min(255, Int(r * 255)))
142
+ let gi = max(0, min(255, Int(g * 255)))
143
+ let bi = max(0, min(255, Int(b * 255)))
144
+ let ai = max(0, min(255, Int(a * 255)))
145
+ return String(format: "#%02X%02X%02X%02X", ri, gi, bi, ai)
146
+ }
147
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAoD,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5F,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAgB5D,eAAO,MAAM,+BAA+B,QAAO,IAElD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,IAAI,GAAG,IAAI,KAAG,IAE3C,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,IAAI,GAAG,IAAa,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;qDAGiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAU,OAAO;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,KAAG,OAAO,CAAC,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAKxD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,KAAK,EAAE,SAAS,aAAa,KAAG,IAqEnE,CAAC;AAiEF,eAAO,MAAM,gBAAgB,UAtIO,KAAK,WAAW,aAAa,KAAG,IAsIxB,CAAC"}
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAoD,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5F,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAgB5D,eAAO,MAAM,+BAA+B,QAAO,IAElD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,IAAI,GAAG,IAAI,KAAG,IAE3C,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,IAAI,GAAG,IAAa,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;qDAGiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAU,OAAO;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,KAAG,OAAO,CAAC,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAKxD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,KAAK,EAAE,SAAS,aAAa,KAAG,IA2EnE,CAAC;AAyFF,eAAO,MAAM,gBAAgB,UApKO,KAAK,WAAW,aAAa,KAAG,IAoKxB,CAAC"}
package/lib/capture.js CHANGED
@@ -3,6 +3,7 @@ import { addBreadcrumb, getBreadcrumbs } from './breadcrumbs';
3
3
  import { getBundleInfo } from './bundle-info';
4
4
  import { getConfig, isInitialized } from './config';
5
5
  import { getFeatureFlagSnapshot } from './feature-flags';
6
+ import { drainReplay } from './replay';
6
7
  import { clearStateSnapshots, getStateSnapshots } from './state-snapshots';
7
8
  import { symbolicateErrorViaMetro } from './handlers/dev-symbolicate';
8
9
  import { captureScreenshot } from './handlers/screenshot';
@@ -122,10 +123,35 @@ export const captureError = (error, extras) => {
122
123
  await captureAndAttachStateSnapshots(event, stateSnapshots);
123
124
  clearStateSnapshots();
124
125
  }
126
+ // v0.9.6 #2 — wireframe replay attachment. drainReplay clears the
127
+ // ring as a side effect so next session's replay starts fresh.
128
+ const replayNdjson = drainReplay();
129
+ if (replayNdjson.length > 0) {
130
+ await captureAndAttachReplay(event, replayNdjson);
131
+ }
125
132
  enqueue(event);
126
133
  };
127
134
  void pipeline();
128
135
  };
136
+ /** v0.9.6 #2 — upload the wireframe replay ring as a `replay`
137
+ * attachment. Plain NDJSON (one snapshot per line) — server may
138
+ * gzip on storage; the network upload is base64. */
139
+ async function captureAndAttachReplay(event, ndjson) {
140
+ try {
141
+ const base64 = typeof globalThis.btoa === 'function'
142
+ ? globalThis.btoa(ndjson)
143
+ : Buffer.from(ndjson, 'utf8').toString('base64');
144
+ const meta = await uploadAttachment(event.id, 'replay', { base64, mediaType: 'application/x-ndjson' }, { source: 'js' });
145
+ if (meta) {
146
+ if (!event.attachments)
147
+ event.attachments = [];
148
+ event.attachments.push(meta);
149
+ }
150
+ }
151
+ catch {
152
+ // best-effort
153
+ }
154
+ }
129
155
  /** v0.9.2 +S2 — upload the rolling state-snapshot ring as a
130
156
  * `stateSnapshot` attachment so the dashboard time-travel viewer can
131
157
  * scrub through diffs alongside the breadcrumb timeline. */
@@ -1 +1 @@
1
- {"version":3,"file":"capture.js","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAkB,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAOxG,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAO5C,eAAO,MAAM,OAAO;;;;;;;;;;aA8F+E,CAAC;eAAmB,CAAC;YAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CAhExI,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxG,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EACL,SAAS,EACT,WAAW,EACX,KAAK,aAAa,EAClB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE1E,YAAY,EACV,KAAK,EACL,YAAY,EACZ,KAAK,EACL,UAAU,EACV,cAAc,EACd,MAAM,EACN,QAAQ,EACR,GAAG,EACH,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,QAAQ,GACT,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAkB,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAOxG,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAO5C,eAAO,MAAM,OAAO;;;;;;;;;;aA8FuH,CAAC;eAAmB,CAAC;YAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CAhEhL,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxG,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EACL,SAAS,EACT,WAAW,EACX,KAAK,aAAa,EAClB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE1E,YAAY,EACV,KAAK,EACL,YAAY,EACZ,KAAK,EACL,UAAU,EACV,cAAc,EACd,MAAM,EACN,QAAQ,EACR,GAAG,EACH,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,QAAQ,GACT,MAAM,SAAS,CAAC"}
package/lib/init.d.ts CHANGED
@@ -44,6 +44,22 @@ export type InitOptions = {
44
44
  * signal before an actual crash. */
45
45
  preCrashSentinel?: boolean;
46
46
  sentinelChannels?: PreCrashChannel[];
47
+ /** v0.9.6 #4 — JS-thread long-task monitor. setInterval(50ms)
48
+ * tick detects JS thread stalls ≥ 200ms (configurable) and
49
+ * emits a `sentori.longtask` span. Pairs with
50
+ * `preCrashSentinel` (slow frames < 32ms) to cover the
51
+ * "JS thread is stuck" spectrum. */
52
+ longTaskMonitor?: boolean | {
53
+ thresholdMs?: number;
54
+ };
55
+ /** v0.9.6 #2 — wireframe session replay. Native walks the iOS
56
+ * UIView / Android View hierarchy at 1 Hz and serializes
57
+ * visible nodes; captureException flushes the last 60 s as a
58
+ * `replay` attachment. Set to `'wireframe'` to enable. */
59
+ replay?: 'off' | 'wireframe' | {
60
+ hz?: number;
61
+ mode: 'off' | 'wireframe';
62
+ };
47
63
  /** v0.9.0 #3 — launch-crash loop guard. When two consecutive
48
64
  * launches don't reach `markLaunchCompleted()` (typical of an
49
65
  * OTA update with a fatal bug), invoke the host callback with
package/lib/init.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAeA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQnF,OAAO,KAAK,EAAkB,cAAc,EAA2B,MAAM,SAAS,CAAC;AAIvF,MAAM,MAAM,WAAW,GAAG;IACxB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EACJ,OAAO,GACP;YACE;;qEAEyD;YACzD,OAAO,CAAC,EAAE,OAAO,CAAC;SACnB,CAAC;QACN;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;;;;;;;uBAOe;QACf,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB;;;6CAGqC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB;;;;6CAIqC;QACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;QACrC;;;sEAG8D;QAC9D,gBAAgB,CAAC,EAAE;YACjB,OAAO,EAAE,OAAO,CAAC;YACjB,qBAAqB,CAAC,EAAE,CACtB,IAAI,EAAE,OAAO,sBAAsB,EAAE,eAAe,KAElD,OAAO,sBAAsB,EAAE,iBAAiB,GAChD,OAAO,CAAC,OAAO,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;YAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC;IACF;;;;;gEAK4D;IAC5D,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAIF,eAAO,MAAM,IAAI,GAAI,SAAS,WAAW,KAAG,IA8I3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AASnF,OAAO,KAAK,EAAkB,cAAc,EAA2B,MAAM,SAAS,CAAC;AAIvF,MAAM,MAAM,WAAW,GAAG;IACxB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EACJ,OAAO,GACP;YACE;;qEAEyD;YACzD,OAAO,CAAC,EAAE,OAAO,CAAC;SACnB,CAAC;QACN;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;;;;;;;uBAOe;QACf,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB;;;6CAGqC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB;;;;6CAIqC;QACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;QACrC;;;;6CAIqC;QACrC,eAAe,CAAC,EAAE,OAAO,GAAG;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACrD;;;mEAG2D;QAC3D,MAAM,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG;YAAE,EAAE,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,WAAW,CAAA;SAAE,CAAC;QAC1E;;;sEAG8D;QAC9D,gBAAgB,CAAC,EAAE;YACjB,OAAO,EAAE,OAAO,CAAC;YACjB,qBAAqB,CAAC,EAAE,CACtB,IAAI,EAAE,OAAO,sBAAsB,EAAE,eAAe,KAElD,OAAO,sBAAsB,EAAE,iBAAiB,GAChD,OAAO,CAAC,OAAO,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;YAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC;IACF;;;;;gEAK4D;IAC5D,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAIF,eAAO,MAAM,IAAI,GAAI,SAAS,WAAW,KAAG,IA6J3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
package/lib/init.js CHANGED
@@ -9,8 +9,10 @@ import { startMetricsTimer } from './metrics';
9
9
  import { drainNativePending, markNativeJsBridgeReady, setNativeConfig } from './native';
10
10
  import { getColdStartMs } from './mobile-vitals';
11
11
  import { startSpan } from '@goliapkg/sentori-core';
12
+ import { startLongTaskMonitor } from './long-task-monitor';
12
13
  import { startNetworkTypeWatch } from './netinfo';
13
14
  import { startPreCrashSentinel } from './pre-crash-sentinel';
15
+ import { startReplay } from './replay';
14
16
  import { startSession } from './session-tracker';
15
17
  import { drainOfflineQueue, enqueue, startTransport, uploadAttachment, } from './transport';
16
18
  const DEFAULT_INGEST_URL = 'https://ingest.sentori.golia.jp';
@@ -82,6 +84,22 @@ export const init = (options) => {
82
84
  channels: options.capture.sentinelChannels,
83
85
  });
84
86
  }
87
+ // v0.9.6 #4 — long-task monitor. Off by default.
88
+ const lt = options.capture?.longTaskMonitor;
89
+ if (lt) {
90
+ startLongTaskMonitor({
91
+ enabled: true,
92
+ thresholdMs: typeof lt === 'object' ? lt.thresholdMs : undefined,
93
+ });
94
+ }
95
+ // v0.9.6 #2 — wireframe replay. Off by default.
96
+ const rp = options.capture?.replay;
97
+ if (rp === 'wireframe') {
98
+ startReplay({ mode: 'wireframe' });
99
+ }
100
+ else if (rp && typeof rp === 'object' && rp.mode === 'wireframe') {
101
+ startReplay({ hz: rp.hz, mode: 'wireframe' });
102
+ }
85
103
  const capture = options.capture ?? {};
86
104
  if (capture.globalErrors !== false)
87
105
  installGlobalHandler();
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,11 @@
1
+ export type LongTaskMonitorOptions = {
2
+ enabled: boolean;
3
+ /** Threshold ms above which a tick lag becomes a longtask span.
4
+ * Default 200ms. Lower → noisier. */
5
+ thresholdMs?: number;
6
+ };
7
+ export declare function startLongTaskMonitor(opts: LongTaskMonitorOptions): void;
8
+ export declare function stopLongTaskMonitor(): void;
9
+ /** Test-only. */
10
+ export declare function __resetLongTaskMonitorForTests(): void;
11
+ //# sourceMappingURL=long-task-monitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"long-task-monitor.d.ts","sourceRoot":"","sources":["../src/long-task-monitor.ts"],"names":[],"mappings":"AAqCA,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB;0CACsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAWvE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AA8BD,iBAAiB;AACjB,wBAAgB,8BAA8B,IAAI,IAAI,CAKrD"}
@@ -0,0 +1,88 @@
1
+ // v0.9.6 #4 — JS thread long-task monitor.
2
+ //
3
+ // What it does: a setInterval(50ms) tick checks how much wall-clock
4
+ // passed vs the requested interval. Excess = the JS thread was busy
5
+ // doing something else for at least that much. When the excess
6
+ // crosses 200ms (a "long task" per Chrome's PerformanceObserver
7
+ // threshold) we emit a `sentori.longtask` span so the dashboard's
8
+ // trace waterfall shows where the JS thread stalled.
9
+ //
10
+ // What it does NOT do: capture the stack DURING the long task. JS
11
+ // is single-threaded — by the time our tick runs, the busy code is
12
+ // already gone. The span carries the duration + nearest navigation
13
+ // context (via active span) so triage still has a route to blame.
14
+ //
15
+ // Why this and not a real Hermes sampler: Hermes ships a sampling
16
+ // profiler but accessing it from JS requires RN-internal bridges
17
+ // that vary per RN minor. We could swizzle / vendor headers but
18
+ // that's an Insight-build-config burden. The long-task monitor
19
+ // gets ~80% of the practical value (find slow renders, expensive
20
+ // reducers, accidental sync work in render path) with zero native
21
+ // code + zero RN-version sensitivity.
22
+ //
23
+ // Pairs naturally with +S4 (pre-crash sentinel, RAF frame budget,
24
+ // fires at the slow-frame threshold) — long-task monitor fires
25
+ // further down the slowness scale.
26
+ import { startSpan } from '@goliapkg/sentori-core';
27
+ const TICK_INTERVAL_MS = 50;
28
+ const LONGTASK_THRESHOLD_MS = 200; // > 200ms blocking = a longtask
29
+ const MAX_EMITS_PER_MIN = 60;
30
+ let _timer = null;
31
+ let _lastTick = 0;
32
+ let _emitWindowStart = 0;
33
+ let _emitsThisWindow = 0;
34
+ export function startLongTaskMonitor(opts) {
35
+ if (_timer !== null)
36
+ return;
37
+ if (!opts.enabled)
38
+ return;
39
+ const threshold = opts.thresholdMs ?? LONGTASK_THRESHOLD_MS;
40
+ _lastTick = Date.now();
41
+ _emitWindowStart = _lastTick;
42
+ _emitsThisWindow = 0;
43
+ _timer = setInterval(() => {
44
+ tick(threshold);
45
+ }, TICK_INTERVAL_MS);
46
+ _timer.unref?.();
47
+ }
48
+ export function stopLongTaskMonitor() {
49
+ if (_timer !== null) {
50
+ clearInterval(_timer);
51
+ _timer = null;
52
+ }
53
+ }
54
+ function tick(threshold) {
55
+ const now = Date.now();
56
+ const elapsed = now - _lastTick;
57
+ _lastTick = now;
58
+ const lag = elapsed - TICK_INTERVAL_MS;
59
+ if (lag <= threshold)
60
+ return;
61
+ // Rate-limit emits: at most MAX_EMITS_PER_MIN per minute so a
62
+ // pathological scroll-block-storm doesn't generate 1000 spans.
63
+ if (now - _emitWindowStart >= 60_000) {
64
+ _emitWindowStart = now;
65
+ _emitsThisWindow = 0;
66
+ }
67
+ if (_emitsThisWindow >= MAX_EMITS_PER_MIN)
68
+ return;
69
+ _emitsThisWindow += 1;
70
+ const span = startSpan('sentori.longtask', {
71
+ name: 'js.longtask',
72
+ startNowMs: now - lag,
73
+ tags: {
74
+ 'profile.kind': 'longtask',
75
+ 'profile.duration_ms': String(Math.round(lag)),
76
+ 'profile.tick_interval_ms': String(TICK_INTERVAL_MS),
77
+ },
78
+ });
79
+ span.finish({ endNowMs: now, status: 'ok' });
80
+ }
81
+ /** Test-only. */
82
+ export function __resetLongTaskMonitorForTests() {
83
+ stopLongTaskMonitor();
84
+ _lastTick = 0;
85
+ _emitWindowStart = 0;
86
+ _emitsThisWindow = 0;
87
+ }
88
+ //# sourceMappingURL=long-task-monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"long-task-monitor.js","sourceRoot":"","sources":["../src/long-task-monitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type ReplayOptions = {
2
+ mode?: 'off' | 'wireframe';
3
+ /** Ticks per second. Default 1. */
4
+ hz?: number;
5
+ };
6
+ export declare function startReplay(opts: ReplayOptions): void;
7
+ export declare function stopReplay(): void;
8
+ /** Drain the ring as NDJSON (one snapshot per line). Empty string
9
+ * when the ring is empty. Also clears the ring so the next session's
10
+ * replay starts fresh. */
11
+ export declare function drainReplay(): string;
12
+ export declare function __resetReplayForTests(): void;
13
+ //# sourceMappingURL=replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AA+BA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;IAC3B,mCAAmC;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAiBrD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAMjC;AA+CD;;2BAE2B;AAC3B,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
package/lib/replay.js ADDED
@@ -0,0 +1,111 @@
1
+ // v0.9.6 #2 — wireframe Session Replay (SDK side).
2
+ //
3
+ // 60-slot ring buffer of native-captured wireframe snapshots. Each
4
+ // tick calls into `SentoriReplayCapture.captureWireframe(maskIds)`
5
+ // which walks the iOS UIView / Android View hierarchy and returns
6
+ // one JSON string per snapshot. captureException flushes the ring
7
+ // as a `replay` attachment (NDJSON: one snapshot per line).
8
+ //
9
+ // Why wireframe and not raster:
10
+ // • Storage: 80 nodes × ~80 bytes ≈ 6 KB per snapshot vs ~50 KB
11
+ // for a downsampled JPEG. 60-slot ring ≈ 400 KB raw / ~80 KB
12
+ // gzipped — fits comfortably in the 500 KB attachment cap.
13
+ // • Privacy: no pixels means no accidental PII leaks; mask
14
+ // registry decides what text to replace with "***".
15
+ // • Replay fidelity: less faithful to pixels but enough to see
16
+ // which screen the user was on and what was on it. Dashboard
17
+ // player renders SVG rects — denser-looking than a 1 Hz
18
+ // screenshot strip.
19
+ import { startSpan } from '@goliapkg/sentori-core';
20
+ import { getRegisteredMaskQuery } from './mask';
21
+ import { isNativeModuleLinked } from './native-loader';
22
+ const TICK_INTERVAL_MS = 1000;
23
+ const RING_SIZE = 60;
24
+ let _ring = [];
25
+ let _timer = null;
26
+ let _running = false;
27
+ export function startReplay(opts) {
28
+ if (_running)
29
+ return;
30
+ if (opts.mode !== 'wireframe')
31
+ return;
32
+ // Native replay needs the Sentori native module linked. Defensive
33
+ // — same pattern as other native peers — for Expo Go / unlinked
34
+ // builds.
35
+ if (!isNativeModuleLinked('Sentori') && !isNativeModuleLinked('SentoriModule')) {
36
+ // Falls back silently. Replay rings stay empty; captureException
37
+ // simply doesn't attach a replay.
38
+ return;
39
+ }
40
+ _running = true;
41
+ const period = Math.max(250, Math.floor(1000 / (opts.hz ?? 1)));
42
+ _timer = setInterval(() => {
43
+ captureTick();
44
+ }, period);
45
+ _timer.unref?.();
46
+ }
47
+ export function stopReplay() {
48
+ _running = false;
49
+ if (_timer !== null) {
50
+ clearInterval(_timer);
51
+ _timer = null;
52
+ }
53
+ }
54
+ function captureTick() {
55
+ if (!_running)
56
+ return;
57
+ const tickSpan = startSpan('sentori.replay.tick', { name: 'tick' });
58
+ try {
59
+ const maskIds = readMaskIds();
60
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
61
+ const nativeMod = loadNativeReplay();
62
+ const snapshot = nativeMod?.captureWireframe?.(maskIds);
63
+ if (typeof snapshot === 'string' && snapshot.length > 0) {
64
+ _ring.push(snapshot);
65
+ while (_ring.length > RING_SIZE)
66
+ _ring.shift();
67
+ }
68
+ tickSpan.finish({ status: 'ok' });
69
+ }
70
+ catch (e) {
71
+ if (e instanceof Error)
72
+ tickSpan.setTag('error.message', e.message);
73
+ tickSpan.finish({ status: 'error' });
74
+ }
75
+ }
76
+ function readMaskIds() {
77
+ const q = getRegisteredMaskQuery();
78
+ if (!q)
79
+ return [];
80
+ try {
81
+ return q();
82
+ }
83
+ catch {
84
+ return [];
85
+ }
86
+ }
87
+ function loadNativeReplay() {
88
+ try {
89
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
90
+ const core = require('expo-modules-core');
91
+ return core.requireNativeModule('Sentori');
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ /** Drain the ring as NDJSON (one snapshot per line). Empty string
98
+ * when the ring is empty. Also clears the ring so the next session's
99
+ * replay starts fresh. */
100
+ export function drainReplay() {
101
+ if (_ring.length === 0)
102
+ return '';
103
+ const out = _ring.join('\n');
104
+ _ring = [];
105
+ return out;
106
+ }
107
+ export function __resetReplayForTests() {
108
+ stopReplay();
109
+ _ring = [];
110
+ }
111
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://sentori.golia.jp",
@@ -72,6 +72,6 @@
72
72
  "access": "public"
73
73
  },
74
74
  "dependencies": {
75
- "@goliapkg/sentori-core": "0.8.1"
75
+ "@goliapkg/sentori-core": "0.8.2"
76
76
  }
77
77
  }
package/src/capture.ts CHANGED
@@ -4,6 +4,7 @@ import { addBreadcrumb, getBreadcrumbs } from './breadcrumbs';
4
4
  import { getBundleInfo } from './bundle-info';
5
5
  import { getConfig, isInitialized } from './config';
6
6
  import { getFeatureFlagSnapshot } from './feature-flags';
7
+ import { drainReplay } from './replay';
7
8
  import { clearStateSnapshots, getStateSnapshots } from './state-snapshots';
8
9
  import { symbolicateErrorViaMetro } from './handlers/dev-symbolicate';
9
10
  import { captureScreenshot } from './handlers/screenshot';
@@ -154,11 +155,41 @@ export const captureError = (error: Error, extras?: CaptureExtras): void => {
154
155
  await captureAndAttachStateSnapshots(event, stateSnapshots);
155
156
  clearStateSnapshots();
156
157
  }
158
+ // v0.9.6 #2 — wireframe replay attachment. drainReplay clears the
159
+ // ring as a side effect so next session's replay starts fresh.
160
+ const replayNdjson = drainReplay();
161
+ if (replayNdjson.length > 0) {
162
+ await captureAndAttachReplay(event, replayNdjson);
163
+ }
157
164
  enqueue(event);
158
165
  };
159
166
  void pipeline();
160
167
  };
161
168
 
169
+ /** v0.9.6 #2 — upload the wireframe replay ring as a `replay`
170
+ * attachment. Plain NDJSON (one snapshot per line) — server may
171
+ * gzip on storage; the network upload is base64. */
172
+ async function captureAndAttachReplay(event: Event, ndjson: string): Promise<void> {
173
+ try {
174
+ const base64 =
175
+ typeof globalThis.btoa === 'function'
176
+ ? globalThis.btoa(ndjson)
177
+ : Buffer.from(ndjson, 'utf8').toString('base64');
178
+ const meta = await uploadAttachment(
179
+ event.id,
180
+ 'replay',
181
+ { base64, mediaType: 'application/x-ndjson' },
182
+ { source: 'js' },
183
+ );
184
+ if (meta) {
185
+ if (!event.attachments) event.attachments = [];
186
+ event.attachments.push(meta);
187
+ }
188
+ } catch {
189
+ // best-effort
190
+ }
191
+ }
192
+
162
193
  /** v0.9.2 +S2 — upload the rolling state-snapshot ring as a
163
194
  * `stateSnapshot` attachment so the dashboard time-travel viewer can
164
195
  * scrub through diffs alongside the breadcrumb timeline. */
package/src/init.ts CHANGED
@@ -12,8 +12,10 @@ import { startMetricsTimer } from './metrics';
12
12
  import { drainNativePending, markNativeJsBridgeReady, setNativeConfig } from './native';
13
13
  import { getColdStartMs } from './mobile-vitals';
14
14
  import { startSpan } from '@goliapkg/sentori-core';
15
+ import { startLongTaskMonitor } from './long-task-monitor';
15
16
  import { startNetworkTypeWatch } from './netinfo';
16
17
  import { startPreCrashSentinel, type PreCrashChannel } from './pre-crash-sentinel';
18
+ import { startReplay } from './replay';
17
19
  import { startSession } from './session-tracker';
18
20
  import {
19
21
  drainOfflineQueue,
@@ -71,6 +73,17 @@ export type InitOptions = {
71
73
  * signal before an actual crash. */
72
74
  preCrashSentinel?: boolean;
73
75
  sentinelChannels?: PreCrashChannel[];
76
+ /** v0.9.6 #4 — JS-thread long-task monitor. setInterval(50ms)
77
+ * tick detects JS thread stalls ≥ 200ms (configurable) and
78
+ * emits a `sentori.longtask` span. Pairs with
79
+ * `preCrashSentinel` (slow frames < 32ms) to cover the
80
+ * "JS thread is stuck" spectrum. */
81
+ longTaskMonitor?: boolean | { thresholdMs?: number };
82
+ /** v0.9.6 #2 — wireframe session replay. Native walks the iOS
83
+ * UIView / Android View hierarchy at 1 Hz and serializes
84
+ * visible nodes; captureException flushes the last 60 s as a
85
+ * `replay` attachment. Set to `'wireframe'` to enable. */
86
+ replay?: 'off' | 'wireframe' | { hz?: number; mode: 'off' | 'wireframe' };
74
87
  /** v0.9.0 #3 — launch-crash loop guard. When two consecutive
75
88
  * launches don't reach `markLaunchCompleted()` (typical of an
76
89
  * OTA update with a fatal bug), invoke the host callback with
@@ -178,6 +191,21 @@ export const init = (options: InitOptions): void => {
178
191
  channels: options.capture.sentinelChannels,
179
192
  });
180
193
  }
194
+ // v0.9.6 #4 — long-task monitor. Off by default.
195
+ const lt = options.capture?.longTaskMonitor;
196
+ if (lt) {
197
+ startLongTaskMonitor({
198
+ enabled: true,
199
+ thresholdMs: typeof lt === 'object' ? lt.thresholdMs : undefined,
200
+ });
201
+ }
202
+ // v0.9.6 #2 — wireframe replay. Off by default.
203
+ const rp = options.capture?.replay;
204
+ if (rp === 'wireframe') {
205
+ startReplay({ mode: 'wireframe' });
206
+ } else if (rp && typeof rp === 'object' && rp.mode === 'wireframe') {
207
+ startReplay({ hz: rp.hz, mode: 'wireframe' });
208
+ }
181
209
 
182
210
  const capture = options.capture ?? {};
183
211
  if (capture.globalErrors !== false) installGlobalHandler();
@@ -0,0 +1,99 @@
1
+ // v0.9.6 #4 — JS thread long-task monitor.
2
+ //
3
+ // What it does: a setInterval(50ms) tick checks how much wall-clock
4
+ // passed vs the requested interval. Excess = the JS thread was busy
5
+ // doing something else for at least that much. When the excess
6
+ // crosses 200ms (a "long task" per Chrome's PerformanceObserver
7
+ // threshold) we emit a `sentori.longtask` span so the dashboard's
8
+ // trace waterfall shows where the JS thread stalled.
9
+ //
10
+ // What it does NOT do: capture the stack DURING the long task. JS
11
+ // is single-threaded — by the time our tick runs, the busy code is
12
+ // already gone. The span carries the duration + nearest navigation
13
+ // context (via active span) so triage still has a route to blame.
14
+ //
15
+ // Why this and not a real Hermes sampler: Hermes ships a sampling
16
+ // profiler but accessing it from JS requires RN-internal bridges
17
+ // that vary per RN minor. We could swizzle / vendor headers but
18
+ // that's an Insight-build-config burden. The long-task monitor
19
+ // gets ~80% of the practical value (find slow renders, expensive
20
+ // reducers, accidental sync work in render path) with zero native
21
+ // code + zero RN-version sensitivity.
22
+ //
23
+ // Pairs naturally with +S4 (pre-crash sentinel, RAF frame budget,
24
+ // fires at the slow-frame threshold) — long-task monitor fires
25
+ // further down the slowness scale.
26
+
27
+ import { startSpan } from '@goliapkg/sentori-core';
28
+
29
+ const TICK_INTERVAL_MS = 50;
30
+ const LONGTASK_THRESHOLD_MS = 200; // > 200ms blocking = a longtask
31
+ const MAX_EMITS_PER_MIN = 60;
32
+
33
+ let _timer: ReturnType<typeof setInterval> | null = null;
34
+ let _lastTick = 0;
35
+ let _emitWindowStart = 0;
36
+ let _emitsThisWindow = 0;
37
+
38
+ export type LongTaskMonitorOptions = {
39
+ enabled: boolean;
40
+ /** Threshold ms above which a tick lag becomes a longtask span.
41
+ * Default 200ms. Lower → noisier. */
42
+ thresholdMs?: number;
43
+ };
44
+
45
+ export function startLongTaskMonitor(opts: LongTaskMonitorOptions): void {
46
+ if (_timer !== null) return;
47
+ if (!opts.enabled) return;
48
+ const threshold = opts.thresholdMs ?? LONGTASK_THRESHOLD_MS;
49
+ _lastTick = Date.now();
50
+ _emitWindowStart = _lastTick;
51
+ _emitsThisWindow = 0;
52
+ _timer = setInterval(() => {
53
+ tick(threshold);
54
+ }, TICK_INTERVAL_MS);
55
+ (_timer as unknown as { unref?: () => void }).unref?.();
56
+ }
57
+
58
+ export function stopLongTaskMonitor(): void {
59
+ if (_timer !== null) {
60
+ clearInterval(_timer);
61
+ _timer = null;
62
+ }
63
+ }
64
+
65
+ function tick(threshold: number): void {
66
+ const now = Date.now();
67
+ const elapsed = now - _lastTick;
68
+ _lastTick = now;
69
+ const lag = elapsed - TICK_INTERVAL_MS;
70
+ if (lag <= threshold) return;
71
+
72
+ // Rate-limit emits: at most MAX_EMITS_PER_MIN per minute so a
73
+ // pathological scroll-block-storm doesn't generate 1000 spans.
74
+ if (now - _emitWindowStart >= 60_000) {
75
+ _emitWindowStart = now;
76
+ _emitsThisWindow = 0;
77
+ }
78
+ if (_emitsThisWindow >= MAX_EMITS_PER_MIN) return;
79
+ _emitsThisWindow += 1;
80
+
81
+ const span = startSpan('sentori.longtask', {
82
+ name: 'js.longtask',
83
+ startNowMs: now - lag,
84
+ tags: {
85
+ 'profile.kind': 'longtask',
86
+ 'profile.duration_ms': String(Math.round(lag)),
87
+ 'profile.tick_interval_ms': String(TICK_INTERVAL_MS),
88
+ },
89
+ });
90
+ span.finish({ endNowMs: now, status: 'ok' });
91
+ }
92
+
93
+ /** Test-only. */
94
+ export function __resetLongTaskMonitorForTests(): void {
95
+ stopLongTaskMonitor();
96
+ _lastTick = 0;
97
+ _emitWindowStart = 0;
98
+ _emitsThisWindow = 0;
99
+ }
package/src/replay.ts ADDED
@@ -0,0 +1,123 @@
1
+ // v0.9.6 #2 — wireframe Session Replay (SDK side).
2
+ //
3
+ // 60-slot ring buffer of native-captured wireframe snapshots. Each
4
+ // tick calls into `SentoriReplayCapture.captureWireframe(maskIds)`
5
+ // which walks the iOS UIView / Android View hierarchy and returns
6
+ // one JSON string per snapshot. captureException flushes the ring
7
+ // as a `replay` attachment (NDJSON: one snapshot per line).
8
+ //
9
+ // Why wireframe and not raster:
10
+ // • Storage: 80 nodes × ~80 bytes ≈ 6 KB per snapshot vs ~50 KB
11
+ // for a downsampled JPEG. 60-slot ring ≈ 400 KB raw / ~80 KB
12
+ // gzipped — fits comfortably in the 500 KB attachment cap.
13
+ // • Privacy: no pixels means no accidental PII leaks; mask
14
+ // registry decides what text to replace with "***".
15
+ // • Replay fidelity: less faithful to pixels but enough to see
16
+ // which screen the user was on and what was on it. Dashboard
17
+ // player renders SVG rects — denser-looking than a 1 Hz
18
+ // screenshot strip.
19
+
20
+ import { startSpan } from '@goliapkg/sentori-core';
21
+
22
+ import { getRegisteredMaskQuery } from './mask';
23
+ import { isNativeModuleLinked } from './native-loader';
24
+
25
+ const TICK_INTERVAL_MS = 1000;
26
+ const RING_SIZE = 60;
27
+
28
+ let _ring: string[] = [];
29
+ let _timer: ReturnType<typeof setInterval> | null = null;
30
+ let _running = false;
31
+
32
+ export type ReplayOptions = {
33
+ mode?: 'off' | 'wireframe';
34
+ /** Ticks per second. Default 1. */
35
+ hz?: number;
36
+ };
37
+
38
+ export function startReplay(opts: ReplayOptions): void {
39
+ if (_running) return;
40
+ if (opts.mode !== 'wireframe') return;
41
+ // Native replay needs the Sentori native module linked. Defensive
42
+ // — same pattern as other native peers — for Expo Go / unlinked
43
+ // builds.
44
+ if (!isNativeModuleLinked('Sentori') && !isNativeModuleLinked('SentoriModule')) {
45
+ // Falls back silently. Replay rings stay empty; captureException
46
+ // simply doesn't attach a replay.
47
+ return;
48
+ }
49
+ _running = true;
50
+ const period = Math.max(250, Math.floor(1000 / (opts.hz ?? 1)));
51
+ _timer = setInterval(() => {
52
+ captureTick();
53
+ }, period);
54
+ (_timer as unknown as { unref?: () => void }).unref?.();
55
+ }
56
+
57
+ export function stopReplay(): void {
58
+ _running = false;
59
+ if (_timer !== null) {
60
+ clearInterval(_timer);
61
+ _timer = null;
62
+ }
63
+ }
64
+
65
+ function captureTick(): void {
66
+ if (!_running) return;
67
+ const tickSpan = startSpan('sentori.replay.tick', { name: 'tick' });
68
+ try {
69
+ const maskIds = readMaskIds();
70
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
71
+ const nativeMod = loadNativeReplay();
72
+ const snapshot = nativeMod?.captureWireframe?.(maskIds);
73
+ if (typeof snapshot === 'string' && snapshot.length > 0) {
74
+ _ring.push(snapshot);
75
+ while (_ring.length > RING_SIZE) _ring.shift();
76
+ }
77
+ tickSpan.finish({ status: 'ok' });
78
+ } catch (e) {
79
+ if (e instanceof Error) tickSpan.setTag('error.message', e.message);
80
+ tickSpan.finish({ status: 'error' });
81
+ }
82
+ }
83
+
84
+ function readMaskIds(): string[] {
85
+ const q = getRegisteredMaskQuery();
86
+ if (!q) return [];
87
+ try {
88
+ return q();
89
+ } catch {
90
+ return [];
91
+ }
92
+ }
93
+
94
+ type ReplayNativeModule = {
95
+ captureWireframe?: (maskedIds: string[]) => null | string;
96
+ };
97
+
98
+ function loadNativeReplay(): ReplayNativeModule | null {
99
+ try {
100
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
101
+ const core = require('expo-modules-core') as {
102
+ requireNativeModule: <T>(name: string) => T;
103
+ };
104
+ return core.requireNativeModule<ReplayNativeModule>('Sentori');
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+
110
+ /** Drain the ring as NDJSON (one snapshot per line). Empty string
111
+ * when the ring is empty. Also clears the ring so the next session's
112
+ * replay starts fresh. */
113
+ export function drainReplay(): string {
114
+ if (_ring.length === 0) return '';
115
+ const out = _ring.join('\n');
116
+ _ring = [];
117
+ return out;
118
+ }
119
+
120
+ export function __resetReplayForTests(): void {
121
+ stopReplay();
122
+ _ring = [];
123
+ }