@reservamos/browser-analytics 1.1.7 → 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.
@@ -11260,9 +11260,9 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function(dat
11260
11260
  if (deviceId) {
11261
11261
  reqParams["$device_id"] = deviceId;
11262
11262
  }
11263
- var userId = this._mixpanel.get_property("$user_id");
11264
- if (userId) {
11265
- reqParams["$user_id"] = userId;
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", onReady);
13420
+ window.removeEventListener("Tracker Ready", onReady2);
13377
13421
  if (!ready) report("readiness", "timeout");
13378
13422
  resolve(ready);
13379
13423
  };
13380
- const onReady = () => {
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", onReady);
13385
- onReady();
13428
+ window.addEventListener("Tracker Ready", onReady2);
13429
+ onReady2();
13386
13430
  });
13387
13431
  }
13388
13432
  function waitForIdentifyStage(stage, timeout, run, report) {
@@ -13427,32 +13471,63 @@ function observeIdentifyResult(stage, report, onTimeout) {
13427
13471
  }, 5e3);
13428
13472
  return { complete };
13429
13473
  }
13430
- const version = "1.1.7";
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 identify$1(userId, properties, report) {
13450
- mixpanel.identify(userId);
13451
- try {
13452
- updateCachedDistinctId(userId);
13453
- } catch {
13454
- report == null ? void 0 : report("cache", "unavailable");
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
+ );
13455
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");
13456
13531
  if (!report) {
13457
13532
  mixpanel.people.set(properties);
13458
13533
  return;
@@ -13482,7 +13557,7 @@ function setPeopleProperties(properties) {
13482
13557
  mixpanel.people.set(properties);
13483
13558
  }
13484
13559
  function isReady() {
13485
- return window.mixpanel !== void 0;
13560
+ return !initializing && window.mixpanel !== void 0;
13486
13561
  }
13487
13562
  function track(eventName, properties) {
13488
13563
  if (!isReady()) {
@@ -13491,22 +13566,31 @@ function track(eventName, properties) {
13491
13566
  mixpanel.track(eventName, { ...properties, "Reservamos Version": version });
13492
13567
  }
13493
13568
  const getMixpanelDistinctId = () => {
13494
- const cachedId = localStorage.getItem(MIXPANEL_DISTINCT_ID_CACHE_KEY);
13495
- if (mixpanel && mixpanel.get_distinct_id) {
13496
- const distinctId = mixpanel.get_distinct_id();
13569
+ var _a;
13570
+ const distinctId = (_a = mixpanel == null ? void 0 : mixpanel.get_distinct_id) == null ? void 0 : _a.call(mixpanel);
13571
+ if (distinctId) {
13497
13572
  updateCachedDistinctId(distinctId);
13498
13573
  return distinctId;
13499
- } else if (cachedId) {
13500
- return cachedId;
13501
13574
  }
13502
- return null;
13575
+ try {
13576
+ return localStorage.getItem(MIXPANEL_DISTINCT_ID_CACHE_KEY);
13577
+ } catch {
13578
+ return null;
13579
+ }
13503
13580
  };
13504
13581
  function updateCachedDistinctId(distinctId) {
13505
- localStorage.setItem(MIXPANEL_DISTINCT_ID_CACHE_KEY, distinctId);
13582
+ try {
13583
+ localStorage.setItem(MIXPANEL_DISTINCT_ID_CACHE_KEY, distinctId);
13584
+ return true;
13585
+ } catch {
13586
+ return false;
13587
+ }
13506
13588
  }
13507
13589
  const mixpanelService = {
13508
13590
  init: init$2,
13591
+ validateConfiguration,
13509
13592
  isReady,
13593
+ onReady: onReady$1,
13510
13594
  track,
13511
13595
  identify: identify$1,
13512
13596
  attachProperty,
@@ -13517,6 +13601,18 @@ const DEFAULT_CACHE_NAME = "default_fingerprint_cache";
13517
13601
  const DEFAULT_CACHE_TIME_IN_DAYS = 7;
13518
13602
  const PROXY_QUERY_PARAM = "apiKey=<apiKey>&version=<version>&loaderVersion=<loaderVersion>";
13519
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
+ }
13520
13616
  const getExpirationDate = (cacheTimeInDays) => {
13521
13617
  const currentDate = /* @__PURE__ */ new Date();
13522
13618
  const futureDate = new Date(
@@ -13528,8 +13624,8 @@ const getCachedFingerprint = () => {
13528
13624
  return readCachedFingerprint();
13529
13625
  };
13530
13626
  function readCachedFingerprint(context) {
13531
- const { cacheName = DEFAULT_CACHE_NAME } = window.fingerprintConfig;
13532
13627
  try {
13628
+ const { cacheName = DEFAULT_CACHE_NAME } = window.fingerprintConfig ?? {};
13533
13629
  const cachedData = JSON.parse(localStorage.getItem(cacheName) || "null");
13534
13630
  if (cachedData && cachedData.expiresAt > Date.now()) {
13535
13631
  return cachedData.fingerprint;
@@ -13562,7 +13658,8 @@ async function initFingerprint(apiKey, proxyUrl) {
13562
13658
  customEndpointArray.unshift(proxyUrl);
13563
13659
  customScriptEndpointArray.unshift(buildProxyUrl(proxyUrl));
13564
13660
  }
13565
- fingerprintAgentReady = false;
13661
+ invalidate();
13662
+ const attempt = initialization$1;
13566
13663
  window.fingerprintConfig = {};
13567
13664
  const client = new FpjsClient({
13568
13665
  loadOptions: {
@@ -13574,42 +13671,37 @@ async function initFingerprint(apiKey, proxyUrl) {
13574
13671
  window.fpClient = client;
13575
13672
  try {
13576
13673
  await client.init();
13577
- if (window.fpClient === client) {
13674
+ if (window.fpClient === client && attempt === initialization$1) {
13578
13675
  fingerprintAgentReady = true;
13676
+ readinessSubscribers.forEach((notify) => notify());
13579
13677
  }
13580
13678
  } catch (error) {
13581
- if (window.fpClient === client) {
13679
+ if (window.fpClient === client && attempt === initialization$1) {
13582
13680
  fingerprintAgentReady = false;
13583
13681
  }
13584
13682
  console.error("Error initializing identification service:", error);
13585
13683
  throw error;
13586
13684
  }
13587
13685
  }
13588
- async function getFingerprint(cacheOnly = false) {
13589
- return readFingerprint(cacheOnly);
13686
+ async function getFingerprint(cacheOnly = false, context) {
13687
+ return readFingerprint(cacheOnly, context);
13590
13688
  }
13591
13689
  function getFingerprintForIdentify(context) {
13592
13690
  return readFingerprint(false, context);
13593
13691
  }
13594
13692
  async function readFingerprint(cacheOnly, context) {
13595
- if (!window.fingerprintConfig) {
13596
- if (cacheOnly) {
13597
- return "";
13598
- }
13599
- throw new Error("Fingerprint configuration is not initialized.");
13600
- }
13601
13693
  const cachedFingerprint = readCachedFingerprint(context);
13602
13694
  if (cachedFingerprint) {
13603
13695
  return cachedFingerprint;
13604
13696
  }
13605
- if (cacheOnly || !isFingerprintReady()) {
13697
+ if (cacheOnly || !window.fingerprintConfig || !isFingerprintReady()) {
13606
13698
  return "";
13607
13699
  }
13608
13700
  const { visitorId } = await requestIdentification(false, context);
13609
13701
  return visitorId;
13610
13702
  }
13611
- async function identifyVisitor(ignoreCache = false) {
13612
- return requestIdentification(ignoreCache);
13703
+ async function identifyVisitor(ignoreCache = false, context) {
13704
+ return requestIdentification(ignoreCache, context);
13613
13705
  }
13614
13706
  async function requestIdentification(ignoreCache, context) {
13615
13707
  if (!isFingerprintReady()) {
@@ -13620,9 +13712,8 @@ async function requestIdentification(ignoreCache, context) {
13620
13712
  if (!context || context.isActive()) {
13621
13713
  try {
13622
13714
  setCachedFingerprint(result.visitorId);
13623
- } catch (error) {
13624
- if (!context) throw error;
13625
- context.report("cache", "unavailable");
13715
+ } catch {
13716
+ context == null ? void 0 : context.report("cache", "unavailable");
13626
13717
  }
13627
13718
  if (typeof result.visitorFound === "boolean") {
13628
13719
  try {
@@ -13655,8 +13746,168 @@ const fingerprintService = {
13655
13746
  getFingerprint,
13656
13747
  identifyVisitor,
13657
13748
  isFingerprintReady,
13749
+ onReady,
13750
+ invalidate,
13658
13751
  getCachedFingerprint
13659
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
+ }
13660
13911
  let environment;
13661
13912
  let appName;
13662
13913
  const origin = window.location.origin;
@@ -13795,7 +14046,7 @@ const tripSchema = z.object({
13795
14046
  "Departure Origin Terminal": stringField("Departure Origin Terminal"),
13796
14047
  "Departure Price": numberField("Departure Price"),
13797
14048
  "Departure Route": stringField("Departure Route"),
13798
- "Departure Stops": intField("Departure Stops"),
14049
+ "Departure Stops": z.number().int(),
13799
14050
  "Departure Time": dateField("Departure Time"),
13800
14051
  "Departure Transport Type": stringField("Departure Transport Type"),
13801
14052
  "Departure Transporter": stringField("Departure Transporter"),
@@ -13809,7 +14060,7 @@ const tripSchema = z.object({
13809
14060
  "Return Origin Terminal": stringField("Return Origin Terminal").optional(),
13810
14061
  "Return Price": numberField("Return Price").optional(),
13811
14062
  "Return Route": stringField("Return Route").optional(),
13812
- "Return Stops": intField("Return Stops").optional(),
14063
+ "Return Stops": z.number().int().optional(),
13813
14064
  "Return Time": dateField("Return Time").optional(),
13814
14065
  "Return Transport Type": stringField("Return Transport Type").optional(),
13815
14066
  "Return Transporter": stringField("Return Transporter").optional(),
@@ -14074,6 +14325,7 @@ const validatorService = {
14074
14325
  parseIdentifyProps,
14075
14326
  validateProps
14076
14327
  };
14328
+ let initialization = 0;
14077
14329
  function onLoaded() {
14078
14330
  window.dispatchEvent(new CustomEvent("Tracker Ready"));
14079
14331
  }
@@ -14088,22 +14340,49 @@ async function init$1(config) {
14088
14340
  identifyProxyUrl,
14089
14341
  appName: appName2
14090
14342
  } = config;
14343
+ mixpanelService.validateConfiguration(mixpanelToken, mixpanelProxyUrl);
14344
+ const attempt = ++initialization;
14345
+ const isCurrent = () => attempt === initialization;
14091
14346
  await mixpanelService.init(mixpanelToken, debug, mixpanelProxyUrl);
14092
- try {
14093
- await fingerprintService.initFingerprint(
14094
- identificationKey,
14095
- identifyProxyUrl
14096
- );
14097
- } catch (error) {
14098
- console.error("Error initializing identification service:", error);
14099
- }
14100
- await geolocationService.init();
14347
+ if (!isCurrent()) return;
14101
14348
  configService.setEnvironment(isSandbox ? "sandbox" : "prod");
14102
14349
  if (appName2) {
14103
14350
  configService.setAppName(appName2);
14104
14351
  }
14105
14352
  a$1.setConfig(configService.getCoreAPIConfig());
14106
14353
  onLoaded();
14354
+ if (!isCurrent()) return;
14355
+ await Promise.all([
14356
+ initializeOptionalStage(
14357
+ "fingerprint",
14358
+ () => isCurrent() ? fingerprintService.initFingerprint(
14359
+ identificationKey,
14360
+ identifyProxyUrl
14361
+ ) : Promise.resolve()
14362
+ ),
14363
+ initializeOptionalStage(
14364
+ "geolocation",
14365
+ () => isCurrent() ? geolocationService.init() : Promise.resolve()
14366
+ )
14367
+ ]);
14368
+ }
14369
+ function initializeOptionalStage(stage, initialize) {
14370
+ return new Promise((resolve) => {
14371
+ let active = true;
14372
+ const finish = (reason) => {
14373
+ if (!active) return;
14374
+ active = false;
14375
+ clearTimeout(timer);
14376
+ if (reason)
14377
+ console.error("SDK initialization diagnostic", { stage, reason });
14378
+ resolve();
14379
+ };
14380
+ const timer = setTimeout(() => finish("timeout"), 3e3);
14381
+ void Promise.resolve().then(initialize).then(
14382
+ () => finish(),
14383
+ () => finish("failed")
14384
+ );
14385
+ });
14107
14386
  }
14108
14387
  function isTrackerReady() {
14109
14388
  return mixpanelService.isReady();
@@ -14310,6 +14589,20 @@ const geolocationService = {
14310
14589
  getCoordinates,
14311
14590
  getGeolocationSource
14312
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
+ }
14313
14606
  const FP_TRIGGER_EVENTS = ["Search", "View Results"];
14314
14607
  const EXTRA_UTM_FIELDS = {
14315
14608
  utm_brand: "UTM Brand",
@@ -14359,32 +14652,137 @@ function trackEventError(eventName, error, payload) {
14359
14652
  }
14360
14653
  });
14361
14654
  }
14362
- async function tryTrackEvent(trackEventCallback) {
14363
- if (mixpanelService.isReady()) {
14655
+ async function tryTrackEvent(trackEventCallback, eventName = "Track Event Error") {
14656
+ if (!mixpanelService.isReady()) {
14657
+ const ready = await new Promise((resolve) => {
14658
+ const finish = (isReady2) => {
14659
+ clearTimeout(timer);
14660
+ window.removeEventListener("Tracker Ready", onReady2);
14661
+ unsubscribe();
14662
+ resolve(isReady2);
14663
+ };
14664
+ const onReady2 = () => {
14665
+ if (mixpanelService.isReady()) finish(true);
14666
+ };
14667
+ const timer = setTimeout(() => finish(mixpanelService.isReady()), 5e3);
14668
+ const unsubscribe = mixpanelService.onReady(onReady2);
14669
+ window.addEventListener("Tracker Ready", onReady2);
14670
+ onReady2();
14671
+ });
14672
+ if (!ready) {
14673
+ console.error("Tracking diagnostic", {
14674
+ eventName,
14675
+ stage: "readiness",
14676
+ reason: "timeout"
14677
+ });
14678
+ return;
14679
+ }
14680
+ }
14681
+ try {
14364
14682
  await trackEventCallback();
14365
- } else {
14366
- window.addEventListener("Tracker Ready", async () => {
14367
- await trackEventCallback();
14683
+ } catch {
14684
+ console.error("Tracking diagnostic", {
14685
+ eventName,
14686
+ stage: "submission",
14687
+ reason: "failed"
14368
14688
  });
14369
14689
  }
14370
14690
  }
14371
- async function trackEvent(eventName, eventProperties, meta = {}) {
14372
- if (!mixpanelService.isReady()) {
14373
- throw new Error("Mixpanel is not initialized.");
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
+ });
14710
+ function trackEvent(eventName, eventProperties, meta = {}) {
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
+ );
14374
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
+ });
14762
+ }
14763
+ async function submitEvent(eventName, eventProperties, meta, isCurrent, trackingParams) {
14764
+ const observationContext = trackingLifecycle.capture();
14375
14765
  try {
14376
14766
  validatorService.parseEventProps(eventName, eventProperties);
14377
14767
  const distinctId = mixpanelService.getMixpanelDistinctId();
14378
14768
  const botDetectionEnabled = botDetectionRelayService.isEnabledFor(eventName);
14379
- let fingerprint;
14380
- let fingerprintRequestId;
14381
- if (botDetectionEnabled && fingerprintService.isFingerprintReady()) {
14382
- const identification = await fingerprintService.identifyVisitor(true);
14383
- fingerprint = identification.visitorId;
14384
- fingerprintRequestId = identification.requestId;
14769
+ let fingerprint = "";
14770
+ if (botDetectionEnabled || FP_TRIGGER_EVENTS.includes(eventName)) {
14771
+ try {
14772
+ fingerprint = fingerprintService.getCachedFingerprint() ?? "";
14773
+ } catch (error) {
14774
+ console.error("Error reading cached fingerprint:", error);
14775
+ }
14385
14776
  } else {
14386
- const cacheOnly = !FP_TRIGGER_EVENTS.includes(eventName);
14387
- fingerprint = await fingerprintService.getFingerprint(cacheOnly);
14777
+ try {
14778
+ fingerprint = await fingerprintService.getFingerprint(true);
14779
+ } catch {
14780
+ console.error("Tracking diagnostic", {
14781
+ eventName,
14782
+ stage: "fingerprint",
14783
+ reason: "failed"
14784
+ });
14785
+ }
14388
14786
  }
14389
14787
  const defaultCoordinates = {};
14390
14788
  const coordinates = geolocationService.getCoordinates();
@@ -14399,7 +14797,6 @@ async function trackEvent(eventName, eventProperties, meta = {}) {
14399
14797
  const defaultProperties = {
14400
14798
  "User Fingerprint": fingerprint
14401
14799
  };
14402
- const trackingParams = extractTrackingParams();
14403
14800
  const simplifiedData = flattenEventData(eventProperties);
14404
14801
  const properties = {
14405
14802
  ...defaultProperties,
@@ -14408,20 +14805,42 @@ async function trackEvent(eventName, eventProperties, meta = {}) {
14408
14805
  ...defaultCoordinates,
14409
14806
  ...meta
14410
14807
  };
14411
- mixpanelService.track(eventName, properties);
14412
- if (fingerprintRequestId) {
14413
- void botDetectionRelayService.relay({
14414
- requestId: fingerprintRequestId,
14415
- visitorId: fingerprint,
14416
- ...distinctId && { distinctId },
14417
- eventName
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"
14418
14816
  });
14817
+ return;
14818
+ }
14819
+ if (botDetectionEnabled) {
14820
+ deferBotDetection(eventName, distinctId, observationContext);
14821
+ } else if (FP_TRIGGER_EVENTS.includes(eventName)) {
14822
+ void refreshFingerprint(eventName, observationContext);
14419
14823
  }
14420
14824
  } catch (error) {
14421
14825
  console.error(`Error tracking event '${eventName}':`, error);
14422
14826
  trackEventError(eventName, error, eventProperties);
14423
14827
  }
14424
14828
  }
14829
+ async function refreshFingerprint(eventName, isCurrent) {
14830
+ const deadline = Date.now() + 1e4;
14831
+ try {
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"
14841
+ });
14842
+ }
14843
+ }
14425
14844
  function extractTrackingParams() {
14426
14845
  try {
14427
14846
  const urlParams = new URLSearchParams(window.location.search);
@@ -14556,7 +14975,7 @@ function mapProperties(properties) {
14556
14975
  );
14557
14976
  return { ...parsedProperties, ...additionalProperties };
14558
14977
  }
14559
- const identifyWithLocation = async (userId, properties, report) => {
14978
+ const identifyWithLocation = async (userId2, properties, report) => {
14560
14979
  var _a, _b, _c;
14561
14980
  let observer;
14562
14981
  try {
@@ -14593,7 +15012,7 @@ const identifyWithLocation = async (userId, properties, report) => {
14593
15012
  body: JSON.stringify({
14594
15013
  profile_params: {
14595
15014
  ...properties,
14596
- distinct_id: userId
15015
+ distinct_id: userId2
14597
15016
  }
14598
15017
  })
14599
15018
  }
@@ -14607,13 +15026,13 @@ const identifyWithLocation = async (userId, properties, report) => {
14607
15026
  else report("datalake", "failed");
14608
15027
  }
14609
15028
  };
14610
- async function identify(userId, properties = {}) {
15029
+ async function identify(userId2, properties = {}) {
14611
15030
  const report = createIdentifyReporter();
14612
15031
  if (!await waitForIdentifyReady(report)) return;
14613
15032
  try {
14614
15033
  try {
14615
15034
  validatorService.parseIdentifyProps(properties);
14616
- if (!userId) {
15035
+ if (!userId2) {
14617
15036
  report("validation", "invalid_input");
14618
15037
  return;
14619
15038
  }
@@ -14632,7 +15051,7 @@ async function identify(userId, properties = {}) {
14632
15051
  }
14633
15052
  const mappedProps = mapProperties(properties);
14634
15053
  try {
14635
- mixpanelService.identify(userId, mappedProps, report);
15054
+ mixpanelService.identify(userId2, mappedProps, report);
14636
15055
  } catch {
14637
15056
  report("mixpanel", "failed");
14638
15057
  }
@@ -14652,7 +15071,7 @@ async function identify(userId, properties = {}) {
14652
15071
  } catch {
14653
15072
  report("mixpanel", "failed");
14654
15073
  } finally {
14655
- void identifyWithLocation(userId, properties, report);
15074
+ void identifyWithLocation(userId2, properties, report);
14656
15075
  }
14657
15076
  }
14658
15077
  z.object({