@xenia-martech/sdk-js 1.2.0-dev.3 → 1.2.0-dev.5
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/README.md +106 -2
- package/dist/{actions-Bhji05Pe.d.cts → actions-C18Kv-4w.d.cts} +35 -0
- package/dist/{actions-Bhji05Pe.d.ts → actions-C18Kv-4w.d.ts} +35 -0
- package/dist/{api-ByoECRhR.d.ts → api-0IycTYJR.d.cts} +1 -1
- package/dist/{api-BqSvWgBZ.d.cts → api-COXWLL5L.d.ts} +1 -1
- package/dist/{chunk-TRRMMPBH.cjs → chunk-2DR5AVPX.cjs} +10 -45
- package/dist/chunk-2DR5AVPX.cjs.map +1 -0
- package/dist/chunk-BQ5PJCZ7.js +179 -0
- package/dist/chunk-BQ5PJCZ7.js.map +1 -0
- package/dist/{chunk-INM2SPH4.js → chunk-GWRDZIVA.js} +4 -36
- package/dist/chunk-GWRDZIVA.js.map +1 -0
- package/dist/{chunk-TGG5Y4QD.js → chunk-LW5AEJ6K.js} +5 -179
- package/dist/chunk-LW5AEJ6K.js.map +1 -0
- package/dist/chunk-N5M4PI7C.cjs +192 -0
- package/dist/chunk-N5M4PI7C.cjs.map +1 -0
- package/dist/chunk-OMMIRSPK.js +336 -0
- package/dist/chunk-OMMIRSPK.js.map +1 -0
- package/dist/chunk-QEYONKWY.js +42 -0
- package/dist/chunk-QEYONKWY.js.map +1 -0
- package/dist/{chunk-YZG6JR4E.cjs → chunk-RWE2OCQL.cjs} +5 -190
- package/dist/chunk-RWE2OCQL.cjs.map +1 -0
- package/dist/chunk-WHGK55JP.cjs +46 -0
- package/dist/chunk-WHGK55JP.cjs.map +1 -0
- package/dist/chunk-YLMMTKQL.cjs +358 -0
- package/dist/chunk-YLMMTKQL.cjs.map +1 -0
- package/dist/client/index.cjs +304 -26
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +15 -4
- package/dist/client/index.d.ts +15 -4
- package/dist/client/index.js +304 -26
- package/dist/client/index.js.map +1 -1
- package/dist/client/react/index.cjs +714 -26
- package/dist/client/react/index.cjs.map +1 -1
- package/dist/client/react/index.d.cts +32 -3
- package/dist/client/react/index.d.ts +32 -3
- package/dist/client/react/index.js +715 -29
- package/dist/client/react/index.js.map +1 -1
- package/dist/cms/contentful.d.cts +2 -1
- package/dist/cms/contentful.d.ts +2 -1
- package/dist/consent-Cemn91j3.d.ts +248 -0
- package/dist/consent-DgWdjsSy.d.cts +248 -0
- package/dist/{cookie-names-Bxd-VNyJ.d.ts → cookie-names-BvUaW3uo.d.ts} +1 -1
- package/dist/{cookie-names-RXVfGYPE.d.cts → cookie-names-CnL65Oly.d.cts} +1 -1
- package/dist/edge/index.cjs +280 -0
- package/dist/edge/index.cjs.map +1 -0
- package/dist/edge/index.d.cts +61 -0
- package/dist/edge/index.d.ts +61 -0
- package/dist/edge/index.js +191 -0
- package/dist/edge/index.js.map +1 -0
- package/dist/index.cjs +41 -40
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +2 -1
- package/dist/next/index.cjs +331 -15
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +180 -6
- package/dist/next/index.d.ts +180 -6
- package/dist/next/index.js +320 -9
- package/dist/next/index.js.map +1 -1
- package/dist/personalize-content-c2DDAV6g.d.ts +140 -0
- package/dist/personalize-content-ghZPKlf1.d.cts +140 -0
- package/dist/server/index.cjs +34 -32
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +6 -5
- package/dist/server/index.d.ts +6 -5
- package/dist/server/index.js +5 -3
- package/dist/server/index.js.map +1 -1
- package/dist/{personalize-content-Bf6YZdkZ.d.cts → types-DgVHS4Qw.d.cts} +7 -138
- package/dist/{personalize-content-Bf6YZdkZ.d.ts → types-DgVHS4Qw.d.ts} +7 -138
- package/dist/xenia-sdk.iife.js +3 -3
- package/dist/xenia-sdk.iife.js.map +1 -1
- package/dist/{xenia-server-MlI3Khya.d.cts → xenia-server-C3O-cWQT.d.cts} +3 -2
- package/dist/{xenia-server-CcjQenru.d.ts → xenia-server-DV8Sjmoo.d.ts} +3 -2
- package/package.json +14 -1
- package/dist/chunk-INM2SPH4.js.map +0 -1
- package/dist/chunk-TGG5Y4QD.js.map +0 -1
- package/dist/chunk-TRRMMPBH.cjs.map +0 -1
- package/dist/chunk-YZG6JR4E.cjs.map +0 -1
|
@@ -1097,17 +1097,22 @@ function parseDataAttribute(value) {
|
|
|
1097
1097
|
return { eventId, interactionType };
|
|
1098
1098
|
}
|
|
1099
1099
|
function readSlotMeta(el) {
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
const contentEntryId =
|
|
1103
|
-
|
|
1104
|
-
const personalized =
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1100
|
+
const attr = (name) => el.getAttribute(`data-xenia-${name}`) ?? void 0;
|
|
1101
|
+
const contentKey = attr("content-key");
|
|
1102
|
+
const contentEntryId = attr("content-entry-id");
|
|
1103
|
+
if (!contentKey && !contentEntryId) return null;
|
|
1104
|
+
const personalized = attr("personalized");
|
|
1105
|
+
const meta2 = {};
|
|
1106
|
+
const slot = attr("slot");
|
|
1107
|
+
if (slot) meta2.slot = slot;
|
|
1108
|
+
if (contentKey) meta2.contentKey = contentKey;
|
|
1109
|
+
if (contentEntryId) meta2.contentEntryId = contentEntryId;
|
|
1110
|
+
const baseEntryId = attr("base-entry-id");
|
|
1111
|
+
if (baseEntryId) meta2.baseEntryId = baseEntryId;
|
|
1112
|
+
if (personalized != null) meta2.personalized = personalized === "true";
|
|
1113
|
+
const bucket = attr("bucket");
|
|
1114
|
+
if (bucket) meta2.bucket = bucket;
|
|
1115
|
+
return meta2;
|
|
1111
1116
|
}
|
|
1112
1117
|
var AutoTracker = class {
|
|
1113
1118
|
opts;
|
|
@@ -1168,8 +1173,12 @@ var AutoTracker = class {
|
|
|
1168
1173
|
if (this.opts.fireSlot) {
|
|
1169
1174
|
const slot = target.closest("[data-xenia-slot]");
|
|
1170
1175
|
if (slot) {
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1176
|
+
const meta2 = readSlotMeta(slot);
|
|
1177
|
+
const found = target.closest("a, button");
|
|
1178
|
+
const control = found && slot.contains(found) ? found : null;
|
|
1179
|
+
if (!control && this.opts.slotClicks === "controls") return;
|
|
1180
|
+
const label = control ? (control.textContent ?? "").trim().slice(0, 60) : "";
|
|
1181
|
+
if (meta2 && !this.throttled(slot)) this.opts.fireSlot("click", label ? { ...meta2, label } : meta2);
|
|
1173
1182
|
}
|
|
1174
1183
|
}
|
|
1175
1184
|
};
|
|
@@ -1177,24 +1186,24 @@ var AutoTracker = class {
|
|
|
1177
1186
|
}
|
|
1178
1187
|
observeSlot(el) {
|
|
1179
1188
|
if (!this.opts.fireSlot || this.slotObservers.has(el)) return;
|
|
1180
|
-
const
|
|
1181
|
-
if (!
|
|
1189
|
+
const meta2 = readSlotMeta(el);
|
|
1190
|
+
if (!meta2) return;
|
|
1182
1191
|
const fireSlot = this.opts.fireSlot;
|
|
1183
1192
|
const { threshold, rootMargin } = this.opts.viewport;
|
|
1184
1193
|
const observer = new IntersectionObserver(
|
|
1185
1194
|
(entries) => {
|
|
1186
1195
|
for (const entry of entries) {
|
|
1187
|
-
|
|
1188
|
-
if (this.slotImpressed.has(el)) continue;
|
|
1196
|
+
const inView = entry.isIntersecting && (entry.intersectionRatio >= threshold || entry.intersectionRect.height >= window.innerHeight / 2);
|
|
1197
|
+
if (!inView || this.slotImpressed.has(el)) continue;
|
|
1189
1198
|
this.slotImpressed.add(el);
|
|
1190
|
-
fireSlot("impression",
|
|
1199
|
+
fireSlot("impression", meta2);
|
|
1191
1200
|
observer.disconnect();
|
|
1192
1201
|
this.slotObservers.delete(el);
|
|
1193
1202
|
}
|
|
1194
1203
|
},
|
|
1195
|
-
{ threshold, rootMargin }
|
|
1204
|
+
{ threshold: [.../* @__PURE__ */ new Set([0.1, 0.25, threshold])].sort(), rootMargin }
|
|
1196
1205
|
);
|
|
1197
|
-
observer.observe(el);
|
|
1206
|
+
observer.observe(boxOf(el));
|
|
1198
1207
|
this.slotObservers.set(el, observer);
|
|
1199
1208
|
}
|
|
1200
1209
|
observeViewport(el, eventId) {
|
|
@@ -1248,6 +1257,235 @@ var AutoTracker = class {
|
|
|
1248
1257
|
this.mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
1249
1258
|
}
|
|
1250
1259
|
};
|
|
1260
|
+
function boxOf(el) {
|
|
1261
|
+
if (typeof getComputedStyle !== "function") return el;
|
|
1262
|
+
return getComputedStyle(el).display === "contents" ? el.firstElementChild ?? el : el;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
// src/edge/trail.ts
|
|
1266
|
+
var MAX_TRAIL = 8;
|
|
1267
|
+
var TRAIL_MAX_AGE_S = 30 * 60;
|
|
1268
|
+
function trailCookieName(prefix = DEFAULT_PREFIX) {
|
|
1269
|
+
return `${prefix}_trail`;
|
|
1270
|
+
}
|
|
1271
|
+
var decode = (v) => {
|
|
1272
|
+
try {
|
|
1273
|
+
return decodeURIComponent(v);
|
|
1274
|
+
} catch {
|
|
1275
|
+
return v;
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
function readTrail(value) {
|
|
1279
|
+
if (!value) return [];
|
|
1280
|
+
try {
|
|
1281
|
+
const parsed = JSON.parse(decode(value));
|
|
1282
|
+
if (!Array.isArray(parsed)) return [];
|
|
1283
|
+
return parsed.filter((t) => Array.isArray(t) && typeof t[0] === "string" && typeof t[1] === "number").slice(0, MAX_TRAIL).map(
|
|
1284
|
+
([path, at, seconds]) => typeof seconds === "number" && seconds >= 0 && seconds <= 86400 ? { path, at, seconds } : { path, at }
|
|
1285
|
+
);
|
|
1286
|
+
} catch {
|
|
1287
|
+
return [];
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
function withView(trail, path, now = Date.now()) {
|
|
1291
|
+
if (trail[0]?.path === path) return trail;
|
|
1292
|
+
const earlier = trail.find((t) => t.path === path);
|
|
1293
|
+
return [{ path, at: earlier?.at ?? now }, ...trail.filter((t) => t.path !== path)].slice(0, MAX_TRAIL);
|
|
1294
|
+
}
|
|
1295
|
+
function trailCookieValue(trail) {
|
|
1296
|
+
return JSON.stringify(
|
|
1297
|
+
trail.slice(0, MAX_TRAIL).map((t) => t.seconds === void 0 ? [t.path, t.at] : [t.path, t.at, t.seconds])
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// src/client/page-tracking.ts
|
|
1302
|
+
var SETTLE_MS = 3e3;
|
|
1303
|
+
var POLL_MS = 50;
|
|
1304
|
+
var MIN_VISIT_MS = 250;
|
|
1305
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
1306
|
+
var restore = null;
|
|
1307
|
+
function watchNavigation(listener) {
|
|
1308
|
+
listeners.add(listener);
|
|
1309
|
+
if (!restore) {
|
|
1310
|
+
const { pushState, replaceState } = history;
|
|
1311
|
+
const notify = () => listeners.forEach((l) => {
|
|
1312
|
+
try {
|
|
1313
|
+
l();
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
const ownPush = function(...args) {
|
|
1318
|
+
pushState.apply(this, args);
|
|
1319
|
+
notify();
|
|
1320
|
+
};
|
|
1321
|
+
const ownReplace = function(...args) {
|
|
1322
|
+
replaceState.apply(this, args);
|
|
1323
|
+
notify();
|
|
1324
|
+
};
|
|
1325
|
+
history.pushState = ownPush;
|
|
1326
|
+
history.replaceState = ownReplace;
|
|
1327
|
+
window.addEventListener("popstate", notify);
|
|
1328
|
+
restore = () => {
|
|
1329
|
+
if (history.pushState !== ownPush || history.replaceState !== ownReplace) return false;
|
|
1330
|
+
history.pushState = pushState;
|
|
1331
|
+
history.replaceState = replaceState;
|
|
1332
|
+
window.removeEventListener("popstate", notify);
|
|
1333
|
+
return true;
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
return () => {
|
|
1337
|
+
listeners.delete(listener);
|
|
1338
|
+
if (!listeners.size && restore?.()) restore = null;
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
var meta = (name) => document.querySelector(`meta[name="${name}"]`)?.content || void 0;
|
|
1342
|
+
function startPageTracking(client, opts) {
|
|
1343
|
+
let path = location.pathname;
|
|
1344
|
+
let lastTitle = null;
|
|
1345
|
+
let timer;
|
|
1346
|
+
let view2 = { path, since: visibleNow(), sent: false };
|
|
1347
|
+
function visibleNow() {
|
|
1348
|
+
return document.visibilityState === "visible" ? Date.now() : null;
|
|
1349
|
+
}
|
|
1350
|
+
function sendView() {
|
|
1351
|
+
clearTimeout(timer);
|
|
1352
|
+
const started = Date.now();
|
|
1353
|
+
const tick = () => {
|
|
1354
|
+
const settled = document.title !== "" && document.title !== lastTitle;
|
|
1355
|
+
if (!settled && Date.now() - started < SETTLE_MS) {
|
|
1356
|
+
timer = setTimeout(tick, POLL_MS);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
const params = new URLSearchParams(location.search);
|
|
1360
|
+
const searchTerm = (params.get("utm_term") ?? params.get("q") ?? "").slice(0, 120);
|
|
1361
|
+
const category = meta("xenia-category");
|
|
1362
|
+
lastTitle = document.title;
|
|
1363
|
+
client.track("pageView", {
|
|
1364
|
+
title: (meta("xenia-title") ?? document.title).slice(0, 160),
|
|
1365
|
+
...searchTerm ? { searchTerm } : {},
|
|
1366
|
+
...category ? { category } : {}
|
|
1367
|
+
});
|
|
1368
|
+
};
|
|
1369
|
+
timer = setTimeout(tick, 0);
|
|
1370
|
+
}
|
|
1371
|
+
function leave() {
|
|
1372
|
+
if (view2.sent || view2.since === null || Date.now() - view2.since < MIN_VISIT_MS) return;
|
|
1373
|
+
view2.sent = true;
|
|
1374
|
+
client.track("page_leave", { path: view2.path, durationMs: Date.now() - view2.since });
|
|
1375
|
+
}
|
|
1376
|
+
const onNavigate = () => {
|
|
1377
|
+
if (location.pathname === path) return;
|
|
1378
|
+
if (opts.pageLeave) leave();
|
|
1379
|
+
path = location.pathname;
|
|
1380
|
+
view2 = { path, since: visibleNow(), sent: false };
|
|
1381
|
+
if (opts.pageViews) sendView();
|
|
1382
|
+
};
|
|
1383
|
+
const onVisibility = () => {
|
|
1384
|
+
if (document.visibilityState === "hidden") leave();
|
|
1385
|
+
else if (view2.since === null) view2.since = Date.now();
|
|
1386
|
+
};
|
|
1387
|
+
const unwatch = watchNavigation(onNavigate);
|
|
1388
|
+
if (opts.pageLeave) document.addEventListener("visibilitychange", onVisibility);
|
|
1389
|
+
if (opts.pageViews) sendView();
|
|
1390
|
+
return () => {
|
|
1391
|
+
clearTimeout(timer);
|
|
1392
|
+
unwatch();
|
|
1393
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// src/client/engagement.ts
|
|
1398
|
+
var rootOf = (opt, fallback) => typeof opt === "object" && opt.root || fallback;
|
|
1399
|
+
function readCookie(name) {
|
|
1400
|
+
return document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))?.[1];
|
|
1401
|
+
}
|
|
1402
|
+
function writeCookie(name, value) {
|
|
1403
|
+
try {
|
|
1404
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${TRAIL_MAX_AGE_S}; samesite=lax`;
|
|
1405
|
+
} catch {
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
function sectionOf(link) {
|
|
1409
|
+
if (!link || link.origin !== location.origin) return void 0;
|
|
1410
|
+
return link.pathname.split("/").filter(Boolean)[0];
|
|
1411
|
+
}
|
|
1412
|
+
function cardImage(target, root) {
|
|
1413
|
+
let el = target;
|
|
1414
|
+
for (let depth = 0; el && depth < 5 && el !== root; depth++, el = el.parentElement) {
|
|
1415
|
+
const imgs = [...el.querySelectorAll("img")].filter((i) => i.alt.trim());
|
|
1416
|
+
if (!imgs.length) continue;
|
|
1417
|
+
return new Set(imgs.map((i) => i.alt.trim())).size === 1 ? imgs[0] : null;
|
|
1418
|
+
}
|
|
1419
|
+
return null;
|
|
1420
|
+
}
|
|
1421
|
+
function startEngagement(client, opts) {
|
|
1422
|
+
const trailName = trailCookieName(opts.prefix);
|
|
1423
|
+
const clicksName = `${opts.prefix}_clicks`;
|
|
1424
|
+
const visibleNow = () => document.visibilityState === "visible" ? Date.now() : null;
|
|
1425
|
+
let current = { path: location.pathname, since: visibleNow(), stamped: false };
|
|
1426
|
+
const stamp = () => {
|
|
1427
|
+
if (current.stamped || !opts.trail || !opts.analyticsAllowed() || current.since === null) return;
|
|
1428
|
+
current.stamped = true;
|
|
1429
|
+
const seconds = Math.round((Date.now() - current.since) / 100) / 10;
|
|
1430
|
+
const trail = readTrail(readCookie(trailName));
|
|
1431
|
+
const i = trail.findIndex((t) => t.path === current.path);
|
|
1432
|
+
if (i < 0) return;
|
|
1433
|
+
trail[i] = { ...trail[i], seconds };
|
|
1434
|
+
writeCookie(trailName, trailCookieValue(trail));
|
|
1435
|
+
};
|
|
1436
|
+
const onNavigate = () => {
|
|
1437
|
+
if (location.pathname === current.path) return;
|
|
1438
|
+
stamp();
|
|
1439
|
+
current = { path: location.pathname, since: visibleNow(), stamped: false };
|
|
1440
|
+
if (!opts.trail || !opts.analyticsAllowed()) return;
|
|
1441
|
+
const trail = readTrail(readCookie(trailName));
|
|
1442
|
+
const next = withView(trail, current.path);
|
|
1443
|
+
if (next !== trail) writeCookie(trailName, trailCookieValue(next));
|
|
1444
|
+
};
|
|
1445
|
+
const onVisible = () => {
|
|
1446
|
+
if (document.visibilityState === "visible" && current.since === null) current.since = Date.now();
|
|
1447
|
+
};
|
|
1448
|
+
const onLeaveClick = (e) => {
|
|
1449
|
+
const link = e.target?.closest?.("a[href]");
|
|
1450
|
+
if (link && link.origin === location.origin && link.pathname !== location.pathname) stamp();
|
|
1451
|
+
};
|
|
1452
|
+
const bump = () => {
|
|
1453
|
+
if (!opts.analyticsAllowed()) return;
|
|
1454
|
+
writeCookie(clicksName, String((Number(readCookie(clicksName)) || 0) + 1));
|
|
1455
|
+
};
|
|
1456
|
+
const navRoot = rootOf(opts.navClicks, "header");
|
|
1457
|
+
const contentRoot = rootOf(opts.contentClicks, "main");
|
|
1458
|
+
const onClick = (e) => {
|
|
1459
|
+
const target = e.target;
|
|
1460
|
+
if (!target?.closest) return;
|
|
1461
|
+
const nav = opts.navClicks ? target.closest(`${navRoot} a[href]`) : null;
|
|
1462
|
+
if (nav) {
|
|
1463
|
+
const category2 = sectionOf(nav);
|
|
1464
|
+
if (!category2) return;
|
|
1465
|
+
client.track("nav_click", { category: category2, label: (nav.textContent ?? "").trim().slice(0, 60) });
|
|
1466
|
+
bump();
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
const root = opts.contentClicks ? target.closest(contentRoot) : null;
|
|
1470
|
+
if (!root) return;
|
|
1471
|
+
const img = target.closest("img") ?? cardImage(target, root);
|
|
1472
|
+
const label = (img?.alt ?? "").trim().slice(0, 160);
|
|
1473
|
+
if (!label) return;
|
|
1474
|
+
const category = sectionOf(target.closest("a[href]"));
|
|
1475
|
+
client.track("content_click", category ? { label, category } : { label });
|
|
1476
|
+
bump();
|
|
1477
|
+
};
|
|
1478
|
+
const unwatch = watchNavigation(onNavigate);
|
|
1479
|
+
window.addEventListener("click", onLeaveClick, { capture: true });
|
|
1480
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
1481
|
+
if (opts.contentClicks || opts.navClicks) document.addEventListener("click", onClick, { capture: true });
|
|
1482
|
+
return () => {
|
|
1483
|
+
unwatch();
|
|
1484
|
+
window.removeEventListener("click", onLeaveClick, { capture: true });
|
|
1485
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
1486
|
+
document.removeEventListener("click", onClick, { capture: true });
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1251
1489
|
|
|
1252
1490
|
// src/server/cookies.ts
|
|
1253
1491
|
function parseCookies(header) {
|
|
@@ -1258,7 +1496,12 @@ function parseCookies(header) {
|
|
|
1258
1496
|
if (idx === -1) continue;
|
|
1259
1497
|
const key = part.slice(0, idx).trim();
|
|
1260
1498
|
const value = part.slice(idx + 1).trim();
|
|
1261
|
-
if (key)
|
|
1499
|
+
if (!key) continue;
|
|
1500
|
+
try {
|
|
1501
|
+
out[key] = decodeURIComponent(value);
|
|
1502
|
+
} catch {
|
|
1503
|
+
out[key] = value;
|
|
1504
|
+
}
|
|
1262
1505
|
}
|
|
1263
1506
|
return out;
|
|
1264
1507
|
}
|
|
@@ -1332,6 +1575,14 @@ var Identity = class {
|
|
|
1332
1575
|
const storageKey = this.key("device_id");
|
|
1333
1576
|
try {
|
|
1334
1577
|
const cached = localStorage.getItem(storageKey);
|
|
1578
|
+
const fromServer = this.cookie?.authoritative ? this.readVisitorCookie() : null;
|
|
1579
|
+
const effective = localStorage.getItem(this.key("visitor_id")) ?? cached;
|
|
1580
|
+
if (cached && fromServer && fromServer !== effective) {
|
|
1581
|
+
this.deviceId = fromServer;
|
|
1582
|
+
localStorage.setItem(storageKey, fromServer);
|
|
1583
|
+
if (localStorage.getItem(this.key("visitor_id"))) localStorage.setItem(this.key("visitor_id"), fromServer);
|
|
1584
|
+
return fromServer;
|
|
1585
|
+
}
|
|
1335
1586
|
if (cached) {
|
|
1336
1587
|
this.deviceId = cached;
|
|
1337
1588
|
this.writeVisitorCookie(this.getVisitorId() ?? cached);
|
|
@@ -1511,7 +1762,7 @@ function resolveCookieConfig(opt) {
|
|
|
1511
1762
|
const o = opt === true ? {} : opt;
|
|
1512
1763
|
const sameSite = o.sameSite ?? "Lax";
|
|
1513
1764
|
const secure = sameSite === "None" ? true : o.secure ?? false;
|
|
1514
|
-
return { sameSite, secure, maxAgeDays: o.maxAgeDays ?? 365, domain: o.domain };
|
|
1765
|
+
return { sameSite, secure, maxAgeDays: o.maxAgeDays ?? 365, domain: o.domain, authoritative: o.authoritative ?? false };
|
|
1515
1766
|
}
|
|
1516
1767
|
|
|
1517
1768
|
// src/client/widgets/form.ts
|
|
@@ -2195,6 +2446,8 @@ var XeniaClient = class {
|
|
|
2195
2446
|
renderer;
|
|
2196
2447
|
analyticsQueue;
|
|
2197
2448
|
tracker = null;
|
|
2449
|
+
stopPageTracking = null;
|
|
2450
|
+
stopEngagement = null;
|
|
2198
2451
|
/** The in-flight (or finished) boot; shared so concurrent `init()` calls start one tracker. */
|
|
2199
2452
|
booting = null;
|
|
2200
2453
|
/** Bumped by `destroy()`, so a boot still waiting on the device id knows to stop. */
|
|
@@ -2246,17 +2499,21 @@ var XeniaClient = class {
|
|
|
2246
2499
|
rootMargin: this.options.viewport?.rootMargin,
|
|
2247
2500
|
triggerOnce: this.options.viewport?.triggerOnce ?? true
|
|
2248
2501
|
},
|
|
2502
|
+
slotClicks: this.options.slotClicks,
|
|
2249
2503
|
// Declarative `data-xenia` elements fire journey triggers (immediate).
|
|
2250
2504
|
fire: (eventId, interaction) => this.track(eventId, { interactionType: interaction }, { trigger: true }),
|
|
2251
2505
|
// `[data-xenia-slot]` elements fire analytics-only personalization events.
|
|
2252
|
-
fireSlot: (interaction,
|
|
2506
|
+
fireSlot: (interaction, meta2) => {
|
|
2253
2507
|
this.track(
|
|
2254
2508
|
"customEvent",
|
|
2255
2509
|
{
|
|
2256
2510
|
customEventName: interaction === "impression" ? "personalization_impression" : "personalization_click",
|
|
2257
|
-
contentKey:
|
|
2258
|
-
contentEntryId:
|
|
2259
|
-
baseEntryId:
|
|
2511
|
+
...meta2.contentKey ? { contentKey: meta2.contentKey } : {},
|
|
2512
|
+
contentEntryId: meta2.contentEntryId ?? null,
|
|
2513
|
+
baseEntryId: meta2.baseEntryId ?? null,
|
|
2514
|
+
...meta2.bucket ? { bucket: meta2.bucket } : {},
|
|
2515
|
+
...meta2.slot ? { slot: meta2.slot } : {},
|
|
2516
|
+
...meta2.label ? { label: meta2.label } : {}
|
|
2260
2517
|
},
|
|
2261
2518
|
{ trigger: false }
|
|
2262
2519
|
);
|
|
@@ -2264,11 +2521,32 @@ var XeniaClient = class {
|
|
|
2264
2521
|
});
|
|
2265
2522
|
this.tracker.start();
|
|
2266
2523
|
}
|
|
2524
|
+
const { pageViews = false, pageLeave = false } = this.options;
|
|
2525
|
+
if (pageViews || pageLeave) {
|
|
2526
|
+
this.stopPageTracking = startPageTracking({ track: (name, props) => this.track(name, props) }, { pageViews, pageLeave });
|
|
2527
|
+
}
|
|
2528
|
+
const { trail = false, contentClicks = false, navClicks = false } = this.options;
|
|
2529
|
+
if (trail || contentClicks || navClicks) {
|
|
2530
|
+
this.stopEngagement = startEngagement(
|
|
2531
|
+
{ track: (name, props) => this.track(name, props) },
|
|
2532
|
+
{
|
|
2533
|
+
trail,
|
|
2534
|
+
contentClicks,
|
|
2535
|
+
navClicks,
|
|
2536
|
+
prefix: this.options.prefix ?? "xenia",
|
|
2537
|
+
analyticsAllowed: () => this.analyticsAllowed() && !this.dntBlocked()
|
|
2538
|
+
}
|
|
2539
|
+
);
|
|
2540
|
+
}
|
|
2267
2541
|
}
|
|
2268
2542
|
/** Tear down listeners, observers, and injected UI. */
|
|
2269
2543
|
destroy() {
|
|
2270
2544
|
this.tracker?.stop();
|
|
2271
2545
|
this.tracker = null;
|
|
2546
|
+
this.stopPageTracking?.();
|
|
2547
|
+
this.stopPageTracking = null;
|
|
2548
|
+
this.stopEngagement?.();
|
|
2549
|
+
this.stopEngagement = null;
|
|
2272
2550
|
this.renderer.destroy();
|
|
2273
2551
|
this.analyticsQueue.stop();
|
|
2274
2552
|
this.booting = null;
|
|
@@ -2966,13 +3244,423 @@ function reactMessageComponent(Component) {
|
|
|
2966
3244
|
};
|
|
2967
3245
|
}
|
|
2968
3246
|
|
|
3247
|
+
// src/edge/debug-entries.ts
|
|
3248
|
+
function readDebugEntries(raw) {
|
|
3249
|
+
if (!raw) return {};
|
|
3250
|
+
try {
|
|
3251
|
+
let text = decodeURIComponent(raw);
|
|
3252
|
+
if (text.startsWith("%")) text = decodeURIComponent(text);
|
|
3253
|
+
const parsed = JSON.parse(text);
|
|
3254
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
3255
|
+
} catch {
|
|
3256
|
+
return {};
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
var str = (v) => typeof v === "string" || typeof v === "number" ? String(v) : "";
|
|
3260
|
+
var isObject2 = (v) => Boolean(v) && typeof v === "object" && !Array.isArray(v);
|
|
3261
|
+
var strings = (v) => Array.isArray(v) ? v.map(str).filter(Boolean) : [];
|
|
3262
|
+
function view(e) {
|
|
3263
|
+
const decisions = (Array.isArray(e.decisions) ? e.decisions : []).filter(isObject2).map((d) => ({
|
|
3264
|
+
key: str(d.key),
|
|
3265
|
+
result: str(d.result) || "base",
|
|
3266
|
+
reason: str(d.reason),
|
|
3267
|
+
trace: isObject2(d.trace) ? Object.entries(d.trace).map(([step, outcome]) => [step, str(outcome)]) : []
|
|
3268
|
+
}));
|
|
3269
|
+
const p = isObject2(e.profile) ? e.profile : void 0;
|
|
3270
|
+
const answers = isObject2(p?.answers) ? Object.entries(p.answers).flatMap(
|
|
3271
|
+
([name, a]) => isObject2(a) ? [{
|
|
3272
|
+
name,
|
|
3273
|
+
choice: str(a.choice),
|
|
3274
|
+
source: str(a.source),
|
|
3275
|
+
confidence: typeof a.confidence === "number" ? a.confidence : void 0,
|
|
3276
|
+
model: str(a.model),
|
|
3277
|
+
scores: isObject2(a.scores) ? Object.entries(a.scores).filter((x) => typeof x[1] === "number").sort((x, y) => y[1] - x[1]) : []
|
|
3278
|
+
}] : []
|
|
3279
|
+
) : [];
|
|
3280
|
+
const r = isObject2(e.request) ? e.request : {};
|
|
3281
|
+
const geoOf = (g) => isObject2(g) ? Object.fromEntries(Object.entries(g).map(([k, v]) => [k, str(v)])) : void 0;
|
|
3282
|
+
const consent = isObject2(r.consent) ? r.consent : void 0;
|
|
3283
|
+
const custom = isObject2(e.custom) ? Object.entries(e.custom).flatMap(
|
|
3284
|
+
([label, value]) => Array.isArray(value) ? [{ label, lines: strings(value) }] : str(value) ? [{ label, lines: [str(value)] }] : []
|
|
3285
|
+
) : [];
|
|
3286
|
+
return {
|
|
3287
|
+
page: str(e.page),
|
|
3288
|
+
source: str(e.source),
|
|
3289
|
+
ms: typeof e.ms === "number" ? e.ms : void 0,
|
|
3290
|
+
decisions,
|
|
3291
|
+
profile: p ? { pageViews: typeof p.pageViews === "number" ? p.pageViews : 0, lastSection: str(p.lastSection), campaign: str(p.campaign), answers } : void 0,
|
|
3292
|
+
request: {
|
|
3293
|
+
location: geoOf(r.location),
|
|
3294
|
+
detected: geoOf(r.detected),
|
|
3295
|
+
via: str(r.via),
|
|
3296
|
+
seen: strings(r.seen),
|
|
3297
|
+
device: str(r.device),
|
|
3298
|
+
localTime: str(r.localTime),
|
|
3299
|
+
consent: consent ? { personalization: consent.personalization !== false, analytics: consent.analytics !== false } : void 0
|
|
3300
|
+
},
|
|
3301
|
+
custom
|
|
3302
|
+
};
|
|
3303
|
+
}
|
|
3304
|
+
var changed = (result) => !/^(base|control|suppressed)\b/.test(result);
|
|
3305
|
+
function debugStatus(entry) {
|
|
3306
|
+
const v = view(entry);
|
|
3307
|
+
if (v.source === "timeout" || v.source === "error") return "attention";
|
|
3308
|
+
return v.decisions.some((d) => changed(d.result)) ? "personalized" : "base";
|
|
3309
|
+
}
|
|
3310
|
+
var STATUS_LABEL = {
|
|
3311
|
+
personalized: "personalized",
|
|
3312
|
+
base: "showing base content",
|
|
3313
|
+
attention: "couldn't decide"
|
|
3314
|
+
};
|
|
3315
|
+
var SOURCE_CHIP = {
|
|
3316
|
+
xenia: "Live",
|
|
3317
|
+
cache: "Cached",
|
|
3318
|
+
timeout: "Timed out",
|
|
3319
|
+
error: "Error",
|
|
3320
|
+
"site page": "Site page",
|
|
3321
|
+
"not targeted": "Not targeted",
|
|
3322
|
+
"no consent": "No consent"
|
|
3323
|
+
};
|
|
3324
|
+
function sourceChip(source) {
|
|
3325
|
+
const known = SOURCE_CHIP[source] ?? Object.entries(SOURCE_CHIP).find(([k]) => source.startsWith(`${k} `))?.[1];
|
|
3326
|
+
if (known) return known;
|
|
3327
|
+
return source ? source[0].toUpperCase() + source.slice(1) : "Unknown";
|
|
3328
|
+
}
|
|
3329
|
+
function readEntry(prefix) {
|
|
3330
|
+
const raw = document.cookie.match(new RegExp(`(?:^|;\\s*)${prefix}_debug=([^;]+)`))?.[1];
|
|
3331
|
+
return readDebugEntries(raw)[location.pathname] ?? null;
|
|
3332
|
+
}
|
|
3333
|
+
var OPEN_KEY = "xenia_debug_open";
|
|
3334
|
+
var TAB_KEY = "xenia_debug_tab";
|
|
3335
|
+
function Mark({ size }) {
|
|
3336
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 32 20", "aria-hidden": "true", focusable: "false", children: [
|
|
3337
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "9", fill: "#3EC6FF" }),
|
|
3338
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "22", cy: "10", r: "9", fill: "#97CF49" })
|
|
3339
|
+
] });
|
|
3340
|
+
}
|
|
3341
|
+
function Id({ value }) {
|
|
3342
|
+
return value.length > 14 && /^[0-9a-f-]+$/i.test(value) ? /* @__PURE__ */ jsxRuntime.jsxs("span", { title: value, children: [
|
|
3343
|
+
value.slice(0, 8),
|
|
3344
|
+
"\u2026"
|
|
3345
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: value });
|
|
3346
|
+
}
|
|
3347
|
+
var percent = (n) => `${Math.round(n <= 1 ? n * 100 : n)}%`;
|
|
3348
|
+
function XeniaDebugPanel({ prefix = DEFAULT_PREFIX, position = "bottom-right", renderExtra }) {
|
|
3349
|
+
const [entry, setEntry] = react.useState(null);
|
|
3350
|
+
const [open, setOpen] = react.useState(false);
|
|
3351
|
+
const [tab, setTab] = react.useState("Decision");
|
|
3352
|
+
const root = react.useRef(null);
|
|
3353
|
+
const launcher = react.useRef(null);
|
|
3354
|
+
const card = react.useRef(null);
|
|
3355
|
+
const tabRefs = react.useRef({});
|
|
3356
|
+
const id = react.useId();
|
|
3357
|
+
react.useEffect(() => {
|
|
3358
|
+
let timer;
|
|
3359
|
+
const read = () => setEntry(readEntry(prefix));
|
|
3360
|
+
const onNavigate = () => {
|
|
3361
|
+
clearTimeout(timer);
|
|
3362
|
+
setTimeout(read, 0);
|
|
3363
|
+
timer = setTimeout(read, 300);
|
|
3364
|
+
};
|
|
3365
|
+
read();
|
|
3366
|
+
try {
|
|
3367
|
+
setOpen(sessionStorage.getItem(OPEN_KEY) === "1");
|
|
3368
|
+
const saved = sessionStorage.getItem(TAB_KEY);
|
|
3369
|
+
if (saved === "Decision" || saved === "Visitor" || saved === "Request" || saved === "Site") setTab(saved);
|
|
3370
|
+
} catch {
|
|
3371
|
+
}
|
|
3372
|
+
const unwatch = watchNavigation(onNavigate);
|
|
3373
|
+
return () => {
|
|
3374
|
+
clearTimeout(timer);
|
|
3375
|
+
unwatch();
|
|
3376
|
+
};
|
|
3377
|
+
}, [prefix]);
|
|
3378
|
+
const toggle = react.useCallback((next, focusLauncher = false) => {
|
|
3379
|
+
setOpen(next);
|
|
3380
|
+
if (focusLauncher) launcher.current?.focus();
|
|
3381
|
+
remember(OPEN_KEY, next ? "1" : "0");
|
|
3382
|
+
}, []);
|
|
3383
|
+
react.useEffect(() => {
|
|
3384
|
+
if (!open) return;
|
|
3385
|
+
card.current?.focus();
|
|
3386
|
+
const onKey = (e) => {
|
|
3387
|
+
if (e.key === "Escape" && root.current?.contains(document.activeElement)) toggle(false, true);
|
|
3388
|
+
};
|
|
3389
|
+
const onDown = (e) => {
|
|
3390
|
+
if (root.current && !root.current.contains(e.target)) toggle(false);
|
|
3391
|
+
};
|
|
3392
|
+
document.addEventListener("keydown", onKey);
|
|
3393
|
+
document.addEventListener("mousedown", onDown);
|
|
3394
|
+
return () => {
|
|
3395
|
+
document.removeEventListener("keydown", onKey);
|
|
3396
|
+
document.removeEventListener("mousedown", onDown);
|
|
3397
|
+
};
|
|
3398
|
+
}, [open, toggle]);
|
|
3399
|
+
if (!entry) return null;
|
|
3400
|
+
const status = debugStatus(entry);
|
|
3401
|
+
const v = view(entry);
|
|
3402
|
+
const tabs = ["Decision", "Visitor", "Request", ...v.custom.length || renderExtra ? ["Site"] : []];
|
|
3403
|
+
const current = tabs.includes(tab) ? tab : "Decision";
|
|
3404
|
+
const [vertical, horizontal] = position.split("-");
|
|
3405
|
+
const choose = (t, focus = false) => {
|
|
3406
|
+
setTab(t);
|
|
3407
|
+
remember(TAB_KEY, t);
|
|
3408
|
+
if (focus) tabRefs.current[t]?.focus();
|
|
3409
|
+
};
|
|
3410
|
+
const onTabKey = (e) => {
|
|
3411
|
+
const i = tabs.indexOf(current);
|
|
3412
|
+
const next = e.key === "ArrowRight" ? tabs[(i + 1) % tabs.length] : e.key === "ArrowLeft" ? tabs[(i - 1 + tabs.length) % tabs.length] : null;
|
|
3413
|
+
if (next) {
|
|
3414
|
+
e.preventDefault();
|
|
3415
|
+
choose(next, true);
|
|
3416
|
+
}
|
|
3417
|
+
};
|
|
3418
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: root, className: "xdp", "data-vertical": vertical, "data-horizontal": horizontal, children: [
|
|
3419
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { children: STYLES2 }),
|
|
3420
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3421
|
+
"button",
|
|
3422
|
+
{
|
|
3423
|
+
ref: launcher,
|
|
3424
|
+
type: "button",
|
|
3425
|
+
className: "xdp-launcher",
|
|
3426
|
+
"data-status": status,
|
|
3427
|
+
"aria-label": `Xenia personalization: ${STATUS_LABEL[status]}`,
|
|
3428
|
+
"aria-expanded": open,
|
|
3429
|
+
"aria-controls": open ? `${id}-card` : void 0,
|
|
3430
|
+
onClick: () => toggle(!open),
|
|
3431
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 24 })
|
|
3432
|
+
}
|
|
3433
|
+
),
|
|
3434
|
+
open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: card, id: `${id}-card`, role: "dialog", "aria-label": "Xenia personalization", tabIndex: -1, className: "xdp-card", children: [
|
|
3435
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "xdp-head", children: [
|
|
3436
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-head-row", children: [
|
|
3437
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-pill", "data-status": status, children: status === "personalized" ? "Personalized" : "Base content" }),
|
|
3438
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-chip", title: v.source, children: sourceChip(v.source) }),
|
|
3439
|
+
typeof v.ms === "number" && v.source === "xenia" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "xdp-ms", children: [
|
|
3440
|
+
v.ms,
|
|
3441
|
+
" ms"
|
|
3442
|
+
] }) : null
|
|
3443
|
+
] }),
|
|
3444
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "xdp-path", title: v.page, children: v.page }),
|
|
3445
|
+
status === "attention" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "xdp-alert", children: v.source === "timeout" ? "Xenia didn't answer within the time budget." : "The decision failed; the proxy's onError has the cause." }) : null
|
|
3446
|
+
] }),
|
|
3447
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": "Details", className: "xdp-tabs", children: tabs.map((t) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3448
|
+
"button",
|
|
3449
|
+
{
|
|
3450
|
+
ref: (el) => {
|
|
3451
|
+
tabRefs.current[t] = el;
|
|
3452
|
+
},
|
|
3453
|
+
type: "button",
|
|
3454
|
+
role: "tab",
|
|
3455
|
+
id: `${id}-tab-${t}`,
|
|
3456
|
+
"aria-selected": current === t,
|
|
3457
|
+
"aria-controls": `${id}-panel`,
|
|
3458
|
+
tabIndex: current === t ? 0 : -1,
|
|
3459
|
+
className: "xdp-tab",
|
|
3460
|
+
onClick: () => choose(t),
|
|
3461
|
+
onKeyDown: onTabKey,
|
|
3462
|
+
children: t
|
|
3463
|
+
},
|
|
3464
|
+
t
|
|
3465
|
+
)) }),
|
|
3466
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "tabpanel", id: `${id}-panel`, "aria-labelledby": `${id}-tab-${current}`, className: "xdp-panel", children: [
|
|
3467
|
+
current === "Decision" ? /* @__PURE__ */ jsxRuntime.jsx(DecisionTab, { v }) : null,
|
|
3468
|
+
current === "Visitor" ? /* @__PURE__ */ jsxRuntime.jsx(VisitorTab, { v }) : null,
|
|
3469
|
+
current === "Request" ? /* @__PURE__ */ jsxRuntime.jsx(RequestTab, { v }) : null,
|
|
3470
|
+
current === "Site" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3471
|
+
v.custom.map(
|
|
3472
|
+
(c) => c.lines.length === 1 ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: c.label, children: c.lines[0] }, c.label) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block", children: [
|
|
3473
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "xdp-block-title", children: c.label }),
|
|
3474
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "xdp-list", children: c.lines.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: line }, i)) })
|
|
3475
|
+
] }, c.label)
|
|
3476
|
+
),
|
|
3477
|
+
renderExtra ? renderExtra(entry) : null
|
|
3478
|
+
] }) : null
|
|
3479
|
+
] })
|
|
3480
|
+
] }) : null
|
|
3481
|
+
] });
|
|
3482
|
+
}
|
|
3483
|
+
function remember(key, value) {
|
|
3484
|
+
try {
|
|
3485
|
+
sessionStorage.setItem(key, value);
|
|
3486
|
+
} catch {
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
function Row({ label, children: children2 }) {
|
|
3490
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-row", children: [
|
|
3491
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-label", children: label }),
|
|
3492
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-value", children: children2 })
|
|
3493
|
+
] });
|
|
3494
|
+
}
|
|
3495
|
+
function DecisionTab({ v }) {
|
|
3496
|
+
if (!v.decisions.length) return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "xdp-empty", children: "No journey targets this page." });
|
|
3497
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: v.decisions.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block", children: [
|
|
3498
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block-head", children: [
|
|
3499
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "xdp-key", children: d.key }),
|
|
3500
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-result", "data-result": changed(d.result) ? "changed" : "base", children: d.result })
|
|
3501
|
+
] }),
|
|
3502
|
+
d.reason ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "xdp-reason", children: d.reason }) : null,
|
|
3503
|
+
d.trace.length ? /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "xdp-steps", "aria-label": "Journey path", children: d.trace.map(([step, outcome]) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
3504
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: step }),
|
|
3505
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(Id, { value: outcome }) })
|
|
3506
|
+
] }, step)) }) : null
|
|
3507
|
+
] }, d.key)) });
|
|
3508
|
+
}
|
|
3509
|
+
var SOURCE_NAME = { jev: "Jev", signals: "Signals" };
|
|
3510
|
+
function VisitorTab({ v }) {
|
|
3511
|
+
const p = v.profile;
|
|
3512
|
+
if (!p) return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "xdp-empty", children: "No visitor profile came with this decision." });
|
|
3513
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3514
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-chips", children: [
|
|
3515
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "xdp-chip", children: [
|
|
3516
|
+
p.pageViews,
|
|
3517
|
+
" page view",
|
|
3518
|
+
p.pageViews === 1 ? "" : "s"
|
|
3519
|
+
] }),
|
|
3520
|
+
p.lastSection ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "xdp-chip", children: [
|
|
3521
|
+
"Last: ",
|
|
3522
|
+
p.lastSection
|
|
3523
|
+
] }) : null,
|
|
3524
|
+
p.campaign ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "xdp-chip", children: [
|
|
3525
|
+
"Campaign: ",
|
|
3526
|
+
p.campaign
|
|
3527
|
+
] }) : null
|
|
3528
|
+
] }),
|
|
3529
|
+
p.answers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "xdp-empty", children: "No Visitor Intent answers." }) : null,
|
|
3530
|
+
p.answers.map((a) => {
|
|
3531
|
+
const max = a.scores[0]?.[1] || 1;
|
|
3532
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block", children: [
|
|
3533
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block-head", children: [
|
|
3534
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "xdp-key", children: a.name }),
|
|
3535
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-answer", children: a.choice || "no answer" })
|
|
3536
|
+
] }),
|
|
3537
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-meta", children: [
|
|
3538
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-source", "data-source": a.source || "none", children: SOURCE_NAME[a.source] ?? "No source" }),
|
|
3539
|
+
typeof a.confidence === "number" && a.confidence > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "xdp-confidence", children: [
|
|
3540
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-meter", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { width: percent(Math.min(1, a.confidence)) } }) }),
|
|
3541
|
+
percent(a.confidence),
|
|
3542
|
+
" confident"
|
|
3543
|
+
] }) : null,
|
|
3544
|
+
a.model ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-model", children: a.model }) : null
|
|
3545
|
+
] }),
|
|
3546
|
+
a.scores.length ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "xdp-scores", children: a.scores.map(([option, score]) => /* @__PURE__ */ jsxRuntime.jsxs("li", { "data-score": option, children: [
|
|
3547
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-score-label", title: option, children: option }),
|
|
3548
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { width: `${Math.max(2, score / max * 100)}%` } }) }),
|
|
3549
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-score-value", children: Math.round(score * 1e3) / 1e3 })
|
|
3550
|
+
] }, option)) }) : null
|
|
3551
|
+
] }, a.name);
|
|
3552
|
+
})
|
|
3553
|
+
] });
|
|
3554
|
+
}
|
|
3555
|
+
var place = (g) => g ? [g.city, g.regionName || g.region].filter(Boolean).join(", ") : "";
|
|
3556
|
+
function RequestTab({ v }) {
|
|
3557
|
+
const r = v.request;
|
|
3558
|
+
const loc = r.location;
|
|
3559
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3560
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block", children: [
|
|
3561
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block-head", children: [
|
|
3562
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-place", children: place(loc) || (loc?.country ? "Country only" : "Location unknown") }),
|
|
3563
|
+
loc?.country ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "xdp-chip", children: loc.country }) : null
|
|
3564
|
+
] }),
|
|
3565
|
+
loc?.latitude && loc.longitude ? /* @__PURE__ */ jsxRuntime.jsxs(Row, { label: "Coordinates", children: [
|
|
3566
|
+
loc.latitude,
|
|
3567
|
+
", ",
|
|
3568
|
+
loc.longitude
|
|
3569
|
+
] }) : null,
|
|
3570
|
+
r.localTime ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Local time", children: r.localTime }) : null,
|
|
3571
|
+
loc?.timeZone ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Time zone", children: loc.timeZone }) : null,
|
|
3572
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Resolved via", children: loc?.source === "qa" ? "QA override" : !r.via || r.via === "none" ? "Not resolved" : r.via }),
|
|
3573
|
+
r.detected ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Edge detected", children: [place(r.detected), r.detected.country].filter(Boolean).join(", ") || "nothing" }) : null
|
|
3574
|
+
] }),
|
|
3575
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "xdp-block", children: [
|
|
3576
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "xdp-block-title", children: "Location sources seen" }),
|
|
3577
|
+
r.seen.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "xdp-chips", children: r.seen.map((s) => /* @__PURE__ */ jsxRuntime.jsx("code", { className: "xdp-chip", children: s }, s)) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "xdp-empty", children: "No location header or runtime context reached the proxy." })
|
|
3578
|
+
] }),
|
|
3579
|
+
r.device ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Device", children: r.device }) : null,
|
|
3580
|
+
r.consent ? /* @__PURE__ */ jsxRuntime.jsxs(Row, { label: "Consent", children: [
|
|
3581
|
+
"Personalization ",
|
|
3582
|
+
r.consent.personalization ? "on" : "off",
|
|
3583
|
+
", Analytics ",
|
|
3584
|
+
r.consent.analytics ? "on" : "off"
|
|
3585
|
+
] }) : null
|
|
3586
|
+
] });
|
|
3587
|
+
}
|
|
3588
|
+
var STYLES2 = `
|
|
3589
|
+
.xdp{--xdp-paper:#FFFFFF;--xdp-ink:#0A0F14;--xdp-muted:#424548;--xdp-faint:#5F6469;--xdp-border:#DEE2E5;--xdp-soft:#F2F4F5;--xdp-blue:#005C91;--xdp-blue-strong:#00334F;--xdp-blue-tint:#E6F1F7;--xdp-ok:#316302;--xdp-ok-tint:#EBF4E1;--xdp-warn:#9A5B00;--xdp-warn-tint:#FFF3DF;
|
|
3590
|
+
position:fixed;z-index:2147483000;display:flex;flex-direction:column;gap:8px;font:13px/1.45 ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;color:var(--xdp-ink);font-variant-numeric:tabular-nums;color-scheme:light;-webkit-font-smoothing:antialiased}
|
|
3591
|
+
.xdp *,.xdp *::before,.xdp *::after{box-sizing:border-box}
|
|
3592
|
+
.xdp[data-vertical=bottom]{bottom:16px;flex-direction:column-reverse}.xdp[data-vertical=top]{top:16px}
|
|
3593
|
+
.xdp[data-horizontal=right]{right:16px;align-items:flex-end}.xdp[data-horizontal=left]{left:16px;align-items:flex-start}
|
|
3594
|
+
.xdp button{font:inherit;color:inherit}
|
|
3595
|
+
.xdp code{font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
3596
|
+
.xdp-launcher{width:40px;height:40px;border-radius:50%;border:0;padding:0;background:var(--xdp-blue);display:grid;place-items:center;cursor:pointer;box-shadow:0 0 0 1px rgba(255,255,255,.25) inset,0 6px 18px rgba(0,51,79,.35)}
|
|
3597
|
+
.xdp-launcher:hover{background:var(--xdp-blue-strong)}
|
|
3598
|
+
.xdp-launcher:focus-visible,.xdp-tab:focus-visible{outline:2px solid var(--xdp-blue);outline-offset:2px}
|
|
3599
|
+
.xdp-card{width:360px;max-width:calc(100vw - 32px);background:var(--xdp-paper);border:1px solid var(--xdp-border);border-radius:14px;box-shadow:0 16px 40px rgba(10,15,20,.16),0 2px 6px rgba(10,15,20,.06);overflow:hidden}
|
|
3600
|
+
.xdp-card:focus,.xdp-card:focus-visible{outline:none}
|
|
3601
|
+
.xdp-head{padding:14px 16px 10px}
|
|
3602
|
+
.xdp-head-row{display:flex;align-items:center;gap:8px}
|
|
3603
|
+
.xdp-pill{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;font-weight:600;background:var(--xdp-soft);color:var(--xdp-muted)}
|
|
3604
|
+
.xdp-pill::before{content:"";width:7px;height:7px;border-radius:50%;background:currentColor}
|
|
3605
|
+
.xdp-pill[data-status=personalized]{background:var(--xdp-ok-tint);color:var(--xdp-ok)}
|
|
3606
|
+
.xdp-pill[data-status=attention]{background:var(--xdp-warn-tint);color:var(--xdp-warn)}
|
|
3607
|
+
.xdp-chip{display:inline-flex;align-items:center;padding:2px 8px;border-radius:6px;background:var(--xdp-soft);color:var(--xdp-muted);font-size:12px;white-space:nowrap}
|
|
3608
|
+
code.xdp-chip{font-size:11.5px}
|
|
3609
|
+
.xdp-ms{margin-left:auto;color:var(--xdp-faint)}
|
|
3610
|
+
.xdp-path{display:block;margin-top:8px;font-size:13px;color:var(--xdp-ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
3611
|
+
.xdp-alert{margin:8px 0 0;padding:8px 10px;border-radius:8px;background:var(--xdp-warn-tint);color:var(--xdp-warn)}
|
|
3612
|
+
.xdp-tabs{display:flex;gap:4px;padding:0 12px;border-bottom:1px solid var(--xdp-border)}
|
|
3613
|
+
.xdp-tab{background:none;border:0;padding:8px 6px 9px;margin-bottom:-1px;border-bottom:2px solid transparent;color:var(--xdp-muted);cursor:pointer;border-radius:4px 4px 0 0}
|
|
3614
|
+
.xdp-tab:hover{color:var(--xdp-ink)}
|
|
3615
|
+
.xdp-tab[aria-selected=true]{color:var(--xdp-blue);border-bottom-color:var(--xdp-blue);font-weight:600}
|
|
3616
|
+
.xdp-panel{padding:12px 16px 16px;display:flex;flex-direction:column;gap:10px}
|
|
3617
|
+
.xdp-block{display:flex;flex-direction:column;gap:6px;padding:10px 12px;border:1px solid var(--xdp-border);border-radius:10px}
|
|
3618
|
+
.xdp-block-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
3619
|
+
.xdp-block-title{font-weight:600}
|
|
3620
|
+
.xdp-key{color:var(--xdp-ink);overflow-wrap:anywhere}
|
|
3621
|
+
.xdp-result{padding:2px 8px;border-radius:6px;background:var(--xdp-soft);color:var(--xdp-muted);font-weight:600;text-align:right}
|
|
3622
|
+
.xdp-result[data-result=changed]{background:var(--xdp-ok-tint);color:var(--xdp-ok)}
|
|
3623
|
+
.xdp-reason{margin:0;color:var(--xdp-warn)}
|
|
3624
|
+
.xdp-steps{list-style:none;margin:2px 0 0;padding:0 0 0 14px;position:relative;display:flex;flex-direction:column;gap:6px}
|
|
3625
|
+
.xdp-steps::before{content:"";position:absolute;left:4px;top:6px;bottom:6px;width:1px;background:var(--xdp-border)}
|
|
3626
|
+
.xdp-steps li{position:relative;display:flex;justify-content:space-between;gap:12px}
|
|
3627
|
+
.xdp-steps li::before{content:"";position:absolute;left:-13px;top:6px;width:7px;height:7px;border-radius:50%;background:var(--xdp-paper);border:1.5px solid var(--xdp-blue)}
|
|
3628
|
+
.xdp-steps code{color:var(--xdp-muted)}
|
|
3629
|
+
.xdp-steps span{text-align:right;overflow-wrap:anywhere}
|
|
3630
|
+
.xdp-row{display:flex;justify-content:space-between;align-items:baseline;gap:16px}
|
|
3631
|
+
.xdp-label{color:var(--xdp-muted);flex:none}
|
|
3632
|
+
.xdp-value{text-align:right;min-width:0;overflow-wrap:anywhere}
|
|
3633
|
+
.xdp-chips{display:flex;flex-wrap:wrap;gap:6px}
|
|
3634
|
+
.xdp-answer{font-weight:600}
|
|
3635
|
+
.xdp-meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;color:var(--xdp-muted);font-size:12px}
|
|
3636
|
+
.xdp-source{padding:1px 7px;border-radius:6px;font-weight:600;background:var(--xdp-soft)}
|
|
3637
|
+
.xdp-source[data-source=signals]{background:var(--xdp-ok-tint);color:var(--xdp-ok)}
|
|
3638
|
+
.xdp-source[data-source=jev]{background:var(--xdp-blue-tint);color:var(--xdp-blue)}
|
|
3639
|
+
.xdp-confidence{display:inline-flex;align-items:center;gap:6px}
|
|
3640
|
+
.xdp-meter{display:inline-block;width:44px;height:5px;border-radius:3px;background:var(--xdp-soft);overflow:hidden}
|
|
3641
|
+
.xdp-meter span,.xdp-bar span{display:block;height:100%;background:var(--xdp-blue);border-radius:3px}
|
|
3642
|
+
.xdp-scores{list-style:none;margin:2px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}
|
|
3643
|
+
.xdp-scores li{display:grid;grid-template-columns:minmax(0,92px) 1fr auto;align-items:center;gap:8px;font-size:12px}
|
|
3644
|
+
.xdp-score-label{color:var(--xdp-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
3645
|
+
.xdp-bar{height:6px;border-radius:3px;background:var(--xdp-soft);overflow:hidden}
|
|
3646
|
+
.xdp-scores li:first-child .xdp-bar span{background:var(--xdp-ok)}
|
|
3647
|
+
.xdp-score-value{color:var(--xdp-muted);min-width:38px;text-align:right}
|
|
3648
|
+
.xdp-place{font-weight:600;font-size:14px}
|
|
3649
|
+
.xdp-list{margin:0;padding-left:18px;list-style:disc;display:flex;flex-direction:column;gap:4px}.xdp-list li::marker{color:var(--xdp-blue)}
|
|
3650
|
+
.xdp-empty{margin:0;color:var(--xdp-muted)}
|
|
3651
|
+
.xdp-model{color:var(--xdp-faint)}
|
|
3652
|
+
@media (prefers-reduced-motion:no-preference){.xdp-card{animation:xdp-in .14s ease-out}@keyframes xdp-in{from{opacity:0;transform:translateY(4px)}}}
|
|
3653
|
+
`;
|
|
3654
|
+
|
|
2969
3655
|
exports.XeniaClient = XeniaClient;
|
|
2970
3656
|
exports.XeniaContentProvider = XeniaContentProvider;
|
|
2971
3657
|
exports.XeniaContext = XeniaContext;
|
|
3658
|
+
exports.XeniaDebugPanel = XeniaDebugPanel;
|
|
2972
3659
|
exports.XeniaMessage = XeniaMessage;
|
|
2973
3660
|
exports.XeniaProvider = XeniaProvider;
|
|
2974
3661
|
exports.XeniaTrack = XeniaTrack;
|
|
2975
3662
|
exports.createXeniaClient = createXeniaClient;
|
|
3663
|
+
exports.debugStatus = debugStatus;
|
|
2976
3664
|
exports.extractContentSwaps = extractContentSwaps;
|
|
2977
3665
|
exports.parseActions = parseActions;
|
|
2978
3666
|
exports.pendingTargets = pendingTargets;
|