@scalebun/react-native 1.10.7 → 1.11.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/src/main/java/com/scalebun/replaysdk/tracking/InteractionTracker.kt +25 -25
- package/android/src/main/java/com/scalebun/rn/ota/SlotManager.kt +15 -3
- package/dist/scalebun.full.js +467 -255
- package/dist/scalebun.slim.js +466 -254
- package/ios/Capture/InteractionTracker.swift +8 -4
- package/ios/Ota/OtaSlotManager.swift +19 -5
- package/lib/commonjs/analytics/EventTracker.js +5 -5
- package/lib/commonjs/analytics/automaticEvents.js +3 -2
- package/lib/commonjs/core/constants/version.js +7 -2
- package/lib/commonjs/features/journey/ScaleBunDebugRoot.js +80 -103
- package/lib/commonjs/features/journey/interactionProtocol.js +47 -0
- package/lib/commonjs/features/journey/uiState.js +8 -1
- package/lib/commonjs/features/ota/OtaOrchestrator.js +174 -48
- package/lib/commonjs/features/ota/OtaTypes.js +4 -0
- package/lib/commonjs/features/ota/useOtaUpdate.js +11 -2
- package/lib/commonjs/features/session/JourneyEventPipeline.js +6 -5
- package/lib/commonjs/features/session/SessionManager.js +37 -38
- package/lib/commonjs/public/ScaleBunFacade.js +115 -2
- package/lib/module/analytics/EventTracker.js +5 -5
- package/lib/module/analytics/automaticEvents.js +3 -2
- package/lib/module/core/constants/version.js +7 -2
- package/lib/module/features/journey/ScaleBunDebugRoot.js +80 -103
- package/lib/module/features/journey/interactionProtocol.js +38 -0
- package/lib/module/features/journey/uiState.js +8 -1
- package/lib/module/features/ota/OtaOrchestrator.js +174 -48
- package/lib/module/features/ota/OtaTypes.js +1 -1
- package/lib/module/features/ota/useOtaUpdate.js +11 -2
- package/lib/module/features/session/JourneyEventPipeline.js +6 -5
- package/lib/module/features/session/SessionManager.js +37 -38
- package/lib/module/public/ScaleBunFacade.js +115 -2
- package/lib/typescript/analytics/EventTracker.d.ts +1 -1
- package/lib/typescript/analytics/automaticEvents.d.ts +3 -1
- package/lib/typescript/core/constants/version.d.ts +7 -2
- package/lib/typescript/features/journey/interactionProtocol.d.ts +21 -0
- package/lib/typescript/features/ota/OtaEventEmitter.d.ts +15 -1
- package/lib/typescript/features/ota/OtaOrchestrator.d.ts +22 -3
- package/lib/typescript/features/ota/OtaTypes.d.ts +29 -32
- package/lib/typescript/features/session/JourneyEventPipeline.d.ts +1 -0
- package/lib/typescript/features/session/SessionManager.d.ts +15 -10
- package/lib/typescript/public/ScaleBunFacade.d.ts +27 -0
- package/package.json +4 -3
- package/src/analytics/EventTracker.ts +5 -5
- package/src/analytics/automaticEvents.ts +4 -0
- package/src/core/constants/version.ts +7 -2
- package/src/features/journey/ScaleBunDebugRoot.tsx +96 -97
- package/src/features/journey/interactionProtocol.ts +65 -0
- package/src/features/journey/uiState.ts +9 -4
- package/src/features/ota/OtaEventEmitter.ts +12 -0
- package/src/features/ota/OtaOrchestrator.ts +209 -62
- package/src/features/ota/OtaTypes.ts +37 -39
- package/src/features/ota/useOtaUpdate.ts +11 -2
- package/src/features/session/JourneyEventPipeline.ts +7 -5
- package/src/features/session/SessionManager.ts +75 -38
- package/src/public/ScaleBunFacade.ts +127 -3
package/dist/scalebun.slim.js
CHANGED
|
@@ -600,7 +600,7 @@ var SDK_VERSION;
|
|
|
600
600
|
var init_version = __esm({
|
|
601
601
|
"lib/module/core/constants/version.js"() {
|
|
602
602
|
"use strict";
|
|
603
|
-
SDK_VERSION = "1.
|
|
603
|
+
SDK_VERSION = "1.11.1";
|
|
604
604
|
}
|
|
605
605
|
});
|
|
606
606
|
|
|
@@ -2459,22 +2459,23 @@ var init_JourneyEventPipeline = __esm({
|
|
|
2459
2459
|
emit(type, opts) {
|
|
2460
2460
|
try {
|
|
2461
2461
|
const key = `${type}:${opts?.subtype ?? ""}`;
|
|
2462
|
-
const
|
|
2463
|
-
|
|
2462
|
+
const receivedAt = Date.now();
|
|
2463
|
+
const occurredAt = opts?.timestamp ?? receivedAt;
|
|
2464
|
+
if (key === this.lastEventKey && receivedAt - this.lastEventTs < this.config.dedupeWindowMs) {
|
|
2464
2465
|
const incomingConfidence = opts?.payload?.confidence;
|
|
2465
2466
|
if (incomingConfidence === "high" && this.lastEventConfidence !== "high") {
|
|
2466
|
-
this._replaceLastEvent(key,
|
|
2467
|
+
this._replaceLastEvent(key, receivedAt, opts);
|
|
2467
2468
|
}
|
|
2468
2469
|
return null;
|
|
2469
2470
|
}
|
|
2470
2471
|
this.lastEventKey = key;
|
|
2471
|
-
this.lastEventTs =
|
|
2472
|
+
this.lastEventTs = receivedAt;
|
|
2472
2473
|
this.lastEventConfidence = opts?.payload?.confidence ?? null;
|
|
2473
2474
|
const event = {
|
|
2474
2475
|
eventId: generateEventId2(),
|
|
2475
2476
|
sessionId: this.sessionId,
|
|
2476
2477
|
journeyId: opts?.journeyId,
|
|
2477
|
-
ts:
|
|
2478
|
+
ts: occurredAt,
|
|
2478
2479
|
type,
|
|
2479
2480
|
subtype: opts?.subtype,
|
|
2480
2481
|
severity: opts?.severity ?? inferSeverity(type),
|
|
@@ -3574,6 +3575,99 @@ var init_calibrationContext = __esm({
|
|
|
3574
3575
|
}
|
|
3575
3576
|
});
|
|
3576
3577
|
|
|
3578
|
+
// lib/module/analytics/automaticEvents.js
|
|
3579
|
+
function compactProperties(properties) {
|
|
3580
|
+
const out = {
|
|
3581
|
+
capture_source: "automatic"
|
|
3582
|
+
};
|
|
3583
|
+
for (const [key, value] of Object.entries(properties ?? {})) {
|
|
3584
|
+
if (value !== void 0) out[key] = value;
|
|
3585
|
+
}
|
|
3586
|
+
return out;
|
|
3587
|
+
}
|
|
3588
|
+
function emitAutomaticEvent(name, properties, timestamp) {
|
|
3589
|
+
const event = {
|
|
3590
|
+
name,
|
|
3591
|
+
properties: compactProperties(properties),
|
|
3592
|
+
timestamp
|
|
3593
|
+
};
|
|
3594
|
+
if (listeners.size === 0) {
|
|
3595
|
+
pending2.push(event);
|
|
3596
|
+
if (pending2.length > MAX_PENDING) pending2.shift();
|
|
3597
|
+
return;
|
|
3598
|
+
}
|
|
3599
|
+
for (const listener of listeners) {
|
|
3600
|
+
try {
|
|
3601
|
+
listener(event);
|
|
3602
|
+
} catch {
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
function subscribeAutomaticEvents(listener) {
|
|
3607
|
+
listeners.add(listener);
|
|
3608
|
+
if (pending2.length > 0) {
|
|
3609
|
+
const buffered = pending2.splice(0, pending2.length);
|
|
3610
|
+
for (const event of buffered) {
|
|
3611
|
+
try {
|
|
3612
|
+
listener(event);
|
|
3613
|
+
} catch {
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
return () => {
|
|
3618
|
+
listeners.delete(listener);
|
|
3619
|
+
};
|
|
3620
|
+
}
|
|
3621
|
+
var listeners, pending2, MAX_PENDING;
|
|
3622
|
+
var init_automaticEvents = __esm({
|
|
3623
|
+
"lib/module/analytics/automaticEvents.js"() {
|
|
3624
|
+
"use strict";
|
|
3625
|
+
listeners = /* @__PURE__ */ new Set();
|
|
3626
|
+
pending2 = [];
|
|
3627
|
+
MAX_PENDING = 50;
|
|
3628
|
+
}
|
|
3629
|
+
});
|
|
3630
|
+
|
|
3631
|
+
// lib/module/features/journey/interactionProtocol.js
|
|
3632
|
+
function generateInteractionId() {
|
|
3633
|
+
return `ixj-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
3634
|
+
}
|
|
3635
|
+
function nearestInteractionStart(starts, occurredAt, toleranceMs = 1500) {
|
|
3636
|
+
let best;
|
|
3637
|
+
let bestDelta = toleranceMs + 1;
|
|
3638
|
+
for (const start of starts) {
|
|
3639
|
+
const delta = Math.abs(start.occurredAt - occurredAt);
|
|
3640
|
+
if (delta < bestDelta) {
|
|
3641
|
+
best = start;
|
|
3642
|
+
bestDelta = delta;
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
return bestDelta <= toleranceMs ? best : void 0;
|
|
3646
|
+
}
|
|
3647
|
+
function automaticInteractionProperties(payload, screenName, canonicalMirror) {
|
|
3648
|
+
return {
|
|
3649
|
+
gesture_type: payload.gestureType,
|
|
3650
|
+
screen_name: screenName,
|
|
3651
|
+
interaction_id: payload.interaction_id,
|
|
3652
|
+
interaction_protocol: payload.interaction_protocol,
|
|
3653
|
+
state_status: payload.state_status,
|
|
3654
|
+
ui: payload.ui,
|
|
3655
|
+
target_id: payload.target_id,
|
|
3656
|
+
normalized_x: payload.normalizedX,
|
|
3657
|
+
normalized_y: payload.normalizedY,
|
|
3658
|
+
direction: payload.direction,
|
|
3659
|
+
duration_ms: payload.durationMs,
|
|
3660
|
+
canonical_mirror: canonicalMirror || void 0
|
|
3661
|
+
};
|
|
3662
|
+
}
|
|
3663
|
+
var INTERACTION_PROTOCOL_VERSION;
|
|
3664
|
+
var init_interactionProtocol = __esm({
|
|
3665
|
+
"lib/module/features/journey/interactionProtocol.js"() {
|
|
3666
|
+
"use strict";
|
|
3667
|
+
INTERACTION_PROTOCOL_VERSION = 1;
|
|
3668
|
+
}
|
|
3669
|
+
});
|
|
3670
|
+
|
|
3577
3671
|
// lib/module/features/session/SessionManager.js
|
|
3578
3672
|
var SessionManager_exports = {};
|
|
3579
3673
|
__export(SessionManager_exports, {
|
|
@@ -3582,7 +3676,7 @@ __export(SessionManager_exports, {
|
|
|
3582
3676
|
function generateSessionId2() {
|
|
3583
3677
|
return `ses-${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 8)}`;
|
|
3584
3678
|
}
|
|
3585
|
-
var
|
|
3679
|
+
var _instance2, SessionManager;
|
|
3586
3680
|
var init_SessionManager = __esm({
|
|
3587
3681
|
"lib/module/features/session/SessionManager.js"() {
|
|
3588
3682
|
"use strict";
|
|
@@ -3599,7 +3693,8 @@ var init_SessionManager = __esm({
|
|
|
3599
3693
|
init_redaction();
|
|
3600
3694
|
init_calibrationContext();
|
|
3601
3695
|
init_device();
|
|
3602
|
-
|
|
3696
|
+
init_automaticEvents();
|
|
3697
|
+
init_interactionProtocol();
|
|
3603
3698
|
_instance2 = null;
|
|
3604
3699
|
SessionManager = class _SessionManager {
|
|
3605
3700
|
desktopTransport = null;
|
|
@@ -3610,15 +3705,6 @@ var init_SessionManager = __esm({
|
|
|
3610
3705
|
* lane even when no replay recording is active. Additive, opt-in (default off).
|
|
3611
3706
|
*/
|
|
3612
3707
|
_captureInteractionHeatmap = false;
|
|
3613
|
-
/**
|
|
3614
|
-
* Sampling cap for the analytics-lane heatmap emission. Now that capture is
|
|
3615
|
-
* ON by default, an unbounded one-event-per-gesture stream could materially
|
|
3616
|
-
* inflate ingest volume. We cap emitted interactions per analytics-session
|
|
3617
|
-
* window (finalize-scoped per foreground): the first N gestures define the
|
|
3618
|
-
* hotspot shape; the long tail is dropped. Resets when the window changes.
|
|
3619
|
-
*/
|
|
3620
|
-
_heatmapWindowSessionId = null;
|
|
3621
|
-
_heatmapWindowCount = 0;
|
|
3622
3708
|
session = null;
|
|
3623
3709
|
active = false;
|
|
3624
3710
|
timeoutTimer = null;
|
|
@@ -4099,18 +4185,11 @@ var init_SessionManager = __esm({
|
|
|
4099
4185
|
* injected sensitive keys (e.g. a label) are stripped before transport.
|
|
4100
4186
|
* - Never throws.
|
|
4101
4187
|
*/
|
|
4102
|
-
_emitInteractionToAnalytics(gestureType, payload) {
|
|
4103
|
-
if (!this._captureInteractionHeatmap) return;
|
|
4104
|
-
if (this.active) return;
|
|
4188
|
+
_emitInteractionToAnalytics(gestureType, payload, occurredAt, screenName) {
|
|
4189
|
+
if (!this._captureInteractionHeatmap) return false;
|
|
4190
|
+
if (this.active) return false;
|
|
4105
4191
|
const adapter = this._backendTransport;
|
|
4106
|
-
if (!adapter) return;
|
|
4107
|
-
const windowId = adapter.analyticsSessionId ?? "";
|
|
4108
|
-
if (windowId !== this._heatmapWindowSessionId) {
|
|
4109
|
-
this._heatmapWindowSessionId = windowId;
|
|
4110
|
-
this._heatmapWindowCount = 0;
|
|
4111
|
-
}
|
|
4112
|
-
if (this._heatmapWindowCount >= HEATMAP_MAX_INTERACTIONS_PER_WINDOW) return;
|
|
4113
|
-
this._heatmapWindowCount++;
|
|
4192
|
+
if (!adapter) return false;
|
|
4114
4193
|
try {
|
|
4115
4194
|
this._normalizeInteractionPayload(payload);
|
|
4116
4195
|
const safePayload = redactBody(payload);
|
|
@@ -4118,16 +4197,18 @@ var init_SessionManager = __esm({
|
|
|
4118
4197
|
eventId: generateEventId(),
|
|
4119
4198
|
// sessionId is (re)stamped by the analytics lane at flush time.
|
|
4120
4199
|
sessionId: adapter.analyticsSessionId ?? "",
|
|
4121
|
-
ts:
|
|
4200
|
+
ts: occurredAt,
|
|
4122
4201
|
type: "USER_ACTION",
|
|
4123
4202
|
subtype: `gesture:${gestureType}`,
|
|
4124
|
-
screen: this._lastKnownScreen ?? void 0,
|
|
4203
|
+
screen: screenName ?? this._lastKnownScreen ?? void 0,
|
|
4125
4204
|
payload: safePayload,
|
|
4126
4205
|
source: "user"
|
|
4127
4206
|
};
|
|
4128
4207
|
adapter.trackEvent(event);
|
|
4208
|
+
return true;
|
|
4129
4209
|
} catch (err) {
|
|
4130
4210
|
logger.error("[SessionManager] heatmap analytics emit failed:", err);
|
|
4211
|
+
return false;
|
|
4131
4212
|
}
|
|
4132
4213
|
}
|
|
4133
4214
|
/**
|
|
@@ -4293,13 +4374,14 @@ var init_SessionManager = __esm({
|
|
|
4293
4374
|
* Notify of a user interaction. Called by ScaleBunDebugRoot touch handlers.
|
|
4294
4375
|
* Also triggers frame capture for desktop-initiated recordings.
|
|
4295
4376
|
*/
|
|
4296
|
-
onUserAction(subtype, payload) {
|
|
4377
|
+
onUserAction(subtype, payload, context) {
|
|
4297
4378
|
if (!this.active) return;
|
|
4298
4379
|
this.emitEvent("USER_ACTION", {
|
|
4299
4380
|
subtype,
|
|
4300
|
-
screen: this._lastKnownScreen ?? void 0,
|
|
4381
|
+
screen: context?.screen ?? this._lastKnownScreen ?? void 0,
|
|
4301
4382
|
payload,
|
|
4302
|
-
source: "user"
|
|
4383
|
+
source: "user",
|
|
4384
|
+
timestamp: context?.timestamp
|
|
4303
4385
|
});
|
|
4304
4386
|
}
|
|
4305
4387
|
/**
|
|
@@ -4307,7 +4389,8 @@ var init_SessionManager = __esm({
|
|
|
4307
4389
|
* Emits a USER_ACTION event with gesture-specific subtype and payload.
|
|
4308
4390
|
*/
|
|
4309
4391
|
onGestureDetected(gestureType, details) {
|
|
4310
|
-
const
|
|
4392
|
+
const suppliedInteractionId = details?.interactionId;
|
|
4393
|
+
const dedupSig = suppliedInteractionId ? `id:${suppliedInteractionId}` : `${gestureType}|${String(details?.x)}|${String(details?.y)}|${String(details?.endX)}|${String(details?.endY)}`;
|
|
4311
4394
|
const nowTs = Date.now();
|
|
4312
4395
|
if (dedupSig === this._lastGestureSig && nowTs - this._lastGestureTs <= _SessionManager.GESTURE_DEDUP_WINDOW_MS) {
|
|
4313
4396
|
this._lastGestureTs = nowTs;
|
|
@@ -4315,7 +4398,15 @@ var init_SessionManager = __esm({
|
|
|
4315
4398
|
}
|
|
4316
4399
|
this._lastGestureSig = dedupSig;
|
|
4317
4400
|
this._lastGestureTs = nowTs;
|
|
4401
|
+
const interactionId = suppliedInteractionId ?? generateInteractionId();
|
|
4402
|
+
const occurredAt = details?.occurredAt ?? Date.now();
|
|
4403
|
+
const stateStatus = details?.stateStatus ?? (details?.ui ? "captured_nonempty" : "not_captured");
|
|
4318
4404
|
const payload = {
|
|
4405
|
+
interaction_id: interactionId,
|
|
4406
|
+
interaction_protocol: details?.interactionProtocol ?? INTERACTION_PROTOCOL_VERSION,
|
|
4407
|
+
state_status: stateStatus,
|
|
4408
|
+
ui: details?.ui,
|
|
4409
|
+
target_id: details?.targetId,
|
|
4319
4410
|
gestureType,
|
|
4320
4411
|
x: details?.x,
|
|
4321
4412
|
y: details?.y,
|
|
@@ -4353,12 +4444,23 @@ var init_SessionManager = __esm({
|
|
|
4353
4444
|
screenHeight: details?.screenHeight,
|
|
4354
4445
|
platform: details?.platform
|
|
4355
4446
|
};
|
|
4356
|
-
this._emitInteractionToAnalytics(gestureType, {
|
|
4447
|
+
const analyticsReplayCarrier = this._emitInteractionToAnalytics(gestureType, {
|
|
4357
4448
|
...payload
|
|
4358
|
-
});
|
|
4449
|
+
}, occurredAt, details?.screenName);
|
|
4450
|
+
const replayCarrier = !!this._backendTransport && (this.active || analyticsReplayCarrier);
|
|
4451
|
+
if (details?.emitAutomaticAnalytics) {
|
|
4452
|
+
try {
|
|
4453
|
+
const safePayload = redactBody(payload);
|
|
4454
|
+
emitAutomaticEvent("element_interacted", automaticInteractionProperties(safePayload, details?.screenName ?? this._lastKnownScreen ?? void 0, replayCarrier), occurredAt);
|
|
4455
|
+
} catch {
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4359
4458
|
if (!this.active) return;
|
|
4360
4459
|
const target = typeof details?.target === "string" ? details.target.trim() : "";
|
|
4361
|
-
this.onUserAction(target ? `gesture:${gestureType} \xB7 ${target}` : `gesture:${gestureType}`, payload
|
|
4460
|
+
this.onUserAction(target ? `gesture:${gestureType} \xB7 ${target}` : `gesture:${gestureType}`, payload, {
|
|
4461
|
+
screen: details?.screenName,
|
|
4462
|
+
timestamp: occurredAt
|
|
4463
|
+
});
|
|
4362
4464
|
}
|
|
4363
4465
|
/**
|
|
4364
4466
|
* Manual frame capture — triggered by Desktop "Capture Step" button.
|
|
@@ -5772,6 +5874,42 @@ var init_bootstrap = __esm({
|
|
|
5772
5874
|
}
|
|
5773
5875
|
});
|
|
5774
5876
|
|
|
5877
|
+
// lib/module/core/lifecycle/appLifecycle.js
|
|
5878
|
+
var appLifecycle_exports = {};
|
|
5879
|
+
__export(appLifecycle_exports, {
|
|
5880
|
+
appLifecycle: () => appLifecycle
|
|
5881
|
+
});
|
|
5882
|
+
var import_react_native6, AppLifecycle, appLifecycle;
|
|
5883
|
+
var init_appLifecycle = __esm({
|
|
5884
|
+
"lib/module/core/lifecycle/appLifecycle.js"() {
|
|
5885
|
+
"use strict";
|
|
5886
|
+
import_react_native6 = require("react-native");
|
|
5887
|
+
init_internalLogger();
|
|
5888
|
+
AppLifecycle = class {
|
|
5889
|
+
listeners = [];
|
|
5890
|
+
currentState = import_react_native6.AppState.currentState;
|
|
5891
|
+
constructor() {
|
|
5892
|
+
import_react_native6.AppState.addEventListener("change", this.handleStateChange);
|
|
5893
|
+
}
|
|
5894
|
+
handleStateChange = (nextState) => {
|
|
5895
|
+
__DEV__ && logger.debug(`App state changed: ${this.currentState} -> ${nextState}`);
|
|
5896
|
+
this.currentState = nextState;
|
|
5897
|
+
this.listeners.forEach((l) => l(nextState));
|
|
5898
|
+
};
|
|
5899
|
+
addListener(listener) {
|
|
5900
|
+
this.listeners.push(listener);
|
|
5901
|
+
}
|
|
5902
|
+
removeListener(listener) {
|
|
5903
|
+
this.listeners = this.listeners.filter((l) => l !== listener);
|
|
5904
|
+
}
|
|
5905
|
+
getCurrentState() {
|
|
5906
|
+
return this.currentState;
|
|
5907
|
+
}
|
|
5908
|
+
};
|
|
5909
|
+
appLifecycle = new AppLifecycle();
|
|
5910
|
+
}
|
|
5911
|
+
});
|
|
5912
|
+
|
|
5775
5913
|
// lib/module/features/crash/CrashReporter.js
|
|
5776
5914
|
function getCrashReporter() {
|
|
5777
5915
|
if (!_reporter) _reporter = new CrashReporter();
|
|
@@ -6229,58 +6367,6 @@ var init_batching = __esm({
|
|
|
6229
6367
|
}
|
|
6230
6368
|
});
|
|
6231
6369
|
|
|
6232
|
-
// lib/module/analytics/automaticEvents.js
|
|
6233
|
-
function compactProperties(properties) {
|
|
6234
|
-
const out = {
|
|
6235
|
-
capture_source: "automatic"
|
|
6236
|
-
};
|
|
6237
|
-
for (const [key, value] of Object.entries(properties ?? {})) {
|
|
6238
|
-
if (value !== void 0) out[key] = value;
|
|
6239
|
-
}
|
|
6240
|
-
return out;
|
|
6241
|
-
}
|
|
6242
|
-
function emitAutomaticEvent(name, properties) {
|
|
6243
|
-
const event = {
|
|
6244
|
-
name,
|
|
6245
|
-
properties: compactProperties(properties)
|
|
6246
|
-
};
|
|
6247
|
-
if (listeners.size === 0) {
|
|
6248
|
-
pending3.push(event);
|
|
6249
|
-
if (pending3.length > MAX_PENDING2) pending3.shift();
|
|
6250
|
-
return;
|
|
6251
|
-
}
|
|
6252
|
-
for (const listener of listeners) {
|
|
6253
|
-
try {
|
|
6254
|
-
listener(event);
|
|
6255
|
-
} catch {
|
|
6256
|
-
}
|
|
6257
|
-
}
|
|
6258
|
-
}
|
|
6259
|
-
function subscribeAutomaticEvents(listener) {
|
|
6260
|
-
listeners.add(listener);
|
|
6261
|
-
if (pending3.length > 0) {
|
|
6262
|
-
const buffered = pending3.splice(0, pending3.length);
|
|
6263
|
-
for (const event of buffered) {
|
|
6264
|
-
try {
|
|
6265
|
-
listener(event);
|
|
6266
|
-
} catch {
|
|
6267
|
-
}
|
|
6268
|
-
}
|
|
6269
|
-
}
|
|
6270
|
-
return () => {
|
|
6271
|
-
listeners.delete(listener);
|
|
6272
|
-
};
|
|
6273
|
-
}
|
|
6274
|
-
var listeners, pending3, MAX_PENDING2;
|
|
6275
|
-
var init_automaticEvents = __esm({
|
|
6276
|
-
"lib/module/analytics/automaticEvents.js"() {
|
|
6277
|
-
"use strict";
|
|
6278
|
-
listeners = /* @__PURE__ */ new Set();
|
|
6279
|
-
pending3 = [];
|
|
6280
|
-
MAX_PENDING2 = 50;
|
|
6281
|
-
}
|
|
6282
|
-
});
|
|
6283
|
-
|
|
6284
6370
|
// lib/module/analytics/EventTracker.js
|
|
6285
6371
|
function uuid() {
|
|
6286
6372
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
@@ -6349,7 +6435,7 @@ var init_EventTracker = __esm({
|
|
|
6349
6435
|
this.started = true;
|
|
6350
6436
|
if (this.cfg.automaticEventTracking) {
|
|
6351
6437
|
this.automaticEventsUnsubscribe = subscribeAutomaticEvents((event) => {
|
|
6352
|
-
this.track(event.name, event.properties);
|
|
6438
|
+
this.track(event.name, event.properties, event.timestamp);
|
|
6353
6439
|
});
|
|
6354
6440
|
}
|
|
6355
6441
|
if (this.cfg.autoLifecycleEvents) {
|
|
@@ -6453,9 +6539,9 @@ var init_EventTracker = __esm({
|
|
|
6453
6539
|
}
|
|
6454
6540
|
}
|
|
6455
6541
|
// ─── tracking ────────────────────────────────────────────────────────────
|
|
6456
|
-
track(eventName, properties) {
|
|
6542
|
+
track(eventName, properties, timestamp) {
|
|
6457
6543
|
try {
|
|
6458
|
-
this.enqueue(this.buildEnvelope(eventName, properties));
|
|
6544
|
+
this.enqueue(this.buildEnvelope(eventName, properties, timestamp));
|
|
6459
6545
|
try {
|
|
6460
6546
|
this.cfg.onEvent?.(eventName);
|
|
6461
6547
|
} catch {
|
|
@@ -6559,7 +6645,7 @@ var init_EventTracker = __esm({
|
|
|
6559
6645
|
};
|
|
6560
6646
|
}
|
|
6561
6647
|
// ─── internals ─────────────────────────────────────────────────────────────
|
|
6562
|
-
buildEnvelope(eventName, properties) {
|
|
6648
|
+
buildEnvelope(eventName, properties, timestamp) {
|
|
6563
6649
|
const ctx = this.cfg.context ?? {};
|
|
6564
6650
|
let canonicalSessionId;
|
|
6565
6651
|
try {
|
|
@@ -6570,7 +6656,7 @@ var init_EventTracker = __esm({
|
|
|
6570
6656
|
const env = {
|
|
6571
6657
|
event_id: uuid(),
|
|
6572
6658
|
event_name: eventName,
|
|
6573
|
-
event_time: Date.now(),
|
|
6659
|
+
event_time: timestamp ?? Date.now(),
|
|
6574
6660
|
app_id: this.cfg.appId,
|
|
6575
6661
|
platform: this.cfg.platform ?? resolveEventPlatform(),
|
|
6576
6662
|
installation_id: this.installationId,
|
|
@@ -7422,6 +7508,11 @@ async function deliverOtaEvents(params) {
|
|
|
7422
7508
|
kind: "ota_event",
|
|
7423
7509
|
type: e.type,
|
|
7424
7510
|
bundleId: e.bundleId,
|
|
7511
|
+
// Without this the backend stored a null releaseId on every row it ingested,
|
|
7512
|
+
// while serving the release id on every check — so the delivery funnel could
|
|
7513
|
+
// only ever be grouped by bundle, and a bundle re-promoted under a second
|
|
7514
|
+
// release merged the two into one indistinguishable series.
|
|
7515
|
+
releaseId: e.releaseId,
|
|
7425
7516
|
installationId: params.installationId,
|
|
7426
7517
|
// OTA bundles are compiled per platform, so this genuinely is ios|android. Narrowed via
|
|
7427
7518
|
// resolveMobileOS so a non-mobile RN target is skipped rather than served an Android bundle.
|
|
@@ -7523,20 +7614,31 @@ var init_OtaOrchestrator = __esm({
|
|
|
7523
7614
|
this.bootGuardConfig = config ?? {};
|
|
7524
7615
|
this.signatureConfig = config?.signature;
|
|
7525
7616
|
__DEV__ && logger.debug(`[OTA] Orchestrator initialized (RN ${this.environment.rnVersionString ?? "unknown"}${this.environment.bridgeless ? ", bridgeless" : ""}${this.environment.hermes ? `, Hermes HBC v${this.environment.hermesBytecodeVersion ?? "?"}` : ""})`);
|
|
7526
|
-
this.
|
|
7617
|
+
const slotState = this.readSlotState();
|
|
7618
|
+
this.hydrateCurrentBundleFromSlots(slotState);
|
|
7527
7619
|
void prefetchDeviceCountry();
|
|
7620
|
+
this.checkBootGuardRecovery(slotState);
|
|
7528
7621
|
this.verifyRunningBundleIdentity();
|
|
7529
|
-
this.checkBootGuardRecovery();
|
|
7530
7622
|
});
|
|
7531
7623
|
}
|
|
7532
7624
|
/**
|
|
7533
7625
|
* Read the active slot back into `currentBundle` so the next check reports
|
|
7534
7626
|
* what this device is genuinely running.
|
|
7535
7627
|
*/
|
|
7536
|
-
|
|
7537
|
-
|
|
7628
|
+
/**
|
|
7629
|
+
* Parse the native slot state once. Returns null when the module is absent or
|
|
7630
|
+
* the payload is unreadable — every caller treats that as "factory bundle".
|
|
7631
|
+
*/
|
|
7632
|
+
readSlotState() {
|
|
7633
|
+
if (!NativeScaleBunOta_default) return null;
|
|
7634
|
+
try {
|
|
7635
|
+
return JSON.parse(NativeScaleBunOta_default.getSlotState());
|
|
7636
|
+
} catch {
|
|
7637
|
+
return null;
|
|
7638
|
+
}
|
|
7639
|
+
}
|
|
7640
|
+
hydrateCurrentBundleFromSlots(state) {
|
|
7538
7641
|
try {
|
|
7539
|
-
const state = JSON.parse(NativeScaleBunOta_default.getSlotState());
|
|
7540
7642
|
const current = state?.current;
|
|
7541
7643
|
if (!current?.sha256) return;
|
|
7542
7644
|
const record4 = this.readInstallRecord();
|
|
@@ -7544,6 +7646,7 @@ var init_OtaOrchestrator = __esm({
|
|
|
7544
7646
|
this.currentBundle = {
|
|
7545
7647
|
id: record4.bundleId,
|
|
7546
7648
|
version: record4.version,
|
|
7649
|
+
releaseId: record4.releaseId ?? void 0,
|
|
7547
7650
|
sha256: record4.sha256
|
|
7548
7651
|
};
|
|
7549
7652
|
__DEV__ && logger.debug(`[OTA] Running bundle v${record4.version} (${record4.bundleId})`);
|
|
@@ -7574,29 +7677,23 @@ var init_OtaOrchestrator = __esm({
|
|
|
7574
7677
|
verifyRunningBundleIdentity() {
|
|
7575
7678
|
if (!this.currentBundle) return;
|
|
7576
7679
|
const running = readRunningBundleMarker();
|
|
7577
|
-
const
|
|
7578
|
-
if (
|
|
7680
|
+
const record4 = this.readInstallRecord();
|
|
7681
|
+
if (!record4) return;
|
|
7682
|
+
if (record4.sha256 !== this.currentBundle.sha256) {
|
|
7579
7683
|
this.clearInstallExpectation();
|
|
7580
7684
|
return;
|
|
7581
7685
|
}
|
|
7582
|
-
if (
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
return;
|
|
7587
|
-
}
|
|
7588
|
-
logger.error(`[OTA] INSTALL DID NOT TAKE EFFECT \u2014 bundle ${this.currentBundle.id} was installed and carries a known identity marker, but the running bundle reports ${running ?? "no marker at all"}. The app is executing different code than the slot manager believes. Check that the host app resolves the OTA bundle path at launch (see the ScaleBunOta integration for your React Native version).`);
|
|
7589
|
-
otaEventEmitter.emitSimple("APPLY_FAILED", this.currentBundle.id, {
|
|
7590
|
-
error: `install_not_effective \u2014 expected ${expected.identityToken}, running ${running ?? "none"}`
|
|
7591
|
-
});
|
|
7686
|
+
if (!record4.identityToken) return;
|
|
7687
|
+
if (running === record4.identityToken) {
|
|
7688
|
+
__DEV__ && logger.debug("[OTA] Install verified \u2014 running bundle matches what was installed.");
|
|
7689
|
+
this.retireIdentityToken(record4);
|
|
7592
7690
|
return;
|
|
7593
7691
|
}
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
}
|
|
7692
|
+
logger.error(`[OTA] INSTALL DID NOT TAKE EFFECT \u2014 bundle ${this.currentBundle.id} was installed and carries a known identity marker, but the running bundle reports ${running ?? "no marker at all"}. The app is executing different code than the slot manager believes. Check that the host app resolves the OTA bundle path at launch (see the ScaleBunOta integration for your React Native version).`);
|
|
7693
|
+
otaEventEmitter.emitSimple("APPLY_FAILED", this.currentBundle.id, {
|
|
7694
|
+
releaseId: this.currentBundle.releaseId,
|
|
7695
|
+
error: `install_not_effective \u2014 expected ${record4.identityToken}, running ${running ?? "none"}`
|
|
7696
|
+
});
|
|
7600
7697
|
}
|
|
7601
7698
|
// ── Install expectation ────────────────────────────────────────────────────
|
|
7602
7699
|
// Written just before the restart that activates a bundle, read on the next
|
|
@@ -7608,6 +7705,11 @@ var init_OtaOrchestrator = __esm({
|
|
|
7608
7705
|
this.storage().set(_OtaOrchestrator.INSTALL_EXPECTATION_KEY, JSON.stringify({
|
|
7609
7706
|
bundleId: bundle.id,
|
|
7610
7707
|
version: bundle.version,
|
|
7708
|
+
// Carried so telemetry emitted on a LATER launch (a boot-guard
|
|
7709
|
+
// rollback, an ineffective install) can still be attributed to the
|
|
7710
|
+
// release, not merely the bundle. The check response is long gone by
|
|
7711
|
+
// then; this record is the only thing that remembers.
|
|
7712
|
+
releaseId: bundle.releaseId ?? null,
|
|
7611
7713
|
// The join key back to the native slot, which records sha256 and
|
|
7612
7714
|
// nothing else identifying.
|
|
7613
7715
|
sha256: bundle.sha256,
|
|
@@ -7626,12 +7728,26 @@ var init_OtaOrchestrator = __esm({
|
|
|
7626
7728
|
return null;
|
|
7627
7729
|
}
|
|
7628
7730
|
}
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7731
|
+
/**
|
|
7732
|
+
* Drop the identity token once the install has been proven, keeping the rest
|
|
7733
|
+
* of the record.
|
|
7734
|
+
*
|
|
7735
|
+
* The record does two jobs: it proves an install took effect (once), and it
|
|
7736
|
+
* maps the native slot's sha256 back to a bundle id (for the life of that
|
|
7737
|
+
* bundle). Only the first job is finished after a successful verification, so
|
|
7738
|
+
* only the token is retired.
|
|
7739
|
+
*/
|
|
7740
|
+
retireIdentityToken(record4) {
|
|
7741
|
+
try {
|
|
7742
|
+
this.storage().set(_OtaOrchestrator.INSTALL_EXPECTATION_KEY, JSON.stringify({
|
|
7743
|
+
bundleId: record4.bundleId,
|
|
7744
|
+
version: record4.version,
|
|
7745
|
+
releaseId: record4.releaseId ?? null,
|
|
7746
|
+
sha256: record4.sha256,
|
|
7747
|
+
identityToken: null
|
|
7748
|
+
}));
|
|
7749
|
+
} catch {
|
|
7750
|
+
}
|
|
7635
7751
|
}
|
|
7636
7752
|
clearInstallExpectation() {
|
|
7637
7753
|
try {
|
|
@@ -7648,17 +7764,24 @@ var init_OtaOrchestrator = __esm({
|
|
|
7648
7764
|
* If getSlotState() shows bootMarkerPresent=false but we have a 'previous' slot
|
|
7649
7765
|
* and no 'current' OTA bundle, the native layer already reverted.
|
|
7650
7766
|
*/
|
|
7651
|
-
checkBootGuardRecovery() {
|
|
7652
|
-
if (!NativeScaleBunOta_default) return;
|
|
7767
|
+
checkBootGuardRecovery(state) {
|
|
7653
7768
|
try {
|
|
7654
|
-
|
|
7655
|
-
const
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7769
|
+
if (!state?.bootGuardReverted) return;
|
|
7770
|
+
const record4 = this.readInstallRecord();
|
|
7771
|
+
const revertedSha = state.bootGuardRevertedSha256;
|
|
7772
|
+
const matchesRecord = !!record4 && (!revertedSha || record4.sha256 === revertedSha);
|
|
7773
|
+
const reason = state.bootGuardRevertReason || "boot_crash_guard";
|
|
7774
|
+
if (matchesRecord && record4) {
|
|
7775
|
+
logger.warn(`[OTA] Boot guard fired \u2014 reverted away from bundle ${record4.bundleId} (v${record4.version}); reason: ${reason}`);
|
|
7776
|
+
otaEventEmitter.emitSimple("AUTO_ROLLBACK", record4.bundleId, {
|
|
7777
|
+
releaseId: record4.releaseId ?? void 0,
|
|
7778
|
+
version: record4.version,
|
|
7779
|
+
reason
|
|
7660
7780
|
});
|
|
7781
|
+
this.clearInstallExpectation();
|
|
7782
|
+
return;
|
|
7661
7783
|
}
|
|
7784
|
+
logger.warn(`[OTA] Boot guard fired (reason: ${reason}) but the rolled-back bundle could not be identified locally \u2014 no install record. The rollback is not reported to the server.`);
|
|
7662
7785
|
} catch {
|
|
7663
7786
|
}
|
|
7664
7787
|
}
|
|
@@ -7749,6 +7872,12 @@ var init_OtaOrchestrator = __esm({
|
|
|
7749
7872
|
};
|
|
7750
7873
|
}
|
|
7751
7874
|
__DEV__ && logger.debug("[OTA] Sync started\u2026");
|
|
7875
|
+
if (this.currentBundle?.id) {
|
|
7876
|
+
otaEventEmitter.emitSimple("CHECK", this.currentBundle.id, {
|
|
7877
|
+
releaseId: this.currentBundle.releaseId,
|
|
7878
|
+
version: this.currentBundle.version
|
|
7879
|
+
});
|
|
7880
|
+
}
|
|
7752
7881
|
const checkRes = await this.checkForUpdate(params);
|
|
7753
7882
|
if (checkRes.action === "NONE") {
|
|
7754
7883
|
__DEV__ && logger.debug("[OTA] App is up to date");
|
|
@@ -7759,7 +7888,9 @@ var init_OtaOrchestrator = __esm({
|
|
|
7759
7888
|
}
|
|
7760
7889
|
if (checkRes.action === "ROLLBACK") {
|
|
7761
7890
|
logger.warn("[OTA] Server requested ROLLBACK \u2014 reverting to previous bundle");
|
|
7762
|
-
otaEventEmitter.emitSimple("MANUAL_ROLLBACK", this.currentBundle?.id ?? "unknown"
|
|
7891
|
+
otaEventEmitter.emitSimple("MANUAL_ROLLBACK", this.currentBundle?.id ?? "unknown", {
|
|
7892
|
+
releaseId: this.currentBundle?.releaseId
|
|
7893
|
+
});
|
|
7763
7894
|
const reverted = await NativeScaleBunOta_default.revertToPrevious();
|
|
7764
7895
|
if (reverted) {
|
|
7765
7896
|
this.currentBundle = null;
|
|
@@ -7783,9 +7914,14 @@ var init_OtaOrchestrator = __esm({
|
|
|
7783
7914
|
}
|
|
7784
7915
|
const bundle = checkRes.bundle;
|
|
7785
7916
|
let patchUsed = false;
|
|
7917
|
+
otaEventEmitter.emitSimple("OFFERED", bundle.id, {
|
|
7918
|
+
releaseId: bundle.releaseId,
|
|
7919
|
+
version: bundle.version
|
|
7920
|
+
});
|
|
7786
7921
|
const signatureOutcome = await verifyBundleSignature(bundle.sha256, bundle.signature, this.signatureConfig);
|
|
7787
7922
|
if (!signatureOutcome.ok) {
|
|
7788
7923
|
otaEventEmitter.emitSimple("APPLY_FAILED", bundle.id, {
|
|
7924
|
+
releaseId: bundle.releaseId,
|
|
7789
7925
|
error: `Signature check failed: ${signatureOutcome.reason}`,
|
|
7790
7926
|
version: bundle.version
|
|
7791
7927
|
});
|
|
@@ -7796,6 +7932,7 @@ var init_OtaOrchestrator = __esm({
|
|
|
7796
7932
|
};
|
|
7797
7933
|
}
|
|
7798
7934
|
otaEventEmitter.emitSimple("DOWNLOAD_STARTED", bundle.id, {
|
|
7935
|
+
releaseId: bundle.releaseId,
|
|
7799
7936
|
version: bundle.version
|
|
7800
7937
|
});
|
|
7801
7938
|
const downloadStart = Date.now();
|
|
@@ -7881,6 +8018,7 @@ var init_OtaOrchestrator = __esm({
|
|
|
7881
8018
|
postProgress(0, "FAILED");
|
|
7882
8019
|
logger.error("[OTA] Staging bundle failed after retries");
|
|
7883
8020
|
otaEventEmitter.emitSimple("APPLY_FAILED", bundle.id, {
|
|
8021
|
+
releaseId: bundle.releaseId,
|
|
7884
8022
|
error: "Staging failed \u2014 SHA-256 mismatch or download error",
|
|
7885
8023
|
version: bundle.version
|
|
7886
8024
|
});
|
|
@@ -7893,6 +8031,7 @@ var init_OtaOrchestrator = __esm({
|
|
|
7893
8031
|
postProgress(bundle.size, "COMPLETED");
|
|
7894
8032
|
const downloadDuration = Date.now() - downloadStart;
|
|
7895
8033
|
otaEventEmitter.emitSimple("DOWNLOAD_COMPLETE", bundle.id, {
|
|
8034
|
+
releaseId: bundle.releaseId,
|
|
7896
8035
|
version: bundle.version,
|
|
7897
8036
|
durationMs: downloadDuration,
|
|
7898
8037
|
patchUsed
|
|
@@ -7901,6 +8040,7 @@ var init_OtaOrchestrator = __esm({
|
|
|
7901
8040
|
if (!applied) {
|
|
7902
8041
|
logger.error("[OTA] Applying update failed");
|
|
7903
8042
|
otaEventEmitter.emitSimple("APPLY_FAILED", bundle.id, {
|
|
8043
|
+
releaseId: bundle.releaseId,
|
|
7904
8044
|
error: "Atomic slot swap failed",
|
|
7905
8045
|
version: bundle.version
|
|
7906
8046
|
});
|
|
@@ -7914,6 +8054,7 @@ var init_OtaOrchestrator = __esm({
|
|
|
7914
8054
|
this.isRestartRequiredState = true;
|
|
7915
8055
|
this.recordInstallExpectation(bundle);
|
|
7916
8056
|
otaEventEmitter.emitSimple("INSTALLED", bundle.id, {
|
|
8057
|
+
releaseId: bundle.releaseId,
|
|
7917
8058
|
version: bundle.version
|
|
7918
8059
|
});
|
|
7919
8060
|
__DEV__ && logger.debug(`[OTA] Update v${bundle.version} installed successfully!`);
|
|
@@ -7966,6 +8107,14 @@ var init_OtaOrchestrator = __esm({
|
|
|
7966
8107
|
NativeScaleBunOta_default?.markHealthy();
|
|
7967
8108
|
__DEV__ && logger.info("[OTA] Boot guard cleared \u2014 bundle marked healthy \u2713");
|
|
7968
8109
|
this.healthyTimer = null;
|
|
8110
|
+
const running = this.currentBundle;
|
|
8111
|
+
if (running?.id) {
|
|
8112
|
+
otaEventEmitter.emitSimple("BOOT_SUCCESS", running.id, {
|
|
8113
|
+
releaseId: running.releaseId,
|
|
8114
|
+
version: running.version,
|
|
8115
|
+
durationMs: healthyMs
|
|
8116
|
+
});
|
|
8117
|
+
}
|
|
7969
8118
|
});
|
|
7970
8119
|
}, healthyMs);
|
|
7971
8120
|
} catch {
|
|
@@ -8056,7 +8205,14 @@ function clearUiState(name) {
|
|
|
8056
8205
|
}
|
|
8057
8206
|
function uiStateSignature() {
|
|
8058
8207
|
if (!declared.size) return void 0;
|
|
8059
|
-
|
|
8208
|
+
const pairs = [...declared.keys()].sort().map((k) => `${k}:${declared.get(k)}`);
|
|
8209
|
+
let signature = "";
|
|
8210
|
+
for (const pair of pairs) {
|
|
8211
|
+
const next = signature ? `${signature};${pair}` : pair;
|
|
8212
|
+
if (next.length > 96) break;
|
|
8213
|
+
signature = next;
|
|
8214
|
+
}
|
|
8215
|
+
return signature || void 0;
|
|
8060
8216
|
}
|
|
8061
8217
|
var declared, clean;
|
|
8062
8218
|
var init_uiState = __esm({
|
|
@@ -10329,31 +10485,8 @@ var FlushScheduler = class {
|
|
|
10329
10485
|
}
|
|
10330
10486
|
};
|
|
10331
10487
|
|
|
10332
|
-
// lib/module/
|
|
10333
|
-
|
|
10334
|
-
init_internalLogger();
|
|
10335
|
-
var AppLifecycle = class {
|
|
10336
|
-
listeners = [];
|
|
10337
|
-
currentState = import_react_native6.AppState.currentState;
|
|
10338
|
-
constructor() {
|
|
10339
|
-
import_react_native6.AppState.addEventListener("change", this.handleStateChange);
|
|
10340
|
-
}
|
|
10341
|
-
handleStateChange = (nextState) => {
|
|
10342
|
-
__DEV__ && logger.debug(`App state changed: ${this.currentState} -> ${nextState}`);
|
|
10343
|
-
this.currentState = nextState;
|
|
10344
|
-
this.listeners.forEach((l) => l(nextState));
|
|
10345
|
-
};
|
|
10346
|
-
addListener(listener) {
|
|
10347
|
-
this.listeners.push(listener);
|
|
10348
|
-
}
|
|
10349
|
-
removeListener(listener) {
|
|
10350
|
-
this.listeners = this.listeners.filter((l) => l !== listener);
|
|
10351
|
-
}
|
|
10352
|
-
getCurrentState() {
|
|
10353
|
-
return this.currentState;
|
|
10354
|
-
}
|
|
10355
|
-
};
|
|
10356
|
-
var appLifecycle = new AppLifecycle();
|
|
10488
|
+
// lib/module/bootstrap/SDKBootstrapper.js
|
|
10489
|
+
init_appLifecycle();
|
|
10357
10490
|
|
|
10358
10491
|
// lib/module/bootstrap/FeatureRegistry.js
|
|
10359
10492
|
init_internalLogger();
|
|
@@ -11013,14 +11146,14 @@ function installRejectionHandler(onRejection, deps) {
|
|
|
11013
11146
|
allRejections: true,
|
|
11014
11147
|
onUnhandled: (id, error) => {
|
|
11015
11148
|
const err = toError(error);
|
|
11016
|
-
|
|
11149
|
+
pending3.set(id, err);
|
|
11017
11150
|
onRejection(err);
|
|
11018
11151
|
if (isDev) {
|
|
11019
11152
|
console.warn(`Possible unhandled promise rejection (id: ${id}):`, err?.message ?? err);
|
|
11020
11153
|
}
|
|
11021
11154
|
},
|
|
11022
11155
|
onHandled: (id) => {
|
|
11023
|
-
|
|
11156
|
+
pending3.delete(id);
|
|
11024
11157
|
if (isDev) {
|
|
11025
11158
|
console.warn(`Promise rejection handled late (id: ${id}) \u2014 it was already reported.`);
|
|
11026
11159
|
}
|
|
@@ -11030,7 +11163,7 @@ function installRejectionHandler(onRejection, deps) {
|
|
|
11030
11163
|
return true;
|
|
11031
11164
|
}) ?? false;
|
|
11032
11165
|
}
|
|
11033
|
-
var
|
|
11166
|
+
var pending3 = /* @__PURE__ */ new Map();
|
|
11034
11167
|
|
|
11035
11168
|
// lib/module/features/crash/CrashFeature.js
|
|
11036
11169
|
init_CrashReporter();
|
|
@@ -11347,7 +11480,7 @@ var AppLaunchCollector = class {
|
|
|
11347
11480
|
};
|
|
11348
11481
|
|
|
11349
11482
|
// lib/module/features/performance/collectors/ScreenLoadCollector.js
|
|
11350
|
-
var
|
|
11483
|
+
var MAX_PENDING2 = 20;
|
|
11351
11484
|
var ScreenLoadCollector = class {
|
|
11352
11485
|
pending = /* @__PURE__ */ new Map();
|
|
11353
11486
|
lastScreen = null;
|
|
@@ -11362,7 +11495,7 @@ var ScreenLoadCollector = class {
|
|
|
11362
11495
|
*/
|
|
11363
11496
|
markStart(screenName) {
|
|
11364
11497
|
if (!this.config.screenLoad) return;
|
|
11365
|
-
if (this.pending.size >=
|
|
11498
|
+
if (this.pending.size >= MAX_PENDING2) {
|
|
11366
11499
|
const oldest = this.pending.keys().next().value;
|
|
11367
11500
|
if (oldest) this.pending.delete(oldest);
|
|
11368
11501
|
}
|
|
@@ -16839,7 +16972,7 @@ async function captureInstallReferrerOnce(sink) {
|
|
|
16839
16972
|
}
|
|
16840
16973
|
|
|
16841
16974
|
// lib/module/public/ScaleBunFacade.js
|
|
16842
|
-
var ScaleBunFacade = class {
|
|
16975
|
+
var ScaleBunFacade = class _ScaleBunFacade {
|
|
16843
16976
|
initialized = false;
|
|
16844
16977
|
/** In-flight init promise — guards against a second init() racing before the first resolves. */
|
|
16845
16978
|
_initInFlight = null;
|
|
@@ -16999,6 +17132,7 @@ var ScaleBunFacade = class {
|
|
|
16999
17132
|
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`.");
|
|
17000
17133
|
}
|
|
17001
17134
|
}
|
|
17135
|
+
const healthyAfterMs = typeof ota.healthyAfterMs === "number" ? ota.healthyAfterMs : typeof ota.healthyTimeoutMs === "number" ? ota.healthyTimeoutMs : void 0;
|
|
17002
17136
|
otaOrchestrator2.init({
|
|
17003
17137
|
...signingRequested ? {
|
|
17004
17138
|
signature: {
|
|
@@ -17008,15 +17142,99 @@ var ScaleBunFacade = class {
|
|
|
17008
17142
|
verifier
|
|
17009
17143
|
}
|
|
17010
17144
|
} : {},
|
|
17011
|
-
...
|
|
17012
|
-
|
|
17145
|
+
...healthyAfterMs !== void 0 ? {
|
|
17146
|
+
healthyAfterMs
|
|
17013
17147
|
} : {}
|
|
17014
17148
|
});
|
|
17015
17149
|
logger.info("[ScaleBun] OTA enabled from init config.");
|
|
17150
|
+
this._startOtaChecks(ota);
|
|
17016
17151
|
} catch (err) {
|
|
17017
17152
|
logger.warn(`[ScaleBun] OTA init failed: ${err?.message ?? err}`);
|
|
17018
17153
|
}
|
|
17019
17154
|
}
|
|
17155
|
+
/** Guards against overlapping config-driven OTA checks. */
|
|
17156
|
+
_otaCheckInFlight = false;
|
|
17157
|
+
/** Wall clock of the last config-driven check, for the foreground floor. */
|
|
17158
|
+
_otaLastCheckAt = 0;
|
|
17159
|
+
_otaForegroundListener = null;
|
|
17160
|
+
/**
|
|
17161
|
+
* Minimum gap between config-driven checks.
|
|
17162
|
+
*
|
|
17163
|
+
* A foreground transition is cheap to trigger — app switchers, permission
|
|
17164
|
+
* dialogs and share sheets all produce one — so an unthrottled check would
|
|
17165
|
+
* put a request on the hot path every time the user glanced away. Ten
|
|
17166
|
+
* minutes is well below any realistic release cadence and well above that
|
|
17167
|
+
* noise. A host that wants a check on demand calls `useOtaUpdate().sync()`,
|
|
17168
|
+
* which is never throttled.
|
|
17169
|
+
*/
|
|
17170
|
+
static OTA_MIN_CHECK_INTERVAL_MS = 10 * 60 * 1e3;
|
|
17171
|
+
/**
|
|
17172
|
+
* Drive OTA checks from init config: once at startup, then on each
|
|
17173
|
+
* foreground when `checkOnForeground` is on (the schema default).
|
|
17174
|
+
*
|
|
17175
|
+
* `appVersion` is resolved from the native bridge rather than asked of the
|
|
17176
|
+
* integrator, because it gates the server's `targetAppVersion` semver check
|
|
17177
|
+
* — sending a wrong or invented value is worse than sending none, and there
|
|
17178
|
+
* is no honest default. If it cannot be resolved, the check is skipped with
|
|
17179
|
+
* a warning instead of guessing.
|
|
17180
|
+
*/
|
|
17181
|
+
_startOtaChecks(ota) {
|
|
17182
|
+
if (__DEV__) {
|
|
17183
|
+
logger.info("[ScaleBun] OTA checks are skipped in debug builds (Metro owns the bundle).");
|
|
17184
|
+
return;
|
|
17185
|
+
}
|
|
17186
|
+
const runCheck = async (trigger) => {
|
|
17187
|
+
if (this._otaCheckInFlight) return;
|
|
17188
|
+
if (trigger === "foreground" && Date.now() - this._otaLastCheckAt < _ScaleBunFacade.OTA_MIN_CHECK_INTERVAL_MS) {
|
|
17189
|
+
return;
|
|
17190
|
+
}
|
|
17191
|
+
const clientKey = this._clientKey;
|
|
17192
|
+
const apiUrl = this._apiBaseUrl;
|
|
17193
|
+
if (!clientKey || !apiUrl) return;
|
|
17194
|
+
this._otaCheckInFlight = true;
|
|
17195
|
+
try {
|
|
17196
|
+
const info = await bridgeAdapter.getDeviceInfo();
|
|
17197
|
+
const appVersion = info?.appVersion;
|
|
17198
|
+
if (!appVersion) {
|
|
17199
|
+
logger.warn("[ScaleBun] OTA check skipped \u2014 the app version could not be read from the native bridge. Rebuild the native app, or drive checks yourself with useOtaUpdate({ appVersion }).");
|
|
17200
|
+
return;
|
|
17201
|
+
}
|
|
17202
|
+
this._otaLastCheckAt = Date.now();
|
|
17203
|
+
const {
|
|
17204
|
+
otaOrchestrator: otaOrchestrator2
|
|
17205
|
+
} = (init_OtaOrchestrator(), __toCommonJS(OtaOrchestrator_exports));
|
|
17206
|
+
await otaOrchestrator2.sync({
|
|
17207
|
+
apiUrl,
|
|
17208
|
+
clientKey,
|
|
17209
|
+
appVersion,
|
|
17210
|
+
// The documented option, finally connected. Omitted means the
|
|
17211
|
+
// server's `default` channel, exactly as before.
|
|
17212
|
+
channelName: typeof ota.channelOverride === "string" ? ota.channelOverride : void 0
|
|
17213
|
+
// Never forced from config: the release's own installMode
|
|
17214
|
+
// decides when the app restarts, and yanking the screen out
|
|
17215
|
+
// from under a user is not a decision this switch should make.
|
|
17216
|
+
});
|
|
17217
|
+
} catch (err) {
|
|
17218
|
+
logger.warn(`[ScaleBun] OTA check failed: ${err?.message ?? err}`);
|
|
17219
|
+
} finally {
|
|
17220
|
+
this._otaCheckInFlight = false;
|
|
17221
|
+
}
|
|
17222
|
+
};
|
|
17223
|
+
void runCheck("startup");
|
|
17224
|
+
if (ota.checkOnForeground === false) return;
|
|
17225
|
+
if (this._otaForegroundListener) return;
|
|
17226
|
+
try {
|
|
17227
|
+
const {
|
|
17228
|
+
appLifecycle: appLifecycle2
|
|
17229
|
+
} = (init_appLifecycle(), __toCommonJS(appLifecycle_exports));
|
|
17230
|
+
this._otaForegroundListener = (state) => {
|
|
17231
|
+
if (state === "active") void runCheck("foreground");
|
|
17232
|
+
};
|
|
17233
|
+
appLifecycle2.addListener(this._otaForegroundListener);
|
|
17234
|
+
} catch {
|
|
17235
|
+
this._otaForegroundListener = null;
|
|
17236
|
+
}
|
|
17237
|
+
}
|
|
17020
17238
|
_autoEnableDebug(debugConfig) {
|
|
17021
17239
|
try {
|
|
17022
17240
|
const dbgConfig = buildDebugConfigFromInitConfig(debugConfig);
|
|
@@ -18428,6 +18646,7 @@ init_internalLogger();
|
|
|
18428
18646
|
|
|
18429
18647
|
// lib/module/features/engage/engageTriggerEngine.js
|
|
18430
18648
|
init_internalLogger();
|
|
18649
|
+
init_appLifecycle();
|
|
18431
18650
|
init_AutoScreenDetector();
|
|
18432
18651
|
init_StorageBackend();
|
|
18433
18652
|
init_engageSignals();
|
|
@@ -18735,6 +18954,7 @@ function installEngageTriggerEngine(deps) {
|
|
|
18735
18954
|
}
|
|
18736
18955
|
|
|
18737
18956
|
// lib/module/features/engage/EngagePromptProvider.js
|
|
18957
|
+
init_appLifecycle();
|
|
18738
18958
|
init_deviceId();
|
|
18739
18959
|
init_api();
|
|
18740
18960
|
init_SessionManager();
|
|
@@ -29983,7 +30203,6 @@ function useEngagePrompt() {
|
|
|
29983
30203
|
// lib/module/features/journey/ScaleBunDebugRoot.js
|
|
29984
30204
|
var import_react9 = __toESM(require("react"));
|
|
29985
30205
|
var import_react_native42 = require("react-native");
|
|
29986
|
-
init_automaticEvents();
|
|
29987
30206
|
|
|
29988
30207
|
// lib/module/features/journey/touchTarget.js
|
|
29989
30208
|
var MAX_DEPTH = 12;
|
|
@@ -30055,6 +30274,7 @@ function describeTouchTarget(t) {
|
|
|
30055
30274
|
|
|
30056
30275
|
// lib/module/features/journey/ScaleBunDebugRoot.js
|
|
30057
30276
|
init_device();
|
|
30277
|
+
init_interactionProtocol();
|
|
30058
30278
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
30059
30279
|
var _bootstrap = null;
|
|
30060
30280
|
function getBootstrap() {
|
|
@@ -30244,7 +30464,9 @@ function ScaleBunDebugRoot({
|
|
|
30244
30464
|
}, [navigationRef]);
|
|
30245
30465
|
const lastNativeTouchTsRef = (0, import_react9.useRef)(0);
|
|
30246
30466
|
const nativeTrackingConfirmedRef = (0, import_react9.useRef)(false);
|
|
30247
|
-
const
|
|
30467
|
+
const touchStartRef = (0, import_react9.useRef)(null);
|
|
30468
|
+
const interactionStartsRef = (0, import_react9.useRef)([]);
|
|
30469
|
+
const pendingJsEmitsRef = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
30248
30470
|
(0, import_react9.useEffect)(() => {
|
|
30249
30471
|
let subscription = null;
|
|
30250
30472
|
try {
|
|
@@ -30255,9 +30477,12 @@ function ScaleBunDebugRoot({
|
|
|
30255
30477
|
try {
|
|
30256
30478
|
lastNativeTouchTsRef.current = Date.now();
|
|
30257
30479
|
nativeTrackingConfirmedRef.current = true;
|
|
30258
|
-
|
|
30259
|
-
|
|
30260
|
-
|
|
30480
|
+
const nativeOccurredAt = typeof event.occurredAt === "number" ? event.occurredAt : (typeof event.timestamp === "number" ? event.timestamp : Date.now()) - (typeof event.durationMs === "number" ? event.durationMs : 0);
|
|
30481
|
+
const start = nearestInteractionStart(interactionStartsRef.current, nativeOccurredAt);
|
|
30482
|
+
if (start) {
|
|
30483
|
+
const pending4 = pendingJsEmitsRef.current.get(start.interactionId);
|
|
30484
|
+
if (pending4 !== void 0) clearTimeout(pending4);
|
|
30485
|
+
pendingJsEmitsRef.current.delete(start.interactionId);
|
|
30261
30486
|
}
|
|
30262
30487
|
const {
|
|
30263
30488
|
SessionManager: SessionManager2
|
|
@@ -30276,6 +30501,15 @@ function ScaleBunDebugRoot({
|
|
|
30276
30501
|
} catch {
|
|
30277
30502
|
}
|
|
30278
30503
|
sm.onGestureDetected(event.gestureType || "tap", {
|
|
30504
|
+
interactionId: event.interactionId || start?.interactionId || generateInteractionId(),
|
|
30505
|
+
interactionProtocol: event.interactionProtocol || INTERACTION_PROTOCOL_VERSION,
|
|
30506
|
+
occurredAt: nativeOccurredAt,
|
|
30507
|
+
ui: start?.ui,
|
|
30508
|
+
stateStatus: start?.stateStatus ?? "not_captured",
|
|
30509
|
+
target: start?.target,
|
|
30510
|
+
targetId: start?.targetId,
|
|
30511
|
+
screenName: start?.screenName,
|
|
30512
|
+
emitAutomaticAnalytics: start?.emitAutomaticAnalytics ?? captureAutomaticInteractions,
|
|
30279
30513
|
x: event.rawX,
|
|
30280
30514
|
y: event.rawY,
|
|
30281
30515
|
// Use the actual native end coords when present, not the down
|
|
@@ -30308,9 +30542,10 @@ function ScaleBunDebugRoot({
|
|
|
30308
30542
|
subscription?.remove();
|
|
30309
30543
|
} catch {
|
|
30310
30544
|
}
|
|
30545
|
+
for (const timer of pendingJsEmitsRef.current.values()) clearTimeout(timer);
|
|
30546
|
+
pendingJsEmitsRef.current.clear();
|
|
30311
30547
|
};
|
|
30312
|
-
}, []);
|
|
30313
|
-
const touchStartRef = (0, import_react9.useRef)(null);
|
|
30548
|
+
}, [captureAutomaticInteractions]);
|
|
30314
30549
|
const rootRectRef = (0, import_react9.useRef)(null);
|
|
30315
30550
|
const measureRoot = () => {
|
|
30316
30551
|
try {
|
|
@@ -30342,11 +30577,39 @@ function ScaleBunDebugRoot({
|
|
|
30342
30577
|
const handleTouchStart = (e) => {
|
|
30343
30578
|
try {
|
|
30344
30579
|
const touch = e.nativeEvent;
|
|
30345
|
-
|
|
30580
|
+
const target = resolveTouchTarget(e);
|
|
30581
|
+
let ui;
|
|
30582
|
+
let screenName;
|
|
30583
|
+
try {
|
|
30584
|
+
const {
|
|
30585
|
+
uiStateSignature: uiStateSignature2
|
|
30586
|
+
} = (init_uiState(), __toCommonJS(uiState_exports));
|
|
30587
|
+
ui = uiStateSignature2();
|
|
30588
|
+
} catch {
|
|
30589
|
+
}
|
|
30590
|
+
try {
|
|
30591
|
+
const {
|
|
30592
|
+
AutoScreenDetector: AutoScreenDetector2
|
|
30593
|
+
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
30594
|
+
screenName = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
30595
|
+
} catch {
|
|
30596
|
+
}
|
|
30597
|
+
const start = {
|
|
30598
|
+
interactionId: generateInteractionId(),
|
|
30599
|
+
occurredAt: Date.now(),
|
|
30346
30600
|
x: touch.pageX,
|
|
30347
30601
|
y: touch.pageY,
|
|
30348
|
-
|
|
30602
|
+
locationX: touch.locationX,
|
|
30603
|
+
locationY: touch.locationY,
|
|
30604
|
+
target: describeTouchTarget(target),
|
|
30605
|
+
targetId: target?.testID,
|
|
30606
|
+
screenName,
|
|
30607
|
+
ui,
|
|
30608
|
+
stateStatus: ui ? "captured_nonempty" : "not_instrumented",
|
|
30609
|
+
emitAutomaticAnalytics: captureAutomaticInteractions
|
|
30349
30610
|
};
|
|
30611
|
+
touchStartRef.current = start;
|
|
30612
|
+
interactionStartsRef.current = interactionStartsRef.current.filter((candidate) => start.occurredAt - candidate.occurredAt < 5e3).concat(start).slice(-8);
|
|
30350
30613
|
} catch {
|
|
30351
30614
|
}
|
|
30352
30615
|
};
|
|
@@ -30377,21 +30640,29 @@ function ScaleBunDebugRoot({
|
|
|
30377
30640
|
}
|
|
30378
30641
|
measureRoot();
|
|
30379
30642
|
const rootRect = rootRectRef.current;
|
|
30380
|
-
const tapped = describeTouchTarget(resolveTouchTarget(e));
|
|
30643
|
+
const tapped = start?.target ?? describeTouchTarget(resolveTouchTarget(e));
|
|
30381
30644
|
const gestureDetails = {
|
|
30382
30645
|
target: tapped,
|
|
30383
|
-
|
|
30384
|
-
|
|
30385
|
-
|
|
30386
|
-
|
|
30387
|
-
|
|
30388
|
-
|
|
30646
|
+
interactionId: start?.interactionId ?? generateInteractionId(),
|
|
30647
|
+
interactionProtocol: INTERACTION_PROTOCOL_VERSION,
|
|
30648
|
+
occurredAt: start?.occurredAt ?? Date.now(),
|
|
30649
|
+
ui: start?.ui,
|
|
30650
|
+
stateStatus: start?.stateStatus ?? "not_captured",
|
|
30651
|
+
targetId: start?.targetId,
|
|
30652
|
+
screenName: start?.screenName,
|
|
30653
|
+
emitAutomaticAnalytics: start?.emitAutomaticAnalytics ?? captureAutomaticInteractions,
|
|
30654
|
+
x: start?.x ?? touch.pageX,
|
|
30655
|
+
y: start?.y ?? touch.pageY,
|
|
30656
|
+
pageX: start?.x ?? touch.pageX,
|
|
30657
|
+
pageY: start?.y ?? touch.pageY,
|
|
30658
|
+
locationX: start?.locationX ?? touch.locationX,
|
|
30659
|
+
locationY: start?.locationY ?? touch.locationY,
|
|
30389
30660
|
viewportWidth: vpW > 0 ? vpW : void 0,
|
|
30390
30661
|
viewportHeight: vpH > 0 ? vpH : void 0
|
|
30391
30662
|
};
|
|
30392
30663
|
if (rootRect && rootRect.w > 0 && rootRect.h > 0) {
|
|
30393
|
-
const nx = Math.max(0, Math.min(1, touch.pageX / rootRect.w));
|
|
30394
|
-
const ny = Math.max(0, Math.min(1, touch.pageY / rootRect.h));
|
|
30664
|
+
const nx = Math.max(0, Math.min(1, (start?.x ?? touch.pageX) / rootRect.w));
|
|
30665
|
+
const ny = Math.max(0, Math.min(1, (start?.y ?? touch.pageY) / rootRect.h));
|
|
30395
30666
|
gestureDetails.normalizedX = nx;
|
|
30396
30667
|
gestureDetails.normalizedY = ny;
|
|
30397
30668
|
gestureDetails.normalizedPrecomputed = true;
|
|
@@ -30422,7 +30693,7 @@ function ScaleBunDebugRoot({
|
|
|
30422
30693
|
const dx = touch.pageX - start.x;
|
|
30423
30694
|
const dy = touch.pageY - start.y;
|
|
30424
30695
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
30425
|
-
const duration = Date.now() - start.
|
|
30696
|
+
const duration = Date.now() - start.occurredAt;
|
|
30426
30697
|
gestureDetails.duration = duration;
|
|
30427
30698
|
if (dist >= 15) {
|
|
30428
30699
|
gestureDetails.endX = touch.pageX;
|
|
@@ -30440,60 +30711,16 @@ function ScaleBunDebugRoot({
|
|
|
30440
30711
|
gestureType = "long_press";
|
|
30441
30712
|
}
|
|
30442
30713
|
}
|
|
30443
|
-
const targetInfo = _extractTarget(e);
|
|
30444
|
-
gestureDetails.target = targetInfo?.testId || targetInfo?.accessibilityLabel;
|
|
30445
|
-
if (captureAutomaticInteractions) {
|
|
30446
|
-
let screen;
|
|
30447
|
-
try {
|
|
30448
|
-
const {
|
|
30449
|
-
AutoScreenDetector: AutoScreenDetector2
|
|
30450
|
-
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
30451
|
-
screen = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
30452
|
-
} catch {
|
|
30453
|
-
}
|
|
30454
|
-
let ui;
|
|
30455
|
-
try {
|
|
30456
|
-
const {
|
|
30457
|
-
uiStateSignature: uiStateSignature2
|
|
30458
|
-
} = (init_uiState(), __toCommonJS(uiState_exports));
|
|
30459
|
-
ui = uiStateSignature2();
|
|
30460
|
-
} catch {
|
|
30461
|
-
}
|
|
30462
|
-
emitAutomaticEvent("element_interacted", {
|
|
30463
|
-
gesture_type: gestureType,
|
|
30464
|
-
screen_name: screen,
|
|
30465
|
-
/* THIS MAP ENUMERATES. A field added to the payload and forgotten here reaches the
|
|
30466
|
-
backend as undefined with no error anywhere — the recurring defect class in this
|
|
30467
|
-
codebase. `ui` is the key the grid aggregate reads for state, byte-identical to
|
|
30468
|
-
the web SDK's, so one dashboard control queries both platforms. */
|
|
30469
|
-
ui,
|
|
30470
|
-
// testID/nativeID is an author-controlled stable identifier.
|
|
30471
|
-
// Accessibility labels and rendered text are deliberately omitted.
|
|
30472
|
-
target_id: targetInfo?.testId,
|
|
30473
|
-
normalized_x: gestureDetails.normalizedX,
|
|
30474
|
-
normalized_y: gestureDetails.normalizedY,
|
|
30475
|
-
direction: gestureDetails.direction,
|
|
30476
|
-
duration_ms: gestureDetails.duration
|
|
30477
|
-
});
|
|
30478
|
-
}
|
|
30479
30714
|
if (gestureType === "tap") {
|
|
30480
30715
|
try {
|
|
30481
30716
|
const {
|
|
30482
30717
|
gestureTriggerDetector: gestureTriggerDetector2
|
|
30483
30718
|
} = (init_gestureTriggerDetector(), __toCommonJS(gestureTriggerDetector_exports));
|
|
30484
|
-
let screen;
|
|
30485
|
-
try {
|
|
30486
|
-
const {
|
|
30487
|
-
AutoScreenDetector: AutoScreenDetector2
|
|
30488
|
-
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
30489
|
-
screen = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
30490
|
-
} catch {
|
|
30491
|
-
}
|
|
30492
30719
|
gestureTriggerDetector2.recordTap({
|
|
30493
|
-
x: touch.pageX,
|
|
30494
|
-
y: touch.pageY,
|
|
30495
|
-
hasTarget: !!(
|
|
30496
|
-
screen
|
|
30720
|
+
x: start?.x ?? touch.pageX,
|
|
30721
|
+
y: start?.y ?? touch.pageY,
|
|
30722
|
+
hasTarget: !!(start?.targetId || start?.target),
|
|
30723
|
+
screen: start?.screenName
|
|
30497
30724
|
});
|
|
30498
30725
|
} catch {
|
|
30499
30726
|
}
|
|
@@ -30506,11 +30733,9 @@ function ScaleBunDebugRoot({
|
|
|
30506
30733
|
const capturedDetails = {
|
|
30507
30734
|
...gestureDetails
|
|
30508
30735
|
};
|
|
30509
|
-
|
|
30510
|
-
|
|
30511
|
-
|
|
30512
|
-
pendingJsEmitRef.current = setTimeout(() => {
|
|
30513
|
-
pendingJsEmitRef.current = null;
|
|
30736
|
+
const interactionId = capturedDetails.interactionId;
|
|
30737
|
+
const timer = setTimeout(() => {
|
|
30738
|
+
pendingJsEmitsRef.current.delete(interactionId);
|
|
30514
30739
|
if (nativeTrackingConfirmedRef.current) return;
|
|
30515
30740
|
try {
|
|
30516
30741
|
const {
|
|
@@ -30527,6 +30752,7 @@ function ScaleBunDebugRoot({
|
|
|
30527
30752
|
} catch {
|
|
30528
30753
|
}
|
|
30529
30754
|
}, 600);
|
|
30755
|
+
pendingJsEmitsRef.current.set(interactionId, timer);
|
|
30530
30756
|
}
|
|
30531
30757
|
touchStartRef.current = null;
|
|
30532
30758
|
} catch {
|
|
@@ -30602,20 +30828,6 @@ function useScaleBunScreen(name) {
|
|
|
30602
30828
|
}
|
|
30603
30829
|
}, [name, manager]);
|
|
30604
30830
|
}
|
|
30605
|
-
function _extractTarget(e) {
|
|
30606
|
-
try {
|
|
30607
|
-
const target = e?.target;
|
|
30608
|
-
if (!target) return void 0;
|
|
30609
|
-
const props = target._internalFiberInstanceHandleDEV?.memoizedProps ?? {};
|
|
30610
|
-
return {
|
|
30611
|
-
testId: props.testID || props.nativeID || void 0,
|
|
30612
|
-
accessibilityLabel: props.accessibilityLabel || void 0,
|
|
30613
|
-
text: void 0
|
|
30614
|
-
};
|
|
30615
|
-
} catch {
|
|
30616
|
-
return void 0;
|
|
30617
|
-
}
|
|
30618
|
-
}
|
|
30619
30831
|
var styles4 = {
|
|
30620
30832
|
root: {
|
|
30621
30833
|
flex: 1
|
|
@@ -30976,7 +31188,7 @@ function useOtaUpdate(options) {
|
|
|
30976
31188
|
setIsSyncing(true);
|
|
30977
31189
|
setDownloadProgress(0);
|
|
30978
31190
|
try {
|
|
30979
|
-
const result = await otaOrchestrator.sync(
|
|
31191
|
+
const result = await otaOrchestrator.sync(optionsRef.current);
|
|
30980
31192
|
setSyncResult(result);
|
|
30981
31193
|
if (result.isMandatory && result.status === "UPDATE_INSTALLED" && optionsRef.current.mandatoryBlocksUi) {
|
|
30982
31194
|
setMandatoryUpdatePending(true);
|
|
@@ -30985,7 +31197,7 @@ function useOtaUpdate(options) {
|
|
|
30985
31197
|
} finally {
|
|
30986
31198
|
setIsSyncing(false);
|
|
30987
31199
|
}
|
|
30988
|
-
}, [
|
|
31200
|
+
}, []);
|
|
30989
31201
|
const restart = (0, import_react16.useCallback)(() => {
|
|
30990
31202
|
setMandatoryUpdatePending(false);
|
|
30991
31203
|
otaOrchestrator.restart();
|