@goliapkg/sentori-react-native 0.7.2 → 0.7.3
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/SentoriModule.kt +10 -0
- package/android/src/main/java/com/sentori/SentoriScreenshotCapture.kt +60 -2
- package/ios/SentoriModule.swift +10 -0
- package/ios/SentoriScreenshotCapture.swift +76 -2
- package/lib/handlers/screenshot.d.ts +3 -2
- package/lib/handlers/screenshot.d.ts.map +1 -1
- package/lib/handlers/screenshot.js +47 -94
- package/lib/handlers/screenshot.js.map +1 -1
- package/lib/index.d.ts +4 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -5
- package/lib/index.js.map +1 -1
- package/lib/init.d.ts +8 -4
- package/lib/init.d.ts.map +1 -1
- package/lib/init.js.map +1 -1
- package/lib/mask.d.ts +11 -47
- package/lib/mask.d.ts.map +1 -1
- package/lib/mask.js +27 -116
- package/lib/mask.js.map +1 -1
- package/lib/native.d.ts +15 -0
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +22 -0
- package/lib/native.js.map +1 -1
- package/package.json +3 -8
- package/src/__tests__/screenshot.test.ts +6 -8
- package/src/handlers/screenshot.ts +46 -117
- package/src/index.ts +4 -5
- package/src/init.ts +8 -4
- package/src/mask.ts +41 -0
- package/src/native.ts +35 -0
- package/src/mask.tsx +0 -150
|
@@ -28,6 +28,16 @@ class SentoriModule : Module() {
|
|
|
28
28
|
SentoriCrashHandler.consumePending()
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// v0.7.3 — JS-triggered screenshot path with consumer-supplied
|
|
32
|
+
// mask IDs. JS owns the registry of `nativeID`s to redact;
|
|
33
|
+
// native walks the view tree and paints black rectangles in
|
|
34
|
+
// the rendered bitmap. Returns `null` when no activity / API
|
|
35
|
+
// < 24 / capture timed out. Replaces the previous
|
|
36
|
+
// `react-native-view-shot` peer-dep path.
|
|
37
|
+
AsyncFunction("captureScreenshotWithMask") { maskedIds: List<String> ->
|
|
38
|
+
SentoriScreenshotCapture.captureScreenshotWithMask(maskedIds)
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
// Watchdog is opt-in from JS so the host app picks the
|
|
32
42
|
// trade-off — stricter detection vs noise from the Metro
|
|
33
43
|
// debugger pausing the main thread. Pass `force: true` to
|
|
@@ -4,6 +4,8 @@ import android.app.Activity
|
|
|
4
4
|
import android.app.Application
|
|
5
5
|
import android.graphics.Bitmap
|
|
6
6
|
import android.graphics.Canvas
|
|
7
|
+
import android.graphics.Color
|
|
8
|
+
import android.graphics.Paint
|
|
7
9
|
import android.os.Build
|
|
8
10
|
import android.os.Bundle
|
|
9
11
|
import android.os.Handler
|
|
@@ -103,16 +105,30 @@ object SentoriScreenshotCapture {
|
|
|
103
105
|
val activity = lastActivity?.get() ?: return null
|
|
104
106
|
val window = activity.window ?: return null
|
|
105
107
|
val out = mutableMapOf<String, Any>()
|
|
106
|
-
captureScreen(window)?.let { (base64, mediaType) ->
|
|
108
|
+
captureScreen(window, emptySet())?.let { (base64, mediaType) ->
|
|
107
109
|
out["screenshot"] = mapOf("base64" to base64, "mediaType" to mediaType)
|
|
108
110
|
}
|
|
109
111
|
out["viewTree"] = walkTree(window.decorView)
|
|
110
112
|
return if (out.isEmpty()) null else out
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
/// v0.7.3 — JS-triggered screenshot path with consumer-supplied
|
|
116
|
+
/// mask IDs. Returns `{ base64, mediaType }` or `null`; matches
|
|
117
|
+
/// the iOS bridge contract. Native walks the view tree by
|
|
118
|
+
/// `View.tag` (RN bridges JS `nativeID` to the default String tag
|
|
119
|
+
/// on the underlying View) and paints black rectangles over each
|
|
120
|
+
/// masked subview's frame on the captured bitmap.
|
|
121
|
+
@JvmStatic
|
|
122
|
+
fun captureScreenshotWithMask(maskedIds: List<String>): Map<String, String>? {
|
|
123
|
+
val activity = lastActivity?.get() ?: return null
|
|
124
|
+
val window = activity.window ?: return null
|
|
125
|
+
val (base64, mediaType) = captureScreen(window, maskedIds.toHashSet()) ?: return null
|
|
126
|
+
return mapOf("base64" to base64, "mediaType" to mediaType)
|
|
127
|
+
}
|
|
128
|
+
|
|
113
129
|
// ── screenshot ────────────────────────────────────────────────
|
|
114
130
|
|
|
115
|
-
private fun captureScreen(window: Window): Pair<String, String>? {
|
|
131
|
+
private fun captureScreen(window: Window, maskedIds: Set<String>): Pair<String, String>? {
|
|
116
132
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
|
117
133
|
// PixelCopy is API 24+. Older Android: fall back to a
|
|
118
134
|
// `View.draw(Canvas)` path that *must* run on main and
|
|
@@ -166,6 +182,28 @@ object SentoriScreenshotCapture {
|
|
|
166
182
|
}
|
|
167
183
|
if (!success) return null
|
|
168
184
|
|
|
185
|
+
// v0.7.3 — paint black rectangles over masked subviews on the
|
|
186
|
+
// already-captured bitmap. We get window-relative coordinates
|
|
187
|
+
// from `getLocationInWindow` (respects parent transforms) and
|
|
188
|
+
// scale them down to the output bitmap size.
|
|
189
|
+
if (maskedIds.isNotEmpty()) {
|
|
190
|
+
val regions = findMaskedViews(decor, maskedIds)
|
|
191
|
+
if (regions.isNotEmpty()) {
|
|
192
|
+
val canvas = Canvas(bitmap)
|
|
193
|
+
val paint = Paint().apply { color = Color.BLACK }
|
|
194
|
+
val rootLoc = IntArray(2).also { decor.getLocationInWindow(it) }
|
|
195
|
+
val tmp = IntArray(2)
|
|
196
|
+
for (v in regions) {
|
|
197
|
+
v.getLocationInWindow(tmp)
|
|
198
|
+
val x = (tmp[0] - rootLoc[0]) * scale
|
|
199
|
+
val y = (tmp[1] - rootLoc[1]) * scale
|
|
200
|
+
val rw = v.width * scale
|
|
201
|
+
val rh = v.height * scale
|
|
202
|
+
canvas.drawRect(x, y, x + rw, y + rh, paint)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
169
207
|
val baos = ByteArrayOutputStream(64 * 1024)
|
|
170
208
|
val mediaType: String
|
|
171
209
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
@@ -181,6 +219,26 @@ object SentoriScreenshotCapture {
|
|
|
181
219
|
return Pair(base64, mediaType)
|
|
182
220
|
}
|
|
183
221
|
|
|
222
|
+
/// Depth-first walk that stops descending once a masked subtree
|
|
223
|
+
/// is hit. RN bridges JS `nativeID` to `View.setTag(Object)` with
|
|
224
|
+
/// a String value — that's why we cast to `String` rather than
|
|
225
|
+
/// looking at the int resource-id tag space.
|
|
226
|
+
private fun findMaskedViews(root: View, ids: Set<String>): List<View> {
|
|
227
|
+
val out = mutableListOf<View>()
|
|
228
|
+
fun walk(v: View) {
|
|
229
|
+
val tag = v.tag as? String
|
|
230
|
+
if (tag != null && ids.contains(tag)) {
|
|
231
|
+
out.add(v)
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
if (v is ViewGroup) {
|
|
235
|
+
for (i in 0 until v.childCount) walk(v.getChildAt(i))
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
walk(root)
|
|
239
|
+
return out
|
|
240
|
+
}
|
|
241
|
+
|
|
184
242
|
// ── view tree ─────────────────────────────────────────────────
|
|
185
243
|
|
|
186
244
|
/** Synchronously walk the view hierarchy from `root`. Safe to call
|
package/ios/SentoriModule.swift
CHANGED
|
@@ -24,6 +24,16 @@ public class SentoriModule: Module {
|
|
|
24
24
|
return SentoriCrashHandler.consumePending()
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// v0.7.3 — JS-triggered screenshot path with consumer-supplied
|
|
28
|
+
// mask IDs. JS owns the registry of `nativeID`s to redact;
|
|
29
|
+
// native walks the view tree and paints black rectangles in
|
|
30
|
+
// the rendered bitmap. Returns `nil` (resolves to `null` in
|
|
31
|
+
// JS) when there's no key window or render fails. Replaces
|
|
32
|
+
// the previous `react-native-view-shot` peer-dep path.
|
|
33
|
+
AsyncFunction("captureScreenshotWithMask") { (maskedIds: [String]) -> [String: String]? in
|
|
34
|
+
return SentoriScreenshotCapture.captureScreenshotWithMask(maskedIds: maskedIds)
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
// Phase 22 sub-E: opt-in iOS hang watchdog. Same JS function
|
|
28
38
|
// name as Android (sub-D) so the host app calls
|
|
29
39
|
// `startAnrWatchdog(...)` once, both platforms react.
|
|
@@ -61,6 +61,37 @@ import UIKit
|
|
|
61
61
|
return result
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/// v0.7.3 — JS-triggered screenshot path. Returns just
|
|
65
|
+
/// `{ base64, mediaType }`; view tree not needed (errors that
|
|
66
|
+
/// reach here are non-fatal and surface the tree via the
|
|
67
|
+
/// breadcrumb / stack pipeline already). When `maskedIds` is
|
|
68
|
+
/// non-empty we walk the view hierarchy by
|
|
69
|
+
/// `accessibilityIdentifier` (RN bridges `nativeID` to this on
|
|
70
|
+
/// iOS) and paint a black rectangle over each subview's frame in
|
|
71
|
+
/// the captured bitmap. Called from `Sentori.captureScreenshotWithMask`
|
|
72
|
+
/// in the Expo Module bridge.
|
|
73
|
+
@objc public static func captureScreenshotWithMask(maskedIds: [String]) -> [String: String]? {
|
|
74
|
+
if Thread.isMainThread {
|
|
75
|
+
return captureWithMaskSync(maskedIds: maskedIds)
|
|
76
|
+
}
|
|
77
|
+
var result: [String: String]?
|
|
78
|
+
DispatchQueue.main.sync {
|
|
79
|
+
result = captureWithMaskSync(maskedIds: maskedIds)
|
|
80
|
+
}
|
|
81
|
+
return result
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private static func captureWithMaskSync(maskedIds: [String]) -> [String: String]? {
|
|
85
|
+
guard let window = keyWindow() else { return nil }
|
|
86
|
+
guard let jpeg = renderJpegBase64(window: window, maskedIds: Set(maskedIds)) else {
|
|
87
|
+
return nil
|
|
88
|
+
}
|
|
89
|
+
return [
|
|
90
|
+
"base64": jpeg,
|
|
91
|
+
"mediaType": "image/jpeg",
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
// MARK: - Internals
|
|
65
96
|
|
|
66
97
|
private static func captureSync() -> [String: Any]? {
|
|
@@ -92,7 +123,10 @@ import UIKit
|
|
|
92
123
|
return UIApplication.shared.windows.first
|
|
93
124
|
}
|
|
94
125
|
|
|
95
|
-
private static func renderJpegBase64(
|
|
126
|
+
private static func renderJpegBase64(
|
|
127
|
+
window: UIWindow,
|
|
128
|
+
maskedIds: Set<String> = []
|
|
129
|
+
) -> String? {
|
|
96
130
|
let bounds = window.bounds
|
|
97
131
|
let longEdge = max(bounds.width, bounds.height)
|
|
98
132
|
let scale: CGFloat = longEdge > maxLongEdgePx ? maxLongEdgePx / longEdge : 1.0
|
|
@@ -103,11 +137,32 @@ import UIKit
|
|
|
103
137
|
format.scale = 1.0
|
|
104
138
|
format.opaque = true
|
|
105
139
|
let renderer = UIGraphicsImageRenderer(size: outSize, format: format)
|
|
106
|
-
let image = renderer.image {
|
|
140
|
+
let image = renderer.image { ctx in
|
|
107
141
|
window.drawHierarchy(
|
|
108
142
|
in: CGRect(origin: .zero, size: outSize),
|
|
109
143
|
afterScreenUpdates: false
|
|
110
144
|
)
|
|
145
|
+
// v0.7.3 — paint a black rectangle over every masked
|
|
146
|
+
// subview's frame, in the same render pass so we don't
|
|
147
|
+
// pay for a second bitmap allocation. `convert(_,to:)`
|
|
148
|
+
// handles transforms and nested coordinate spaces; the
|
|
149
|
+
// scale factor maps window-points to output-pixels.
|
|
150
|
+
if !maskedIds.isEmpty {
|
|
151
|
+
let regions = findMaskedSubviews(rootView: window, ids: maskedIds)
|
|
152
|
+
if !regions.isEmpty {
|
|
153
|
+
UIColor.black.setFill()
|
|
154
|
+
for v in regions {
|
|
155
|
+
let rect = v.convert(v.bounds, to: window)
|
|
156
|
+
let scaled = CGRect(
|
|
157
|
+
x: rect.origin.x * scale,
|
|
158
|
+
y: rect.origin.y * scale,
|
|
159
|
+
width: rect.size.width * scale,
|
|
160
|
+
height: rect.size.height * scale
|
|
161
|
+
)
|
|
162
|
+
ctx.fill(scaled)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
111
166
|
}
|
|
112
167
|
guard let data = image.jpegData(compressionQuality: jpegQuality) else {
|
|
113
168
|
return nil
|
|
@@ -115,6 +170,25 @@ import UIKit
|
|
|
115
170
|
return data.base64EncodedString()
|
|
116
171
|
}
|
|
117
172
|
|
|
173
|
+
/// Depth-first walk that stops descending once a masked subtree
|
|
174
|
+
/// is hit — the entire region is being blacked out, no need to
|
|
175
|
+
/// look at children for a second match.
|
|
176
|
+
private static func findMaskedSubviews(
|
|
177
|
+
rootView: UIView,
|
|
178
|
+
ids: Set<String>
|
|
179
|
+
) -> [UIView] {
|
|
180
|
+
var found: [UIView] = []
|
|
181
|
+
func walk(_ v: UIView) {
|
|
182
|
+
if let id = v.accessibilityIdentifier, ids.contains(id) {
|
|
183
|
+
found.append(v)
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
for sub in v.subviews { walk(sub) }
|
|
187
|
+
}
|
|
188
|
+
walk(rootView)
|
|
189
|
+
return found
|
|
190
|
+
}
|
|
191
|
+
|
|
118
192
|
private static func walkTree(root: UIView) -> [String: Any] {
|
|
119
193
|
var nodes: [String: Any] = [:]
|
|
120
194
|
var counter = 0
|
|
@@ -5,8 +5,9 @@ export type ScreenshotBlob = {
|
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
7
|
* Take one screenshot, yielding the JS thread first. Returns null on
|
|
8
|
-
* any error (
|
|
9
|
-
* Caller is responsible for opt-in checks
|
|
8
|
+
* any error (no native module bound, native side refused, capture
|
|
9
|
+
* timed out, etc.). Caller is responsible for opt-in checks
|
|
10
|
+
* (`config.screenshotsEnabled`).
|
|
10
11
|
*/
|
|
11
12
|
export declare function captureScreenshot(): Promise<ScreenshotBlob | null>;
|
|
12
13
|
//# sourceMappingURL=screenshot.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/handlers/screenshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/handlers/screenshot.ts"],"names":[],"mappings":"AA8BA,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BxE"}
|
|
@@ -1,109 +1,62 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// v0.7.3 — capture a screenshot of the current view tree on
|
|
2
|
+
// `captureException`. Off-main-thread, best-effort, opt-in.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// - On any failure we silently return null. The error event still
|
|
11
|
-
// goes to the server; the user just doesn't see a thumbnail.
|
|
4
|
+
// JS owns the registry of which regions to redact: the host app
|
|
5
|
+
// passes a thunk via `sentori.registerMaskQuery(() => string[])` that
|
|
6
|
+
// returns the `nativeID`s currently mounted as masked. We call it
|
|
7
|
+
// once per capture and forward the list to the native module, which
|
|
8
|
+
// renders the bitmap and paints black rectangles over the matching
|
|
9
|
+
// subviews in a single pass.
|
|
12
10
|
//
|
|
13
|
-
// `react-native-view-shot`
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
11
|
+
// History: pre-v0.7.3 went through `react-native-view-shot` (peer
|
|
12
|
+
// dep) and used a JS-side overlay-opacity trick (`<MaskRegion>` /
|
|
13
|
+
// `setMaskedNode`) to hide PII before snapshotting. That design put
|
|
14
|
+
// the SDK on the render path; a single SDK bug could break the host
|
|
15
|
+
// app's UI. v0.7.3 cuts that coupling — the SDK no longer ships
|
|
16
|
+
// React components, and the screenshot path runs entirely through
|
|
17
|
+
// the native module already used for native-crash captures.
|
|
17
18
|
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// commit before captureRef snapshots.
|
|
29
|
-
import { engageMasks } from '../mask';
|
|
30
|
-
function loadCaptureRef() {
|
|
31
|
-
try {
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
33
|
-
const mod = require('react-native-view-shot');
|
|
34
|
-
return mod.captureRef ?? mod.default?.captureRef ?? null;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const MAX_LONG_EDGE_PX = 480;
|
|
41
|
-
const WEBP_QUALITY = 0.7;
|
|
42
|
-
const CAPTURE_TIMEOUT_MS = 1500;
|
|
19
|
+
// Performance:
|
|
20
|
+
// - Yield one paint via `requestAnimationFrame` before the native
|
|
21
|
+
// call so post-error UI state has committed.
|
|
22
|
+
// - 480 px on the longest edge, JPEG q=70 (iOS) / WEBP_LOSSY q=70
|
|
23
|
+
// (Android 11+). Typical payload 30-80 KB; multipart hard cap
|
|
24
|
+
// is 500 KB.
|
|
25
|
+
// - On any failure we silently return null. The error event still
|
|
26
|
+
// goes to the server; the user just doesn't see a thumbnail.
|
|
27
|
+
import { getRegisteredMaskQuery } from '../mask';
|
|
28
|
+
import { captureNativeScreenshotWithMask } from '../native';
|
|
43
29
|
/**
|
|
44
30
|
* Take one screenshot, yielding the JS thread first. Returns null on
|
|
45
|
-
* any error (
|
|
46
|
-
* Caller is responsible for opt-in checks
|
|
31
|
+
* any error (no native module bound, native side refused, capture
|
|
32
|
+
* timed out, etc.). Caller is responsible for opt-in checks
|
|
33
|
+
* (`config.screenshotsEnabled`).
|
|
47
34
|
*/
|
|
48
35
|
export async function captureScreenshot() {
|
|
49
|
-
const captureRef = loadCaptureRef();
|
|
50
|
-
if (!captureRef)
|
|
51
|
-
return null;
|
|
52
36
|
// Yield one paint frame so the post-error UI has committed before
|
|
53
|
-
// we ask the OS to snapshot it.
|
|
54
|
-
// `InteractionManager.runAfterInteractions` step was removed: see
|
|
55
|
-
// file header — its replacement (`requestIdleCallback`) doesn't
|
|
56
|
-
// exist in RN, and on captureException the user is between actions
|
|
57
|
-
// anyway, so the gesture-batch-drain semantics never came into
|
|
58
|
-
// play in practice.
|
|
59
|
-
await new Promise((resolve) => {
|
|
60
|
-
requestAnimationFrame(() => resolve());
|
|
61
|
-
});
|
|
62
|
-
// Phase 48 sub-B — flip every registered MaskRegion overlay to
|
|
63
|
-
// opacity 1 (black covers the children) and every imperative
|
|
64
|
-
// setMaskedNode ref to opacity 0 (subtree disappears). Held for
|
|
65
|
-
// exactly one frame's worth of capture, then restored.
|
|
66
|
-
const restoreMasks = engageMasks();
|
|
67
|
-
// Yield one more frame so the overlay paint reaches the screen
|
|
68
|
-
// before captureRef snapshots. Without this the overlay opacity
|
|
69
|
-
// change is queued but the screenshotter may see the previous
|
|
70
|
-
// frame.
|
|
37
|
+
// we ask the OS to snapshot it.
|
|
71
38
|
await new Promise((resolve) => {
|
|
72
39
|
requestAnimationFrame(() => resolve());
|
|
73
40
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// RN minimum we support has it everywhere.
|
|
90
|
-
return { base64, mediaType: 'image/jpeg' };
|
|
41
|
+
// Read the consumer-supplied mask query once per capture. If
|
|
42
|
+
// the host never called `registerMaskQuery`, no mask is applied
|
|
43
|
+
// and the full screenshot ships — sane default: SDK does nothing
|
|
44
|
+
// unless told to.
|
|
45
|
+
const query = getRegisteredMaskQuery();
|
|
46
|
+
let maskedIds = [];
|
|
47
|
+
if (query) {
|
|
48
|
+
try {
|
|
49
|
+
maskedIds = query();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// A throwing query is the host's bug, not ours; skip mask
|
|
53
|
+
// rather than skip the screenshot.
|
|
54
|
+
maskedIds = [];
|
|
55
|
+
}
|
|
91
56
|
}
|
|
92
|
-
|
|
93
|
-
|
|
57
|
+
const result = await captureNativeScreenshotWithMask(maskedIds);
|
|
58
|
+
if (!result)
|
|
94
59
|
return null;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function withTimeout(p, ms) {
|
|
98
|
-
return new Promise((resolve) => {
|
|
99
|
-
const t = setTimeout(() => resolve(null), ms);
|
|
100
|
-
p.then((v) => {
|
|
101
|
-
clearTimeout(t);
|
|
102
|
-
resolve(v);
|
|
103
|
-
}, () => {
|
|
104
|
-
clearTimeout(t);
|
|
105
|
-
resolve(null);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
60
|
+
return { base64: result.base64, mediaType: result.mediaType };
|
|
108
61
|
}
|
|
109
62
|
//# sourceMappingURL=screenshot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/handlers/screenshot.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/handlers/screenshot.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,4DAA4D;AAC5D,EAAE;AACF,gEAAgE;AAChE,sEAAsE;AACtE,kEAAkE;AAClE,oEAAoE;AACpE,mEAAmE;AACnE,6BAA6B;AAC7B,EAAE;AACF,kEAAkE;AAClE,kEAAkE;AAClE,oEAAoE;AACpE,oEAAoE;AACpE,gEAAgE;AAChE,kEAAkE;AAClE,4DAA4D;AAC5D,EAAE;AACF,eAAe;AACf,oEAAoE;AACpE,iDAAiD;AACjD,oEAAoE;AACpE,kEAAkE;AAClE,iBAAiB;AACjB,oEAAoE;AACpE,iEAAiE;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,+BAA+B,EAAE,MAAM,WAAW,CAAC;AAQ5D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,kEAAkE;IAClE,gCAAgC;IAChC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,qBAAqB,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,6DAA6D;IAC7D,gEAAgE;IAChE,iEAAiE;IACjE,kBAAkB;IAClB,MAAM,KAAK,GAAG,sBAAsB,EAAE,CAAC;IACvC,IAAI,SAAS,GAAa,EAAE,CAAC;IAC7B,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC;YACH,SAAS,GAAG,KAAK,EAAE,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,0DAA0D;YAC1D,mCAAmC;YACnC,SAAS,GAAG,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,+BAA+B,CAAC,SAAS,CAAC,CAAC;IAChE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;AAChE,CAAC"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ErrorBoundary } from './error-boundary';
|
|
2
|
-
import {
|
|
2
|
+
import { clearMaskQuery, registerMaskQuery } from './mask';
|
|
3
3
|
export declare const sentori: {
|
|
4
4
|
init: (options: import("./init").InitOptions) => void;
|
|
5
5
|
addBreadcrumb: (input: import("./breadcrumbs").AddBreadcrumbInput) => void;
|
|
@@ -9,9 +9,8 @@ export declare const sentori: {
|
|
|
9
9
|
captureException: (error: Error, extras?: import("./capture").CaptureExtras) => void;
|
|
10
10
|
captureStep: (label: string, opts?: Partial<import("@goliapkg/sentori-core").TrailStep>) => void;
|
|
11
11
|
ErrorBoundary: typeof ErrorBoundary;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
unsetMaskedNode: typeof unsetMaskedNode;
|
|
12
|
+
registerMaskQuery: typeof registerMaskQuery;
|
|
13
|
+
clearMaskQuery: typeof clearMaskQuery;
|
|
15
14
|
startSession: () => void;
|
|
16
15
|
endSession: (status?: "exited") => void;
|
|
17
16
|
markSessionCrashed: () => void;
|
|
@@ -21,7 +20,7 @@ export { init, init as initSentori } from './init';
|
|
|
21
20
|
export { addBreadcrumb } from './breadcrumbs';
|
|
22
21
|
export { captureError, captureException, captureStep, getUser, setUser, } from './capture';
|
|
23
22
|
export { ErrorBoundary } from './error-boundary';
|
|
24
|
-
export {
|
|
23
|
+
export { clearMaskQuery, registerMaskQuery } from './mask';
|
|
25
24
|
export { startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
|
|
26
25
|
export { endSession, markSessionCrashed, startSession, } from './session-tracker';
|
|
27
26
|
export { type NavigationRefLike, useTraceNavigation } from './navigation';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAO3D,eAAO,MAAM,OAAO;;;;;;;;;;;;;;CAcnB,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,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,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/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { init } from './init';
|
|
|
2
2
|
import { addBreadcrumb } from './breadcrumbs';
|
|
3
3
|
import { setUser, getUser, captureError, captureException, captureStep } from './capture';
|
|
4
4
|
import { ErrorBoundary } from './error-boundary';
|
|
5
|
-
import {
|
|
5
|
+
import { clearMaskQuery, registerMaskQuery } from './mask';
|
|
6
6
|
import { endSession, markSessionCrashed, startSession, } from './session-tracker';
|
|
7
7
|
export const sentori = {
|
|
8
8
|
init,
|
|
@@ -13,9 +13,8 @@ export const sentori = {
|
|
|
13
13
|
captureException,
|
|
14
14
|
captureStep,
|
|
15
15
|
ErrorBoundary,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
unsetMaskedNode,
|
|
16
|
+
registerMaskQuery,
|
|
17
|
+
clearMaskQuery,
|
|
19
18
|
startSession,
|
|
20
19
|
endSession,
|
|
21
20
|
markSessionCrashed,
|
|
@@ -25,7 +24,7 @@ export { init, init as initSentori } from './init';
|
|
|
25
24
|
export { addBreadcrumb } from './breadcrumbs';
|
|
26
25
|
export { captureError, captureException, captureStep, getUser, setUser, } from './capture';
|
|
27
26
|
export { ErrorBoundary } from './error-boundary';
|
|
28
|
-
export {
|
|
27
|
+
export { clearMaskQuery, registerMaskQuery } from './mask';
|
|
29
28
|
export { startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
|
|
30
29
|
export { endSession, markSessionCrashed, startSession, } from './session-tracker';
|
|
31
30
|
export { useTraceNavigation } from './navigation';
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI;IACJ,aAAa;IACb,OAAO;IACP,OAAO;IACP,YAAY;IACZ,gBAAgB;IAChB,WAAW;IACX,aAAa;IACb,iBAAiB;IACjB,cAAc;IACd,YAAY;IACZ,UAAU;IACV,kBAAkB;CACnB,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,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,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,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/lib/init.d.ts
CHANGED
|
@@ -17,10 +17,14 @@ export type InitOptions = {
|
|
|
17
17
|
* foreground (`AppState` → `active`), ends it on background.
|
|
18
18
|
* Drives crash-free rate. Set `false` to opt out. */
|
|
19
19
|
sessions?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
/** Capture a screenshot of the current screen on
|
|
21
|
+
* `captureException`. Opt-in. The capture runs through the
|
|
22
|
+
* bundled native module — no extra peer dep required since
|
|
23
|
+
* v0.7.3. To redact PII regions, register a mask query via
|
|
24
|
+
* `sentori.registerMaskQuery(() => string[])` and put
|
|
25
|
+
* `nativeID="..."` on the `<View>`s the SDK should black out.
|
|
26
|
+
* The image is webp q=70 / jpeg q=70 at 480 px max, < 100 KB
|
|
27
|
+
* typical. */
|
|
24
28
|
screenshot?: boolean;
|
|
25
29
|
/** Phase 46: record the last N steps (route changes, custom
|
|
26
30
|
* breadcrumbs) leading up to a crash. On `captureException`
|
package/lib/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAaA,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,EAAE,OAAO,CAAC;QAClB;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAaA,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,EAAE,OAAO,CAAC;QAClB;;8DAEsD;QACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB;;;;;;;uBAOe;QACf,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB;;;6CAGqC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,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,IAoF3C,CAAC;AAiBF,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
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,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC/D,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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"}
|
package/lib/mask.d.ts
CHANGED
|
@@ -1,52 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
import { type ViewProps } from 'react-native';
|
|
3
|
-
/** What we drive in the capture window: any handle with
|
|
4
|
-
* `setNativeProps({ opacity })`. RN's View instance satisfies this. */
|
|
5
|
-
type Maskable = {
|
|
6
|
-
setNativeProps?: (props: {
|
|
7
|
-
style?: {
|
|
8
|
-
opacity?: number;
|
|
9
|
-
};
|
|
10
|
-
}) => void;
|
|
11
|
-
};
|
|
1
|
+
type MaskQuery = () => string[];
|
|
12
2
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
export declare function setMaskedNode(node: null | Maskable | unknown): void;
|
|
17
|
-
export declare function unsetMaskedNode(node: null | Maskable | unknown): void;
|
|
18
|
-
/** Returns the current set of registered masked nodes + nativeIDs.
|
|
19
|
-
* Read by the native screenshotter layer (iOS / Android sub-E / F). */
|
|
20
|
-
export declare function getMaskedRegions(): {
|
|
21
|
-
nativeIds: Set<string>;
|
|
22
|
-
overlays: Set<Maskable>;
|
|
23
|
-
refs: Set<Maskable>;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Phase 48 sub-B — engage masking right before screenshot capture.
|
|
27
|
-
* Returns a function the caller must invoke once capture is done so
|
|
28
|
-
* the user never sees the black overlays.
|
|
29
|
-
*
|
|
30
|
-
* Two paths:
|
|
31
|
-
* - Overlays from `<MaskRegion>`: flip opacity 0 → 1 (cover children).
|
|
32
|
-
* - Imperative refs from `setMaskedNode`: flip opacity 1 → 0 on the
|
|
33
|
-
* view itself (whole subtree disappears for one frame).
|
|
3
|
+
* Register a callback the SDK calls right before each screenshot
|
|
4
|
+
* capture. Return the native-IDs (the `nativeID` prop on the RN
|
|
5
|
+
* `<View>`) that should be blacked-out in the captured image.
|
|
34
6
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
export declare function engageMasks(): () => void;
|
|
39
|
-
/**
|
|
40
|
-
* Declarative redaction. `<MaskRegion>{children}</MaskRegion>` keeps
|
|
41
|
-
* the children visible in normal flight; under capture the overlay's
|
|
42
|
-
* opacity is flipped to 1 and the children are hidden behind a black
|
|
43
|
-
* square in the rendered screenshot.
|
|
7
|
+
* Idempotent: a second call replaces the first. Pass `null` (or
|
|
8
|
+
* call `clearMaskQuery`) to detach.
|
|
44
9
|
*/
|
|
45
|
-
export declare function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
export declare function __resetMaskedRegionsForTests(): void;
|
|
10
|
+
export declare function registerMaskQuery(query: MaskQuery): void;
|
|
11
|
+
/** Unregister. Mostly for tests / teardown. */
|
|
12
|
+
export declare function clearMaskQuery(): void;
|
|
13
|
+
/** Internal — read by `handlers/screenshot.ts` at capture time. */
|
|
14
|
+
export declare function getRegisteredMaskQuery(): MaskQuery | null;
|
|
51
15
|
export {};
|
|
52
16
|
//# sourceMappingURL=mask.d.ts.map
|
package/lib/mask.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.
|
|
1
|
+
{"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAgBA,KAAK,SAAS,GAAG,MAAM,MAAM,EAAE,CAAC;AAIhC;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAExD;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,mEAAmE;AACnE,wBAAgB,sBAAsB,IAAI,SAAS,GAAG,IAAI,CAEzD"}
|