@scalebun/react-native 1.13.0 → 2.0.1

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 (115) hide show
  1. package/android/build.gradle +8 -0
  2. package/android/src/androidTest/java/com/scalebun/rn/ota/ScaleBunOtaVerifierInstrumentedTest.kt +112 -0
  3. package/android/src/main/java/com/scalebun/rn/ota/BundleDownloader.kt +10 -0
  4. package/android/src/main/java/com/scalebun/rn/ota/DeviceIntegrity.kt +75 -0
  5. package/android/src/main/java/com/scalebun/rn/ota/OtaProtocol.kt +244 -0
  6. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaKeyRegistry.kt +100 -0
  7. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaModule.kt +132 -62
  8. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaReleaseVerifier.kt +129 -0
  9. package/android/src/main/java/com/scalebun/rn/ota/SlotManager.kt +80 -1
  10. package/android/src/main/java/com/scalebun/rn/ota/TlsPinning.kt +118 -0
  11. package/android/src/oldarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +6 -8
  12. package/dist/scalebun.full.js +964 -533
  13. package/dist/scalebun.slim.js +962 -531
  14. package/ios/Ota/OtaProtocol.swift +242 -0
  15. package/ios/Ota/OtaSlotManager.swift +26 -0
  16. package/ios/Ota/ScaleBunOtaBridge.mm +6 -3
  17. package/ios/Ota/ScaleBunOtaKeyRegistry.swift +147 -0
  18. package/ios/Ota/ScaleBunOtaModule.swift +125 -53
  19. package/ios/Ota/ScaleBunOtaReleaseVerifier.swift +115 -0
  20. package/ios/Ota/ScaleBunOtaVerifierTests.swift +92 -0
  21. package/ios/ReplaySdk.swift +65 -2
  22. package/lib/commonjs/bootstrap/SDKBootstrapper.js +30 -0
  23. package/lib/commonjs/core/config/schema.js +19 -12
  24. package/lib/commonjs/core/constants/version.js +1 -1
  25. package/lib/commonjs/features/journey/ScaleBunDebugRoot.js +293 -5
  26. package/lib/commonjs/features/journey/ScaleBunScrollView.js +28 -0
  27. package/lib/commonjs/features/journey/autoInstrumentScroll.js +161 -0
  28. package/lib/commonjs/features/journey/interactionProtocol.js +131 -10
  29. package/lib/commonjs/features/journey/scrollContext.js +146 -0
  30. package/lib/commonjs/features/journey/targetGeometry.js +164 -0
  31. package/lib/commonjs/features/journey/touchTarget.js +152 -24
  32. package/lib/commonjs/features/journey/uiState.js +81 -1
  33. package/lib/commonjs/features/navigation/AutoScreenDetector.js +74 -5
  34. package/lib/commonjs/features/network/NetworkFeature.js +39 -5
  35. package/lib/commonjs/features/network/thirdParty.js +90 -0
  36. package/lib/commonjs/features/ota/OtaOrchestrator.js +175 -80
  37. package/lib/commonjs/features/session/SessionManager.js +63 -0
  38. package/lib/commonjs/public/ScaleBunFacade.js +23 -57
  39. package/lib/module/bootstrap/SDKBootstrapper.js +30 -0
  40. package/lib/module/core/config/schema.js +19 -12
  41. package/lib/module/core/constants/version.js +1 -1
  42. package/lib/module/features/journey/ScaleBunDebugRoot.js +295 -7
  43. package/lib/module/features/journey/ScaleBunScrollView.js +28 -0
  44. package/lib/module/features/journey/autoInstrumentScroll.js +155 -0
  45. package/lib/module/features/journey/interactionProtocol.js +128 -8
  46. package/lib/module/features/journey/scrollContext.js +135 -0
  47. package/lib/module/features/journey/targetGeometry.js +155 -0
  48. package/lib/module/features/journey/touchTarget.js +151 -24
  49. package/lib/module/features/journey/uiState.js +78 -1
  50. package/lib/module/features/navigation/AutoScreenDetector.js +74 -5
  51. package/lib/module/features/network/NetworkFeature.js +38 -4
  52. package/lib/module/features/network/thirdParty.js +83 -0
  53. package/lib/module/features/ota/OtaOrchestrator.js +175 -80
  54. package/lib/module/features/session/SessionManager.js +63 -0
  55. package/lib/module/public/ScaleBunFacade.js +23 -57
  56. package/lib/typescript/core/config/schema.d.ts +2 -3
  57. package/lib/typescript/core/constants/version.d.ts +1 -1
  58. package/lib/typescript/features/journey/autoInstrumentScroll.d.ts +46 -0
  59. package/lib/typescript/features/journey/interactionProtocol.d.ts +139 -1
  60. package/lib/typescript/features/journey/scrollContext.d.ts +85 -0
  61. package/lib/typescript/features/journey/targetGeometry.d.ts +114 -0
  62. package/lib/typescript/features/journey/touchTarget.d.ts +148 -15
  63. package/lib/typescript/features/journey/uiState.d.ts +39 -0
  64. package/lib/typescript/features/navigation/AutoScreenDetector.d.ts +48 -2
  65. package/lib/typescript/features/network/index.d.ts +18 -0
  66. package/lib/typescript/features/network/thirdParty.d.ts +65 -0
  67. package/lib/typescript/features/ota/OtaOrchestrator.d.ts +12 -8
  68. package/lib/typescript/features/ota/OtaTypes.d.ts +22 -0
  69. package/lib/typescript/features/session/SessionManager.d.ts +55 -0
  70. package/lib/typescript/public/ScaleBunFacade.d.ts +5 -11
  71. package/lib/typescript/public/types.d.ts +10 -0
  72. package/lib/typescript/specs/NativeScaleBunOta.d.ts +32 -20
  73. package/package.json +3 -13
  74. package/scalebun-react-native.podspec +4 -0
  75. package/src/bootstrap/SDKBootstrapper.ts +40 -0
  76. package/src/core/config/schema.ts +21 -9
  77. package/src/core/constants/version.ts +1 -1
  78. package/src/features/journey/ScaleBunDebugRoot.tsx +288 -7
  79. package/src/features/journey/ScaleBunScrollView.tsx +29 -0
  80. package/src/features/journey/autoInstrumentScroll.ts +155 -0
  81. package/src/features/journey/interactionProtocol.ts +188 -10
  82. package/src/features/journey/scrollContext.ts +137 -0
  83. package/src/features/journey/targetGeometry.ts +176 -0
  84. package/src/features/journey/touchTarget.ts +237 -26
  85. package/src/features/journey/uiState.ts +80 -1
  86. package/src/features/navigation/AutoScreenDetector.ts +65 -5
  87. package/src/features/network/NetworkFeature.ts +41 -4
  88. package/src/features/network/index.ts +18 -0
  89. package/src/features/network/thirdParty.ts +92 -0
  90. package/src/features/ota/OtaOrchestrator.ts +190 -90
  91. package/src/features/ota/OtaTypes.ts +23 -1
  92. package/src/features/session/SessionManager.ts +113 -0
  93. package/src/public/ScaleBunFacade.ts +23 -69
  94. package/src/public/types.ts +10 -0
  95. package/src/specs/NativeScaleBunOta.ts +35 -20
  96. package/lib/commonjs/features/ota/crypto/builtinVerifier.js +0 -248
  97. package/lib/commonjs/features/ota/crypto/loadEd25519.js +0 -40
  98. package/lib/commonjs/features/ota/crypto/loadSha512.js +0 -40
  99. package/lib/commonjs/features/ota/crypto/nativeVerifier.js +0 -121
  100. package/lib/commonjs/features/ota/signature.js +0 -175
  101. package/lib/module/features/ota/crypto/builtinVerifier.js +0 -240
  102. package/lib/module/features/ota/crypto/loadEd25519.js +0 -34
  103. package/lib/module/features/ota/crypto/loadSha512.js +0 -34
  104. package/lib/module/features/ota/crypto/nativeVerifier.js +0 -113
  105. package/lib/module/features/ota/signature.js +0 -169
  106. package/lib/typescript/features/ota/crypto/builtinVerifier.d.ts +0 -53
  107. package/lib/typescript/features/ota/crypto/loadEd25519.d.ts +0 -30
  108. package/lib/typescript/features/ota/crypto/loadSha512.d.ts +0 -15
  109. package/lib/typescript/features/ota/crypto/nativeVerifier.d.ts +0 -35
  110. package/lib/typescript/features/ota/signature.d.ts +0 -81
  111. package/src/features/ota/crypto/builtinVerifier.ts +0 -257
  112. package/src/features/ota/crypto/loadEd25519.ts +0 -41
  113. package/src/features/ota/crypto/loadSha512.ts +0 -35
  114. package/src/features/ota/crypto/nativeVerifier.ts +0 -117
  115. package/src/features/ota/signature.ts +0 -206
@@ -175,7 +175,7 @@ class ScaleBunFacade {
175
175
  const realQueue = _container.coreContainer.get('PersistentQueue');
176
176
  const buffered = this._preInitBuffer.popBatch(this._preInitBuffer.length());
177
177
  if (buffered.length > 0) {
178
- __DEV__ && _internalLogger.logger.debug(`[ScaleBun] Draining ${buffered.length} pre-init events into persistent queue`);
178
+ _internalLogger.logger.debug(`[ScaleBun] Draining ${buffered.length} pre-init events into persistent queue`);
179
179
  for (const envelope of buffered) {
180
180
  realQueue.add(envelope);
181
181
  }
@@ -215,17 +215,11 @@ class ScaleBunFacade {
215
215
  /**
216
216
  * Boot the OTA orchestrator when the init config asks for it.
217
217
  *
218
- * `publicSigningKey` / `publicSigningKeys` are honoured here so signature
219
- * enforcement is reachable from configuration alone. The list form exists
220
- * for key ROTATION: a build pinning [old, new] keeps verifying while the
221
- * server moves to the new key, so replacing a key never needs an emergency
222
- * store release. Both fields merge (deduplicated) into one pinned set.
223
- *
224
- * Verification comes from `ota.verifySignature` when supplied, else the
225
- * built-in @noble-based verifier (optional peers). Pinning keys with
226
- * NEITHER available is fail-CLOSED by design (signature.ts) — an update
227
- * that cannot be verified is not installed. We say that out loud rather
228
- * than letting the app discover it as a silent no-update condition.
218
+ * Signature enforcement is no longer configured from JS. Signed releases are
219
+ * verified and staged in NATIVE code against RSA keys embedded in the app
220
+ * package (SB-OTA-RSA-SHA256-V1); unsigned releases keep working on SHA-256
221
+ * integrity. There are no signing-key or `verifySignature` options to pass
222
+ * through the host embeds its trusted keys natively.
229
223
  */
230
224
  _maybeStartOta(rawConfig) {
231
225
  const ota = rawConfig?.ota;
@@ -237,42 +231,12 @@ class ScaleBunFacade {
237
231
  const {
238
232
  otaOrchestrator
239
233
  } = require('../features/ota/OtaOrchestrator');
240
- const rawSingle = ota.publicSigningKey;
241
- const rawList = ota.publicSigningKeys;
242
- const publicKeys = Array.from(new Set([...(typeof rawSingle === 'string' && rawSingle ? [rawSingle] : []), ...(Array.isArray(rawList) ? rawList : [])].filter(k => typeof k === 'string' && k.trim().length > 0)));
243
- // Signing was REQUESTED if a usable key exists, or the host passed a
244
- // keys array at all — an empty one included. `publicSigningKeys: []`
245
- // is a broken attempt to enable signing, and it must flow through to
246
- // signature.ts's fail-closed handling, not silently disable signing.
247
- const signingRequested = publicKeys.length > 0 || Array.isArray(rawList);
248
- const verifier = ota.verifySignature;
249
- if (signingRequested && typeof verifier !== 'function') {
250
- // A host verifier is optional since the built-in one landed — the
251
- // old unconditional warning here told every correctly-configured
252
- // app that its updates would be rejected. Warn only when neither
253
- // verifier can actually be resolved.
254
- // eslint-disable-next-line @typescript-eslint/no-var-requires
255
- const {
256
- getBuiltinVerifier
257
- } = require('../features/ota/crypto/builtinVerifier');
258
- if (!getBuiltinVerifier()) {
259
- _internalLogger.logger.warn('[ScaleBun] A signing key is pinned but no signature verifier is available. ' + 'Signature checking is fail-closed: updates will be REJECTED until one exists. ' + 'Install the optional peers `@noble/ed25519` + `@noble/hashes` (no further ' + 'code needed), or supply `ota.verifySignature`.');
260
- }
261
- }
262
234
  // `healthyAfterMs` is the field BootGuardConfig actually declares.
263
235
  // This passed `healthyTimeoutMs`, which nothing reads, so a host that
264
236
  // tuned the boot-guard window silently got the 10s default instead.
265
237
  // Both spellings are accepted so the older one keeps working.
266
238
  const healthyAfterMs = typeof ota.healthyAfterMs === 'number' ? ota.healthyAfterMs : typeof ota.healthyTimeoutMs === 'number' ? ota.healthyTimeoutMs : undefined;
267
239
  otaOrchestrator.init({
268
- ...(signingRequested ? {
269
- signature: {
270
- // Single key stays a plain string — the shape every
271
- // existing consumer and test already handles.
272
- publicKey: publicKeys.length === 1 ? publicKeys[0] : publicKeys,
273
- verifier
274
- }
275
- } : {}),
276
240
  ...(healthyAfterMs !== undefined ? {
277
241
  healthyAfterMs
278
242
  } : {})
@@ -339,7 +303,9 @@ class ScaleBunFacade {
339
303
  }
340
304
  const clientKey = this._clientKey;
341
305
  const apiUrl = this._apiBaseUrl;
342
- if (!clientKey || !apiUrl) return;
306
+ if (!clientKey || !apiUrl) {
307
+ return;
308
+ }
343
309
  this._otaCheckInFlight = true;
344
310
  try {
345
311
  const info = await _bridgeAdapter.bridgeAdapter.getDeviceInfo();
@@ -396,7 +362,7 @@ class ScaleBunFacade {
396
362
  if (!dbgConfig) return;
397
363
  dbgConfig.__skipDeprecationWarning = true;
398
364
  this.enableDebug(dbgConfig);
399
- __DEV__ && _internalLogger.logger.info('[ScaleBun] Debug auto-connected via init({ debug }).');
365
+ _internalLogger.logger.info('[ScaleBun] Debug auto-connected via init({ debug }).');
400
366
  } catch (err) {
401
367
  _internalLogger.logger.warn('[ScaleBun] Auto debug connection failed:', err?.message);
402
368
  }
@@ -413,7 +379,7 @@ class ScaleBunFacade {
413
379
  const apiBaseUrl = this._apiBaseUrl;
414
380
  if (!enabled || !appId || !clientKey || !apiBaseUrl) {
415
381
  if (enabled && !appId) {
416
- __DEV__ && _internalLogger.logger.info('[ScaleBun] Envelope event tracking disabled — no appId in init config.');
382
+ _internalLogger.logger.info('[ScaleBun] Envelope event tracking disabled — no appId in init config.');
417
383
  }
418
384
  return;
419
385
  }
@@ -465,7 +431,7 @@ class ScaleBunFacade {
465
431
  onEvent: (eventName, revenue) => this._skanManager?.onEvent(eventName, revenue)
466
432
  });
467
433
  this._eventTracker.start();
468
- __DEV__ && _internalLogger.logger.info('[ScaleBun] Envelope event tracking started → /v1/batch.');
434
+ _internalLogger.logger.info('[ScaleBun] Envelope event tracking started → /v1/batch.');
469
435
 
470
436
  // Complete the device context from the native bridge.
471
437
  //
@@ -1147,7 +1113,7 @@ class ScaleBunFacade {
1147
1113
  const cfg = await (this._getEngageTransport()?.fetchEngageConfig(context) ?? Promise.resolve(null));
1148
1114
  const messages = cfg?.inAppMessages ?? [];
1149
1115
  const previews = messages.filter(m => m.preview === true || m.isTest === true);
1150
- __DEV__ && _internalLogger.logger.info(`[Engage] debugFetchInAppMessages → ${messages.length} message(s), ${previews.length} test preview(s)`);
1116
+ _internalLogger.logger.info(`[Engage] debugFetchInAppMessages → ${messages.length} message(s), ${previews.length} test preview(s)`);
1151
1117
  return messages;
1152
1118
  },
1153
1119
  /** Upload a survey/NPS/feedback response (idempotent, rides the outbox). */
@@ -1432,7 +1398,7 @@ class ScaleBunFacade {
1432
1398
  _internalLogger.logger.warn('SDK not initialized. Event dropped:', name);
1433
1399
  return;
1434
1400
  }
1435
- __DEV__ && _internalLogger.logger.debug('Tracking event:', name);
1401
+ _internalLogger.logger.debug('Tracking event:', name);
1436
1402
 
1437
1403
  // Fan this event out to the Engage trigger engine. Same single funnel,
1438
1404
  // extra observer — lets behavioral triggers (custom_event, failed_action,
@@ -1605,7 +1571,7 @@ class ScaleBunFacade {
1605
1571
  await Promise.all([this._eventTracker?.flush() ?? Promise.resolve(), adapter?.flushAnalytics() ?? Promise.resolve()]);
1606
1572
  return;
1607
1573
  }
1608
- __DEV__ && _internalLogger.logger.debug('Flushing events from persistent queue...');
1574
+ _internalLogger.logger.debug('Flushing events from persistent queue...');
1609
1575
  const httpClient = _container.coreContainer.get('HttpClient');
1610
1576
  await (0, _flushQueue.flushQueue)(this._getQueue(), httpClient, (0, _deviceId.getDeviceId)());
1611
1577
  });
@@ -1628,9 +1594,9 @@ class ScaleBunFacade {
1628
1594
  const bootstrapPerfFeature = (0, _debug.getPerformanceFeature)();
1629
1595
  if (bootstrapPerfFeature) {
1630
1596
  this._performanceFeature = bootstrapPerfFeature;
1631
- __DEV__ && _internalLogger.logger.debug('Performance feature linked from bootstrap');
1597
+ _internalLogger.logger.debug('Performance feature linked from bootstrap');
1632
1598
  }
1633
- __DEV__ && _internalLogger.logger.info('Debug enabled');
1599
+ _internalLogger.logger.info('Debug enabled');
1634
1600
  });
1635
1601
  }
1636
1602
 
@@ -1782,14 +1748,14 @@ class ScaleBunFacade {
1782
1748
  return false;
1783
1749
  }
1784
1750
  sm.startSession(metadata);
1785
- __DEV__ && _internalLogger.logger.info('session.start() ✅ sessionId:', sm.currentSessionId);
1751
+ _internalLogger.logger.info('session.start() ✅ sessionId:', sm.currentSessionId);
1786
1752
  return true;
1787
1753
  },
1788
1754
  end: reason => {
1789
1755
  const sm = _SessionManager.SessionManager.getExistingInstance();
1790
1756
  if (!sm || !sm.isActive) return false;
1791
1757
  sm.endSession(reason);
1792
- __DEV__ && _internalLogger.logger.info('session.end() ✅');
1758
+ _internalLogger.logger.info('session.end() ✅');
1793
1759
  return true;
1794
1760
  },
1795
1761
  emitEvent: (type, data) => {
@@ -1847,7 +1813,7 @@ class ScaleBunFacade {
1847
1813
  ...this._privacyConfig,
1848
1814
  ...config
1849
1815
  };
1850
- __DEV__ && _internalLogger.logger.debug('[report] Privacy config updated');
1816
+ _internalLogger.logger.debug('[report] Privacy config updated');
1851
1817
  },
1852
1818
  /** Set branding for exported reports. */
1853
1819
  setBranding: config => {
@@ -1855,7 +1821,7 @@ class ScaleBunFacade {
1855
1821
  ...this._brandingConfig,
1856
1822
  ...config
1857
1823
  };
1858
- __DEV__ && _internalLogger.logger.debug('[report] Branding config updated');
1824
+ _internalLogger.logger.debug('[report] Branding config updated');
1859
1825
  },
1860
1826
  /** Get current privacy config. */
1861
1827
  getPrivacy: () => ({
@@ -1910,9 +1876,9 @@ class ScaleBunFacade {
1910
1876
  AutoScreenDetector
1911
1877
  } = require('../features/navigation/AutoScreenDetector');
1912
1878
  AutoScreenDetector.getInstance().setNavigationRef(ref);
1913
- __DEV__ && _internalLogger.logger.info('[ScaleBun] Navigation ref set → auto screen detection active');
1879
+ _internalLogger.logger.info('[ScaleBun] Navigation ref set → auto screen detection active');
1914
1880
  } catch (err) {
1915
- __DEV__ && _internalLogger.logger.debug('[ScaleBun] Navigation ref stashed (detector not ready):', err?.message);
1881
+ _internalLogger.logger.debug('[ScaleBun] Navigation ref stashed (detector not ready):', err?.message);
1916
1882
  }
1917
1883
  });
1918
1884
  }
@@ -75,6 +75,15 @@ export class SDKBootstrapper {
75
75
  // apiBaseUrl is LOCKED: whatever an integrator passed (or the schema default) is
76
76
  // discarded here so the SDK can never be repointed away from the ScaleBun cloud.
77
77
  // Change DEFAULT_API_BASE_URL at build time to target a different backend.
78
+ // Say so when we discard it. The value was accepted by the schema, silently
79
+ // overwritten here, and the SDK then talked to a different server than the
80
+ // integrator configured — with no log, no warning, and no error. Someone
81
+ // pointing the SDK at a staging or local backend would watch requests arrive
82
+ // at production and have nothing to go on.
83
+ const requestedApiBaseUrl = rawConfig?.apiBaseUrl;
84
+ if (typeof requestedApiBaseUrl === 'string' && requestedApiBaseUrl && requestedApiBaseUrl !== DEFAULT_API_BASE_URL) {
85
+ logger.warn(`[ScaleBun] Ignoring apiBaseUrl '${requestedApiBaseUrl}' — the endpoint is ` + `locked at build time and this build targets ${DEFAULT_API_BASE_URL}. To ` + `target another backend, change DEFAULT_API_BASE_URL in the SDK source and ` + `rebuild.`);
86
+ }
78
87
  this.config.apiBaseUrl = DEFAULT_API_BASE_URL;
79
88
  // Explicit logLevel wins; otherwise debug:true implies verbose 'debug'.
80
89
  if (this.config.logLevel) {
@@ -314,6 +323,27 @@ export class SDKBootstrapper {
314
323
  await this.featureRegistry.initializeAll(featureContext);
315
324
 
316
325
  // ── Session Replay Initialization (Core) ───────────────
326
+ /**
327
+ * RN-3 zero-config scroll instrumentation, opt-in.
328
+ *
329
+ * Placed before replay init because it patches a module export and must be in place before the
330
+ * host renders its first scroll view. Reports rather than assumes: the equivalent React
331
+ * Navigation hook once claimed success it had not verified and left a whole pipeline silently
332
+ * empty, so a failure here is said out loud with a reason an integrator can act on.
333
+ */
334
+ if (this.config.autoInstrumentScrollViews === true) {
335
+ try {
336
+ const {
337
+ autoInstrumentScrollViews
338
+ } = require('../features/journey/autoInstrumentScroll');
339
+ const outcome = autoInstrumentScrollViews();
340
+ if (!outcome.installed) {
341
+ logger.warn('[Bootstrap] autoInstrumentScrollViews was requested but could not be ' + 'installed: ' + outcome.reason + ' — taps will carry no content depth.');
342
+ } else {
343
+ __DEV__ && logger.debug('[Bootstrap] ScrollView auto-instrumentation installed');
344
+ }
345
+ } catch {/* no-throw */}
346
+ }
317
347
  if (features.replay !== false) {
318
348
  try {
319
349
  __DEV__ && logger.debug('[Bootstrap] Initializing unified SessionManager');
@@ -269,6 +269,22 @@ const SHAPE = {
269
269
  }
270
270
  },
271
271
  captureInteractionHeatmap: bool(true),
272
+ /**
273
+ * RN-3 zero-config: patch React Native's ScrollView export so EVERY scroll view reports its
274
+ * offset, not just ones wrapped in ScaleBunScrollView.
275
+ *
276
+ * DEFAULT FALSE, unlike captureInteractionHeatmap above, and the difference is deliberate.
277
+ * That flag changes what the SDK records about the host; this one changes what the HOST
278
+ * RENDERS — every scroll view in the app, including ones inside third-party libraries the app
279
+ * did not write, starts routing through an SDK component. The failure mode is not a wrong
280
+ * number in a dashboard, it is the host's UI behaving differently because an analytics SDK
281
+ * replaced a primitive. That is a decision an integrator makes deliberately, not one they
282
+ * discover afterwards.
283
+ *
284
+ * With it off, a plain <ScrollView> yields no content depth and the tap says so
285
+ * (scroll_source: 'none') rather than defaulting its offset to 0.
286
+ */
287
+ autoInstrumentScrollViews: bool(false),
272
288
  // Opt-in: intercept console.* and ship the lines to the Diagnose → Logs lane in SaaS
273
289
  // mode. OFF by default — console output can carry PII/secrets and adds ingest volume,
274
290
  // so capturing it is the host's explicit choice, not a silent default. When true and a
@@ -285,18 +301,9 @@ const SHAPE = {
285
301
  kind: 'str',
286
302
  opt: true
287
303
  },
288
- publicSigningKey: {
289
- kind: 'str',
290
- opt: true
291
- },
292
- // Rotation support: several pinned keys, any of which may verify a
293
- // bundle. Ship a build pinning [old, new], re-sign server-side with
294
- // new, drop old next release — no emergency store submission when a
295
- // key must be replaced. Merged with publicSigningKey by the facade.
296
- publicSigningKeys: {
297
- kind: 'strArr',
298
- opt: true
299
- },
304
+ // No signing-key fields: signed releases are verified natively against
305
+ // RSA keys embedded in the app package (SB-OTA-RSA-SHA256-V1). JS must
306
+ // not supply a trusted key.
300
307
  mandatoryBlocksUi: bool(false)
301
308
  }
302
309
  }
@@ -8,5 +8,5 @@
8
8
  * value, so a stale one makes a rollout unobservable — which is the exact problem sending an SDK
9
9
  * version was introduced to solve.
10
10
  */
11
- export const SDK_VERSION = '1.13.0';
11
+ export const SDK_VERSION = '2.0.1';
12
12
  //# sourceMappingURL=version.js.map