@xenia-martech/sdk-js 1.2.0-dev.3 → 1.2.0-dev.4

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