@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.
- package/android/build.gradle +8 -0
- package/android/src/androidTest/java/com/scalebun/rn/ota/ScaleBunOtaVerifierInstrumentedTest.kt +112 -0
- package/android/src/main/java/com/scalebun/rn/ota/BundleDownloader.kt +10 -0
- package/android/src/main/java/com/scalebun/rn/ota/DeviceIntegrity.kt +75 -0
- package/android/src/main/java/com/scalebun/rn/ota/OtaProtocol.kt +244 -0
- package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaKeyRegistry.kt +100 -0
- package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaModule.kt +132 -62
- package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaReleaseVerifier.kt +129 -0
- package/android/src/main/java/com/scalebun/rn/ota/SlotManager.kt +80 -1
- package/android/src/main/java/com/scalebun/rn/ota/TlsPinning.kt +118 -0
- package/android/src/oldarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +6 -8
- package/dist/scalebun.full.js +964 -533
- package/dist/scalebun.slim.js +962 -531
- package/ios/Ota/OtaProtocol.swift +242 -0
- package/ios/Ota/OtaSlotManager.swift +26 -0
- package/ios/Ota/ScaleBunOtaBridge.mm +6 -3
- package/ios/Ota/ScaleBunOtaKeyRegistry.swift +147 -0
- package/ios/Ota/ScaleBunOtaModule.swift +125 -53
- package/ios/Ota/ScaleBunOtaReleaseVerifier.swift +115 -0
- package/ios/Ota/ScaleBunOtaVerifierTests.swift +92 -0
- package/ios/ReplaySdk.swift +65 -2
- package/lib/commonjs/bootstrap/SDKBootstrapper.js +30 -0
- package/lib/commonjs/core/config/schema.js +19 -12
- package/lib/commonjs/core/constants/version.js +1 -1
- package/lib/commonjs/features/journey/ScaleBunDebugRoot.js +293 -5
- package/lib/commonjs/features/journey/ScaleBunScrollView.js +28 -0
- package/lib/commonjs/features/journey/autoInstrumentScroll.js +161 -0
- package/lib/commonjs/features/journey/interactionProtocol.js +131 -10
- package/lib/commonjs/features/journey/scrollContext.js +146 -0
- package/lib/commonjs/features/journey/targetGeometry.js +164 -0
- package/lib/commonjs/features/journey/touchTarget.js +152 -24
- package/lib/commonjs/features/journey/uiState.js +81 -1
- package/lib/commonjs/features/navigation/AutoScreenDetector.js +74 -5
- package/lib/commonjs/features/network/NetworkFeature.js +39 -5
- package/lib/commonjs/features/network/thirdParty.js +90 -0
- package/lib/commonjs/features/ota/OtaOrchestrator.js +175 -80
- package/lib/commonjs/features/session/SessionManager.js +63 -0
- package/lib/commonjs/public/ScaleBunFacade.js +23 -57
- package/lib/module/bootstrap/SDKBootstrapper.js +30 -0
- package/lib/module/core/config/schema.js +19 -12
- package/lib/module/core/constants/version.js +1 -1
- package/lib/module/features/journey/ScaleBunDebugRoot.js +295 -7
- package/lib/module/features/journey/ScaleBunScrollView.js +28 -0
- package/lib/module/features/journey/autoInstrumentScroll.js +155 -0
- package/lib/module/features/journey/interactionProtocol.js +128 -8
- package/lib/module/features/journey/scrollContext.js +135 -0
- package/lib/module/features/journey/targetGeometry.js +155 -0
- package/lib/module/features/journey/touchTarget.js +151 -24
- package/lib/module/features/journey/uiState.js +78 -1
- package/lib/module/features/navigation/AutoScreenDetector.js +74 -5
- package/lib/module/features/network/NetworkFeature.js +38 -4
- package/lib/module/features/network/thirdParty.js +83 -0
- package/lib/module/features/ota/OtaOrchestrator.js +175 -80
- package/lib/module/features/session/SessionManager.js +63 -0
- package/lib/module/public/ScaleBunFacade.js +23 -57
- package/lib/typescript/core/config/schema.d.ts +2 -3
- package/lib/typescript/core/constants/version.d.ts +1 -1
- package/lib/typescript/features/journey/autoInstrumentScroll.d.ts +46 -0
- package/lib/typescript/features/journey/interactionProtocol.d.ts +139 -1
- package/lib/typescript/features/journey/scrollContext.d.ts +85 -0
- package/lib/typescript/features/journey/targetGeometry.d.ts +114 -0
- package/lib/typescript/features/journey/touchTarget.d.ts +148 -15
- package/lib/typescript/features/journey/uiState.d.ts +39 -0
- package/lib/typescript/features/navigation/AutoScreenDetector.d.ts +48 -2
- package/lib/typescript/features/network/index.d.ts +18 -0
- package/lib/typescript/features/network/thirdParty.d.ts +65 -0
- package/lib/typescript/features/ota/OtaOrchestrator.d.ts +12 -8
- package/lib/typescript/features/ota/OtaTypes.d.ts +22 -0
- package/lib/typescript/features/session/SessionManager.d.ts +55 -0
- package/lib/typescript/public/ScaleBunFacade.d.ts +5 -11
- package/lib/typescript/public/types.d.ts +10 -0
- package/lib/typescript/specs/NativeScaleBunOta.d.ts +32 -20
- package/package.json +3 -13
- package/scalebun-react-native.podspec +4 -0
- package/src/bootstrap/SDKBootstrapper.ts +40 -0
- package/src/core/config/schema.ts +21 -9
- package/src/core/constants/version.ts +1 -1
- package/src/features/journey/ScaleBunDebugRoot.tsx +288 -7
- package/src/features/journey/ScaleBunScrollView.tsx +29 -0
- package/src/features/journey/autoInstrumentScroll.ts +155 -0
- package/src/features/journey/interactionProtocol.ts +188 -10
- package/src/features/journey/scrollContext.ts +137 -0
- package/src/features/journey/targetGeometry.ts +176 -0
- package/src/features/journey/touchTarget.ts +237 -26
- package/src/features/journey/uiState.ts +80 -1
- package/src/features/navigation/AutoScreenDetector.ts +65 -5
- package/src/features/network/NetworkFeature.ts +41 -4
- package/src/features/network/index.ts +18 -0
- package/src/features/network/thirdParty.ts +92 -0
- package/src/features/ota/OtaOrchestrator.ts +190 -90
- package/src/features/ota/OtaTypes.ts +23 -1
- package/src/features/session/SessionManager.ts +113 -0
- package/src/public/ScaleBunFacade.ts +23 -69
- package/src/public/types.ts +10 -0
- package/src/specs/NativeScaleBunOta.ts +35 -20
- package/lib/commonjs/features/ota/crypto/builtinVerifier.js +0 -248
- package/lib/commonjs/features/ota/crypto/loadEd25519.js +0 -40
- package/lib/commonjs/features/ota/crypto/loadSha512.js +0 -40
- package/lib/commonjs/features/ota/crypto/nativeVerifier.js +0 -121
- package/lib/commonjs/features/ota/signature.js +0 -175
- package/lib/module/features/ota/crypto/builtinVerifier.js +0 -240
- package/lib/module/features/ota/crypto/loadEd25519.js +0 -34
- package/lib/module/features/ota/crypto/loadSha512.js +0 -34
- package/lib/module/features/ota/crypto/nativeVerifier.js +0 -113
- package/lib/module/features/ota/signature.js +0 -169
- package/lib/typescript/features/ota/crypto/builtinVerifier.d.ts +0 -53
- package/lib/typescript/features/ota/crypto/loadEd25519.d.ts +0 -30
- package/lib/typescript/features/ota/crypto/loadSha512.d.ts +0 -15
- package/lib/typescript/features/ota/crypto/nativeVerifier.d.ts +0 -35
- package/lib/typescript/features/ota/signature.d.ts +0 -81
- package/src/features/ota/crypto/builtinVerifier.ts +0 -257
- package/src/features/ota/crypto/loadEd25519.ts +0 -41
- package/src/features/ota/crypto/loadSha512.ts +0 -35
- package/src/features/ota/crypto/nativeVerifier.ts +0 -117
- 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
|
-
|
|
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
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1597
|
+
_internalLogger.logger.debug('Performance feature linked from bootstrap');
|
|
1632
1598
|
}
|
|
1633
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1879
|
+
_internalLogger.logger.info('[ScaleBun] Navigation ref set → auto screen detection active');
|
|
1914
1880
|
} catch (err) {
|
|
1915
|
-
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
}
|