@scalebun/react-native 1.3.1 → 1.3.2-beta.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.
@@ -301,7 +301,11 @@ class ReplaySdkModule(reactContext: ReactApplicationContext) : ReplaySdkSpec(rea
301
301
  return
302
302
  }
303
303
 
304
- val config = ReplayConfig()
304
+ // Honor the host's privacy config when the SDK stored one (native
305
+ // initialize()/initOutbox()). Falling back to a fresh ReplayConfig() — as
306
+ // before — still masks text inputs, since maskTextInputs defaults to true;
307
+ // this additionally honors maskImages / maskedElementIds and an explicit opt-out.
308
+ val config = outboxConfig ?: ReplayConfig()
305
309
  val captureManager = com.scalebun.replaysdk.capture.FrameCaptureManager(config)
306
310
  captureManager.capture(activity, "standalone", "unknown", reason, config) { frame ->
307
311
  captureManager.destroy()
@@ -152,7 +152,21 @@ class FrameCaptureManager(private var config: ReplayConfig) {
152
152
 
153
153
  acquireBitmap(
154
154
  activity, captureView,
155
- onBitmap = { bmp -> compressAndEmit(bmp, targetWidth, targetHeight, sessionId, screenName, trigger, cfg, callback) },
155
+ onBitmap = { bmp ->
156
+ // Privacy masking on the full-res bitmap BEFORE scaling — identical to
157
+ // captureToFile(). Without this, the default base64 path (used whenever
158
+ // the native file outbox is off) uploaded text inputs UNMASKED while
159
+ // still stamping masked=true. FAIL CLOSED: if masking throws, the frame
160
+ // is DISCARDED — never emitted unmasked, never with a falsely-true flag.
161
+ val masked = applyMaskSafe(bmp, captureView, cfg)
162
+ if (masked == null) {
163
+ ReplayLogger.warn("capture: masking failed — frame dropped (fail-closed)")
164
+ if (!bmp.isRecycled) bmp.recycle()
165
+ callback(null)
166
+ } else {
167
+ compressAndEmit(masked, targetWidth, targetHeight, sessionId, screenName, trigger, cfg, callback)
168
+ }
169
+ },
156
170
  onFail = { callback(null) }
157
171
  )
158
172
  }
@@ -385,6 +399,11 @@ class FrameCaptureManager(private var config: ReplayConfig) {
385
399
  val actualFormat = if (format == Bitmap.CompressFormat.JPEG) "jpeg" else "webp"
386
400
 
387
401
  val seq = sequenceCounter.incrementAndGet()
402
+ // Truthful masked flag: the bitmap reaching here has already been through
403
+ // applyMaskSafe() in capture() (fail-closed — an unmasked frame never gets
404
+ // here), so this reflects what was actually configured. Mirrors
405
+ // compressToBytes()'s maskApplied, incl. maskedElementIds.
406
+ val maskApplied = cfg.maskTextInputs || cfg.maskImages || cfg.maskedElementIds.isNotEmpty()
388
407
  val frame = ReplayFrame(
389
408
  frameId = SessionIdGenerator.frameId(),
390
409
  sessionId = sessionId,
@@ -397,7 +416,7 @@ class FrameCaptureManager(private var config: ReplayConfig) {
397
416
  width = bitmap.width,
398
417
  height = bitmap.height,
399
418
  quality = cfg.screenshotQuality.value,
400
- masked = cfg.maskTextInputs || cfg.maskImages,
419
+ masked = maskApplied,
401
420
  base64 = base64
402
421
  )
403
422
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalebun/react-native",
3
- "version": "1.3.1",
3
+ "version": "1.3.2-beta.0",
4
4
  "description": "Production-grade React Native SDK for ScaleBun",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",