@active-reach/web-sdk 1.37.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/aegis.min.js +1 -1
  2. package/dist/aegis.min.js.map +1 -1
  3. package/dist/{analytics-Qyzk8JaB.mjs → analytics-Cz1ZBOxH.mjs} +244 -110
  4. package/dist/analytics-Cz1ZBOxH.mjs.map +1 -0
  5. package/dist/core/analytics.d.ts +10 -0
  6. package/dist/core/analytics.d.ts.map +1 -1
  7. package/dist/core/prefetch-bundle-client.d.ts +1 -0
  8. package/dist/core/prefetch-bundle-client.d.ts.map +1 -1
  9. package/dist/core/queue.d.ts.map +1 -1
  10. package/dist/core/session.d.ts +12 -1
  11. package/dist/core/session.d.ts.map +1 -1
  12. package/dist/ecommerce/index.d.ts.map +1 -1
  13. package/dist/inapp/AegisInAppManager.d.ts +17 -1
  14. package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
  15. package/dist/inapp/actions.d.ts +7 -0
  16. package/dist/inapp/actions.d.ts.map +1 -1
  17. package/dist/inapp/index.d.ts +1 -1
  18. package/dist/inapp/index.d.ts.map +1 -1
  19. package/dist/inapp/renderers/card-template.d.ts.map +1 -1
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +181 -32
  23. package/dist/index.js.map +1 -1
  24. package/dist/react.js +1 -1
  25. package/dist/triggers/TriggerEngine.d.ts +5 -0
  26. package/dist/triggers/TriggerEngine.d.ts.map +1 -1
  27. package/dist/utils/device.d.ts.map +1 -1
  28. package/dist/utils/meta-cookies.d.ts +7 -0
  29. package/dist/utils/meta-cookies.d.ts.map +1 -1
  30. package/dist/utils/redact-url.d.ts +56 -0
  31. package/dist/utils/redact-url.d.ts.map +1 -0
  32. package/dist/utils/url-parser.d.ts +38 -0
  33. package/dist/utils/url-parser.d.ts.map +1 -1
  34. package/dist/utils/visitor.d.ts +43 -0
  35. package/dist/utils/visitor.d.ts.map +1 -0
  36. package/dist/widgets/AegisWidgetManager.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/analytics-Qyzk8JaB.mjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { S as Storage, l as logger, A as Aegis } from "./analytics-Qyzk8JaB.mjs";
2
- import { B, E, N, R, U, m } from "./analytics-Qyzk8JaB.mjs";
1
+ import { S as Storage, r as redactUrl, l as logger, A as Aegis } from "./analytics-Cz1ZBOxH.mjs";
2
+ import { B, E, N, R, U, m } from "./analytics-Cz1ZBOxH.mjs";
3
3
  import { AegisWebPush } from "./push/AegisWebPush.js";
4
4
  function debounce(func, wait) {
5
5
  let timeoutId = null;
@@ -26,6 +26,13 @@ function throttle(func, limit) {
26
26
  };
27
27
  }
28
28
  const PDP_SKU_RE = /\/p\/([^/?#]+)/;
29
+ function productPath(sku) {
30
+ const encoded = encodeURIComponent(sku).replace(
31
+ /[!'()*]/g,
32
+ (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
33
+ );
34
+ return `/p/${encoded}`;
35
+ }
29
36
  function parseAction(actionUrl, meta) {
30
37
  const url = (actionUrl ?? "").trim();
31
38
  const m2 = meta ?? {};
@@ -61,7 +68,7 @@ function parseAction(actionUrl, meta) {
61
68
  case "open-product":
62
69
  case "product": {
63
70
  const sku = params.get("sku") || m2.sku || void 0;
64
- return { type: "open_product", sku, productId: m2.product_id, url: sku ? `/p/${sku}` : void 0 };
71
+ return { type: "open_product", sku, productId: m2.product_id, url: sku ? productPath(sku) : void 0 };
65
72
  }
66
73
  default:
67
74
  return { type: "custom", name: verb || "unknown", payload: Object.fromEntries(params) };
@@ -96,7 +103,7 @@ function parseAction(actionUrl, meta) {
96
103
  }
97
104
  return { type: "dismiss" };
98
105
  }
99
- function fallbackUrlForAction(a, productUrl = (sku) => `/p/${encodeURIComponent(sku)}`) {
106
+ function fallbackUrlForAction(a, productUrl = productPath) {
100
107
  switch (a.type) {
101
108
  case "navigate":
102
109
  return a.url;
@@ -652,9 +659,11 @@ function appendRatingThanks(wrap, el2, ctx, fg, accent, isHigh) {
652
659
  cta.textContent = el2.rating_high_cta || "Leave a review";
653
660
  cta.style.cssText = `margin:4px auto 0;display:block;padding:9px 18px;border:none;border-radius:999px;background:${accent};color:#fff;font-size:13px;font-weight:800;cursor:pointer;`;
654
661
  cta.addEventListener("click", () => {
662
+ var _a;
655
663
  ctx.trackEvent(ctx.campaign.id, "clicked", {
656
664
  meta: { element: "rating_input", cta: "high_review" }
657
665
  });
666
+ void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "review_redirect", { cta: "high_review" }));
658
667
  if (ctx.navigate) ctx.navigate(url, "cta");
659
668
  else window.location.href = url;
660
669
  });
@@ -821,6 +830,7 @@ function buildProductRatingListElement(el2, ctx, fg) {
821
830
  const orderId = slot.getAttribute("data-order-id");
822
831
  const billCode = slot.getAttribute("data-bill-code");
823
832
  const token = slot.getAttribute("data-token");
833
+ const reviewsViaPage = Boolean(slot.getAttribute("data-reviews-url"));
824
834
  const reviewsUrl = slot.getAttribute("data-reviews-url") || el2.rating_high_url || null;
825
835
  const scale = typeof el2.rating_scale === "number" && el2.rating_scale >= 2 && el2.rating_scale <= 10 ? Math.floor(el2.rating_scale) : 5;
826
836
  const showThumb = el2.show_thumbnail !== false && el2.rating_layout !== "compact";
@@ -1071,6 +1081,12 @@ function buildProductRatingListElement(el2, ctx, fg) {
1071
1081
  a.href = ctx.sanitizeUrl(reviewsUrl) || "#";
1072
1082
  a.textContent = el2.rating_high_cta || "Share a review";
1073
1083
  a.style.cssText = `display:inline-block;margin-top:6px;font-size:12px;font-weight:700;color:${accent};text-decoration:none;`;
1084
+ if (!reviewsViaPage) {
1085
+ a.addEventListener("click", () => {
1086
+ var _a2;
1087
+ void ((_a2 = ctx.submitResponse) == null ? void 0 : _a2.call(ctx, "review_redirect", { cta: "item_rating_review" }));
1088
+ });
1089
+ }
1074
1090
  ack.appendChild(a);
1075
1091
  }
1076
1092
  wrap.appendChild(ack);
@@ -1247,9 +1263,11 @@ function appendNpsThanks(wrap, el2, ctx, fg, accent, isPromoter) {
1247
1263
  cta.textContent = el2.nps_promoter_cta || "Leave a review";
1248
1264
  cta.style.cssText = `margin:4px auto 0;display:block;padding:9px 18px;border:none;border-radius:999px;background:${accent};color:#fff;font-size:13px;font-weight:800;cursor:pointer;`;
1249
1265
  cta.addEventListener("click", () => {
1266
+ var _a;
1250
1267
  ctx.trackEvent(ctx.campaign.id, "clicked", {
1251
1268
  meta: { element: "nps", cta: "promoter_review" }
1252
1269
  });
1270
+ void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "review_redirect", { cta: "promoter_review" }));
1253
1271
  if (ctx.navigate) ctx.navigate(url, "cta");
1254
1272
  else window.location.href = url;
1255
1273
  });
@@ -4937,7 +4955,7 @@ class TriggerEngine {
4937
4955
  this.exitIntentFired = true;
4938
4956
  this.emit("exit_intent", {
4939
4957
  client_y: event.clientY,
4940
- page_url: window.location.href,
4958
+ page_url: redactUrl(window.location.href),
4941
4959
  time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1e3 : 0
4942
4960
  });
4943
4961
  }
@@ -4958,7 +4976,7 @@ class TriggerEngine {
4958
4976
  scroll_velocity: velocity,
4959
4977
  scroll_distance: distance,
4960
4978
  current_position: currentY,
4961
- page_url: window.location.href,
4979
+ page_url: redactUrl(window.location.href),
4962
4980
  time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1e3 : 0
4963
4981
  });
4964
4982
  this.scrollVelocityCooldownTimer = window.setTimeout(() => {
@@ -4972,12 +4990,12 @@ class TriggerEngine {
4972
4990
  this.handleVisibilityChange = () => {
4973
4991
  if (document.hidden) {
4974
4992
  this.emit("visibility_hidden", {
4975
- page_url: window.location.href,
4993
+ page_url: redactUrl(window.location.href),
4976
4994
  time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1e3 : 0
4977
4995
  });
4978
4996
  } else {
4979
4997
  this.emit("visibility_visible", {
4980
- page_url: window.location.href
4998
+ page_url: redactUrl(window.location.href)
4981
4999
  });
4982
5000
  }
4983
5001
  };
@@ -4988,7 +5006,7 @@ class TriggerEngine {
4988
5006
  this.backButtonFired = true;
4989
5007
  window.history.pushState(null, "", window.location.href);
4990
5008
  this.emit("back_button", {
4991
- page_url: window.location.href,
5009
+ page_url: redactUrl(window.location.href),
4992
5010
  time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1e3 : 0
4993
5011
  });
4994
5012
  };
@@ -5016,7 +5034,7 @@ class TriggerEngine {
5016
5034
  const timerId = window.setTimeout(() => {
5017
5035
  this.emit(`time_on_page_${seconds}`, {
5018
5036
  seconds,
5019
- page_url: window.location.href
5037
+ page_url: redactUrl(window.location.href)
5020
5038
  });
5021
5039
  this.timeOnPageTargets.delete(seconds);
5022
5040
  }, seconds * 1e3);
@@ -5936,6 +5954,54 @@ function renderReviewsOverlay(ctx, creds) {
5936
5954
  document.body.appendChild(overlay);
5937
5955
  renderReviewsInline(ctx, body, creds);
5938
5956
  }
5957
+ const RETURNING_MARKER_KEY = "aegis_returning_user";
5958
+ const SESSION_VERDICT_KEY = "aegis_new_visitor_session";
5959
+ let cachedVerdict = null;
5960
+ function readSessionVerdict() {
5961
+ try {
5962
+ if (typeof sessionStorage === "undefined") return null;
5963
+ const stored = sessionStorage.getItem(SESSION_VERDICT_KEY);
5964
+ if (stored === "1") return true;
5965
+ if (stored === "0") return false;
5966
+ return null;
5967
+ } catch {
5968
+ return null;
5969
+ }
5970
+ }
5971
+ function writeSessionVerdict(verdict) {
5972
+ try {
5973
+ if (typeof sessionStorage === "undefined") return;
5974
+ sessionStorage.setItem(SESSION_VERDICT_KEY, verdict ? "1" : "0");
5975
+ } catch {
5976
+ }
5977
+ }
5978
+ function readMarkerVerdict() {
5979
+ try {
5980
+ if (typeof localStorage === "undefined") return false;
5981
+ return localStorage.getItem(RETURNING_MARKER_KEY) === null;
5982
+ } catch {
5983
+ return false;
5984
+ }
5985
+ }
5986
+ function isNewVisitor() {
5987
+ if (cachedVerdict !== null) return cachedVerdict;
5988
+ const sessionVerdict = readSessionVerdict();
5989
+ if (sessionVerdict !== null) {
5990
+ cachedVerdict = sessionVerdict;
5991
+ return cachedVerdict;
5992
+ }
5993
+ cachedVerdict = readMarkerVerdict();
5994
+ writeSessionVerdict(cachedVerdict);
5995
+ return cachedVerdict;
5996
+ }
5997
+ function markReturningVisitor() {
5998
+ isNewVisitor();
5999
+ try {
6000
+ if (typeof localStorage === "undefined") return;
6001
+ localStorage.setItem(RETURNING_MARKER_KEY, "1");
6002
+ } catch {
6003
+ }
6004
+ }
5939
6005
  function readAnonIdFromStorage$1() {
5940
6006
  if (typeof document === "undefined") return void 0;
5941
6007
  try {
@@ -5945,6 +6011,11 @@ function readAnonIdFromStorage$1() {
5945
6011
  return void 0;
5946
6012
  }
5947
6013
  }
6014
+ const JOURNEY_ACK_ACTION = {
6015
+ impression: "viewed",
6016
+ clicked: "clicked",
6017
+ dismissed: "dismissed"
6018
+ };
5948
6019
  function svgNode(svg) {
5949
6020
  try {
5950
6021
  const doc = new DOMParser().parseFromString(svg, "image/svg+xml");
@@ -5956,6 +6027,7 @@ function svgNode(svg) {
5956
6027
  }
5957
6028
  }
5958
6029
  const productIdentityCache = /* @__PURE__ */ new WeakMap();
6030
+ const UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5959
6031
  function productIdentitiesFor(campaign) {
5960
6032
  const ic = campaign == null ? void 0 : campaign.interactive_config;
5961
6033
  const cards = ic && Array.isArray(ic.cards) ? ic.cards : [];
@@ -5966,11 +6038,18 @@ function productIdentitiesFor(campaign) {
5966
6038
  const seen = /* @__PURE__ */ new Set();
5967
6039
  for (const card of cards.slice(0, 24)) {
5968
6040
  const meta = (card == null ? void 0 : card.metadata) || {};
5969
- const identity = String(meta.product_id || "").trim() || String(meta.sku || "").trim() || String(meta.platform_product_id || "").trim();
6041
+ const rawId = String(meta.product_id || "").trim();
6042
+ const rawSku = String(meta.sku || "").trim();
6043
+ const platformId = String(meta.platform_product_id || "").trim();
6044
+ const productId = UUID_SHAPE.test(rawId) ? rawId : "";
6045
+ const sku = rawSku && !UUID_SHAPE.test(rawSku) ? rawSku : rawId && !productId ? rawId : "";
6046
+ const identity = productId || sku || platformId;
5970
6047
  if (!identity || seen.has(identity)) continue;
5971
6048
  seen.add(identity);
5972
6049
  items.push({
5973
- product_id: identity,
6050
+ ...productId ? { product_id: productId } : {},
6051
+ ...sku ? { sku } : {},
6052
+ ...!productId && !sku && platformId ? { platform_product_id: platformId } : {},
5974
6053
  name: String((card == null ? void 0 : card.title) || identity),
5975
6054
  quantity: 1
5976
6055
  });
@@ -5981,7 +6060,7 @@ function productIdentitiesFor(campaign) {
5981
6060
  }
5982
6061
  const _AegisInAppManager = class _AegisInAppManager {
5983
6062
  constructor(config) {
5984
- this.productUrl = (sku) => `/p/${encodeURIComponent(sku)}`;
6063
+ this.productUrl = productPath;
5985
6064
  this.campaigns = [];
5986
6065
  this.displayedCampaigns = /* @__PURE__ */ new Set();
5987
6066
  this._displaySizeMul = 1;
@@ -6007,6 +6086,8 @@ const _AegisInAppManager = class _AegisInAppManager {
6007
6086
  this.slotUnfilledBeaconed = /* @__PURE__ */ new Set();
6008
6087
  this.slotUnfilledSweepTimer = null;
6009
6088
  this._pushOptInLoading = false;
6089
+ this.journeyStepByCampaign = /* @__PURE__ */ new Map();
6090
+ this.journeyAcks = /* @__PURE__ */ new Set();
6010
6091
  this.writeKey = config.writeKey;
6011
6092
  this.apiHost = config.apiHost || "https://api.aegis.ai";
6012
6093
  this.userId = config.userId ?? readAnonIdFromStorage$1();
@@ -6112,13 +6193,13 @@ const _AegisInAppManager = class _AegisInAppManager {
6112
6193
  this.log("AegisInApp already initialized");
6113
6194
  return;
6114
6195
  }
6115
- if (typeof localStorage !== "undefined") {
6116
- localStorage.setItem("aegis_returning_user", "1");
6117
- try {
6196
+ markReturningVisitor();
6197
+ try {
6198
+ if (typeof localStorage !== "undefined") {
6118
6199
  const pv = parseInt(localStorage.getItem("aegis_pv_count") || "0", 10);
6119
6200
  localStorage.setItem("aegis_pv_count", String(pv + 1));
6120
- } catch {
6121
6201
  }
6202
+ } catch {
6122
6203
  }
6123
6204
  ensureInAppFont();
6124
6205
  await this.refreshCampaigns();
@@ -6495,9 +6576,11 @@ const _AegisInAppManager = class _AegisInAppManager {
6495
6576
  try {
6496
6577
  const context = new URLSearchParams({
6497
6578
  device_type: this.detectDeviceType(),
6498
- page_url: typeof window !== "undefined" ? window.location.pathname + window.location.search : "/"
6579
+ // Credential params keep their key and lose their value, so a
6580
+ // `*placed=1*` / `*?step=cart*` rule still matches.
6581
+ page_url: typeof window !== "undefined" ? redactUrl(window.location.pathname + window.location.search) : "/"
6499
6582
  });
6500
- context.set("is_new_user", this.isNewUser() ? "true" : "false");
6583
+ context.set("is_new_user", isNewVisitor() ? "true" : "false");
6501
6584
  if (this.currentSurface) {
6502
6585
  context.set("current_surface", this.currentSurface);
6503
6586
  }
@@ -6579,28 +6662,29 @@ const _AegisInAppManager = class _AegisInAppManager {
6579
6662
  if (/iPad|Tablet/i.test(ua)) return "tablet";
6580
6663
  return "desktop";
6581
6664
  }
6582
- isNewUser() {
6583
- if (typeof localStorage === "undefined") return true;
6584
- return !localStorage.getItem("aegis_returning_user");
6585
- }
6586
6665
  // --- A/B Assignment Persistence (Critical Fix C) ---
6666
+ // Both A/B helpers sit on the campaign-fetch path, so blocked storage
6667
+ // (where even `typeof localStorage` throws) must not abort the fetch.
6587
6668
  getABAssignments() {
6588
- if (typeof localStorage === "undefined") return {};
6589
6669
  try {
6670
+ if (typeof localStorage === "undefined") return {};
6590
6671
  return JSON.parse(localStorage.getItem("aegis_ab_assignments") || "{}");
6591
6672
  } catch {
6592
6673
  return {};
6593
6674
  }
6594
6675
  }
6595
6676
  processABAssignments(campaigns) {
6596
- if (typeof localStorage === "undefined") return;
6597
6677
  const stored = this.getABAssignments();
6598
6678
  for (const campaign of campaigns) {
6599
6679
  if (campaign.assigned_variant_id) {
6600
6680
  stored[campaign.id] = campaign.assigned_variant_id;
6601
6681
  }
6602
6682
  }
6603
- localStorage.setItem("aegis_ab_assignments", JSON.stringify(stored));
6683
+ try {
6684
+ if (typeof localStorage === "undefined") return;
6685
+ localStorage.setItem("aegis_ab_assignments", JSON.stringify(stored));
6686
+ } catch {
6687
+ }
6604
6688
  }
6605
6689
  getVariantId(campaignId) {
6606
6690
  const assignments = this.getABAssignments();
@@ -11864,6 +11948,67 @@ const _AegisInAppManager = class _AegisInAppManager {
11864
11948
  } catch (error) {
11865
11949
  this.log(`Error tracking event: ${error}`, "error");
11866
11950
  }
11951
+ const step = (trackedCampaign == null ? void 0 : trackedCampaign.journey_step_execution_id) || this.journeyStepByCampaign.get(campaignId);
11952
+ const ackAction = JOURNEY_ACK_ACTION[eventType];
11953
+ if (step) {
11954
+ this.journeyStepByCampaign.set(campaignId, step);
11955
+ if (ackAction) void this.ackJourneyQueueItem(step, ackAction);
11956
+ }
11957
+ }
11958
+ /**
11959
+ * POST /v1/in-app/widgets/{step}/ack — the canonical writer of a queue row's
11960
+ * seen-state (the same endpoint the Android and iOS SDKs call). Fail-soft by
11961
+ * construction: it runs after the render, is never awaited by it, and never
11962
+ * throws. A network error or 5xx is retried once; if that also fails the key
11963
+ * is released, so the next render of the (still re-served) message tries
11964
+ * again. A 4xx is the server's answer and is not retried. The server side is
11965
+ * idempotent — a repeated action is answered `late_arrival` and writes
11966
+ * nothing — so a duplicate ack is harmless.
11967
+ */
11968
+ async ackJourneyQueueItem(step, action, attempt = 0) {
11969
+ const key = `${step}:${action}`;
11970
+ if (attempt === 0) {
11971
+ if (this.journeyAcks.has(key)) return;
11972
+ this.journeyAcks.add(key);
11973
+ }
11974
+ const headers = {
11975
+ "Content-Type": "application/json",
11976
+ "X-Aegis-Write-Key": this.writeKey
11977
+ };
11978
+ if (this.organizationId) headers["X-Organization-ID"] = this.organizationId;
11979
+ if (this.userId) headers["X-User-ID"] = this.userId;
11980
+ if (this.contactId) headers["X-Contact-ID"] = this.contactId;
11981
+ let retryable = true;
11982
+ try {
11983
+ const response = await fetch(
11984
+ `${this.apiHost}/v1/in-app/widgets/${encodeURIComponent(step)}/ack`,
11985
+ {
11986
+ method: "POST",
11987
+ headers,
11988
+ body: JSON.stringify({ action }),
11989
+ credentials: "include",
11990
+ // A click usually navigates away at once; keepalive lets the ack
11991
+ // outlive the page instead of being cancelled with it.
11992
+ keepalive: true
11993
+ }
11994
+ );
11995
+ if (response.ok) {
11996
+ this.log(`Acknowledged queued message ${step}: ${action}`);
11997
+ return;
11998
+ }
11999
+ retryable = response.status >= 500 || response.status === 408 || response.status === 429;
12000
+ this.log(`Queue ack ${action} for ${step} failed: HTTP ${response.status}`, "warn");
12001
+ } catch (error) {
12002
+ this.log(`Queue ack ${action} for ${step} failed: ${error}`, "warn");
12003
+ }
12004
+ if (!retryable) return;
12005
+ if (attempt === 0) {
12006
+ setTimeout(() => {
12007
+ void this.ackJourneyQueueItem(step, action, 1);
12008
+ }, _AegisInAppManager.JOURNEY_ACK_RETRY_MS);
12009
+ return;
12010
+ }
12011
+ this.journeyAcks.delete(key);
11867
12012
  }
11868
12013
  log(message, level = "log") {
11869
12014
  if (this.debugMode) {
@@ -11914,6 +12059,7 @@ _AegisInAppManager.KNOWN_SURFACES = /* @__PURE__ */ new Set([
11914
12059
  "external_mobile_screen"
11915
12060
  ]);
11916
12061
  _AegisInAppManager.SERVED_DEDUP_PREFIX = "aegis_served_fired:";
12062
+ _AegisInAppManager.JOURNEY_ACK_RETRY_MS = 2e3;
11917
12063
  let AegisInAppManager = _AegisInAppManager;
11918
12064
  function renderPreview(config, opts) {
11919
12065
  document.querySelectorAll(
@@ -12632,9 +12778,10 @@ class PrefetchBundleClient {
12632
12778
  const ctx = this.contextProvider();
12633
12779
  const qs = new URLSearchParams();
12634
12780
  if (ctx.device_type) qs.set("device_type", ctx.device_type);
12635
- if (ctx.page_url) qs.set("page_url", ctx.page_url);
12781
+ if (ctx.page_url) qs.set("page_url", redactUrl(ctx.page_url));
12636
12782
  if (ctx.geo) qs.set("geo", ctx.geo);
12637
- qs.set("is_new_user", ctx.is_new_user ? "true" : "false");
12783
+ const isNewUser = ctx.is_new_user ?? isNewVisitor();
12784
+ qs.set("is_new_user", isNewUser ? "true" : "false");
12638
12785
  const url = `${this.apiHost}/v1/sdk/prefetch-bundle?${qs.toString()}`;
12639
12786
  const headers = {
12640
12787
  "X-Aegis-Write-Key": this.writeKey,
@@ -13516,8 +13663,8 @@ class AegisWidgetManager {
13516
13663
  cart_items: this.cartData.cart_items,
13517
13664
  user_email: this.userId,
13518
13665
  abandoned_at: (/* @__PURE__ */ new Date()).toISOString(),
13519
- page_url: window.location.href,
13520
- referrer: document.referrer
13666
+ page_url: redactUrl(window.location.href),
13667
+ referrer: redactUrl(document.referrer)
13521
13668
  };
13522
13669
  const beaconUrl = `${this.apiHost}/v1/widgets/beacon/cart-abandoned`;
13523
13670
  if (navigator.sendBeacon) {
@@ -14021,7 +14168,9 @@ class AegisWidgetManager {
14021
14168
  cart_total: ((_c = data.cart) == null ? void 0 : _c.cart_total) || 0,
14022
14169
  cart_currency: ((_d = data.cart) == null ? void 0 : _d.cart_currency) || "USD",
14023
14170
  cart_items: ((_e = data.cart) == null ? void 0 : _e.cart_items) || [],
14024
- cart_url: window.location.href,
14171
+ // Redacted: a stored cart URL is re-sent later as a recovery link, and a
14172
+ // credential in it (`?t=` / `?k=`) must not outlive this page view.
14173
+ cart_url: redactUrl(window.location.href),
14025
14174
  platform: "web",
14026
14175
  geo_region: geoRegion,
14027
14176
  device_type: deviceType,
@@ -15137,7 +15286,7 @@ const _AegisMessageRuntime = class _AegisMessageRuntime {
15137
15286
  var _a;
15138
15287
  this.initialized = false;
15139
15288
  {
15140
- const v = "1.37.0";
15289
+ const v = "1.38.0";
15141
15290
  try {
15142
15291
  globalThis.__AEGIS_SDK_VERSION__ = v;
15143
15292
  } catch {