@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
package/dist/chunk-N5M4PI7C.cjs
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/core/http-client.ts
|
|
4
|
-
var DEFAULT_BASE_URL = "https://engine.xeniamartech.com/xenia";
|
|
5
|
-
function isBrowser() {
|
|
6
|
-
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
7
|
-
}
|
|
8
|
-
function buildUrl(url, queryParams) {
|
|
9
|
-
if (!queryParams || Object.keys(queryParams).length === 0) return url;
|
|
10
|
-
const params = new URLSearchParams(queryParams);
|
|
11
|
-
const sep = url.includes("?") ? "&" : "?";
|
|
12
|
-
return `${url}${sep}${params.toString()}`;
|
|
13
|
-
}
|
|
14
|
-
function delay(ms) {
|
|
15
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
-
}
|
|
17
|
-
var HttpError = class extends Error {
|
|
18
|
-
constructor(status, data, message) {
|
|
19
|
-
super(message ?? `Request failed with status ${status}`);
|
|
20
|
-
this.status = status;
|
|
21
|
-
this.data = data;
|
|
22
|
-
this.name = "HttpError";
|
|
23
|
-
}
|
|
24
|
-
status;
|
|
25
|
-
data;
|
|
26
|
-
};
|
|
27
|
-
var CircuitOpenError = class extends Error {
|
|
28
|
-
constructor(endpoint) {
|
|
29
|
-
super(`Circuit open for ${endpoint}: failing fast until the cooldown passes`);
|
|
30
|
-
this.endpoint = endpoint;
|
|
31
|
-
this.name = "CircuitOpenError";
|
|
32
|
-
}
|
|
33
|
-
endpoint;
|
|
34
|
-
};
|
|
35
|
-
var breakers = /* @__PURE__ */ new Map();
|
|
36
|
-
var HttpClient = class {
|
|
37
|
-
baseUrl;
|
|
38
|
-
defaultHeaders;
|
|
39
|
-
timeout;
|
|
40
|
-
retry;
|
|
41
|
-
debug;
|
|
42
|
-
breaker;
|
|
43
|
-
constructor(opts) {
|
|
44
|
-
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
45
|
-
this.defaultHeaders = opts.defaultHeaders ?? {};
|
|
46
|
-
this.timeout = opts.timeout ?? 8e3;
|
|
47
|
-
this.retry = {
|
|
48
|
-
attempts: opts.retry?.attempts ?? 2,
|
|
49
|
-
baseDelayMs: opts.retry?.baseDelayMs ?? 300
|
|
50
|
-
};
|
|
51
|
-
this.debug = opts.debug ?? false;
|
|
52
|
-
const cb = opts.circuitBreaker === true ? {} : opts.circuitBreaker || null;
|
|
53
|
-
this.breaker = cb && { failureThreshold: cb.failureThreshold ?? 3, cooldownMs: cb.cooldownMs ?? 3e4 };
|
|
54
|
-
}
|
|
55
|
-
async request(opts) {
|
|
56
|
-
if (!this.breaker) return this.send(opts);
|
|
57
|
-
const key = buildUrl(this.baseUrl + opts.path, opts.query);
|
|
58
|
-
const b = breakers.get(key) ?? { failures: 0, openedAt: 0 };
|
|
59
|
-
if (b.openedAt) {
|
|
60
|
-
if (Date.now() - b.openedAt < this.breaker.cooldownMs) throw new CircuitOpenError(key);
|
|
61
|
-
b.openedAt = 0;
|
|
62
|
-
b.failures = this.breaker.failureThreshold - 1;
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
const result = await this.send(opts);
|
|
66
|
-
breakers.delete(key);
|
|
67
|
-
return result;
|
|
68
|
-
} catch (err) {
|
|
69
|
-
if (err instanceof HttpError && !this.isRetryableStatus(err.status)) {
|
|
70
|
-
breakers.delete(key);
|
|
71
|
-
throw err;
|
|
72
|
-
}
|
|
73
|
-
b.failures += 1;
|
|
74
|
-
if (b.failures >= this.breaker.failureThreshold) {
|
|
75
|
-
b.openedAt = Date.now();
|
|
76
|
-
this.log(`circuit opened for ${opts.path} after ${b.failures} failures`);
|
|
77
|
-
}
|
|
78
|
-
breakers.set(key, b);
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async send(opts) {
|
|
83
|
-
const url = buildUrl(this.baseUrl + opts.path, opts.query);
|
|
84
|
-
const method = opts.method ?? "GET";
|
|
85
|
-
const headers = {
|
|
86
|
-
"Content-Type": "application/json",
|
|
87
|
-
...this.defaultHeaders,
|
|
88
|
-
...opts.headers
|
|
89
|
-
};
|
|
90
|
-
const body = opts.body !== void 0 ? JSON.stringify(opts.body) : void 0;
|
|
91
|
-
const timeout = opts.timeout ?? this.timeout;
|
|
92
|
-
const maxAttempts = opts.noRetry ? 1 : (opts.retry?.attempts ?? this.retry.attempts) + 1;
|
|
93
|
-
const baseDelay = opts.retry?.baseDelayMs ?? this.retry.baseDelayMs;
|
|
94
|
-
let lastError;
|
|
95
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
96
|
-
try {
|
|
97
|
-
const response = await this.fetchWithTimeout(
|
|
98
|
-
url,
|
|
99
|
-
{ method, headers, body, ...opts.keepalive ? { keepalive: true } : {} },
|
|
100
|
-
timeout
|
|
101
|
-
);
|
|
102
|
-
const data = await this.parseBody(response);
|
|
103
|
-
if (response.ok) {
|
|
104
|
-
return { response, data };
|
|
105
|
-
}
|
|
106
|
-
if (this.isRetryableStatus(response.status) && attempt < maxAttempts - 1) {
|
|
107
|
-
const wait = this.retryAfterMs(response, baseDelay, attempt);
|
|
108
|
-
this.log(`retrying ${opts.path} after ${wait}ms (status ${response.status})`);
|
|
109
|
-
await delay(wait);
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
throw new HttpError(response.status, data);
|
|
113
|
-
} catch (err) {
|
|
114
|
-
lastError = err;
|
|
115
|
-
if (err instanceof HttpError) throw err;
|
|
116
|
-
if (attempt < maxAttempts - 1) {
|
|
117
|
-
const wait = baseDelay * 2 ** attempt;
|
|
118
|
-
this.log(`retrying ${opts.path} after ${wait}ms (network error)`);
|
|
119
|
-
await delay(wait);
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
throw lastError instanceof Error ? lastError : new Error("Request failed");
|
|
125
|
-
}
|
|
126
|
-
async fetchWithTimeout(url, init, timeout) {
|
|
127
|
-
const controller = new AbortController();
|
|
128
|
-
const timer = setTimeout(() => controller.abort(), timeout);
|
|
129
|
-
try {
|
|
130
|
-
return await fetch(url, { ...init, signal: controller.signal });
|
|
131
|
-
} catch (err) {
|
|
132
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
133
|
-
throw new Error(`Request timeout after ${timeout}ms`, { cause: err });
|
|
134
|
-
}
|
|
135
|
-
throw err;
|
|
136
|
-
} finally {
|
|
137
|
-
clearTimeout(timer);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
async parseBody(response) {
|
|
141
|
-
const text = await response.text().catch(() => "");
|
|
142
|
-
if (!text) return null;
|
|
143
|
-
try {
|
|
144
|
-
return JSON.parse(text);
|
|
145
|
-
} catch {
|
|
146
|
-
return text;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
isRetryableStatus(status) {
|
|
150
|
-
return status === 429 || status >= 500 && status <= 599;
|
|
151
|
-
}
|
|
152
|
-
retryAfterMs(response, baseDelay, attempt) {
|
|
153
|
-
const header = response.headers.get("Retry-After");
|
|
154
|
-
if (header) {
|
|
155
|
-
const seconds = Number(header);
|
|
156
|
-
if (!Number.isNaN(seconds)) return seconds * 1e3;
|
|
157
|
-
}
|
|
158
|
-
return baseDelay * 2 ** attempt;
|
|
159
|
-
}
|
|
160
|
-
log(msg) {
|
|
161
|
-
if (this.debug) console.warn(`[xenia] ${msg}`);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// src/core/cookie-names.ts
|
|
166
|
-
var DEFAULT_PREFIX = "xenia";
|
|
167
|
-
function visitorCookieName(prefix = DEFAULT_PREFIX) {
|
|
168
|
-
return `${prefix || DEFAULT_PREFIX}_vid`;
|
|
169
|
-
}
|
|
170
|
-
function consentCookieName(prefix = DEFAULT_PREFIX) {
|
|
171
|
-
return `${prefix || DEFAULT_PREFIX}_consent`;
|
|
172
|
-
}
|
|
173
|
-
var VISITOR_COOKIE = visitorCookieName();
|
|
174
|
-
var CONSENT_COOKIE = consentCookieName();
|
|
175
|
-
function consentCookie(state, prefix, maxAgeDays = 365) {
|
|
176
|
-
return `${consentCookieName(prefix)}=${encodeURIComponent(JSON.stringify(state))}; path=/; max-age=${Math.floor(maxAgeDays * 86400)}; SameSite=Lax`;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
exports.CONSENT_COOKIE = CONSENT_COOKIE;
|
|
180
|
-
exports.CircuitOpenError = CircuitOpenError;
|
|
181
|
-
exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
182
|
-
exports.DEFAULT_PREFIX = DEFAULT_PREFIX;
|
|
183
|
-
exports.HttpClient = HttpClient;
|
|
184
|
-
exports.HttpError = HttpError;
|
|
185
|
-
exports.VISITOR_COOKIE = VISITOR_COOKIE;
|
|
186
|
-
exports.buildUrl = buildUrl;
|
|
187
|
-
exports.consentCookie = consentCookie;
|
|
188
|
-
exports.consentCookieName = consentCookieName;
|
|
189
|
-
exports.isBrowser = isBrowser;
|
|
190
|
-
exports.visitorCookieName = visitorCookieName;
|
|
191
|
-
//# sourceMappingURL=chunk-N5M4PI7C.cjs.map
|
|
192
|
-
//# sourceMappingURL=chunk-N5M4PI7C.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/http-client.ts","../src/core/cookie-names.ts"],"names":[],"mappings":"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","file":"chunk-N5M4PI7C.cjs","sourcesContent":["import type { CircuitBreakerConfig, HttpMethod, JsonValue, RetryConfig } from \"./types\";\n\n/**\n * Default Xenia backend base URL, used whenever `baseUrl` is omitted from\n * config. Points at the hosted engine — override only for a self-hosted or\n * non-default environment.\n */\nexport const DEFAULT_BASE_URL = \"https://engine.xeniamartech.com/xenia\";\n\n/** Returns true when running in a browser environment (SSR-safe). */\nexport function isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/** Appends query parameters to a URL. Returns the URL unchanged when empty. */\nexport function buildUrl(url: string, queryParams?: Record<string, string>): string {\n if (!queryParams || Object.keys(queryParams).length === 0) return url;\n const params = new URLSearchParams(queryParams);\n const sep = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${sep}${params.toString()}`;\n}\n\n/** Sleep helper used by the retry backoff. */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Options for a single request. */\nexport interface RequestOptions {\n method?: HttpMethod;\n /** Path appended to `baseUrl` (should start with `/`). */\n path: string;\n headers?: Record<string, string>;\n query?: Record<string, string>;\n body?: JsonValue;\n /** Per-request timeout override in ms. */\n timeout?: number;\n /** Disable retry for this request (e.g. long-polling webhook). */\n noRetry?: boolean;\n /** Per-request retry override. */\n retry?: RetryConfig;\n /**\n * Keep the request alive past page unload (`fetch`'s `keepalive` flag).\n * Used for best-effort flushes on `pagehide`, where `sendBeacon` can't be\n * used instead because it doesn't support custom headers (tenant scope).\n */\n keepalive?: boolean;\n}\n\n/** Result of a request: the raw Response plus the parsed JSON (or null). */\nexport interface HttpResult {\n response: Response;\n data: JsonValue;\n}\n\n/** Error thrown for non-2xx responses (after retries are exhausted). */\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n public readonly data: JsonValue,\n message?: string,\n ) {\n super(message ?? `Request failed with status ${status}`);\n this.name = \"HttpError\";\n }\n}\n\n/** Thrown without a network call while an endpoint's circuit is open (see {@link CircuitBreakerConfig}). */\nexport class CircuitOpenError extends Error {\n constructor(public readonly endpoint: string) {\n super(`Circuit open for ${endpoint}: failing fast until the cooldown passes`);\n this.name = \"CircuitOpenError\";\n }\n}\n\n/**\n * Per-endpoint breaker state, module-wide so it outlives a single client.\n * ponytail: after the cooldown every concurrent caller probes, not just one; fine for a fail-fast\n * guard, add a probe lock if a thundering herd on recovery ever matters.\n */\nconst breakers = new Map<string, { failures: number; openedAt: number }>();\n\nexport interface HttpClientOptions {\n /** Defaults to {@link DEFAULT_BASE_URL} when omitted. */\n baseUrl?: string;\n defaultHeaders?: Record<string, string>;\n timeout?: number;\n retry?: RetryConfig;\n circuitBreaker?: boolean | CircuitBreakerConfig;\n debug?: boolean;\n}\n\n/**\n * Minimal fetch wrapper shared by all runtimes.\n *\n * - Injects default headers (tenant scope, content-type).\n * - Applies an `AbortController` timeout.\n * - Retries transient failures (network error, `429`, `5xx`) with exponential\n * backoff, honoring a `Retry-After` header when present.\n * - Parses JSON, falling back to `null` on empty/invalid bodies.\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly defaultHeaders: Record<string, string>;\n private readonly timeout: number;\n private readonly retry: Required<RetryConfig>;\n private readonly debug: boolean;\n private readonly breaker: Required<CircuitBreakerConfig> | null;\n\n constructor(opts: HttpClientOptions) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.defaultHeaders = opts.defaultHeaders ?? {};\n this.timeout = opts.timeout ?? 8000;\n this.retry = {\n attempts: opts.retry?.attempts ?? 2,\n baseDelayMs: opts.retry?.baseDelayMs ?? 300,\n };\n this.debug = opts.debug ?? false;\n const cb = opts.circuitBreaker === true ? {} : opts.circuitBreaker || null;\n this.breaker = cb && { failureThreshold: cb.failureThreshold ?? 3, cooldownMs: cb.cooldownMs ?? 30_000 };\n }\n\n async request(opts: RequestOptions): Promise<HttpResult> {\n if (!this.breaker) return this.send(opts);\n // Keyed by full URL, query included: every webhook shares `/flow`, and one slow journey\n // (`?id=`) must not short-circuit the others.\n const key = buildUrl(this.baseUrl + opts.path, opts.query);\n const b = breakers.get(key) ?? { failures: 0, openedAt: 0 };\n if (b.openedAt) {\n if (Date.now() - b.openedAt < this.breaker.cooldownMs) throw new CircuitOpenError(key);\n // Half-open: let this call probe; one more failure re-opens.\n b.openedAt = 0;\n b.failures = this.breaker.failureThreshold - 1;\n }\n try {\n const result = await this.send(opts);\n breakers.delete(key);\n return result;\n } catch (err) {\n if (err instanceof HttpError && !this.isRetryableStatus(err.status)) {\n breakers.delete(key); // the backend answered: it's up\n throw err;\n }\n b.failures += 1;\n if (b.failures >= this.breaker.failureThreshold) {\n b.openedAt = Date.now();\n this.log(`circuit opened for ${opts.path} after ${b.failures} failures`);\n }\n breakers.set(key, b);\n throw err;\n }\n }\n\n private async send(opts: RequestOptions): Promise<HttpResult> {\n const url = buildUrl(this.baseUrl + opts.path, opts.query);\n const method = opts.method ?? \"GET\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.defaultHeaders,\n ...opts.headers,\n };\n const body = opts.body !== undefined ? JSON.stringify(opts.body) : undefined;\n const timeout = opts.timeout ?? this.timeout;\n const maxAttempts = opts.noRetry ? 1 : (opts.retry?.attempts ?? this.retry.attempts) + 1;\n const baseDelay = opts.retry?.baseDelayMs ?? this.retry.baseDelayMs;\n\n let lastError: unknown;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const response = await this.fetchWithTimeout(\n url,\n { method, headers, body, ...(opts.keepalive ? { keepalive: true } : {}) },\n timeout,\n );\n const data = await this.parseBody(response);\n\n if (response.ok) {\n return { response, data };\n }\n\n // Retry on 429/5xx if attempts remain; otherwise throw.\n if (this.isRetryableStatus(response.status) && attempt < maxAttempts - 1) {\n const wait = this.retryAfterMs(response, baseDelay, attempt);\n this.log(`retrying ${opts.path} after ${wait}ms (status ${response.status})`);\n await delay(wait);\n continue;\n }\n throw new HttpError(response.status, data);\n } catch (err) {\n lastError = err;\n // Non-retryable HttpError → rethrow immediately.\n if (err instanceof HttpError) throw err;\n // Network/timeout error → retry if attempts remain.\n if (attempt < maxAttempts - 1) {\n const wait = baseDelay * 2 ** attempt;\n this.log(`retrying ${opts.path} after ${wait}ms (network error)`);\n await delay(wait);\n continue;\n }\n }\n }\n throw lastError instanceof Error ? lastError : new Error(\"Request failed\");\n }\n\n private async fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeout: number,\n ): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timeout after ${timeout}ms`, { cause: err });\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async parseBody(response: Response): Promise<JsonValue> {\n const text = await response.text().catch(() => \"\");\n if (!text) return null;\n try {\n return JSON.parse(text) as JsonValue;\n } catch {\n return text;\n }\n }\n\n private isRetryableStatus(status: number): boolean {\n return status === 429 || (status >= 500 && status <= 599);\n }\n\n private retryAfterMs(response: Response, baseDelay: number, attempt: number): number {\n const header = response.headers.get(\"Retry-After\");\n if (header) {\n const seconds = Number(header);\n if (!Number.isNaN(seconds)) return seconds * 1000;\n }\n return baseDelay * 2 ** attempt;\n }\n\n private log(msg: string): void {\n if (this.debug) console.warn(`[xenia] ${msg}`);\n }\n}\n","/**\n * Cookie names shared by the browser and server halves of the SDK.\n *\n * The visitor cookie is the one channel where two runtimes must agree on a literal string: the\n * browser writes it, a same-origin server reads it back, and that match is what lets a server-side\n * conversion attribute to a browser-entered journey. `config.prefix` namespaces it — so two Xenia\n * apps on one domain keep separate visitors — which means **both halves must derive the name the\n * same way**. Deriving it on one side and hardcoding it on the other silently breaks the link for\n * anyone using a custom prefix: the server just finds no cookie and falls back to no visitor.\n *\n * Always build the name with these helpers rather than interpolating it by hand.\n */\n\nimport type { ConsentState } from \"./types\";\n\n/** Default storage/cookie prefix, matching `XeniaConfig.prefix`. */\nexport const DEFAULT_PREFIX = \"xenia\";\n\n/** Name of the first-party cookie carrying the SDK-owned visitor id, for a given prefix. */\nexport function visitorCookieName(prefix: string = DEFAULT_PREFIX): string {\n return `${prefix || DEFAULT_PREFIX}_vid`;\n}\n\n/** Name of the first-party cookie carrying consent scopes, for a given prefix. */\nexport function consentCookieName(prefix: string = DEFAULT_PREFIX): string {\n return `${prefix || DEFAULT_PREFIX}_consent`;\n}\n\n/**\n * The visitor cookie name for the DEFAULT prefix (`\"xenia_vid\"`).\n *\n * Correct for the common case, and kept so existing code (e.g. reading the cookie straight out of a\n * framework's cookie jar) keeps working. If you set `config.prefix`, use {@link visitorCookieName}\n * instead — this constant will not match what the browser wrote.\n */\nexport const VISITOR_COOKIE = visitorCookieName();\n\n/**\n * The consent cookie name for the DEFAULT prefix (`\"xenia_consent\"`). Same custom-prefix caveat as\n * {@link VISITOR_COOKIE}.\n */\nexport const CONSENT_COOKIE = consentCookieName();\n\n/**\n * A `document.cookie` string carrying consent, in the JSON form the server SDK's `getConsent()`\n * reads back. The browser client's `consent()` writes it; a page with its own consent banner and no\n * browser client can write it directly, so server-side calls see the visitor's choice.\n */\nexport function consentCookie(state: ConsentState, prefix?: string, maxAgeDays = 365): string {\n return `${consentCookieName(prefix)}=${encodeURIComponent(JSON.stringify(state))}; path=/; max-age=${Math.floor(maxAgeDays * 86400)}; SameSite=Lax`;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/edge/consent.ts","../src/edge/request-facts.ts","../src/edge/trail.ts","../src/edge/webhook.ts","../src/edge/variant.ts","../src/edge/manifest.ts"],"names":["enc"],"mappings":"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","file":"chunk-OMMIRSPK.js","sourcesContent":["import { consentCookieName } from \"../core/cookie-names\";\nimport { parseCookies } from \"../server/cookies\";\n\nexport interface EdgeConsent {\n /** Off: don't ask Xenia, serve base content. */\n personalization: boolean;\n /** Off: decide, but keep no trail or click cookies and send no trail. */\n analytics: boolean;\n}\n\n/**\n * What the edge flow may do for this request, from the consent cookie the browser client's\n * `consent()` writes and the visitor's privacy signals:\n * - no consent cookie (or an unreadable one) → no choice made: everything on, as before;\n * - an explicit choice → followed (JSON `{analytics, personalization}`, or the scopes form\n * `analytics,personalization` where an unlisted scope is refused);\n * - `Sec-GPC: 1` / `DNT: 1` → analytics off, like the browser client's `respectDnt` (default on).\n *\n * Unlike `getConsent()`, an absent cookie isn't \"all denied\": the edge can't tell a visitor who\n * refused from one who was never asked, and refusing both would change every first page view.\n */\nexport function edgeConsent(headers: Headers, opts: { prefix?: string; respectDnt?: boolean } = {}): EdgeConsent {\n const raw = parseCookies(headers.get(\"cookie\"))[consentCookieName(opts.prefix)];\n let consent: EdgeConsent = { personalization: true, analytics: true };\n if (raw) {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n const p = parsed as Record<string, unknown>;\n consent = { personalization: p.personalization !== false, analytics: p.analytics !== false };\n }\n } catch {\n if (/^[a-z]+(\\s*,\\s*[a-z]+)*$/i.test(raw.trim())) {\n const scopes = new Set(raw.split(\",\").map((s) => s.trim()));\n consent = { personalization: scopes.has(\"personalization\"), analytics: scopes.has(\"analytics\") };\n }\n }\n }\n const privacySignal = headers.get(\"sec-gpc\") === \"1\" || headers.get(\"dnt\") === \"1\";\n if (opts.respectDnt !== false && privacySignal) consent = { ...consent, analytics: false };\n return consent;\n}\n","/**\n * Facts about a request that journey rules read — where the visitor is, on what device, where they\n * came from, their local time — derived from a standard `Request` in any runtime.\n */\nimport type { ViewerGeo } from \"./types\";\n\nconst GEO_KEYS = [\n \"country\",\n \"countryName\",\n \"region\",\n \"regionName\",\n \"city\",\n \"postalCode\",\n \"timeZone\",\n \"latitude\",\n \"longitude\",\n \"source\",\n] as const;\n\n/** Any host's geo object (Netlify, Next.js runtimes, our own edge function). */\ntype GeoLike = {\n country?: string | { code?: string; name?: string };\n countryName?: string;\n region?: string;\n subdivision?: { code?: string; name?: string };\n regionName?: string;\n city?: string;\n postalCode?: string;\n timeZone?: string;\n timezone?: string;\n latitude?: string | number;\n longitude?: string | number;\n};\n\n/** Normalizes any host's geo object into Xenia's `ViewerGeo` keys (values over 100 chars dropped). */\nfunction toViewerGeo(g: GeoLike | undefined, source: string): ViewerGeo | undefined {\n if (!g) return undefined;\n const country = typeof g.country === \"string\" ? g.country : g.country?.code;\n if (!country) return undefined;\n const raw: Record<string, unknown> = {\n country: country.toUpperCase(),\n countryName: g.countryName ?? (typeof g.country === \"object\" ? g.country?.name : undefined),\n region: g.region ?? g.subdivision?.code,\n regionName: g.regionName ?? g.subdivision?.name,\n city: g.city,\n postalCode: g.postalCode,\n timeZone: g.timeZone ?? g.timezone,\n latitude: g.latitude?.toString(),\n longitude: g.longitude?.toString(),\n source,\n };\n const geo: ViewerGeo = {};\n for (const k of GEO_KEYS) {\n const v = raw[k];\n if (typeof v === \"string\" && v && v.length <= 100) geo[k] = v;\n }\n return geo;\n}\n\nconst parseJson = (text: string): GeoLike | undefined => {\n try {\n return JSON.parse(text) as GeoLike;\n } catch {\n return undefined;\n }\n};\n\nfunction safeDecode(v: string): string {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n}\n\nfunction safeBase64(v: string): string {\n try {\n return atob(v);\n } catch {\n return \"\";\n }\n}\n\n/** Netlify's per-request context, when running in Netlify's runtime. */\nfunction netlifyContext(): { geo?: GeoLike } | undefined {\n try {\n return (globalThis as unknown as { Netlify?: { context?: { geo?: GeoLike } | null } }).Netlify?.context ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nconst COUNTRY_HEADERS = [\"x-country\", \"x-vercel-ip-country\", \"cloudfront-viewer-country\", \"cf-ipcountry\"];\n\n/** The location headers `viewerGeo` can read, when trusted. */\nexport type GeoHeader = \"x-xn-geo\" | \"x-nf-geo\" | \"x-country\" | \"x-vercel-ip-country\" | \"cloudfront-viewer-country\" | \"cf-ipcountry\";\n\nfunction companions(h: Headers, country: string): GeoLike {\n const of = (name: string) => h.get(name) ?? undefined;\n if (country === \"x-vercel-ip-country\") {\n return { region: of(\"x-vercel-ip-country-region\"), city: safeDecode(of(\"x-vercel-ip-city\") ?? \"\") || undefined, timeZone: of(\"x-vercel-ip-timezone\") };\n }\n if (country === \"cloudfront-viewer-country\") {\n return { region: of(\"cloudfront-viewer-country-region\"), city: safeDecode(of(\"cloudfront-viewer-city\") ?? \"\") || undefined, timeZone: of(\"cloudfront-viewer-time-zone\") };\n }\n return {};\n}\n\n/**\n * The visitor's location as the hosting edge resolved it, and which source supplied it (`via`).\n * Geo must come from the storefront's edge, never Xenia's: `/decide` is server to server. Tried in\n * order — whichever the host provides:\n * 1. Netlify's per-request `Netlify.context.geo` (can't be spoofed by the client, unlike a header)\n * 2. `x-xn-geo` (URI-encoded JSON) from the site's own edge function\n * 3. a `request.geo` some runtimes attach\n * 4. Netlify's `x-nf-geo` header (base64 or URI-encoded JSON)\n * 5. `x-country` (Netlify), `x-vercel-ip-*`, `cloudfront-viewer-*`, `cf-ipcountry`\n * 6. `?xn_country=GB` — only with `devOverride`, for testing geo rules without an edge\n *\n * Headers (2, 4 and 5) are read only when named in `trust`: a visitor can send any header, and only\n * the site knows which ones its own host or edge function sets (and overwrites). Name exactly those,\n * e.g. `[\"x-vercel-ip-country\"]` on Vercel, `[\"cf-ipcountry\"]` behind Cloudflare,\n * `[\"x-nf-geo\", \"x-country\"]` on Netlify. 1 and 3 come from the runtime and are always used.\n */\nexport function viewerGeo(\n request: Request,\n opts: { devOverride?: boolean; trust?: readonly GeoHeader[] } = {},\n): { geo?: ViewerGeo; via: string } {\n const trusted = new Set<string>(opts.trust ?? []);\n const fromNetlify = toViewerGeo(netlifyContext()?.geo, \"edge\");\n if (fromNetlify) return { geo: fromNetlify, via: \"Netlify.context\" };\n\n const h = { get: (name: string) => (trusted.has(name) ? request.headers.get(name) : null) };\n const xn = h.get(\"x-xn-geo\");\n const fromXn = xn ? toViewerGeo(parseJson(safeDecode(xn)), \"edge\") : undefined;\n if (fromXn) return { geo: fromXn, via: \"x-xn-geo (edge function)\" };\n\n const fromRuntime = toViewerGeo((request as unknown as { geo?: GeoLike }).geo, \"edge\");\n if (fromRuntime) return { geo: fromRuntime, via: \"request.geo\" };\n\n const nf = h.get(\"x-nf-geo\");\n if (nf) {\n const fromNf = toViewerGeo(parseJson(safeBase64(nf)) ?? parseJson(safeDecode(nf)), \"edge\");\n if (fromNf) return { geo: fromNf, via: \"x-nf-geo\" };\n }\n\n const via = COUNTRY_HEADERS.find((n) => h.get(n));\n const headerCountry = via ? h.get(via) : null;\n if (via && headerCountry && /^[a-z]{2}$/i.test(headerCountry)) {\n const geo = toViewerGeo(\n {\n country: headerCountry,\n // The region, city and time zone of the same provider as the country header.\n ...companions(request.headers, via),\n },\n \"edge\",\n );\n return { geo, via };\n }\n\n const override = new URL(request.url).searchParams.get(\"xn_country\");\n if (opts.devOverride && override && /^[a-z]{2}$/i.test(override)) {\n return { geo: { country: override.toUpperCase(), source: \"dev\" }, via: \"?xn_country (dev)\" };\n }\n return { via: \"none\" };\n}\n\nexport function deviceOf(headers: Headers): \"mobile\" | \"tablet\" | \"desktop\" {\n const ua = headers.get(\"user-agent\") ?? \"\";\n if (/iPad|Tablet/i.test(ua)) return \"tablet\";\n if (headers.get(\"sec-ch-ua-mobile\") === \"?1\" || /Mobi|Android|iPhone/i.test(ua)) return \"mobile\";\n return \"desktop\";\n}\n\nconst BOT = /bot|crawl|spider|slurp|facebookexternalhit|embedly|preview|whatsapp|bingpreview/i;\n\n/** Crawlers and link-preview fetchers: never decided, never recorded. */\nexport function isBot(userAgent: string | null | undefined): boolean {\n return BOT.test(userAgent ?? \"\");\n}\n\n/** Link prefetches pass through a proxy too; they aren't page views. */\nexport function isPrefetch(headers: Headers): boolean {\n return (\n headers.has(\"next-router-prefetch\") ||\n /prefetch/i.test(headers.get(\"purpose\") ?? \"\") ||\n /prefetch/i.test(headers.get(\"sec-purpose\") ?? \"\")\n );\n}\n\n/**\n * Whether this is the browser loading a page (a full page load), by `Sec-Fetch-Dest`. Requests\n * without it (old browsers, curl) count as page loads.\n */\nexport function isPageLoad(headers: Headers): boolean {\n return (headers.get(\"sec-fetch-dest\") ?? \"document\") === \"document\" && !isPrefetch(headers);\n}\n\nconst UTM: Record<string, string> = {\n utm_source: \"utmSource\",\n utm_medium: \"utmMedium\",\n utm_campaign: \"utmCampaign\",\n utm_content: \"utmContent\",\n utm_term: \"utmTerm\",\n utm_id: \"utmId\",\n};\n\n/**\n * This session's landing context — first-touch attribution, so a campaign carries across pages:\n * the UTMs (≤200 chars each) and an external referrer (≤500), refreshed when the visitor arrives\n * from a new campaign. `saved` is the value kept from earlier (a cookie); `changed` says to save it.\n */\nexport function landingContext(\n url: URL,\n referrer: string | null | undefined,\n saved: string | undefined,\n): { ctx: Record<string, string>; changed: boolean } {\n const fromQuery: Record<string, string> = {};\n for (const [param, fact] of Object.entries(UTM)) {\n const v = url.searchParams.get(param);\n if (v) fromQuery[fact] = v.slice(0, 200);\n }\n const external = referrer && !referrer.startsWith(url.origin) ? referrer.slice(0, 500) : null;\n\n let kept: Record<string, string> | null;\n try {\n const parsed: unknown = saved ? JSON.parse(saved) : null;\n kept = parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as Record<string, string>) : null;\n } catch {\n kept = null;\n }\n if (kept && !Object.keys(fromQuery).length) return { ctx: kept, changed: false };\n return { ctx: { ...fromQuery, ...(external ? { referrer: external } : {}) }, changed: true };\n}\n\nconst WEEKDAYS = [\"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\"];\n\n/** Meteorological seasons: Dec–Feb winter, Mar–May spring, Jun–Aug summer, Sep–Nov fall. */\nexport function seasonOf(month: number, southernHemisphere = false): string {\n const north = [\"winter\", \"winter\", \"spring\", \"spring\", \"spring\", \"summer\", \"summer\", \"summer\", \"fall\", \"fall\", \"fall\", \"winter\"];\n const season = north[(month - 1 + 12) % 12];\n if (!southernHemisphere) return season;\n return ({ winter: \"summer\", summer: \"winter\", spring: \"fall\", fall: \"spring\" } as Record<string, string>)[season] ?? season;\n}\n\nfunction validTimeZone(tz: string | undefined): string | undefined {\n if (!tz) return undefined;\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz });\n return tz;\n } catch {\n return undefined;\n }\n}\n\nexport interface LocalTime {\n local_weekday: string;\n local_month: number;\n local_hour: number;\n is_weekend: boolean;\n season: string;\n}\n\n/** Weekday, month, hour and season where the visitor is (their time zone; UTC when unknown). */\nexport function localTime(geo: ViewerGeo | undefined, now: Date): LocalTime {\n const timeZone = validTimeZone(geo?.timeZone) ?? \"UTC\";\n const parts = Object.fromEntries(\n new Intl.DateTimeFormat(\"en-US\", { timeZone, weekday: \"long\", month: \"numeric\", hour: \"numeric\", hourCycle: \"h23\" })\n .formatToParts(now)\n .map((p) => [p.type, p.value]),\n );\n const weekday = String(parts.weekday ?? WEEKDAYS[now.getUTCDay()]).toLowerCase();\n const month = Number(parts.month) || now.getUTCMonth() + 1;\n return {\n local_weekday: weekday,\n local_month: month,\n local_hour: Number(parts.hour) % 24,\n is_weekend: weekday === \"saturday\" || weekday === \"sunday\",\n season: seasonOf(month, Number(geo?.latitude) < 0),\n };\n}\n","/**\n * The visitor's recent page views, most recent first, kept in a short-lived first-party cookie\n * (`[[path, at], [path, at, seconds], …]`). The proxy sends it with `/decide`, so profile rules see\n * pages whose analytics events haven't been processed yet; the browser adds client-side navigations\n * and the time spent on a page as the visitor leaves it. Shared by both sides.\n */\nimport { DEFAULT_PREFIX } from \"../core/cookie-names\";\nimport type { TrailView } from \"./types\";\n\nexport const MAX_TRAIL = 8;\n/** Cookie lifetime: a visit ends after 30 idle minutes, like the SDK's session. */\nexport const TRAIL_MAX_AGE_S = 30 * 60;\n\nexport function trailCookieName(prefix: string = DEFAULT_PREFIX): string {\n return `${prefix}_trail`;\n}\n\nconst decode = (v: string) => {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n};\n\n/** The trail in a cookie value (raw or URI-encoded); anything malformed reads as no trail. */\nexport function readTrail(value: string | undefined | null): TrailView[] {\n if (!value) return [];\n try {\n const parsed: unknown = JSON.parse(decode(value));\n if (!Array.isArray(parsed)) return [];\n return parsed\n .filter((t): t is [string, number, number?] => Array.isArray(t) && typeof t[0] === \"string\" && typeof t[1] === \"number\")\n .slice(0, MAX_TRAIL)\n .map(([path, at, seconds]) =>\n typeof seconds === \"number\" && seconds >= 0 && seconds <= 86_400 ? { path, at, seconds } : { path, at },\n );\n } catch {\n return [];\n }\n}\n\n/**\n * The trail with this view first: a revisit moves to the front and keeps its first time (its old\n * time on page is dropped — this view's isn't known yet). The same array when `path` is already first.\n */\nexport function withView(trail: TrailView[], path: string, now: number = Date.now()): TrailView[] {\n if (trail[0]?.path === path) return trail;\n const earlier = trail.find((t) => t.path === path);\n return [{ path, at: earlier?.at ?? now }, ...trail.filter((t) => t.path !== path)].slice(0, MAX_TRAIL);\n}\n\n/** The cookie value for a trail (not URI-encoded; cookie setters encode it). */\nexport function trailCookieValue(trail: TrailView[]): string {\n return JSON.stringify(\n trail.slice(0, MAX_TRAIL).map((t) => (t.seconds === undefined ? [t.path, t.at] : [t.path, t.at, t.seconds])),\n );\n}\n","const enc = new TextEncoder();\n\nasync function hmacHex(secret: string, payload: string): Promise<string> {\n const key = await crypto.subtle.importKey(\"raw\", enc.encode(secret), { name: \"HMAC\", hash: \"SHA-256\" }, false, [\"sign\"]);\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, enc.encode(payload)));\n return Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** Constant-time comparison, so a signature can't be guessed byte by byte. */\nexport function sameString(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n\n/**\n * Whether a storefront webhook from Xenia is genuine and fresh:\n * `X-Xenia-Signature: t=<unix s>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>`. Requests older than\n * `toleranceS` are refused, so a captured request can't be replayed. Pass the raw body text.\n */\nexport async function verifyWebhook(\n input: { headers: Headers; body: string },\n secret: string,\n toleranceS = 300,\n): Promise<boolean> {\n const header = input.headers.get(\"x-xenia-signature\") ?? \"\";\n if (!secret || !header) return false;\n const parts = Object.fromEntries(header.split(\",\").map((p) => p.trim().split(\"=\", 2)));\n const t = Number(parts.t);\n if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceS || !parts.v1) return false;\n return sameString(await hmacHex(secret, `${parts.t}.${input.body}`), String(parts.v1).toLowerCase());\n}\n","/**\n * The proxy hands a decision to the page as a signed token in the rewritten URL\n * (`/xv/<token>/women`). The token is just the swaps — identical for every visitor in the same\n * variant — so each variant renders once and is then served from the ISR/CDN cache like any static\n * page. A site may carry its own data along (`extra`), e.g. what the page fills itself from.\n *\n * Signed (HMAC-SHA256) so nobody can craft a URL that renders arbitrary entries. Web Crypto only, so\n * it runs in any runtime.\n */\nimport type { EdgeDecision } from \"./types\";\nimport { sameString } from \"./webhook\";\n\n/**\n * One swap: the base entry's field, the entry shown in its place, and the content key whose\n * decision it is — so the page can report impressions and clicks per journey and entry.\n */\nexport type VariantSwap = [identifier: string, replacementEntryId: string, contentKey?: string];\n\n/** Swaps for one base entry. */\nexport interface SwapGroup {\n base: string;\n swaps: VariantSwap[];\n}\n\n/** The longest payload `decodeVariant` accepts. */\nconst MAX_PAYLOAD = 4096;\n\nconst enc = new TextEncoder();\n\nconst b64url = (bytes: Uint8Array) =>\n btoa(String.fromCharCode(...bytes))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n\nconst fromB64url = (s: string) =>\n Uint8Array.from(atob(s.replace(/-/g, \"+\").replace(/_/g, \"/\")), (c) => c.charCodeAt(0));\n\nconst keys = new Map<string, Promise<CryptoKey>>();\nconst keyFor = (secret: string) => {\n let key = keys.get(secret);\n if (!key) {\n key = crypto.subtle.importKey(\"raw\", enc.encode(secret), { name: \"HMAC\", hash: \"SHA-256\" }, false, [\"sign\"]);\n keys.set(secret, key);\n }\n return key;\n};\n\nasync function sign(secret: string, payload: string): Promise<string> {\n const mac = await crypto.subtle.sign(\"HMAC\", await keyFor(secret), enc.encode(payload));\n return b64url(new Uint8Array(mac).slice(0, 16));\n}\n\n/** The swap groups of the personalized decisions, in a stable order (stable cache keys). */\nexport function swapGroups(decisions: EdgeDecision[]): SwapGroup[] {\n const byBase = new Map<string, Map<string, VariantSwap>>();\n for (const d of decisions) {\n if (!d.personalized || !d.baseEntryId) continue;\n for (const s of d.swaps) {\n if (!s.identifier || !s.replacementEntryId) continue;\n if (!byBase.has(d.baseEntryId)) byBase.set(d.baseEntryId, new Map());\n byBase.get(d.baseEntryId)!.set(s.identifier, [s.identifier, s.replacementEntryId, d.contentKey]);\n }\n }\n return [...byBase.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([base, swaps]) => ({ base, swaps: [...swaps.values()].sort(([a], [b]) => a.localeCompare(b)) }));\n}\n\n/**\n * The token for a variant. An `extra` that would push it past the payload limit is left out — the\n * page still renders its swaps — rather than making a token no page accepts.\n */\nexport async function encodeVariant(groups: SwapGroup[], secret: string, extra?: unknown): Promise<string> {\n const g = groups.map((x) => [x.base, x.swaps]);\n const payloadOf = (x: unknown) => b64url(enc.encode(JSON.stringify(x === undefined ? { g } : { g, x })));\n let payload = payloadOf(extra);\n if (payload.length > MAX_PAYLOAD && extra !== undefined) payload = payloadOf(undefined);\n return `${payload}.${await sign(secret, payload)}`;\n}\n\n/** The variant in a token, or `null` if it is malformed or not signed with `secret`. */\nexport async function decodeVariant<E = unknown>(\n token: string,\n secret: string,\n): Promise<{ groups: SwapGroup[]; extra?: E } | null> {\n const [payload, mac, rest] = token.split(\".\");\n if (!payload || !mac || rest !== undefined || payload.length > MAX_PAYLOAD) return null;\n if (!sameString(await sign(secret, payload), mac)) return null;\n try {\n const raw = JSON.parse(new TextDecoder().decode(fromB64url(payload))) as { g: [string, VariantSwap[]][]; x?: E };\n const groups = raw.g.map(([base, swaps]) => ({ base, swaps }));\n return raw.x === undefined ? { groups } : { groups, extra: raw.x };\n } catch {\n return null;\n }\n}\n","import { DEFAULT_BASE_URL } from \"../core/http-client\";\nimport type { Manifest, PublicManifest } from \"./types\";\n\nexport interface FetchManifestOptions {\n /** Xenia engine base URL. Default the hosted engine. */\n baseUrl?: string;\n /** A server-type SDK token. */\n token: string;\n /** Default 5000 ms. */\n timeoutMs?: number;\n fetch?: typeof fetch;\n /** Extra fetch options, e.g. Next.js `{ next: { revalidate } }`. */\n init?: RequestInit;\n}\n\n/** Xenia's manifest (`GET /api/personalization/edge/manifest`). Throws on a non-2xx answer. */\nexport async function fetchManifest(opts: FetchManifestOptions): Promise<Manifest> {\n const base = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const res = await (opts.fetch ?? fetch)(`${base}/api/personalization/edge/manifest`, {\n ...opts.init,\n headers: { Authorization: `Bearer ${opts.token}` },\n signal: AbortSignal.timeout(opts.timeoutMs ?? 5_000),\n });\n if (!res.ok) throw new Error(`[xenia] manifest ${res.status}`);\n return (await res.json()) as Manifest;\n}\n\n/**\n * The manifest as a storefront may serve it publicly (e.g. from a CDN): the version and the page\n * patterns any live journey targets — no content keys, modes or rules. A proxy reading it decides by\n * path, and Xenia picks the content keys itself.\n */\nexport function trimManifest(m: Manifest): PublicManifest {\n const pages = new Set<string>();\n for (const k of m.keys ?? []) if (k.mode !== \"off\") for (const p of k.pages ?? []) pages.add(p);\n return { version: m.version, pages: [...pages].sort() };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
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","../src/core/personalize-content.ts"],"names":["HttpClient"],"mappings":"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","file":"chunk-RWE2OCQL.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","/**\n * CMS page personalization — walk a fetched CMS page breadth-first, swap the\n * entries Xenia marked as personalized, and do it in as few round trips as\n * the page's nesting allows.\n *\n * Rules (see the \"Rounds\" section of the feature plan):\n * - **Static** targets carry their replacement in the payload (`xeniaVariants`)\n * and are swapped inline — no network at all.\n * - **Runtime** targets are a barrier: their id is collected, their subtree is\n * NOT walked (it may be replaced). One `resolve-entries` call decides every\n * target found in a round, one parallel CMS fetch loads every replacement,\n * and the next round walks whatever now sits at each position.\n * - Never throws: on error or when `timeoutMs` runs out, whatever is not yet\n * decided keeps its base content.\n *\n * CMS specifics live behind {@link CmsAdapter}; built-in adapters ship as\n * `@xenia-martech/sdk-js/cms/contentful` (and later `/cms/contentstack`). Any\n * other CMS works by implementing the interface.\n */\n\nimport type { EntryDecision, EntryQuery, EntrySwapOp, ResolveOptions } from \"./types\";\n\n/** Any value inside a CMS payload — the walker is shape-agnostic; adapters give it meaning. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Node = any;\n\n/** The parsed `xenia` marker field of a personalized entry. */\nexport interface XeniaMarker {\n kind: \"static\" | \"runtime\";\n op?: EntrySwapOp;\n /** Array field replaced by `op: \"items\"`. */\n field?: string;\n limit?: number;\n /**\n * The content keys (Personalization Resolve identifiers) that personalize this entry. A page only\n * acts on markers that list its `contentKey`; a marker without keys is ignored.\n */\n keys?: string[];\n}\n\n/** What the page resolver needs to know about a CMS's entries. `N` is the entry shape. */\nexport interface CmsAdapter<N extends object = Node> {\n /** The entry id when `value` is a CMS entry (not a link stub, asset or plain object). */\n entryId(value: unknown): string | undefined;\n /** The entry's Xenia marker, or null when it is not personalized. */\n marker(entry: N): XeniaMarker | null;\n /** Static replacements pinned on the entry (its resolved `xeniaVariants`). */\n staticVariants(entry: N): N[];\n getField(entry: N, field: string): unknown;\n setField(entry: N, field: string, value: unknown): void;\n /** Legacy `items` without a field: copy the replacement's array fields onto the entry. */\n mergeItems?(entry: N, replacement: N): void;\n /**\n * Remove the marker from an entry that has been dealt with (kept base, or had its items replaced),\n * so personalizing the output again — e.g. the browser continuing a server render — never decides\n * it twice. Optional; without it a re-run re-asks Xenia about those entries.\n */\n clearMarker?(entry: N): void;\n /** Normalize a fetched payload before walking (e.g. resolve links). Defaults to identity. */\n prepare?(payload: unknown): unknown;\n /** Load entries by id in ONE call; order does not matter. */\n fetchEntries(ids: string[], locale?: string): Promise<N[]>;\n /** Run a content-type query in ONE call, in the query's order. */\n queryEntries(query: EntryQuery, locale?: string): Promise<N[]>;\n /**\n * Load one page with its whole tree (links resolved), or null when there is none. Optional; it\n * is what lets `personalizePage(ref)` do the fetch, so apps never fetch the page themselves.\n */\n fetchPage?(ref: PageRef, locale?: string): Promise<N | null>;\n}\n\n/** Identifies a page in the CMS: its entry id, or a content type plus exact field values (a slug). */\nexport type PageRef = string | { contentType: string; fields: Record<string, string | number | boolean> };\n\n/** Resolves a round's runtime targets — `XeniaApi.resolveEntries` bound to the visitor. */\nexport type EntryResolver = (entryIds: string[]) => Promise<EntryDecision[]>;\n\n/** Reported for every swap actually applied (for impressions / analytics). */\nexport interface AppliedSwap {\n target: string;\n kind: \"static\" | \"runtime\";\n op: EntrySwapOp;\n /** Ids of the entries now at the target's position (or in its field). */\n entryIds: string[];\n contentKey?: string;\n bucket?: string;\n round: number;\n}\n\nexport interface PersonalizeContentOptions {\n cms: CmsAdapter;\n /** Decides runtime targets. Omit to apply static swaps only (zero network). */\n resolve?: EntryResolver;\n locale?: string;\n /**\n * The page's Personalization Resolve identifier (required). Only that journey personalizes the\n * page: a marker that doesn't list this key is plain content, and the backend decides for this key\n * alone — another journey targeting the same section is neither consulted nor run.\n */\n contentKey: string;\n /** Max network rounds (nesting depth of runtime targets). Default 3. */\n maxRounds?: number;\n /** Total budget for all rounds, in ms. Undecided targets keep their base. Default 300. */\n timeoutMs?: number;\n /** Mutate the payload in place instead of personalizing a copy. Default false. */\n inPlace?: boolean;\n onApplied?(swap: AppliedSwap): void;\n /**\n * Called when a round starts waiting on the network (`pending` = targets being decided) and when\n * it has been applied (`pending` empty). `content` is the live, partially personalized tree —\n * lets a UI render level by level instead of waiting for every round.\n */\n onProgress?(progress: { content: unknown; round: number; pending: string[] }): void;\n}\n\n/** `personalizeContent` options as taken by `XeniaClient` / `XeniaServer`, which supply `resolve`. */\nexport type PagePersonalizeOptions = Omit<PersonalizeContentOptions, \"resolve\"> &\n Pick<ResolveOptions, \"data\" | \"identity\" | \"context\">;\n\nexport interface PersonalizeContentResult<T> {\n content: T;\n applied: AppliedSwap[];\n /** False when the budget ran out, a call failed, or `maxRounds` was hit with targets left. */\n complete: boolean;\n error?: unknown;\n}\n\nconst DEFAULT_TIMEOUT_MS = 300;\nconst DEFAULT_MAX_ROUNDS = 3;\n\n/** One place a value sits in the tree: `parent[key]`. Arrays are re-indexed by identity on write. */\ninterface Slot {\n parent: Node;\n key: string | number;\n value: Node;\n}\n\n/** What Xenia decided for an entry id, with the fetched replacements (copied per use). */\ninterface Decided {\n decision?: EntryDecision;\n items: Node[];\n}\n\nconst copyOf = (v: Node): Node =>\n v && typeof v === \"object\" && typeof structuredClone === \"function\" ? structuredClone(v) : v;\n\n/** A runtime target found in a round, at every place it appears (an entry may be shared). */\ninterface Pending {\n id: string;\n marker: XeniaMarker;\n entry: Node;\n slots: Slot[];\n}\n\nexport async function personalizeContent<T>(\n payload: T,\n options: PersonalizeContentOptions,\n): Promise<PersonalizeContentResult<T>> {\n const cms = scopedAdapter(options.cms, options.contentKey);\n const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;\n const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n const applied: AppliedSwap[] = [];\n const report = (swap: AppliedSwap) => {\n applied.push(swap);\n try {\n options.onApplied?.(swap);\n } catch {\n /* a broken analytics callback must never break rendering */\n }\n };\n\n let content: Node = payload;\n try {\n if (!options.inPlace && typeof structuredClone === \"function\") content = structuredClone(content);\n content = cms.prepare ? cms.prepare(content) : content;\n } catch (error) {\n return { content: payload, applied, complete: false, error };\n }\n\n const box = { root: content };\n // Entries whose own marker is already dealt with this call (kept base / swapped in) — walked as\n // plain content from now on so a target is never decided twice.\n const settled = new WeakSet<object>();\n // Decisions made in this call, by entry id. An entry that turns up again in a later round (a\n // shared entry inside a replacement) gets the same decision — consistent, and no second request.\n const decided = new Map<string, Decided>();\n let frontier: Slot[] = [{ parent: box, key: \"root\", value: box.root }];\n\n /** Apply a decision at a target's slots; returns what to walk next. */\n const settle = (target: Pending, d: Decided, round: number): Slot[] => {\n settled.add(target.entry);\n cms.clearMarker?.(target.entry);\n // A copy per use: fetched entries share objects (one CDA include graph), and a shared object\n // would be \"already settled\" wherever else it appears, hiding entries that are targets there.\n const items = d.items.map(copyOf);\n if (!d.decision || items.length === 0) {\n // Kept base: its subtree was never walked (barrier), so it is next round's frontier.\n return deferredSlots(target, cms);\n }\n for (const item of items) if (item && typeof item === \"object\") settled.add(item);\n const op = d.decision.op ?? target.marker.op ?? \"replace\";\n const next = apply(target, op, d.decision.field ?? target.marker.field, items, cms);\n report({\n target: target.id,\n kind: \"runtime\",\n op,\n entryIds: items.map((e) => cms.entryId(e)).filter((id): id is string => !!id),\n contentKey: d.decision.contentKey,\n bucket: d.decision.bucket,\n round,\n });\n return next;\n };\n\n for (let round = 0; ; round++) {\n const pending = walk(frontier, cms, settled, round, report, (t) => {\n const d = decided.get(t.id);\n return d ? settle(t, d, round) : undefined;\n });\n if (pending.size === 0) return { content: box.root, applied, complete: true };\n if (!options.resolve || round >= maxRounds) {\n return { content: box.root, applied, complete: !options.resolve };\n }\n progress(options, { content: box.root, round, pending: [...pending.keys()] });\n\n let decisions: EntryDecision[];\n let entriesById: Map<string, Node>;\n let queried: Map<EntryDecision, Node[]>;\n try {\n decisions = await withDeadline(options.resolve([...pending.keys()]), deadline);\n ({ entriesById, queried } = await withDeadline(loadReplacements(decisions, cms, options.locale), deadline));\n } catch (error) {\n return { content: box.root, applied, complete: false, error: error === TIMEOUT ? undefined : error };\n }\n\n const byTarget = new Map(decisions.map((d) => [d.target, d]));\n frontier = [];\n for (const target of pending.values()) {\n const decision = byTarget.get(target.id);\n const items = decision\n ? decision.ids\n ? decision.ids.map((id) => entriesById.get(id)).filter((e) => e !== undefined)\n : queried.get(decision) ?? []\n : [];\n const d: Decided = { decision, items };\n decided.set(target.id, d);\n frontier.push(...settle(target, d, round));\n }\n progress(options, { content: box.root, round, pending: [] });\n }\n}\n\nfunction progress(options: PersonalizeContentOptions, p: { content: unknown; round: number; pending: string[] }) {\n try {\n options.onProgress?.(p);\n } catch {\n /* UI callbacks must never break personalization */\n }\n}\n\n/**\n * Breadth-first walk of `frontier`: applies static swaps inline, collects runtime targets (without\n * descending into them) and returns them keyed by entry id.\n */\nfunction walk(\n frontier: Slot[],\n cms: CmsAdapter,\n settled: WeakSet<object>,\n round: number,\n report: (swap: AppliedSwap) => void,\n /** Applies an earlier decision for this entry id inline; undefined when it hasn't been decided. */\n reuse: (target: Pending) => Slot[] | undefined,\n): Map<string, Pending> {\n const pending = new Map<string, Pending>();\n const seen = new WeakSet<object>();\n // Fields held back by a runtime `items` target, wherever the CMS nests them (Contentful: `fields.x`).\n const deferred = new WeakSet<object>();\n const queue: Slot[] = [...frontier];\n\n while (queue.length > 0) {\n const slot = queue.shift()!;\n const value = slot.value;\n if (!value || typeof value !== \"object\" || deferred.has(value)) continue;\n\n const id = settled.has(value) ? undefined : cms.entryId(value);\n const marker = id ? cms.marker(value) : null;\n\n if (id && marker?.kind === \"runtime\") {\n const again = reuse({ id, marker, entry: value, slots: [slot] });\n if (again) {\n queue.push(...again);\n continue;\n }\n const existing = pending.get(id);\n if (existing) {\n existing.slots.push(slot);\n } else {\n pending.set(id, { id, marker, entry: value, slots: [slot] });\n // `items` only defers the replaced field; the entry's other fields are walked now.\n if (marker.op === \"items\" && marker.field) {\n const held = cms.getField(value, marker.field);\n if (held && typeof held === \"object\") deferred.add(held);\n queue.push(...children(value));\n }\n }\n continue;\n }\n\n if (id && marker?.kind === \"static\") {\n const variants = cms.staticVariants(value).filter((v) => v && typeof v === \"object\");\n settled.add(value);\n cms.clearMarker?.(value);\n if (variants.length > 0) {\n for (const v of variants) settled.add(v);\n const op = marker.op ?? \"replace\";\n const target: Pending = { id, marker, entry: value, slots: [slot] };\n queue.push(...apply(target, op, marker.field, variants, cms));\n report({\n target: id,\n kind: \"static\",\n op,\n entryIds: variants.map((v) => cms.entryId(v)).filter((x): x is string => !!x),\n round,\n });\n continue;\n }\n // A static marker with nothing pinned (write-back pending) is just base content.\n }\n\n if (seen.has(value)) continue;\n seen.add(value);\n queue.push(...children(value));\n }\n return pending;\n}\n\n/** Splice `items` in for `target` at all its slots; returns the new content to walk next. */\nfunction apply(target: Pending, op: EntrySwapOp, field: string | undefined, items: Node[], cms: CmsAdapter): Slot[] {\n if (op === \"items\") {\n if (field) {\n cms.setField(target.entry, field, items);\n return [{ parent: target.entry, key: field, value: cms.getField(target.entry, field) }];\n }\n if (cms.mergeItems) {\n cms.mergeItems(target.entry, items[0]);\n return target.slots.map((s) => ({ ...s, value: target.entry }));\n }\n op = \"replace\"; // no merge support → closest meaning\n }\n\n const next: Slot[] = [];\n for (const slot of target.slots) {\n const placed = op === \"expand\" && Array.isArray(slot.parent) ? items : [items[0]];\n if (Array.isArray(slot.parent)) {\n const index = slot.parent.indexOf(target.entry);\n if (index < 0) continue;\n slot.parent.splice(index, 1, ...placed);\n } else {\n slot.parent[slot.key] = placed[0];\n }\n for (const value of placed) next.push({ parent: slot.parent, key: slot.key, value });\n }\n return next;\n}\n\n/** What still needs walking under a target that kept its base content. */\nfunction deferredSlots(target: Pending, cms: CmsAdapter): Slot[] {\n if (target.marker.op === \"items\" && target.marker.field) {\n return [{ parent: target.entry, key: target.marker.field, value: cms.getField(target.entry, target.marker.field) }];\n }\n return target.slots.map((s) => ({ ...s, value: target.entry }));\n}\n\nfunction children(value: Node): Slot[] {\n if (Array.isArray(value)) return value.map((v, i) => ({ parent: value, key: i, value: v }));\n return Object.keys(value).map((k) => ({ parent: value, key: k, value: value[k] }));\n}\n\n/** One `fetchEntries` call for every explicit id, plus one query per content-type decision — all in parallel. */\nasync function loadReplacements(decisions: EntryDecision[], cms: CmsAdapter, locale?: string) {\n const ids = [...new Set(decisions.flatMap((d) => d.ids ?? []))];\n const queries = decisions.filter((d) => !d.ids && d.query);\n const [fetched, ...results] = await Promise.all([\n ids.length > 0 ? cms.fetchEntries(ids, locale) : Promise.resolve([]),\n ...queries.map((d) => cms.queryEntries(d.query!, locale).catch(() => [] as Node[])),\n ]);\n const entriesById = new Map<string, Node>();\n for (const entry of fetched) {\n const id = cms.entryId(entry);\n if (id) entriesById.set(id, entry);\n }\n const queried = new Map<EntryDecision, Node[]>();\n queries.forEach((d, i) => queried.set(d, results[i]!));\n return { entriesById, queried };\n}\n\nconst TIMEOUT = Symbol(\"timeout\");\n\nfunction withDeadline<T>(promise: Promise<T>, deadline: number): Promise<T> {\n const remaining = deadline - Date.now();\n if (remaining <= 0) return Promise.reject(TIMEOUT);\n let timer: ReturnType<typeof setTimeout>;\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(TIMEOUT), remaining);\n }),\n ]).finally(() => clearTimeout(timer));\n}\n\n/**\n * The entries Xenia still has to decide on this page — runtime targets reachable without crossing\n * another undecided one. Synchronous and network-free (it reads the `xenia` markers), so a page can\n * render a skeleton in exactly those places from the first frame instead of flashing base content.\n * Nested targets inside a pending one are found once it is decided.\n */\nexport function pendingTargets(payload: unknown, adapter: CmsAdapter, contentKey: string): string[] {\n const cms = scopedAdapter(adapter, contentKey);\n try {\n let content: Node = typeof structuredClone === \"function\" ? structuredClone(payload) : payload;\n content = cms.prepare ? cms.prepare(content) : content;\n const root = { parent: { root: content }, key: \"root\", value: content };\n // On a copy: the walk applies static swaps inline, which must not touch the caller's page.\n return [...walk([root], cms, new WeakSet(), 0, () => {}, () => undefined).keys()];\n } catch {\n return [];\n }\n}\n\n/**\n * The adapter as the page's journey sees it: only markers that list `contentKey` count. Any other\n * marker — another journey's, or one without keys — is plain content: no static swap, no request,\n * no pending skeleton, and its children are walked as usual.\n */\nfunction scopedAdapter(cms: CmsAdapter, contentKey: string | undefined): CmsAdapter {\n return {\n ...cms,\n marker(entry) {\n const m = cms.marker(entry);\n return m && contentKey && m.keys?.includes(contentKey) ? m : null;\n },\n };\n}\n\n/**\n * Fetch a page through `options.cms` and personalize it — {@link personalizeContent} without the\n * fetch in app code. Never throws: a failed fetch comes back as `content: null` with `error`; a page\n * that does not exist as `content: null`, `complete: true`. The page fetch is not counted against\n * `timeoutMs` — that budget is for personalization only.\n */\nexport async function personalizePage<T>(\n ref: PageRef,\n options: PersonalizeContentOptions,\n): Promise<PersonalizeContentResult<T | null>> {\n let page: unknown;\n try {\n if (!options.cms.fetchPage) throw new Error(\"This CMS adapter cannot fetch pages; use personalizeContent(page)\");\n page = await options.cms.fetchPage(ref, options.locale);\n } catch (error) {\n return { content: null, applied: [], complete: false, error };\n }\n if (page == null) return { content: null, applied: [], complete: true };\n return personalizeContent(page as T, options);\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/edge/consent.ts","../src/edge/request-facts.ts","../src/edge/trail.ts","../src/edge/webhook.ts","../src/edge/variant.ts","../src/edge/manifest.ts"],"names":["parseCookies","consentCookieName","DEFAULT_PREFIX","enc","DEFAULT_BASE_URL"],"mappings":"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","file":"chunk-YLMMTKQL.cjs","sourcesContent":["import { consentCookieName } from \"../core/cookie-names\";\nimport { parseCookies } from \"../server/cookies\";\n\nexport interface EdgeConsent {\n /** Off: don't ask Xenia, serve base content. */\n personalization: boolean;\n /** Off: decide, but keep no trail or click cookies and send no trail. */\n analytics: boolean;\n}\n\n/**\n * What the edge flow may do for this request, from the consent cookie the browser client's\n * `consent()` writes and the visitor's privacy signals:\n * - no consent cookie (or an unreadable one) → no choice made: everything on, as before;\n * - an explicit choice → followed (JSON `{analytics, personalization}`, or the scopes form\n * `analytics,personalization` where an unlisted scope is refused);\n * - `Sec-GPC: 1` / `DNT: 1` → analytics off, like the browser client's `respectDnt` (default on).\n *\n * Unlike `getConsent()`, an absent cookie isn't \"all denied\": the edge can't tell a visitor who\n * refused from one who was never asked, and refusing both would change every first page view.\n */\nexport function edgeConsent(headers: Headers, opts: { prefix?: string; respectDnt?: boolean } = {}): EdgeConsent {\n const raw = parseCookies(headers.get(\"cookie\"))[consentCookieName(opts.prefix)];\n let consent: EdgeConsent = { personalization: true, analytics: true };\n if (raw) {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n const p = parsed as Record<string, unknown>;\n consent = { personalization: p.personalization !== false, analytics: p.analytics !== false };\n }\n } catch {\n if (/^[a-z]+(\\s*,\\s*[a-z]+)*$/i.test(raw.trim())) {\n const scopes = new Set(raw.split(\",\").map((s) => s.trim()));\n consent = { personalization: scopes.has(\"personalization\"), analytics: scopes.has(\"analytics\") };\n }\n }\n }\n const privacySignal = headers.get(\"sec-gpc\") === \"1\" || headers.get(\"dnt\") === \"1\";\n if (opts.respectDnt !== false && privacySignal) consent = { ...consent, analytics: false };\n return consent;\n}\n","/**\n * Facts about a request that journey rules read — where the visitor is, on what device, where they\n * came from, their local time — derived from a standard `Request` in any runtime.\n */\nimport type { ViewerGeo } from \"./types\";\n\nconst GEO_KEYS = [\n \"country\",\n \"countryName\",\n \"region\",\n \"regionName\",\n \"city\",\n \"postalCode\",\n \"timeZone\",\n \"latitude\",\n \"longitude\",\n \"source\",\n] as const;\n\n/** Any host's geo object (Netlify, Next.js runtimes, our own edge function). */\ntype GeoLike = {\n country?: string | { code?: string; name?: string };\n countryName?: string;\n region?: string;\n subdivision?: { code?: string; name?: string };\n regionName?: string;\n city?: string;\n postalCode?: string;\n timeZone?: string;\n timezone?: string;\n latitude?: string | number;\n longitude?: string | number;\n};\n\n/** Normalizes any host's geo object into Xenia's `ViewerGeo` keys (values over 100 chars dropped). */\nfunction toViewerGeo(g: GeoLike | undefined, source: string): ViewerGeo | undefined {\n if (!g) return undefined;\n const country = typeof g.country === \"string\" ? g.country : g.country?.code;\n if (!country) return undefined;\n const raw: Record<string, unknown> = {\n country: country.toUpperCase(),\n countryName: g.countryName ?? (typeof g.country === \"object\" ? g.country?.name : undefined),\n region: g.region ?? g.subdivision?.code,\n regionName: g.regionName ?? g.subdivision?.name,\n city: g.city,\n postalCode: g.postalCode,\n timeZone: g.timeZone ?? g.timezone,\n latitude: g.latitude?.toString(),\n longitude: g.longitude?.toString(),\n source,\n };\n const geo: ViewerGeo = {};\n for (const k of GEO_KEYS) {\n const v = raw[k];\n if (typeof v === \"string\" && v && v.length <= 100) geo[k] = v;\n }\n return geo;\n}\n\nconst parseJson = (text: string): GeoLike | undefined => {\n try {\n return JSON.parse(text) as GeoLike;\n } catch {\n return undefined;\n }\n};\n\nfunction safeDecode(v: string): string {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n}\n\nfunction safeBase64(v: string): string {\n try {\n return atob(v);\n } catch {\n return \"\";\n }\n}\n\n/** Netlify's per-request context, when running in Netlify's runtime. */\nfunction netlifyContext(): { geo?: GeoLike } | undefined {\n try {\n return (globalThis as unknown as { Netlify?: { context?: { geo?: GeoLike } | null } }).Netlify?.context ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nconst COUNTRY_HEADERS = [\"x-country\", \"x-vercel-ip-country\", \"cloudfront-viewer-country\", \"cf-ipcountry\"];\n\n/** The location headers `viewerGeo` can read, when trusted. */\nexport type GeoHeader = \"x-xn-geo\" | \"x-nf-geo\" | \"x-country\" | \"x-vercel-ip-country\" | \"cloudfront-viewer-country\" | \"cf-ipcountry\";\n\nfunction companions(h: Headers, country: string): GeoLike {\n const of = (name: string) => h.get(name) ?? undefined;\n if (country === \"x-vercel-ip-country\") {\n return { region: of(\"x-vercel-ip-country-region\"), city: safeDecode(of(\"x-vercel-ip-city\") ?? \"\") || undefined, timeZone: of(\"x-vercel-ip-timezone\") };\n }\n if (country === \"cloudfront-viewer-country\") {\n return { region: of(\"cloudfront-viewer-country-region\"), city: safeDecode(of(\"cloudfront-viewer-city\") ?? \"\") || undefined, timeZone: of(\"cloudfront-viewer-time-zone\") };\n }\n return {};\n}\n\n/**\n * The visitor's location as the hosting edge resolved it, and which source supplied it (`via`).\n * Geo must come from the storefront's edge, never Xenia's: `/decide` is server to server. Tried in\n * order — whichever the host provides:\n * 1. Netlify's per-request `Netlify.context.geo` (can't be spoofed by the client, unlike a header)\n * 2. `x-xn-geo` (URI-encoded JSON) from the site's own edge function\n * 3. a `request.geo` some runtimes attach\n * 4. Netlify's `x-nf-geo` header (base64 or URI-encoded JSON)\n * 5. `x-country` (Netlify), `x-vercel-ip-*`, `cloudfront-viewer-*`, `cf-ipcountry`\n * 6. `?xn_country=GB` — only with `devOverride`, for testing geo rules without an edge\n *\n * Headers (2, 4 and 5) are read only when named in `trust`: a visitor can send any header, and only\n * the site knows which ones its own host or edge function sets (and overwrites). Name exactly those,\n * e.g. `[\"x-vercel-ip-country\"]` on Vercel, `[\"cf-ipcountry\"]` behind Cloudflare,\n * `[\"x-nf-geo\", \"x-country\"]` on Netlify. 1 and 3 come from the runtime and are always used.\n */\nexport function viewerGeo(\n request: Request,\n opts: { devOverride?: boolean; trust?: readonly GeoHeader[] } = {},\n): { geo?: ViewerGeo; via: string } {\n const trusted = new Set<string>(opts.trust ?? []);\n const fromNetlify = toViewerGeo(netlifyContext()?.geo, \"edge\");\n if (fromNetlify) return { geo: fromNetlify, via: \"Netlify.context\" };\n\n const h = { get: (name: string) => (trusted.has(name) ? request.headers.get(name) : null) };\n const xn = h.get(\"x-xn-geo\");\n const fromXn = xn ? toViewerGeo(parseJson(safeDecode(xn)), \"edge\") : undefined;\n if (fromXn) return { geo: fromXn, via: \"x-xn-geo (edge function)\" };\n\n const fromRuntime = toViewerGeo((request as unknown as { geo?: GeoLike }).geo, \"edge\");\n if (fromRuntime) return { geo: fromRuntime, via: \"request.geo\" };\n\n const nf = h.get(\"x-nf-geo\");\n if (nf) {\n const fromNf = toViewerGeo(parseJson(safeBase64(nf)) ?? parseJson(safeDecode(nf)), \"edge\");\n if (fromNf) return { geo: fromNf, via: \"x-nf-geo\" };\n }\n\n const via = COUNTRY_HEADERS.find((n) => h.get(n));\n const headerCountry = via ? h.get(via) : null;\n if (via && headerCountry && /^[a-z]{2}$/i.test(headerCountry)) {\n const geo = toViewerGeo(\n {\n country: headerCountry,\n // The region, city and time zone of the same provider as the country header.\n ...companions(request.headers, via),\n },\n \"edge\",\n );\n return { geo, via };\n }\n\n const override = new URL(request.url).searchParams.get(\"xn_country\");\n if (opts.devOverride && override && /^[a-z]{2}$/i.test(override)) {\n return { geo: { country: override.toUpperCase(), source: \"dev\" }, via: \"?xn_country (dev)\" };\n }\n return { via: \"none\" };\n}\n\nexport function deviceOf(headers: Headers): \"mobile\" | \"tablet\" | \"desktop\" {\n const ua = headers.get(\"user-agent\") ?? \"\";\n if (/iPad|Tablet/i.test(ua)) return \"tablet\";\n if (headers.get(\"sec-ch-ua-mobile\") === \"?1\" || /Mobi|Android|iPhone/i.test(ua)) return \"mobile\";\n return \"desktop\";\n}\n\nconst BOT = /bot|crawl|spider|slurp|facebookexternalhit|embedly|preview|whatsapp|bingpreview/i;\n\n/** Crawlers and link-preview fetchers: never decided, never recorded. */\nexport function isBot(userAgent: string | null | undefined): boolean {\n return BOT.test(userAgent ?? \"\");\n}\n\n/** Link prefetches pass through a proxy too; they aren't page views. */\nexport function isPrefetch(headers: Headers): boolean {\n return (\n headers.has(\"next-router-prefetch\") ||\n /prefetch/i.test(headers.get(\"purpose\") ?? \"\") ||\n /prefetch/i.test(headers.get(\"sec-purpose\") ?? \"\")\n );\n}\n\n/**\n * Whether this is the browser loading a page (a full page load), by `Sec-Fetch-Dest`. Requests\n * without it (old browsers, curl) count as page loads.\n */\nexport function isPageLoad(headers: Headers): boolean {\n return (headers.get(\"sec-fetch-dest\") ?? \"document\") === \"document\" && !isPrefetch(headers);\n}\n\nconst UTM: Record<string, string> = {\n utm_source: \"utmSource\",\n utm_medium: \"utmMedium\",\n utm_campaign: \"utmCampaign\",\n utm_content: \"utmContent\",\n utm_term: \"utmTerm\",\n utm_id: \"utmId\",\n};\n\n/**\n * This session's landing context — first-touch attribution, so a campaign carries across pages:\n * the UTMs (≤200 chars each) and an external referrer (≤500), refreshed when the visitor arrives\n * from a new campaign. `saved` is the value kept from earlier (a cookie); `changed` says to save it.\n */\nexport function landingContext(\n url: URL,\n referrer: string | null | undefined,\n saved: string | undefined,\n): { ctx: Record<string, string>; changed: boolean } {\n const fromQuery: Record<string, string> = {};\n for (const [param, fact] of Object.entries(UTM)) {\n const v = url.searchParams.get(param);\n if (v) fromQuery[fact] = v.slice(0, 200);\n }\n const external = referrer && !referrer.startsWith(url.origin) ? referrer.slice(0, 500) : null;\n\n let kept: Record<string, string> | null;\n try {\n const parsed: unknown = saved ? JSON.parse(saved) : null;\n kept = parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as Record<string, string>) : null;\n } catch {\n kept = null;\n }\n if (kept && !Object.keys(fromQuery).length) return { ctx: kept, changed: false };\n return { ctx: { ...fromQuery, ...(external ? { referrer: external } : {}) }, changed: true };\n}\n\nconst WEEKDAYS = [\"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\"];\n\n/** Meteorological seasons: Dec–Feb winter, Mar–May spring, Jun–Aug summer, Sep–Nov fall. */\nexport function seasonOf(month: number, southernHemisphere = false): string {\n const north = [\"winter\", \"winter\", \"spring\", \"spring\", \"spring\", \"summer\", \"summer\", \"summer\", \"fall\", \"fall\", \"fall\", \"winter\"];\n const season = north[(month - 1 + 12) % 12];\n if (!southernHemisphere) return season;\n return ({ winter: \"summer\", summer: \"winter\", spring: \"fall\", fall: \"spring\" } as Record<string, string>)[season] ?? season;\n}\n\nfunction validTimeZone(tz: string | undefined): string | undefined {\n if (!tz) return undefined;\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz });\n return tz;\n } catch {\n return undefined;\n }\n}\n\nexport interface LocalTime {\n local_weekday: string;\n local_month: number;\n local_hour: number;\n is_weekend: boolean;\n season: string;\n}\n\n/** Weekday, month, hour and season where the visitor is (their time zone; UTC when unknown). */\nexport function localTime(geo: ViewerGeo | undefined, now: Date): LocalTime {\n const timeZone = validTimeZone(geo?.timeZone) ?? \"UTC\";\n const parts = Object.fromEntries(\n new Intl.DateTimeFormat(\"en-US\", { timeZone, weekday: \"long\", month: \"numeric\", hour: \"numeric\", hourCycle: \"h23\" })\n .formatToParts(now)\n .map((p) => [p.type, p.value]),\n );\n const weekday = String(parts.weekday ?? WEEKDAYS[now.getUTCDay()]).toLowerCase();\n const month = Number(parts.month) || now.getUTCMonth() + 1;\n return {\n local_weekday: weekday,\n local_month: month,\n local_hour: Number(parts.hour) % 24,\n is_weekend: weekday === \"saturday\" || weekday === \"sunday\",\n season: seasonOf(month, Number(geo?.latitude) < 0),\n };\n}\n","/**\n * The visitor's recent page views, most recent first, kept in a short-lived first-party cookie\n * (`[[path, at], [path, at, seconds], …]`). The proxy sends it with `/decide`, so profile rules see\n * pages whose analytics events haven't been processed yet; the browser adds client-side navigations\n * and the time spent on a page as the visitor leaves it. Shared by both sides.\n */\nimport { DEFAULT_PREFIX } from \"../core/cookie-names\";\nimport type { TrailView } from \"./types\";\n\nexport const MAX_TRAIL = 8;\n/** Cookie lifetime: a visit ends after 30 idle minutes, like the SDK's session. */\nexport const TRAIL_MAX_AGE_S = 30 * 60;\n\nexport function trailCookieName(prefix: string = DEFAULT_PREFIX): string {\n return `${prefix}_trail`;\n}\n\nconst decode = (v: string) => {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n};\n\n/** The trail in a cookie value (raw or URI-encoded); anything malformed reads as no trail. */\nexport function readTrail(value: string | undefined | null): TrailView[] {\n if (!value) return [];\n try {\n const parsed: unknown = JSON.parse(decode(value));\n if (!Array.isArray(parsed)) return [];\n return parsed\n .filter((t): t is [string, number, number?] => Array.isArray(t) && typeof t[0] === \"string\" && typeof t[1] === \"number\")\n .slice(0, MAX_TRAIL)\n .map(([path, at, seconds]) =>\n typeof seconds === \"number\" && seconds >= 0 && seconds <= 86_400 ? { path, at, seconds } : { path, at },\n );\n } catch {\n return [];\n }\n}\n\n/**\n * The trail with this view first: a revisit moves to the front and keeps its first time (its old\n * time on page is dropped — this view's isn't known yet). The same array when `path` is already first.\n */\nexport function withView(trail: TrailView[], path: string, now: number = Date.now()): TrailView[] {\n if (trail[0]?.path === path) return trail;\n const earlier = trail.find((t) => t.path === path);\n return [{ path, at: earlier?.at ?? now }, ...trail.filter((t) => t.path !== path)].slice(0, MAX_TRAIL);\n}\n\n/** The cookie value for a trail (not URI-encoded; cookie setters encode it). */\nexport function trailCookieValue(trail: TrailView[]): string {\n return JSON.stringify(\n trail.slice(0, MAX_TRAIL).map((t) => (t.seconds === undefined ? [t.path, t.at] : [t.path, t.at, t.seconds])),\n );\n}\n","const enc = new TextEncoder();\n\nasync function hmacHex(secret: string, payload: string): Promise<string> {\n const key = await crypto.subtle.importKey(\"raw\", enc.encode(secret), { name: \"HMAC\", hash: \"SHA-256\" }, false, [\"sign\"]);\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, enc.encode(payload)));\n return Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** Constant-time comparison, so a signature can't be guessed byte by byte. */\nexport function sameString(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n\n/**\n * Whether a storefront webhook from Xenia is genuine and fresh:\n * `X-Xenia-Signature: t=<unix s>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>`. Requests older than\n * `toleranceS` are refused, so a captured request can't be replayed. Pass the raw body text.\n */\nexport async function verifyWebhook(\n input: { headers: Headers; body: string },\n secret: string,\n toleranceS = 300,\n): Promise<boolean> {\n const header = input.headers.get(\"x-xenia-signature\") ?? \"\";\n if (!secret || !header) return false;\n const parts = Object.fromEntries(header.split(\",\").map((p) => p.trim().split(\"=\", 2)));\n const t = Number(parts.t);\n if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceS || !parts.v1) return false;\n return sameString(await hmacHex(secret, `${parts.t}.${input.body}`), String(parts.v1).toLowerCase());\n}\n","/**\n * The proxy hands a decision to the page as a signed token in the rewritten URL\n * (`/xv/<token>/women`). The token is just the swaps — identical for every visitor in the same\n * variant — so each variant renders once and is then served from the ISR/CDN cache like any static\n * page. A site may carry its own data along (`extra`), e.g. what the page fills itself from.\n *\n * Signed (HMAC-SHA256) so nobody can craft a URL that renders arbitrary entries. Web Crypto only, so\n * it runs in any runtime.\n */\nimport type { EdgeDecision } from \"./types\";\nimport { sameString } from \"./webhook\";\n\n/**\n * One swap: the base entry's field, the entry shown in its place, and the content key whose\n * decision it is — so the page can report impressions and clicks per journey and entry.\n */\nexport type VariantSwap = [identifier: string, replacementEntryId: string, contentKey?: string];\n\n/** Swaps for one base entry. */\nexport interface SwapGroup {\n base: string;\n swaps: VariantSwap[];\n}\n\n/** The longest payload `decodeVariant` accepts. */\nconst MAX_PAYLOAD = 4096;\n\nconst enc = new TextEncoder();\n\nconst b64url = (bytes: Uint8Array) =>\n btoa(String.fromCharCode(...bytes))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n\nconst fromB64url = (s: string) =>\n Uint8Array.from(atob(s.replace(/-/g, \"+\").replace(/_/g, \"/\")), (c) => c.charCodeAt(0));\n\nconst keys = new Map<string, Promise<CryptoKey>>();\nconst keyFor = (secret: string) => {\n let key = keys.get(secret);\n if (!key) {\n key = crypto.subtle.importKey(\"raw\", enc.encode(secret), { name: \"HMAC\", hash: \"SHA-256\" }, false, [\"sign\"]);\n keys.set(secret, key);\n }\n return key;\n};\n\nasync function sign(secret: string, payload: string): Promise<string> {\n const mac = await crypto.subtle.sign(\"HMAC\", await keyFor(secret), enc.encode(payload));\n return b64url(new Uint8Array(mac).slice(0, 16));\n}\n\n/** The swap groups of the personalized decisions, in a stable order (stable cache keys). */\nexport function swapGroups(decisions: EdgeDecision[]): SwapGroup[] {\n const byBase = new Map<string, Map<string, VariantSwap>>();\n for (const d of decisions) {\n if (!d.personalized || !d.baseEntryId) continue;\n for (const s of d.swaps) {\n if (!s.identifier || !s.replacementEntryId) continue;\n if (!byBase.has(d.baseEntryId)) byBase.set(d.baseEntryId, new Map());\n byBase.get(d.baseEntryId)!.set(s.identifier, [s.identifier, s.replacementEntryId, d.contentKey]);\n }\n }\n return [...byBase.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([base, swaps]) => ({ base, swaps: [...swaps.values()].sort(([a], [b]) => a.localeCompare(b)) }));\n}\n\n/**\n * The token for a variant. An `extra` that would push it past the payload limit is left out — the\n * page still renders its swaps — rather than making a token no page accepts.\n */\nexport async function encodeVariant(groups: SwapGroup[], secret: string, extra?: unknown): Promise<string> {\n const g = groups.map((x) => [x.base, x.swaps]);\n const payloadOf = (x: unknown) => b64url(enc.encode(JSON.stringify(x === undefined ? { g } : { g, x })));\n let payload = payloadOf(extra);\n if (payload.length > MAX_PAYLOAD && extra !== undefined) payload = payloadOf(undefined);\n return `${payload}.${await sign(secret, payload)}`;\n}\n\n/** The variant in a token, or `null` if it is malformed or not signed with `secret`. */\nexport async function decodeVariant<E = unknown>(\n token: string,\n secret: string,\n): Promise<{ groups: SwapGroup[]; extra?: E } | null> {\n const [payload, mac, rest] = token.split(\".\");\n if (!payload || !mac || rest !== undefined || payload.length > MAX_PAYLOAD) return null;\n if (!sameString(await sign(secret, payload), mac)) return null;\n try {\n const raw = JSON.parse(new TextDecoder().decode(fromB64url(payload))) as { g: [string, VariantSwap[]][]; x?: E };\n const groups = raw.g.map(([base, swaps]) => ({ base, swaps }));\n return raw.x === undefined ? { groups } : { groups, extra: raw.x };\n } catch {\n return null;\n }\n}\n","import { DEFAULT_BASE_URL } from \"../core/http-client\";\nimport type { Manifest, PublicManifest } from \"./types\";\n\nexport interface FetchManifestOptions {\n /** Xenia engine base URL. Default the hosted engine. */\n baseUrl?: string;\n /** A server-type SDK token. */\n token: string;\n /** Default 5000 ms. */\n timeoutMs?: number;\n fetch?: typeof fetch;\n /** Extra fetch options, e.g. Next.js `{ next: { revalidate } }`. */\n init?: RequestInit;\n}\n\n/** Xenia's manifest (`GET /api/personalization/edge/manifest`). Throws on a non-2xx answer. */\nexport async function fetchManifest(opts: FetchManifestOptions): Promise<Manifest> {\n const base = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const res = await (opts.fetch ?? fetch)(`${base}/api/personalization/edge/manifest`, {\n ...opts.init,\n headers: { Authorization: `Bearer ${opts.token}` },\n signal: AbortSignal.timeout(opts.timeoutMs ?? 5_000),\n });\n if (!res.ok) throw new Error(`[xenia] manifest ${res.status}`);\n return (await res.json()) as Manifest;\n}\n\n/**\n * The manifest as a storefront may serve it publicly (e.g. from a CDN): the version and the page\n * patterns any live journey targets — no content keys, modes or rules. A proxy reading it decides by\n * path, and Xenia picks the content keys itself.\n */\nexport function trimManifest(m: Manifest): PublicManifest {\n const pages = new Set<string>();\n for (const k of m.keys ?? []) if (k.mode !== \"off\") for (const p of k.pages ?? []) pages.add(p);\n return { version: m.version, pages: [...pages].sort() };\n}\n"]}
|