@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.
- package/android/src/main/java/com/sentori/SentoriCrashHandler.kt +3 -0
- package/android/src/main/java/com/sentori/SentoriModule.kt +5 -0
- package/android/src/main/java/com/sentori/SentoriReplayCapture.kt +153 -0
- package/ios/SentoriModule.swift +5 -0
- package/ios/SentoriReplayCapture.swift +147 -0
- package/lib/capture.d.ts.map +1 -1
- package/lib/capture.js +26 -0
- package/lib/capture.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/init.d.ts +16 -0
- package/lib/init.d.ts.map +1 -1
- package/lib/init.js +18 -0
- package/lib/init.js.map +1 -1
- package/lib/long-task-monitor.d.ts +11 -0
- package/lib/long-task-monitor.d.ts.map +1 -0
- package/lib/long-task-monitor.js +88 -0
- package/lib/long-task-monitor.js.map +1 -0
- package/lib/replay.d.ts +13 -0
- package/lib/replay.d.ts.map +1 -0
- package/lib/replay.js +111 -0
- package/lib/replay.js.map +1 -0
- package/package.json +2 -2
- package/src/capture.ts +31 -0
- package/src/init.ts +28 -0
- package/src/long-task-monitor.ts +99 -0
- package/src/replay.ts +123 -0
|
@@ -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
|
+
}
|
package/ios/SentoriModule.swift
CHANGED
|
@@ -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
|
+
}
|
package/lib/capture.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"
|
|
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. */
|
package/lib/capture.js.map
CHANGED
|
@@ -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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"}
|
package/lib/index.d.ts.map
CHANGED
|
@@ -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;;;;;;;;;;
|
|
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":"
|
|
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":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAwB,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,OAAO,EACP,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;
|
|
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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"}
|
package/lib/replay.d.ts
ADDED
|
@@ -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.
|
|
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.
|
|
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
|
+
}
|