@xenia-martech/sdk-js 1.0.1-dev.1 → 1.1.0-dev.1
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 +53 -4
- package/dist/{actions-CcBYV--3.d.cts → actions-CKeiofxJ.d.cts} +19 -1
- package/dist/{actions-CcBYV--3.d.ts → actions-CKeiofxJ.d.ts} +19 -1
- package/dist/{cookie-names-B3b0XNc2.d.cts → api-URhxxi4x.d.cts} +19 -42
- package/dist/{cookie-names-B3b0XNc2.d.ts → api-URhxxi4x.d.ts} +19 -42
- package/dist/chunk-5D7SJIO4.cjs +109 -0
- package/dist/chunk-5D7SJIO4.cjs.map +1 -0
- package/dist/chunk-BHNOKSJH.js +214 -0
- package/dist/chunk-BHNOKSJH.js.map +1 -0
- package/dist/{chunk-XXNDHYAS.js → chunk-FYSEKFIY.js} +45 -103
- package/dist/chunk-FYSEKFIY.js.map +1 -0
- package/dist/{chunk-WYM4CQVG.cjs → chunk-JEKVN7HK.cjs} +46 -106
- package/dist/chunk-JEKVN7HK.cjs.map +1 -0
- package/dist/chunk-LBRZMWE2.cjs +220 -0
- package/dist/chunk-LBRZMWE2.cjs.map +1 -0
- package/dist/chunk-TLTG3BTC.js +104 -0
- package/dist/chunk-TLTG3BTC.js.map +1 -0
- package/dist/client/index.cjs +60 -6
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +25 -3
- package/dist/client/index.d.ts +25 -3
- package/dist/client/index.js +59 -7
- package/dist/client/index.js.map +1 -1
- package/dist/client/react/index.cjs +58 -6
- package/dist/client/react/index.cjs.map +1 -1
- package/dist/client/react/index.d.cts +2 -2
- package/dist/client/react/index.d.ts +2 -2
- package/dist/client/react/index.js +58 -6
- package/dist/client/react/index.js.map +1 -1
- package/dist/cookie-names-8FxbGKGS.d.ts +127 -0
- package/dist/cookie-names-QYMiEMAq.d.cts +127 -0
- package/dist/index.cjs +41 -32
- package/dist/index.d.cts +4 -71
- package/dist/index.d.ts +4 -71
- package/dist/index.js +2 -1
- package/dist/next/index.cjs +59 -0
- package/dist/next/index.cjs.map +1 -0
- package/dist/next/index.d.cts +45 -0
- package/dist/next/index.d.ts +45 -0
- package/dist/next/index.js +54 -0
- package/dist/next/index.js.map +1 -0
- package/dist/server/index.cjs +38 -214
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +5 -104
- package/dist/server/index.d.ts +5 -104
- package/dist/server/index.js +5 -204
- package/dist/server/index.js.map +1 -1
- package/dist/xenia-sdk.iife.js +3 -3
- package/dist/xenia-sdk.iife.js.map +1 -1
- package/dist/xenia-server-BG4Vkaua.d.cts +110 -0
- package/dist/xenia-server-CpFUOxbB.d.ts +110 -0
- package/package.json +26 -7
- package/dist/chunk-WYM4CQVG.cjs.map +0 -1
- package/dist/chunk-XXNDHYAS.js.map +0 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// src/core/content-splice.ts
|
|
2
|
+
function isPlainObject(v) {
|
|
3
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
4
|
+
}
|
|
5
|
+
function cloneJson(value) {
|
|
6
|
+
return value === null || typeof value !== "object" ? value : JSON.parse(JSON.stringify(value));
|
|
7
|
+
}
|
|
8
|
+
function setAtPath(node, path, value, mode) {
|
|
9
|
+
if (path.length === 0) {
|
|
10
|
+
if (mode === "merge" && isPlainObject(node) && isPlainObject(value)) {
|
|
11
|
+
return { ...node, ...value };
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
const [key, ...rest] = path;
|
|
16
|
+
if (Array.isArray(node)) {
|
|
17
|
+
const index = Number(key);
|
|
18
|
+
if (!Number.isInteger(index) || index < 0 || index >= node.length) return node;
|
|
19
|
+
const next = node.slice();
|
|
20
|
+
next[index] = setAtPath(next[index], rest, value, mode);
|
|
21
|
+
return next;
|
|
22
|
+
}
|
|
23
|
+
if (isPlainObject(node)) {
|
|
24
|
+
if (!(key in node)) return node;
|
|
25
|
+
return { ...node, [key]: setAtPath(node[key], rest, value, mode) };
|
|
26
|
+
}
|
|
27
|
+
return node;
|
|
28
|
+
}
|
|
29
|
+
function spliceSlots(slots, swaps) {
|
|
30
|
+
const result = {};
|
|
31
|
+
for (const [key, value] of Object.entries(slots)) {
|
|
32
|
+
result[key] = cloneJson(value);
|
|
33
|
+
}
|
|
34
|
+
if (!swaps) return result;
|
|
35
|
+
for (const swap of swaps) {
|
|
36
|
+
const [slotKey, ...pathParts] = swap.identifier.split(".");
|
|
37
|
+
if (!(slotKey in result)) continue;
|
|
38
|
+
result[slotKey] = setAtPath(result[slotKey], pathParts, swap.replacement, swap.mode ?? "replace");
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
function extractContentSwaps(body) {
|
|
43
|
+
if (!isPlainObject(body)) return void 0;
|
|
44
|
+
const swaps = body.xeniaContentSwaps;
|
|
45
|
+
return Array.isArray(swaps) ? swaps : void 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/core/response-store.ts
|
|
49
|
+
var MemoryResponseStore = class {
|
|
50
|
+
map = /* @__PURE__ */ new Map();
|
|
51
|
+
set(key, value) {
|
|
52
|
+
this.map.set(key, value);
|
|
53
|
+
}
|
|
54
|
+
get(key) {
|
|
55
|
+
return this.map.get(key);
|
|
56
|
+
}
|
|
57
|
+
keys() {
|
|
58
|
+
return [...this.map.keys()];
|
|
59
|
+
}
|
|
60
|
+
clear() {
|
|
61
|
+
this.map.clear();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
var LocalStorageResponseStore = class {
|
|
65
|
+
nsKey;
|
|
66
|
+
constructor(prefix = "xenia") {
|
|
67
|
+
this.nsKey = `${prefix}_responses`;
|
|
68
|
+
}
|
|
69
|
+
read() {
|
|
70
|
+
try {
|
|
71
|
+
const raw = localStorage.getItem(this.nsKey);
|
|
72
|
+
return raw ? JSON.parse(raw) : {};
|
|
73
|
+
} catch {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
write(data) {
|
|
78
|
+
try {
|
|
79
|
+
localStorage.setItem(this.nsKey, JSON.stringify(data));
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
set(key, value) {
|
|
84
|
+
const data = this.read();
|
|
85
|
+
data[key] = value;
|
|
86
|
+
this.write(data);
|
|
87
|
+
}
|
|
88
|
+
get(key) {
|
|
89
|
+
return this.read()[key];
|
|
90
|
+
}
|
|
91
|
+
keys() {
|
|
92
|
+
return Object.keys(this.read());
|
|
93
|
+
}
|
|
94
|
+
clear() {
|
|
95
|
+
try {
|
|
96
|
+
localStorage.removeItem(this.nsKey);
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export { LocalStorageResponseStore, MemoryResponseStore, extractContentSwaps, spliceSlots };
|
|
103
|
+
//# sourceMappingURL=chunk-TLTG3BTC.js.map
|
|
104
|
+
//# sourceMappingURL=chunk-TLTG3BTC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/content-splice.ts","../src/core/response-store.ts"],"names":[],"mappings":"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","file":"chunk-TLTG3BTC.js","sourcesContent":["import type { JsonValue } from \"./types\";\n\n/**\n * A single content swap, as emitted in a webhook-response body's\n * `xeniaContentSwaps` array (the multi-slot personalization analogue of\n * `xeniaActions`). `identifier` is `\"<slotKey>\"` (whole-slot replace) or\n * `\"<slotKey>.<dotted.path>\"` addressing a node inside that slot's JSON\n * (object keys or array indices).\n *\n * NOTE: this field name/shape is a proposed contract, not yet emitted by any\n * journey node — confirm with the Journey Orchestrator (FE/BE) team before\n * relying on it in production.\n */\nexport interface ContentSwap {\n identifier: string;\n replacement: JsonValue;\n /** `\"replace\"` (default) swaps the whole matched node; `\"merge\"` shallow-merges when both sides are objects. */\n mode?: \"replace\" | \"merge\";\n}\n\nfunction isPlainObject(v: JsonValue): v is { [key: string]: JsonValue } {\n return v !== null && typeof v === \"object\" && !Array.isArray(v);\n}\n\nfunction cloneJson<T extends JsonValue>(value: T): T {\n return value === null || typeof value !== \"object\" ? value : (JSON.parse(JSON.stringify(value)) as T);\n}\n\nfunction setAtPath(node: JsonValue, path: string[], value: JsonValue, mode: \"replace\" | \"merge\"): JsonValue {\n if (path.length === 0) {\n if (mode === \"merge\" && isPlainObject(node) && isPlainObject(value)) {\n return { ...node, ...value };\n }\n return value;\n }\n\n const [key, ...rest] = path;\n if (Array.isArray(node)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0 || index >= node.length) return node;\n const next = node.slice();\n next[index] = setAtPath(next[index], rest, value, mode);\n return next;\n }\n if (isPlainObject(node)) {\n if (!(key in node)) return node;\n return { ...node, [key]: setAtPath(node[key], rest, value, mode) };\n }\n return node;\n}\n\n/**\n * Splice `swaps` into a base map of named content slots, recursively at any\n * nesting depth. Defensive by design (mirrors the PHP SDK's personalization\n * client): a swap whose `identifier` doesn't resolve to an existing slot/path\n * is silently ignored rather than thrown — this never fails, it degrades to\n * the base slot value. Slots are deep-cloned; inputs are never mutated.\n */\nexport function spliceSlots(\n slots: Record<string, JsonValue>,\n swaps: ContentSwap[] | undefined,\n): Record<string, JsonValue> {\n const result: Record<string, JsonValue> = {};\n for (const [key, value] of Object.entries(slots)) {\n result[key] = cloneJson(value);\n }\n if (!swaps) return result;\n\n for (const swap of swaps) {\n const [slotKey, ...pathParts] = swap.identifier.split(\".\");\n if (!(slotKey in result)) continue;\n result[slotKey] = setAtPath(result[slotKey], pathParts, swap.replacement, swap.mode ?? \"replace\");\n }\n return result;\n}\n\n/** Extract `xeniaContentSwaps` from a webhook-response body, if present and well-formed. */\nexport function extractContentSwaps(body: JsonValue): ContentSwap[] | undefined {\n if (!isPlainObject(body)) return undefined;\n const swaps = body.xeniaContentSwaps;\n return Array.isArray(swaps) ? (swaps as unknown as ContentSwap[]) : undefined;\n}\n","import type { WebhookResponse } from \"./types\";\n\n/**\n * Persists webhook responses the SDK receives, keyed by an arbitrary string\n * (typically the eventId, triggerId, or journeyId). Lets the app read back the\n * last server response for a given interaction without re-firing it.\n */\nexport interface ResponseStore {\n set(key: string, value: WebhookResponse): void;\n get(key: string): WebhookResponse | undefined;\n keys(): string[];\n clear(): void;\n}\n\n/** In-memory store. Default; lost on reload. */\nexport class MemoryResponseStore implements ResponseStore {\n private readonly map = new Map<string, WebhookResponse>();\n\n set(key: string, value: WebhookResponse): void {\n this.map.set(key, value);\n }\n get(key: string): WebhookResponse | undefined {\n return this.map.get(key);\n }\n keys(): string[] {\n return [...this.map.keys()];\n }\n clear(): void {\n this.map.clear();\n }\n}\n\n/**\n * localStorage-backed store — survives reloads. Falls back to memory semantics\n * (silent no-op reads/writes) when localStorage is unavailable or throws.\n */\nexport class LocalStorageResponseStore implements ResponseStore {\n private readonly nsKey: string;\n\n constructor(prefix = \"xenia\") {\n this.nsKey = `${prefix}_responses`;\n }\n\n private read(): Record<string, WebhookResponse> {\n try {\n const raw = localStorage.getItem(this.nsKey);\n return raw ? (JSON.parse(raw) as Record<string, WebhookResponse>) : {};\n } catch {\n return {};\n }\n }\n\n private write(data: Record<string, WebhookResponse>): void {\n try {\n localStorage.setItem(this.nsKey, JSON.stringify(data));\n } catch {\n /* storage full / unavailable — ignore */\n }\n }\n\n set(key: string, value: WebhookResponse): void {\n const data = this.read();\n data[key] = value;\n this.write(data);\n }\n get(key: string): WebhookResponse | undefined {\n return this.read()[key];\n }\n keys(): string[] {\n return Object.keys(this.read());\n }\n clear(): void {\n try {\n localStorage.removeItem(this.nsKey);\n } catch {\n /* ignore */\n }\n }\n}\n"]}
|
package/dist/client/index.cjs
CHANGED
|
@@ -163,12 +163,22 @@ var HttpError = class extends Error {
|
|
|
163
163
|
status;
|
|
164
164
|
data;
|
|
165
165
|
};
|
|
166
|
+
var CircuitOpenError = class extends Error {
|
|
167
|
+
constructor(endpoint) {
|
|
168
|
+
super(`Circuit open for ${endpoint}: failing fast until the cooldown passes`);
|
|
169
|
+
this.endpoint = endpoint;
|
|
170
|
+
this.name = "CircuitOpenError";
|
|
171
|
+
}
|
|
172
|
+
endpoint;
|
|
173
|
+
};
|
|
174
|
+
var breakers = /* @__PURE__ */ new Map();
|
|
166
175
|
var HttpClient = class {
|
|
167
176
|
baseUrl;
|
|
168
177
|
defaultHeaders;
|
|
169
178
|
timeout;
|
|
170
179
|
retry;
|
|
171
180
|
debug;
|
|
181
|
+
breaker;
|
|
172
182
|
constructor(opts) {
|
|
173
183
|
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
174
184
|
this.defaultHeaders = opts.defaultHeaders ?? {};
|
|
@@ -178,8 +188,37 @@ var HttpClient = class {
|
|
|
178
188
|
baseDelayMs: opts.retry?.baseDelayMs ?? 300
|
|
179
189
|
};
|
|
180
190
|
this.debug = opts.debug ?? false;
|
|
191
|
+
const cb = opts.circuitBreaker === true ? {} : opts.circuitBreaker || null;
|
|
192
|
+
this.breaker = cb && { failureThreshold: cb.failureThreshold ?? 3, cooldownMs: cb.cooldownMs ?? 3e4 };
|
|
181
193
|
}
|
|
182
194
|
async request(opts) {
|
|
195
|
+
if (!this.breaker) return this.send(opts);
|
|
196
|
+
const key = buildUrl(this.baseUrl + opts.path, opts.query);
|
|
197
|
+
const b = breakers.get(key) ?? { failures: 0, openedAt: 0 };
|
|
198
|
+
if (b.openedAt) {
|
|
199
|
+
if (Date.now() - b.openedAt < this.breaker.cooldownMs) throw new CircuitOpenError(key);
|
|
200
|
+
b.openedAt = 0;
|
|
201
|
+
b.failures = this.breaker.failureThreshold - 1;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
const result = await this.send(opts);
|
|
205
|
+
breakers.delete(key);
|
|
206
|
+
return result;
|
|
207
|
+
} catch (err) {
|
|
208
|
+
if (err instanceof HttpError && !this.isRetryableStatus(err.status)) {
|
|
209
|
+
breakers.delete(key);
|
|
210
|
+
throw err;
|
|
211
|
+
}
|
|
212
|
+
b.failures += 1;
|
|
213
|
+
if (b.failures >= this.breaker.failureThreshold) {
|
|
214
|
+
b.openedAt = Date.now();
|
|
215
|
+
this.log(`circuit opened for ${opts.path} after ${b.failures} failures`);
|
|
216
|
+
}
|
|
217
|
+
breakers.set(key, b);
|
|
218
|
+
throw err;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async send(opts) {
|
|
183
222
|
const url = buildUrl(this.baseUrl + opts.path, opts.query);
|
|
184
223
|
const method = opts.method ?? "GET";
|
|
185
224
|
const headers = {
|
|
@@ -332,6 +371,7 @@ var XeniaApi = class {
|
|
|
332
371
|
defaultHeaders: config.headers,
|
|
333
372
|
timeout: config.timeout,
|
|
334
373
|
retry: config.retry,
|
|
374
|
+
circuitBreaker: config.circuitBreaker,
|
|
335
375
|
debug: config.debug
|
|
336
376
|
});
|
|
337
377
|
}
|
|
@@ -504,6 +544,18 @@ var XeniaApi = class {
|
|
|
504
544
|
}
|
|
505
545
|
};
|
|
506
546
|
|
|
547
|
+
// src/core/cookie-names.ts
|
|
548
|
+
var DEFAULT_PREFIX = "xenia";
|
|
549
|
+
function visitorCookieName(prefix = DEFAULT_PREFIX) {
|
|
550
|
+
return `${prefix || DEFAULT_PREFIX}_vid`;
|
|
551
|
+
}
|
|
552
|
+
function consentCookieName(prefix = DEFAULT_PREFIX) {
|
|
553
|
+
return `${prefix || DEFAULT_PREFIX}_consent`;
|
|
554
|
+
}
|
|
555
|
+
function consentCookie(state, prefix, maxAgeDays = 365) {
|
|
556
|
+
return `${consentCookieName(prefix)}=${encodeURIComponent(JSON.stringify(state))}; path=/; max-age=${Math.floor(maxAgeDays * 86400)}; SameSite=Lax`;
|
|
557
|
+
}
|
|
558
|
+
|
|
507
559
|
// src/core/event-payload.ts
|
|
508
560
|
var RESERVED = /* @__PURE__ */ new Set([
|
|
509
561
|
"eventId",
|
|
@@ -933,12 +985,6 @@ var AutoTracker = class {
|
|
|
933
985
|
}
|
|
934
986
|
};
|
|
935
987
|
|
|
936
|
-
// src/core/cookie-names.ts
|
|
937
|
-
var DEFAULT_PREFIX = "xenia";
|
|
938
|
-
function visitorCookieName(prefix = DEFAULT_PREFIX) {
|
|
939
|
-
return `${prefix || DEFAULT_PREFIX}_vid`;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
988
|
// src/client/identity.ts
|
|
943
989
|
var SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
944
990
|
var Identity = class {
|
|
@@ -2216,6 +2262,12 @@ var XeniaClient = class {
|
|
|
2216
2262
|
async consent(state) {
|
|
2217
2263
|
const wasAllowed = this.analyticsAllowed();
|
|
2218
2264
|
this.consentState = { ...this.consentState, ...state };
|
|
2265
|
+
if (isBrowser()) {
|
|
2266
|
+
try {
|
|
2267
|
+
document.cookie = consentCookie(this.consentState, this.options.prefix);
|
|
2268
|
+
} catch {
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2219
2271
|
if (this.analyticsAllowed() && !wasAllowed) {
|
|
2220
2272
|
this.analyticsQueue.start();
|
|
2221
2273
|
void this.analyticsQueue.flush();
|
|
@@ -2314,6 +2366,8 @@ exports.WIDGET_RENDERERS = WIDGET_RENDERERS;
|
|
|
2314
2366
|
exports.XeniaClient = XeniaClient;
|
|
2315
2367
|
exports.collectFields = collectFields;
|
|
2316
2368
|
exports.computeSpinRotation = computeSpinRotation;
|
|
2369
|
+
exports.consentCookie = consentCookie;
|
|
2370
|
+
exports.consentCookieName = consentCookieName;
|
|
2317
2371
|
exports.createXeniaClient = createXeniaClient;
|
|
2318
2372
|
exports.extractContentSwaps = extractContentSwaps;
|
|
2319
2373
|
exports.hideContent = hideContent;
|