@active-reach/web-sdk 1.37.0 → 1.39.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.
- package/dist/aegis-push.min.js +1 -1
- package/dist/aegis-push.min.js.map +1 -1
- package/dist/aegis.min.js +1 -1
- package/dist/aegis.min.js.map +1 -1
- package/dist/{analytics-Qyzk8JaB.mjs → analytics-DoHdxjjh.mjs} +255 -110
- package/dist/analytics-DoHdxjjh.mjs.map +1 -0
- package/dist/core/analytics.d.ts +10 -0
- package/dist/core/analytics.d.ts.map +1 -1
- package/dist/core/prefetch-bundle-client.d.ts +1 -0
- package/dist/core/prefetch-bundle-client.d.ts.map +1 -1
- package/dist/core/queue.d.ts.map +1 -1
- package/dist/core/session.d.ts +12 -1
- package/dist/core/session.d.ts.map +1 -1
- package/dist/ecommerce/index.d.ts.map +1 -1
- package/dist/inapp/AegisInAppManager.d.ts +22 -2
- package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
- package/dist/inapp/actions.d.ts +7 -0
- package/dist/inapp/actions.d.ts.map +1 -1
- package/dist/inapp/index.d.ts +1 -1
- package/dist/inapp/index.d.ts.map +1 -1
- package/dist/inapp/renderers/card-template.d.ts.map +1 -1
- package/dist/inapp/renderers/games.d.ts.map +1 -1
- package/dist/inapp/renderers/types.d.ts +13 -0
- package/dist/inapp/renderers/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +266 -40
- package/dist/index.js.map +1 -1
- package/dist/push/AegisWebPush.d.ts +19 -0
- package/dist/push/AegisWebPush.d.ts.map +1 -1
- package/dist/push/AegisWebPush.js +31 -2
- package/dist/push/AegisWebPush.js.map +1 -1
- package/dist/react.js +1 -1
- package/dist/runtime/AegisMessageRuntime.d.ts +1 -1
- package/dist/runtime/AegisMessageRuntime.d.ts.map +1 -1
- package/dist/triggers/ContactScoresFetcher.d.ts +2 -1
- package/dist/triggers/ContactScoresFetcher.d.ts.map +1 -1
- package/dist/triggers/IntentRuleEvaluator.d.ts +1 -1
- package/dist/triggers/IntentRuleEvaluator.d.ts.map +1 -1
- package/dist/triggers/TriggerEngine.d.ts +5 -0
- package/dist/triggers/TriggerEngine.d.ts.map +1 -1
- package/dist/utils/device.d.ts.map +1 -1
- package/dist/utils/meta-cookies.d.ts +7 -0
- package/dist/utils/meta-cookies.d.ts.map +1 -1
- package/dist/utils/redact-url.d.ts +56 -0
- package/dist/utils/redact-url.d.ts.map +1 -0
- package/dist/utils/url-parser.d.ts +38 -0
- package/dist/utils/url-parser.d.ts.map +1 -1
- package/dist/utils/visitor.d.ts +43 -0
- package/dist/utils/visitor.d.ts.map +1 -0
- package/dist/widgets/AegisWidgetManager.d.ts +17 -0
- package/dist/widgets/AegisWidgetManager.d.ts.map +1 -1
- package/package.json +1 -1
- 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,31 @@ class Storage {
|
|
|
980
1111
|
}
|
|
981
1112
|
}
|
|
982
1113
|
}
|
|
1114
|
+
const CREDENTIAL_URL_PARAMS = [
|
|
1115
|
+
"t",
|
|
1116
|
+
"k",
|
|
1117
|
+
"code",
|
|
1118
|
+
"session_code",
|
|
1119
|
+
"aegis_pair",
|
|
1120
|
+
"u",
|
|
1121
|
+
// The Shopify CarrierService callback token (2026-09-18). Server-to-server
|
|
1122
|
+
// today, so the SDK never sees one — it is here because the two lists are
|
|
1123
|
+
// ONE rule, and a list that is only correct for today's callers is not.
|
|
1124
|
+
"carrier_token"
|
|
1125
|
+
];
|
|
1126
|
+
const REDACTED = "REDACTED";
|
|
1127
|
+
const CREDENTIAL_PARAM_PATTERN = new RegExp(
|
|
1128
|
+
`([?&])(${CREDENTIAL_URL_PARAMS.join("|")})=([^&#\\s"'<>]+)`,
|
|
1129
|
+
"g"
|
|
1130
|
+
);
|
|
1131
|
+
function redactUrl(value) {
|
|
1132
|
+
if (typeof value !== "string" || value.length === 0) return value;
|
|
1133
|
+
try {
|
|
1134
|
+
return value.replace(CREDENTIAL_PARAM_PATTERN, `$1$2=${REDACTED}`);
|
|
1135
|
+
} catch {
|
|
1136
|
+
return value;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
983
1139
|
function parseUTMParameters(url) {
|
|
984
1140
|
try {
|
|
985
1141
|
const searchParams = url ? new URL(url).searchParams : new URLSearchParams(window.location.search);
|
|
@@ -1010,6 +1166,8 @@ function parseAdClickIDs(url) {
|
|
|
1010
1166
|
const adClickIDs = {};
|
|
1011
1167
|
const clickIDKeys = [
|
|
1012
1168
|
"gclid",
|
|
1169
|
+
"gbraid",
|
|
1170
|
+
"wbraid",
|
|
1013
1171
|
"fbclid",
|
|
1014
1172
|
"msclkid",
|
|
1015
1173
|
"ctwa_clid",
|
|
@@ -1031,6 +1189,30 @@ function parseAdClickIDs(url) {
|
|
|
1031
1189
|
function hasAdClickIDs(adClickIDs) {
|
|
1032
1190
|
return Object.keys(adClickIDs).length > 0;
|
|
1033
1191
|
}
|
|
1192
|
+
const LINK_ATTRIBUTION_KEYS = [
|
|
1193
|
+
"aegis_code",
|
|
1194
|
+
"aegis_campaign",
|
|
1195
|
+
"aegis_journey",
|
|
1196
|
+
"aegis_playbook",
|
|
1197
|
+
"aegis_button"
|
|
1198
|
+
];
|
|
1199
|
+
function parseLinkAttribution(url) {
|
|
1200
|
+
try {
|
|
1201
|
+
const searchParams = url ? new URL(url).searchParams : new URLSearchParams(window.location.search);
|
|
1202
|
+
if (!searchParams.get("aegis_code")) return {};
|
|
1203
|
+
const attribution = {};
|
|
1204
|
+
LINK_ATTRIBUTION_KEYS.forEach((key) => {
|
|
1205
|
+
const value = searchParams.get(key);
|
|
1206
|
+
if (value) {
|
|
1207
|
+
attribution[key] = value;
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
return attribution;
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
console.warn("[Active Reach URL Parser] parseLinkAttribution failed:", error);
|
|
1213
|
+
return {};
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1034
1216
|
function buildContext(config, session) {
|
|
1035
1217
|
const utm = config.capture_utm ? parseUTMParameters() : void 0;
|
|
1036
1218
|
const device = detectDevice();
|
|
@@ -1038,18 +1220,22 @@ function buildContext(config, session) {
|
|
|
1038
1220
|
const browser = detectBrowser();
|
|
1039
1221
|
const network = detectNetworkInfo();
|
|
1040
1222
|
const adClickIDs = session == null ? void 0 : session.getAdClickIDs();
|
|
1041
|
-
const
|
|
1223
|
+
const storedLandingPage = session == null ? void 0 : session.getLandingPage();
|
|
1224
|
+
const landingPage = storedLandingPage ? redactUrl(storedLandingPage) : void 0;
|
|
1042
1225
|
return {
|
|
1043
1226
|
library: {
|
|
1044
1227
|
name: "@active-reach/web-sdk",
|
|
1045
1228
|
version: "1.0.0"
|
|
1046
1229
|
},
|
|
1230
|
+
// Credential params (`k`, `t`, `code`, ...) keep their key and lose their
|
|
1231
|
+
// value here, where the URL enters the page object. The referrer is
|
|
1232
|
+
// redacted too: the previous page can be our own order/landing link.
|
|
1047
1233
|
page: {
|
|
1048
1234
|
path: window.location.pathname,
|
|
1049
|
-
referrer: config.capture_referrer ? document.referrer : "",
|
|
1050
|
-
search: window.location.search,
|
|
1235
|
+
referrer: config.capture_referrer ? redactUrl(document.referrer) : "",
|
|
1236
|
+
search: redactUrl(window.location.search),
|
|
1051
1237
|
title: document.title,
|
|
1052
|
-
url: window.location.href,
|
|
1238
|
+
url: redactUrl(window.location.href),
|
|
1053
1239
|
hash: window.location.hash
|
|
1054
1240
|
},
|
|
1055
1241
|
userAgent: navigator.userAgent,
|
|
@@ -1525,96 +1711,13 @@ class ConsentManager {
|
|
|
1525
1711
|
updateGoogleConsent();
|
|
1526
1712
|
}
|
|
1527
1713
|
}
|
|
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
1714
|
function sumItems(products) {
|
|
1612
1715
|
return products.reduce((sum, p) => sum + (p.quantity ?? 1), 0);
|
|
1613
1716
|
}
|
|
1614
1717
|
function mapProducts(products) {
|
|
1615
1718
|
return products.map((p) => ({
|
|
1616
1719
|
product_id: p.product_id,
|
|
1617
|
-
sku: p.sku
|
|
1720
|
+
sku: p.sku,
|
|
1618
1721
|
name: p.name,
|
|
1619
1722
|
price: p.price,
|
|
1620
1723
|
quantity: p.quantity ?? 1,
|
|
@@ -1653,7 +1756,7 @@ class EcommerceTracker {
|
|
|
1653
1756
|
productViewed(product) {
|
|
1654
1757
|
this.aegis.track("product_viewed", {
|
|
1655
1758
|
product_id: product.product_id,
|
|
1656
|
-
sku: product.sku
|
|
1759
|
+
sku: product.sku,
|
|
1657
1760
|
name: product.name,
|
|
1658
1761
|
price: product.price,
|
|
1659
1762
|
currency: product.currency ?? "INR",
|
|
@@ -1666,17 +1769,29 @@ class EcommerceTracker {
|
|
|
1666
1769
|
});
|
|
1667
1770
|
}
|
|
1668
1771
|
productListViewed(list) {
|
|
1772
|
+
const products = mapProducts(list.products);
|
|
1669
1773
|
this.aegis.track("product_list_viewed", {
|
|
1670
1774
|
list_id: list.list_id,
|
|
1671
1775
|
list_name: list.list_name,
|
|
1672
1776
|
category: list.category,
|
|
1673
|
-
products
|
|
1777
|
+
products,
|
|
1778
|
+
// `items` as well as `products` — a THIRD spelling of the same fact was
|
|
1779
|
+
// one spelling too many. Every product reader in the platform looks for
|
|
1780
|
+
// `items` (or `line_items`, the Shopify shape); this event alone said
|
|
1781
|
+
// `products`, so a list view showed N products and contributed nothing to
|
|
1782
|
+
// any of them. On ST that was 4 views recorded as `not measured`, and it
|
|
1783
|
+
// is the same defect that made every Shopify order invisible.
|
|
1784
|
+
//
|
|
1785
|
+
// `products` is kept so nothing already reading it breaks. mapProducts
|
|
1786
|
+
// already emits product_id / sku / name / price / quantity, which is
|
|
1787
|
+
// exactly the canonical item shape — no second mapping to drift.
|
|
1788
|
+
items: products
|
|
1674
1789
|
});
|
|
1675
1790
|
}
|
|
1676
1791
|
productClicked(product, source) {
|
|
1677
1792
|
this.aegis.track("product_clicked", {
|
|
1678
1793
|
product_id: product.product_id,
|
|
1679
|
-
sku: product.sku
|
|
1794
|
+
sku: product.sku,
|
|
1680
1795
|
name: product.name,
|
|
1681
1796
|
price: product.price,
|
|
1682
1797
|
currency: product.currency ?? "INR",
|
|
@@ -1691,7 +1806,7 @@ class EcommerceTracker {
|
|
|
1691
1806
|
productImpressed(product, source) {
|
|
1692
1807
|
this.aegis.track("product_impression", {
|
|
1693
1808
|
product_id: product.product_id,
|
|
1694
|
-
sku: product.sku
|
|
1809
|
+
sku: product.sku,
|
|
1695
1810
|
name: product.name,
|
|
1696
1811
|
price: product.price,
|
|
1697
1812
|
currency: product.currency ?? "INR",
|
|
@@ -1720,7 +1835,7 @@ class EcommerceTracker {
|
|
|
1720
1835
|
const qty = product.quantity ?? 1;
|
|
1721
1836
|
this.aegis.track("cart_item_added", {
|
|
1722
1837
|
product_id: product.product_id,
|
|
1723
|
-
sku: product.sku
|
|
1838
|
+
sku: product.sku,
|
|
1724
1839
|
name: product.name,
|
|
1725
1840
|
price: product.price,
|
|
1726
1841
|
quantity: qty,
|
|
@@ -1739,7 +1854,7 @@ class EcommerceTracker {
|
|
|
1739
1854
|
const qty = product.quantity ?? 1;
|
|
1740
1855
|
this.aegis.track("cart_item_removed", {
|
|
1741
1856
|
product_id: product.product_id,
|
|
1742
|
-
sku: product.sku
|
|
1857
|
+
sku: product.sku,
|
|
1743
1858
|
name: product.name,
|
|
1744
1859
|
price: product.price,
|
|
1745
1860
|
quantity: qty,
|
|
@@ -1834,7 +1949,7 @@ class EcommerceTracker {
|
|
|
1834
1949
|
wishlist_id: wishlist.wishlist_id,
|
|
1835
1950
|
wishlist_name: wishlist.wishlist_name,
|
|
1836
1951
|
product_id: wishlist.product.product_id,
|
|
1837
|
-
sku: wishlist.product.sku
|
|
1952
|
+
sku: wishlist.product.sku,
|
|
1838
1953
|
name: wishlist.product.name,
|
|
1839
1954
|
price: wishlist.product.price,
|
|
1840
1955
|
variant_id: wishlist.product.variant_id
|
|
@@ -1845,7 +1960,7 @@ class EcommerceTracker {
|
|
|
1845
1960
|
wishlist_id: wishlist.wishlist_id,
|
|
1846
1961
|
wishlist_name: wishlist.wishlist_name,
|
|
1847
1962
|
product_id: wishlist.product.product_id,
|
|
1848
|
-
sku: wishlist.product.sku
|
|
1963
|
+
sku: wishlist.product.sku,
|
|
1849
1964
|
name: wishlist.product.name,
|
|
1850
1965
|
price: wishlist.product.price,
|
|
1851
1966
|
variant_id: wishlist.product.variant_id
|
|
@@ -1862,7 +1977,7 @@ class EcommerceTracker {
|
|
|
1862
1977
|
productWaitlisted(waitlist) {
|
|
1863
1978
|
this.aegis.track("product_waitlisted", {
|
|
1864
1979
|
product_id: waitlist.product.product_id,
|
|
1865
|
-
sku: waitlist.product.sku
|
|
1980
|
+
sku: waitlist.product.sku,
|
|
1866
1981
|
variant_id: waitlist.product.variant_id,
|
|
1867
1982
|
name: waitlist.product.name,
|
|
1868
1983
|
price: waitlist.product.price,
|
|
@@ -2569,6 +2684,7 @@ class Aegis {
|
|
|
2569
2684
|
if (currentUrl === this._lastPageUrl) return;
|
|
2570
2685
|
this._lastPageUrl = currentUrl;
|
|
2571
2686
|
setTimeout(() => {
|
|
2687
|
+
if (!this._popstateHandler) return;
|
|
2572
2688
|
this.page();
|
|
2573
2689
|
}, 50);
|
|
2574
2690
|
};
|
|
@@ -2617,9 +2733,13 @@ class Aegis {
|
|
|
2617
2733
|
if (!this.session) return;
|
|
2618
2734
|
const adClickIDs = parseAdClickIDs();
|
|
2619
2735
|
if (hasAdClickIDs(adClickIDs)) {
|
|
2620
|
-
this.session.setAdClickIDs(adClickIDs, window.location.href);
|
|
2736
|
+
this.session.setAdClickIDs(adClickIDs, redactUrl(window.location.href));
|
|
2621
2737
|
logger.info("Ad click IDs captured on page load:", adClickIDs);
|
|
2622
2738
|
}
|
|
2739
|
+
const linkAttribution = parseLinkAttribution();
|
|
2740
|
+
if (linkAttribution.aegis_code) {
|
|
2741
|
+
this.session.setLinkAttribution(linkAttribution);
|
|
2742
|
+
}
|
|
2623
2743
|
}
|
|
2624
2744
|
async initializePlugins() {
|
|
2625
2745
|
if (!this.config) return;
|
|
@@ -3028,26 +3148,38 @@ class Aegis {
|
|
|
3028
3148
|
}
|
|
3029
3149
|
const ctx = event.context;
|
|
3030
3150
|
const props = event.properties;
|
|
3031
|
-
if ((ctx == null ? void 0 : ctx.campaign) && props
|
|
3151
|
+
if ((ctx == null ? void 0 : ctx.campaign) && props) {
|
|
3032
3152
|
const utm = ctx.campaign;
|
|
3033
|
-
if (utm.
|
|
3034
|
-
if (utm.
|
|
3035
|
-
if (utm.
|
|
3036
|
-
if (utm.content) props.
|
|
3037
|
-
if (utm.term) props.
|
|
3153
|
+
if (utm.source && !props.utm_source) props.utm_source = utm.source;
|
|
3154
|
+
if (utm.medium && !props.utm_medium) props.utm_medium = utm.medium;
|
|
3155
|
+
if (utm.campaign && !props.utm_campaign) props.utm_campaign = utm.campaign;
|
|
3156
|
+
if (utm.content && !props.utm_content) props.utm_content = utm.content;
|
|
3157
|
+
if (utm.term && !props.utm_term) props.utm_term = utm.term;
|
|
3038
3158
|
}
|
|
3039
3159
|
if ((ctx == null ? void 0 : ctx.adClickIDs) && props) {
|
|
3040
3160
|
const clicks = ctx.adClickIDs;
|
|
3161
|
+
if (clicks.gclid && !props.gclid) props.gclid = clicks.gclid;
|
|
3162
|
+
if (clicks.gbraid && !props.gbraid) props.gbraid = clicks.gbraid;
|
|
3163
|
+
if (clicks.wbraid && !props.wbraid) props.wbraid = clicks.wbraid;
|
|
3164
|
+
if (clicks.fbclid && !props.fbclid) props.fbclid = clicks.fbclid;
|
|
3041
3165
|
const clickId = clicks.gclid || clicks.fbclid || clicks.ctwa_clid || clicks.msclkid || clicks.ttclid;
|
|
3042
3166
|
if (clickId && !props.campaign_click_id) props.campaign_click_id = clickId;
|
|
3043
3167
|
}
|
|
3168
|
+
if (props && this.session) {
|
|
3169
|
+
const link = this.session.getLinkAttribution();
|
|
3170
|
+
if (link.aegis_code) {
|
|
3171
|
+
for (const [key, value] of Object.entries(link)) {
|
|
3172
|
+
if (value && !props[key]) props[key] = value;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3044
3176
|
if (props) {
|
|
3045
3177
|
const meta = captureMetaCookies();
|
|
3046
3178
|
if (meta.fbp && !props.fbp) props.fbp = meta.fbp;
|
|
3047
3179
|
if (meta.fbc && !props.fbc) props.fbc = meta.fbc;
|
|
3048
3180
|
if (meta.fbclid && !props.fbclid) props.fbclid = meta.fbclid;
|
|
3049
3181
|
}
|
|
3050
|
-
logger.debug("Capturing event:", event);
|
|
3182
|
+
logger.debug("Capturing event:", redactMetaCookies(event));
|
|
3051
3183
|
const transformedEvent = await this.plugins.executeHookChain(
|
|
3052
3184
|
"beforeEventCapture",
|
|
3053
3185
|
event
|
|
@@ -3154,6 +3286,18 @@ class Aegis {
|
|
|
3154
3286
|
if (!this.identity) return null;
|
|
3155
3287
|
return this.identity.getUserId();
|
|
3156
3288
|
}
|
|
3289
|
+
/**
|
|
3290
|
+
* The Aegis short-link attribution captured from this visitor's landing URL
|
|
3291
|
+
* (`aegis_code` + the link row's `aegis_campaign` / `aegis_journey` /
|
|
3292
|
+
* `aegis_playbook` / `aegis_button`), or `{}` when they did not arrive
|
|
3293
|
+
* through one. Hosts forward `aegis_code` with an order so the order can be
|
|
3294
|
+
* joined to the send that brought the shopper. Never contains `utm_*`, `k`,
|
|
3295
|
+
* `t` or `u`.
|
|
3296
|
+
*/
|
|
3297
|
+
getLinkAttribution() {
|
|
3298
|
+
if (!this.session) return {};
|
|
3299
|
+
return { ...this.session.getLinkAttribution() };
|
|
3300
|
+
}
|
|
3157
3301
|
/**
|
|
3158
3302
|
* Fetch the identified contact's REDEEMABLE rewards — coupon codes the
|
|
3159
3303
|
* storefront can auto-apply at checkout + loyalty points balance/tier.
|
|
@@ -3345,6 +3489,7 @@ export {
|
|
|
3345
3489
|
Storage as S,
|
|
3346
3490
|
UserNamespace as U,
|
|
3347
3491
|
logger as l,
|
|
3348
|
-
murmurhash3_x86_32 as m
|
|
3492
|
+
murmurhash3_x86_32 as m,
|
|
3493
|
+
redactUrl as r
|
|
3349
3494
|
};
|
|
3350
|
-
//# sourceMappingURL=analytics-
|
|
3495
|
+
//# sourceMappingURL=analytics-DoHdxjjh.mjs.map
|