@xenia-martech/sdk-js 1.0.1-dev.1 → 1.1.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +54 -4
  2. package/dist/{actions-CcBYV--3.d.cts → actions-CKeiofxJ.d.cts} +19 -1
  3. package/dist/{actions-CcBYV--3.d.ts → actions-CKeiofxJ.d.ts} +19 -1
  4. package/dist/{cookie-names-B3b0XNc2.d.cts → api-URhxxi4x.d.cts} +19 -42
  5. package/dist/{cookie-names-B3b0XNc2.d.ts → api-URhxxi4x.d.ts} +19 -42
  6. package/dist/chunk-5D7SJIO4.cjs +109 -0
  7. package/dist/chunk-5D7SJIO4.cjs.map +1 -0
  8. package/dist/{chunk-XXNDHYAS.js → chunk-FYSEKFIY.js} +45 -103
  9. package/dist/chunk-FYSEKFIY.js.map +1 -0
  10. package/dist/{chunk-WYM4CQVG.cjs → chunk-JEKVN7HK.cjs} +46 -106
  11. package/dist/chunk-JEKVN7HK.cjs.map +1 -0
  12. package/dist/chunk-TLTG3BTC.js +104 -0
  13. package/dist/chunk-TLTG3BTC.js.map +1 -0
  14. package/dist/chunk-U2WBBOYT.cjs +233 -0
  15. package/dist/chunk-U2WBBOYT.cjs.map +1 -0
  16. package/dist/chunk-WYAMPEVV.js +227 -0
  17. package/dist/chunk-WYAMPEVV.js.map +1 -0
  18. package/dist/client/index.cjs +60 -6
  19. package/dist/client/index.cjs.map +1 -1
  20. package/dist/client/index.d.cts +25 -3
  21. package/dist/client/index.d.ts +25 -3
  22. package/dist/client/index.js +59 -7
  23. package/dist/client/index.js.map +1 -1
  24. package/dist/client/react/index.cjs +58 -6
  25. package/dist/client/react/index.cjs.map +1 -1
  26. package/dist/client/react/index.d.cts +2 -2
  27. package/dist/client/react/index.d.ts +2 -2
  28. package/dist/client/react/index.js +58 -6
  29. package/dist/client/react/index.js.map +1 -1
  30. package/dist/cookie-names-8FxbGKGS.d.ts +127 -0
  31. package/dist/cookie-names-QYMiEMAq.d.cts +127 -0
  32. package/dist/index.cjs +41 -32
  33. package/dist/index.d.cts +4 -71
  34. package/dist/index.d.ts +4 -71
  35. package/dist/index.js +2 -1
  36. package/dist/next/index.cjs +59 -0
  37. package/dist/next/index.cjs.map +1 -0
  38. package/dist/next/index.d.cts +45 -0
  39. package/dist/next/index.d.ts +45 -0
  40. package/dist/next/index.js +54 -0
  41. package/dist/next/index.js.map +1 -0
  42. package/dist/server/index.cjs +38 -214
  43. package/dist/server/index.cjs.map +1 -1
  44. package/dist/server/index.d.cts +5 -104
  45. package/dist/server/index.d.ts +5 -104
  46. package/dist/server/index.js +5 -204
  47. package/dist/server/index.js.map +1 -1
  48. package/dist/xenia-sdk.iife.js +3 -3
  49. package/dist/xenia-sdk.iife.js.map +1 -1
  50. package/dist/xenia-server-D-ozqSgv.d.ts +126 -0
  51. package/dist/xenia-server-rs3Gpbw7.d.cts +126 -0
  52. package/package.json +26 -7
  53. package/dist/chunk-WYM4CQVG.cjs.map +0 -1
  54. package/dist/chunk-XXNDHYAS.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { I as InteractionType, X as XeniaConfig, a as XeniaEvent, M as MessageCta, b as MessageTemplateFn, c as MessageComponentRenderer, W as WidgetFormSubmit, d as WidgetSubmitResponse, e as XeniaAction, f as MessagePlacement } from '../actions-CcBYV--3.cjs';
2
- export { A as AnalyticsContext, g as AnalyticsEventName, h as AnalyticsIdentity, i as AnalyticsIngestResponse, C as ClientEvent, j as ConsentState, k as ContentSwap, l as IdentifyRequest, m as IdentifyResponse, n as Identity, J as JsonValue, o as MessageMountContext, p as MessageRenderContext, P as PersonalizationSwap, R as ResolveBatchItem, q as ResolveBatchResult, r as ResolveOptions, s as ResolveResult, T as TrackOptions, t as WebhookResponse, u as WidgetPrize, v as WidgetSegment, w as WidgetType, x as XeniaClient, y as XeniaClientOptions, z as createXeniaClient, B as extractContentSwaps, D as parseActions, E as spliceSlots } from '../actions-CcBYV--3.cjs';
1
+ import { I as InteractionType, X as XeniaConfig, a as XeniaEvent, M as MessageCta, b as MessageTemplateFn, c as MessageComponentRenderer, W as WidgetFormSubmit, d as WidgetSubmitResponse, e as XeniaAction, f as MessagePlacement, C as ConsentState } from '../actions-CKeiofxJ.cjs';
2
+ export { A as AnalyticsContext, g as AnalyticsEventName, h as AnalyticsIdentity, i as AnalyticsIngestResponse, j as ClientEvent, k as ContentSwap, l as IdentifyRequest, m as IdentifyResponse, n as Identity, J as JsonValue, o as MessageMountContext, p as MessageRenderContext, P as PersonalizationSwap, R as ResolveBatchItem, q as ResolveBatchResult, r as ResolveOptions, s as ResolveResult, T as TrackOptions, t as WebhookResponse, u as WidgetPrize, v as WidgetSegment, w as WidgetType, x as XeniaClient, y as XeniaClientOptions, z as createXeniaClient, B as extractContentSwaps, D as parseActions, E as spliceSlots } from '../actions-CKeiofxJ.cjs';
3
3
 
4
4
  interface Parsed {
5
5
  eventId: string;
@@ -322,4 +322,26 @@ declare function computeSpinRotation(segmentIndex: number, segmentCount: number,
322
322
  */
323
323
  declare const WIDGET_RENDERERS: Record<string, WidgetRenderer>;
324
324
 
325
- export { ActionRenderer, AnalyticsQueue, type AnalyticsQueueOptions, type AutoTrackOptions, AutoTracker, type CtaHandler, InteractionType, type MessageAction, MessageComponentRenderer, MessageCta, MessagePlacement, MessageTemplateFn, type SlotMeta, type SubmitWidgetFormHandler, TokenProvider, WIDGET_RENDERERS, WidgetFormSubmit, type WidgetRenderer, WidgetSubmitResponse, type WidgetWireContext, XeniaAction, XeniaConfig, XeniaEvent, collectFields, computeSpinRotation, hideContent, parseDataAttribute, readSlotMeta, resolveTarget, showContent, swapContent, wireFormSubmit };
325
+ /**
326
+ * Cookie names shared by the browser and server halves of the SDK.
327
+ *
328
+ * The visitor cookie is the one channel where two runtimes must agree on a literal string: the
329
+ * browser writes it, a same-origin server reads it back, and that match is what lets a server-side
330
+ * conversion attribute to a browser-entered journey. `config.prefix` namespaces it — so two Xenia
331
+ * apps on one domain keep separate visitors — which means **both halves must derive the name the
332
+ * same way**. Deriving it on one side and hardcoding it on the other silently breaks the link for
333
+ * anyone using a custom prefix: the server just finds no cookie and falls back to no visitor.
334
+ *
335
+ * Always build the name with these helpers rather than interpolating it by hand.
336
+ */
337
+
338
+ /** Name of the first-party cookie carrying consent scopes, for a given prefix. */
339
+ declare function consentCookieName(prefix?: string): string;
340
+ /**
341
+ * A `document.cookie` string carrying consent, in the JSON form the server SDK's `getConsent()`
342
+ * reads back. The browser client's `consent()` writes it; a page with its own consent banner and no
343
+ * browser client can write it directly, so server-side calls see the visitor's choice.
344
+ */
345
+ declare function consentCookie(state: ConsentState, prefix?: string, maxAgeDays?: number): string;
346
+
347
+ export { ActionRenderer, AnalyticsQueue, type AnalyticsQueueOptions, type AutoTrackOptions, AutoTracker, ConsentState, type CtaHandler, InteractionType, type MessageAction, MessageComponentRenderer, MessageCta, MessagePlacement, MessageTemplateFn, type SlotMeta, type SubmitWidgetFormHandler, TokenProvider, WIDGET_RENDERERS, WidgetFormSubmit, type WidgetRenderer, WidgetSubmitResponse, type WidgetWireContext, XeniaAction, XeniaConfig, XeniaEvent, collectFields, computeSpinRotation, consentCookie, consentCookieName, hideContent, parseDataAttribute, readSlotMeta, resolveTarget, showContent, swapContent, wireFormSubmit };
@@ -1,5 +1,5 @@
1
- import { I as InteractionType, X as XeniaConfig, a as XeniaEvent, M as MessageCta, b as MessageTemplateFn, c as MessageComponentRenderer, W as WidgetFormSubmit, d as WidgetSubmitResponse, e as XeniaAction, f as MessagePlacement } from '../actions-CcBYV--3.js';
2
- export { A as AnalyticsContext, g as AnalyticsEventName, h as AnalyticsIdentity, i as AnalyticsIngestResponse, C as ClientEvent, j as ConsentState, k as ContentSwap, l as IdentifyRequest, m as IdentifyResponse, n as Identity, J as JsonValue, o as MessageMountContext, p as MessageRenderContext, P as PersonalizationSwap, R as ResolveBatchItem, q as ResolveBatchResult, r as ResolveOptions, s as ResolveResult, T as TrackOptions, t as WebhookResponse, u as WidgetPrize, v as WidgetSegment, w as WidgetType, x as XeniaClient, y as XeniaClientOptions, z as createXeniaClient, B as extractContentSwaps, D as parseActions, E as spliceSlots } from '../actions-CcBYV--3.js';
1
+ import { I as InteractionType, X as XeniaConfig, a as XeniaEvent, M as MessageCta, b as MessageTemplateFn, c as MessageComponentRenderer, W as WidgetFormSubmit, d as WidgetSubmitResponse, e as XeniaAction, f as MessagePlacement, C as ConsentState } from '../actions-CKeiofxJ.js';
2
+ export { A as AnalyticsContext, g as AnalyticsEventName, h as AnalyticsIdentity, i as AnalyticsIngestResponse, j as ClientEvent, k as ContentSwap, l as IdentifyRequest, m as IdentifyResponse, n as Identity, J as JsonValue, o as MessageMountContext, p as MessageRenderContext, P as PersonalizationSwap, R as ResolveBatchItem, q as ResolveBatchResult, r as ResolveOptions, s as ResolveResult, T as TrackOptions, t as WebhookResponse, u as WidgetPrize, v as WidgetSegment, w as WidgetType, x as XeniaClient, y as XeniaClientOptions, z as createXeniaClient, B as extractContentSwaps, D as parseActions, E as spliceSlots } from '../actions-CKeiofxJ.js';
3
3
 
4
4
  interface Parsed {
5
5
  eventId: string;
@@ -322,4 +322,26 @@ declare function computeSpinRotation(segmentIndex: number, segmentCount: number,
322
322
  */
323
323
  declare const WIDGET_RENDERERS: Record<string, WidgetRenderer>;
324
324
 
325
- export { ActionRenderer, AnalyticsQueue, type AnalyticsQueueOptions, type AutoTrackOptions, AutoTracker, type CtaHandler, InteractionType, type MessageAction, MessageComponentRenderer, MessageCta, MessagePlacement, MessageTemplateFn, type SlotMeta, type SubmitWidgetFormHandler, TokenProvider, WIDGET_RENDERERS, WidgetFormSubmit, type WidgetRenderer, WidgetSubmitResponse, type WidgetWireContext, XeniaAction, XeniaConfig, XeniaEvent, collectFields, computeSpinRotation, hideContent, parseDataAttribute, readSlotMeta, resolveTarget, showContent, swapContent, wireFormSubmit };
325
+ /**
326
+ * Cookie names shared by the browser and server halves of the SDK.
327
+ *
328
+ * The visitor cookie is the one channel where two runtimes must agree on a literal string: the
329
+ * browser writes it, a same-origin server reads it back, and that match is what lets a server-side
330
+ * conversion attribute to a browser-entered journey. `config.prefix` namespaces it — so two Xenia
331
+ * apps on one domain keep separate visitors — which means **both halves must derive the name the
332
+ * same way**. Deriving it on one side and hardcoding it on the other silently breaks the link for
333
+ * anyone using a custom prefix: the server just finds no cookie and falls back to no visitor.
334
+ *
335
+ * Always build the name with these helpers rather than interpolating it by hand.
336
+ */
337
+
338
+ /** Name of the first-party cookie carrying consent scopes, for a given prefix. */
339
+ declare function consentCookieName(prefix?: string): string;
340
+ /**
341
+ * A `document.cookie` string carrying consent, in the JSON form the server SDK's `getConsent()`
342
+ * reads back. The browser client's `consent()` writes it; a page with its own consent banner and no
343
+ * browser client can write it directly, so server-side calls see the visitor's choice.
344
+ */
345
+ declare function consentCookie(state: ConsentState, prefix?: string, maxAgeDays?: number): string;
346
+
347
+ export { ActionRenderer, AnalyticsQueue, type AnalyticsQueueOptions, type AutoTrackOptions, AutoTracker, ConsentState, type CtaHandler, InteractionType, type MessageAction, MessageComponentRenderer, MessageCta, MessagePlacement, MessageTemplateFn, type SlotMeta, type SubmitWidgetFormHandler, TokenProvider, WIDGET_RENDERERS, WidgetFormSubmit, type WidgetRenderer, WidgetSubmitResponse, type WidgetWireContext, XeniaAction, XeniaConfig, XeniaEvent, collectFields, computeSpinRotation, consentCookie, consentCookieName, hideContent, parseDataAttribute, readSlotMeta, resolveTarget, showContent, swapContent, wireFormSubmit };
@@ -161,12 +161,22 @@ var HttpError = class extends Error {
161
161
  status;
162
162
  data;
163
163
  };
164
+ var CircuitOpenError = class extends Error {
165
+ constructor(endpoint) {
166
+ super(`Circuit open for ${endpoint}: failing fast until the cooldown passes`);
167
+ this.endpoint = endpoint;
168
+ this.name = "CircuitOpenError";
169
+ }
170
+ endpoint;
171
+ };
172
+ var breakers = /* @__PURE__ */ new Map();
164
173
  var HttpClient = class {
165
174
  baseUrl;
166
175
  defaultHeaders;
167
176
  timeout;
168
177
  retry;
169
178
  debug;
179
+ breaker;
170
180
  constructor(opts) {
171
181
  this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
172
182
  this.defaultHeaders = opts.defaultHeaders ?? {};
@@ -176,8 +186,37 @@ var HttpClient = class {
176
186
  baseDelayMs: opts.retry?.baseDelayMs ?? 300
177
187
  };
178
188
  this.debug = opts.debug ?? false;
189
+ const cb = opts.circuitBreaker === true ? {} : opts.circuitBreaker || null;
190
+ this.breaker = cb && { failureThreshold: cb.failureThreshold ?? 3, cooldownMs: cb.cooldownMs ?? 3e4 };
179
191
  }
180
192
  async request(opts) {
193
+ if (!this.breaker) return this.send(opts);
194
+ const key = buildUrl(this.baseUrl + opts.path, opts.query);
195
+ const b = breakers.get(key) ?? { failures: 0, openedAt: 0 };
196
+ if (b.openedAt) {
197
+ if (Date.now() - b.openedAt < this.breaker.cooldownMs) throw new CircuitOpenError(key);
198
+ b.openedAt = 0;
199
+ b.failures = this.breaker.failureThreshold - 1;
200
+ }
201
+ try {
202
+ const result = await this.send(opts);
203
+ breakers.delete(key);
204
+ return result;
205
+ } catch (err) {
206
+ if (err instanceof HttpError && !this.isRetryableStatus(err.status)) {
207
+ breakers.delete(key);
208
+ throw err;
209
+ }
210
+ b.failures += 1;
211
+ if (b.failures >= this.breaker.failureThreshold) {
212
+ b.openedAt = Date.now();
213
+ this.log(`circuit opened for ${opts.path} after ${b.failures} failures`);
214
+ }
215
+ breakers.set(key, b);
216
+ throw err;
217
+ }
218
+ }
219
+ async send(opts) {
181
220
  const url = buildUrl(this.baseUrl + opts.path, opts.query);
182
221
  const method = opts.method ?? "GET";
183
222
  const headers = {
@@ -330,6 +369,7 @@ var XeniaApi = class {
330
369
  defaultHeaders: config.headers,
331
370
  timeout: config.timeout,
332
371
  retry: config.retry,
372
+ circuitBreaker: config.circuitBreaker,
333
373
  debug: config.debug
334
374
  });
335
375
  }
@@ -502,6 +542,18 @@ var XeniaApi = class {
502
542
  }
503
543
  };
504
544
 
545
+ // src/core/cookie-names.ts
546
+ var DEFAULT_PREFIX = "xenia";
547
+ function visitorCookieName(prefix = DEFAULT_PREFIX) {
548
+ return `${prefix || DEFAULT_PREFIX}_vid`;
549
+ }
550
+ function consentCookieName(prefix = DEFAULT_PREFIX) {
551
+ return `${prefix || DEFAULT_PREFIX}_consent`;
552
+ }
553
+ function consentCookie(state, prefix, maxAgeDays = 365) {
554
+ return `${consentCookieName(prefix)}=${encodeURIComponent(JSON.stringify(state))}; path=/; max-age=${Math.floor(maxAgeDays * 86400)}; SameSite=Lax`;
555
+ }
556
+
505
557
  // src/core/event-payload.ts
506
558
  var RESERVED = /* @__PURE__ */ new Set([
507
559
  "eventId",
@@ -931,12 +983,6 @@ var AutoTracker = class {
931
983
  }
932
984
  };
933
985
 
934
- // src/core/cookie-names.ts
935
- var DEFAULT_PREFIX = "xenia";
936
- function visitorCookieName(prefix = DEFAULT_PREFIX) {
937
- return `${prefix || DEFAULT_PREFIX}_vid`;
938
- }
939
-
940
986
  // src/client/identity.ts
941
987
  var SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
942
988
  var Identity = class {
@@ -2214,6 +2260,12 @@ var XeniaClient = class {
2214
2260
  async consent(state) {
2215
2261
  const wasAllowed = this.analyticsAllowed();
2216
2262
  this.consentState = { ...this.consentState, ...state };
2263
+ if (isBrowser()) {
2264
+ try {
2265
+ document.cookie = consentCookie(this.consentState, this.options.prefix);
2266
+ } catch {
2267
+ }
2268
+ }
2217
2269
  if (this.analyticsAllowed() && !wasAllowed) {
2218
2270
  this.analyticsQueue.start();
2219
2271
  void this.analyticsQueue.flush();
@@ -2303,6 +2355,6 @@ function extractContentSwaps(body) {
2303
2355
  return Array.isArray(swaps) ? swaps : void 0;
2304
2356
  }
2305
2357
 
2306
- export { ActionRenderer, AnalyticsQueue, AutoTracker, Identity, TokenProvider, WIDGET_RENDERERS, XeniaClient, collectFields, computeSpinRotation, createXeniaClient, extractContentSwaps, hideContent, parseActions, parseDataAttribute, readSlotMeta, resolveTarget, showContent, spliceSlots, swapContent, wireFormSubmit };
2358
+ export { ActionRenderer, AnalyticsQueue, AutoTracker, Identity, TokenProvider, WIDGET_RENDERERS, XeniaClient, collectFields, computeSpinRotation, consentCookie, consentCookieName, createXeniaClient, extractContentSwaps, hideContent, parseActions, parseDataAttribute, readSlotMeta, resolveTarget, showContent, spliceSlots, swapContent, wireFormSubmit };
2307
2359
  //# sourceMappingURL=index.js.map
2308
2360
  //# sourceMappingURL=index.js.map