@crelora/mark 0.2.2 → 0.3.2

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.
@@ -1,15 +1,15 @@
1
- const O = "https://ingest.onelence.com";
2
- class p extends Error {
1
+ const H = "https://ingest.onelence.com";
2
+ class g extends Error {
3
3
  status;
4
4
  retryAfterMs;
5
5
  constructor(e, t = {}) {
6
6
  super(e), this.name = "TransportError", this.status = t.status, this.retryAfterMs = t.retryAfterMs;
7
7
  }
8
8
  }
9
- function H(r) {
9
+ function z(r) {
10
10
  return !(typeof r != "number" || r < 400 || r >= 500 || r === 408 || r === 429);
11
11
  }
12
- function V(r) {
12
+ function M(r) {
13
13
  if (!r) return;
14
14
  const e = r.trim();
15
15
  if (!e) return;
@@ -22,10 +22,10 @@ function V(r) {
22
22
  return n > 0 ? n : 0;
23
23
  }
24
24
  }
25
- const z = 5, $ = 300, M = 15e3, j = 2880 * 60 * 1e3;
26
- class Y {
25
+ const $ = 5, Y = 300, j = 15e3, Q = 2880 * 60 * 1e3;
26
+ class W {
27
27
  constructor(e, t = {}) {
28
- this.transport = e, this.maxAttempts = t.maxAttempts ?? z, this.baseBackoffMs = t.baseBackoffMs ?? $, this.maxBackoffMs = t.maxBackoffMs ?? M, this.maxItemAgeMs = t.maxItemAgeMs ?? j, this.debug = t.debug ?? !1, this.loadPersisted = t.loadPersisted, this.savePersisted = t.savePersisted, this.onError = t.onError;
28
+ this.transport = e, this.maxAttempts = t.maxAttempts ?? $, this.baseBackoffMs = t.baseBackoffMs ?? Y, this.maxBackoffMs = t.maxBackoffMs ?? j, this.maxItemAgeMs = t.maxItemAgeMs ?? Q, this.debug = t.debug ?? !1, this.loadPersisted = t.loadPersisted, this.savePersisted = t.savePersisted, this.onError = t.onError;
29
29
  const i = this.loadPersisted?.() ?? [];
30
30
  if (i.length > 0) {
31
31
  const n = Date.now();
@@ -66,8 +66,8 @@ class Y {
66
66
  await this.process(!0), await this.transport.flush?.();
67
67
  }
68
68
  /**
69
- * Best-effort synchronous drain using sendBeacon. Intended for page unload;
70
- * errors are swallowed because the tab is going away.
69
+ * Best-effort synchronous drain on page unload. Uses fetch keepalive (via
70
+ * preferBeacon) so auth headers are included.
71
71
  */
72
72
  drainViaBeacon() {
73
73
  if (this.queue.length === 0) return;
@@ -117,8 +117,8 @@ class Y {
117
117
  delete i.__prefer_beacon, await this.transport.send(t.path, i, { preferBeacon: n }), this.queue.shift(), this.sent += 1, this.persist();
118
118
  } catch (i) {
119
119
  this.failed += 1, this.onError?.(i, t.data);
120
- const n = i instanceof p ? i.status : void 0;
121
- if (H(n)) {
120
+ const n = i instanceof g ? i.status : void 0;
121
+ if (z(n)) {
122
122
  this.queue.shift(), this.dropped += 1, this.persist(), this.debug && console.error("[Mark] Dropping event after non-retriable status", n, t.path);
123
123
  continue;
124
124
  }
@@ -126,7 +126,7 @@ class Y {
126
126
  this.queue.shift(), this.dropped += 1, this.persist(), this.debug && console.error("[Mark] Dropping event after max retries", t.path, i);
127
127
  continue;
128
128
  }
129
- const o = i instanceof p ? i.retryAfterMs : void 0;
129
+ const o = i instanceof g ? i.retryAfterMs : void 0;
130
130
  let a;
131
131
  if (typeof o == "number")
132
132
  a = Math.min(this.maxBackoffMs, Math.max(0, o));
@@ -147,7 +147,15 @@ class Y {
147
147
  }
148
148
  }
149
149
  }
150
- const Q = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "source", "is_conversion"]), W = /* @__PURE__ */ new Set([
150
+ const G = 256;
151
+ function T(r) {
152
+ if (typeof r != "string")
153
+ return;
154
+ const e = r.trim();
155
+ if (!(!e || e.length > G) && !e.includes("@") && !/\s/.test(e))
156
+ return e;
157
+ }
158
+ const X = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "source", "is_conversion"]), J = /* @__PURE__ */ new Set([
151
159
  "user_id",
152
160
  "visitor_id",
153
161
  "click_id",
@@ -156,13 +164,13 @@ const Q = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "so
156
164
  "consent_state",
157
165
  "source"
158
166
  ]);
159
- class G {
167
+ class Z {
160
168
  constructor(e, t) {
161
169
  this.deps = t, this.validateConfig(e), this.config = {
162
- endpoint: e.endpoint ?? O,
170
+ endpoint: e.endpoint ?? H,
163
171
  ...e,
164
172
  include_page_context: e.include_page_context ?? !0
165
- }, this.consentRequirement = e.require_consent ?? !1, this.siteId = e.site_id, this.siteHost = e.site_host, this.sessionTimeoutMs = e.session_timeout_ms ?? 1800 * 1e3, this.queue = new Y(this.deps.transport, {
173
+ }, this.consentRequirement = e.require_consent ?? !1, this.siteId = e.site_id, this.siteHost = e.site_host, this.sessionTimeoutMs = e.session_timeout_ms ?? 1800 * 1e3, this.queue = new W(this.deps.transport, {
166
174
  debug: this.config.debug,
167
175
  loadPersisted: () => this.deps.storage.getOutbox?.() ?? [],
168
176
  savePersisted: (i) => this.deps.storage.setOutbox?.(i),
@@ -180,7 +188,7 @@ class G {
180
188
  tcfCachedAllowed = !1;
181
189
  /**
182
190
  * Best-effort synchronous drain that dispatches all queued events via
183
- * sendBeacon. Intended for use on page unload (visibilitychange=hidden,
191
+ * fetch keepalive. Intended for use on page unload (visibilitychange=hidden,
184
192
  * pagehide) where async fetch may be cancelled by the browser.
185
193
  */
186
194
  drainViaBeacon() {
@@ -213,8 +221,8 @@ class G {
213
221
  ...a
214
222
  };
215
223
  i && (c.is_conversion = !0);
216
- const f = o.site_id ?? this.siteId, l = o.site_host ?? this.siteHost;
217
- f && (c.site_id = f), l && (c.site_host = l), this.config.include_page_context && typeof window < "u" && (this.applyPageContext(c), !l && c.site && (c.site_host = c.site)), this.applyInternalFlag(c, o.is_internal);
224
+ const f = o.site_id ?? this.siteId, u = o.site_host ?? this.siteHost;
225
+ f && (c.site_id = f), u && (c.site_host = u), this.config.include_page_context && typeof window < "u" && (this.applyPageContext(c), !u && c.site && (c.site_host = c.site)), this.applyInternalFlag(c, o.is_internal);
218
226
  const d = this.config.before_send ? this.config.before_send(c) : c;
219
227
  return d ? (this.ensureSession(), this.applySessionFields(d), this.config.batching?.enabled && !i && !n?.preferBeacon ? (this.enqueueBatch(d), !0) : (this.queue.enqueue("/event", { ...d, __prefer_beacon: n?.preferBeacon === !0 }), !0)) : !0;
220
228
  }
@@ -251,6 +259,15 @@ class G {
251
259
  getVisitorId() {
252
260
  return this.deps.storage.getVisitorId();
253
261
  }
262
+ /**
263
+ * Adopts or replaces the stored visitor id with a trusted first-party value.
264
+ * Use when an external anonymous id (for example a platform client id) arrives
265
+ * after init. Returns false when the id is invalid.
266
+ */
267
+ setVisitorId(e) {
268
+ const t = T(e);
269
+ return t ? this.deps.storage.setVisitorId ? this.deps.storage.setVisitorId(t) : (this.deps.storage.getVisitorId() === t || this.deps.storage.update({ visitor_id: t }), !0) : (this.config.debug && console.warn("[Mark] setVisitorId called with an invalid visitor id."), !1);
270
+ }
254
271
  setConsent(e) {
255
272
  const t = this.deps.storage.getConsentStatus();
256
273
  this.deps.storage.setConsentStatus(e), e === "denied" ? (this.deps.storage.clearAttribution?.(), this.deps.storage.clearCookieVisitorId?.(), this.deps.storage.setInternal?.(!1)) : e === "granted" && t === "denied" && this.config.rotate_visitor_on_consent_change && this.deps.storage.rotateVisitorId?.();
@@ -318,10 +335,10 @@ class G {
318
335
  t === !0 || i ? e.is_internal = !0 : delete e.is_internal;
319
336
  }
320
337
  getIdentityFields(e) {
321
- const t = e?.visitor_id ?? this.deps.storage.getVisitorId(), i = e?.user_id ?? this.deps.storage.getUserId?.(), n = e?.click_id ?? this.deps.storage.getLastClickId(), o = e?.campaign_id ?? this.deps.storage.getCampaignId(), a = e?.session_id ?? this.deps.storage.getSessionId?.(), c = this.deps.storage.getQueryParams() ?? {}, f = e?.query ?? {}, l = { ...c, ...f }, d = {};
338
+ const t = e?.visitor_id ?? this.deps.storage.getVisitorId(), i = e?.user_id ?? this.deps.storage.getUserId?.(), n = e?.click_id ?? this.deps.storage.getLastClickId(), o = e?.campaign_id ?? this.deps.storage.getCampaignId(), a = e?.session_id ?? this.deps.storage.getSessionId?.(), c = this.deps.storage.getQueryParams() ?? {}, f = e?.query ?? {}, u = { ...c, ...f }, d = {};
322
339
  t && (d.visitor_id = t), i && (d.user_id = i), n && (d.click_id = n), o && (d.campaign_id = o), a && (d.session_id = a);
323
340
  const h = this.deps.storage.getSessionStartedAt?.();
324
- return a && h && (d.session_started_at = h, d.session_elapsed_ms = Date.now() - Date.parse(h)), Object.keys(l).length > 0 && (d.query = l), d;
341
+ return a && h && (d.session_started_at = h, d.session_elapsed_ms = Date.now() - Date.parse(h)), Object.keys(u).length > 0 && (d.query = u), d;
325
342
  }
326
343
  /**
327
344
  * Patches session fields after ensureSession when the first event in a session was built
@@ -346,13 +363,13 @@ class G {
346
363
  sanitizeTrackData(e) {
347
364
  const t = {};
348
365
  for (const [i, n] of Object.entries(e))
349
- Q.has(i) || (t[i] = n);
366
+ X.has(i) || (t[i] = n);
350
367
  return t;
351
368
  }
352
369
  sanitizeIdentifyTraits(e) {
353
370
  const t = {};
354
371
  for (const [i, n] of Object.entries(e))
355
- W.has(i) || (t[i] = n);
372
+ J.has(i) || (t[i] = n);
356
373
  return t;
357
374
  }
358
375
  validateConfig(e) {
@@ -368,6 +385,8 @@ class G {
368
385
  throw new Error("[Mark] `site_id` cannot be an empty string.");
369
386
  if (typeof e.site_host == "string" && !e.site_host.trim())
370
387
  throw new Error("[Mark] `site_host` cannot be an empty string.");
388
+ if (e.visitor_id !== void 0 && !T(e.visitor_id))
389
+ throw new Error("[Mark] `visitor_id` must be a non-empty string (max 256 characters).");
371
390
  }
372
391
  applyPageContext(e) {
373
392
  typeof document > "u" || (e.site || (e.site = window.location.host), e.page || (e.page = window.location.pathname), e.title || (e.title = document.title), !e.referrer && document.referrer && (e.referrer = this.scrubReferrer(document.referrer)));
@@ -462,7 +481,7 @@ class G {
462
481
  return;
463
482
  }
464
483
  const f = a.purpose?.consents ?? {};
465
- this.tcfCachedAllowed = t.every((l) => f[String(l)] === !0);
484
+ this.tcfCachedAllowed = t.every((u) => f[String(u)] === !0);
466
485
  });
467
486
  } catch {
468
487
  this.tcfCachedAllowed = !1;
@@ -471,12 +490,12 @@ class G {
471
490
  i(10);
472
491
  }
473
492
  }
474
- class J {
493
+ class ee {
475
494
  config;
476
495
  endpoint;
477
496
  pending = /* @__PURE__ */ new Set();
478
497
  constructor(e) {
479
- this.config = e, this.endpoint = e.endpoint ?? O;
498
+ this.config = e, this.endpoint = e.endpoint ?? H;
480
499
  }
481
500
  async send(e, t, i) {
482
501
  const n = this.sendInternal(e, t, i);
@@ -495,48 +514,41 @@ class J {
495
514
  "Content-Type": "application/json",
496
515
  [o.startsWith("sk_") ? "x-secret-key" : "x-publishable-key"]: o
497
516
  };
498
- this.config.debug && console.log("[Mark] Sending", n, t);
499
- const c = JSON.stringify(t);
500
- if (i?.preferBeacon && typeof navigator < "u" && typeof navigator.sendBeacon == "function") {
501
- const u = new Blob([c], { type: "application/json" });
502
- if (navigator.sendBeacon(n, u))
503
- return;
504
- }
505
- if (typeof fetch != "function")
506
- throw this.config.debug && console.error("[Mark] Global fetch is not available in this runtime."), new p("[Mark] Global fetch is not available in this runtime.");
507
- const f = this.config.request_timeout_ms ?? 1e4, l = new AbortController();
517
+ if (this.config.debug && console.log("[Mark] Sending", n, t), typeof fetch != "function")
518
+ throw this.config.debug && console.error("[Mark] Global fetch is not available in this runtime."), new g("[Mark] Global fetch is not available in this runtime.");
519
+ const c = JSON.stringify(t), f = this.config.request_timeout_ms ?? 1e4, u = new AbortController();
508
520
  let d = !1;
509
521
  const h = setTimeout(() => {
510
- d = !0, l.abort();
522
+ d = !0, u.abort();
511
523
  }, f);
512
524
  try {
513
- const u = await fetch(n, {
525
+ const l = await fetch(n, {
514
526
  method: "POST",
515
527
  headers: a,
516
528
  body: c,
517
- keepalive: !0,
518
- signal: l.signal
529
+ keepalive: i?.preferBeacon === !0,
530
+ signal: u.signal
519
531
  });
520
- if (!u.ok) {
521
- const g = await this.readErrorSnippet(u), P = V(u.headers.get("Retry-After"));
532
+ if (!l.ok) {
533
+ const p = await this.readErrorSnippet(l), m = M(l.headers.get("Retry-After"));
522
534
  throw this.config.debug && console.error("[Mark] Request rejected", {
523
535
  url: n,
524
- status: u.status,
525
- statusText: u.statusText,
526
- body: g,
527
- retryAfterMs: P
528
- }), new p(
529
- `[Mark] Request rejected with status ${u.status}: ${g}`,
530
- { status: u.status, retryAfterMs: P }
536
+ status: l.status,
537
+ statusText: l.statusText,
538
+ body: p,
539
+ retryAfterMs: m
540
+ }), new g(
541
+ `[Mark] Request rejected with status ${l.status}: ${p}`,
542
+ { status: l.status, retryAfterMs: m }
531
543
  );
532
544
  }
533
- } catch (u) {
534
- if (this.config.debug && console.error("[Mark] Failed to send", n, u), u instanceof p)
535
- throw u;
545
+ } catch (l) {
546
+ if (this.config.debug && console.error("[Mark] Failed to send", n, l), l instanceof g)
547
+ throw l;
536
548
  if (d)
537
- throw new p(`[Mark] Request timed out after ${f}ms`, { status: 408 });
538
- const g = u instanceof Error ? u.message : String(u);
539
- throw new p(`[Mark] Network error: ${g}`);
549
+ throw new g(`[Mark] Request timed out after ${f}ms`, { status: 408 });
550
+ const p = l instanceof Error ? l.message : String(l);
551
+ throw new g(`[Mark] Network error: ${p}`);
540
552
  } finally {
541
553
  clearTimeout(h);
542
554
  }
@@ -553,8 +565,8 @@ class J {
553
565
  }
554
566
  }
555
567
  }
556
- const X = "crelora_mark_data", Z = "crelora_mark_outbox", T = "crelora_mark_vid";
557
- class ee {
568
+ const te = "crelora_mark_data", ie = "crelora_mark_outbox", L = "crelora_mark_vid";
569
+ class ne {
558
570
  data;
559
571
  storageKey;
560
572
  outboxKey;
@@ -563,11 +575,13 @@ class ee {
563
575
  bridgeReady = !1;
564
576
  bridgeOrigin;
565
577
  constructor(e) {
566
- if (this.options = e ?? {}, this.storageKey = this.options.storageKey ?? X, this.outboxKey = this.options.outboxKey ?? Z, typeof window > "u") {
578
+ if (this.options = e ?? {}, this.storageKey = this.options.storageKey ?? te, this.outboxKey = this.options.outboxKey ?? ie, typeof window > "u") {
567
579
  this.data = {};
568
580
  return;
569
581
  }
570
- this.data = this.load(), this.data.visitor_id || (this.data.visitor_id = this.generateUUID(), this.save()), typeof window < "u" && this.options.bridge?.url && this.setupBridge(this.options.bridge), window.addEventListener("storage", this.handleStorageEvent);
582
+ this.data = this.load();
583
+ const t = T(this.options.seed_visitor_id);
584
+ !this.data.visitor_id && t && (this.data.visitor_id = t, this.save()), this.data.visitor_id || (this.data.visitor_id = this.generateUUID(), this.save()), typeof window < "u" && this.options.bridge?.url && this.setupBridge(this.options.bridge), window.addEventListener("storage", this.handleStorageEvent);
571
585
  }
572
586
  getVisitorId() {
573
587
  return this.data.visitor_id;
@@ -616,11 +630,19 @@ class ee {
616
630
  });
617
631
  }
618
632
  clearCookieVisitorId() {
619
- this.setCookie(T, "", -1);
633
+ this.setCookie(L, "", -1);
620
634
  }
621
635
  rotateVisitorId() {
622
636
  this.update({ visitor_id: this.generateUUID() });
623
637
  }
638
+ /**
639
+ * Adopts or replaces the stored visitor id with a trusted first-party value.
640
+ * No-op when the id is invalid or already set to the same value.
641
+ */
642
+ setVisitorId(e) {
643
+ const t = T(e);
644
+ return t ? (this.data.visitor_id === t || this.update({ visitor_id: t }), !0) : !1;
645
+ }
624
646
  getOutbox() {
625
647
  if (typeof window > "u") return [];
626
648
  try {
@@ -648,7 +670,7 @@ class ee {
648
670
  return JSON.parse(t);
649
671
  } catch {
650
672
  }
651
- const e = this.getCookie(T);
673
+ const e = this.getCookie(L);
652
674
  return e ? { visitor_id: e } : {};
653
675
  }
654
676
  save() {
@@ -657,7 +679,7 @@ class ee {
657
679
  localStorage.setItem(this.storageKey, JSON.stringify(this.data));
658
680
  } catch {
659
681
  }
660
- this.data.visitor_id && this.isCookieEnabled() && (this.setCookie(T, this.data.visitor_id, 365), this.options.bridge?.url && this.bridgeReady && this.postBridgeMessage({
682
+ this.data.visitor_id && this.isCookieEnabled() && (this.setCookie(L, this.data.visitor_id, 365), this.options.bridge?.url && this.bridgeReady && this.postBridgeMessage({
661
683
  type: "MARK_SYNC_UPDATE",
662
684
  visitorId: this.data.visitor_id
663
685
  }));
@@ -753,7 +775,7 @@ class ee {
753
775
  }
754
776
  };
755
777
  }
756
- const te = [
778
+ const se = [
757
779
  "click_id",
758
780
  "ch_click_id",
759
781
  "gclid",
@@ -765,7 +787,7 @@ const te = [
765
787
  "ttclid",
766
788
  "twclid",
767
789
  "li_fat_id"
768
- ], ie = ["cid", "campaign_id"], ne = [
790
+ ], re = ["cid", "campaign_id"], oe = [
769
791
  "utm_source",
770
792
  "utm_medium",
771
793
  "utm_campaign",
@@ -787,80 +809,80 @@ const te = [
787
809
  "ttclid",
788
810
  "twclid",
789
811
  "li_fat_id"
790
- ], se = {
812
+ ], ae = {
791
813
  referral: "ref",
792
814
  affiliate_id: "ref",
793
815
  ch_click_id: "click_id",
794
816
  cid: "campaign_id"
795
- }, re = ["email", "phone", "token", "auth", "password", "code"], oe = 30, ae = 256;
796
- function L(r, e = {}) {
797
- const t = new URLSearchParams(r), i = de(t), n = U(i, te), o = U(i, ie), a = ce(t, e), c = {};
817
+ }, ce = ["email", "phone", "token", "auth", "password", "code"], de = 30, ue = 256;
818
+ function R(r, e = {}) {
819
+ const t = new URLSearchParams(r), i = fe(t), n = F(i, se), o = F(i, re), a = le(t, e), c = {};
798
820
  return n && (c.last_click_id = n), o && (c.campaign_id = o), Object.keys(a).length > 0 && (c.query_params = a), c;
799
821
  }
800
- function ce(r, e) {
801
- const t = {}, i = new Set(R(e.query_param_denylist, re)), n = B(
822
+ function le(r, e) {
823
+ const t = {}, i = new Set(B(e.query_param_denylist, ce)), n = O(
802
824
  e.max_captured_query_params,
803
- oe
804
- ), o = B(
825
+ de
826
+ ), o = O(
805
827
  e.max_query_param_value_length,
806
- ae
828
+ ue
807
829
  ), c = e.capture_all_query_params ?? !1 ? null : /* @__PURE__ */ new Set([
808
- ...ne.map(I),
809
- ...R(e.capture_query_params, [])
830
+ ...oe.map(x),
831
+ ...B(e.capture_query_params, [])
810
832
  ]);
811
- for (const [f, l] of r.entries()) {
812
- const d = I(f);
833
+ for (const [f, u] of r.entries()) {
834
+ const d = x(f);
813
835
  if (!d)
814
836
  continue;
815
- const h = se[d] ?? d;
837
+ const h = ae[d] ?? d;
816
838
  if (i.has(d) || i.has(h) || c && !c.has(d))
817
839
  continue;
818
- const u = l.trim();
819
- if (u) {
840
+ const l = u.trim();
841
+ if (l) {
820
842
  if (!(h in t) && Object.keys(t).length >= n)
821
843
  break;
822
- t[h] = u.slice(0, o);
844
+ t[h] = l.slice(0, o);
823
845
  }
824
846
  }
825
847
  return t;
826
848
  }
827
- function U(r, e) {
849
+ function F(r, e) {
828
850
  for (const t of e) {
829
- const i = I(t), n = r[i]?.trim();
851
+ const i = x(t), n = r[i]?.trim();
830
852
  if (n)
831
853
  return n;
832
854
  }
833
855
  }
834
- function de(r) {
856
+ function fe(r) {
835
857
  const e = {};
836
858
  for (const [t, i] of r.entries()) {
837
- const n = I(t);
859
+ const n = x(t);
838
860
  !n || n in e || (e[n] = i);
839
861
  }
840
862
  return e;
841
863
  }
842
- function I(r) {
864
+ function x(r) {
843
865
  return r.trim().toLowerCase();
844
866
  }
845
- function R(r, e) {
867
+ function B(r, e) {
846
868
  const t = r ?? e, i = /* @__PURE__ */ new Set();
847
869
  for (const n of t) {
848
870
  if (typeof n != "string") continue;
849
- const o = I(n);
871
+ const o = x(n);
850
872
  o && i.add(o);
851
873
  }
852
874
  return Array.from(i);
853
875
  }
854
- function B(r, e) {
876
+ function O(r, e) {
855
877
  if (typeof r != "number" || !Number.isFinite(r))
856
878
  return e;
857
879
  const t = Math.floor(r);
858
880
  return t < 0 ? e : t;
859
881
  }
860
- function E(r) {
882
+ function k(r) {
861
883
  return r.length > 1 && r.endsWith("/") ? r.slice(0, -1) : r;
862
884
  }
863
- function ue(r) {
885
+ function he(r) {
864
886
  if (!r || r === "?")
865
887
  return "";
866
888
  const e = r.startsWith("?") ? r.slice(1) : r;
@@ -869,9 +891,9 @@ function ue(r) {
869
891
  const t = new URLSearchParams(e), i = [];
870
892
  t.forEach((a, c) => {
871
893
  i.push([c, a]);
872
- }), i.sort(([a, c], [f, l]) => {
894
+ }), i.sort(([a, c], [f, u]) => {
873
895
  const d = a.localeCompare(f);
874
- return d !== 0 ? d : c.localeCompare(l);
896
+ return d !== 0 ? d : c.localeCompare(u);
875
897
  });
876
898
  const n = new URLSearchParams();
877
899
  for (const [a, c] of i)
@@ -879,86 +901,86 @@ function ue(r) {
879
901
  const o = n.toString();
880
902
  return o === "" ? "" : `?${o}`;
881
903
  }
882
- function C(r) {
883
- const e = E(r.pathname), t = ue(r.search);
904
+ function P(r) {
905
+ const e = k(r.pathname), t = he(r.search);
884
906
  return `${r.origin}${e}${t}${r.hash}`;
885
907
  }
886
- let x = !1, m = null;
887
- const w = [], y = [], _ = [];
888
- let b = null, v = null, A = null, S = null;
889
- function k() {
908
+ let q = !1, w = null;
909
+ const y = [], _ = [], v = [];
910
+ let b = null, A = null, I = null, S = null, E = null;
911
+ function D() {
890
912
  if (typeof window > "u") return;
891
- const r = C(window.location);
892
- if (r === m) return;
893
- const e = { previousKey: m, nextKey: r };
894
- for (const t of w)
895
- t(e);
896
- m = r;
913
+ const r = P(window.location);
914
+ if (r === w) return;
915
+ const e = { previousKey: w, nextKey: r };
897
916
  for (const t of y)
898
917
  t(e);
918
+ w = r;
919
+ for (const t of _)
920
+ t(e);
899
921
  }
900
- function le() {
901
- for (const r of _)
922
+ function ge() {
923
+ for (const r of v)
902
924
  r();
903
925
  }
904
- function fe(r = {}) {
905
- if (x || typeof window > "u" || typeof document > "u")
926
+ function pe(r = {}) {
927
+ if (q || typeof window > "u" || typeof document > "u")
906
928
  return;
907
- x = !0;
929
+ q = !0;
908
930
  const e = r.trackRouteChanges ?? !0;
909
- m = C(window.location), S = le, window.addEventListener("pagehide", S), e && (b = history.pushState, v = history.replaceState, history.pushState = function(...t) {
931
+ w = P(window.location), E = ge, window.addEventListener("pagehide", E), e && (b = history.pushState, A = history.replaceState, history.pushState = function(...t) {
910
932
  const i = b.apply(this, t);
911
- return k(), i;
933
+ return D(), i;
912
934
  }, history.replaceState = function(...t) {
913
- const i = v.apply(this, t);
914
- return k(), i;
915
- }, A = k, window.addEventListener("popstate", A));
916
- }
917
- function he(r) {
918
- return w.push(r), () => {
919
- const e = w.indexOf(r);
920
- e >= 0 && w.splice(e, 1);
921
- };
935
+ const i = A.apply(this, t);
936
+ return D(), i;
937
+ }, I = D, window.addEventListener("popstate", I), S = D, window.addEventListener("hashchange", S));
922
938
  }
923
- function q(r) {
939
+ function me(r) {
924
940
  return y.push(r), () => {
925
941
  const e = y.indexOf(r);
926
942
  e >= 0 && y.splice(e, 1);
927
943
  };
928
944
  }
929
- function ge(r) {
945
+ function U(r) {
930
946
  return _.push(r), () => {
931
947
  const e = _.indexOf(r);
932
948
  e >= 0 && _.splice(e, 1);
933
949
  };
934
950
  }
935
- function pe() {
936
- !x || typeof window > "u" || (b && (history.pushState = b), v && (history.replaceState = v), A && window.removeEventListener("popstate", A), S && window.removeEventListener("pagehide", S), b = null, v = null, A = null, S = null, w.length = 0, y.length = 0, _.length = 0, m = null, x = !1);
951
+ function we(r) {
952
+ return v.push(r), () => {
953
+ const e = v.indexOf(r);
954
+ e >= 0 && v.splice(e, 1);
955
+ };
956
+ }
957
+ function ye() {
958
+ !q || typeof window > "u" || (b && (history.pushState = b), A && (history.replaceState = A), I && window.removeEventListener("popstate", I), S && window.removeEventListener("hashchange", S), E && window.removeEventListener("pagehide", E), b = null, A = null, I = null, S = null, E = null, y.length = 0, _.length = 0, v.length = 0, w = null, q = !1);
937
959
  }
938
- let D = 0;
939
- function N() {
940
- D = 0;
960
+ let C = 0;
961
+ function V() {
962
+ C = 0;
941
963
  }
942
- function me() {
943
- return D;
964
+ function _e() {
965
+ return C;
944
966
  }
945
- function we() {
967
+ function ve() {
946
968
  if (typeof document > "u" || typeof window > "u")
947
969
  return 0;
948
970
  const r = document.documentElement, e = window.scrollY || r.scrollTop, t = Math.max(1, r.scrollHeight - window.innerHeight);
949
971
  return Math.min(100, Math.round(e / t * 100));
950
972
  }
951
973
  function K() {
952
- const r = we();
953
- return r > D && (D = r), r;
974
+ const r = ve();
975
+ return r > C && (C = r), r;
954
976
  }
955
- const ye = [25, 50, 75, 100];
956
- function _e(r, e = ye) {
977
+ const be = [25, 50, 75, 100];
978
+ function Ae(r, e = be) {
957
979
  if (typeof window > "u") return;
958
980
  const t = /* @__PURE__ */ new Set(), i = () => {
959
- t.clear(), N();
981
+ t.clear(), V();
960
982
  };
961
- i(), q(() => {
983
+ i(), U(() => {
962
984
  i();
963
985
  }), window.addEventListener(
964
986
  "scroll",
@@ -970,49 +992,55 @@ function _e(r, e = ye) {
970
992
  { passive: !0 }
971
993
  );
972
994
  }
973
- const F = 1e4;
974
- function be(r) {
975
- return r === !0 ? { minActiveMs: F, useBeacon: !0 } : {
976
- minActiveMs: r.min_active_ms ?? F,
995
+ const N = 1e4;
996
+ function Ie(r) {
997
+ return r === !0 ? { minActiveMs: N, useBeacon: !0 } : {
998
+ minActiveMs: r.min_active_ms ?? N,
977
999
  useBeacon: r.use_beacon !== !1
978
1000
  };
979
1001
  }
980
- function ve(r, e) {
1002
+ function Se(r, e) {
981
1003
  if (typeof window > "u" || typeof document > "u") return;
982
- let t = Date.now(), i = 0, n = document.visibilityState === "visible" ? Date.now() : null, o = E(window.location.pathname), a = !1;
1004
+ let t = Date.now(), i = 0, n = document.visibilityState === "visible" ? Date.now() : null, o = k(window.location.pathname), a = !1;
983
1005
  const c = () => {
984
1006
  n !== null && (i += Date.now() - n, n = null);
985
1007
  }, f = () => {
986
1008
  document.visibilityState === "visible" && n === null && (n = Date.now());
987
- }, l = (h) => {
1009
+ }, u = () => {
1010
+ document.visibilityState === "visible" ? f() : c();
1011
+ }, d = (l) => {
988
1012
  if (!a) {
989
1013
  a = !0;
990
1014
  try {
991
- if (c(), K(), i < e.minActiveMs)
1015
+ if (c(), K(), i < e.minActiveMs) {
1016
+ e.debug && console.debug("[Mark] page_engagement skipped (active time below min_active_ms)", {
1017
+ page: o,
1018
+ active_time_ms: i,
1019
+ min_active_ms: e.minActiveMs
1020
+ });
992
1021
  return;
993
- const u = Date.now() - t, g = {
1022
+ }
1023
+ const p = Date.now() - t, m = {
994
1024
  page: o,
995
1025
  active_time_ms: i,
996
- total_time_ms: u,
997
- max_scroll_percent: me()
1026
+ total_time_ms: p,
1027
+ max_scroll_percent: _e()
998
1028
  };
999
- e.useBeacon && h ? r.trackWithOptions("page_engagement", g, { preferBeacon: !0 }) : r.track("page_engagement", g);
1029
+ e.useBeacon && l ? r.trackWithOptions("page_engagement", m, { preferBeacon: !0 }) : r.track("page_engagement", m);
1000
1030
  } finally {
1001
1031
  a = !1;
1002
1032
  }
1003
1033
  }
1004
- }, d = () => {
1005
- t = Date.now(), i = 0, o = E(window.location.pathname), N(), f();
1034
+ }, h = () => {
1035
+ t = Date.now(), i = 0, o = k(window.location.pathname), V(), f();
1006
1036
  };
1007
- d(), he(() => {
1008
- l(!0), c();
1009
- }), q(() => {
1010
- d();
1011
- }), ge(() => {
1012
- l(!0);
1013
- }), document.addEventListener("visibilitychange", () => {
1014
- document.visibilityState === "hidden" ? c() : f();
1015
- });
1037
+ h(), me(() => {
1038
+ d(!1), c();
1039
+ }), U(() => {
1040
+ h();
1041
+ }), we(() => {
1042
+ d(!0);
1043
+ }), document.addEventListener("visibilitychange", u), window.addEventListener("pageshow", u), window.addEventListener("focus", u), queueMicrotask(u), typeof requestAnimationFrame == "function" && requestAnimationFrame(u);
1016
1044
  }
1017
1045
  class s {
1018
1046
  static client = null;
@@ -1028,8 +1056,11 @@ class s {
1028
1056
  static kickTimer = null;
1029
1057
  static init(e) {
1030
1058
  if (!s.client) {
1031
- const t = new ee(e.cross_domain), i = new J(e);
1032
- s.client = new G(e, { storage: t, transport: i }), s.storage = t, s.config = e, s.refreshAttribution(t, e), typeof window < "u" && (s.installPageLifecycleIfNeeded(e), e.autocapture?.pageview && s.installPageviewTracking(e, t), s.installExtendedAutocapture(e), s.installLifecycleFlushing());
1059
+ const t = new ne({
1060
+ ...e.cross_domain,
1061
+ seed_visitor_id: e.visitor_id
1062
+ }), i = new ee(e);
1063
+ s.client = new Z(e, { storage: t, transport: i }), s.storage = t, s.config = e, s.refreshAttribution(t, e), typeof window < "u" && (s.installPageLifecycleIfNeeded(e), e.autocapture?.pageview && s.installPageviewTracking(e, t), s.installExtendedAutocapture(e), s.installLifecycleFlushing());
1033
1064
  }
1034
1065
  return s.client;
1035
1066
  }
@@ -1084,6 +1115,17 @@ class s {
1084
1115
  if (!(!s.client || !s.storage || !s.config || (s.config.require_consent ?? !1) && s.storage.getConsentStatus() !== "granted"))
1085
1116
  return s.client.getVisitorId();
1086
1117
  }
1118
+ /**
1119
+ * Adopts or replaces the stored visitor id with a trusted first-party value.
1120
+ * Updates in-memory storage, localStorage, and the visitor cookie immediately.
1121
+ * Use when an external anonymous id (for example a platform client id) is
1122
+ * available after init. Theme embeds and pixels should call this with the
1123
+ * same source id. Returns false when the id is invalid or the SDK is not
1124
+ * initialized.
1125
+ */
1126
+ static setVisitorId(e) {
1127
+ return s.client ? s.client.setVisitorId(e) : (s.config?.debug && console.warn("[Mark] Not initialized. Call init() first."), !1);
1128
+ }
1087
1129
  static flush() {
1088
1130
  return s.client ? s.client.flush() : Promise.resolve();
1089
1131
  }
@@ -1118,13 +1160,13 @@ class s {
1118
1160
  return s.client?.getStats() ?? { queued: 0, sent: 0, failed: 0, dropped: 0 };
1119
1161
  }
1120
1162
  static destroy() {
1121
- typeof window > "u" || (pe(), s.beaconDrainHandler && (window.removeEventListener("pagehide", s.beaconDrainHandler), window.removeEventListener("beforeunload", s.beaconDrainHandler)), s.visibilityHandler && typeof document < "u" && document.removeEventListener("visibilitychange", s.visibilityHandler), s.onlineHandler && window.removeEventListener("online", s.onlineHandler), s.kickTimer && clearInterval(s.kickTimer), s.beaconDrainHandler = null, s.visibilityHandler = null, s.onlineHandler = null, s.kickTimer = null, s.pageviewTrackerInstalled = !1);
1163
+ typeof window > "u" || (ye(), s.beaconDrainHandler && (window.removeEventListener("pagehide", s.beaconDrainHandler), window.removeEventListener("beforeunload", s.beaconDrainHandler)), s.visibilityHandler && typeof document < "u" && document.removeEventListener("visibilitychange", s.visibilityHandler), s.onlineHandler && window.removeEventListener("online", s.onlineHandler), s.kickTimer && clearInterval(s.kickTimer), s.beaconDrainHandler = null, s.visibilityHandler = null, s.onlineHandler = null, s.kickTimer = null, s.pageviewTrackerInstalled = !1);
1122
1164
  }
1123
1165
  static installPageLifecycleIfNeeded(e) {
1124
1166
  const t = e.autocapture;
1125
1167
  if (!(!!t?.pageview || !!t?.scroll_depth || !!t?.page_engagement)) return;
1126
1168
  const n = e.track_route_changes ?? !0;
1127
- fe({ trackRouteChanges: n });
1169
+ pe({ trackRouteChanges: n });
1128
1170
  }
1129
1171
  static installPageviewTracking(e, t) {
1130
1172
  if (s.pageviewTrackerInstalled) return;
@@ -1132,23 +1174,23 @@ class s {
1132
1174
  const i = () => {
1133
1175
  if (!s.client) return;
1134
1176
  s.refreshAttribution(t, e);
1135
- const o = C(window.location);
1177
+ const o = P(window.location);
1136
1178
  if (o === s.lastPageviewDedupeKey) return;
1137
1179
  s.client.track("page_view", {
1138
1180
  site: window.location.host,
1139
- page: E(window.location.pathname),
1181
+ page: k(window.location.pathname),
1140
1182
  title: document.title,
1141
1183
  referrer: document.referrer || void 0
1142
1184
  }) && (s.lastPageviewDedupeKey = o);
1143
1185
  };
1144
- s.emitAutoPageview = i, i(), (e.track_route_changes ?? !0) && q(() => {
1186
+ s.emitAutoPageview = i, i(), (e.track_route_changes ?? !0) && U(() => {
1145
1187
  i();
1146
1188
  });
1147
1189
  }
1148
1190
  static refreshAttribution(e, t) {
1149
1191
  if (typeof window > "u")
1150
1192
  return;
1151
- const i = L(window.location.search, t);
1193
+ const i = R(window.location.search, t);
1152
1194
  if (Object.keys(i).length !== 0) {
1153
1195
  if (s.shouldPersistAttribution(e, t)) {
1154
1196
  const n = s.mergeAttributionUpdates(s.pendingAttribution, i);
@@ -1162,7 +1204,7 @@ class s {
1162
1204
  const e = s.storage, t = s.config;
1163
1205
  if (!e || !t || typeof window > "u")
1164
1206
  return;
1165
- const i = L(window.location.search, t), n = s.mergeAttributionUpdates(s.pendingAttribution, i);
1207
+ const i = R(window.location.search, t), n = s.mergeAttributionUpdates(s.pendingAttribution, i);
1166
1208
  Object.keys(n).length > 0 && e.update(n), s.pendingAttribution = {};
1167
1209
  }
1168
1210
  static shouldPersistAttribution(e, t) {
@@ -1208,7 +1250,10 @@ class s {
1208
1250
  o.origin !== a.origin && s.client?.trackWithOptions("outbound_link_click", { href: o.toString() }, { preferBeacon: !0 });
1209
1251
  } catch {
1210
1252
  }
1211
- }), t.scroll_depth && s.client && _e(s.client), t.page_engagement && s.client && ve(s.client, be(t.page_engagement)), t.web_vitals && import("./web-vitals-CrnTllyu.js").then((i) => {
1253
+ }), t.scroll_depth && s.client && Ae(s.client), t.page_engagement && s.client && Se(s.client, {
1254
+ ...Ie(t.page_engagement),
1255
+ debug: e.debug
1256
+ }), t.web_vitals && import("./web-vitals-CrnTllyu.js").then((i) => {
1212
1257
  const n = (o) => {
1213
1258
  s.client?.track("web_vital", {
1214
1259
  metric: o.name,