@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
@@ -164,6 +164,7 @@ class Identity {
164
164
  };
165
165
  }
166
166
  }
167
+ const LINK_ATTRIBUTION_DURABLE_DAYS = 30;
167
168
  class SessionManager {
168
169
  constructor(storage, sessionTimeoutMinutes = 30) {
169
170
  this.eventCount = 0;
@@ -171,6 +172,7 @@ class SessionManager {
171
172
  this.activityThrottle = 1e3;
172
173
  this.lastActivityUpdate = 0;
173
174
  this.adClickIDs = {};
175
+ this.linkAttribution = {};
174
176
  this.storage = storage;
175
177
  this.sessionTimeout = sessionTimeoutMinutes * 60 * 1e3;
176
178
  this.lastActivityTime = Date.now();
@@ -183,6 +185,7 @@ class SessionManager {
183
185
  this.eventCount = session.eventCount;
184
186
  this.adClickIDs = session.adClickIDs || {};
185
187
  this.landingPage = session.landingPage;
188
+ this.linkAttribution = session.linkAttribution || {};
186
189
  logger.debug("Session loaded:", session);
187
190
  } else {
188
191
  this.sessionId = this.createNewSession();
@@ -228,7 +231,8 @@ class SessionManager {
228
231
  lastActivityTime: this.lastActivityTime,
229
232
  eventCount: this.eventCount,
230
233
  adClickIDs: this.adClickIDs,
231
- landingPage: this.landingPage
234
+ landingPage: this.landingPage,
235
+ linkAttribution: this.linkAttribution
232
236
  };
233
237
  this.storage.set("session", JSON.stringify(sessionData));
234
238
  }
@@ -293,7 +297,8 @@ class SessionManager {
293
297
  lastActivityTime: this.lastActivityTime,
294
298
  eventCount: this.eventCount,
295
299
  adClickIDs: this.adClickIDs,
296
- landingPage: this.landingPage
300
+ landingPage: this.landingPage,
301
+ linkAttribution: this.linkAttribution
297
302
  };
298
303
  }
299
304
  setAdClickIDs(adClickIDs, landingPage) {
@@ -334,6 +339,41 @@ class SessionManager {
334
339
  getLandingPage() {
335
340
  return this.landingPage;
336
341
  }
342
+ /**
343
+ * Record the landing's Aegis link attribution. LAST touch: a new `aegis_code`
344
+ * replaces the previous set whole — never merged, because the fields are the
345
+ * attributes of ONE link and a mix of two links describes neither.
346
+ * Session + durable (30d, the server's short-link attribution window) so a
347
+ * checkout in a later session can still name the send that brought them.
348
+ */
349
+ setLinkAttribution(attribution) {
350
+ if (!attribution.aegis_code) return;
351
+ this.linkAttribution = { ...attribution };
352
+ this.persistSession();
353
+ try {
354
+ this.storage.set(
355
+ "link_attribution",
356
+ JSON.stringify(this.linkAttribution),
357
+ LINK_ATTRIBUTION_DURABLE_DAYS
358
+ );
359
+ } catch {
360
+ }
361
+ }
362
+ getLinkAttribution() {
363
+ if (!this.linkAttribution.aegis_code) {
364
+ try {
365
+ const durable = this.storage.get("link_attribution");
366
+ if (durable) {
367
+ const parsed = JSON.parse(durable);
368
+ if (parsed && parsed.aegis_code) {
369
+ this.linkAttribution = parsed;
370
+ }
371
+ }
372
+ } catch {
373
+ }
374
+ }
375
+ return this.linkAttribution;
376
+ }
337
377
  destroy() {
338
378
  if (this.checkInterval) {
339
379
  clearInterval(this.checkInterval);
@@ -341,6 +381,97 @@ class SessionManager {
341
381
  }
342
382
  }
343
383
  }
384
+ const FBP_COOKIE = "_fbp";
385
+ const FBC_COOKIE = "_fbc";
386
+ const COOKIE_LIFETIME_DAYS = 90;
387
+ function readCookie(name) {
388
+ if (typeof document === "undefined") return null;
389
+ try {
390
+ const target = `${name}=`;
391
+ const parts = document.cookie.split(";");
392
+ for (let i = 0; i < parts.length; i++) {
393
+ let c = parts[i];
394
+ while (c.charAt(0) === " ") c = c.substring(1);
395
+ if (c.indexOf(target) === 0) {
396
+ return decodeURIComponent(c.substring(target.length));
397
+ }
398
+ }
399
+ } catch {
400
+ }
401
+ return null;
402
+ }
403
+ function writeCookie(name, value, days) {
404
+ if (typeof document === "undefined" || typeof window === "undefined") return;
405
+ try {
406
+ const expiry = new Date(Date.now() + days * 24 * 60 * 60 * 1e3).toUTCString();
407
+ const domain = getRootDomain();
408
+ const isHttps = window.location.protocol === "https:";
409
+ let cookieStr = `${name}=${encodeURIComponent(value)};expires=${expiry};path=/;SameSite=Lax`;
410
+ if (isHttps) cookieStr += ";Secure";
411
+ if (domain) cookieStr += `;domain=${domain}`;
412
+ document.cookie = cookieStr;
413
+ } catch {
414
+ }
415
+ }
416
+ function getRootDomain() {
417
+ if (typeof window === "undefined") return null;
418
+ const host = window.location.hostname;
419
+ if (!host || host === "localhost") return null;
420
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(host)) return null;
421
+ const parts = host.split(".");
422
+ if (parts.length < 2) return null;
423
+ return "." + parts.slice(-2).join(".");
424
+ }
425
+ function subdomainIndex() {
426
+ if (typeof window === "undefined") return 1;
427
+ const host = window.location.hostname;
428
+ if (!host || host === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(host)) return 1;
429
+ const parts = host.split(".");
430
+ return Math.max(1, parts.length - 1);
431
+ }
432
+ function randomToken() {
433
+ const n = Math.floor(Math.random() * 1e10);
434
+ return n.toString().padStart(10, "0");
435
+ }
436
+ function ensureFbp() {
437
+ const existing = readCookie(FBP_COOKIE);
438
+ if (existing) return existing;
439
+ const fbp = `fb.${subdomainIndex()}.${Date.now()}.${randomToken()}`;
440
+ writeCookie(FBP_COOKIE, fbp, COOKIE_LIFETIME_DAYS);
441
+ return fbp;
442
+ }
443
+ function ensureFbc() {
444
+ const existing = readCookie(FBC_COOKIE);
445
+ if (existing) return existing;
446
+ const fbclid = readFbclidFromUrl();
447
+ if (!fbclid) return null;
448
+ const fbc = `fb.${subdomainIndex()}.${Date.now()}.${fbclid}`;
449
+ writeCookie(FBC_COOKIE, fbc, COOKIE_LIFETIME_DAYS);
450
+ return fbc;
451
+ }
452
+ function readFbclidFromUrl() {
453
+ if (typeof window === "undefined") return null;
454
+ try {
455
+ return new URLSearchParams(window.location.search).get("fbclid");
456
+ } catch {
457
+ return null;
458
+ }
459
+ }
460
+ function captureMetaCookies() {
461
+ return {
462
+ fbp: ensureFbp(),
463
+ fbc: ensureFbc(),
464
+ fbclid: readFbclidFromUrl()
465
+ };
466
+ }
467
+ function redactMetaCookies(event) {
468
+ const props = event == null ? void 0 : event.properties;
469
+ if (!props || props.fbc === void 0 && props.fbp === void 0) return event;
470
+ const masked = { ...props };
471
+ if (masked.fbc !== void 0) masked.fbc = "[redacted]";
472
+ if (masked.fbp !== void 0) masked.fbp = "[redacted]";
473
+ return { ...event, properties: masked };
474
+ }
344
475
  class EventQueue {
345
476
  constructor(config, transport, storage) {
346
477
  this.buffer = [];
@@ -428,7 +559,7 @@ class EventQueue {
428
559
  return;
429
560
  }
430
561
  this.buffer.push(event);
431
- logger.debug("Event queued:", event.type, event);
562
+ logger.debug("Event queued:", event.type, redactMetaCookies(event));
432
563
  if (this.buffer.length >= this.config.batchSize) {
433
564
  this.flush();
434
565
  }
@@ -980,6 +1111,20 @@ class Storage {
980
1111
  }
981
1112
  }
982
1113
  }
1114
+ const CREDENTIAL_URL_PARAMS = ["t", "k", "code", "session_code", "aegis_pair", "u"];
1115
+ const REDACTED = "REDACTED";
1116
+ const CREDENTIAL_PARAM_PATTERN = new RegExp(
1117
+ `([?&])(${CREDENTIAL_URL_PARAMS.join("|")})=([^&#\\s"'<>]+)`,
1118
+ "g"
1119
+ );
1120
+ function redactUrl(value) {
1121
+ if (typeof value !== "string" || value.length === 0) return value;
1122
+ try {
1123
+ return value.replace(CREDENTIAL_PARAM_PATTERN, `$1$2=${REDACTED}`);
1124
+ } catch {
1125
+ return value;
1126
+ }
1127
+ }
983
1128
  function parseUTMParameters(url) {
984
1129
  try {
985
1130
  const searchParams = url ? new URL(url).searchParams : new URLSearchParams(window.location.search);
@@ -1010,6 +1155,8 @@ function parseAdClickIDs(url) {
1010
1155
  const adClickIDs = {};
1011
1156
  const clickIDKeys = [
1012
1157
  "gclid",
1158
+ "gbraid",
1159
+ "wbraid",
1013
1160
  "fbclid",
1014
1161
  "msclkid",
1015
1162
  "ctwa_clid",
@@ -1031,6 +1178,30 @@ function parseAdClickIDs(url) {
1031
1178
  function hasAdClickIDs(adClickIDs) {
1032
1179
  return Object.keys(adClickIDs).length > 0;
1033
1180
  }
1181
+ const LINK_ATTRIBUTION_KEYS = [
1182
+ "aegis_code",
1183
+ "aegis_campaign",
1184
+ "aegis_journey",
1185
+ "aegis_playbook",
1186
+ "aegis_button"
1187
+ ];
1188
+ function parseLinkAttribution(url) {
1189
+ try {
1190
+ const searchParams = url ? new URL(url).searchParams : new URLSearchParams(window.location.search);
1191
+ if (!searchParams.get("aegis_code")) return {};
1192
+ const attribution = {};
1193
+ LINK_ATTRIBUTION_KEYS.forEach((key) => {
1194
+ const value = searchParams.get(key);
1195
+ if (value) {
1196
+ attribution[key] = value;
1197
+ }
1198
+ });
1199
+ return attribution;
1200
+ } catch (error) {
1201
+ console.warn("[Active Reach URL Parser] parseLinkAttribution failed:", error);
1202
+ return {};
1203
+ }
1204
+ }
1034
1205
  function buildContext(config, session) {
1035
1206
  const utm = config.capture_utm ? parseUTMParameters() : void 0;
1036
1207
  const device = detectDevice();
@@ -1038,18 +1209,22 @@ function buildContext(config, session) {
1038
1209
  const browser = detectBrowser();
1039
1210
  const network = detectNetworkInfo();
1040
1211
  const adClickIDs = session == null ? void 0 : session.getAdClickIDs();
1041
- const landingPage = session == null ? void 0 : session.getLandingPage();
1212
+ const storedLandingPage = session == null ? void 0 : session.getLandingPage();
1213
+ const landingPage = storedLandingPage ? redactUrl(storedLandingPage) : void 0;
1042
1214
  return {
1043
1215
  library: {
1044
1216
  name: "@active-reach/web-sdk",
1045
1217
  version: "1.0.0"
1046
1218
  },
1219
+ // Credential params (`k`, `t`, `code`, ...) keep their key and lose their
1220
+ // value here, where the URL enters the page object. The referrer is
1221
+ // redacted too: the previous page can be our own order/landing link.
1047
1222
  page: {
1048
1223
  path: window.location.pathname,
1049
- referrer: config.capture_referrer ? document.referrer : "",
1050
- search: window.location.search,
1224
+ referrer: config.capture_referrer ? redactUrl(document.referrer) : "",
1225
+ search: redactUrl(window.location.search),
1051
1226
  title: document.title,
1052
- url: window.location.href,
1227
+ url: redactUrl(window.location.href),
1053
1228
  hash: window.location.hash
1054
1229
  },
1055
1230
  userAgent: navigator.userAgent,
@@ -1525,96 +1700,13 @@ class ConsentManager {
1525
1700
  updateGoogleConsent();
1526
1701
  }
1527
1702
  }
1528
- const FBP_COOKIE = "_fbp";
1529
- const FBC_COOKIE = "_fbc";
1530
- const COOKIE_LIFETIME_DAYS = 90;
1531
- function readCookie(name) {
1532
- if (typeof document === "undefined") return null;
1533
- try {
1534
- const target = `${name}=`;
1535
- const parts = document.cookie.split(";");
1536
- for (let i = 0; i < parts.length; i++) {
1537
- let c = parts[i];
1538
- while (c.charAt(0) === " ") c = c.substring(1);
1539
- if (c.indexOf(target) === 0) {
1540
- return decodeURIComponent(c.substring(target.length));
1541
- }
1542
- }
1543
- } catch {
1544
- }
1545
- return null;
1546
- }
1547
- function writeCookie(name, value, days) {
1548
- if (typeof document === "undefined" || typeof window === "undefined") return;
1549
- try {
1550
- const expiry = new Date(Date.now() + days * 24 * 60 * 60 * 1e3).toUTCString();
1551
- const domain = getRootDomain();
1552
- const isHttps = window.location.protocol === "https:";
1553
- let cookieStr = `${name}=${encodeURIComponent(value)};expires=${expiry};path=/;SameSite=Lax`;
1554
- if (isHttps) cookieStr += ";Secure";
1555
- if (domain) cookieStr += `;domain=${domain}`;
1556
- document.cookie = cookieStr;
1557
- } catch {
1558
- }
1559
- }
1560
- function getRootDomain() {
1561
- if (typeof window === "undefined") return null;
1562
- const host = window.location.hostname;
1563
- if (!host || host === "localhost") return null;
1564
- if (/^\d+\.\d+\.\d+\.\d+$/.test(host)) return null;
1565
- const parts = host.split(".");
1566
- if (parts.length < 2) return null;
1567
- return "." + parts.slice(-2).join(".");
1568
- }
1569
- function subdomainIndex() {
1570
- if (typeof window === "undefined") return 1;
1571
- const host = window.location.hostname;
1572
- if (!host || host === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(host)) return 1;
1573
- const parts = host.split(".");
1574
- return Math.max(1, parts.length - 1);
1575
- }
1576
- function randomToken() {
1577
- const n = Math.floor(Math.random() * 1e10);
1578
- return n.toString().padStart(10, "0");
1579
- }
1580
- function ensureFbp() {
1581
- const existing = readCookie(FBP_COOKIE);
1582
- if (existing) return existing;
1583
- const fbp = `fb.${subdomainIndex()}.${Date.now()}.${randomToken()}`;
1584
- writeCookie(FBP_COOKIE, fbp, COOKIE_LIFETIME_DAYS);
1585
- return fbp;
1586
- }
1587
- function ensureFbc() {
1588
- const existing = readCookie(FBC_COOKIE);
1589
- if (existing) return existing;
1590
- const fbclid = readFbclidFromUrl();
1591
- if (!fbclid) return null;
1592
- const fbc = `fb.${subdomainIndex()}.${Date.now()}.${fbclid}`;
1593
- writeCookie(FBC_COOKIE, fbc, COOKIE_LIFETIME_DAYS);
1594
- return fbc;
1595
- }
1596
- function readFbclidFromUrl() {
1597
- if (typeof window === "undefined") return null;
1598
- try {
1599
- return new URLSearchParams(window.location.search).get("fbclid");
1600
- } catch {
1601
- return null;
1602
- }
1603
- }
1604
- function captureMetaCookies() {
1605
- return {
1606
- fbp: ensureFbp(),
1607
- fbc: ensureFbc(),
1608
- fbclid: readFbclidFromUrl()
1609
- };
1610
- }
1611
1703
  function sumItems(products) {
1612
1704
  return products.reduce((sum, p) => sum + (p.quantity ?? 1), 0);
1613
1705
  }
1614
1706
  function mapProducts(products) {
1615
1707
  return products.map((p) => ({
1616
1708
  product_id: p.product_id,
1617
- sku: p.sku ?? p.product_id,
1709
+ sku: p.sku,
1618
1710
  name: p.name,
1619
1711
  price: p.price,
1620
1712
  quantity: p.quantity ?? 1,
@@ -1653,7 +1745,7 @@ class EcommerceTracker {
1653
1745
  productViewed(product) {
1654
1746
  this.aegis.track("product_viewed", {
1655
1747
  product_id: product.product_id,
1656
- sku: product.sku ?? product.product_id,
1748
+ sku: product.sku,
1657
1749
  name: product.name,
1658
1750
  price: product.price,
1659
1751
  currency: product.currency ?? "INR",
@@ -1666,17 +1758,29 @@ class EcommerceTracker {
1666
1758
  });
1667
1759
  }
1668
1760
  productListViewed(list) {
1761
+ const products = mapProducts(list.products);
1669
1762
  this.aegis.track("product_list_viewed", {
1670
1763
  list_id: list.list_id,
1671
1764
  list_name: list.list_name,
1672
1765
  category: list.category,
1673
- products: mapProducts(list.products)
1766
+ products,
1767
+ // `items` as well as `products` — a THIRD spelling of the same fact was
1768
+ // one spelling too many. Every product reader in the platform looks for
1769
+ // `items` (or `line_items`, the Shopify shape); this event alone said
1770
+ // `products`, so a list view showed N products and contributed nothing to
1771
+ // any of them. On ST that was 4 views recorded as `not measured`, and it
1772
+ // is the same defect that made every Shopify order invisible.
1773
+ //
1774
+ // `products` is kept so nothing already reading it breaks. mapProducts
1775
+ // already emits product_id / sku / name / price / quantity, which is
1776
+ // exactly the canonical item shape — no second mapping to drift.
1777
+ items: products
1674
1778
  });
1675
1779
  }
1676
1780
  productClicked(product, source) {
1677
1781
  this.aegis.track("product_clicked", {
1678
1782
  product_id: product.product_id,
1679
- sku: product.sku ?? product.product_id,
1783
+ sku: product.sku,
1680
1784
  name: product.name,
1681
1785
  price: product.price,
1682
1786
  currency: product.currency ?? "INR",
@@ -1691,7 +1795,7 @@ class EcommerceTracker {
1691
1795
  productImpressed(product, source) {
1692
1796
  this.aegis.track("product_impression", {
1693
1797
  product_id: product.product_id,
1694
- sku: product.sku ?? product.product_id,
1798
+ sku: product.sku,
1695
1799
  name: product.name,
1696
1800
  price: product.price,
1697
1801
  currency: product.currency ?? "INR",
@@ -1720,7 +1824,7 @@ class EcommerceTracker {
1720
1824
  const qty = product.quantity ?? 1;
1721
1825
  this.aegis.track("cart_item_added", {
1722
1826
  product_id: product.product_id,
1723
- sku: product.sku ?? product.product_id,
1827
+ sku: product.sku,
1724
1828
  name: product.name,
1725
1829
  price: product.price,
1726
1830
  quantity: qty,
@@ -1739,7 +1843,7 @@ class EcommerceTracker {
1739
1843
  const qty = product.quantity ?? 1;
1740
1844
  this.aegis.track("cart_item_removed", {
1741
1845
  product_id: product.product_id,
1742
- sku: product.sku ?? product.product_id,
1846
+ sku: product.sku,
1743
1847
  name: product.name,
1744
1848
  price: product.price,
1745
1849
  quantity: qty,
@@ -1834,7 +1938,7 @@ class EcommerceTracker {
1834
1938
  wishlist_id: wishlist.wishlist_id,
1835
1939
  wishlist_name: wishlist.wishlist_name,
1836
1940
  product_id: wishlist.product.product_id,
1837
- sku: wishlist.product.sku ?? wishlist.product.product_id,
1941
+ sku: wishlist.product.sku,
1838
1942
  name: wishlist.product.name,
1839
1943
  price: wishlist.product.price,
1840
1944
  variant_id: wishlist.product.variant_id
@@ -1845,7 +1949,7 @@ class EcommerceTracker {
1845
1949
  wishlist_id: wishlist.wishlist_id,
1846
1950
  wishlist_name: wishlist.wishlist_name,
1847
1951
  product_id: wishlist.product.product_id,
1848
- sku: wishlist.product.sku ?? wishlist.product.product_id,
1952
+ sku: wishlist.product.sku,
1849
1953
  name: wishlist.product.name,
1850
1954
  price: wishlist.product.price,
1851
1955
  variant_id: wishlist.product.variant_id
@@ -1862,7 +1966,7 @@ class EcommerceTracker {
1862
1966
  productWaitlisted(waitlist) {
1863
1967
  this.aegis.track("product_waitlisted", {
1864
1968
  product_id: waitlist.product.product_id,
1865
- sku: waitlist.product.sku ?? waitlist.product.product_id,
1969
+ sku: waitlist.product.sku,
1866
1970
  variant_id: waitlist.product.variant_id,
1867
1971
  name: waitlist.product.name,
1868
1972
  price: waitlist.product.price,
@@ -2569,6 +2673,7 @@ class Aegis {
2569
2673
  if (currentUrl === this._lastPageUrl) return;
2570
2674
  this._lastPageUrl = currentUrl;
2571
2675
  setTimeout(() => {
2676
+ if (!this._popstateHandler) return;
2572
2677
  this.page();
2573
2678
  }, 50);
2574
2679
  };
@@ -2617,9 +2722,13 @@ class Aegis {
2617
2722
  if (!this.session) return;
2618
2723
  const adClickIDs = parseAdClickIDs();
2619
2724
  if (hasAdClickIDs(adClickIDs)) {
2620
- this.session.setAdClickIDs(adClickIDs, window.location.href);
2725
+ this.session.setAdClickIDs(adClickIDs, redactUrl(window.location.href));
2621
2726
  logger.info("Ad click IDs captured on page load:", adClickIDs);
2622
2727
  }
2728
+ const linkAttribution = parseLinkAttribution();
2729
+ if (linkAttribution.aegis_code) {
2730
+ this.session.setLinkAttribution(linkAttribution);
2731
+ }
2623
2732
  }
2624
2733
  async initializePlugins() {
2625
2734
  if (!this.config) return;
@@ -3028,26 +3137,38 @@ class Aegis {
3028
3137
  }
3029
3138
  const ctx = event.context;
3030
3139
  const props = event.properties;
3031
- if ((ctx == null ? void 0 : ctx.campaign) && props && !props.campaign_id) {
3140
+ if ((ctx == null ? void 0 : ctx.campaign) && props) {
3032
3141
  const utm = ctx.campaign;
3033
- if (utm.campaign) props.campaign_id = utm.campaign;
3034
- if (utm.source) props.campaign_source = utm.source;
3035
- if (utm.medium) props.campaign_medium = utm.medium;
3036
- if (utm.content) props.campaign_content = utm.content;
3037
- if (utm.term) props.campaign_term = utm.term;
3142
+ if (utm.source && !props.utm_source) props.utm_source = utm.source;
3143
+ if (utm.medium && !props.utm_medium) props.utm_medium = utm.medium;
3144
+ if (utm.campaign && !props.utm_campaign) props.utm_campaign = utm.campaign;
3145
+ if (utm.content && !props.utm_content) props.utm_content = utm.content;
3146
+ if (utm.term && !props.utm_term) props.utm_term = utm.term;
3038
3147
  }
3039
3148
  if ((ctx == null ? void 0 : ctx.adClickIDs) && props) {
3040
3149
  const clicks = ctx.adClickIDs;
3150
+ if (clicks.gclid && !props.gclid) props.gclid = clicks.gclid;
3151
+ if (clicks.gbraid && !props.gbraid) props.gbraid = clicks.gbraid;
3152
+ if (clicks.wbraid && !props.wbraid) props.wbraid = clicks.wbraid;
3153
+ if (clicks.fbclid && !props.fbclid) props.fbclid = clicks.fbclid;
3041
3154
  const clickId = clicks.gclid || clicks.fbclid || clicks.ctwa_clid || clicks.msclkid || clicks.ttclid;
3042
3155
  if (clickId && !props.campaign_click_id) props.campaign_click_id = clickId;
3043
3156
  }
3157
+ if (props && this.session) {
3158
+ const link = this.session.getLinkAttribution();
3159
+ if (link.aegis_code) {
3160
+ for (const [key, value] of Object.entries(link)) {
3161
+ if (value && !props[key]) props[key] = value;
3162
+ }
3163
+ }
3164
+ }
3044
3165
  if (props) {
3045
3166
  const meta = captureMetaCookies();
3046
3167
  if (meta.fbp && !props.fbp) props.fbp = meta.fbp;
3047
3168
  if (meta.fbc && !props.fbc) props.fbc = meta.fbc;
3048
3169
  if (meta.fbclid && !props.fbclid) props.fbclid = meta.fbclid;
3049
3170
  }
3050
- logger.debug("Capturing event:", event);
3171
+ logger.debug("Capturing event:", redactMetaCookies(event));
3051
3172
  const transformedEvent = await this.plugins.executeHookChain(
3052
3173
  "beforeEventCapture",
3053
3174
  event
@@ -3154,6 +3275,18 @@ class Aegis {
3154
3275
  if (!this.identity) return null;
3155
3276
  return this.identity.getUserId();
3156
3277
  }
3278
+ /**
3279
+ * The Aegis short-link attribution captured from this visitor's landing URL
3280
+ * (`aegis_code` + the link row's `aegis_campaign` / `aegis_journey` /
3281
+ * `aegis_playbook` / `aegis_button`), or `{}` when they did not arrive
3282
+ * through one. Hosts forward `aegis_code` with an order so the order can be
3283
+ * joined to the send that brought the shopper. Never contains `utm_*`, `k`,
3284
+ * `t` or `u`.
3285
+ */
3286
+ getLinkAttribution() {
3287
+ if (!this.session) return {};
3288
+ return { ...this.session.getLinkAttribution() };
3289
+ }
3157
3290
  /**
3158
3291
  * Fetch the identified contact's REDEEMABLE rewards — coupon codes the
3159
3292
  * storefront can auto-apply at checkout + loyalty points balance/tier.
@@ -3345,6 +3478,7 @@ export {
3345
3478
  Storage as S,
3346
3479
  UserNamespace as U,
3347
3480
  logger as l,
3348
- murmurhash3_x86_32 as m
3481
+ murmurhash3_x86_32 as m,
3482
+ redactUrl as r
3349
3483
  };
3350
- //# sourceMappingURL=analytics-Qyzk8JaB.mjs.map
3484
+ //# sourceMappingURL=analytics-Cz1ZBOxH.mjs.map