@goliapkg/sentori-react-native 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/MIGRATION.md +131 -0
  2. package/README.md +40 -30
  3. package/android/src/main/java/com/sentori/SentoriModule.kt +8 -0
  4. package/android/src/main/java/com/sentori/SentoriScreenshotCapture.kt +36 -4
  5. package/ios/SentoriCrashHandler.swift +48 -4
  6. package/ios/SentoriModule.swift +12 -0
  7. package/ios/SentoriScreenshotCapture.swift +34 -3
  8. package/lib/config.d.ts +1 -0
  9. package/lib/config.d.ts.map +1 -1
  10. package/lib/config.js.map +1 -1
  11. package/lib/index.d.ts +1 -0
  12. package/lib/index.d.ts.map +1 -1
  13. package/lib/index.js +3 -0
  14. package/lib/index.js.map +1 -1
  15. package/lib/init.d.ts.map +1 -1
  16. package/lib/init.js +18 -6
  17. package/lib/init.js.map +1 -1
  18. package/lib/mask.d.ts +8 -0
  19. package/lib/mask.d.ts.map +1 -0
  20. package/lib/mask.js +35 -0
  21. package/lib/mask.js.map +1 -0
  22. package/lib/native.d.ts +4 -11
  23. package/lib/native.d.ts.map +1 -1
  24. package/lib/native.js +23 -0
  25. package/lib/native.js.map +1 -1
  26. package/lib/rage-tap.d.ts.map +1 -1
  27. package/lib/rage-tap.js +30 -2
  28. package/lib/rage-tap.js.map +1 -1
  29. package/lib/replay-screens.d.ts +15 -0
  30. package/lib/replay-screens.d.ts.map +1 -0
  31. package/lib/replay-screens.js +87 -0
  32. package/lib/replay-screens.js.map +1 -0
  33. package/lib/responsiveness-detector.d.ts +18 -0
  34. package/lib/responsiveness-detector.d.ts.map +1 -0
  35. package/lib/responsiveness-detector.js +55 -0
  36. package/lib/responsiveness-detector.js.map +1 -0
  37. package/package.json +3 -2
  38. package/src/__tests__/replay-screens.test.ts +63 -0
  39. package/src/__tests__/responsiveness-detector.test.ts +74 -0
  40. package/src/config.ts +1 -0
  41. package/src/index.ts +3 -0
  42. package/src/init.ts +27 -9
  43. package/src/mask.ts +39 -0
  44. package/src/native.ts +33 -0
  45. package/src/rage-tap.tsx +46 -2
  46. package/src/replay-screens.ts +95 -0
  47. package/src/responsiveness-detector.ts +66 -0
package/MIGRATION.md ADDED
@@ -0,0 +1,131 @@
1
+ # Migrating to @goliapkg/sentori-react-native 5.x
2
+
3
+ 5.0 is the five-kind redesign: the SDK surface shrinks from 40+
4
+ verbs to **eight**, everything is synchronous and can never throw
5
+ into your app, and the server it talks to is the self-hosted
6
+ Sentori 2.x stack. This guide covers every 4.x API a host app is
7
+ likely to use, in the order a migration usually meets them.
8
+
9
+ ```
10
+ sentori.init(config) sentori.user(u) sentori.context(patch)
11
+ sentori.error(err) sentori.warn(name) sentori.trace(name)
12
+ sentori.assert(n, ok) sentori.probe(ref)
13
+ ```
14
+
15
+ ## 1. Install
16
+
17
+ ```bash
18
+ bun add @goliapkg/sentori-react-native@^5.0.0
19
+ # Expo apps also bump the config plugin:
20
+ bun add @goliapkg/sentori-expo@^10.0.0
21
+ # Build pipelines:
22
+ bun add -d @goliapkg/sentori-cli@^1.0.0
23
+ ```
24
+
25
+ `@goliapkg/sentori-core` 2.x comes in transitively. The native
26
+ layer (iOS/Android) is unchanged — no pod/gradle churn, an
27
+ existing dev client keeps working.
28
+
29
+ ## 2. Tokens
30
+
31
+ 4.x `st_pk_…` tokens do not work against the 2.x server. Mint a
32
+ fresh **ingest**-scope token in **Settings → Tokens** and swap it
33
+ into your config. Build-time tooling (sourcemap upload, probe
34
+ sync) needs a separate **api**-scope token — the ingest token
35
+ shipped inside the app is deliberately refused there.
36
+
37
+ ## 3. `init`
38
+
39
+ The `capture.*` switch block is gone. Warn scenarios are detected,
40
+ not configured; replay is a single rolling-buffer knob.
41
+
42
+ ```ts
43
+ // 4.x
44
+ init({
45
+ capture: {
46
+ longTaskMonitor: true,
47
+ preCrashSentinel: true,
48
+ replay: 'wireframe',
49
+ sampleProfiler: false,
50
+ screenshot: true,
51
+ sessionTrail: true,
52
+ },
53
+ environment: 'prod',
54
+ ingestUrl, token, release,
55
+ onReady: (info) => { ... },
56
+ })
57
+
58
+ // 5.x
59
+ init({
60
+ detect: {
61
+ rageTap: true,
62
+ longFreeze: true,
63
+ slowColdStart: true,
64
+ // slowApi stays opt-in
65
+ },
66
+ replaySeconds: 15, // 0 disables; ships only on error/warn
67
+ environment: 'prod',
68
+ ingestUrl, token, release,
69
+ logLevel: 'warn',
70
+ })
71
+ ```
72
+
73
+ Removed with no replacement: `onReady`, `sampleProfiler`,
74
+ `sessionTrail` (the signal ring is always on), `launchCrashGuard`.
75
+ Cold-start timing is internal to the `slow_cold_start` detector —
76
+ `getColdStartMs()` no longer exists; drop it from log lines.
77
+
78
+ ## 4. Verb mapping
79
+
80
+ | 4.x | 5.x |
81
+ |---|---|
82
+ | `sentori.captureException(err, { tags })` | `sentori.error(err, tags)` — data is a flat object |
83
+ | `sentori.captureMessage(msg)` | `sentori.warn(name, data)` — a named sub-health report |
84
+ | `sentori.track(name, props)` | `sentori.trace(name, props)` |
85
+ | `sentori.addBreadcrumb({ type, data })` | `sentori.trace(name, data, { quiet: true })` — ring-only |
86
+ | `sentori.setUser({ id, linkBy: { email }, name })` | `sentori.user({ id, email, name })` — flat shape |
87
+ | `sentori.setUser(null)` | `sentori.user(null)` |
88
+ | `sentori.setFeatureFlag(key, value)` | `sentori.context({ [key]: value })` |
89
+ | — | `sentori.assert(name, ok, data?)` — **new**: production assertion; failure reports, never halts |
90
+ | — | `sentori.probe(ref, data?)` — **new**: regression tripwire; plant in the branch that used to break |
91
+
92
+ Every verb returns immediately, never returns a Promise, and never
93
+ throws — the queue is the contract.
94
+
95
+ ## 5. Components and helpers
96
+
97
+ | 4.x | 5.x |
98
+ |---|---|
99
+ | `<sentori.RageTapCapture>` | `import { RageTapCapture }` — named export, same wrapper role |
100
+ | `<FeedbackButton />` | removed |
101
+ | `sentori.registerMaskQuery(fn)` | removed — screenshot masking returns with the privacy pass |
102
+ | `useTraceNavigation(ref)` | unchanged (feeds `nav` signals + screen names on warns) |
103
+ | `triggerNativeCrash()` | unchanged (dev-panel helper) |
104
+ | `ErrorBoundary` | unchanged |
105
+ | `push.*` namespace | unchanged |
106
+
107
+ ## 6. Build pipeline (CLI 1.x)
108
+
109
+ ```bash
110
+ # Sourcemaps — upload failures print a friendly notice and exit 0
111
+ # so they never block a release; pass --strict to opt into a
112
+ # non-zero exit. Events received before the upload are
113
+ # re-symbolicated automatically afterwards.
114
+ sentori-cli upload sourcemap dist/main.jsbundle.map \
115
+ --release "myapp@1.4.2+381" --token $SENTORI_API_TOKEN
116
+
117
+ # Probe tripwires — static-scans your source for sentori.probe()
118
+ # call sites and registers them against the release, so a silent
119
+ # probe is provable "fix holding".
120
+ sentori-cli probes sync --release "myapp@1.4.2+381" --dir src
121
+ ```
122
+
123
+ ## 7. Worked example
124
+
125
+ The first migration (Qualcomm insight-mobile) touched ten files
126
+ and took the shape above verbatim; the diff is a useful reference:
127
+ `captureException`→`error` in error reporters, `track`/
128
+ `addBreadcrumb`→`trace` in analytics shims, `setUser` flattening
129
+ in the auth listener, `setFeatureFlag`→one `context()` call at
130
+ boot, plus one new `probe()` planted on a previously-fixed bug's
131
+ failure branch.
package/README.md CHANGED
@@ -1,9 +1,15 @@
1
1
  # @goliapkg/sentori-react-native
2
2
 
3
- React Native SDK for [Sentori](https://sentori.golia.jp) — JS layer
4
- + iOS Swift + Android Kotlin native, distributed as an Expo module
3
+ React Native SDK for [Sentori](https://sentori.golia.jp) — the
4
+ self-hosted crash + warning monitor for mobile apps. JS layer +
5
+ iOS Swift + Android Kotlin native, distributed as an Expo module
5
6
  (works on bare RN too).
6
7
 
8
+ Eight verbs are the whole API. Every one is synchronous, returns
9
+ immediately, and can never throw into your app.
10
+
11
+ Upgrading from 4.x? See [MIGRATION.md](./MIGRATION.md).
12
+
7
13
  ## Install
8
14
 
9
15
  ```sh
@@ -17,47 +23,51 @@ cd ios && pod install --repo-update
17
23
  import { sentori } from '@goliapkg/sentori-react-native'
18
24
 
19
25
  sentori.init({
20
- token: 'st_pk_…',
26
+ token: 'st_…', // ingest token, Settings → Tokens
27
+ ingestUrl: 'https://sentori.example.com',
21
28
  release: 'my-app@1.2.3',
22
29
  environment: 'prod',
23
- capture: {
24
- replay: { mode: 'wireframe', hz: 1 },
25
- },
26
30
  })
27
31
 
28
- sentori.captureException(new Error('boom'))
32
+ sentori.user({ id, email, name }) // drives breadth × depth stats
33
+ sentori.context({ tenant: 'acme' }) // ambient tags on every event
34
+
35
+ sentori.error(new Error('boom')) // what broke
36
+ sentori.warn('pay.gateway-retry', data) // where users hurt
37
+ sentori.trace('checkout.start', data) // what happened
38
+ sentori.assert('total-positive', ok) // what should hold (never halts)
39
+ sentori.probe('BUG-123', data) // did that bug come back
29
40
  ```
30
41
 
31
- Auto-wired:
42
+ Auto-wired (no configuration):
32
43
 
33
44
  - JS `error` / `unhandledrejection` global hooks
34
- - iOS `NSException` handler primed by `init`
35
- - Android uncaught exception handler primed by `init`
36
- - Native screenshot + view-tree capture under JS-supplied mask IDs
37
- - Hang watchdog (main blocked > 2s emits `kind: "anr"`)
38
- - Wireframe replay sampler (60 slots × ~120 bytes/frame at idle)
45
+ - iOS `NSException` + Android uncaught-exception handlers
46
+ - Warn scenario detectors: rage taps, long freezes, slow cold start
47
+ (slow API stays opt-in) — tune with `init({ detect })`
48
+ - Signal ring: recent taps, navigation, traces ride along on every
49
+ error/warn as the "what the user was doing" timeline
50
+ - B-type replay: rolling wireframe buffer, shipped only when an
51
+ error/warn actually fires (`init({ replaySeconds })`)
39
52
 
40
- ## Cross-project user lookup (PII-safe)
41
-
42
- ```ts
43
- sentori.setUser({ linkBy: { email: user.email } })
44
- ```
53
+ Identity is hashed on-device with a salted hash — the server never
54
+ sees the raw email.
45
55
 
46
- Identity is hashed on-device with a per-org salt. The server never
47
- sees the raw email / phone.
56
+ ## React extras
48
57
 
49
- ## Sentry compat drop-in
50
-
51
- ```ts
52
- import * as Sentry from '@goliapkg/sentori-react-native/compat'
53
-
54
- Sentry.init({ dsn: 'st_pk_…' })
55
- Sentry.captureException(err)
58
+ ```tsx
59
+ import {
60
+ ErrorBoundary, // React idiom for the error verb
61
+ RageTapCapture, // wrap your root to feed the rage-tap detector
62
+ useTraceNavigation, // pass your react-navigation ref
63
+ } from '@goliapkg/sentori-react-native'
56
64
  ```
57
65
 
58
- → Full guide: [sentori.golia.jp/docs/getting-started/react-native](https://sentori.golia.jp/docs/getting-started/react-native)
59
- → Privacy contract: [sentori.golia.jp/docs/privacy/identity](https://sentori.golia.jp/docs/privacy/identity)
60
- → Sentry translation: [sentori.golia.jp/docs/sentry-compat](https://sentori.golia.jp/docs/sentry-compat)
66
+ ## Build pipeline
67
+
68
+ `@goliapkg/sentori-cli` uploads sourcemaps (failures never block a
69
+ release — friendly notice, exit 0) and registers `probe()`
70
+ tripwires per release. See MIGRATION.md §6.
61
71
 
62
72
  ## License
63
73
 
@@ -79,6 +79,14 @@ class SentoriModule : Module() {
79
79
  SentoriScreenshotCapture.captureScreenshotWithMask(maskedIds)
80
80
  }
81
81
 
82
+ // v5.1 — low-bitrate replay frame (screens ring). Long edge +
83
+ // quality come from JS so the frame budget is tunable without
84
+ // a native release.
85
+ AsyncFunction("captureReplayFrame") {
86
+ maskedIds: List<String>, longEdgePx: Double, quality: Double ->
87
+ SentoriScreenshotCapture.captureReplayFrame(maskedIds, longEdgePx, quality)
88
+ }
89
+
82
90
  // Watchdog is opt-in from JS so the host app picks the
83
91
  // trade-off — stricter detection vs noise from the Metro
84
92
  // debugger pausing the main thread. Pass `force: true` to
@@ -147,9 +147,33 @@ object SentoriScreenshotCapture {
147
147
  return mapOf("base64" to base64, "mediaType" to mediaType)
148
148
  }
149
149
 
150
+ /// v5.1 — low-bitrate replay frame: the screenshot pipeline with
151
+ /// the long edge and quality dialed down by the caller. A replay
152
+ /// ring ticks this a few times per minute, so a frame is budgeted
153
+ /// in tens of KB, not the crash screenshot's hundred.
154
+ @JvmStatic
155
+ fun captureReplayFrame(
156
+ maskedIds: List<String>,
157
+ longEdgePx: Double,
158
+ quality: Double,
159
+ ): Map<String, String>? {
160
+ val activity = SentoriForegroundActivity.current() ?: return null
161
+ val window = activity.window ?: return null
162
+ val pct = (quality * 100).toInt().coerceIn(1, 100)
163
+ val (base64, mediaType) =
164
+ captureScreen(window, maskedIds.toHashSet(), longEdgePx.toFloat(), pct)
165
+ ?: return null
166
+ return mapOf("base64" to base64, "mediaType" to mediaType)
167
+ }
168
+
150
169
  // ── screenshot ────────────────────────────────────────────────
151
170
 
152
- private fun captureScreen(window: Window, maskedIds: Set<String>): Pair<String, String>? {
171
+ private fun captureScreen(
172
+ window: Window,
173
+ maskedIds: Set<String>,
174
+ longEdgePx: Float = MAX_LONG_EDGE_PX.toFloat(),
175
+ qualityPct: Int = -1,
176
+ ): Pair<String, String>? {
153
177
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
154
178
  // PixelCopy is API 24+. Older Android: fall back to a
155
179
  // `View.draw(Canvas)` path that *must* run on main and
@@ -175,7 +199,7 @@ object SentoriScreenshotCapture {
175
199
 
176
200
  // Long-edge scale.
177
201
  val longEdge = maxOf(w, h).toFloat()
178
- val scale = if (longEdge > MAX_LONG_EDGE_PX) MAX_LONG_EDGE_PX / longEdge else 1f
202
+ val scale = if (longEdge > longEdgePx) longEdgePx / longEdge else 1f
179
203
  val outW = (w * scale).toInt().coerceAtLeast(1)
180
204
  val outH = (h * scale).toInt().coerceAtLeast(1)
181
205
  val bitmap = Bitmap.createBitmap(outW, outH, Bitmap.Config.ARGB_8888)
@@ -244,10 +268,18 @@ object SentoriScreenshotCapture {
244
268
  val mediaType: String
245
269
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
246
270
  // Android 11+: native WEBP_LOSSY ~30% smaller than JPEG q=70.
247
- bitmap.compress(Bitmap.CompressFormat.WEBP_LOSSY, WEBP_QUALITY, baos)
271
+ bitmap.compress(
272
+ Bitmap.CompressFormat.WEBP_LOSSY,
273
+ if (qualityPct in 1..100) qualityPct else WEBP_QUALITY,
274
+ baos,
275
+ )
248
276
  mediaType = "image/webp"
249
277
  } else {
250
- bitmap.compress(Bitmap.CompressFormat.JPEG, JPEG_QUALITY, baos)
278
+ bitmap.compress(
279
+ Bitmap.CompressFormat.JPEG,
280
+ if (qualityPct in 1..100) qualityPct else JPEG_QUALITY,
281
+ baos,
282
+ )
251
283
  mediaType = "image/jpeg"
252
284
  }
253
285
  bitmap.recycle()
@@ -1,4 +1,5 @@
1
1
  import Foundation
2
+ import MachO
2
3
 
3
4
  /// Static crash handler — captures NSException and writes one JSON file
4
5
  /// per crash to <Documents>/sentori/pending/<uuid>.json. JS drains that
@@ -87,7 +88,7 @@ import Foundation
87
88
  "error": [
88
89
  "type": exception.name.rawValue,
89
90
  "message": exception.reason ?? "",
90
- "stack": frames(from: exception.callStackSymbols),
91
+ "stack": frames(from: exception.callStackSymbols, addresses: exception.callStackReturnAddresses),
91
92
  "cause": NSNull(),
92
93
  ],
93
94
  "fingerprint": [String](),
@@ -171,8 +172,11 @@ import Foundation
171
172
  /// "1 AppName 0x0001a0b0 -[ClassName method:] + 100"
172
173
  /// We don't have file/line info in raw symbol output; sourcemap-style
173
174
  /// symbolication for native happens server-side (Phase 8+).
174
- private static func frames(from symbols: [String]) -> [[String: Any]] {
175
- return symbols.map { sym -> [String: Any] in
175
+ private static func frames(
176
+ from symbols: [String],
177
+ addresses: [NSNumber] = []
178
+ ) -> [[String: Any]] {
179
+ return symbols.enumerated().map { (i, sym) -> [[String: Any]].Element in
176
180
  let parts = sym.split(separator: " ", omittingEmptySubsequences: true).map(String.init)
177
181
  let module = parts.count > 1 ? parts[1] : "<unknown>"
178
182
  let function = parts.count > 3 ? parts.dropFirst(3).joined(separator: " ") : "<anonymous>"
@@ -181,12 +185,52 @@ import Foundation
181
185
  && !module.contains("CoreFoundation")
182
186
  && !module.contains("libsystem")
183
187
  && !module.contains("libobjc")
184
- return [
188
+ var frame: [String: Any] = [
185
189
  "function": function,
186
190
  "file": module,
187
191
  "line": 0,
188
192
  "inApp": inApp,
189
193
  ]
194
+ // v5.1 — raw address + owning image (base, LC_UUID) so the
195
+ // server can resolve the frame through the release's dSYM
196
+ // slice. dladdr + load-command walk are async-signal-
197
+ // unsafe in general but fine here: NSException handlers
198
+ // run on a live runtime, same as the UIKit capture below.
199
+ if i < addresses.count {
200
+ let addr = addresses[i].uintValue
201
+ var info = Dl_info()
202
+ if dladdr(UnsafeRawPointer(bitPattern: addr), &info) != 0,
203
+ let fbase = info.dli_fbase {
204
+ frame["addr"] = UInt64(addr)
205
+ frame["imageBase"] = UInt64(UInt(bitPattern: fbase))
206
+ if let uuid = imageUuid(atBase: fbase) {
207
+ frame["imageUuid"] = uuid
208
+ }
209
+ }
210
+ }
211
+ return frame
212
+ }
213
+ }
214
+
215
+ /// LC_UUID of the Mach-O image loaded at `base` — the identity a
216
+ /// dSYM slice is matched by. Walks the load commands off the
217
+ /// in-memory header; read-only, bounded, no allocation beyond
218
+ /// the hex string.
219
+ private static func imageUuid(atBase base: UnsafeRawPointer) -> String? {
220
+ let header = base.assumingMemoryBound(to: mach_header_64.self)
221
+ guard header.pointee.magic == MH_MAGIC_64 else { return nil }
222
+ var cursor = base.advanced(by: MemoryLayout<mach_header_64>.size)
223
+ for _ in 0..<header.pointee.ncmds {
224
+ let cmd = cursor.assumingMemoryBound(to: load_command.self)
225
+ if cmd.pointee.cmd == LC_UUID {
226
+ let uuidCmd = cursor.assumingMemoryBound(to: uuid_command.self)
227
+ let u = uuidCmd.pointee.uuid
228
+ let bytes = [u.0, u.1, u.2, u.3, u.4, u.5, u.6, u.7,
229
+ u.8, u.9, u.10, u.11, u.12, u.13, u.14, u.15]
230
+ return bytes.map { String(format: "%02X", $0) }.joined()
231
+ }
232
+ cursor = cursor.advanced(by: Int(cmd.pointee.cmdsize))
190
233
  }
234
+ return nil
191
235
  }
192
236
  }
@@ -77,6 +77,18 @@ public class SentoriModule: Module {
77
77
  return SentoriScreenshotCapture.captureScreenshotWithMask(maskedIds: maskedIds)
78
78
  }
79
79
 
80
+ // v5.1 — low-bitrate replay frame (screens ring). Long edge +
81
+ // quality come from JS so the frame budget is tunable without
82
+ // a native release.
83
+ AsyncFunction("captureReplayFrame") {
84
+ (maskedIds: [String], longEdgePx: Double, quality: Double) -> [String: String]? in
85
+ return SentoriScreenshotCapture.captureReplayFrame(
86
+ maskedIds: maskedIds,
87
+ longEdgePx: longEdgePx,
88
+ quality: quality
89
+ )
90
+ }
91
+
80
92
  // Phase 22 sub-E: opt-in iOS hang watchdog. Same JS function
81
93
  // name as Android (sub-D) so the host app calls
82
94
  // `startAnrWatchdog(...)` once, both platforms react.
@@ -81,6 +81,35 @@ import UIKit
81
81
  return result
82
82
  }
83
83
 
84
+ /// v5.1 — replay-frame capture: the screenshot pipeline with the
85
+ /// long edge and JPEG quality dialed down by the caller. A replay
86
+ /// ring ticks this a few times per minute, so a frame is budgeted
87
+ /// in tens of KB, not the crash screenshot's hundred.
88
+ @objc public static func captureReplayFrame(
89
+ maskedIds: [String],
90
+ longEdgePx: Double,
91
+ quality: Double
92
+ ) -> [String: String]? {
93
+ let run: () -> [String: String]? = {
94
+ guard let window = keyWindowDiag().window else { return nil }
95
+ guard
96
+ let jpeg = renderJpegBase64(
97
+ window: window,
98
+ maskedIds: Set(maskedIds),
99
+ longEdgePx: CGFloat(longEdgePx),
100
+ quality: CGFloat(quality)
101
+ )
102
+ else { return nil }
103
+ return ["base64": jpeg, "mediaType": "image/jpeg"]
104
+ }
105
+ if Thread.isMainThread {
106
+ return run()
107
+ }
108
+ var result: [String: String]?
109
+ DispatchQueue.main.sync { result = run() }
110
+ return result
111
+ }
112
+
84
113
  private static func captureWithMaskSync(maskedIds: [String]) -> [String: String]? {
85
114
  guard let window = keyWindowDiag().window else {
86
115
  lastDiagPath = "window.null"
@@ -191,11 +220,13 @@ import UIKit
191
220
 
192
221
  private static func renderJpegBase64(
193
222
  window: UIWindow,
194
- maskedIds: Set<String> = []
223
+ maskedIds: Set<String> = [],
224
+ longEdgePx: CGFloat = maxLongEdgePx,
225
+ quality: CGFloat = jpegQuality
195
226
  ) -> String? {
196
227
  let bounds = window.bounds
197
228
  let longEdge = max(bounds.width, bounds.height)
198
- let scale: CGFloat = longEdge > maxLongEdgePx ? maxLongEdgePx / longEdge : 1.0
229
+ let scale: CGFloat = longEdge > longEdgePx ? longEdgePx / longEdge : 1.0
199
230
  let outSize = CGSize(width: bounds.width * scale, height: bounds.height * scale)
200
231
  guard outSize.width > 1, outSize.height > 1 else { return nil }
201
232
 
@@ -230,7 +261,7 @@ import UIKit
230
261
  }
231
262
  }
232
263
  }
233
- guard let data = image.jpegData(compressionQuality: jpegQuality) else {
264
+ guard let data = image.jpegData(compressionQuality: quality) else {
234
265
  return nil
235
266
  }
236
267
  return data.base64EncodedString()
package/lib/config.d.ts CHANGED
@@ -14,6 +14,7 @@ export type Config = {
14
14
  };
15
15
  /** B-type replay rolling buffer, seconds. 0 disables. */
16
16
  replaySeconds: number;
17
+ replayScreens: boolean;
17
18
  /** Sentori console output gate. Default `warn`: silent on the
18
19
  * host's console unless something is genuinely broken. */
19
20
  logLevel?: LogLevel;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,MAAM,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,OAAO,CAAC;QACpB,aAAa,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB;+DAC2D;IAC3D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;8DAC0D;IAC1D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,SAAS,GAAG,IAAI,CAAC;CACrD,CAAC;AAIF,eAAO,MAAM,SAAS,WAAY,MAAM,KAAG,IAE1C,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,MAAM,GAAG,IAAe,CAAC;AAEtD,eAAO,MAAM,aAAa,QAAO,OAA2B,CAAC;AAE7D,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,MAAM,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,OAAO,CAAC;QACpB,aAAa,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB;+DAC2D;IAC3D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;8DAC0D;IAC1D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,SAAS,GAAG,IAAI,CAAC;CACrD,CAAC;AAIF,eAAO,MAAM,SAAS,WAAY,MAAM,KAAG,IAE1C,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,MAAM,GAAG,IAAe,CAAC;AAEtD,eAAO,MAAM,aAAa,QAAO,OAA2B,CAAC;AAE7D,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
package/lib/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kEAAkE;AAClE,4DAA4D;AA2B5D,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAc,EAAQ,EAAE;IAChD,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAkB,EAAE,CAAC,OAAO,CAAC;AAEtD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAY,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC;AAE7D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE;IACxC,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kEAAkE;AAClE,4DAA4D;AA4B5D,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAc,EAAQ,EAAE;IAChD,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAkB,EAAE,CAAC,OAAO,CAAC;AAEtD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAY,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC;AAE7D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE;IACxC,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC,CAAC"}
package/lib/index.d.ts CHANGED
@@ -30,6 +30,7 @@ export default sentori;
30
30
  export { init } from './init';
31
31
  export { ErrorBoundary } from './error-boundary';
32
32
  export { RageTapCapture } from './rage-tap';
33
+ export { registerMaskQuery } from './mask';
33
34
  export { triggerNativeCrash } from './native';
34
35
  export { type NavigationRefLike, useTraceNavigation } from './navigation';
35
36
  export type { AssertStat, Device, EventData, EventKind, Frame, InitConfig, SentoriApi, SentoriError, Signal, Surface, TraceOptions, User, WireEvent, WirePayload, } from '@goliapkg/sentori-core';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,IAAI,EACL,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,OAAO;IAClB,2DAA2D;IAC3D,IAAI,WAAW,UAAU,KAAG,IAAI;IAGhC;;4CAEwC;IACxC,IAAI,MAAM,IAAI,GAAG,IAAI,KAAG,IAAI;IAG5B;8CAC0C;IAC1C,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;IAI/C;sEACkE;IAClE,KAAK,QAAQ,OAAO,SAAS,SAAS,KAAG,MAAM;IAC/C,kDAAkD;IAClD,IAAI,SAAS,MAAM,SAAS,SAAS,KAAG,MAAM;IAC9C;6DACyD;IACzD,KAAK,SAAS,MAAM,SAAS,SAAS,SAAS,YAAY,KAAG,MAAM;IAEpE;;mDAE+C;IAC/C,MAAM,SAAS,MAAM,MAAM,OAAO,SAAS,SAAS,KAAG,MAAM;IAE7D;;qCAEiC;IACjC,KAAK,QAAQ,MAAM,SAAS,SAAS,KAAG,MAAM;CAC/C,CAAC;eAEa,OAAO;AAEtB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAG1E,YAAY,EACV,UAAU,EACV,MAAM,EACN,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,EACV,UAAU,EACV,YAAY,EACZ,MAAM,EACN,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,WAAW,EACX,KAAK,QAAQ,EACb,WAAW,EACX,KAAK,YAAY,EACjB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,IAAI,EACL,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,OAAO;IAClB,2DAA2D;IAC3D,IAAI,WAAW,UAAU,KAAG,IAAI;IAGhC;;4CAEwC;IACxC,IAAI,MAAM,IAAI,GAAG,IAAI,KAAG,IAAI;IAG5B;8CAC0C;IAC1C,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;IAI/C;sEACkE;IAClE,KAAK,QAAQ,OAAO,SAAS,SAAS,KAAG,MAAM;IAC/C,kDAAkD;IAClD,IAAI,SAAS,MAAM,SAAS,SAAS,KAAG,MAAM;IAC9C;6DACyD;IACzD,KAAK,SAAS,MAAM,SAAS,SAAS,SAAS,YAAY,KAAG,MAAM;IAEpE;;mDAE+C;IAC/C,MAAM,SAAS,MAAM,MAAM,OAAO,SAAS,SAAS,KAAG,MAAM;IAE7D;;qCAEiC;IACjC,KAAK,QAAQ,MAAM,SAAS,SAAS,KAAG,MAAM;CAC/C,CAAC;eAEa,OAAO;AAEtB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAG3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAG1E,YAAY,EACV,UAAU,EACV,MAAM,EACN,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,EACV,UAAU,EACV,YAAY,EACZ,MAAM,EACN,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,WAAW,EACX,KAAK,QAAQ,EACb,WAAW,EACX,KAAK,YAAY,EACjB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
package/lib/index.js CHANGED
@@ -48,6 +48,9 @@ export default sentori;
48
48
  export { init } from './init';
49
49
  export { ErrorBoundary } from './error-boundary';
50
50
  export { RageTapCapture } from './rage-tap';
51
+ // Privacy: register a query returning nativeIDs that must be
52
+ // blacked out in every captured frame (visual replay, screenshots).
53
+ export { registerMaskQuery } from './mask';
51
54
  // Dev-panel helper: crash the native layer on purpose to exercise
52
55
  // the pending-crash upload pipeline. Not part of the 8-verb surface.
53
56
  export { triggerNativeCrash } from './native';
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,8CAA8C;AAC9C,EAAE;AACF,gEAAgE;AAChE,oEAAoE;AACpE,qEAAqE;AACrE,8DAA8D;AAE9D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAShC,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,2DAA2D;IAC3D,IAAI,EAAE,CAAC,MAAkB,EAAQ,EAAE;QACjC,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC;IACD;;4CAEwC;IACxC,IAAI,EAAE,CAAC,CAAc,EAAQ,EAAE;QAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;IACD;8CAC0C;IAC1C,OAAO,EAAE,CAAC,KAA8B,EAAQ,EAAE;QAChD,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED;sEACkE;IAClE,KAAK,EAAE,CAAC,GAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;IACzE,kDAAkD;IAClD,IAAI,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;IACxE;6DACyD;IACzD,KAAK,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAE,IAAmB,EAAU,EAAE,CACrE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC/B;;mDAE+C;IAC/C,MAAM,EAAE,CAAC,IAAY,EAAE,EAAW,EAAE,IAAgB,EAAU,EAAE,CAC9D,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC;IAC9B;;qCAEiC;IACjC,KAAK,EAAE,CAAC,GAAW,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;CACzE,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,kEAAkE;AAClE,qEAAqE;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAoB1E,mDAAmD;AACnD,OAAO,EACL,WAAW,EAEX,WAAW,EAEX,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,qEAAqE;AACrE,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,8CAA8C;AAC9C,EAAE;AACF,gEAAgE;AAChE,oEAAoE;AACpE,qEAAqE;AACrE,8DAA8D;AAE9D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAShC,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,2DAA2D;IAC3D,IAAI,EAAE,CAAC,MAAkB,EAAQ,EAAE;QACjC,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,CAAC;IACD;;4CAEwC;IACxC,IAAI,EAAE,CAAC,CAAc,EAAQ,EAAE;QAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;IACD;8CAC0C;IAC1C,OAAO,EAAE,CAAC,KAA8B,EAAQ,EAAE;QAChD,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED;sEACkE;IAClE,KAAK,EAAE,CAAC,GAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;IACzE,kDAAkD;IAClD,IAAI,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;IACxE;6DACyD;IACzD,KAAK,EAAE,CAAC,IAAY,EAAE,IAAgB,EAAE,IAAmB,EAAU,EAAE,CACrE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC/B;;mDAE+C;IAC/C,MAAM,EAAE,CAAC,IAAY,EAAE,EAAW,EAAE,IAAgB,EAAU,EAAE,CAC9D,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC;IAC9B;;qCAEiC;IACjC,KAAK,EAAE,CAAC,GAAW,EAAE,IAAgB,EAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC;CACzE,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,6DAA6D;AAC7D,oEAAoE;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,kEAAkE;AAClE,qEAAqE;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAA0B,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAoB1E,mDAAmD;AACnD,OAAO,EACL,WAAW,EAEX,WAAW,EAEX,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,qEAAqE;AACrE,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
package/lib/init.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiBzD,eAAO,MAAM,IAAI,0CA+Ef,CAAC;AAeH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,eAAO,MAAM,IAAI,0CAgGf,CAAC;AAeH,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}
package/lib/init.js CHANGED
@@ -14,6 +14,7 @@ import { checkColdStart } from './mobile-vitals';
14
14
  import { markNativeJsBridgeReady, setNativeConfig } from './native';
15
15
  import { shipNativePending } from './native-pending';
16
16
  import { drainReplay, startReplay } from './replay';
17
+ import { drainScreenReplay, startScreenReplay } from './replay-screens';
17
18
  import { drainOfflineQueue, startTransport, uploadAttachment } from './transport';
18
19
  let _initialized = false;
19
20
  export const init = safeFn('init', (config) => {
@@ -43,6 +44,7 @@ export const init = safeFn('init', (config) => {
43
44
  slowApi: config.detect?.slowApi ?? false,
44
45
  },
45
46
  replaySeconds: config.replaySeconds ?? 30,
47
+ replayScreens: config.replayScreens ?? false,
46
48
  beforeSend: config.beforeSend,
47
49
  });
48
50
  setLogLevel(config.logLevel ?? 'warn');
@@ -60,18 +62,28 @@ export const init = safeFn('init', (config) => {
60
62
  const replaySeconds = config.replaySeconds ?? 30;
61
63
  if (replaySeconds > 0) {
62
64
  startReplay({ mode: 'wireframe' });
65
+ // Visual ring is opt-in: screenshots can carry user content.
66
+ if (config.replayScreens === true)
67
+ startScreenReplay(replaySeconds);
63
68
  registerEmitHook((event) => {
64
69
  if (event.kind !== 'error' && event.kind !== 'warn')
65
70
  return;
66
71
  if (!event.id)
67
72
  return;
68
73
  const lines = drainReplay();
69
- if (!lines)
70
- return;
71
- const base64 = base64Encode(lines);
72
- if (!base64)
73
- return;
74
- void uploadAttachment(event.id, 'replay', { base64, mediaType: 'application/x-sentori-replay' }, { source: 'js' });
74
+ if (lines) {
75
+ const base64 = base64Encode(lines);
76
+ if (base64) {
77
+ void uploadAttachment(event.id, 'replay', { base64, mediaType: 'application/x-sentori-replay' }, { source: 'js' });
78
+ }
79
+ }
80
+ const frames = drainScreenReplay();
81
+ if (frames) {
82
+ const base64 = base64Encode(frames);
83
+ if (base64) {
84
+ void uploadAttachment(event.id, 'screens', { base64, mediaType: 'application/x-sentori-screens' }, { source: 'js' });
85
+ }
86
+ }
75
87
  });
76
88
  }
77
89
  // Native side: hand over release/environment for the crash-file
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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"}
package/lib/mask.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ type MaskQuery = () => string[];
2
+ /** Register (or with `null`, clear) the mask query. */
3
+ export declare const registerMaskQuery: (query: MaskQuery | null) => void;
4
+ /** The current mask list; empty when unregistered or throwing. */
5
+ export declare const maskedNativeIds: () => string[];
6
+ export declare const __resetForTests: () => void;
7
+ export {};
8
+ //# sourceMappingURL=mask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAeA,KAAK,SAAS,GAAG,MAAM,MAAM,EAAE,CAAC;AAIhC,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,UAAW,SAAS,GAAG,IAAI,KAAG,IAE3D,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,eAAe,QAAO,MAAM,EASxC,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC"}