@reservamos/browser-analytics 1.1.8-alpha.0 → 1.1.8-alpha.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/CHANGELOG.md +6 -1
- package/README.md +8 -4
- package/dist/browser-analytics.cjs +2 -2
- package/dist/browser-analytics.cjs.map +1 -1
- package/dist/browser-analytics.esm.js +417 -58
- package/dist/browser-analytics.esm.js.map +1 -1
- package/dist/browser-analytics.iife.js +2 -2
- package/dist/browser-analytics.iife.js.map +1 -1
- package/package.json +1 -1
- package/src/events/sharedSchemas/tripSchema.ts +3 -8
- package/src/init.botDetection.test.ts +187 -0
- package/src/init.test.ts +1 -0
- package/src/init.ts +15 -2
- package/src/services/deferredBotDetection.ts +60 -0
- package/src/services/fingerprint.test.ts +18 -0
- package/src/services/fingerprint.ts +36 -9
- package/src/services/mixpanel.test.ts +42 -0
- package/src/services/mixpanel.ts +54 -5
- package/src/services/trackingLifecycle.ts +54 -0
- package/src/services/validator/validator.test.ts +79 -0
- package/src/track.readiness.test.ts +131 -0
- package/src/track.recovery.test.ts +339 -0
- package/src/track.storage.test.ts +127 -0
- package/src/track.test.ts +130 -5
- package/src/track.ts +110 -25
- package/src/util/pendingWork.test.ts +164 -0
- package/src/util/pendingWork.ts +148 -0
- package/src/util/snapshotEventData.ts +15 -0
|
@@ -11260,9 +11260,9 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function(dat
|
|
|
11260
11260
|
if (deviceId) {
|
|
11261
11261
|
reqParams["$device_id"] = deviceId;
|
|
11262
11262
|
}
|
|
11263
|
-
var
|
|
11264
|
-
if (
|
|
11265
|
-
reqParams["$user_id"] =
|
|
11263
|
+
var userId2 = this._mixpanel.get_property("$user_id");
|
|
11264
|
+
if (userId2) {
|
|
11265
|
+
reqParams["$user_id"] = userId2;
|
|
11266
11266
|
}
|
|
11267
11267
|
if (CompressionStream) {
|
|
11268
11268
|
var jsonStream = new Blob([eventsJson], { type: "application/json" }).stream();
|
|
@@ -13339,6 +13339,50 @@ function loadNoop(_src, onload) {
|
|
|
13339
13339
|
onload();
|
|
13340
13340
|
}
|
|
13341
13341
|
var mixpanel = init_as_module(loadNoop);
|
|
13342
|
+
let generation = 0;
|
|
13343
|
+
let initialized = false;
|
|
13344
|
+
let userId;
|
|
13345
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
13346
|
+
const initializationSubscribers = /* @__PURE__ */ new Set();
|
|
13347
|
+
function invalidate$1() {
|
|
13348
|
+
generation++;
|
|
13349
|
+
subscribers.forEach((notify) => notify());
|
|
13350
|
+
}
|
|
13351
|
+
function beginInitialization() {
|
|
13352
|
+
if (initialized) invalidate$1();
|
|
13353
|
+
initialized = true;
|
|
13354
|
+
userId = void 0;
|
|
13355
|
+
initializationSubscribers.forEach((notify) => notify());
|
|
13356
|
+
}
|
|
13357
|
+
function identify$2(nextUserId) {
|
|
13358
|
+
if (userId !== nextUserId) {
|
|
13359
|
+
userId = nextUserId;
|
|
13360
|
+
invalidate$1();
|
|
13361
|
+
}
|
|
13362
|
+
}
|
|
13363
|
+
function capture() {
|
|
13364
|
+
const captured = generation;
|
|
13365
|
+
return () => captured === generation;
|
|
13366
|
+
}
|
|
13367
|
+
function onChange(notify) {
|
|
13368
|
+
subscribers.add(notify);
|
|
13369
|
+
return () => {
|
|
13370
|
+
subscribers.delete(notify);
|
|
13371
|
+
};
|
|
13372
|
+
}
|
|
13373
|
+
function onInitialization(notify) {
|
|
13374
|
+
initializationSubscribers.add(notify);
|
|
13375
|
+
return () => {
|
|
13376
|
+
initializationSubscribers.delete(notify);
|
|
13377
|
+
};
|
|
13378
|
+
}
|
|
13379
|
+
const trackingLifecycle = {
|
|
13380
|
+
beginInitialization,
|
|
13381
|
+
identify: identify$2,
|
|
13382
|
+
capture,
|
|
13383
|
+
onChange,
|
|
13384
|
+
onInitialization
|
|
13385
|
+
};
|
|
13342
13386
|
function createIdentifyReporter() {
|
|
13343
13387
|
const reported = /* @__PURE__ */ new Set();
|
|
13344
13388
|
return (stage, reason, httpStatus) => {
|
|
@@ -13373,16 +13417,16 @@ function waitForIdentifyReady(report) {
|
|
|
13373
13417
|
if (!active) return;
|
|
13374
13418
|
active = false;
|
|
13375
13419
|
clearTimeout(timer);
|
|
13376
|
-
window.removeEventListener("Tracker Ready",
|
|
13420
|
+
window.removeEventListener("Tracker Ready", onReady2);
|
|
13377
13421
|
if (!ready) report("readiness", "timeout");
|
|
13378
13422
|
resolve(ready);
|
|
13379
13423
|
};
|
|
13380
|
-
const
|
|
13424
|
+
const onReady2 = () => {
|
|
13381
13425
|
if (mixpanelService.isReady()) finish(true);
|
|
13382
13426
|
};
|
|
13383
13427
|
const timer = setTimeout(() => finish(false), 5e3);
|
|
13384
|
-
window.addEventListener("Tracker Ready",
|
|
13385
|
-
|
|
13428
|
+
window.addEventListener("Tracker Ready", onReady2);
|
|
13429
|
+
onReady2();
|
|
13386
13430
|
});
|
|
13387
13431
|
}
|
|
13388
13432
|
function waitForIdentifyStage(stage, timeout, run, report) {
|
|
@@ -13427,28 +13471,63 @@ function observeIdentifyResult(stage, report, onTimeout) {
|
|
|
13427
13471
|
}, 5e3);
|
|
13428
13472
|
return { complete };
|
|
13429
13473
|
}
|
|
13430
|
-
const version = "1.1.8-alpha.
|
|
13474
|
+
const version = "1.1.8-alpha.1";
|
|
13431
13475
|
const MIXPANEL_DISTINCT_ID_CACHE_KEY = "mp_distinct_id";
|
|
13476
|
+
const readinessSubscribers$1 = /* @__PURE__ */ new Set();
|
|
13477
|
+
let initializing = false;
|
|
13478
|
+
let initialization$2 = 0;
|
|
13479
|
+
let initializedConfig;
|
|
13480
|
+
function onReady$1(callback) {
|
|
13481
|
+
readinessSubscribers$1.add(callback);
|
|
13482
|
+
return () => {
|
|
13483
|
+
readinessSubscribers$1.delete(callback);
|
|
13484
|
+
};
|
|
13485
|
+
}
|
|
13432
13486
|
const SDK_SUPER_PROPERTIES = {
|
|
13433
13487
|
"Event Source": "sdk",
|
|
13434
13488
|
"Reservamos Version": version
|
|
13435
13489
|
};
|
|
13436
13490
|
function init$2(mixpanelToken, debug = false, proxyUrl) {
|
|
13491
|
+
validateConfiguration(mixpanelToken, proxyUrl);
|
|
13492
|
+
const attempt = ++initialization$2;
|
|
13493
|
+
initializing = true;
|
|
13494
|
+
trackingLifecycle.beginInitialization();
|
|
13495
|
+
if (initializedConfig && window.mixpanel === mixpanel) {
|
|
13496
|
+
mixpanel.set_config({ debug });
|
|
13497
|
+
initializing = false;
|
|
13498
|
+
readinessSubscribers$1.forEach((notify) => notify());
|
|
13499
|
+
return Promise.resolve();
|
|
13500
|
+
}
|
|
13437
13501
|
return new Promise((resolve) => {
|
|
13438
13502
|
mixpanel.init(mixpanelToken, {
|
|
13439
13503
|
debug,
|
|
13440
13504
|
loaded: () => {
|
|
13505
|
+
if (attempt !== initialization$2) {
|
|
13506
|
+
resolve();
|
|
13507
|
+
return;
|
|
13508
|
+
}
|
|
13441
13509
|
window.mixpanel = mixpanel;
|
|
13442
13510
|
mixpanel.register({ ...SDK_SUPER_PROPERTIES });
|
|
13511
|
+
initializedConfig = { token: mixpanelToken, proxyUrl };
|
|
13512
|
+
initializing = false;
|
|
13513
|
+
readinessSubscribers$1.forEach((notify) => notify());
|
|
13443
13514
|
resolve();
|
|
13444
13515
|
},
|
|
13445
13516
|
...proxyUrl && { api_host: proxyUrl }
|
|
13446
13517
|
});
|
|
13447
13518
|
});
|
|
13448
13519
|
}
|
|
13449
|
-
function
|
|
13450
|
-
mixpanel.
|
|
13451
|
-
|
|
13520
|
+
function validateConfiguration(token, proxyUrl) {
|
|
13521
|
+
if (initializedConfig && window.mixpanel === mixpanel && (initializedConfig.token !== token || initializedConfig.proxyUrl !== proxyUrl)) {
|
|
13522
|
+
throw new Error(
|
|
13523
|
+
"Changing the Mixpanel project or proxy requires a new page session."
|
|
13524
|
+
);
|
|
13525
|
+
}
|
|
13526
|
+
}
|
|
13527
|
+
function identify$1(userId2, properties, report) {
|
|
13528
|
+
trackingLifecycle.identify(userId2);
|
|
13529
|
+
mixpanel.identify(userId2);
|
|
13530
|
+
if (!updateCachedDistinctId(userId2)) report == null ? void 0 : report("cache", "unavailable");
|
|
13452
13531
|
if (!report) {
|
|
13453
13532
|
mixpanel.people.set(properties);
|
|
13454
13533
|
return;
|
|
@@ -13478,7 +13557,7 @@ function setPeopleProperties(properties) {
|
|
|
13478
13557
|
mixpanel.people.set(properties);
|
|
13479
13558
|
}
|
|
13480
13559
|
function isReady() {
|
|
13481
|
-
return window.mixpanel !== void 0;
|
|
13560
|
+
return !initializing && window.mixpanel !== void 0;
|
|
13482
13561
|
}
|
|
13483
13562
|
function track(eventName, properties) {
|
|
13484
13563
|
if (!isReady()) {
|
|
@@ -13509,7 +13588,9 @@ function updateCachedDistinctId(distinctId) {
|
|
|
13509
13588
|
}
|
|
13510
13589
|
const mixpanelService = {
|
|
13511
13590
|
init: init$2,
|
|
13591
|
+
validateConfiguration,
|
|
13512
13592
|
isReady,
|
|
13593
|
+
onReady: onReady$1,
|
|
13513
13594
|
track,
|
|
13514
13595
|
identify: identify$1,
|
|
13515
13596
|
attachProperty,
|
|
@@ -13520,6 +13601,18 @@ const DEFAULT_CACHE_NAME = "default_fingerprint_cache";
|
|
|
13520
13601
|
const DEFAULT_CACHE_TIME_IN_DAYS = 7;
|
|
13521
13602
|
const PROXY_QUERY_PARAM = "apiKey=<apiKey>&version=<version>&loaderVersion=<loaderVersion>";
|
|
13522
13603
|
let fingerprintAgentReady = false;
|
|
13604
|
+
let initialization$1 = 0;
|
|
13605
|
+
const readinessSubscribers = /* @__PURE__ */ new Set();
|
|
13606
|
+
function onReady(notify) {
|
|
13607
|
+
readinessSubscribers.add(notify);
|
|
13608
|
+
return () => {
|
|
13609
|
+
readinessSubscribers.delete(notify);
|
|
13610
|
+
};
|
|
13611
|
+
}
|
|
13612
|
+
function invalidate() {
|
|
13613
|
+
initialization$1++;
|
|
13614
|
+
fingerprintAgentReady = false;
|
|
13615
|
+
}
|
|
13523
13616
|
const getExpirationDate = (cacheTimeInDays) => {
|
|
13524
13617
|
const currentDate = /* @__PURE__ */ new Date();
|
|
13525
13618
|
const futureDate = new Date(
|
|
@@ -13565,7 +13658,8 @@ async function initFingerprint(apiKey, proxyUrl) {
|
|
|
13565
13658
|
customEndpointArray.unshift(proxyUrl);
|
|
13566
13659
|
customScriptEndpointArray.unshift(buildProxyUrl(proxyUrl));
|
|
13567
13660
|
}
|
|
13568
|
-
|
|
13661
|
+
invalidate();
|
|
13662
|
+
const attempt = initialization$1;
|
|
13569
13663
|
window.fingerprintConfig = {};
|
|
13570
13664
|
const client = new FpjsClient({
|
|
13571
13665
|
loadOptions: {
|
|
@@ -13577,19 +13671,20 @@ async function initFingerprint(apiKey, proxyUrl) {
|
|
|
13577
13671
|
window.fpClient = client;
|
|
13578
13672
|
try {
|
|
13579
13673
|
await client.init();
|
|
13580
|
-
if (window.fpClient === client) {
|
|
13674
|
+
if (window.fpClient === client && attempt === initialization$1) {
|
|
13581
13675
|
fingerprintAgentReady = true;
|
|
13676
|
+
readinessSubscribers.forEach((notify) => notify());
|
|
13582
13677
|
}
|
|
13583
13678
|
} catch (error) {
|
|
13584
|
-
if (window.fpClient === client) {
|
|
13679
|
+
if (window.fpClient === client && attempt === initialization$1) {
|
|
13585
13680
|
fingerprintAgentReady = false;
|
|
13586
13681
|
}
|
|
13587
13682
|
console.error("Error initializing identification service:", error);
|
|
13588
13683
|
throw error;
|
|
13589
13684
|
}
|
|
13590
13685
|
}
|
|
13591
|
-
async function getFingerprint(cacheOnly = false) {
|
|
13592
|
-
return readFingerprint(cacheOnly);
|
|
13686
|
+
async function getFingerprint(cacheOnly = false, context) {
|
|
13687
|
+
return readFingerprint(cacheOnly, context);
|
|
13593
13688
|
}
|
|
13594
13689
|
function getFingerprintForIdentify(context) {
|
|
13595
13690
|
return readFingerprint(false, context);
|
|
@@ -13605,8 +13700,8 @@ async function readFingerprint(cacheOnly, context) {
|
|
|
13605
13700
|
const { visitorId } = await requestIdentification(false, context);
|
|
13606
13701
|
return visitorId;
|
|
13607
13702
|
}
|
|
13608
|
-
async function identifyVisitor(ignoreCache = false) {
|
|
13609
|
-
return requestIdentification(ignoreCache);
|
|
13703
|
+
async function identifyVisitor(ignoreCache = false, context) {
|
|
13704
|
+
return requestIdentification(ignoreCache, context);
|
|
13610
13705
|
}
|
|
13611
13706
|
async function requestIdentification(ignoreCache, context) {
|
|
13612
13707
|
if (!isFingerprintReady()) {
|
|
@@ -13617,9 +13712,8 @@ async function requestIdentification(ignoreCache, context) {
|
|
|
13617
13712
|
if (!context || context.isActive()) {
|
|
13618
13713
|
try {
|
|
13619
13714
|
setCachedFingerprint(result.visitorId);
|
|
13620
|
-
} catch
|
|
13621
|
-
|
|
13622
|
-
context.report("cache", "unavailable");
|
|
13715
|
+
} catch {
|
|
13716
|
+
context == null ? void 0 : context.report("cache", "unavailable");
|
|
13623
13717
|
}
|
|
13624
13718
|
if (typeof result.visitorFound === "boolean") {
|
|
13625
13719
|
try {
|
|
@@ -13652,8 +13746,168 @@ const fingerprintService = {
|
|
|
13652
13746
|
getFingerprint,
|
|
13653
13747
|
identifyVisitor,
|
|
13654
13748
|
isFingerprintReady,
|
|
13749
|
+
onReady,
|
|
13750
|
+
invalidate,
|
|
13655
13751
|
getCachedFingerprint
|
|
13656
13752
|
};
|
|
13753
|
+
trackingLifecycle.onInitialization(invalidate);
|
|
13754
|
+
function createPendingWorkQueue(options) {
|
|
13755
|
+
const entries = /* @__PURE__ */ new Set();
|
|
13756
|
+
let bytes = 0;
|
|
13757
|
+
let active = 0;
|
|
13758
|
+
let draining = false;
|
|
13759
|
+
let unsubscribe;
|
|
13760
|
+
let timer;
|
|
13761
|
+
function diagnostic(entry, reason) {
|
|
13762
|
+
console.error("Tracking recovery diagnostic", {
|
|
13763
|
+
eventName: entry.eventName,
|
|
13764
|
+
stage: options.stage,
|
|
13765
|
+
reason
|
|
13766
|
+
});
|
|
13767
|
+
}
|
|
13768
|
+
function resolveForeground(entry) {
|
|
13769
|
+
var _a;
|
|
13770
|
+
(_a = entry.resolve) == null ? void 0 : _a.call(entry);
|
|
13771
|
+
entry.resolve = void 0;
|
|
13772
|
+
}
|
|
13773
|
+
function close(entry, reason) {
|
|
13774
|
+
if (entry.state === "closed") return;
|
|
13775
|
+
entry.state = "closed";
|
|
13776
|
+
entries.delete(entry);
|
|
13777
|
+
bytes -= entry.bytes;
|
|
13778
|
+
resolveForeground(entry);
|
|
13779
|
+
if (reason) diagnostic(entry, reason);
|
|
13780
|
+
}
|
|
13781
|
+
function schedule() {
|
|
13782
|
+
clearTimeout(timer);
|
|
13783
|
+
timer = void 0;
|
|
13784
|
+
if (entries.size === 0) {
|
|
13785
|
+
unsubscribe == null ? void 0 : unsubscribe();
|
|
13786
|
+
unsubscribe = void 0;
|
|
13787
|
+
return;
|
|
13788
|
+
}
|
|
13789
|
+
let next = Infinity;
|
|
13790
|
+
for (const entry of entries) {
|
|
13791
|
+
next = Math.min(next, entry.deadline);
|
|
13792
|
+
if (entry.resolve) next = Math.min(next, entry.foregroundDeadline);
|
|
13793
|
+
}
|
|
13794
|
+
timer = setTimeout(drain, Math.max(0, next - Date.now()));
|
|
13795
|
+
}
|
|
13796
|
+
function drain() {
|
|
13797
|
+
if (draining) return;
|
|
13798
|
+
draining = true;
|
|
13799
|
+
try {
|
|
13800
|
+
for (const entry of entries) {
|
|
13801
|
+
if (!entry.isCurrent()) close(entry, "identity_changed");
|
|
13802
|
+
else if (Date.now() >= entry.deadline) close(entry, "timeout");
|
|
13803
|
+
else if (entry.resolve && Date.now() >= entry.foregroundDeadline) {
|
|
13804
|
+
resolveForeground(entry);
|
|
13805
|
+
}
|
|
13806
|
+
}
|
|
13807
|
+
for (const entry of entries) {
|
|
13808
|
+
if (active >= options.maxActive || !options.isReady()) break;
|
|
13809
|
+
if (entry.state !== "waiting") continue;
|
|
13810
|
+
entry.state = "active";
|
|
13811
|
+
active++;
|
|
13812
|
+
const isActive = () => entry.state === "active" && Date.now() < entry.deadline && entry.isCurrent();
|
|
13813
|
+
const finish = (failed = false) => {
|
|
13814
|
+
if (failed && isActive()) diagnostic(entry, "failed");
|
|
13815
|
+
close(entry);
|
|
13816
|
+
active--;
|
|
13817
|
+
drain();
|
|
13818
|
+
};
|
|
13819
|
+
try {
|
|
13820
|
+
void Promise.resolve(entry.run(isActive)).then(
|
|
13821
|
+
() => finish(),
|
|
13822
|
+
() => finish(true)
|
|
13823
|
+
);
|
|
13824
|
+
} catch {
|
|
13825
|
+
finish(true);
|
|
13826
|
+
}
|
|
13827
|
+
}
|
|
13828
|
+
} finally {
|
|
13829
|
+
draining = false;
|
|
13830
|
+
schedule();
|
|
13831
|
+
}
|
|
13832
|
+
}
|
|
13833
|
+
function enqueue(work) {
|
|
13834
|
+
if (work.bytes > options.maxBytes) {
|
|
13835
|
+
diagnostic(work, "capacity");
|
|
13836
|
+
return Promise.resolve();
|
|
13837
|
+
}
|
|
13838
|
+
while (entries.size >= options.maxEntries || bytes + work.bytes > options.maxBytes) {
|
|
13839
|
+
const oldest = [...entries].find((entry) => entry.state === "waiting");
|
|
13840
|
+
if (!oldest) {
|
|
13841
|
+
diagnostic(work, "capacity");
|
|
13842
|
+
return Promise.resolve();
|
|
13843
|
+
}
|
|
13844
|
+
close(oldest, "capacity");
|
|
13845
|
+
}
|
|
13846
|
+
return new Promise((resolve) => {
|
|
13847
|
+
const entry = {
|
|
13848
|
+
...work,
|
|
13849
|
+
state: "waiting",
|
|
13850
|
+
deadline: Date.now() + options.lifetime,
|
|
13851
|
+
foregroundDeadline: Date.now() + options.wait,
|
|
13852
|
+
resolve
|
|
13853
|
+
};
|
|
13854
|
+
entries.add(entry);
|
|
13855
|
+
bytes += entry.bytes;
|
|
13856
|
+
unsubscribe ?? (unsubscribe = options.subscribe(drain));
|
|
13857
|
+
drain();
|
|
13858
|
+
});
|
|
13859
|
+
}
|
|
13860
|
+
return { enqueue };
|
|
13861
|
+
}
|
|
13862
|
+
const observations = createPendingWorkQueue({
|
|
13863
|
+
isReady: () => fingerprintService.isFingerprintReady(),
|
|
13864
|
+
subscribe(notify) {
|
|
13865
|
+
const stopReady = fingerprintService.onReady(notify);
|
|
13866
|
+
const stopIdentity = trackingLifecycle.onChange(notify);
|
|
13867
|
+
return () => {
|
|
13868
|
+
stopReady();
|
|
13869
|
+
stopIdentity();
|
|
13870
|
+
};
|
|
13871
|
+
},
|
|
13872
|
+
maxEntries: 100,
|
|
13873
|
+
maxBytes: 1024 * 1024,
|
|
13874
|
+
maxActive: 3,
|
|
13875
|
+
lifetime: 1e4,
|
|
13876
|
+
wait: 0,
|
|
13877
|
+
stage: "fingerprint"
|
|
13878
|
+
});
|
|
13879
|
+
function deferBotDetection(eventName, distinctId, isCurrent) {
|
|
13880
|
+
void observations.enqueue({
|
|
13881
|
+
eventName,
|
|
13882
|
+
bytes: new Blob([eventName, distinctId ?? ""]).size,
|
|
13883
|
+
isCurrent,
|
|
13884
|
+
async run(isActive) {
|
|
13885
|
+
let stage = "fingerprint";
|
|
13886
|
+
try {
|
|
13887
|
+
const identification = await fingerprintService.identifyVisitor(true, {
|
|
13888
|
+
isActive,
|
|
13889
|
+
report: () => void 0
|
|
13890
|
+
});
|
|
13891
|
+
if (!isActive() || !identification.requestId) return;
|
|
13892
|
+
stage = "relay";
|
|
13893
|
+
await botDetectionRelayService.relay({
|
|
13894
|
+
requestId: identification.requestId,
|
|
13895
|
+
visitorId: identification.visitorId,
|
|
13896
|
+
...distinctId && { distinctId },
|
|
13897
|
+
eventName
|
|
13898
|
+
});
|
|
13899
|
+
} catch {
|
|
13900
|
+
if (isActive()) {
|
|
13901
|
+
console.error("Bot Detection diagnostic", {
|
|
13902
|
+
eventName,
|
|
13903
|
+
stage,
|
|
13904
|
+
reason: "failed"
|
|
13905
|
+
});
|
|
13906
|
+
}
|
|
13907
|
+
}
|
|
13908
|
+
}
|
|
13909
|
+
});
|
|
13910
|
+
}
|
|
13657
13911
|
let environment;
|
|
13658
13912
|
let appName;
|
|
13659
13913
|
const origin = window.location.origin;
|
|
@@ -13792,7 +14046,7 @@ const tripSchema = z.object({
|
|
|
13792
14046
|
"Departure Origin Terminal": stringField("Departure Origin Terminal"),
|
|
13793
14047
|
"Departure Price": numberField("Departure Price"),
|
|
13794
14048
|
"Departure Route": stringField("Departure Route"),
|
|
13795
|
-
"Departure Stops":
|
|
14049
|
+
"Departure Stops": z.number().int(),
|
|
13796
14050
|
"Departure Time": dateField("Departure Time"),
|
|
13797
14051
|
"Departure Transport Type": stringField("Departure Transport Type"),
|
|
13798
14052
|
"Departure Transporter": stringField("Departure Transporter"),
|
|
@@ -13806,7 +14060,7 @@ const tripSchema = z.object({
|
|
|
13806
14060
|
"Return Origin Terminal": stringField("Return Origin Terminal").optional(),
|
|
13807
14061
|
"Return Price": numberField("Return Price").optional(),
|
|
13808
14062
|
"Return Route": stringField("Return Route").optional(),
|
|
13809
|
-
"Return Stops":
|
|
14063
|
+
"Return Stops": z.number().int().optional(),
|
|
13810
14064
|
"Return Time": dateField("Return Time").optional(),
|
|
13811
14065
|
"Return Transport Type": stringField("Return Transport Type").optional(),
|
|
13812
14066
|
"Return Transporter": stringField("Return Transporter").optional(),
|
|
@@ -14071,6 +14325,7 @@ const validatorService = {
|
|
|
14071
14325
|
parseIdentifyProps,
|
|
14072
14326
|
validateProps
|
|
14073
14327
|
};
|
|
14328
|
+
let initialization = 0;
|
|
14074
14329
|
function onLoaded() {
|
|
14075
14330
|
window.dispatchEvent(new CustomEvent("Tracker Ready"));
|
|
14076
14331
|
}
|
|
@@ -14085,19 +14340,30 @@ async function init$1(config) {
|
|
|
14085
14340
|
identifyProxyUrl,
|
|
14086
14341
|
appName: appName2
|
|
14087
14342
|
} = config;
|
|
14343
|
+
mixpanelService.validateConfiguration(mixpanelToken, mixpanelProxyUrl);
|
|
14344
|
+
const attempt = ++initialization;
|
|
14345
|
+
const isCurrent = () => attempt === initialization;
|
|
14088
14346
|
await mixpanelService.init(mixpanelToken, debug, mixpanelProxyUrl);
|
|
14347
|
+
if (!isCurrent()) return;
|
|
14089
14348
|
configService.setEnvironment(isSandbox ? "sandbox" : "prod");
|
|
14090
14349
|
if (appName2) {
|
|
14091
14350
|
configService.setAppName(appName2);
|
|
14092
14351
|
}
|
|
14093
14352
|
a$1.setConfig(configService.getCoreAPIConfig());
|
|
14094
14353
|
onLoaded();
|
|
14354
|
+
if (!isCurrent()) return;
|
|
14095
14355
|
await Promise.all([
|
|
14096
14356
|
initializeOptionalStage(
|
|
14097
14357
|
"fingerprint",
|
|
14098
|
-
() => fingerprintService.initFingerprint(
|
|
14358
|
+
() => isCurrent() ? fingerprintService.initFingerprint(
|
|
14359
|
+
identificationKey,
|
|
14360
|
+
identifyProxyUrl
|
|
14361
|
+
) : Promise.resolve()
|
|
14099
14362
|
),
|
|
14100
|
-
initializeOptionalStage(
|
|
14363
|
+
initializeOptionalStage(
|
|
14364
|
+
"geolocation",
|
|
14365
|
+
() => isCurrent() ? geolocationService.init() : Promise.resolve()
|
|
14366
|
+
)
|
|
14101
14367
|
]);
|
|
14102
14368
|
}
|
|
14103
14369
|
function initializeOptionalStage(stage, initialize) {
|
|
@@ -14323,6 +14589,20 @@ const geolocationService = {
|
|
|
14323
14589
|
getCoordinates,
|
|
14324
14590
|
getGeolocationSource
|
|
14325
14591
|
};
|
|
14592
|
+
function snapshotEventData(value) {
|
|
14593
|
+
if (Array.isArray(value))
|
|
14594
|
+
return value.map((item) => snapshotEventData(item));
|
|
14595
|
+
if (value instanceof Date) return new Date(value.getTime());
|
|
14596
|
+
if (value !== null && typeof value === "object") {
|
|
14597
|
+
return Object.fromEntries(
|
|
14598
|
+
Object.entries(value).map(([key, item]) => [
|
|
14599
|
+
key,
|
|
14600
|
+
snapshotEventData(item)
|
|
14601
|
+
])
|
|
14602
|
+
);
|
|
14603
|
+
}
|
|
14604
|
+
return value;
|
|
14605
|
+
}
|
|
14326
14606
|
const FP_TRIGGER_EVENTS = ["Search", "View Results"];
|
|
14327
14607
|
const EXTRA_UTM_FIELDS = {
|
|
14328
14608
|
utm_brand: "UTM Brand",
|
|
@@ -14377,15 +14657,17 @@ async function tryTrackEvent(trackEventCallback, eventName = "Track Event Error"
|
|
|
14377
14657
|
const ready = await new Promise((resolve) => {
|
|
14378
14658
|
const finish = (isReady2) => {
|
|
14379
14659
|
clearTimeout(timer);
|
|
14380
|
-
window.removeEventListener("Tracker Ready",
|
|
14660
|
+
window.removeEventListener("Tracker Ready", onReady2);
|
|
14661
|
+
unsubscribe();
|
|
14381
14662
|
resolve(isReady2);
|
|
14382
14663
|
};
|
|
14383
|
-
const
|
|
14664
|
+
const onReady2 = () => {
|
|
14384
14665
|
if (mixpanelService.isReady()) finish(true);
|
|
14385
14666
|
};
|
|
14386
14667
|
const timer = setTimeout(() => finish(mixpanelService.isReady()), 5e3);
|
|
14387
|
-
|
|
14388
|
-
|
|
14668
|
+
const unsubscribe = mixpanelService.onReady(onReady2);
|
|
14669
|
+
window.addEventListener("Tracker Ready", onReady2);
|
|
14670
|
+
onReady2();
|
|
14389
14671
|
});
|
|
14390
14672
|
if (!ready) {
|
|
14391
14673
|
console.error("Tracking diagnostic", {
|
|
@@ -14406,28 +14688,94 @@ async function tryTrackEvent(trackEventCallback, eventName = "Track Event Error"
|
|
|
14406
14688
|
});
|
|
14407
14689
|
}
|
|
14408
14690
|
}
|
|
14691
|
+
const pendingEvents = createPendingWorkQueue({
|
|
14692
|
+
isReady: () => mixpanelService.isReady(),
|
|
14693
|
+
subscribe(notify) {
|
|
14694
|
+
const stopReady = mixpanelService.onReady(notify);
|
|
14695
|
+
const stopIdentity = trackingLifecycle.onChange(notify);
|
|
14696
|
+
window.addEventListener("Tracker Ready", notify);
|
|
14697
|
+
return () => {
|
|
14698
|
+
stopReady();
|
|
14699
|
+
stopIdentity();
|
|
14700
|
+
window.removeEventListener("Tracker Ready", notify);
|
|
14701
|
+
};
|
|
14702
|
+
},
|
|
14703
|
+
maxEntries: 100,
|
|
14704
|
+
maxBytes: 1024 * 1024,
|
|
14705
|
+
maxActive: 100,
|
|
14706
|
+
lifetime: 6e4,
|
|
14707
|
+
wait: 5e3,
|
|
14708
|
+
stage: "readiness"
|
|
14709
|
+
});
|
|
14409
14710
|
function trackEvent(eventName, eventProperties, meta = {}) {
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14711
|
+
const isCurrent = trackingLifecycle.capture();
|
|
14712
|
+
const trackingParams = extractTrackingParams();
|
|
14713
|
+
if (mixpanelService.isReady()) {
|
|
14714
|
+
return submitEvent(
|
|
14715
|
+
eventName,
|
|
14716
|
+
eventProperties,
|
|
14717
|
+
meta,
|
|
14718
|
+
isCurrent,
|
|
14719
|
+
trackingParams
|
|
14720
|
+
);
|
|
14721
|
+
}
|
|
14722
|
+
try {
|
|
14723
|
+
validatorService.parseEventProps(eventName, eventProperties);
|
|
14724
|
+
} catch (error) {
|
|
14725
|
+
trackEventError(eventName, error, eventProperties);
|
|
14726
|
+
return Promise.resolve();
|
|
14727
|
+
}
|
|
14728
|
+
let snapshot2;
|
|
14729
|
+
let bytes;
|
|
14730
|
+
try {
|
|
14731
|
+
const serialized = JSON.stringify(
|
|
14732
|
+
{ eventName, eventProperties, meta, trackingParams },
|
|
14733
|
+
(_key, value) => {
|
|
14734
|
+
if (typeof value === "function" || typeof value === "symbol")
|
|
14735
|
+
throw new Error();
|
|
14736
|
+
return value === void 0 ? null : value;
|
|
14737
|
+
}
|
|
14738
|
+
);
|
|
14739
|
+
bytes = new Blob([serialized]).size;
|
|
14740
|
+
if (bytes > 1024 * 1024) throw new Error();
|
|
14741
|
+
snapshot2 = snapshotEventData({ eventProperties, meta });
|
|
14742
|
+
} catch {
|
|
14743
|
+
console.error("Tracking recovery diagnostic", {
|
|
14744
|
+
eventName,
|
|
14745
|
+
stage: "readiness",
|
|
14746
|
+
reason: "snapshot_unavailable"
|
|
14747
|
+
});
|
|
14748
|
+
return Promise.resolve();
|
|
14749
|
+
}
|
|
14750
|
+
return pendingEvents.enqueue({
|
|
14751
|
+
eventName,
|
|
14752
|
+
bytes,
|
|
14753
|
+
isCurrent,
|
|
14754
|
+
run: (isActive) => submitEvent(
|
|
14755
|
+
eventName,
|
|
14756
|
+
snapshot2.eventProperties,
|
|
14757
|
+
snapshot2.meta,
|
|
14758
|
+
isActive,
|
|
14759
|
+
trackingParams
|
|
14760
|
+
)
|
|
14761
|
+
});
|
|
14414
14762
|
}
|
|
14415
|
-
async function submitEvent(eventName, eventProperties, meta) {
|
|
14763
|
+
async function submitEvent(eventName, eventProperties, meta, isCurrent, trackingParams) {
|
|
14764
|
+
const observationContext = trackingLifecycle.capture();
|
|
14416
14765
|
try {
|
|
14417
14766
|
validatorService.parseEventProps(eventName, eventProperties);
|
|
14418
14767
|
const distinctId = mixpanelService.getMixpanelDistinctId();
|
|
14419
14768
|
const botDetectionEnabled = botDetectionRelayService.isEnabledFor(eventName);
|
|
14420
14769
|
let fingerprint = "";
|
|
14421
|
-
if (botDetectionEnabled) {
|
|
14770
|
+
if (botDetectionEnabled || FP_TRIGGER_EVENTS.includes(eventName)) {
|
|
14422
14771
|
try {
|
|
14423
14772
|
fingerprint = fingerprintService.getCachedFingerprint() ?? "";
|
|
14424
14773
|
} catch (error) {
|
|
14425
14774
|
console.error("Error reading cached fingerprint:", error);
|
|
14426
14775
|
}
|
|
14427
14776
|
} else {
|
|
14428
|
-
const cacheOnly = !FP_TRIGGER_EVENTS.includes(eventName);
|
|
14429
14777
|
try {
|
|
14430
|
-
fingerprint = await fingerprintService.getFingerprint(
|
|
14778
|
+
fingerprint = await fingerprintService.getFingerprint(true);
|
|
14431
14779
|
} catch {
|
|
14432
14780
|
console.error("Tracking diagnostic", {
|
|
14433
14781
|
eventName,
|
|
@@ -14449,7 +14797,6 @@ async function submitEvent(eventName, eventProperties, meta) {
|
|
|
14449
14797
|
const defaultProperties = {
|
|
14450
14798
|
"User Fingerprint": fingerprint
|
|
14451
14799
|
};
|
|
14452
|
-
const trackingParams = extractTrackingParams();
|
|
14453
14800
|
const simplifiedData = flattenEventData(eventProperties);
|
|
14454
14801
|
const properties = {
|
|
14455
14802
|
...defaultProperties,
|
|
@@ -14458,28 +14805,40 @@ async function submitEvent(eventName, eventProperties, meta) {
|
|
|
14458
14805
|
...defaultCoordinates,
|
|
14459
14806
|
...meta
|
|
14460
14807
|
};
|
|
14461
|
-
|
|
14808
|
+
if (!isCurrent()) return;
|
|
14809
|
+
try {
|
|
14810
|
+
mixpanelService.track(eventName, properties);
|
|
14811
|
+
} catch {
|
|
14812
|
+
console.error("Tracking diagnostic", {
|
|
14813
|
+
eventName,
|
|
14814
|
+
stage: "submission",
|
|
14815
|
+
reason: "uncertain"
|
|
14816
|
+
});
|
|
14817
|
+
return;
|
|
14818
|
+
}
|
|
14462
14819
|
if (botDetectionEnabled) {
|
|
14463
|
-
|
|
14820
|
+
deferBotDetection(eventName, distinctId, observationContext);
|
|
14821
|
+
} else if (FP_TRIGGER_EVENTS.includes(eventName)) {
|
|
14822
|
+
void refreshFingerprint(eventName, observationContext);
|
|
14464
14823
|
}
|
|
14465
14824
|
} catch (error) {
|
|
14466
14825
|
console.error(`Error tracking event '${eventName}':`, error);
|
|
14467
14826
|
trackEventError(eventName, error, eventProperties);
|
|
14468
14827
|
}
|
|
14469
14828
|
}
|
|
14470
|
-
async function
|
|
14829
|
+
async function refreshFingerprint(eventName, isCurrent) {
|
|
14830
|
+
const deadline = Date.now() + 1e4;
|
|
14471
14831
|
try {
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
|
|
14832
|
+
await fingerprintService.getFingerprint(false, {
|
|
14833
|
+
isActive: () => isCurrent() && Date.now() < deadline,
|
|
14834
|
+
report: () => void 0
|
|
14835
|
+
});
|
|
14836
|
+
} catch {
|
|
14837
|
+
console.error("Tracking diagnostic", {
|
|
14838
|
+
eventName,
|
|
14839
|
+
stage: "fingerprint",
|
|
14840
|
+
reason: "failed"
|
|
14480
14841
|
});
|
|
14481
|
-
} catch (error) {
|
|
14482
|
-
console.error(`Error running Bot Detection for '${eventName}':`, error);
|
|
14483
14842
|
}
|
|
14484
14843
|
}
|
|
14485
14844
|
function extractTrackingParams() {
|
|
@@ -14616,7 +14975,7 @@ function mapProperties(properties) {
|
|
|
14616
14975
|
);
|
|
14617
14976
|
return { ...parsedProperties, ...additionalProperties };
|
|
14618
14977
|
}
|
|
14619
|
-
const identifyWithLocation = async (
|
|
14978
|
+
const identifyWithLocation = async (userId2, properties, report) => {
|
|
14620
14979
|
var _a, _b, _c;
|
|
14621
14980
|
let observer;
|
|
14622
14981
|
try {
|
|
@@ -14653,7 +15012,7 @@ const identifyWithLocation = async (userId, properties, report) => {
|
|
|
14653
15012
|
body: JSON.stringify({
|
|
14654
15013
|
profile_params: {
|
|
14655
15014
|
...properties,
|
|
14656
|
-
distinct_id:
|
|
15015
|
+
distinct_id: userId2
|
|
14657
15016
|
}
|
|
14658
15017
|
})
|
|
14659
15018
|
}
|
|
@@ -14667,13 +15026,13 @@ const identifyWithLocation = async (userId, properties, report) => {
|
|
|
14667
15026
|
else report("datalake", "failed");
|
|
14668
15027
|
}
|
|
14669
15028
|
};
|
|
14670
|
-
async function identify(
|
|
15029
|
+
async function identify(userId2, properties = {}) {
|
|
14671
15030
|
const report = createIdentifyReporter();
|
|
14672
15031
|
if (!await waitForIdentifyReady(report)) return;
|
|
14673
15032
|
try {
|
|
14674
15033
|
try {
|
|
14675
15034
|
validatorService.parseIdentifyProps(properties);
|
|
14676
|
-
if (!
|
|
15035
|
+
if (!userId2) {
|
|
14677
15036
|
report("validation", "invalid_input");
|
|
14678
15037
|
return;
|
|
14679
15038
|
}
|
|
@@ -14692,7 +15051,7 @@ async function identify(userId, properties = {}) {
|
|
|
14692
15051
|
}
|
|
14693
15052
|
const mappedProps = mapProperties(properties);
|
|
14694
15053
|
try {
|
|
14695
|
-
mixpanelService.identify(
|
|
15054
|
+
mixpanelService.identify(userId2, mappedProps, report);
|
|
14696
15055
|
} catch {
|
|
14697
15056
|
report("mixpanel", "failed");
|
|
14698
15057
|
}
|
|
@@ -14712,7 +15071,7 @@ async function identify(userId, properties = {}) {
|
|
|
14712
15071
|
} catch {
|
|
14713
15072
|
report("mixpanel", "failed");
|
|
14714
15073
|
} finally {
|
|
14715
|
-
void identifyWithLocation(
|
|
15074
|
+
void identifyWithLocation(userId2, properties, report);
|
|
14716
15075
|
}
|
|
14717
15076
|
}
|
|
14718
15077
|
z.object({
|