@scalebun/react-native 1.10.7 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/scalebun/replaysdk/tracking/InteractionTracker.kt +25 -24
- package/dist/scalebun.full.js +236 -187
- package/dist/scalebun.slim.js +235 -186
- package/ios/Capture/InteractionTracker.swift +8 -4
- 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/session/JourneyEventPipeline.js +6 -5
- package/lib/commonjs/features/session/SessionManager.js +37 -38
- 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/session/JourneyEventPipeline.js +6 -5
- package/lib/module/features/session/SessionManager.js +37 -38
- 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/session/JourneyEventPipeline.d.ts +1 -0
- package/lib/typescript/features/session/SessionManager.d.ts +15 -10
- package/package.json +3 -2
- 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/session/JourneyEventPipeline.ts +7 -5
- package/src/features/session/SessionManager.ts +75 -38
package/dist/scalebun.full.js
CHANGED
|
@@ -605,7 +605,7 @@ var SDK_VERSION;
|
|
|
605
605
|
var init_version = __esm({
|
|
606
606
|
"lib/module/core/constants/version.js"() {
|
|
607
607
|
"use strict";
|
|
608
|
-
SDK_VERSION = "1.
|
|
608
|
+
SDK_VERSION = "1.11.0";
|
|
609
609
|
}
|
|
610
610
|
});
|
|
611
611
|
|
|
@@ -4567,22 +4567,23 @@ var init_JourneyEventPipeline = __esm({
|
|
|
4567
4567
|
emit(type, opts) {
|
|
4568
4568
|
try {
|
|
4569
4569
|
const key = `${type}:${opts?.subtype ?? ""}`;
|
|
4570
|
-
const
|
|
4571
|
-
|
|
4570
|
+
const receivedAt = Date.now();
|
|
4571
|
+
const occurredAt = opts?.timestamp ?? receivedAt;
|
|
4572
|
+
if (key === this.lastEventKey && receivedAt - this.lastEventTs < this.config.dedupeWindowMs) {
|
|
4572
4573
|
const incomingConfidence = opts?.payload?.confidence;
|
|
4573
4574
|
if (incomingConfidence === "high" && this.lastEventConfidence !== "high") {
|
|
4574
|
-
this._replaceLastEvent(key,
|
|
4575
|
+
this._replaceLastEvent(key, receivedAt, opts);
|
|
4575
4576
|
}
|
|
4576
4577
|
return null;
|
|
4577
4578
|
}
|
|
4578
4579
|
this.lastEventKey = key;
|
|
4579
|
-
this.lastEventTs =
|
|
4580
|
+
this.lastEventTs = receivedAt;
|
|
4580
4581
|
this.lastEventConfidence = opts?.payload?.confidence ?? null;
|
|
4581
4582
|
const event = {
|
|
4582
4583
|
eventId: generateEventId2(),
|
|
4583
4584
|
sessionId: this.sessionId,
|
|
4584
4585
|
journeyId: opts?.journeyId,
|
|
4585
|
-
ts:
|
|
4586
|
+
ts: occurredAt,
|
|
4586
4587
|
type,
|
|
4587
4588
|
subtype: opts?.subtype,
|
|
4588
4589
|
severity: opts?.severity ?? inferSeverity(type),
|
|
@@ -5682,6 +5683,99 @@ var init_calibrationContext = __esm({
|
|
|
5682
5683
|
}
|
|
5683
5684
|
});
|
|
5684
5685
|
|
|
5686
|
+
// lib/module/analytics/automaticEvents.js
|
|
5687
|
+
function compactProperties(properties) {
|
|
5688
|
+
const out = {
|
|
5689
|
+
capture_source: "automatic"
|
|
5690
|
+
};
|
|
5691
|
+
for (const [key, value] of Object.entries(properties ?? {})) {
|
|
5692
|
+
if (value !== void 0) out[key] = value;
|
|
5693
|
+
}
|
|
5694
|
+
return out;
|
|
5695
|
+
}
|
|
5696
|
+
function emitAutomaticEvent(name, properties, timestamp) {
|
|
5697
|
+
const event = {
|
|
5698
|
+
name,
|
|
5699
|
+
properties: compactProperties(properties),
|
|
5700
|
+
timestamp
|
|
5701
|
+
};
|
|
5702
|
+
if (listeners.size === 0) {
|
|
5703
|
+
pending2.push(event);
|
|
5704
|
+
if (pending2.length > MAX_PENDING) pending2.shift();
|
|
5705
|
+
return;
|
|
5706
|
+
}
|
|
5707
|
+
for (const listener of listeners) {
|
|
5708
|
+
try {
|
|
5709
|
+
listener(event);
|
|
5710
|
+
} catch {
|
|
5711
|
+
}
|
|
5712
|
+
}
|
|
5713
|
+
}
|
|
5714
|
+
function subscribeAutomaticEvents(listener) {
|
|
5715
|
+
listeners.add(listener);
|
|
5716
|
+
if (pending2.length > 0) {
|
|
5717
|
+
const buffered = pending2.splice(0, pending2.length);
|
|
5718
|
+
for (const event of buffered) {
|
|
5719
|
+
try {
|
|
5720
|
+
listener(event);
|
|
5721
|
+
} catch {
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
return () => {
|
|
5726
|
+
listeners.delete(listener);
|
|
5727
|
+
};
|
|
5728
|
+
}
|
|
5729
|
+
var listeners, pending2, MAX_PENDING;
|
|
5730
|
+
var init_automaticEvents = __esm({
|
|
5731
|
+
"lib/module/analytics/automaticEvents.js"() {
|
|
5732
|
+
"use strict";
|
|
5733
|
+
listeners = /* @__PURE__ */ new Set();
|
|
5734
|
+
pending2 = [];
|
|
5735
|
+
MAX_PENDING = 50;
|
|
5736
|
+
}
|
|
5737
|
+
});
|
|
5738
|
+
|
|
5739
|
+
// lib/module/features/journey/interactionProtocol.js
|
|
5740
|
+
function generateInteractionId() {
|
|
5741
|
+
return `ixj-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
5742
|
+
}
|
|
5743
|
+
function nearestInteractionStart(starts, occurredAt, toleranceMs = 1500) {
|
|
5744
|
+
let best;
|
|
5745
|
+
let bestDelta = toleranceMs + 1;
|
|
5746
|
+
for (const start of starts) {
|
|
5747
|
+
const delta = Math.abs(start.occurredAt - occurredAt);
|
|
5748
|
+
if (delta < bestDelta) {
|
|
5749
|
+
best = start;
|
|
5750
|
+
bestDelta = delta;
|
|
5751
|
+
}
|
|
5752
|
+
}
|
|
5753
|
+
return bestDelta <= toleranceMs ? best : void 0;
|
|
5754
|
+
}
|
|
5755
|
+
function automaticInteractionProperties(payload, screenName, canonicalMirror) {
|
|
5756
|
+
return {
|
|
5757
|
+
gesture_type: payload.gestureType,
|
|
5758
|
+
screen_name: screenName,
|
|
5759
|
+
interaction_id: payload.interaction_id,
|
|
5760
|
+
interaction_protocol: payload.interaction_protocol,
|
|
5761
|
+
state_status: payload.state_status,
|
|
5762
|
+
ui: payload.ui,
|
|
5763
|
+
target_id: payload.target_id,
|
|
5764
|
+
normalized_x: payload.normalizedX,
|
|
5765
|
+
normalized_y: payload.normalizedY,
|
|
5766
|
+
direction: payload.direction,
|
|
5767
|
+
duration_ms: payload.durationMs,
|
|
5768
|
+
canonical_mirror: canonicalMirror || void 0
|
|
5769
|
+
};
|
|
5770
|
+
}
|
|
5771
|
+
var INTERACTION_PROTOCOL_VERSION;
|
|
5772
|
+
var init_interactionProtocol = __esm({
|
|
5773
|
+
"lib/module/features/journey/interactionProtocol.js"() {
|
|
5774
|
+
"use strict";
|
|
5775
|
+
INTERACTION_PROTOCOL_VERSION = 1;
|
|
5776
|
+
}
|
|
5777
|
+
});
|
|
5778
|
+
|
|
5685
5779
|
// lib/module/features/session/SessionManager.js
|
|
5686
5780
|
var SessionManager_exports = {};
|
|
5687
5781
|
__export(SessionManager_exports, {
|
|
@@ -5690,7 +5784,7 @@ __export(SessionManager_exports, {
|
|
|
5690
5784
|
function generateSessionId2() {
|
|
5691
5785
|
return `ses-${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 8)}`;
|
|
5692
5786
|
}
|
|
5693
|
-
var
|
|
5787
|
+
var _instance2, SessionManager;
|
|
5694
5788
|
var init_SessionManager = __esm({
|
|
5695
5789
|
"lib/module/features/session/SessionManager.js"() {
|
|
5696
5790
|
"use strict";
|
|
@@ -5707,7 +5801,8 @@ var init_SessionManager = __esm({
|
|
|
5707
5801
|
init_redaction();
|
|
5708
5802
|
init_calibrationContext();
|
|
5709
5803
|
init_device();
|
|
5710
|
-
|
|
5804
|
+
init_automaticEvents();
|
|
5805
|
+
init_interactionProtocol();
|
|
5711
5806
|
_instance2 = null;
|
|
5712
5807
|
SessionManager = class _SessionManager {
|
|
5713
5808
|
desktopTransport = null;
|
|
@@ -5718,15 +5813,6 @@ var init_SessionManager = __esm({
|
|
|
5718
5813
|
* lane even when no replay recording is active. Additive, opt-in (default off).
|
|
5719
5814
|
*/
|
|
5720
5815
|
_captureInteractionHeatmap = false;
|
|
5721
|
-
/**
|
|
5722
|
-
* Sampling cap for the analytics-lane heatmap emission. Now that capture is
|
|
5723
|
-
* ON by default, an unbounded one-event-per-gesture stream could materially
|
|
5724
|
-
* inflate ingest volume. We cap emitted interactions per analytics-session
|
|
5725
|
-
* window (finalize-scoped per foreground): the first N gestures define the
|
|
5726
|
-
* hotspot shape; the long tail is dropped. Resets when the window changes.
|
|
5727
|
-
*/
|
|
5728
|
-
_heatmapWindowSessionId = null;
|
|
5729
|
-
_heatmapWindowCount = 0;
|
|
5730
5816
|
session = null;
|
|
5731
5817
|
active = false;
|
|
5732
5818
|
timeoutTimer = null;
|
|
@@ -6207,18 +6293,11 @@ var init_SessionManager = __esm({
|
|
|
6207
6293
|
* injected sensitive keys (e.g. a label) are stripped before transport.
|
|
6208
6294
|
* - Never throws.
|
|
6209
6295
|
*/
|
|
6210
|
-
_emitInteractionToAnalytics(gestureType, payload) {
|
|
6211
|
-
if (!this._captureInteractionHeatmap) return;
|
|
6212
|
-
if (this.active) return;
|
|
6296
|
+
_emitInteractionToAnalytics(gestureType, payload, occurredAt, screenName) {
|
|
6297
|
+
if (!this._captureInteractionHeatmap) return false;
|
|
6298
|
+
if (this.active) return false;
|
|
6213
6299
|
const adapter = this._backendTransport;
|
|
6214
|
-
if (!adapter) return;
|
|
6215
|
-
const windowId = adapter.analyticsSessionId ?? "";
|
|
6216
|
-
if (windowId !== this._heatmapWindowSessionId) {
|
|
6217
|
-
this._heatmapWindowSessionId = windowId;
|
|
6218
|
-
this._heatmapWindowCount = 0;
|
|
6219
|
-
}
|
|
6220
|
-
if (this._heatmapWindowCount >= HEATMAP_MAX_INTERACTIONS_PER_WINDOW) return;
|
|
6221
|
-
this._heatmapWindowCount++;
|
|
6300
|
+
if (!adapter) return false;
|
|
6222
6301
|
try {
|
|
6223
6302
|
this._normalizeInteractionPayload(payload);
|
|
6224
6303
|
const safePayload = redactBody(payload);
|
|
@@ -6226,16 +6305,18 @@ var init_SessionManager = __esm({
|
|
|
6226
6305
|
eventId: generateEventId(),
|
|
6227
6306
|
// sessionId is (re)stamped by the analytics lane at flush time.
|
|
6228
6307
|
sessionId: adapter.analyticsSessionId ?? "",
|
|
6229
|
-
ts:
|
|
6308
|
+
ts: occurredAt,
|
|
6230
6309
|
type: "USER_ACTION",
|
|
6231
6310
|
subtype: `gesture:${gestureType}`,
|
|
6232
|
-
screen: this._lastKnownScreen ?? void 0,
|
|
6311
|
+
screen: screenName ?? this._lastKnownScreen ?? void 0,
|
|
6233
6312
|
payload: safePayload,
|
|
6234
6313
|
source: "user"
|
|
6235
6314
|
};
|
|
6236
6315
|
adapter.trackEvent(event);
|
|
6316
|
+
return true;
|
|
6237
6317
|
} catch (err) {
|
|
6238
6318
|
logger.error("[SessionManager] heatmap analytics emit failed:", err);
|
|
6319
|
+
return false;
|
|
6239
6320
|
}
|
|
6240
6321
|
}
|
|
6241
6322
|
/**
|
|
@@ -6401,13 +6482,14 @@ var init_SessionManager = __esm({
|
|
|
6401
6482
|
* Notify of a user interaction. Called by ScaleBunDebugRoot touch handlers.
|
|
6402
6483
|
* Also triggers frame capture for desktop-initiated recordings.
|
|
6403
6484
|
*/
|
|
6404
|
-
onUserAction(subtype, payload) {
|
|
6485
|
+
onUserAction(subtype, payload, context) {
|
|
6405
6486
|
if (!this.active) return;
|
|
6406
6487
|
this.emitEvent("USER_ACTION", {
|
|
6407
6488
|
subtype,
|
|
6408
|
-
screen: this._lastKnownScreen ?? void 0,
|
|
6489
|
+
screen: context?.screen ?? this._lastKnownScreen ?? void 0,
|
|
6409
6490
|
payload,
|
|
6410
|
-
source: "user"
|
|
6491
|
+
source: "user",
|
|
6492
|
+
timestamp: context?.timestamp
|
|
6411
6493
|
});
|
|
6412
6494
|
}
|
|
6413
6495
|
/**
|
|
@@ -6415,7 +6497,8 @@ var init_SessionManager = __esm({
|
|
|
6415
6497
|
* Emits a USER_ACTION event with gesture-specific subtype and payload.
|
|
6416
6498
|
*/
|
|
6417
6499
|
onGestureDetected(gestureType, details) {
|
|
6418
|
-
const
|
|
6500
|
+
const suppliedInteractionId = details?.interactionId;
|
|
6501
|
+
const dedupSig = suppliedInteractionId ? `id:${suppliedInteractionId}` : `${gestureType}|${String(details?.x)}|${String(details?.y)}|${String(details?.endX)}|${String(details?.endY)}`;
|
|
6419
6502
|
const nowTs = Date.now();
|
|
6420
6503
|
if (dedupSig === this._lastGestureSig && nowTs - this._lastGestureTs <= _SessionManager.GESTURE_DEDUP_WINDOW_MS) {
|
|
6421
6504
|
this._lastGestureTs = nowTs;
|
|
@@ -6423,7 +6506,15 @@ var init_SessionManager = __esm({
|
|
|
6423
6506
|
}
|
|
6424
6507
|
this._lastGestureSig = dedupSig;
|
|
6425
6508
|
this._lastGestureTs = nowTs;
|
|
6509
|
+
const interactionId = suppliedInteractionId ?? generateInteractionId();
|
|
6510
|
+
const occurredAt = details?.occurredAt ?? Date.now();
|
|
6511
|
+
const stateStatus = details?.stateStatus ?? (details?.ui ? "captured_nonempty" : "not_captured");
|
|
6426
6512
|
const payload = {
|
|
6513
|
+
interaction_id: interactionId,
|
|
6514
|
+
interaction_protocol: details?.interactionProtocol ?? INTERACTION_PROTOCOL_VERSION,
|
|
6515
|
+
state_status: stateStatus,
|
|
6516
|
+
ui: details?.ui,
|
|
6517
|
+
target_id: details?.targetId,
|
|
6427
6518
|
gestureType,
|
|
6428
6519
|
x: details?.x,
|
|
6429
6520
|
y: details?.y,
|
|
@@ -6461,12 +6552,23 @@ var init_SessionManager = __esm({
|
|
|
6461
6552
|
screenHeight: details?.screenHeight,
|
|
6462
6553
|
platform: details?.platform
|
|
6463
6554
|
};
|
|
6464
|
-
this._emitInteractionToAnalytics(gestureType, {
|
|
6555
|
+
const analyticsReplayCarrier = this._emitInteractionToAnalytics(gestureType, {
|
|
6465
6556
|
...payload
|
|
6466
|
-
});
|
|
6557
|
+
}, occurredAt, details?.screenName);
|
|
6558
|
+
const replayCarrier = !!this._backendTransport && (this.active || analyticsReplayCarrier);
|
|
6559
|
+
if (details?.emitAutomaticAnalytics) {
|
|
6560
|
+
try {
|
|
6561
|
+
const safePayload = redactBody(payload);
|
|
6562
|
+
emitAutomaticEvent("element_interacted", automaticInteractionProperties(safePayload, details?.screenName ?? this._lastKnownScreen ?? void 0, replayCarrier), occurredAt);
|
|
6563
|
+
} catch {
|
|
6564
|
+
}
|
|
6565
|
+
}
|
|
6467
6566
|
if (!this.active) return;
|
|
6468
6567
|
const target = typeof details?.target === "string" ? details.target.trim() : "";
|
|
6469
|
-
this.onUserAction(target ? `gesture:${gestureType} \xB7 ${target}` : `gesture:${gestureType}`, payload
|
|
6568
|
+
this.onUserAction(target ? `gesture:${gestureType} \xB7 ${target}` : `gesture:${gestureType}`, payload, {
|
|
6569
|
+
screen: details?.screenName,
|
|
6570
|
+
timestamp: occurredAt
|
|
6571
|
+
});
|
|
6470
6572
|
}
|
|
6471
6573
|
/**
|
|
6472
6574
|
* Manual frame capture — triggered by Desktop "Capture Step" button.
|
|
@@ -7781,12 +7883,12 @@ var init_AppLaunchCollector = __esm({
|
|
|
7781
7883
|
});
|
|
7782
7884
|
|
|
7783
7885
|
// lib/module/features/performance/collectors/ScreenLoadCollector.js
|
|
7784
|
-
var
|
|
7886
|
+
var MAX_PENDING2, ScreenLoadCollector;
|
|
7785
7887
|
var init_ScreenLoadCollector = __esm({
|
|
7786
7888
|
"lib/module/features/performance/collectors/ScreenLoadCollector.js"() {
|
|
7787
7889
|
"use strict";
|
|
7788
7890
|
init_models();
|
|
7789
|
-
|
|
7891
|
+
MAX_PENDING2 = 20;
|
|
7790
7892
|
ScreenLoadCollector = class {
|
|
7791
7893
|
pending = /* @__PURE__ */ new Map();
|
|
7792
7894
|
lastScreen = null;
|
|
@@ -7801,7 +7903,7 @@ var init_ScreenLoadCollector = __esm({
|
|
|
7801
7903
|
*/
|
|
7802
7904
|
markStart(screenName) {
|
|
7803
7905
|
if (!this.config.screenLoad) return;
|
|
7804
|
-
if (this.pending.size >=
|
|
7906
|
+
if (this.pending.size >= MAX_PENDING2) {
|
|
7805
7907
|
const oldest = this.pending.keys().next().value;
|
|
7806
7908
|
if (oldest) this.pending.delete(oldest);
|
|
7807
7909
|
}
|
|
@@ -10933,58 +11035,6 @@ var init_batching = __esm({
|
|
|
10933
11035
|
}
|
|
10934
11036
|
});
|
|
10935
11037
|
|
|
10936
|
-
// lib/module/analytics/automaticEvents.js
|
|
10937
|
-
function compactProperties(properties) {
|
|
10938
|
-
const out = {
|
|
10939
|
-
capture_source: "automatic"
|
|
10940
|
-
};
|
|
10941
|
-
for (const [key, value] of Object.entries(properties ?? {})) {
|
|
10942
|
-
if (value !== void 0) out[key] = value;
|
|
10943
|
-
}
|
|
10944
|
-
return out;
|
|
10945
|
-
}
|
|
10946
|
-
function emitAutomaticEvent(name, properties) {
|
|
10947
|
-
const event = {
|
|
10948
|
-
name,
|
|
10949
|
-
properties: compactProperties(properties)
|
|
10950
|
-
};
|
|
10951
|
-
if (listeners.size === 0) {
|
|
10952
|
-
pending3.push(event);
|
|
10953
|
-
if (pending3.length > MAX_PENDING2) pending3.shift();
|
|
10954
|
-
return;
|
|
10955
|
-
}
|
|
10956
|
-
for (const listener of listeners) {
|
|
10957
|
-
try {
|
|
10958
|
-
listener(event);
|
|
10959
|
-
} catch {
|
|
10960
|
-
}
|
|
10961
|
-
}
|
|
10962
|
-
}
|
|
10963
|
-
function subscribeAutomaticEvents(listener) {
|
|
10964
|
-
listeners.add(listener);
|
|
10965
|
-
if (pending3.length > 0) {
|
|
10966
|
-
const buffered = pending3.splice(0, pending3.length);
|
|
10967
|
-
for (const event of buffered) {
|
|
10968
|
-
try {
|
|
10969
|
-
listener(event);
|
|
10970
|
-
} catch {
|
|
10971
|
-
}
|
|
10972
|
-
}
|
|
10973
|
-
}
|
|
10974
|
-
return () => {
|
|
10975
|
-
listeners.delete(listener);
|
|
10976
|
-
};
|
|
10977
|
-
}
|
|
10978
|
-
var listeners, pending3, MAX_PENDING2;
|
|
10979
|
-
var init_automaticEvents = __esm({
|
|
10980
|
-
"lib/module/analytics/automaticEvents.js"() {
|
|
10981
|
-
"use strict";
|
|
10982
|
-
listeners = /* @__PURE__ */ new Set();
|
|
10983
|
-
pending3 = [];
|
|
10984
|
-
MAX_PENDING2 = 50;
|
|
10985
|
-
}
|
|
10986
|
-
});
|
|
10987
|
-
|
|
10988
11038
|
// lib/module/analytics/EventTracker.js
|
|
10989
11039
|
function uuid() {
|
|
10990
11040
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
@@ -11053,7 +11103,7 @@ var init_EventTracker = __esm({
|
|
|
11053
11103
|
this.started = true;
|
|
11054
11104
|
if (this.cfg.automaticEventTracking) {
|
|
11055
11105
|
this.automaticEventsUnsubscribe = subscribeAutomaticEvents((event) => {
|
|
11056
|
-
this.track(event.name, event.properties);
|
|
11106
|
+
this.track(event.name, event.properties, event.timestamp);
|
|
11057
11107
|
});
|
|
11058
11108
|
}
|
|
11059
11109
|
if (this.cfg.autoLifecycleEvents) {
|
|
@@ -11157,9 +11207,9 @@ var init_EventTracker = __esm({
|
|
|
11157
11207
|
}
|
|
11158
11208
|
}
|
|
11159
11209
|
// ─── tracking ────────────────────────────────────────────────────────────
|
|
11160
|
-
track(eventName, properties) {
|
|
11210
|
+
track(eventName, properties, timestamp) {
|
|
11161
11211
|
try {
|
|
11162
|
-
this.enqueue(this.buildEnvelope(eventName, properties));
|
|
11212
|
+
this.enqueue(this.buildEnvelope(eventName, properties, timestamp));
|
|
11163
11213
|
try {
|
|
11164
11214
|
this.cfg.onEvent?.(eventName);
|
|
11165
11215
|
} catch {
|
|
@@ -11263,7 +11313,7 @@ var init_EventTracker = __esm({
|
|
|
11263
11313
|
};
|
|
11264
11314
|
}
|
|
11265
11315
|
// ─── internals ─────────────────────────────────────────────────────────────
|
|
11266
|
-
buildEnvelope(eventName, properties) {
|
|
11316
|
+
buildEnvelope(eventName, properties, timestamp) {
|
|
11267
11317
|
const ctx = this.cfg.context ?? {};
|
|
11268
11318
|
let canonicalSessionId;
|
|
11269
11319
|
try {
|
|
@@ -11274,7 +11324,7 @@ var init_EventTracker = __esm({
|
|
|
11274
11324
|
const env = {
|
|
11275
11325
|
event_id: uuid(),
|
|
11276
11326
|
event_name: eventName,
|
|
11277
|
-
event_time: Date.now(),
|
|
11327
|
+
event_time: timestamp ?? Date.now(),
|
|
11278
11328
|
app_id: this.cfg.appId,
|
|
11279
11329
|
platform: this.cfg.platform ?? resolveEventPlatform(),
|
|
11280
11330
|
installation_id: this.installationId,
|
|
@@ -12760,7 +12810,14 @@ function clearUiState(name) {
|
|
|
12760
12810
|
}
|
|
12761
12811
|
function uiStateSignature() {
|
|
12762
12812
|
if (!declared.size) return void 0;
|
|
12763
|
-
|
|
12813
|
+
const pairs = [...declared.keys()].sort().map((k) => `${k}:${declared.get(k)}`);
|
|
12814
|
+
let signature = "";
|
|
12815
|
+
for (const pair of pairs) {
|
|
12816
|
+
const next = signature ? `${signature};${pair}` : pair;
|
|
12817
|
+
if (next.length > 96) break;
|
|
12818
|
+
signature = next;
|
|
12819
|
+
}
|
|
12820
|
+
return signature || void 0;
|
|
12764
12821
|
}
|
|
12765
12822
|
var declared, clean;
|
|
12766
12823
|
var init_uiState = __esm({
|
|
@@ -15668,14 +15725,14 @@ function installRejectionHandler(onRejection, deps) {
|
|
|
15668
15725
|
allRejections: true,
|
|
15669
15726
|
onUnhandled: (id, error) => {
|
|
15670
15727
|
const err = toError(error);
|
|
15671
|
-
|
|
15728
|
+
pending3.set(id, err);
|
|
15672
15729
|
onRejection(err);
|
|
15673
15730
|
if (isDev) {
|
|
15674
15731
|
console.warn(`Possible unhandled promise rejection (id: ${id}):`, err?.message ?? err);
|
|
15675
15732
|
}
|
|
15676
15733
|
},
|
|
15677
15734
|
onHandled: (id) => {
|
|
15678
|
-
|
|
15735
|
+
pending3.delete(id);
|
|
15679
15736
|
if (isDev) {
|
|
15680
15737
|
console.warn(`Promise rejection handled late (id: ${id}) \u2014 it was already reported.`);
|
|
15681
15738
|
}
|
|
@@ -15685,7 +15742,7 @@ function installRejectionHandler(onRejection, deps) {
|
|
|
15685
15742
|
return true;
|
|
15686
15743
|
}) ?? false;
|
|
15687
15744
|
}
|
|
15688
|
-
var
|
|
15745
|
+
var pending3 = /* @__PURE__ */ new Map();
|
|
15689
15746
|
|
|
15690
15747
|
// lib/module/features/crash/CrashFeature.js
|
|
15691
15748
|
init_CrashReporter();
|
|
@@ -33194,7 +33251,6 @@ function useEngagePrompt() {
|
|
|
33194
33251
|
// lib/module/features/journey/ScaleBunDebugRoot.js
|
|
33195
33252
|
var import_react9 = __toESM(require("react"));
|
|
33196
33253
|
var import_react_native43 = require("react-native");
|
|
33197
|
-
init_automaticEvents();
|
|
33198
33254
|
|
|
33199
33255
|
// lib/module/features/journey/touchTarget.js
|
|
33200
33256
|
var MAX_DEPTH = 12;
|
|
@@ -33266,6 +33322,7 @@ function describeTouchTarget(t) {
|
|
|
33266
33322
|
|
|
33267
33323
|
// lib/module/features/journey/ScaleBunDebugRoot.js
|
|
33268
33324
|
init_device();
|
|
33325
|
+
init_interactionProtocol();
|
|
33269
33326
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
33270
33327
|
var _bootstrap = null;
|
|
33271
33328
|
function getBootstrap() {
|
|
@@ -33455,7 +33512,9 @@ function ScaleBunDebugRoot({
|
|
|
33455
33512
|
}, [navigationRef]);
|
|
33456
33513
|
const lastNativeTouchTsRef = (0, import_react9.useRef)(0);
|
|
33457
33514
|
const nativeTrackingConfirmedRef = (0, import_react9.useRef)(false);
|
|
33458
|
-
const
|
|
33515
|
+
const touchStartRef = (0, import_react9.useRef)(null);
|
|
33516
|
+
const interactionStartsRef = (0, import_react9.useRef)([]);
|
|
33517
|
+
const pendingJsEmitsRef = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
33459
33518
|
(0, import_react9.useEffect)(() => {
|
|
33460
33519
|
let subscription = null;
|
|
33461
33520
|
try {
|
|
@@ -33466,9 +33525,12 @@ function ScaleBunDebugRoot({
|
|
|
33466
33525
|
try {
|
|
33467
33526
|
lastNativeTouchTsRef.current = Date.now();
|
|
33468
33527
|
nativeTrackingConfirmedRef.current = true;
|
|
33469
|
-
|
|
33470
|
-
|
|
33471
|
-
|
|
33528
|
+
const nativeOccurredAt = typeof event.occurredAt === "number" ? event.occurredAt : (typeof event.timestamp === "number" ? event.timestamp : Date.now()) - (typeof event.durationMs === "number" ? event.durationMs : 0);
|
|
33529
|
+
const start = nearestInteractionStart(interactionStartsRef.current, nativeOccurredAt);
|
|
33530
|
+
if (start) {
|
|
33531
|
+
const pending4 = pendingJsEmitsRef.current.get(start.interactionId);
|
|
33532
|
+
if (pending4 !== void 0) clearTimeout(pending4);
|
|
33533
|
+
pendingJsEmitsRef.current.delete(start.interactionId);
|
|
33472
33534
|
}
|
|
33473
33535
|
const {
|
|
33474
33536
|
SessionManager: SessionManager2
|
|
@@ -33487,6 +33549,15 @@ function ScaleBunDebugRoot({
|
|
|
33487
33549
|
} catch {
|
|
33488
33550
|
}
|
|
33489
33551
|
sm.onGestureDetected(event.gestureType || "tap", {
|
|
33552
|
+
interactionId: event.interactionId || start?.interactionId || generateInteractionId(),
|
|
33553
|
+
interactionProtocol: event.interactionProtocol || INTERACTION_PROTOCOL_VERSION,
|
|
33554
|
+
occurredAt: nativeOccurredAt,
|
|
33555
|
+
ui: start?.ui,
|
|
33556
|
+
stateStatus: start?.stateStatus ?? "not_captured",
|
|
33557
|
+
target: start?.target,
|
|
33558
|
+
targetId: start?.targetId,
|
|
33559
|
+
screenName: start?.screenName,
|
|
33560
|
+
emitAutomaticAnalytics: start?.emitAutomaticAnalytics ?? captureAutomaticInteractions,
|
|
33490
33561
|
x: event.rawX,
|
|
33491
33562
|
y: event.rawY,
|
|
33492
33563
|
// Use the actual native end coords when present, not the down
|
|
@@ -33519,9 +33590,10 @@ function ScaleBunDebugRoot({
|
|
|
33519
33590
|
subscription?.remove();
|
|
33520
33591
|
} catch {
|
|
33521
33592
|
}
|
|
33593
|
+
for (const timer of pendingJsEmitsRef.current.values()) clearTimeout(timer);
|
|
33594
|
+
pendingJsEmitsRef.current.clear();
|
|
33522
33595
|
};
|
|
33523
|
-
}, []);
|
|
33524
|
-
const touchStartRef = (0, import_react9.useRef)(null);
|
|
33596
|
+
}, [captureAutomaticInteractions]);
|
|
33525
33597
|
const rootRectRef = (0, import_react9.useRef)(null);
|
|
33526
33598
|
const measureRoot = () => {
|
|
33527
33599
|
try {
|
|
@@ -33553,11 +33625,39 @@ function ScaleBunDebugRoot({
|
|
|
33553
33625
|
const handleTouchStart = (e) => {
|
|
33554
33626
|
try {
|
|
33555
33627
|
const touch = e.nativeEvent;
|
|
33556
|
-
|
|
33628
|
+
const target = resolveTouchTarget(e);
|
|
33629
|
+
let ui;
|
|
33630
|
+
let screenName;
|
|
33631
|
+
try {
|
|
33632
|
+
const {
|
|
33633
|
+
uiStateSignature: uiStateSignature2
|
|
33634
|
+
} = (init_uiState(), __toCommonJS(uiState_exports));
|
|
33635
|
+
ui = uiStateSignature2();
|
|
33636
|
+
} catch {
|
|
33637
|
+
}
|
|
33638
|
+
try {
|
|
33639
|
+
const {
|
|
33640
|
+
AutoScreenDetector: AutoScreenDetector2
|
|
33641
|
+
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
33642
|
+
screenName = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
33643
|
+
} catch {
|
|
33644
|
+
}
|
|
33645
|
+
const start = {
|
|
33646
|
+
interactionId: generateInteractionId(),
|
|
33647
|
+
occurredAt: Date.now(),
|
|
33557
33648
|
x: touch.pageX,
|
|
33558
33649
|
y: touch.pageY,
|
|
33559
|
-
|
|
33650
|
+
locationX: touch.locationX,
|
|
33651
|
+
locationY: touch.locationY,
|
|
33652
|
+
target: describeTouchTarget(target),
|
|
33653
|
+
targetId: target?.testID,
|
|
33654
|
+
screenName,
|
|
33655
|
+
ui,
|
|
33656
|
+
stateStatus: ui ? "captured_nonempty" : "not_instrumented",
|
|
33657
|
+
emitAutomaticAnalytics: captureAutomaticInteractions
|
|
33560
33658
|
};
|
|
33659
|
+
touchStartRef.current = start;
|
|
33660
|
+
interactionStartsRef.current = interactionStartsRef.current.filter((candidate) => start.occurredAt - candidate.occurredAt < 5e3).concat(start).slice(-8);
|
|
33561
33661
|
} catch {
|
|
33562
33662
|
}
|
|
33563
33663
|
};
|
|
@@ -33588,21 +33688,29 @@ function ScaleBunDebugRoot({
|
|
|
33588
33688
|
}
|
|
33589
33689
|
measureRoot();
|
|
33590
33690
|
const rootRect = rootRectRef.current;
|
|
33591
|
-
const tapped = describeTouchTarget(resolveTouchTarget(e));
|
|
33691
|
+
const tapped = start?.target ?? describeTouchTarget(resolveTouchTarget(e));
|
|
33592
33692
|
const gestureDetails = {
|
|
33593
33693
|
target: tapped,
|
|
33594
|
-
|
|
33595
|
-
|
|
33596
|
-
|
|
33597
|
-
|
|
33598
|
-
|
|
33599
|
-
|
|
33694
|
+
interactionId: start?.interactionId ?? generateInteractionId(),
|
|
33695
|
+
interactionProtocol: INTERACTION_PROTOCOL_VERSION,
|
|
33696
|
+
occurredAt: start?.occurredAt ?? Date.now(),
|
|
33697
|
+
ui: start?.ui,
|
|
33698
|
+
stateStatus: start?.stateStatus ?? "not_captured",
|
|
33699
|
+
targetId: start?.targetId,
|
|
33700
|
+
screenName: start?.screenName,
|
|
33701
|
+
emitAutomaticAnalytics: start?.emitAutomaticAnalytics ?? captureAutomaticInteractions,
|
|
33702
|
+
x: start?.x ?? touch.pageX,
|
|
33703
|
+
y: start?.y ?? touch.pageY,
|
|
33704
|
+
pageX: start?.x ?? touch.pageX,
|
|
33705
|
+
pageY: start?.y ?? touch.pageY,
|
|
33706
|
+
locationX: start?.locationX ?? touch.locationX,
|
|
33707
|
+
locationY: start?.locationY ?? touch.locationY,
|
|
33600
33708
|
viewportWidth: vpW > 0 ? vpW : void 0,
|
|
33601
33709
|
viewportHeight: vpH > 0 ? vpH : void 0
|
|
33602
33710
|
};
|
|
33603
33711
|
if (rootRect && rootRect.w > 0 && rootRect.h > 0) {
|
|
33604
|
-
const nx = Math.max(0, Math.min(1, touch.pageX / rootRect.w));
|
|
33605
|
-
const ny = Math.max(0, Math.min(1, touch.pageY / rootRect.h));
|
|
33712
|
+
const nx = Math.max(0, Math.min(1, (start?.x ?? touch.pageX) / rootRect.w));
|
|
33713
|
+
const ny = Math.max(0, Math.min(1, (start?.y ?? touch.pageY) / rootRect.h));
|
|
33606
33714
|
gestureDetails.normalizedX = nx;
|
|
33607
33715
|
gestureDetails.normalizedY = ny;
|
|
33608
33716
|
gestureDetails.normalizedPrecomputed = true;
|
|
@@ -33633,7 +33741,7 @@ function ScaleBunDebugRoot({
|
|
|
33633
33741
|
const dx = touch.pageX - start.x;
|
|
33634
33742
|
const dy = touch.pageY - start.y;
|
|
33635
33743
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
33636
|
-
const duration = Date.now() - start.
|
|
33744
|
+
const duration = Date.now() - start.occurredAt;
|
|
33637
33745
|
gestureDetails.duration = duration;
|
|
33638
33746
|
if (dist >= 15) {
|
|
33639
33747
|
gestureDetails.endX = touch.pageX;
|
|
@@ -33651,60 +33759,16 @@ function ScaleBunDebugRoot({
|
|
|
33651
33759
|
gestureType = "long_press";
|
|
33652
33760
|
}
|
|
33653
33761
|
}
|
|
33654
|
-
const targetInfo = _extractTarget(e);
|
|
33655
|
-
gestureDetails.target = targetInfo?.testId || targetInfo?.accessibilityLabel;
|
|
33656
|
-
if (captureAutomaticInteractions) {
|
|
33657
|
-
let screen;
|
|
33658
|
-
try {
|
|
33659
|
-
const {
|
|
33660
|
-
AutoScreenDetector: AutoScreenDetector2
|
|
33661
|
-
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
33662
|
-
screen = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
33663
|
-
} catch {
|
|
33664
|
-
}
|
|
33665
|
-
let ui;
|
|
33666
|
-
try {
|
|
33667
|
-
const {
|
|
33668
|
-
uiStateSignature: uiStateSignature2
|
|
33669
|
-
} = (init_uiState(), __toCommonJS(uiState_exports));
|
|
33670
|
-
ui = uiStateSignature2();
|
|
33671
|
-
} catch {
|
|
33672
|
-
}
|
|
33673
|
-
emitAutomaticEvent("element_interacted", {
|
|
33674
|
-
gesture_type: gestureType,
|
|
33675
|
-
screen_name: screen,
|
|
33676
|
-
/* THIS MAP ENUMERATES. A field added to the payload and forgotten here reaches the
|
|
33677
|
-
backend as undefined with no error anywhere — the recurring defect class in this
|
|
33678
|
-
codebase. `ui` is the key the grid aggregate reads for state, byte-identical to
|
|
33679
|
-
the web SDK's, so one dashboard control queries both platforms. */
|
|
33680
|
-
ui,
|
|
33681
|
-
// testID/nativeID is an author-controlled stable identifier.
|
|
33682
|
-
// Accessibility labels and rendered text are deliberately omitted.
|
|
33683
|
-
target_id: targetInfo?.testId,
|
|
33684
|
-
normalized_x: gestureDetails.normalizedX,
|
|
33685
|
-
normalized_y: gestureDetails.normalizedY,
|
|
33686
|
-
direction: gestureDetails.direction,
|
|
33687
|
-
duration_ms: gestureDetails.duration
|
|
33688
|
-
});
|
|
33689
|
-
}
|
|
33690
33762
|
if (gestureType === "tap") {
|
|
33691
33763
|
try {
|
|
33692
33764
|
const {
|
|
33693
33765
|
gestureTriggerDetector: gestureTriggerDetector2
|
|
33694
33766
|
} = (init_gestureTriggerDetector(), __toCommonJS(gestureTriggerDetector_exports));
|
|
33695
|
-
let screen;
|
|
33696
|
-
try {
|
|
33697
|
-
const {
|
|
33698
|
-
AutoScreenDetector: AutoScreenDetector2
|
|
33699
|
-
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
33700
|
-
screen = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
33701
|
-
} catch {
|
|
33702
|
-
}
|
|
33703
33767
|
gestureTriggerDetector2.recordTap({
|
|
33704
|
-
x: touch.pageX,
|
|
33705
|
-
y: touch.pageY,
|
|
33706
|
-
hasTarget: !!(
|
|
33707
|
-
screen
|
|
33768
|
+
x: start?.x ?? touch.pageX,
|
|
33769
|
+
y: start?.y ?? touch.pageY,
|
|
33770
|
+
hasTarget: !!(start?.targetId || start?.target),
|
|
33771
|
+
screen: start?.screenName
|
|
33708
33772
|
});
|
|
33709
33773
|
} catch {
|
|
33710
33774
|
}
|
|
@@ -33717,11 +33781,9 @@ function ScaleBunDebugRoot({
|
|
|
33717
33781
|
const capturedDetails = {
|
|
33718
33782
|
...gestureDetails
|
|
33719
33783
|
};
|
|
33720
|
-
|
|
33721
|
-
|
|
33722
|
-
|
|
33723
|
-
pendingJsEmitRef.current = setTimeout(() => {
|
|
33724
|
-
pendingJsEmitRef.current = null;
|
|
33784
|
+
const interactionId = capturedDetails.interactionId;
|
|
33785
|
+
const timer = setTimeout(() => {
|
|
33786
|
+
pendingJsEmitsRef.current.delete(interactionId);
|
|
33725
33787
|
if (nativeTrackingConfirmedRef.current) return;
|
|
33726
33788
|
try {
|
|
33727
33789
|
const {
|
|
@@ -33738,6 +33800,7 @@ function ScaleBunDebugRoot({
|
|
|
33738
33800
|
} catch {
|
|
33739
33801
|
}
|
|
33740
33802
|
}, 600);
|
|
33803
|
+
pendingJsEmitsRef.current.set(interactionId, timer);
|
|
33741
33804
|
}
|
|
33742
33805
|
touchStartRef.current = null;
|
|
33743
33806
|
} catch {
|
|
@@ -33813,20 +33876,6 @@ function useScaleBunScreen(name) {
|
|
|
33813
33876
|
}
|
|
33814
33877
|
}, [name, manager]);
|
|
33815
33878
|
}
|
|
33816
|
-
function _extractTarget(e) {
|
|
33817
|
-
try {
|
|
33818
|
-
const target = e?.target;
|
|
33819
|
-
if (!target) return void 0;
|
|
33820
|
-
const props = target._internalFiberInstanceHandleDEV?.memoizedProps ?? {};
|
|
33821
|
-
return {
|
|
33822
|
-
testId: props.testID || props.nativeID || void 0,
|
|
33823
|
-
accessibilityLabel: props.accessibilityLabel || void 0,
|
|
33824
|
-
text: void 0
|
|
33825
|
-
};
|
|
33826
|
-
} catch {
|
|
33827
|
-
return void 0;
|
|
33828
|
-
}
|
|
33829
|
-
}
|
|
33830
33879
|
var styles4 = {
|
|
33831
33880
|
root: {
|
|
33832
33881
|
flex: 1
|