@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.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.0";
|
|
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.
|
|
@@ -6229,58 +6331,6 @@ var init_batching = __esm({
|
|
|
6229
6331
|
}
|
|
6230
6332
|
});
|
|
6231
6333
|
|
|
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
6334
|
// lib/module/analytics/EventTracker.js
|
|
6285
6335
|
function uuid() {
|
|
6286
6336
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
@@ -6349,7 +6399,7 @@ var init_EventTracker = __esm({
|
|
|
6349
6399
|
this.started = true;
|
|
6350
6400
|
if (this.cfg.automaticEventTracking) {
|
|
6351
6401
|
this.automaticEventsUnsubscribe = subscribeAutomaticEvents((event) => {
|
|
6352
|
-
this.track(event.name, event.properties);
|
|
6402
|
+
this.track(event.name, event.properties, event.timestamp);
|
|
6353
6403
|
});
|
|
6354
6404
|
}
|
|
6355
6405
|
if (this.cfg.autoLifecycleEvents) {
|
|
@@ -6453,9 +6503,9 @@ var init_EventTracker = __esm({
|
|
|
6453
6503
|
}
|
|
6454
6504
|
}
|
|
6455
6505
|
// ─── tracking ────────────────────────────────────────────────────────────
|
|
6456
|
-
track(eventName, properties) {
|
|
6506
|
+
track(eventName, properties, timestamp) {
|
|
6457
6507
|
try {
|
|
6458
|
-
this.enqueue(this.buildEnvelope(eventName, properties));
|
|
6508
|
+
this.enqueue(this.buildEnvelope(eventName, properties, timestamp));
|
|
6459
6509
|
try {
|
|
6460
6510
|
this.cfg.onEvent?.(eventName);
|
|
6461
6511
|
} catch {
|
|
@@ -6559,7 +6609,7 @@ var init_EventTracker = __esm({
|
|
|
6559
6609
|
};
|
|
6560
6610
|
}
|
|
6561
6611
|
// ─── internals ─────────────────────────────────────────────────────────────
|
|
6562
|
-
buildEnvelope(eventName, properties) {
|
|
6612
|
+
buildEnvelope(eventName, properties, timestamp) {
|
|
6563
6613
|
const ctx = this.cfg.context ?? {};
|
|
6564
6614
|
let canonicalSessionId;
|
|
6565
6615
|
try {
|
|
@@ -6570,7 +6620,7 @@ var init_EventTracker = __esm({
|
|
|
6570
6620
|
const env = {
|
|
6571
6621
|
event_id: uuid(),
|
|
6572
6622
|
event_name: eventName,
|
|
6573
|
-
event_time: Date.now(),
|
|
6623
|
+
event_time: timestamp ?? Date.now(),
|
|
6574
6624
|
app_id: this.cfg.appId,
|
|
6575
6625
|
platform: this.cfg.platform ?? resolveEventPlatform(),
|
|
6576
6626
|
installation_id: this.installationId,
|
|
@@ -8056,7 +8106,14 @@ function clearUiState(name) {
|
|
|
8056
8106
|
}
|
|
8057
8107
|
function uiStateSignature() {
|
|
8058
8108
|
if (!declared.size) return void 0;
|
|
8059
|
-
|
|
8109
|
+
const pairs = [...declared.keys()].sort().map((k) => `${k}:${declared.get(k)}`);
|
|
8110
|
+
let signature = "";
|
|
8111
|
+
for (const pair of pairs) {
|
|
8112
|
+
const next = signature ? `${signature};${pair}` : pair;
|
|
8113
|
+
if (next.length > 96) break;
|
|
8114
|
+
signature = next;
|
|
8115
|
+
}
|
|
8116
|
+
return signature || void 0;
|
|
8060
8117
|
}
|
|
8061
8118
|
var declared, clean;
|
|
8062
8119
|
var init_uiState = __esm({
|
|
@@ -11013,14 +11070,14 @@ function installRejectionHandler(onRejection, deps) {
|
|
|
11013
11070
|
allRejections: true,
|
|
11014
11071
|
onUnhandled: (id, error) => {
|
|
11015
11072
|
const err = toError(error);
|
|
11016
|
-
|
|
11073
|
+
pending3.set(id, err);
|
|
11017
11074
|
onRejection(err);
|
|
11018
11075
|
if (isDev) {
|
|
11019
11076
|
console.warn(`Possible unhandled promise rejection (id: ${id}):`, err?.message ?? err);
|
|
11020
11077
|
}
|
|
11021
11078
|
},
|
|
11022
11079
|
onHandled: (id) => {
|
|
11023
|
-
|
|
11080
|
+
pending3.delete(id);
|
|
11024
11081
|
if (isDev) {
|
|
11025
11082
|
console.warn(`Promise rejection handled late (id: ${id}) \u2014 it was already reported.`);
|
|
11026
11083
|
}
|
|
@@ -11030,7 +11087,7 @@ function installRejectionHandler(onRejection, deps) {
|
|
|
11030
11087
|
return true;
|
|
11031
11088
|
}) ?? false;
|
|
11032
11089
|
}
|
|
11033
|
-
var
|
|
11090
|
+
var pending3 = /* @__PURE__ */ new Map();
|
|
11034
11091
|
|
|
11035
11092
|
// lib/module/features/crash/CrashFeature.js
|
|
11036
11093
|
init_CrashReporter();
|
|
@@ -11347,7 +11404,7 @@ var AppLaunchCollector = class {
|
|
|
11347
11404
|
};
|
|
11348
11405
|
|
|
11349
11406
|
// lib/module/features/performance/collectors/ScreenLoadCollector.js
|
|
11350
|
-
var
|
|
11407
|
+
var MAX_PENDING2 = 20;
|
|
11351
11408
|
var ScreenLoadCollector = class {
|
|
11352
11409
|
pending = /* @__PURE__ */ new Map();
|
|
11353
11410
|
lastScreen = null;
|
|
@@ -11362,7 +11419,7 @@ var ScreenLoadCollector = class {
|
|
|
11362
11419
|
*/
|
|
11363
11420
|
markStart(screenName) {
|
|
11364
11421
|
if (!this.config.screenLoad) return;
|
|
11365
|
-
if (this.pending.size >=
|
|
11422
|
+
if (this.pending.size >= MAX_PENDING2) {
|
|
11366
11423
|
const oldest = this.pending.keys().next().value;
|
|
11367
11424
|
if (oldest) this.pending.delete(oldest);
|
|
11368
11425
|
}
|
|
@@ -29983,7 +30040,6 @@ function useEngagePrompt() {
|
|
|
29983
30040
|
// lib/module/features/journey/ScaleBunDebugRoot.js
|
|
29984
30041
|
var import_react9 = __toESM(require("react"));
|
|
29985
30042
|
var import_react_native42 = require("react-native");
|
|
29986
|
-
init_automaticEvents();
|
|
29987
30043
|
|
|
29988
30044
|
// lib/module/features/journey/touchTarget.js
|
|
29989
30045
|
var MAX_DEPTH = 12;
|
|
@@ -30055,6 +30111,7 @@ function describeTouchTarget(t) {
|
|
|
30055
30111
|
|
|
30056
30112
|
// lib/module/features/journey/ScaleBunDebugRoot.js
|
|
30057
30113
|
init_device();
|
|
30114
|
+
init_interactionProtocol();
|
|
30058
30115
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
30059
30116
|
var _bootstrap = null;
|
|
30060
30117
|
function getBootstrap() {
|
|
@@ -30244,7 +30301,9 @@ function ScaleBunDebugRoot({
|
|
|
30244
30301
|
}, [navigationRef]);
|
|
30245
30302
|
const lastNativeTouchTsRef = (0, import_react9.useRef)(0);
|
|
30246
30303
|
const nativeTrackingConfirmedRef = (0, import_react9.useRef)(false);
|
|
30247
|
-
const
|
|
30304
|
+
const touchStartRef = (0, import_react9.useRef)(null);
|
|
30305
|
+
const interactionStartsRef = (0, import_react9.useRef)([]);
|
|
30306
|
+
const pendingJsEmitsRef = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
30248
30307
|
(0, import_react9.useEffect)(() => {
|
|
30249
30308
|
let subscription = null;
|
|
30250
30309
|
try {
|
|
@@ -30255,9 +30314,12 @@ function ScaleBunDebugRoot({
|
|
|
30255
30314
|
try {
|
|
30256
30315
|
lastNativeTouchTsRef.current = Date.now();
|
|
30257
30316
|
nativeTrackingConfirmedRef.current = true;
|
|
30258
|
-
|
|
30259
|
-
|
|
30260
|
-
|
|
30317
|
+
const nativeOccurredAt = typeof event.occurredAt === "number" ? event.occurredAt : (typeof event.timestamp === "number" ? event.timestamp : Date.now()) - (typeof event.durationMs === "number" ? event.durationMs : 0);
|
|
30318
|
+
const start = nearestInteractionStart(interactionStartsRef.current, nativeOccurredAt);
|
|
30319
|
+
if (start) {
|
|
30320
|
+
const pending4 = pendingJsEmitsRef.current.get(start.interactionId);
|
|
30321
|
+
if (pending4 !== void 0) clearTimeout(pending4);
|
|
30322
|
+
pendingJsEmitsRef.current.delete(start.interactionId);
|
|
30261
30323
|
}
|
|
30262
30324
|
const {
|
|
30263
30325
|
SessionManager: SessionManager2
|
|
@@ -30276,6 +30338,15 @@ function ScaleBunDebugRoot({
|
|
|
30276
30338
|
} catch {
|
|
30277
30339
|
}
|
|
30278
30340
|
sm.onGestureDetected(event.gestureType || "tap", {
|
|
30341
|
+
interactionId: event.interactionId || start?.interactionId || generateInteractionId(),
|
|
30342
|
+
interactionProtocol: event.interactionProtocol || INTERACTION_PROTOCOL_VERSION,
|
|
30343
|
+
occurredAt: nativeOccurredAt,
|
|
30344
|
+
ui: start?.ui,
|
|
30345
|
+
stateStatus: start?.stateStatus ?? "not_captured",
|
|
30346
|
+
target: start?.target,
|
|
30347
|
+
targetId: start?.targetId,
|
|
30348
|
+
screenName: start?.screenName,
|
|
30349
|
+
emitAutomaticAnalytics: start?.emitAutomaticAnalytics ?? captureAutomaticInteractions,
|
|
30279
30350
|
x: event.rawX,
|
|
30280
30351
|
y: event.rawY,
|
|
30281
30352
|
// Use the actual native end coords when present, not the down
|
|
@@ -30308,9 +30379,10 @@ function ScaleBunDebugRoot({
|
|
|
30308
30379
|
subscription?.remove();
|
|
30309
30380
|
} catch {
|
|
30310
30381
|
}
|
|
30382
|
+
for (const timer of pendingJsEmitsRef.current.values()) clearTimeout(timer);
|
|
30383
|
+
pendingJsEmitsRef.current.clear();
|
|
30311
30384
|
};
|
|
30312
|
-
}, []);
|
|
30313
|
-
const touchStartRef = (0, import_react9.useRef)(null);
|
|
30385
|
+
}, [captureAutomaticInteractions]);
|
|
30314
30386
|
const rootRectRef = (0, import_react9.useRef)(null);
|
|
30315
30387
|
const measureRoot = () => {
|
|
30316
30388
|
try {
|
|
@@ -30342,11 +30414,39 @@ function ScaleBunDebugRoot({
|
|
|
30342
30414
|
const handleTouchStart = (e) => {
|
|
30343
30415
|
try {
|
|
30344
30416
|
const touch = e.nativeEvent;
|
|
30345
|
-
|
|
30417
|
+
const target = resolveTouchTarget(e);
|
|
30418
|
+
let ui;
|
|
30419
|
+
let screenName;
|
|
30420
|
+
try {
|
|
30421
|
+
const {
|
|
30422
|
+
uiStateSignature: uiStateSignature2
|
|
30423
|
+
} = (init_uiState(), __toCommonJS(uiState_exports));
|
|
30424
|
+
ui = uiStateSignature2();
|
|
30425
|
+
} catch {
|
|
30426
|
+
}
|
|
30427
|
+
try {
|
|
30428
|
+
const {
|
|
30429
|
+
AutoScreenDetector: AutoScreenDetector2
|
|
30430
|
+
} = (init_AutoScreenDetector(), __toCommonJS(AutoScreenDetector_exports));
|
|
30431
|
+
screenName = AutoScreenDetector2.getInstance().getCurrentScreen() || void 0;
|
|
30432
|
+
} catch {
|
|
30433
|
+
}
|
|
30434
|
+
const start = {
|
|
30435
|
+
interactionId: generateInteractionId(),
|
|
30436
|
+
occurredAt: Date.now(),
|
|
30346
30437
|
x: touch.pageX,
|
|
30347
30438
|
y: touch.pageY,
|
|
30348
|
-
|
|
30439
|
+
locationX: touch.locationX,
|
|
30440
|
+
locationY: touch.locationY,
|
|
30441
|
+
target: describeTouchTarget(target),
|
|
30442
|
+
targetId: target?.testID,
|
|
30443
|
+
screenName,
|
|
30444
|
+
ui,
|
|
30445
|
+
stateStatus: ui ? "captured_nonempty" : "not_instrumented",
|
|
30446
|
+
emitAutomaticAnalytics: captureAutomaticInteractions
|
|
30349
30447
|
};
|
|
30448
|
+
touchStartRef.current = start;
|
|
30449
|
+
interactionStartsRef.current = interactionStartsRef.current.filter((candidate) => start.occurredAt - candidate.occurredAt < 5e3).concat(start).slice(-8);
|
|
30350
30450
|
} catch {
|
|
30351
30451
|
}
|
|
30352
30452
|
};
|
|
@@ -30377,21 +30477,29 @@ function ScaleBunDebugRoot({
|
|
|
30377
30477
|
}
|
|
30378
30478
|
measureRoot();
|
|
30379
30479
|
const rootRect = rootRectRef.current;
|
|
30380
|
-
const tapped = describeTouchTarget(resolveTouchTarget(e));
|
|
30480
|
+
const tapped = start?.target ?? describeTouchTarget(resolveTouchTarget(e));
|
|
30381
30481
|
const gestureDetails = {
|
|
30382
30482
|
target: tapped,
|
|
30383
|
-
|
|
30384
|
-
|
|
30385
|
-
|
|
30386
|
-
|
|
30387
|
-
|
|
30388
|
-
|
|
30483
|
+
interactionId: start?.interactionId ?? generateInteractionId(),
|
|
30484
|
+
interactionProtocol: INTERACTION_PROTOCOL_VERSION,
|
|
30485
|
+
occurredAt: start?.occurredAt ?? Date.now(),
|
|
30486
|
+
ui: start?.ui,
|
|
30487
|
+
stateStatus: start?.stateStatus ?? "not_captured",
|
|
30488
|
+
targetId: start?.targetId,
|
|
30489
|
+
screenName: start?.screenName,
|
|
30490
|
+
emitAutomaticAnalytics: start?.emitAutomaticAnalytics ?? captureAutomaticInteractions,
|
|
30491
|
+
x: start?.x ?? touch.pageX,
|
|
30492
|
+
y: start?.y ?? touch.pageY,
|
|
30493
|
+
pageX: start?.x ?? touch.pageX,
|
|
30494
|
+
pageY: start?.y ?? touch.pageY,
|
|
30495
|
+
locationX: start?.locationX ?? touch.locationX,
|
|
30496
|
+
locationY: start?.locationY ?? touch.locationY,
|
|
30389
30497
|
viewportWidth: vpW > 0 ? vpW : void 0,
|
|
30390
30498
|
viewportHeight: vpH > 0 ? vpH : void 0
|
|
30391
30499
|
};
|
|
30392
30500
|
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));
|
|
30501
|
+
const nx = Math.max(0, Math.min(1, (start?.x ?? touch.pageX) / rootRect.w));
|
|
30502
|
+
const ny = Math.max(0, Math.min(1, (start?.y ?? touch.pageY) / rootRect.h));
|
|
30395
30503
|
gestureDetails.normalizedX = nx;
|
|
30396
30504
|
gestureDetails.normalizedY = ny;
|
|
30397
30505
|
gestureDetails.normalizedPrecomputed = true;
|
|
@@ -30422,7 +30530,7 @@ function ScaleBunDebugRoot({
|
|
|
30422
30530
|
const dx = touch.pageX - start.x;
|
|
30423
30531
|
const dy = touch.pageY - start.y;
|
|
30424
30532
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
30425
|
-
const duration = Date.now() - start.
|
|
30533
|
+
const duration = Date.now() - start.occurredAt;
|
|
30426
30534
|
gestureDetails.duration = duration;
|
|
30427
30535
|
if (dist >= 15) {
|
|
30428
30536
|
gestureDetails.endX = touch.pageX;
|
|
@@ -30440,60 +30548,16 @@ function ScaleBunDebugRoot({
|
|
|
30440
30548
|
gestureType = "long_press";
|
|
30441
30549
|
}
|
|
30442
30550
|
}
|
|
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
30551
|
if (gestureType === "tap") {
|
|
30480
30552
|
try {
|
|
30481
30553
|
const {
|
|
30482
30554
|
gestureTriggerDetector: gestureTriggerDetector2
|
|
30483
30555
|
} = (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
30556
|
gestureTriggerDetector2.recordTap({
|
|
30493
|
-
x: touch.pageX,
|
|
30494
|
-
y: touch.pageY,
|
|
30495
|
-
hasTarget: !!(
|
|
30496
|
-
screen
|
|
30557
|
+
x: start?.x ?? touch.pageX,
|
|
30558
|
+
y: start?.y ?? touch.pageY,
|
|
30559
|
+
hasTarget: !!(start?.targetId || start?.target),
|
|
30560
|
+
screen: start?.screenName
|
|
30497
30561
|
});
|
|
30498
30562
|
} catch {
|
|
30499
30563
|
}
|
|
@@ -30506,11 +30570,9 @@ function ScaleBunDebugRoot({
|
|
|
30506
30570
|
const capturedDetails = {
|
|
30507
30571
|
...gestureDetails
|
|
30508
30572
|
};
|
|
30509
|
-
|
|
30510
|
-
|
|
30511
|
-
|
|
30512
|
-
pendingJsEmitRef.current = setTimeout(() => {
|
|
30513
|
-
pendingJsEmitRef.current = null;
|
|
30573
|
+
const interactionId = capturedDetails.interactionId;
|
|
30574
|
+
const timer = setTimeout(() => {
|
|
30575
|
+
pendingJsEmitsRef.current.delete(interactionId);
|
|
30514
30576
|
if (nativeTrackingConfirmedRef.current) return;
|
|
30515
30577
|
try {
|
|
30516
30578
|
const {
|
|
@@ -30527,6 +30589,7 @@ function ScaleBunDebugRoot({
|
|
|
30527
30589
|
} catch {
|
|
30528
30590
|
}
|
|
30529
30591
|
}, 600);
|
|
30592
|
+
pendingJsEmitsRef.current.set(interactionId, timer);
|
|
30530
30593
|
}
|
|
30531
30594
|
touchStartRef.current = null;
|
|
30532
30595
|
} catch {
|
|
@@ -30602,20 +30665,6 @@ function useScaleBunScreen(name) {
|
|
|
30602
30665
|
}
|
|
30603
30666
|
}, [name, manager]);
|
|
30604
30667
|
}
|
|
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
30668
|
var styles4 = {
|
|
30620
30669
|
root: {
|
|
30621
30670
|
flex: 1
|