@xenia-martech/sdk-js 1.2.0-dev.7 → 1.2.0-dev.9
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 +70 -6
- package/dist/{actions-35V37IT0.d.cts → actions--1_9Z8ig.d.cts} +13 -2
- package/dist/{actions-35V37IT0.d.ts → actions--1_9Z8ig.d.ts} +13 -2
- package/dist/{api-0IycTYJR.d.cts → api-DbUxT38T.d.ts} +1 -1
- package/dist/{api-COXWLL5L.d.ts → api-DgzJ5s-k.d.cts} +1 -1
- package/dist/chunk-DPXINHQR.cjs +34 -0
- package/dist/chunk-DPXINHQR.cjs.map +1 -0
- package/dist/chunk-FSJMHXS6.js +432 -0
- package/dist/chunk-FSJMHXS6.js.map +1 -0
- package/dist/chunk-GXJLU3RE.cjs +448 -0
- package/dist/chunk-GXJLU3RE.cjs.map +1 -0
- package/dist/{chunk-2DR5AVPX.cjs → chunk-I5EHLRSR.cjs} +11 -10
- package/dist/chunk-I5EHLRSR.cjs.map +1 -0
- package/dist/{chunk-LW5AEJ6K.js → chunk-MEULT5X6.js} +4 -241
- package/dist/chunk-MEULT5X6.js.map +1 -0
- package/dist/{chunk-GWRDZIVA.js → chunk-NDRRSRTU.js} +4 -3
- package/dist/chunk-NDRRSRTU.js.map +1 -0
- package/dist/chunk-RC46KXDM.js +32 -0
- package/dist/chunk-RC46KXDM.js.map +1 -0
- package/dist/{chunk-RWE2OCQL.cjs → chunk-SU25SELD.cjs} +4 -244
- package/dist/chunk-SU25SELD.cjs.map +1 -0
- package/dist/{chunk-WHGK55JP.cjs → chunk-UUIKUU5W.cjs} +5 -5
- package/dist/{chunk-WHGK55JP.cjs.map → chunk-UUIKUU5W.cjs.map} +1 -1
- package/dist/{chunk-QEYONKWY.js → chunk-UVTFGQR6.js} +3 -3
- package/dist/{chunk-QEYONKWY.js.map → chunk-UVTFGQR6.js.map} +1 -1
- package/dist/{chunk-OMMIRSPK.js → chunk-V4EGU3PM.js} +48 -11
- package/dist/chunk-V4EGU3PM.js.map +1 -0
- package/dist/{chunk-YLMMTKQL.cjs → chunk-WMGCQPHY.cjs} +52 -13
- package/dist/chunk-WMGCQPHY.cjs.map +1 -0
- package/dist/client/index.cjs +26 -10
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +26 -10
- package/dist/client/index.js.map +1 -1
- package/dist/client/react/index.cjs +73 -15
- package/dist/client/react/index.cjs.map +1 -1
- package/dist/client/react/index.d.cts +9 -3
- package/dist/client/react/index.d.ts +9 -3
- package/dist/client/react/index.js +73 -15
- package/dist/client/react/index.js.map +1 -1
- package/dist/cms/contentful.cjs +7 -24
- package/dist/cms/contentful.cjs.map +1 -1
- package/dist/cms/contentful.d.cts +5 -4
- package/dist/cms/contentful.d.ts +5 -4
- package/dist/cms/contentful.js +4 -23
- package/dist/cms/contentful.js.map +1 -1
- package/dist/cms/contentstack.cjs +120 -0
- package/dist/cms/contentstack.cjs.map +1 -0
- package/dist/cms/contentstack.d.cts +41 -0
- package/dist/cms/contentstack.d.ts +41 -0
- package/dist/cms/contentstack.js +117 -0
- package/dist/cms/contentstack.js.map +1 -0
- package/dist/{consent-DRCV0N0d.d.ts → consent-Dtiqzz2B.d.cts} +71 -11
- package/dist/{consent-BgAETCkL.d.cts → consent-byYiDMFr.d.ts} +71 -11
- package/dist/{cookie-names-DU3MtcNG.d.ts → cookie-names-B4hda2rX.d.cts} +1 -1
- package/dist/{cookie-names-DFItnSLK.d.cts → cookie-names-DioZXuV0.d.ts} +1 -1
- package/dist/edge/index.cjs +122 -29
- package/dist/edge/index.cjs.map +1 -1
- package/dist/edge/index.d.cts +42 -6
- package/dist/edge/index.d.ts +42 -6
- package/dist/edge/index.js +92 -9
- package/dist/edge/index.js.map +1 -1
- package/dist/index.cjs +31 -31
- package/dist/index.d.cts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +2 -2
- package/dist/next/index.cjs +39 -34
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +2 -3
- package/dist/next/index.d.ts +2 -3
- package/dist/next/index.js +13 -8
- package/dist/next/index.js.map +1 -1
- package/dist/{types-DgVHS4Qw.d.ts → personalize-content-D6xeBI7-.d.cts} +150 -1
- package/dist/{types-DgVHS4Qw.d.cts → personalize-content-D6xeBI7-.d.ts} +150 -1
- package/dist/server/index.cjs +30 -30
- package/dist/server/index.d.cts +5 -6
- package/dist/server/index.d.ts +5 -6
- package/dist/server/index.js +5 -5
- package/dist/xenia-sdk.iife.js +3 -3
- package/dist/xenia-sdk.iife.js.map +1 -1
- package/dist/{xenia-server-Cf24mL0c.d.ts → xenia-server-BcgeUHX4.d.ts} +2 -3
- package/dist/{xenia-server-D-bx14lw.d.cts → xenia-server-lv6LtJZP.d.cts} +2 -3
- package/package.json +14 -1
- package/dist/chunk-2DR5AVPX.cjs.map +0 -1
- package/dist/chunk-BQ5PJCZ7.js +0 -179
- package/dist/chunk-BQ5PJCZ7.js.map +0 -1
- package/dist/chunk-GWRDZIVA.js.map +0 -1
- package/dist/chunk-LW5AEJ6K.js.map +0 -1
- package/dist/chunk-N5M4PI7C.cjs +0 -192
- package/dist/chunk-N5M4PI7C.cjs.map +0 -1
- package/dist/chunk-OMMIRSPK.js.map +0 -1
- package/dist/chunk-RWE2OCQL.cjs.map +0 -1
- package/dist/chunk-YLMMTKQL.cjs.map +0 -1
- package/dist/personalize-content-Cwc2AomC.d.ts +0 -141
- package/dist/personalize-content-CxSdplMV.d.cts +0 -141
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkGXJLU3RE_cjs = require('./chunk-GXJLU3RE.cjs');
|
|
4
4
|
|
|
5
5
|
// src/core/actions.ts
|
|
6
6
|
var MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -206,7 +206,7 @@ var XeniaApi = class {
|
|
|
206
206
|
this.tenantId = config.tenantId;
|
|
207
207
|
this.environmentKey = config.environmentKey;
|
|
208
208
|
this.tokenProvider = new TokenProvider(config);
|
|
209
|
-
this.http = new
|
|
209
|
+
this.http = new chunkGXJLU3RE_cjs.HttpClient({
|
|
210
210
|
baseUrl: config.baseUrl,
|
|
211
211
|
defaultHeaders: config.headers,
|
|
212
212
|
timeout: config.timeout,
|
|
@@ -480,252 +480,12 @@ function contextFromUrl(url, referrer) {
|
|
|
480
480
|
return ctx;
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
-
// src/core/personalize-content.ts
|
|
484
|
-
var DEFAULT_TIMEOUT_MS = 300;
|
|
485
|
-
var DEFAULT_MAX_ROUNDS = 3;
|
|
486
|
-
var copyOf = (v) => v && typeof v === "object" && typeof structuredClone === "function" ? structuredClone(v) : v;
|
|
487
|
-
async function personalizeContent(payload, options) {
|
|
488
|
-
const cms = scopedAdapter(options.cms, options.contentKey);
|
|
489
|
-
const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
|
|
490
|
-
const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
491
|
-
const applied = [];
|
|
492
|
-
const report = (swap) => {
|
|
493
|
-
applied.push(swap);
|
|
494
|
-
try {
|
|
495
|
-
options.onApplied?.(swap);
|
|
496
|
-
} catch {
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
let content = payload;
|
|
500
|
-
try {
|
|
501
|
-
if (!options.inPlace && typeof structuredClone === "function") content = structuredClone(content);
|
|
502
|
-
content = cms.prepare ? cms.prepare(content) : content;
|
|
503
|
-
} catch (error) {
|
|
504
|
-
return { content: payload, applied, complete: false, error };
|
|
505
|
-
}
|
|
506
|
-
const box = { root: content };
|
|
507
|
-
const settled = /* @__PURE__ */ new WeakSet();
|
|
508
|
-
const decided = /* @__PURE__ */ new Map();
|
|
509
|
-
let frontier = [{ parent: box, key: "root", value: box.root }];
|
|
510
|
-
const settle = (target, d, round) => {
|
|
511
|
-
settled.add(target.entry);
|
|
512
|
-
cms.clearMarker?.(target.entry);
|
|
513
|
-
const items = d.items.map(copyOf);
|
|
514
|
-
if (!d.decision || items.length === 0) {
|
|
515
|
-
return deferredSlots(target, cms);
|
|
516
|
-
}
|
|
517
|
-
for (const item of items) if (item && typeof item === "object") settled.add(item);
|
|
518
|
-
const op = d.decision.op ?? target.marker.op ?? "replace";
|
|
519
|
-
const next = apply(target, op, d.decision.field ?? target.marker.field, items, cms);
|
|
520
|
-
report({
|
|
521
|
-
target: target.id,
|
|
522
|
-
kind: "runtime",
|
|
523
|
-
op,
|
|
524
|
-
entryIds: items.map((e) => cms.entryId(e)).filter((id) => !!id),
|
|
525
|
-
contentKey: d.decision.contentKey,
|
|
526
|
-
bucket: d.decision.bucket,
|
|
527
|
-
round
|
|
528
|
-
});
|
|
529
|
-
return next;
|
|
530
|
-
};
|
|
531
|
-
for (let round = 0; ; round++) {
|
|
532
|
-
const pending = walk(frontier, cms, settled, round, report, (t) => {
|
|
533
|
-
const d = decided.get(t.id);
|
|
534
|
-
return d ? settle(t, d, round) : void 0;
|
|
535
|
-
});
|
|
536
|
-
if (pending.size === 0) return { content: box.root, applied, complete: true };
|
|
537
|
-
if (!options.resolve || round >= maxRounds) {
|
|
538
|
-
return { content: box.root, applied, complete: !options.resolve };
|
|
539
|
-
}
|
|
540
|
-
progress(options, { content: box.root, round, pending: [...pending.keys()] });
|
|
541
|
-
let decisions;
|
|
542
|
-
let entriesById;
|
|
543
|
-
let queried;
|
|
544
|
-
try {
|
|
545
|
-
decisions = await withDeadline(options.resolve([...pending.keys()]), deadline);
|
|
546
|
-
({ entriesById, queried } = await withDeadline(loadReplacements(decisions, cms, options.locale), deadline));
|
|
547
|
-
} catch (error) {
|
|
548
|
-
return { content: box.root, applied, complete: false, error: error === TIMEOUT ? void 0 : error };
|
|
549
|
-
}
|
|
550
|
-
const byTarget = new Map(decisions.map((d) => [d.target, d]));
|
|
551
|
-
frontier = [];
|
|
552
|
-
for (const target of pending.values()) {
|
|
553
|
-
const decision = byTarget.get(target.id);
|
|
554
|
-
const items = decision ? decision.ids ? decision.ids.map((id) => entriesById.get(id)).filter((e) => e !== void 0) : queried.get(decision) ?? [] : [];
|
|
555
|
-
const d = { decision, items };
|
|
556
|
-
decided.set(target.id, d);
|
|
557
|
-
frontier.push(...settle(target, d, round));
|
|
558
|
-
}
|
|
559
|
-
progress(options, { content: box.root, round, pending: [] });
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
function progress(options, p) {
|
|
563
|
-
try {
|
|
564
|
-
options.onProgress?.(p);
|
|
565
|
-
} catch {
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
function walk(frontier, cms, settled, round, report, reuse) {
|
|
569
|
-
const pending = /* @__PURE__ */ new Map();
|
|
570
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
571
|
-
const deferred = /* @__PURE__ */ new WeakSet();
|
|
572
|
-
const queue = [...frontier];
|
|
573
|
-
while (queue.length > 0) {
|
|
574
|
-
const slot = queue.shift();
|
|
575
|
-
const value = slot.value;
|
|
576
|
-
if (!value || typeof value !== "object" || deferred.has(value)) continue;
|
|
577
|
-
const id = settled.has(value) ? void 0 : cms.entryId(value);
|
|
578
|
-
const marker = id ? cms.marker(value) : null;
|
|
579
|
-
if (id && marker?.kind === "runtime") {
|
|
580
|
-
const again = reuse({ id, marker, entry: value, slots: [slot] });
|
|
581
|
-
if (again) {
|
|
582
|
-
queue.push(...again);
|
|
583
|
-
continue;
|
|
584
|
-
}
|
|
585
|
-
const existing = pending.get(id);
|
|
586
|
-
if (existing) {
|
|
587
|
-
existing.slots.push(slot);
|
|
588
|
-
} else {
|
|
589
|
-
pending.set(id, { id, marker, entry: value, slots: [slot] });
|
|
590
|
-
if (marker.op === "items" && marker.field) {
|
|
591
|
-
const held = cms.getField(value, marker.field);
|
|
592
|
-
if (held && typeof held === "object") deferred.add(held);
|
|
593
|
-
queue.push(...children(value));
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
if (id && marker?.kind === "static") {
|
|
599
|
-
const variants = cms.staticVariants(value).filter((v) => v && typeof v === "object");
|
|
600
|
-
settled.add(value);
|
|
601
|
-
cms.clearMarker?.(value);
|
|
602
|
-
if (variants.length > 0) {
|
|
603
|
-
for (const v of variants) settled.add(v);
|
|
604
|
-
const op = marker.op ?? "replace";
|
|
605
|
-
const target = { entry: value, slots: [slot] };
|
|
606
|
-
queue.push(...apply(target, op, marker.field, variants, cms));
|
|
607
|
-
report({
|
|
608
|
-
target: id,
|
|
609
|
-
kind: "static",
|
|
610
|
-
op,
|
|
611
|
-
entryIds: variants.map((v) => cms.entryId(v)).filter((x) => !!x),
|
|
612
|
-
round
|
|
613
|
-
});
|
|
614
|
-
continue;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
if (seen.has(value)) continue;
|
|
618
|
-
seen.add(value);
|
|
619
|
-
queue.push(...children(value));
|
|
620
|
-
}
|
|
621
|
-
return pending;
|
|
622
|
-
}
|
|
623
|
-
function apply(target, op, field, items, cms) {
|
|
624
|
-
if (op === "items") {
|
|
625
|
-
if (field) {
|
|
626
|
-
cms.setField(target.entry, field, items);
|
|
627
|
-
return [{ parent: target.entry, key: field, value: cms.getField(target.entry, field) }];
|
|
628
|
-
}
|
|
629
|
-
if (cms.mergeItems) {
|
|
630
|
-
cms.mergeItems(target.entry, items[0]);
|
|
631
|
-
return target.slots.map((s) => ({ ...s, value: target.entry }));
|
|
632
|
-
}
|
|
633
|
-
op = "replace";
|
|
634
|
-
}
|
|
635
|
-
const next = [];
|
|
636
|
-
for (const slot of target.slots) {
|
|
637
|
-
const placed = op === "expand" && Array.isArray(slot.parent) ? items : [items[0]];
|
|
638
|
-
if (Array.isArray(slot.parent)) {
|
|
639
|
-
const index = slot.parent.indexOf(target.entry);
|
|
640
|
-
if (index < 0) continue;
|
|
641
|
-
slot.parent.splice(index, 1, ...placed);
|
|
642
|
-
} else {
|
|
643
|
-
slot.parent[slot.key] = placed[0];
|
|
644
|
-
}
|
|
645
|
-
for (const value of placed) next.push({ parent: slot.parent, key: slot.key, value });
|
|
646
|
-
}
|
|
647
|
-
return next;
|
|
648
|
-
}
|
|
649
|
-
function deferredSlots(target, cms) {
|
|
650
|
-
if (target.marker.op === "items" && target.marker.field) {
|
|
651
|
-
return [{ parent: target.entry, key: target.marker.field, value: cms.getField(target.entry, target.marker.field) }];
|
|
652
|
-
}
|
|
653
|
-
return target.slots.map((s) => ({ ...s, value: target.entry }));
|
|
654
|
-
}
|
|
655
|
-
function children(value) {
|
|
656
|
-
if (Array.isArray(value)) return value.map((v, i) => ({ parent: value, key: i, value: v }));
|
|
657
|
-
return Object.keys(value).map((k) => ({ parent: value, key: k, value: value[k] }));
|
|
658
|
-
}
|
|
659
|
-
async function loadReplacements(decisions, cms, locale) {
|
|
660
|
-
const ids = [...new Set(decisions.flatMap((d) => d.ids ?? []))];
|
|
661
|
-
const queries = decisions.filter((d) => !d.ids && d.query);
|
|
662
|
-
const [fetched, ...results] = await Promise.all([
|
|
663
|
-
ids.length > 0 ? cms.fetchEntries(ids, locale) : Promise.resolve([]),
|
|
664
|
-
...queries.map((d) => cms.queryEntries(d.query, locale).catch(() => []))
|
|
665
|
-
]);
|
|
666
|
-
const entriesById = /* @__PURE__ */ new Map();
|
|
667
|
-
for (const entry of fetched) {
|
|
668
|
-
const id = cms.entryId(entry);
|
|
669
|
-
if (id) entriesById.set(id, entry);
|
|
670
|
-
}
|
|
671
|
-
const queried = /* @__PURE__ */ new Map();
|
|
672
|
-
queries.forEach((d, i) => queried.set(d, results[i]));
|
|
673
|
-
return { entriesById, queried };
|
|
674
|
-
}
|
|
675
|
-
var TIMEOUT = /* @__PURE__ */ Symbol("timeout");
|
|
676
|
-
function withDeadline(promise, deadline) {
|
|
677
|
-
const remaining = deadline - Date.now();
|
|
678
|
-
if (remaining <= 0) return Promise.reject(TIMEOUT);
|
|
679
|
-
let timer;
|
|
680
|
-
return Promise.race([
|
|
681
|
-
promise,
|
|
682
|
-
new Promise((_, reject) => {
|
|
683
|
-
timer = setTimeout(() => reject(TIMEOUT), remaining);
|
|
684
|
-
})
|
|
685
|
-
]).finally(() => clearTimeout(timer));
|
|
686
|
-
}
|
|
687
|
-
function pendingTargets(payload, adapter, contentKey) {
|
|
688
|
-
const cms = scopedAdapter(adapter, contentKey);
|
|
689
|
-
try {
|
|
690
|
-
let content = typeof structuredClone === "function" ? structuredClone(payload) : payload;
|
|
691
|
-
content = cms.prepare ? cms.prepare(content) : content;
|
|
692
|
-
const root = { parent: { root: content }, key: "root", value: content };
|
|
693
|
-
return [...walk([root], cms, /* @__PURE__ */ new WeakSet(), 0, () => {
|
|
694
|
-
}, () => void 0).keys()];
|
|
695
|
-
} catch {
|
|
696
|
-
return [];
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
function scopedAdapter(cms, contentKey) {
|
|
700
|
-
return {
|
|
701
|
-
...cms,
|
|
702
|
-
marker(entry) {
|
|
703
|
-
const m = cms.marker(entry);
|
|
704
|
-
return m && contentKey && m.keys?.includes(contentKey) ? m : null;
|
|
705
|
-
}
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
async function personalizePage(ref, options) {
|
|
709
|
-
let page;
|
|
710
|
-
try {
|
|
711
|
-
if (!options.cms.fetchPage) throw new Error("This CMS adapter cannot fetch pages; use personalizeContent(page)");
|
|
712
|
-
page = await options.cms.fetchPage(ref, options.locale);
|
|
713
|
-
} catch (error) {
|
|
714
|
-
return { content: null, applied: [], complete: false, error };
|
|
715
|
-
}
|
|
716
|
-
if (page == null) return { content: null, applied: [], complete: true };
|
|
717
|
-
return personalizeContent(page, options);
|
|
718
|
-
}
|
|
719
|
-
|
|
720
483
|
exports.MAX_EVENT_ID_LENGTH = MAX_EVENT_ID_LENGTH;
|
|
721
484
|
exports.XeniaApi = XeniaApi;
|
|
722
485
|
exports.compact = compact;
|
|
723
486
|
exports.contextFromUrl = contextFromUrl;
|
|
724
487
|
exports.generateUlid = generateUlid;
|
|
725
488
|
exports.parseActions = parseActions;
|
|
726
|
-
exports.pendingTargets = pendingTargets;
|
|
727
|
-
exports.personalizeContent = personalizeContent;
|
|
728
|
-
exports.personalizePage = personalizePage;
|
|
729
489
|
exports.toEventId = toEventId;
|
|
730
|
-
//# sourceMappingURL=chunk-
|
|
731
|
-
//# sourceMappingURL=chunk-
|
|
490
|
+
//# sourceMappingURL=chunk-SU25SELD.cjs.map
|
|
491
|
+
//# sourceMappingURL=chunk-SU25SELD.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/actions.ts","../src/core/token-provider.ts","../src/core/api.ts","../src/core/id.ts","../src/core/request-context.ts"],"names":["HttpClient"],"mappings":";;;;;AAWA,IAAM,aAAA,uBAAyC,GAAA,CAAsB;AAAA,EACnE,QAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAC,CAAA;AAED,IAAM,iBAAA,uBAA6C,GAAA,CAAqB;AAAA,EACtE,UAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAC,CAAA;AAMD,IAAM,+BAAoC,IAAI,GAAA,CAAgB,CAAC,UAAA,EAAY,YAAY,CAAC,CAAA;AAExF,IAAM,SAAA,uBAAqC,GAAA,CAAY;AAAA,EACrD,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,GAAG;AACL,CAAC,CAAA;AAGD,SAAS,SAAS,CAAA,EAA2D;AAC3E,EAAA,OAAO,OAAO,MAAM,QAAA,IAAY,CAAA,KAAM,QAAQ,CAAC,KAAA,CAAM,QAAQ,CAAC,CAAA;AAChE;AAEA,SAAS,SAAS,CAAA,EAA8C;AAC9D,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,MAAA;AACrC;AAEA,SAAS,SAAS,CAAA,EAA8C;AAC9D,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,MAAA;AACrC;AAMA,SAAS,SAAS,GAAA,EAAoC;AACpD,EAAA,IAAI,CAAC,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,IAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AAC9B,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,UAAU,GAAA,CAAI,IAAI,GAAG,OAAO,IAAA;AAE1C,EAAA,IAAI,SAAS,UAAA,EAAY;AACvB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AAC5B,IAAA,OAAO,GAAA,GAAM,EAAE,IAAA,EAAM,GAAA,EAAI,GAAI,IAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,IAAA,KAAS,MAAA,IAAU,IAAA,KAAS,MAAA,EAAQ;AACtC,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AAClC,IAAA,OAAO,MAAA,GAAS,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,IAAA;AAAA,EACrC;AAEA,EAAA,IAAI,IAAA,KAAS,MAAA,IAAU,IAAA,KAAS,YAAA,EAAc;AAC5C,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AAClC,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG,IAAA,EAAM,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAE;AAAA,EAC5E;AAGA,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA,GACxB;AAAA,IACE,KAAA,EAAO,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,KAAK,CAAA,IAAK,EAAA;AAAA,IAClC,GAAA,EAAK,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAAA,IACzB,KAAA,EAAO,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,KAAK;AAAA,GAC/B,GACA,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,MAAA,EAAQ,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AAAA,IAC3B,KAAA,EAAO,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AAAA,IACzB,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA;AAAA,IAC7B,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,QAAQ,CAAA;AAAA,IAC/B,IAAA,EAAM,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA,IAIvB,KAAK,GAAA,KAAQ,GAAA,CAAI,KAAA,IAAS,GAAA,CAAI,OAAO,GAAA,GAAM,MAAA;AAAA,IAC3C,cAAA,EAAgB,QAAA,CAAS,GAAA,CAAI,cAAc,CAAA;AAAA,IAC3C,QAAA,EAAU,iBAAA,CAAkB,GAAA,CAAI,QAAQ,CAAA;AAAA,IACxC,UAAA,EAAY,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA;AAAA,IACvC,QAAA,EAAU,UAAA,CAAW,GAAA,CAAI,QAAQ,CAAA;AAAA,IACjC,UAAA,EAAY,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA;AAAA,IACvC,KAAA,EAAO,aAAA,CAAc,GAAA,CAAI,KAAK,CAAA;AAAA,IAC9B,WAAA,EAAa,QAAA,CAAS,GAAA,CAAI,WAAW,CAAA;AAAA,IACrC,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA;AAAA,IAC7B,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,QAAQ;AAAA,GACjC;AACF;AAEA,SAAS,kBAAkB,CAAA,EAAuD;AAChF,EAAA,MAAM,CAAA,GAAI,SAAS,CAAC,CAAA;AACpB,EAAA,OAAO,CAAA,IAAK,iBAAA,CAAkB,GAAA,CAAI,CAAC,IAAK,CAAA,GAAwB,MAAA;AAClE;AAEA,SAAS,aAAa,CAAA,EAAkD;AACtE,EAAA,MAAM,CAAA,GAAI,SAAS,CAAC,CAAA;AACpB,EAAA,OAAO,CAAA,IAAK,YAAA,CAAa,GAAA,CAAI,CAAC,IAAK,CAAA,GAAmB,MAAA;AACxD;AAGA,SAAS,WAAW,CAAA,EAAuD;AACzE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAC,GAAG,OAAO,MAAA;AAC9B,EAAA,MAAM,WAA4B,EAAC;AACnC,EAAA,KAAA,MAAW,SAAS,CAAA,EAAG;AACrB,IAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG;AACtB,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,KAAA,CAAM,EAAE,CAAA;AAC5B,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA;AAClC,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,KAAA,EAAO;AACnB,IAAA,QAAA,CAAS,IAAA,CAAK;AAAA,MACZ,EAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAA,EAAU,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAA;AAAA,MACjC,MAAA,EAAQ,MAAM,MAAA,KAAW;AAAA,KAC1B,CAAA;AAAA,EACH;AACA,EAAA,OAAO,QAAA,CAAS,SAAS,QAAA,GAAW,MAAA;AACtC;AAOA,SAAS,aAAa,CAAA,EAAwD;AAC5E,EAAA,IAAI,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG,OAAO,MAAA;AACzB,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,CAAA,CAAE,IAAI,CAAA;AAC5B,EAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,EAAA,OAAO;AAAA,IACL,eAAA,EAAiB,EAAE,eAAA,KAAoB,IAAA;AAAA,IACvC,IAAA;AAAA,IACA,OAAA,EAAS,QAAA,CAAS,CAAA,CAAE,OAAO,CAAA;AAAA,IAC3B,UAAA,EAAY,QAAA,CAAS,CAAA,CAAE,UAAU,CAAA;AAAA,IACjC,gBAAA,EAAkB,QAAA,CAAS,CAAA,CAAE,gBAAgB;AAAA,GAC/C;AACF;AAOA,SAAS,cAAc,CAAA,EAAmD;AACxE,EAAA,IAAI,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG,OAAO,MAAA;AACzB,EAAA,MAAM,KAAA,GAAqB;AAAA,IACzB,eAAA,EAAiB,EAAE,eAAA,KAAoB,IAAA;AAAA,IACvC,WAAA,EAAa,EAAE,WAAA,KAAgB;AAAA,GACjC;AACA,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,eAAA,IAAmB,KAAA,CAAM,WAAA;AAC9C,EAAA,OAAO,SAAS,KAAA,GAAQ,MAAA;AAC1B;AASO,SAAS,aAAa,IAAA,EAAgC;AAC3D,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AACvB,IAAA,IAAA,GAAO,IAAA;AAAA,EACT,CAAA,MAAA,IAAW,SAAS,IAAI,CAAA,IAAK,MAAM,OAAA,CAAQ,IAAA,CAAK,YAAY,CAAA,EAAG;AAC7D,IAAA,IAAA,GAAO,IAAA,CAAK,YAAA;AAAA,EACd;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,SAAU,EAAC;AAElC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,KAAA,MAAW,SAAS,IAAA,EAAM;AACxB,IAAA,MAAM,MAAA,GAAS,SAAS,KAAK,CAAA;AAC7B,IAAA,IAAI,MAAA,EAAQ,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,OAAA;AACT;;;AC3LA,SAAS,UAAU,KAAA,EAAmC;AACpD,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AAClC,IAAA,IAAI,CAAC,SAAS,OAAO,KAAA,CAAA;AACrB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAC,CAAC,CAAA;AAC3E,IAAA,OAAO,OAAO,IAAA,CAAK,GAAA,KAAQ,QAAA,GAAW,IAAA,CAAK,MAAM,GAAA,GAAO,KAAA,CAAA;AAAA,EAC1D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAQO,IAAM,gBAAN,MAAoB;AAAA,EACR,MAAA;AAAA,EACT,MAAA,GAAwB,IAAA;AAAA,EACxB,QAAA,GAAmC,IAAA;AAAA,EAE3C,YAAY,MAAA,EAAqB;AAC/B,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,SAAA,GAAqB;AACnB,IAAA,OAAO,QAAQ,IAAA,CAAK,MAAA,CAAO,KAAA,IAAS,IAAA,CAAK,OAAO,QAAQ,CAAA;AAAA,EAC1D;AAAA,EAES,WAAW,YAA6B;AAC/C,IAAA,IAAI,IAAA,CAAK,OAAO,KAAA,IAAS,CAAC,KAAK,MAAA,CAAO,QAAA,EAAU,OAAO,IAAA,CAAK,MAAA,CAAO,KAAA;AAEnE,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,IAAA,CAAK,UAAU,IAAA,CAAK,MAAA,CAAO,YAAY,GAAA,EAAK,OAAO,KAAK,MAAA,CAAO,KAAA;AACnE,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA;AAE/B,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,QAAA,EAAU;AACzB,MAAA,MAAM,IAAI,MAAM,uDAAuD,CAAA;AAAA,IACzE;AAEA,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,CACnD,IAAA,CAAK,CAAC,KAAA,KAAU;AACf,MAAA,MAAM,GAAA,GAAM,UAAU,KAAK,CAAA;AAE3B,MAAA,MAAM,SAAA,GAAY,GAAA,GAAM,GAAA,GAAM,GAAA,GAAS,MAAM,CAAA,GAAI,GAAA;AACjD,MAAA,IAAA,CAAK,MAAA,GAAS,EAAE,KAAA,EAAO,SAAA,EAAU;AACjC,MAAA,OAAO,KAAA;AAAA,IACT,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,IAClB,CAAC,CAAA;AAEH,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd,CAAA;AACF,CAAA;;;ACzCA,SAAS,aAAa,CAAA,EAA+B;AACnD,EAAA,OAAO,OAAO,MAAM,QAAA,IAAY,CAAA,KAAM,QAAQ,CAAC,KAAA,CAAM,QAAQ,CAAC,CAAA;AAChE;AAGA,SAAS,cAAc,CAAA,EAAmD;AACxE,EAAA,OAAO,CAAA,KAAM,MAAA,IAAa,YAAA,CAAa,CAAC,IAAK,CAAA,GAAoB,MAAA;AACnE;AAGO,SAAS,QAAQ,GAAA,EAAwD;AAC9E,EAAA,MAAM,MAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACxC,IAAA,IAAI,CAAA,KAAM,MAAA,EAAW,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,GAAA;AACT;AAQO,IAAM,WAAN,MAAe;AAAA,EACH,IAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EAEjB,YAAY,MAAA,EAAqB;AAC/B,IAAA,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AACvB,IAAA,IAAA,CAAK,iBAAiB,MAAA,CAAO,cAAA;AAC7B,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAI,aAAA,CAAc,MAAM,CAAA;AAC7C,IAAA,IAAA,CAAK,IAAA,GAAO,IAAIA,4BAAA,CAAW;AAAA,MACzB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,gBAAgB,MAAA,CAAO,OAAA;AAAA,MACvB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,gBAAgB,MAAA,CAAO,cAAA;AAAA,MACvB,OAAO,MAAA,CAAO;AAAA,KACf,CAAA;AAAA,EACH;AAAA;AAAA,EAGQ,aAAA,GAAwC;AAC9C,IAAA,OAAO;AAAA,MACL,eAAe,IAAA,CAAK,QAAA;AAAA,MACpB,iBAAiB,IAAA,CAAK;AAAA,KACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,WAAA,GAA+C;AAC3D,IAAA,MAAM,OAAA,GAAU,KAAK,aAAA,EAAc;AACnC,IAAA,IAAI,CAAC,IAAA,CAAK,aAAA,CAAc,SAAA,IAAa,OAAO,OAAA;AAC5C,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,aAAA,CAAc,QAAA,EAAS;AAChD,IAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAClD,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OAAA,CACJ,SAAA,EACA,IAAA,EACA,SAAyB,MAAA,EACC;AAC1B,IAAA,MAAM,EAAE,UAAU,IAAA,EAAM,OAAA,KAAY,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MAC1D,MAAA;AAAA,MACA,IAAA,EAAM,OAAA;AAAA,MACN,KAAA,EAAO,EAAE,EAAA,EAAI,SAAA,EAAU;AAAA,MACvB,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,IAAA,EAAM,MAAA,KAAW,MAAA,GAAU,IAAA,IAAQ,EAAC,GAAK,MAAA;AAAA,MACzC,OAAA,EAAS;AAAA,KACV,CAAA;AACD,IAAA,OAAO;AAAA,MACL,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,IAAA,EAAM,OAAA;AAAA,MACN,OAAA,EAAS,aAAa,OAAO,CAAA;AAAA,MAC7B,UAAA,EAAY,KAAK,GAAA;AAAI,KACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,YAAA,CAAa,GAAA,EAAa,IAAA,EAAiD;AAC/E,IAAA,MAAM,EAAE,UAAU,IAAA,EAAM,OAAA,KAAY,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MAC1D,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,qBAAA;AAAA,MACN,KAAA,EAAO,EAAE,GAAA,EAAI;AAAA,MACb,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,IAAA,EAAM,QAAQ,EAAC;AAAA,MACf,OAAA,EAAS;AAAA,KACV,CAAA;AACD,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAO,CAAA,GAAI,UAAU,EAAC;AAC/C,IAAA,OAAO;AAAA,MACL,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,IAAA,EAAM,OAAA;AAAA,MACN,OAAA,EAAS,aAAa,OAAO,CAAA;AAAA,MAC7B,KAAA,EAAO,aAAA,CAAc,GAAA,CAAI,KAAK,CAAA;AAAA,MAC9B,aAAA,EAAe,IAAI,aAAA,KAAkB,IAAA;AAAA,MACrC,UAAA,EAAY,IAAI,UAAA,KAAe,IAAA;AAAA,MAC/B,eAAe,OAAO,GAAA,CAAI,aAAA,KAAkB,QAAA,GAAW,IAAI,aAAA,GAAgB,MAAA;AAAA,MAC3E,YAAY,OAAO,GAAA,CAAI,UAAA,KAAe,QAAA,GAAY,IAAI,UAAA,GAA4B,MAAA;AAAA,MAClF,UAAA,EAAY,KAAK,GAAA;AAAI,KACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAA,CACJ,MAAA,EACA,IAAA,EACkC;AAClC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,gBAAA;AAAA,MACN,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,IAAA,EAAM,EAAE,MAAA,EAAO;AAAA,MACf,WAAW,IAAA,EAAM;AAAA,KAClB,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,SAAS,IAAA,EAAkD;AAC/D,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,yBAAA;AAAA,MACN,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC;AAAA,KACD,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OAAA,CAAQ,cAAA,EAAwB,OAAA,EAA2C;AAC/E,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,wBAAA;AAAA,MACN,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,MAAM,OAAA,CAAQ;AAAA,QACZ,cAAA;AAAA,QACA,SAAA,EAAW,QAAQ,SAAA,KAAc,IAAA;AAAA,QACjC,SAAA,EAAW,QAAQ,SAAA,KAAc,IAAA;AAAA,QACjC,eAAA,EAAiB,QAAQ,eAAA,KAAoB,IAAA;AAAA,QAC7C,eAAe,OAAA,CAAQ,aAAA;AAAA,QACvB,gBAAgB,OAAA,CAAQ;AAAA,OACzB;AAAA,KACF,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAA,CAAQ,UAAA,EAAoB,IAAA,GAAuB,EAAC,EAA2B;AACnF,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,8BAAA;AAAA,MACN,KAAA,EAAO,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,EAAE,OAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,EAAE,GAAI,MAAA;AAAA,MAClE,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,MAAM,OAAA,CAAQ;AAAA,QACZ,UAAA;AAAA,QACA,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,QAAQ,IAAA,CAAK;AAAA,OACd;AAAA,KACF,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAA,CACJ,KAAA,EACA,IAAA,GAAuB,EAAC,EACO;AAC/B,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,oCAAA;AAAA,MACN,KAAA,EAAO,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,EAAE,OAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,EAAE,GAAI,MAAA;AAAA,MAClE,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,MAAM,OAAA,CAAQ;AAAA,QACZ,KAAA;AAAA,QACA,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,QAAQ,IAAA,CAAK;AAAA,OACd;AAAA,KACF,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,cAAA,CACJ,QAAA,EACA,IAAA,EAC+B;AAC/B,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,sCAAA;AAAA,MACN,OAAA,EAAS,MAAM,IAAA,CAAK,WAAA,EAAY;AAAA,MAChC,MAAM,OAAA,CAAQ;AAAA,QACZ,QAAA;AAAA,QACA,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,QAAQ,IAAA,CAAK,MAAA;AAAA,QACb,YAAY,IAAA,CAAK;AAAA,OAClB;AAAA,KACF,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;ACpRA,IAAM,QAAA,GAAW,kCAAA;AAEjB,SAAS,YAAY,MAAA,EAA4B;AAC/C,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,eAAA,EAAiB;AAC3D,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAA,KAAW,GAAG,CAAA;AAAA,EAC5E;AACA,EAAA,OAAO,KAAA;AACT;AAQO,SAAS,YAAA,CAAa,IAAA,GAAe,IAAA,CAAK,GAAA,EAAI,EAAW;AAC9D,EAAA,IAAI,QAAA,GAAW,EAAA;AACf,EAAA,IAAI,CAAA,GAAI,IAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,CAAA,EAAG,CAAA,EAAA,EAAK;AAC3B,IAAA,QAAA,GAAW,QAAA,CAAS,CAAA,GAAI,EAAE,CAAA,GAAI,QAAA;AAC9B,IAAA,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,EAAE,CAAA;AAAA,EACvB;AAEA,EAAA,MAAM,MAAA,GAAS,YAAY,EAAE,CAAA;AAC7B,EAAA,IAAI,UAAA,GAAa,EAAA;AACjB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,EAAI,CAAA,EAAA,EAAK;AAC3B,IAAA,UAAA,IAAc,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,GAAI,EAAE,CAAA;AAAA,EACvC;AAEA,EAAA,OAAO,QAAA,GAAW,UAAA;AACpB;AAGO,IAAM,mBAAA,GAAsB;AAe5B,SAAS,UAAU,GAAA,EAAqB;AAC7C,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,mBAAA,EAAqB,OAAO,GAAA;AAG9C,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,UAAA,EAAY,QAAU,CAAA,EAAG;AAC3C,IAAA,IAAI,OAAO,IAAA,KAAS,CAAA;AACpB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACnC,MAAA,IAAA,IAAQ,GAAA,CAAI,WAAW,CAAC,CAAA;AACxB,MAAA,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,IAAA,EAAM,QAAU,CAAA,KAAM,CAAA;AACvC,MAAA,GAAA,IAAO,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,mBAAA,EAAqB,CAAA,EAAA,EAAK;AAC5C,IAAA,IAAI,MAAM,CAAA,GAAI,CAAA;AACd,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,mBAAA,EAAqB;AACxD,MAAA,GAAA,GAAO,MAAM,EAAA,GAAK,QAAA,CAAS,QAAQ,GAAA,CAAI,CAAC,CAAC,CAAA,KAAO,CAAA;AAAA,IAClD;AACA,IAAA,MAAA,IAAU,QAAA,CAAS,MAAM,EAAE,CAAA;AAAA,EAC7B;AACA,EAAA,OAAO,MAAA;AACT;;;ACvDO,SAAS,cAAA,CAAe,KAAgC,QAAA,EAAwC;AACrG,EAAA,MAAM,MAAoB,EAAC;AAC3B,EAAA,IAAI,QAAA,MAAc,QAAA,GAAW,QAAA;AAC7B,EAAA,IAAI,CAAC,KAAK,OAAO,GAAA;AAEjB,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,IAAI,GAAG,CAAA;AAAA,EACtB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,GAAA,CAAI,MAAM,MAAA,CAAO,IAAA;AACjB,EAAA,GAAA,CAAI,OAAO,MAAA,CAAO,QAAA;AAClB,EAAA,GAAA,CAAI,KAAA,GAAQ,MAAA,CAAO,WAAA,CAAY,MAAA,CAAO,YAAY,CAAA;AAElD,EAAA,MAAM,MAAM,CAAC,IAAA,KAAiB,OAAO,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,IAAK,MAAA;AAC/D,EAAA,MAAM,SAAA,GAAY,IAAI,YAAY,CAAA;AAClC,EAAA,MAAM,SAAA,GAAY,IAAI,YAAY,CAAA;AAClC,EAAA,MAAM,WAAA,GAAc,IAAI,cAAc,CAAA;AACtC,EAAA,MAAM,UAAA,GAAa,IAAI,aAAa,CAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,IAAI,QAAQ,CAAA;AAC1B,EAAA,IAAI,SAAA,MAAe,SAAA,GAAY,SAAA;AAC/B,EAAA,IAAI,SAAA,MAAe,SAAA,GAAY,SAAA;AAC/B,EAAA,IAAI,WAAA,MAAiB,WAAA,GAAc,WAAA;AACnC,EAAA,IAAI,UAAA,MAAgB,UAAA,GAAa,UAAA;AACjC,EAAA,IAAI,KAAA,MAAW,KAAA,GAAQ,KAAA;AAEvB,EAAA,OAAO,GAAA;AACT","file":"chunk-SU25SELD.cjs","sourcesContent":["import type {\n JsonValue,\n MessagePlacement,\n MessagePosition,\n WidgetFormSubmit,\n WidgetSegment,\n WidgetStyle,\n WidgetType,\n XeniaAction,\n} from \"./types\";\n\nconst MESSAGE_TYPES: ReadonlySet<string> = new Set<MessagePlacement>([\n \"banner\",\n \"popup\",\n \"modal\",\n \"inline\",\n]);\n\nconst MESSAGE_POSITIONS: ReadonlySet<string> = new Set<MessagePosition>([\n \"top-left\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-right\",\n \"top\",\n \"bottom\",\n]);\n\n// NOTE: `widgetType` is deliberately NOT added to `ALL_TYPES`/`MESSAGE_TYPES` below — it is an\n// orthogonal field on message-placement actions, not a new `type` value. Keeping `type`'s\n// allowlist untouched is exactly what keeps the PHP SDK's `XeniaActions::KNOWN_TYPES` (same value\n// set) valid with zero PHP changes.\nconst WIDGET_TYPES: ReadonlySet<string> = new Set<WidgetType>([\"standard\", \"spin-wheel\"]);\n\nconst ALL_TYPES: ReadonlySet<string> = new Set<string>([\n \"swap\",\n \"hide\",\n \"show\",\n \"setContent\",\n \"redirect\",\n ...MESSAGE_TYPES,\n]);\n\n/** Type guard for a plain JSON object. */\nfunction isObject(v: JsonValue | undefined): v is { [k: string]: JsonValue } {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction asString(v: JsonValue | undefined): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\nfunction asNumber(v: JsonValue | undefined): number | undefined {\n return typeof v === \"number\" ? v : undefined;\n}\n\n/**\n * Validate and narrow a single raw entry into a {@link XeniaAction}.\n * Returns null for anything malformed so a bad entry can't crash the renderer.\n */\nfunction toAction(raw: JsonValue): XeniaAction | null {\n if (!isObject(raw)) return null;\n const type = asString(raw.type);\n if (!type || !ALL_TYPES.has(type)) return null;\n\n if (type === \"redirect\") {\n const url = asString(raw.url);\n return url ? { type, url } : null;\n }\n\n if (type === \"hide\" || type === \"show\") {\n const target = asString(raw.target);\n return target ? { type, target } : null;\n }\n\n if (type === \"swap\" || type === \"setContent\") {\n const target = asString(raw.target);\n if (!target) return null;\n return { type, target, html: asString(raw.html), text: asString(raw.text) };\n }\n\n // Message placement actions (banner/popup/modal/inline).\n const cta = isObject(raw.cta)\n ? {\n label: asString(raw.cta.label) ?? \"\",\n url: asString(raw.cta.url),\n event: asString(raw.cta.event),\n }\n : undefined;\n\n return {\n type: type as MessagePlacement,\n target: asString(raw.target),\n title: asString(raw.title),\n message: asString(raw.message),\n imageUrl: asString(raw.imageUrl),\n html: asString(raw.html),\n // A link-only CTA (empty label, e.g. a spin-wheel's data-xenia-wheel-cta —\n // label is meaningless there, the winHtml/lossHtml design supplies its own button text)\n // must still parse through — gating on `cta.label` alone silently dropped it.\n cta: cta && (cta.label || cta.url) ? cta : undefined,\n dismissAfterMs: asNumber(raw.dismissAfterMs),\n position: asMessagePosition(raw.position),\n widgetType: asWidgetType(raw.widgetType),\n segments: asSegments(raw.segments),\n formSubmit: asFormSubmit(raw.formSubmit),\n style: asWidgetStyle(raw.style),\n spinnerHtml: asString(raw.spinnerHtml),\n winHtml: asString(raw.winHtml),\n lossHtml: asString(raw.lossHtml),\n };\n}\n\nfunction asMessagePosition(v: JsonValue | undefined): MessagePosition | undefined {\n const s = asString(v);\n return s && MESSAGE_POSITIONS.has(s) ? (s as MessagePosition) : undefined;\n}\n\nfunction asWidgetType(v: JsonValue | undefined): WidgetType | undefined {\n const s = asString(v);\n return s && WIDGET_TYPES.has(s) ? (s as WidgetType) : undefined;\n}\n\n/** Narrow a raw `segments` array to label/color/isLoss-only entries — drops anything malformed. */\nfunction asSegments(v: JsonValue | undefined): WidgetSegment[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const segments: WidgetSegment[] = [];\n for (const entry of v) {\n if (!isObject(entry)) continue;\n const id = asString(entry.id);\n const label = asString(entry.label);\n if (!id || !label) continue;\n segments.push({\n id,\n label,\n colorHex: asString(entry.colorHex),\n isLoss: entry.isLoss === true,\n });\n }\n return segments.length ? segments : undefined;\n}\n\n/**\n * Narrow a raw `formSubmit` envelope. Defensive by design (same as the rest of this\n * module) — a malformed envelope (missing `mode`) is dropped entirely rather than\n * passed through half-formed, since the SDK's endpoint-selection logic depends on it.\n */\nfunction asFormSubmit(v: JsonValue | undefined): WidgetFormSubmit | undefined {\n if (!isObject(v)) return undefined;\n const mode = asString(v.mode);\n if (!mode) return undefined;\n return {\n requiresResolve: v.requiresResolve === true,\n mode,\n flowRef: asString(v.flowRef),\n bindingRef: asString(v.bindingRef),\n successDisplayMs: asNumber(v.successDisplayMs),\n };\n}\n\n/**\n * Narrow a raw `style` override. Every field is independently optional/defensive (same\n * philosophy as the rest of this module) — a malformed value for one field just drops that\n * field, it never discards the whole `style` object.\n */\nfunction asWidgetStyle(v: JsonValue | undefined): WidgetStyle | undefined {\n if (!isObject(v)) return undefined;\n const style: WidgetStyle = {\n hideCloseButton: v.hideCloseButton === true,\n hideOverlay: v.hideOverlay === true,\n };\n const hasAny = style.hideCloseButton || style.hideOverlay;\n return hasAny ? style : undefined;\n}\n\n/**\n * Parse render actions out of a webhook-response body.\n *\n * The convention: marketers return `{ \"xeniaActions\": [ ... ] }` (or a bare\n * array) from the `webhook-response` node. Any body without a recognizable\n * `xeniaActions` array yields an empty list — a safe no-op.\n */\nexport function parseActions(body: JsonValue): XeniaAction[] {\n let list: JsonValue | undefined;\n if (Array.isArray(body)) {\n list = body;\n } else if (isObject(body) && Array.isArray(body.xeniaActions)) {\n list = body.xeniaActions;\n }\n if (!Array.isArray(list)) return [];\n\n const actions: XeniaAction[] = [];\n for (const entry of list) {\n const action = toAction(entry);\n if (action) actions.push(action);\n }\n return actions;\n}\n","import type { XeniaConfig } from \"./types\";\n\ninterface Cached {\n token: string;\n /** Epoch ms when the token should be considered stale. */\n expiresAt: number;\n}\n\n/** JWT `exp` (seconds) if decodable, else undefined. Best-effort, no verify. */\nfunction decodeExp(token: string): number | undefined {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return undefined;\n const json = JSON.parse(atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\")));\n return typeof json.exp === \"number\" ? json.exp * 1000 : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolves the Bearer token `XeniaApi` attaches to every request, caching a\n * short-lived token from `config.getToken` until ~30s before expiry. A static\n * `config.token` is returned as-is. Isomorphic (browser + Node ≥18, both have\n * global `atob`).\n */\nexport class TokenProvider {\n private readonly config: XeniaConfig;\n private cached: Cached | null = null;\n private inflight: Promise<string> | null = null;\n\n constructor(config: XeniaConfig) {\n this.config = config;\n }\n\n /** Whether a token source is configured at all — lets callers skip resolution entirely. */\n hasSource(): boolean {\n return Boolean(this.config.token || this.config.getToken);\n }\n\n readonly getToken = async (): Promise<string> => {\n if (this.config.token && !this.config.getToken) return this.config.token;\n\n const now = Date.now();\n if (this.cached && this.cached.expiresAt > now) return this.cached.token;\n if (this.inflight) return this.inflight;\n\n if (!this.config.getToken) {\n throw new Error(\"No token source: set config.token or config.getToken.\");\n }\n\n this.inflight = Promise.resolve(this.config.getToken())\n .then((token) => {\n const exp = decodeExp(token);\n // Refresh 30s before real expiry; default 5 min if the token is opaque.\n const expiresAt = exp ? exp - 30_000 : now + 5 * 60_000;\n this.cached = { token, expiresAt };\n return token;\n })\n .finally(() => {\n this.inflight = null;\n });\n\n return this.inflight;\n };\n}\n","import { parseActions } from \"./actions\";\nimport { HttpClient } from \"./http-client\";\nimport { TokenProvider } from \"./token-provider\";\nimport type {\n AnalyticsIngestResponse,\n ConsentState,\n IdentifyRequest,\n IdentifyResponse,\n JsonObject,\n JsonValue,\n ResolveBatchItem,\n ResolveBatchResult,\n ResolveEntriesResult,\n ResolveOptions,\n ResolveResult,\n WebhookResponse,\n WidgetPrize,\n WidgetSubmitResponse,\n WidgetType,\n XeniaConfig,\n XeniaEvent,\n} from \"./types\";\n\n/** Type guard for a plain JSON object (as opposed to an array/primitive/null). */\nfunction isJsonObject(v: JsonValue): v is JsonObject {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/** Narrow a raw `prize` field off a `/widget-submissions` response body. */\nfunction asWidgetPrize(v: JsonValue | undefined): WidgetPrize | undefined {\n return v !== undefined && isJsonObject(v) ? (v as WidgetPrize) : undefined;\n}\n\n/** Drop `undefined` values so the JSON body stays clean. */\nexport function compact(obj: Record<string, JsonValue | undefined>): JsonObject {\n const out: JsonObject = {};\n for (const [k, v] of Object.entries(obj)) {\n if (v !== undefined) out[k] = v;\n }\n return out;\n}\n\n/**\n * Low-level, isomorphic Xenia API client. Wraps the raw endpoints; identity,\n * UTM capture, and action rendering are layered on top by the client runtime.\n * All paths are relative to `baseUrl`, which defaults to the hosted engine\n * (`https://engine.xeniamartech.com/xenia`) when omitted from config.\n */\nexport class XeniaApi {\n private readonly http: HttpClient;\n private readonly tenantId: string;\n private readonly environmentKey: string;\n private readonly tokenProvider: TokenProvider;\n\n constructor(config: XeniaConfig) {\n this.tenantId = config.tenantId;\n this.environmentKey = config.environmentKey;\n this.tokenProvider = new TokenProvider(config);\n this.http = new HttpClient({\n baseUrl: config.baseUrl,\n defaultHeaders: config.headers,\n timeout: config.timeout,\n retry: config.retry,\n circuitBreaker: config.circuitBreaker,\n debug: config.debug,\n });\n }\n\n /** Tenant-scope headers required by header-scoped endpoints. */\n private tenantHeaders(): Record<string, string> {\n return {\n \"X-Tenant-Id\": this.tenantId,\n \"X-Environment\": this.environmentKey,\n };\n }\n\n /**\n * Tenant headers plus a resolved `Authorization: Bearer` header when\n * `config.token`/`config.getToken` is set — e.g. required by a webhook\n * trigger node configured with its own auth token. No-op (tenant headers\n * only) when no token source is configured, so this is safe to call\n * unconditionally on every request.\n */\n private async authHeaders(): Promise<Record<string, string>> {\n const headers = this.tenantHeaders();\n if (!this.tokenProvider.hasSource()) return headers;\n const token = await this.tokenProvider.getToken();\n if (token) headers.Authorization = `Bearer ${token}`;\n return headers;\n }\n\n /**\n * Webhook request/response — `GET|POST /flow?id={triggerId}`. Held open by the\n * backend until a `webhook-response` node resolves. Returns the normalized\n * response, including any `xeniaActions` parsed from the body.\n *\n * Not retried by default: the backend long-polls this call, so a retry would\n * duplicate the journey run.\n */\n async webhook(\n triggerId: string,\n data?: JsonValue,\n method: \"GET\" | \"POST\" = \"POST\",\n ): Promise<WebhookResponse> {\n const { response, data: rawBody } = await this.http.request({\n method,\n path: \"/flow\",\n query: { id: triggerId },\n headers: await this.authHeaders(),\n body: method === \"POST\" ? (data ?? {}) : undefined,\n noRetry: true,\n });\n return {\n status: response.status,\n body: rawBody,\n actions: parseActions(rawBody),\n receivedAt: Date.now(),\n };\n }\n\n /**\n * Widget form submission — `POST /widget-submissions?ref={bindingRef}`. Used whenever the\n * action's `formSubmit.requiresResolve` is true (spin-wheel, which must have a\n * server-resolved outcome before anything renders) or `mode === \"endpoint\"` — the common\n * plain-popup case (`mode === \"journey\" && !requiresResolve`) bypasses this entirely and calls\n * {@link webhook} against `flowRef` instead (see `XeniaClient.submitWidgetForm`'s endpoint\n * selection).\n *\n * Not retried (`noRetry: true`), styled like {@link webhook} — a retried POST must never\n * double-fire a journey or double-resolve a prize server-side.\n */\n async submitWidget(ref: string, body?: JsonValue): Promise<WidgetSubmitResponse> {\n const { response, data: rawBody } = await this.http.request({\n method: \"POST\",\n path: \"/widget-submissions\",\n query: { ref },\n headers: await this.authHeaders(),\n body: body ?? {},\n noRetry: true,\n });\n const obj = isJsonObject(rawBody) ? rawBody : {};\n return {\n status: response.status,\n body: rawBody,\n actions: parseActions(rawBody),\n prize: asWidgetPrize(obj.prize),\n alreadyPlayed: obj.alreadyPlayed === true,\n dispatched: obj.dispatched === true,\n dispatchError: typeof obj.dispatchError === \"string\" ? obj.dispatchError : undefined,\n widgetType: typeof obj.widgetType === \"string\" ? (obj.widgetType as WidgetType) : undefined,\n receivedAt: Date.now(),\n };\n }\n\n /**\n * Unified event batch (max 100/request per the backend) — `POST /api/events/v1`.\n * Records analytics for every event and matches/advances a journey for any\n * event with `trigger: true`. Replaces the old `sendEvent()` (journey trigger)\n * and `sendAnalytics()` (CDP) calls.\n */\n async sendEvents(\n events: XeniaEvent[],\n opts?: { keepalive?: boolean },\n ): Promise<AnalyticsIngestResponse> {\n const { data } = await this.http.request({\n method: \"POST\",\n path: \"/api/events/v1\",\n headers: await this.authHeaders(),\n body: { events } as unknown as JsonObject,\n keepalive: opts?.keepalive,\n });\n return data as unknown as AnalyticsIngestResponse;\n }\n\n /** Bind visitor→user — `POST /api/events/v1/identify`. */\n async identify(body: IdentifyRequest): Promise<IdentifyResponse> {\n const { data } = await this.http.request({\n method: \"POST\",\n path: \"/api/events/v1/identify\",\n headers: await this.authHeaders(),\n body: body as unknown as JsonObject,\n });\n return data as unknown as IdentifyResponse;\n }\n\n /**\n * Update consent — `POST /api/events/v1/consent`.\n *\n * The three scope flags are required (non-null) by the backend, so an omitted\n * one is sent as an explicit `false` rather than left out: a partial body like\n * `consent({ analytics: true })` — the shape most callers actually write — is\n * otherwise rejected with a 400 and the consent record is never stored.\n */\n async consent(xeniaVisitorId: string, consent: ConsentState): Promise<JsonValue> {\n const { data } = await this.http.request({\n method: \"POST\",\n path: \"/api/events/v1/consent\",\n headers: await this.authHeaders(),\n body: compact({\n xeniaVisitorId,\n analytics: consent.analytics === true,\n marketing: consent.marketing === true,\n personalization: consent.personalization === true,\n consentSource: consent.consentSource,\n consentVersion: consent.consentVersion,\n }),\n });\n return data;\n }\n\n /**\n * Resolve in-entry content personalization for one content key —\n * `POST /api/personalization/resolve?merge=<bool>`. Requires the SDK Bearer\n * token (same credential as events; resolve is auth-required). `merge=true`\n * returns server-spliced `content`; otherwise splice `swaps` client-side.\n */\n async resolve(contentKey: string, opts: ResolveOptions = {}): Promise<ResolveResult> {\n const { data } = await this.http.request({\n method: \"POST\",\n path: \"/api/personalization/resolve\",\n query: opts.merge !== undefined ? { merge: String(opts.merge) } : undefined,\n headers: await this.authHeaders(),\n body: compact({\n contentKey,\n data: opts.data as JsonValue,\n locale: opts.locale,\n }),\n });\n return data as unknown as ResolveResult;\n }\n\n /**\n * Resolve several content keys in one round-trip (≤50) —\n * `POST /api/personalization/resolve-batch?merge=<bool>`. Same auth/merge\n * semantics as {@link resolve}.\n */\n async resolveBatch(\n items: ResolveBatchItem[],\n opts: ResolveOptions = {},\n ): Promise<ResolveBatchResult[]> {\n const { data } = await this.http.request({\n method: \"POST\",\n path: \"/api/personalization/resolve-batch\",\n query: opts.merge !== undefined ? { merge: String(opts.merge) } : undefined,\n headers: await this.authHeaders(),\n body: compact({\n items: items as unknown as JsonValue,\n data: opts.data as JsonValue,\n locale: opts.locale,\n }),\n });\n return data as unknown as ResolveBatchResult[];\n }\n\n /**\n * Resolve personalized CMS entries by id for one visitor (≤200) —\n * `POST /api/personalization/resolve-entries`. The page resolver\n * ({@link personalizeContent}) calls this once per round with the runtime\n * targets it found; callers rarely need it directly.\n */\n async resolveEntries(\n entryIds: string[],\n opts: ResolveOptions & { contentKey: string },\n ): Promise<ResolveEntriesResult> {\n const { data } = await this.http.request({\n method: \"POST\",\n path: \"/api/personalization/resolve-entries\",\n headers: await this.authHeaders(),\n body: compact({\n entryIds: entryIds as unknown as JsonValue,\n data: opts.data as JsonValue,\n locale: opts.locale,\n contentKey: opts.contentKey,\n }),\n });\n return data as unknown as ResolveEntriesResult;\n }\n}\n","/** Crockford base32 alphabet (no I/L/O/U, avoids visual ambiguity) — used by ULID. */\nconst ENCODING = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\nfunction randomBytes(length: number): Uint8Array {\n const bytes = new Uint8Array(length);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n return bytes;\n}\n\n/**\n * Generate a ULID (Universally Unique Lexicographically Sortable Identifier):\n * a 48-bit timestamp (10 Crockford-base32 chars) + 80 bits of randomness (16\n * chars), 26 chars total — matches the backend's `eventId` field (`≤26`\n * chars). No dependency; implemented inline to keep the SDK lean.\n */\nexport function generateUlid(time: number = Date.now()): string {\n let timePart = \"\";\n let t = time;\n for (let i = 9; i >= 0; i--) {\n timePart = ENCODING[t % 32] + timePart;\n t = Math.floor(t / 32);\n }\n\n const random = randomBytes(16);\n let randomPart = \"\";\n for (let i = 0; i < 16; i++) {\n randomPart += ENCODING[random[i] % 32];\n }\n\n return timePart + randomPart;\n}\n\n/** Backend cap on `eventId` (`@Size(max = 26)`), which a ULID exactly fills. */\nexport const MAX_EVENT_ID_LENGTH = 26;\n\n/**\n * Coerce a caller-supplied dedup key into something the backend will accept.\n *\n * `eventId` is capped at 26 characters server-side, and an over-length value\n * rejects the ENTIRE batch it rides in — not just its own event. That is easy to\n * hit: `\"ord-\" + <uuid>` is 40. Rather than drop the caller's idempotency key or\n * let the batch 400, fold anything longer into a deterministic 26-char digest.\n * Deterministic is the point — the same order id always yields the same event id,\n * so re-firing it still de-dupes to one conversion, which is what the key is for.\n *\n * Truncation is deliberately not used: `\"ord-<uuid>\"` values share a long common\n * prefix, so cutting to 26 chars can map two different orders onto one id.\n */\nexport function toEventId(raw: string): string {\n if (raw.length <= MAX_EVENT_ID_LENGTH) return raw;\n\n // Two independently-seeded FNV-1a passes → 128 bits, encoded Crockford base32.\n let out = \"\";\n for (const seed of [0x811c9dc5, 0x01000193]) {\n let hash = seed >>> 0;\n for (let i = 0; i < raw.length; i++) {\n hash ^= raw.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n out += ENCODING[hash % 32];\n }\n }\n // Fold the accumulated stream down to exactly the cap, order-dependently.\n let digest = \"\";\n for (let i = 0; i < MAX_EVENT_ID_LENGTH; i++) {\n let acc = i + 1;\n for (let j = i; j < out.length; j += MAX_EVENT_ID_LENGTH) {\n acc = (acc * 31 + ENCODING.indexOf(out[j])) >>> 0;\n }\n digest += ENCODING[acc % 32];\n }\n return digest;\n}\n","import type { EventContext } from \"./types\";\n\n/**\n * Derive the SDK-provided page/campaign fields from a URL — the server-side counterpart to the\n * browser client's `Identity.collectContext()`, which reads the same fields off `window.location`.\n *\n * Exists because a server runtime has no ambient `window`: a Node client is constructed per request,\n * so the one thing it needs handed over is the URL being served. Everything a journey rule can\n * reference — `path`, `query.<name>`, `url`, `referrer`, `utmSource`/`utmMedium`/`utmCampaign`/\n * `utmContent`/`utmId` — is derived here rather than by each app, so a server-rendered page gets the\n * same field set a browser page does without hand-rolling UTM parsing at every call site.\n *\n * Field names and semantics deliberately mirror `collectContext()` exactly: `query` is the flattened\n * search params, UTMs come from the standard `utm_*` params, and absent values are omitted rather\n * than set to `\"\"` (a blank string is a value a condition could accidentally match).\n *\n * @param url Absolute URL of the request being served (e.g. `https://shop.example/product/x?ref=a`).\n * A relative or unparseable value yields an empty context rather than throwing.\n * @param referrer Optional referring URL, typically the request's `Referer` header.\n */\nexport function contextFromUrl(url: string | null | undefined, referrer?: string | null): EventContext {\n const ctx: EventContext = {};\n if (referrer) ctx.referrer = referrer;\n if (!url) return ctx;\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return ctx; // not an absolute URL — nothing safely derivable\n }\n\n ctx.url = parsed.href;\n ctx.path = parsed.pathname;\n ctx.query = Object.fromEntries(parsed.searchParams);\n\n const utm = (name: string) => parsed.searchParams.get(name) || undefined;\n const utmSource = utm(\"utm_source\");\n const utmMedium = utm(\"utm_medium\");\n const utmCampaign = utm(\"utm_campaign\");\n const utmContent = utm(\"utm_content\");\n const utmId = utm(\"utm_id\");\n if (utmSource) ctx.utmSource = utmSource;\n if (utmMedium) ctx.utmMedium = utmMedium;\n if (utmCampaign) ctx.utmCampaign = utmCampaign;\n if (utmContent) ctx.utmContent = utmContent;\n if (utmId) ctx.utmId = utmId;\n\n return ctx;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkGXJLU3RE_cjs = require('./chunk-GXJLU3RE.cjs');
|
|
4
4
|
|
|
5
5
|
// src/server/cookies.ts
|
|
6
6
|
function parseCookies(header) {
|
|
@@ -21,10 +21,10 @@ function parseCookies(header) {
|
|
|
21
21
|
return out;
|
|
22
22
|
}
|
|
23
23
|
function getVisitorId(cookieHeader, prefix) {
|
|
24
|
-
return parseCookies(cookieHeader)[
|
|
24
|
+
return parseCookies(cookieHeader)[chunkGXJLU3RE_cjs.visitorCookieName(prefix)] ?? null;
|
|
25
25
|
}
|
|
26
26
|
function getConsent(cookieHeader, prefix) {
|
|
27
|
-
const raw = parseCookies(cookieHeader)[
|
|
27
|
+
const raw = parseCookies(cookieHeader)[chunkGXJLU3RE_cjs.consentCookieName(prefix)];
|
|
28
28
|
if (!raw) return { analytics: false, marketing: false, personalization: false };
|
|
29
29
|
try {
|
|
30
30
|
const parsed = JSON.parse(raw);
|
|
@@ -42,5 +42,5 @@ function getConsent(cookieHeader, prefix) {
|
|
|
42
42
|
exports.getConsent = getConsent;
|
|
43
43
|
exports.getVisitorId = getVisitorId;
|
|
44
44
|
exports.parseCookies = parseCookies;
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
46
|
-
//# sourceMappingURL=chunk-
|
|
45
|
+
//# sourceMappingURL=chunk-UUIKUU5W.cjs.map
|
|
46
|
+
//# sourceMappingURL=chunk-UUIKUU5W.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/cookies.ts"],"names":["visitorCookieName","consentCookieName"],"mappings":";;;;;AAsBO,SAAS,aAAa,MAAA,EAA2D;AACtF,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,IAAI,CAAC,QAAQ,OAAO,GAAA;AACpB,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,EAAG;AACpC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC5B,IAAA,IAAI,QAAQ,EAAA,EAAI;AAChB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,EAAE,IAAA,EAAK;AACpC,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAC,EAAE,IAAA,EAAK;AACvC,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,kBAAA,CAAmB,KAAK,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AACN,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AASO,SAAS,YAAA,CACd,cACA,MAAA,EACe;AACf,EAAA,OAAO,aAAa,YAAY,CAAA,CAAEA,mCAAA,CAAkB,MAAM,CAAC,CAAA,IAAK,IAAA;AAClE;AAQO,SAAS,UAAA,CACd,cACA,MAAA,EACc;AACd,EAAA,MAAM,MAAM,YAAA,CAAa,YAAY,CAAA,CAAEC,mCAAA,CAAkB,MAAM,CAAC,CAAA;AAChE,EAAA,IAAI,CAAC,KAAK,OAAO,EAAE,WAAW,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAM;AAC9E,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AAC1D,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,eAAA,EAAiB,MAAA,CAAO,GAAA,CAAI,iBAAiB;AAAA,KAC/C;AAAA,EACF;AACF","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/server/cookies.ts"],"names":["visitorCookieName","consentCookieName"],"mappings":";;;;;AAsBO,SAAS,aAAa,MAAA,EAA2D;AACtF,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,IAAI,CAAC,QAAQ,OAAO,GAAA;AACpB,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,EAAG;AACpC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC5B,IAAA,IAAI,QAAQ,EAAA,EAAI;AAChB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,EAAE,IAAA,EAAK;AACpC,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAC,EAAE,IAAA,EAAK;AACvC,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,kBAAA,CAAmB,KAAK,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AACN,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AASO,SAAS,YAAA,CACd,cACA,MAAA,EACe;AACf,EAAA,OAAO,aAAa,YAAY,CAAA,CAAEA,mCAAA,CAAkB,MAAM,CAAC,CAAA,IAAK,IAAA;AAClE;AAQO,SAAS,UAAA,CACd,cACA,MAAA,EACc;AACd,EAAA,MAAM,MAAM,YAAA,CAAa,YAAY,CAAA,CAAEC,mCAAA,CAAkB,MAAM,CAAC,CAAA;AAChE,EAAA,IAAI,CAAC,KAAK,OAAO,EAAE,WAAW,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAM;AAC9E,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AAC1D,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,eAAA,EAAiB,MAAA,CAAO,GAAA,CAAI,iBAAiB;AAAA,KAC/C;AAAA,EACF;AACF","file":"chunk-UUIKUU5W.cjs","sourcesContent":["import {\n CONSENT_COOKIE,\n VISITOR_COOKIE,\n consentCookie,\n consentCookieName,\n visitorCookieName,\n} from \"../core/cookie-names\";\nimport type { ConsentState } from \"../core/types\";\n\n/**\n * Cookie names the SDK reads server-side (set by the browser SDK / your app).\n *\n * The constants are the DEFAULT-prefix names; the functions build the name for any prefix. If you\n * pass `config.prefix` to the browser client, pass the same prefix here — the browser namespaces\n * the cookie by it, so the default name won't be there to find.\n */\nexport { CONSENT_COOKIE, VISITOR_COOKIE, consentCookie, consentCookieName, visitorCookieName };\n\n/**\n * Parse a raw `Cookie` header into a map. Framework-agnostic so it works with\n * `Request.headers.get(\"cookie\")`, Node `req.headers.cookie`, etc.\n */\nexport function parseCookies(header: string | null | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!header) return out;\n for (const part of header.split(\";\")) {\n const idx = part.indexOf(\"=\");\n if (idx === -1) continue;\n const key = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (!key) continue;\n try {\n out[key] = decodeURIComponent(value);\n } catch {\n out[key] = value; // not URI-encoded (e.g. a stray `%` in another app's cookie): keep it as sent\n }\n }\n return out;\n}\n\n/**\n * Read the visitor id the browser SDK wrote, so a server-side event can be bound to the same\n * visitor (`createXeniaServer({ visitorId })`) and attribute to a browser-entered journey.\n *\n * @param prefix Must match the browser client's `config.prefix`. The cookie is namespaced by it, so\n * a mismatch finds nothing and quietly leaves the server with no visitor.\n */\nexport function getVisitorId(\n cookieHeader: string | null | undefined,\n prefix?: string,\n): string | null {\n return parseCookies(cookieHeader)[visitorCookieName(prefix)] ?? null;\n}\n\n/**\n * Read consent from a cookie header. Accepts a JSON blob or a comma-list of\n * granted scopes (e.g. `analytics,personalization`). Absent → all denied.\n *\n * @param prefix Must match the browser client's `config.prefix` — see {@link getVisitorId}.\n */\nexport function getConsent(\n cookieHeader: string | null | undefined,\n prefix?: string,\n): ConsentState {\n const raw = parseCookies(cookieHeader)[consentCookieName(prefix)];\n if (!raw) return { analytics: false, marketing: false, personalization: false };\n try {\n const parsed = JSON.parse(raw) as ConsentState;\n return parsed;\n } catch {\n const scopes = new Set(raw.split(\",\").map((s) => s.trim()));\n return {\n analytics: scopes.has(\"analytics\"),\n marketing: scopes.has(\"marketing\"),\n personalization: scopes.has(\"personalization\"),\n };\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { visitorCookieName, consentCookieName } from './chunk-
|
|
1
|
+
import { visitorCookieName, consentCookieName } from './chunk-FSJMHXS6.js';
|
|
2
2
|
|
|
3
3
|
// src/server/cookies.ts
|
|
4
4
|
function parseCookies(header) {
|
|
@@ -38,5 +38,5 @@ function getConsent(cookieHeader, prefix) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export { getConsent, getVisitorId, parseCookies };
|
|
41
|
-
//# sourceMappingURL=chunk-
|
|
42
|
-
//# sourceMappingURL=chunk-
|
|
41
|
+
//# sourceMappingURL=chunk-UVTFGQR6.js.map
|
|
42
|
+
//# sourceMappingURL=chunk-UVTFGQR6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/cookies.ts"],"names":[],"mappings":";;;AAsBO,SAAS,aAAa,MAAA,EAA2D;AACtF,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,IAAI,CAAC,QAAQ,OAAO,GAAA;AACpB,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,EAAG;AACpC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC5B,IAAA,IAAI,QAAQ,EAAA,EAAI;AAChB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,EAAE,IAAA,EAAK;AACpC,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAC,EAAE,IAAA,EAAK;AACvC,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,kBAAA,CAAmB,KAAK,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AACN,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AASO,SAAS,YAAA,CACd,cACA,MAAA,EACe;AACf,EAAA,OAAO,aAAa,YAAY,CAAA,CAAE,iBAAA,CAAkB,MAAM,CAAC,CAAA,IAAK,IAAA;AAClE;AAQO,SAAS,UAAA,CACd,cACA,MAAA,EACc;AACd,EAAA,MAAM,MAAM,YAAA,CAAa,YAAY,CAAA,CAAE,iBAAA,CAAkB,MAAM,CAAC,CAAA;AAChE,EAAA,IAAI,CAAC,KAAK,OAAO,EAAE,WAAW,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAM;AAC9E,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AAC1D,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,eAAA,EAAiB,MAAA,CAAO,GAAA,CAAI,iBAAiB;AAAA,KAC/C;AAAA,EACF;AACF","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/server/cookies.ts"],"names":[],"mappings":";;;AAsBO,SAAS,aAAa,MAAA,EAA2D;AACtF,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,IAAI,CAAC,QAAQ,OAAO,GAAA;AACpB,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,EAAG;AACpC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC5B,IAAA,IAAI,QAAQ,EAAA,EAAI;AAChB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,EAAE,IAAA,EAAK;AACpC,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAC,EAAE,IAAA,EAAK;AACvC,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,kBAAA,CAAmB,KAAK,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AACN,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AASO,SAAS,YAAA,CACd,cACA,MAAA,EACe;AACf,EAAA,OAAO,aAAa,YAAY,CAAA,CAAE,iBAAA,CAAkB,MAAM,CAAC,CAAA,IAAK,IAAA;AAClE;AAQO,SAAS,UAAA,CACd,cACA,MAAA,EACc;AACd,EAAA,MAAM,MAAM,YAAA,CAAa,YAAY,CAAA,CAAE,iBAAA,CAAkB,MAAM,CAAC,CAAA;AAChE,EAAA,IAAI,CAAC,KAAK,OAAO,EAAE,WAAW,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAM;AAC9E,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AAC1D,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA;AAAA,MACjC,eAAA,EAAiB,MAAA,CAAO,GAAA,CAAI,iBAAiB;AAAA,KAC/C;AAAA,EACF;AACF","file":"chunk-UVTFGQR6.js","sourcesContent":["import {\n CONSENT_COOKIE,\n VISITOR_COOKIE,\n consentCookie,\n consentCookieName,\n visitorCookieName,\n} from \"../core/cookie-names\";\nimport type { ConsentState } from \"../core/types\";\n\n/**\n * Cookie names the SDK reads server-side (set by the browser SDK / your app).\n *\n * The constants are the DEFAULT-prefix names; the functions build the name for any prefix. If you\n * pass `config.prefix` to the browser client, pass the same prefix here — the browser namespaces\n * the cookie by it, so the default name won't be there to find.\n */\nexport { CONSENT_COOKIE, VISITOR_COOKIE, consentCookie, consentCookieName, visitorCookieName };\n\n/**\n * Parse a raw `Cookie` header into a map. Framework-agnostic so it works with\n * `Request.headers.get(\"cookie\")`, Node `req.headers.cookie`, etc.\n */\nexport function parseCookies(header: string | null | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!header) return out;\n for (const part of header.split(\";\")) {\n const idx = part.indexOf(\"=\");\n if (idx === -1) continue;\n const key = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (!key) continue;\n try {\n out[key] = decodeURIComponent(value);\n } catch {\n out[key] = value; // not URI-encoded (e.g. a stray `%` in another app's cookie): keep it as sent\n }\n }\n return out;\n}\n\n/**\n * Read the visitor id the browser SDK wrote, so a server-side event can be bound to the same\n * visitor (`createXeniaServer({ visitorId })`) and attribute to a browser-entered journey.\n *\n * @param prefix Must match the browser client's `config.prefix`. The cookie is namespaced by it, so\n * a mismatch finds nothing and quietly leaves the server with no visitor.\n */\nexport function getVisitorId(\n cookieHeader: string | null | undefined,\n prefix?: string,\n): string | null {\n return parseCookies(cookieHeader)[visitorCookieName(prefix)] ?? null;\n}\n\n/**\n * Read consent from a cookie header. Accepts a JSON blob or a comma-list of\n * granted scopes (e.g. `analytics,personalization`). Absent → all denied.\n *\n * @param prefix Must match the browser client's `config.prefix` — see {@link getVisitorId}.\n */\nexport function getConsent(\n cookieHeader: string | null | undefined,\n prefix?: string,\n): ConsentState {\n const raw = parseCookies(cookieHeader)[consentCookieName(prefix)];\n if (!raw) return { analytics: false, marketing: false, personalization: false };\n try {\n const parsed = JSON.parse(raw) as ConsentState;\n return parsed;\n } catch {\n const scopes = new Set(raw.split(\",\").map((s) => s.trim()));\n return {\n analytics: scopes.has(\"analytics\"),\n marketing: scopes.has(\"marketing\"),\n personalization: scopes.has(\"personalization\"),\n };\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { parseCookies } from './chunk-
|
|
2
|
-
import { DEFAULT_PREFIX, consentCookieName, DEFAULT_BASE_URL } from './chunk-
|
|
1
|
+
import { parseCookies } from './chunk-UVTFGQR6.js';
|
|
2
|
+
import { DEFAULT_PREFIX, consentCookieName, DEFAULT_BASE_URL } from './chunk-FSJMHXS6.js';
|
|
3
3
|
|
|
4
4
|
// src/edge/consent.ts
|
|
5
5
|
function edgeConsent(headers, opts = {}) {
|
|
@@ -294,13 +294,42 @@ function swapGroups(decisions) {
|
|
|
294
294
|
}
|
|
295
295
|
return [...byBase.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([base, swaps]) => ({ base, swaps: [...swaps.values()].sort(([a], [b]) => a.localeCompare(b)) }));
|
|
296
296
|
}
|
|
297
|
-
async function
|
|
297
|
+
async function deflate(text) {
|
|
298
|
+
const stream = new Response(text).body.pipeThrough(new CompressionStream("deflate-raw"));
|
|
299
|
+
return new Uint8Array(await new Response(stream).arrayBuffer());
|
|
300
|
+
}
|
|
301
|
+
async function inflate(bytes) {
|
|
302
|
+
const stream = new Response(bytes).body.pipeThrough(new DecompressionStream("deflate-raw"));
|
|
303
|
+
return new Response(stream).text();
|
|
304
|
+
}
|
|
305
|
+
async function encodeVariant(groups, secret, extra, entries) {
|
|
298
306
|
const g = groups.map((x) => [x.base, x.swaps]);
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
307
|
+
const ez = entries?.length ? b64url(await deflate(JSON.stringify(entries))) : void 0;
|
|
308
|
+
const payloadOf = (x, withEntries) => b64url(
|
|
309
|
+
enc2.encode(
|
|
310
|
+
JSON.stringify({
|
|
311
|
+
g,
|
|
312
|
+
...ez ? withEntries ? { ez } : { ed: entries.length } : {},
|
|
313
|
+
...x === void 0 ? {} : { x }
|
|
314
|
+
})
|
|
315
|
+
)
|
|
316
|
+
);
|
|
317
|
+
let payload = payloadOf(extra, true);
|
|
318
|
+
if (payload.length > MAX_PAYLOAD && extra !== void 0) payload = payloadOf(void 0, true);
|
|
319
|
+
if (payload.length > MAX_PAYLOAD && ez) payload = payloadOf(void 0, false);
|
|
302
320
|
return `${payload}.${await sign(secret, payload)}`;
|
|
303
321
|
}
|
|
322
|
+
function variantEntries(decisions, entryDecisions) {
|
|
323
|
+
if (!entryDecisions) return [];
|
|
324
|
+
return decisions.filter((d) => d.personalized).flatMap((d) => entryDecisions[d.contentKey] ?? []);
|
|
325
|
+
}
|
|
326
|
+
function variantEntryResolver(entries, contentKey) {
|
|
327
|
+
const mine = (entries ?? []).filter((d) => d.contentKey === contentKey);
|
|
328
|
+
return async (ids) => {
|
|
329
|
+
const wanted = new Set(ids);
|
|
330
|
+
return mine.filter((d) => wanted.has(d.target));
|
|
331
|
+
};
|
|
332
|
+
}
|
|
304
333
|
async function decodeVariant(token, secret) {
|
|
305
334
|
const [payload, mac, rest] = token.split(".");
|
|
306
335
|
if (!payload || !mac || rest !== void 0 || payload.length > MAX_PAYLOAD) return null;
|
|
@@ -308,7 +337,13 @@ async function decodeVariant(token, secret) {
|
|
|
308
337
|
try {
|
|
309
338
|
const raw = JSON.parse(new TextDecoder().decode(fromB64url(payload)));
|
|
310
339
|
const groups = raw.g.map(([base, swaps]) => ({ base, swaps }));
|
|
311
|
-
|
|
340
|
+
const entries = raw.ez ? JSON.parse(await inflate(fromB64url(raw.ez))) : void 0;
|
|
341
|
+
return {
|
|
342
|
+
groups,
|
|
343
|
+
...raw.x === void 0 ? {} : { extra: raw.x },
|
|
344
|
+
...Array.isArray(entries) ? { entries } : {},
|
|
345
|
+
...typeof raw.ed === "number" && raw.ed > 0 ? { entriesDropped: raw.ed } : {}
|
|
346
|
+
};
|
|
312
347
|
} catch {
|
|
313
348
|
return null;
|
|
314
349
|
}
|
|
@@ -317,9 +352,11 @@ async function decodeVariant(token, secret) {
|
|
|
317
352
|
// src/edge/manifest.ts
|
|
318
353
|
async function fetchManifest(opts) {
|
|
319
354
|
const base = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
355
|
+
const headers = new Headers(opts.init?.headers);
|
|
356
|
+
headers.set("Authorization", `Bearer ${opts.token}`);
|
|
320
357
|
const res = await (opts.fetch ?? fetch)(`${base}/api/personalization/edge/manifest`, {
|
|
321
358
|
...opts.init,
|
|
322
|
-
headers
|
|
359
|
+
headers,
|
|
323
360
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 5e3)
|
|
324
361
|
});
|
|
325
362
|
if (!res.ok) throw new Error(`[xenia] manifest ${res.status}`);
|
|
@@ -331,6 +368,6 @@ function trimManifest(m) {
|
|
|
331
368
|
return { version: m.version, pages: [...pages].sort() };
|
|
332
369
|
}
|
|
333
370
|
|
|
334
|
-
export { MAX_TRAIL, TRAIL_MAX_AGE_S, decodeVariant, deviceOf, edgeConsent, encodeVariant, fetchManifest, isBot, isPageLoad, isPrefetch, landingContext, localTime, readTrail, seasonOf, swapGroups, trailCookieName, trailCookieValue, trimManifest, verifyWebhook, viewerGeo, withView };
|
|
335
|
-
//# sourceMappingURL=chunk-
|
|
336
|
-
//# sourceMappingURL=chunk-
|
|
371
|
+
export { MAX_TRAIL, TRAIL_MAX_AGE_S, decodeVariant, deviceOf, edgeConsent, encodeVariant, fetchManifest, isBot, isPageLoad, isPrefetch, landingContext, localTime, readTrail, seasonOf, swapGroups, trailCookieName, trailCookieValue, trimManifest, variantEntries, variantEntryResolver, verifyWebhook, viewerGeo, withView };
|
|
372
|
+
//# sourceMappingURL=chunk-V4EGU3PM.js.map
|
|
373
|
+
//# sourceMappingURL=chunk-V4EGU3PM.js.map
|