@xenia-martech/sdk-js 1.0.0-dev.27 → 1.0.0-dev.28

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 (35) hide show
  1. package/CSS_VARIABLES.md +7 -0
  2. package/README.md +50 -1
  3. package/dist/{actions-CkiSdvSa.d.cts → actions-CcBYV--3.d.cts} +177 -1
  4. package/dist/{actions-CkiSdvSa.d.ts → actions-CcBYV--3.d.ts} +177 -1
  5. package/dist/{chunk-UOW3GK4I.cjs → chunk-WYM4CQVG.cjs} +96 -4
  6. package/dist/chunk-WYM4CQVG.cjs.map +1 -0
  7. package/dist/{chunk-7D2HJMW6.js → chunk-XXNDHYAS.js} +96 -4
  8. package/dist/chunk-XXNDHYAS.js.map +1 -0
  9. package/dist/client/index.cjs +540 -27
  10. package/dist/client/index.cjs.map +1 -1
  11. package/dist/client/index.d.cts +112 -3
  12. package/dist/client/index.d.ts +112 -3
  13. package/dist/client/index.js +537 -28
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/client/react/index.cjs +536 -27
  16. package/dist/client/react/index.cjs.map +1 -1
  17. package/dist/client/react/index.d.cts +2 -2
  18. package/dist/client/react/index.d.ts +2 -2
  19. package/dist/client/react/index.js +536 -27
  20. package/dist/client/react/index.js.map +1 -1
  21. package/dist/{cookie-names-C3LKDhsg.d.cts → cookie-names-B3b0XNc2.d.cts} +153 -1
  22. package/dist/{cookie-names-C3LKDhsg.d.ts → cookie-names-B3b0XNc2.d.ts} +153 -1
  23. package/dist/index.cjs +20 -20
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +1 -1
  27. package/dist/server/index.cjs +15 -15
  28. package/dist/server/index.d.cts +2 -2
  29. package/dist/server/index.d.ts +2 -2
  30. package/dist/server/index.js +2 -2
  31. package/dist/xenia-sdk.iife.js +37 -3
  32. package/dist/xenia-sdk.iife.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/chunk-7D2HJMW6.js.map +0 -1
  35. package/dist/chunk-UOW3GK4I.cjs.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, d as XeniaAction } from '../actions-CkiSdvSa.cjs';
2
- export { A as AnalyticsContext, e as AnalyticsEventName, f as AnalyticsIdentity, g as AnalyticsIngestResponse, C as ClientEvent, h as ConsentState, i as ContentSwap, j as IdentifyRequest, k as IdentifyResponse, l as Identity, J as JsonValue, m as MessageMountContext, n as MessagePlacement, o as MessageRenderContext, P as PersonalizationSwap, R as ResolveBatchItem, p as ResolveBatchResult, q as ResolveOptions, r as ResolveResult, T as TrackOptions, W as WebhookResponse, s as XeniaClient, t as XeniaClientOptions, u as createXeniaClient, v as extractContentSwaps, w as parseActions, x as spliceSlots } from '../actions-CkiSdvSa.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 } 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';
3
3
 
4
4
  interface Parsed {
5
5
  eventId: string;
@@ -156,6 +156,10 @@ declare class AnalyticsQueue {
156
156
 
157
157
  /** Callback invoked when a rendered CTA fires an event. */
158
158
  type CtaHandler = (event: string, cta: MessageCta) => void;
159
+ /** Submits a widget's captured form values — injected from `XeniaClient.submitWidgetForm`. */
160
+ type SubmitWidgetFormHandler = (submit: WidgetFormSubmit, fields: Record<string, string>, opts?: {
161
+ idempotencyKey?: string;
162
+ }) => Promise<WidgetSubmitResponse>;
159
163
  /**
160
164
  * Resolve a target string to an element. Supports plain CSS selectors and the
161
165
  * `data-xenia-slot="<id>"` convention (a bare id with no CSS metacharacters is
@@ -183,12 +187,15 @@ declare class ActionRenderer {
183
187
  private readonly messageTemplate?;
184
188
  private readonly messageStyles?;
185
189
  private readonly messageComponent?;
190
+ private readonly submitWidgetFormFn?;
186
191
  /** Unmount callbacks for currently-mounted framework components, keyed by their container. */
187
192
  private readonly mounted;
188
193
  constructor(onCta?: CtaHandler, opts?: {
189
194
  messageTemplate?: MessageTemplateFn;
190
195
  messageStyles?: string;
191
196
  messageComponent?: MessageComponentRenderer;
197
+ /** Wired from `XeniaClient.submitWidgetForm` — powers every widget's form submission. */
198
+ submitWidgetForm?: SubmitWidgetFormHandler;
192
199
  });
193
200
  /** Apply a list of actions. Returns the count successfully applied. */
194
201
  apply(actions: XeniaAction[]): number;
@@ -211,6 +218,108 @@ declare class ActionRenderer {
211
218
  private positionClass;
212
219
  private cardHtml;
213
220
  private wireCard;
221
+ /** Build the imperative hooks (`dismiss`/`fireCta`/`submitWidgetForm`) handed to a widget's `wire()`. */
222
+ private buildWidgetCtx;
214
223
  }
215
224
 
216
- export { ActionRenderer, AnalyticsQueue, type AnalyticsQueueOptions, type AutoTrackOptions, AutoTracker, type CtaHandler, InteractionType, MessageComponentRenderer, MessageCta, MessageTemplateFn, type SlotMeta, TokenProvider, XeniaAction, XeniaConfig, XeniaEvent, hideContent, parseDataAttribute, readSlotMeta, resolveTarget, showContent, swapContent };
225
+ /** A message-placement action (banner/popup/modal/inline) — the shape every widget renders. */
226
+ type MessageAction = Extract<XeniaAction, {
227
+ type: MessagePlacement;
228
+ }>;
229
+ /**
230
+ * Imperative hooks a widget's `wire()` can call back into, injected by `ActionRenderer` —
231
+ * the widget module itself never touches `XeniaClient`/`XeniaApi` directly.
232
+ */
233
+ interface WidgetWireContext {
234
+ /**
235
+ * Dismiss this message — unmounts/removes it, same as the built-in card's close button.
236
+ * Absent for placements with no dismiss affordance in this render (e.g. an `inline` action
237
+ * rendered without a wrapping overlay). Widgets should guard with `ctx.dismiss?.()`.
238
+ */
239
+ dismiss?: () => void;
240
+ /** Fire the action's `cta` (event + url), then {@link dismiss}. A no-op beyond dismiss when the action has no `cta`. */
241
+ fireCta: () => void;
242
+ /**
243
+ * Submit captured field values for this widget's `formSubmit` config. Routes to the `/flow`
244
+ * fast path or `/widget-submissions`, per the cross-repo contract's endpoint-selection rule —
245
+ * the widget module never branches on `mode`/inspects the ref fields itself, it just calls this.
246
+ *
247
+ * Rejects if the action has no `formSubmit` config or no submission handler is wired (e.g. a
248
+ * bare `ActionRenderer` constructed without `XeniaClient`). A per-widget-instance
249
+ * `idempotencyKey` is applied automatically and reused across every call from the SAME
250
+ * `wire()` invocation (i.e. a retried submit of the same interaction never mints a new one).
251
+ */
252
+ submitWidgetForm: (fields: Record<string, string>) => Promise<WidgetSubmitResponse>;
253
+ }
254
+ /**
255
+ * Renders and wires a `widgetType`'s UI. One implementation per dispatchable widget type,
256
+ * collected into `WIDGET_RENDERERS` (`client/widgets/index.ts`). `standard`/`custom`/undefined
257
+ * are NOT dispatched through this interface — they use `ActionRenderer`'s existing built-in card
258
+ * path unmodified (plus the shared `wireFormSubmit()` addition), per the cross-repo contract.
259
+ */
260
+ interface WidgetRenderer {
261
+ /** Build the card markup injected into the shadow overlay or host-page slot. */
262
+ html(action: MessageAction, variant: MessagePlacement): string;
263
+ /** Wire interactivity after `html()`'s markup is already in the DOM under `root`. */
264
+ wire(root: Element | ShadowRoot, action: MessageAction, ctx: WidgetWireContext): void;
265
+ }
266
+
267
+ /**
268
+ * Shared form-field / submit DOM convention, used by EVERY widget type (including standard
269
+ * popups and `custom`) — see the cross-repo contract. Capturable inputs are marked
270
+ * `data-xenia-field="<name>"`; the submit trigger is marked `data-xenia-submit`. Read directly
271
+ * by `wireFormSubmit()` below, and reused as-is by the spin-wheel widget module
272
+ * (which has its own trigger — a Spin button — but still collects
273
+ * `data-xenia-field` values the same way).
274
+ */
275
+ declare function collectFields(root: Element | ShadowRoot | Document): Record<string, string>;
276
+ /**
277
+ * Wire the shared field-collection/submit convention onto an already-injected card. Used for
278
+ * every `standard`/`custom` widget (i.e. the fallthrough path in `ActionRenderer.wireCard()`) —
279
+ * this is the fix for the original loophole: a marketer/AI-authored popup with a real `<input>` +
280
+ * submit button now actually does something on submit.
281
+ *
282
+ * - If a real `<form>` is present in the injected HTML, its native `submit` event is
283
+ * auto-detected: `preventDefault()` is called and its `FormData` is merged into the collected
284
+ * `data-xenia-field` values (a marketer/AI who bothers to wrap fields in a `<form>` gets native
285
+ * Enter-to-submit/validation for free — nothing requires it).
286
+ * - Otherwise, the trigger is a click on `[data-xenia-submit]`.
287
+ * - The submit control is disabled synchronously on trigger (double-submit guard) and grows a
288
+ * small spinner (`[data-xenia-submitting]`) for the duration of the request.
289
+ * - On success: the spinner clears, the design's own `[data-xenia-success]` block (if authored —
290
+ * see {@link revealSuccess}) swaps in for the form, and after at least `successDisplayMs` has
291
+ * elapsed since the submit started (real dispatch round-trips are typically well under 100ms,
292
+ * too fast to register on its own), the whole card fades/scales out and dismisses itself
293
+ * ({@link fadeOutAndDismiss}) — the widget never just sits there disabled forever, and never
294
+ * vanishes before a visitor sees it worked.
295
+ * - On error: the spinner clears, the control re-enables, and an error message is shown.
296
+ *
297
+ * The `<form>`'s native `submit` is ALWAYS intercepted, even when `action.formSubmit` is missing
298
+ * (the marketer hasn't configured a submission target in the webhook-response node's
299
+ * Form-submission panel yet) — otherwise an unconfigured widget's real `<form>` falls through to
300
+ * the browser's default GET-to-current-URL submission, i.e. a full page reload. An unconfigured
301
+ * submit now surfaces a visible, inert error instead of silently doing nothing OR reloading.
302
+ */
303
+ declare function wireFormSubmit(root: Element | ShadowRoot, action: MessageAction, ctx: WidgetWireContext): void;
304
+
305
+ /**
306
+ * Deterministic resting rotation (degrees) that lands segment `segmentIndex` (out of
307
+ * `segmentCount`, equal slices starting at 12 o'clock going clockwise) under the wheel's fixed
308
+ * pointer, plus `extraSpins` full rotations for purely cosmetic flair — extra spins are
309
+ * client-random visual dressing ONLY; they never affect which segment the wheel lands on (the
310
+ * returned value mod 360 is fully determined by `segmentIndex`/`segmentCount`).
311
+ *
312
+ * Pure, exported, and unit-testable with no DOM — per the "wheel resolution sequencing"
313
+ * rule, this is called only AFTER the server-resolved `segmentIndex` is known, never before.
314
+ */
315
+ declare function computeSpinRotation(segmentIndex: number, segmentCount: number, extraSpins?: number): number;
316
+
317
+ /**
318
+ * Dispatch table keyed by `widgetType`, consulted by `ActionRenderer.cardHtml()`/`wireCard()`.
319
+ * `standard`/undefined is deliberately NOT here — it falls through to `ActionRenderer`'s
320
+ * existing built-in card path (plus the shared `wireFormSubmit()` addition), per the cross-repo
321
+ * contract. A 3rd future widget type is one new module + one new line here.
322
+ */
323
+ declare const WIDGET_RENDERERS: Record<string, WidgetRenderer>;
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 };
@@ -1,5 +1,5 @@
1
- import { I as InteractionType, X as XeniaConfig, a as XeniaEvent, M as MessageCta, b as MessageTemplateFn, c as MessageComponentRenderer, d as XeniaAction } from '../actions-CkiSdvSa.js';
2
- export { A as AnalyticsContext, e as AnalyticsEventName, f as AnalyticsIdentity, g as AnalyticsIngestResponse, C as ClientEvent, h as ConsentState, i as ContentSwap, j as IdentifyRequest, k as IdentifyResponse, l as Identity, J as JsonValue, m as MessageMountContext, n as MessagePlacement, o as MessageRenderContext, P as PersonalizationSwap, R as ResolveBatchItem, p as ResolveBatchResult, q as ResolveOptions, r as ResolveResult, T as TrackOptions, W as WebhookResponse, s as XeniaClient, t as XeniaClientOptions, u as createXeniaClient, v as extractContentSwaps, w as parseActions, x as spliceSlots } from '../actions-CkiSdvSa.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 } 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';
3
3
 
4
4
  interface Parsed {
5
5
  eventId: string;
@@ -156,6 +156,10 @@ declare class AnalyticsQueue {
156
156
 
157
157
  /** Callback invoked when a rendered CTA fires an event. */
158
158
  type CtaHandler = (event: string, cta: MessageCta) => void;
159
+ /** Submits a widget's captured form values — injected from `XeniaClient.submitWidgetForm`. */
160
+ type SubmitWidgetFormHandler = (submit: WidgetFormSubmit, fields: Record<string, string>, opts?: {
161
+ idempotencyKey?: string;
162
+ }) => Promise<WidgetSubmitResponse>;
159
163
  /**
160
164
  * Resolve a target string to an element. Supports plain CSS selectors and the
161
165
  * `data-xenia-slot="<id>"` convention (a bare id with no CSS metacharacters is
@@ -183,12 +187,15 @@ declare class ActionRenderer {
183
187
  private readonly messageTemplate?;
184
188
  private readonly messageStyles?;
185
189
  private readonly messageComponent?;
190
+ private readonly submitWidgetFormFn?;
186
191
  /** Unmount callbacks for currently-mounted framework components, keyed by their container. */
187
192
  private readonly mounted;
188
193
  constructor(onCta?: CtaHandler, opts?: {
189
194
  messageTemplate?: MessageTemplateFn;
190
195
  messageStyles?: string;
191
196
  messageComponent?: MessageComponentRenderer;
197
+ /** Wired from `XeniaClient.submitWidgetForm` — powers every widget's form submission. */
198
+ submitWidgetForm?: SubmitWidgetFormHandler;
192
199
  });
193
200
  /** Apply a list of actions. Returns the count successfully applied. */
194
201
  apply(actions: XeniaAction[]): number;
@@ -211,6 +218,108 @@ declare class ActionRenderer {
211
218
  private positionClass;
212
219
  private cardHtml;
213
220
  private wireCard;
221
+ /** Build the imperative hooks (`dismiss`/`fireCta`/`submitWidgetForm`) handed to a widget's `wire()`. */
222
+ private buildWidgetCtx;
214
223
  }
215
224
 
216
- export { ActionRenderer, AnalyticsQueue, type AnalyticsQueueOptions, type AutoTrackOptions, AutoTracker, type CtaHandler, InteractionType, MessageComponentRenderer, MessageCta, MessageTemplateFn, type SlotMeta, TokenProvider, XeniaAction, XeniaConfig, XeniaEvent, hideContent, parseDataAttribute, readSlotMeta, resolveTarget, showContent, swapContent };
225
+ /** A message-placement action (banner/popup/modal/inline) — the shape every widget renders. */
226
+ type MessageAction = Extract<XeniaAction, {
227
+ type: MessagePlacement;
228
+ }>;
229
+ /**
230
+ * Imperative hooks a widget's `wire()` can call back into, injected by `ActionRenderer` —
231
+ * the widget module itself never touches `XeniaClient`/`XeniaApi` directly.
232
+ */
233
+ interface WidgetWireContext {
234
+ /**
235
+ * Dismiss this message — unmounts/removes it, same as the built-in card's close button.
236
+ * Absent for placements with no dismiss affordance in this render (e.g. an `inline` action
237
+ * rendered without a wrapping overlay). Widgets should guard with `ctx.dismiss?.()`.
238
+ */
239
+ dismiss?: () => void;
240
+ /** Fire the action's `cta` (event + url), then {@link dismiss}. A no-op beyond dismiss when the action has no `cta`. */
241
+ fireCta: () => void;
242
+ /**
243
+ * Submit captured field values for this widget's `formSubmit` config. Routes to the `/flow`
244
+ * fast path or `/widget-submissions`, per the cross-repo contract's endpoint-selection rule —
245
+ * the widget module never branches on `mode`/inspects the ref fields itself, it just calls this.
246
+ *
247
+ * Rejects if the action has no `formSubmit` config or no submission handler is wired (e.g. a
248
+ * bare `ActionRenderer` constructed without `XeniaClient`). A per-widget-instance
249
+ * `idempotencyKey` is applied automatically and reused across every call from the SAME
250
+ * `wire()` invocation (i.e. a retried submit of the same interaction never mints a new one).
251
+ */
252
+ submitWidgetForm: (fields: Record<string, string>) => Promise<WidgetSubmitResponse>;
253
+ }
254
+ /**
255
+ * Renders and wires a `widgetType`'s UI. One implementation per dispatchable widget type,
256
+ * collected into `WIDGET_RENDERERS` (`client/widgets/index.ts`). `standard`/`custom`/undefined
257
+ * are NOT dispatched through this interface — they use `ActionRenderer`'s existing built-in card
258
+ * path unmodified (plus the shared `wireFormSubmit()` addition), per the cross-repo contract.
259
+ */
260
+ interface WidgetRenderer {
261
+ /** Build the card markup injected into the shadow overlay or host-page slot. */
262
+ html(action: MessageAction, variant: MessagePlacement): string;
263
+ /** Wire interactivity after `html()`'s markup is already in the DOM under `root`. */
264
+ wire(root: Element | ShadowRoot, action: MessageAction, ctx: WidgetWireContext): void;
265
+ }
266
+
267
+ /**
268
+ * Shared form-field / submit DOM convention, used by EVERY widget type (including standard
269
+ * popups and `custom`) — see the cross-repo contract. Capturable inputs are marked
270
+ * `data-xenia-field="<name>"`; the submit trigger is marked `data-xenia-submit`. Read directly
271
+ * by `wireFormSubmit()` below, and reused as-is by the spin-wheel widget module
272
+ * (which has its own trigger — a Spin button — but still collects
273
+ * `data-xenia-field` values the same way).
274
+ */
275
+ declare function collectFields(root: Element | ShadowRoot | Document): Record<string, string>;
276
+ /**
277
+ * Wire the shared field-collection/submit convention onto an already-injected card. Used for
278
+ * every `standard`/`custom` widget (i.e. the fallthrough path in `ActionRenderer.wireCard()`) —
279
+ * this is the fix for the original loophole: a marketer/AI-authored popup with a real `<input>` +
280
+ * submit button now actually does something on submit.
281
+ *
282
+ * - If a real `<form>` is present in the injected HTML, its native `submit` event is
283
+ * auto-detected: `preventDefault()` is called and its `FormData` is merged into the collected
284
+ * `data-xenia-field` values (a marketer/AI who bothers to wrap fields in a `<form>` gets native
285
+ * Enter-to-submit/validation for free — nothing requires it).
286
+ * - Otherwise, the trigger is a click on `[data-xenia-submit]`.
287
+ * - The submit control is disabled synchronously on trigger (double-submit guard) and grows a
288
+ * small spinner (`[data-xenia-submitting]`) for the duration of the request.
289
+ * - On success: the spinner clears, the design's own `[data-xenia-success]` block (if authored —
290
+ * see {@link revealSuccess}) swaps in for the form, and after at least `successDisplayMs` has
291
+ * elapsed since the submit started (real dispatch round-trips are typically well under 100ms,
292
+ * too fast to register on its own), the whole card fades/scales out and dismisses itself
293
+ * ({@link fadeOutAndDismiss}) — the widget never just sits there disabled forever, and never
294
+ * vanishes before a visitor sees it worked.
295
+ * - On error: the spinner clears, the control re-enables, and an error message is shown.
296
+ *
297
+ * The `<form>`'s native `submit` is ALWAYS intercepted, even when `action.formSubmit` is missing
298
+ * (the marketer hasn't configured a submission target in the webhook-response node's
299
+ * Form-submission panel yet) — otherwise an unconfigured widget's real `<form>` falls through to
300
+ * the browser's default GET-to-current-URL submission, i.e. a full page reload. An unconfigured
301
+ * submit now surfaces a visible, inert error instead of silently doing nothing OR reloading.
302
+ */
303
+ declare function wireFormSubmit(root: Element | ShadowRoot, action: MessageAction, ctx: WidgetWireContext): void;
304
+
305
+ /**
306
+ * Deterministic resting rotation (degrees) that lands segment `segmentIndex` (out of
307
+ * `segmentCount`, equal slices starting at 12 o'clock going clockwise) under the wheel's fixed
308
+ * pointer, plus `extraSpins` full rotations for purely cosmetic flair — extra spins are
309
+ * client-random visual dressing ONLY; they never affect which segment the wheel lands on (the
310
+ * returned value mod 360 is fully determined by `segmentIndex`/`segmentCount`).
311
+ *
312
+ * Pure, exported, and unit-testable with no DOM — per the "wheel resolution sequencing"
313
+ * rule, this is called only AFTER the server-resolved `segmentIndex` is known, never before.
314
+ */
315
+ declare function computeSpinRotation(segmentIndex: number, segmentCount: number, extraSpins?: number): number;
316
+
317
+ /**
318
+ * Dispatch table keyed by `widgetType`, consulted by `ActionRenderer.cardHtml()`/`wireCard()`.
319
+ * `standard`/undefined is deliberately NOT here — it falls through to `ActionRenderer`'s
320
+ * existing built-in card path (plus the shared `wireFormSubmit()` addition), per the cross-repo
321
+ * contract. A 3rd future widget type is one new module + one new line here.
322
+ */
323
+ declare const WIDGET_RENDERERS: Record<string, WidgetRenderer>;
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 };