@returningai/widget-sdk 1.4.2 → 1.5.0

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.
@@ -10697,6 +10697,9 @@ function clearState(state) {
10697
10697
  state.syncTimer = null;
10698
10698
  }
10699
10699
  }
10700
+ const STORE_CALLBACK_FIELD_OPTIONS_SCOPE = "store.callback_field_options";
10701
+ const STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME = "callbackFieldOptions";
10702
+ const STORE_CALLBACK_FIELD_OPTIONS_TIMEOUT_MS = 15e3;
10700
10703
  function debounce(fn, wait) {
10701
10704
  let timer = null;
10702
10705
  return {
@@ -10733,13 +10736,13 @@ function sendTokenToWidget(config, state, iframe) {
10733
10736
  } catch {
10734
10737
  }
10735
10738
  }
10736
- function setupMessageListener(config, state, _shadow, iframe, onRefreshScheduled, onLogout, hideLoader, emit) {
10739
+ function setupMessageListener(config, state, _shadow, iframe, onRefreshScheduled, onLogout, hideLoader, emit, getCallbacks) {
10737
10740
  const heightSetter = debounce((h) => {
10738
10741
  iframe.style.height = `${h}px`;
10739
10742
  emit == null ? void 0 : emit("rai-height-change", { height: h });
10740
10743
  }, config.heightDebounce ?? 100);
10741
10744
  const handler = async (event) => {
10742
- var _a;
10745
+ var _a, _b;
10743
10746
  if (event.origin !== config.widgetDomain) return;
10744
10747
  if (!event.data || typeof event.data.type !== "string") return;
10745
10748
  const { type, containerId, widgetId, payload } = event.data;
@@ -10785,6 +10788,55 @@ function setupMessageListener(config, state, _shadow, iframe, onRefreshScheduled
10785
10788
  if (onLogout) await onLogout();
10786
10789
  break;
10787
10790
  }
10791
+ case "RETURNINGAI_WIDGET_ACTION": {
10792
+ if (event.source !== iframe.contentWindow) break;
10793
+ const message = event.data;
10794
+ if (config.widgetType !== "store" && config.widgetType !== "custom") break;
10795
+ if (message.widgetType !== "store") break;
10796
+ if (message.action !== "store:host-callback") break;
10797
+ if (message.callbackName !== STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME) break;
10798
+ if (((_b = message.payload) == null ? void 0 : _b.scope) !== STORE_CALLBACK_FIELD_OPTIONS_SCOPE) break;
10799
+ if (message.widgetId !== void 0 && message.widgetId !== config.widgetId) break;
10800
+ if (message.containerId !== void 0 && message.containerId !== config.container) break;
10801
+ const respond = (result) => {
10802
+ var _a2;
10803
+ (_a2 = iframe.contentWindow) == null ? void 0 : _a2.postMessage(result, config.widgetDomain);
10804
+ };
10805
+ const callbacks = (getCallbacks == null ? void 0 : getCallbacks()) ?? {};
10806
+ const callback = callbacks[message.callbackName];
10807
+ if (!callback) {
10808
+ respond({
10809
+ type: "RETURNINGAI_WIDGET_ACTION_RESULT",
10810
+ requestId: message.requestId,
10811
+ action: "store:host-callback",
10812
+ ok: false,
10813
+ status: "failed",
10814
+ error: { message: "Host callback is not registered" }
10815
+ });
10816
+ break;
10817
+ }
10818
+ try {
10819
+ const value = await callback(message.payload);
10820
+ respond({
10821
+ type: "RETURNINGAI_WIDGET_ACTION_RESULT",
10822
+ requestId: message.requestId,
10823
+ action: "store:host-callback",
10824
+ ok: true,
10825
+ status: "success",
10826
+ value
10827
+ });
10828
+ } catch {
10829
+ respond({
10830
+ type: "RETURNINGAI_WIDGET_ACTION_RESULT",
10831
+ requestId: message.requestId,
10832
+ action: "store:host-callback",
10833
+ ok: false,
10834
+ status: "failed",
10835
+ error: { message: "Host callback failed" }
10836
+ });
10837
+ }
10838
+ break;
10839
+ }
10788
10840
  }
10789
10841
  };
10790
10842
  window.addEventListener("message", handler);
@@ -10793,6 +10845,45 @@ function setupMessageListener(config, state, _shadow, iframe, onRefreshScheduled
10793
10845
  heightSetter.cancel();
10794
10846
  };
10795
10847
  }
10848
+ function assertCallbackName(callbackName) {
10849
+ if (!callbackName || typeof callbackName !== "string") {
10850
+ throw new TypeError("ReturningAI callback name must be a non-empty string");
10851
+ }
10852
+ }
10853
+ function assertCallback(callback) {
10854
+ if (typeof callback !== "function") {
10855
+ throw new TypeError("ReturningAI callback must be a function");
10856
+ }
10857
+ }
10858
+ class WidgetCallbackRegistry {
10859
+ constructor() {
10860
+ __publicField(this, "registeredCallbacks", {});
10861
+ __publicField(this, "locked", false);
10862
+ }
10863
+ get isLocked() {
10864
+ return this.locked;
10865
+ }
10866
+ registerCallback(callbackName, callback) {
10867
+ if (this.locked) {
10868
+ return;
10869
+ }
10870
+ assertCallbackName(callbackName);
10871
+ assertCallback(callback);
10872
+ this.registeredCallbacks = {
10873
+ ...this.registeredCallbacks,
10874
+ [callbackName]: callback
10875
+ };
10876
+ }
10877
+ lock() {
10878
+ if (this.locked) {
10879
+ return;
10880
+ }
10881
+ this.locked = true;
10882
+ }
10883
+ read() {
10884
+ return { ...this.registeredCallbacks };
10885
+ }
10886
+ }
10796
10887
  const widgetCSS = ':host{display:block;position:relative;width:100%;height:100%}.rai-loader{position:absolute;top:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;width:100%;height:100%;background:var(--background-5, var(--rai-loader-bg, #ffffff));border-radius:8px;z-index:10;transition:opacity .3s ease-out;font-family:var(--rai-loader-font, "Roboto", system-ui, -apple-system, sans-serif)}.rai-loader.fade-out{opacity:0;pointer-events:none}.rai-loader-text{margin:.5rem 0 0;font-size:1.125rem;line-height:1.75rem;font-weight:400;letter-spacing:normal;color:var(--accent-1, var(--rai-accent, #000000));text-align:center}@media (min-width: 768px){.rai-loader-text{font-size:1.5rem;line-height:2rem}}.rai-error{display:none;position:absolute;top:0;left:0;width:100%;height:100%;align-items:center;justify-content:center;flex-direction:column;gap:12px;background:var(--rai-error-bg, #1a1a1a);border-radius:8px;padding:24px;box-sizing:border-box;text-align:center;color:var(--rai-error-text, #9ca3af);font-family:system-ui,-apple-system,sans-serif;z-index:10}.rai-error.visible{display:flex}iframe{display:block;border:none;opacity:0;transition:opacity .3s ease-in}iframe.loaded{opacity:1}.rai-lottie-loader{width:100px;height:100px}.rai-lottie-loader svg{width:100%!important;height:100%!important}.rai-lottie-spinner{width:32px;height:32px;margin:34px auto;border:3px solid var(--rai-text4, #6b7280);border-top-color:var(--rai-accent, #000000);border-radius:50%;animation:rai-spin .7s linear infinite}@keyframes rai-spin{to{transform:rotate(360deg)}}.rai-sdk-loader{position:relative;width:75px;height:100px}.rai-sdk-loader__bar{position:absolute;bottom:0;width:10px;height:50%;background:var(--rai-accent, #000000);transform-origin:center bottom;box-shadow:1px 1px #0003}.rai-sdk-loader__bar:nth-child(1){left:0;transform:scaleY(.2);animation:rai-sdk-barUp1 4s infinite}.rai-sdk-loader__bar:nth-child(2){left:15px;transform:scaleY(.4);animation:rai-sdk-barUp2 4s infinite}.rai-sdk-loader__bar:nth-child(3){left:30px;transform:scaleY(.6);animation:rai-sdk-barUp3 4s infinite}.rai-sdk-loader__bar:nth-child(4){left:45px;transform:scaleY(.8);animation:rai-sdk-barUp4 4s infinite}.rai-sdk-loader__bar:nth-child(5){left:60px;transform:scale(1);animation:rai-sdk-barUp5 4s infinite}.rai-sdk-loader__ball{position:absolute;bottom:10px;left:0;width:10px;height:10px;background:var(--rai-accent, #000000);border-radius:50%;animation:rai-sdk-ball 4s infinite}@keyframes rai-sdk-ball{0%{transform:translate(0)}5%{transform:translate(8px,-14px)}10%{transform:translate(15px,-10px)}17%{transform:translate(23px,-24px)}20%{transform:translate(30px,-20px)}27%{transform:translate(38px,-34px)}30%{transform:translate(45px,-30px)}37%{transform:translate(53px,-44px)}40%{transform:translate(60px,-40px)}50%{transform:translate(60px)}57%{transform:translate(53px,-14px)}60%{transform:translate(45px,-10px)}67%{transform:translate(37px,-24px)}70%{transform:translate(30px,-20px)}77%{transform:translate(22px,-34px)}80%{transform:translate(15px,-30px)}87%{transform:translate(7px,-44px)}90%{transform:translateY(-40px)}to{transform:translate(0)}}@keyframes rai-sdk-barUp1{0%{transform:scaleY(.2)}40%{transform:scaleY(.2)}50%{transform:scale(1)}90%{transform:scale(1)}to{transform:scaleY(.2)}}@keyframes rai-sdk-barUp2{0%{transform:scaleY(.4)}40%{transform:scaleY(.4)}50%{transform:scaleY(.8)}90%{transform:scaleY(.8)}to{transform:scaleY(.4)}}@keyframes rai-sdk-barUp3{0%{transform:scaleY(.6)}to{transform:scaleY(.6)}}@keyframes rai-sdk-barUp4{0%{transform:scaleY(.8)}40%{transform:scaleY(.8)}50%{transform:scaleY(.4)}90%{transform:scaleY(.4)}to{transform:scaleY(.8)}}@keyframes rai-sdk-barUp5{0%{transform:scale(1)}40%{transform:scale(1)}50%{transform:scaleY(.2)}90%{transform:scaleY(.2)}to{transform:scale(1)}}#loading-square{width:75px;aspect-ratio:1;display:flex;color:var(--rai-accent, #000000);background:linear-gradient(currentColor 0 0) right / 51% 100%,linear-gradient(currentColor 0 0) bottom / 100% 51%;background-repeat:no-repeat;animation:l16-0 2s infinite linear .25s}#loading-square>div{width:50%;height:50%;background:currentColor;animation:l16-1 .5s infinite linear}@keyframes l16-0{0%,12.49%{transform:rotate(0)}12.5%,37.49%{transform:rotate(90deg)}37.5%,62.49%{transform:rotate(180deg)}62.5%,87.49%{transform:rotate(270deg)}87.5%,to{transform:rotate(360deg)}}@keyframes l16-1{0%{transform:perspective(80px) rotate3d(-1,-1,0,0)}80%,to{transform:perspective(80px) rotate3d(-1,-1,0,-180deg)}}#loading-circle{width:75px;aspect-ratio:1;display:grid;grid:50%/50%;color:var(--rai-accent, #000000);border-radius:50%;--_g: no-repeat linear-gradient(currentColor 0 0);background:var(--_g),var(--_g),var(--_g);background-size:50.1% 50.1%;animation:l9-0 1.5s infinite steps(1) alternate,l9-0-0 3s infinite steps(1) alternate}#loading-circle>div{background:var(--rai-text4, #6b7280);border-top-left-radius:100px;transform:perspective(150px) rotateY(0) rotateX(0);transform-origin:bottom right;animation:l9-1 1.5s infinite linear alternate}@keyframes l9-0{0%{background-position:0 100%,100% 100%,100% 0}33%{background-position:100% 100%,100% 100%,100% 0}66%{background-position:100% 0,100% 0,100% 0}}@keyframes l9-0-0{0%{transform:scaleX(1) rotate(0)}50%{transform:scaleX(-1) rotate(-90deg)}}@keyframes l9-1{16.5%{transform:perspective(150px) rotateX(-90deg) rotateY(0) rotateX(0);filter:grayscale(.8)}33%{transform:perspective(150px) rotateX(-180deg) rotateY(0) rotateX(0)}66%{transform:perspective(150px) rotateX(-180deg) rotateY(-180deg) rotateX(0)}to{transform:perspective(150px) rotateX(-180deg) rotateY(-180deg) rotateX(-180deg);filter:grayscale(.8)}}.rai-custom-error{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.tiptap strong.tw-font-bold,.tiptap b.tw-font-bold{font-weight:700}.tiptap em.tw-font-italic,.tiptap i.tw-font-italic{font-style:italic}.tiptap a.tiptap-rich-text-link{color:#3b82f6;text-decoration:underline;position:relative;display:inline-block;width:fit-content}.tiptap a.tiptap-rich-text-link:hover{color:#3b82f6cc;text-decoration:none}.tiptap a.tiptap-rich-text-link:not([title=""]):before{content:attr(title);position:absolute;top:-2rem;left:50%;transform:translate(-50%);white-space:nowrap;border-radius:.25rem;background-color:#000;padding:.25rem .5rem;color:#fff;opacity:0;transition:opacity .2s;pointer-events:none}.tiptap a.tiptap-rich-text-link:not([title=""]):hover:before{opacity:1}.tiptap p[style*="text-align: left"]{text-align:left}.tiptap p[style*="text-align: center"]{text-align:center}.tiptap p[style*="text-align: right"]{text-align:right}.tiptap p[style*="text-align: justify"]{text-align:justify}.tiptap u{text-decoration:underline}.tiptap.ProseMirror{background-color:transparent;height:fit-content!important;word-wrap:break-word;white-space:pre-wrap;white-space:break-spaces;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-feature-settings:"liga" 0;padding:0;width:100%;overflow-y:auto}.tiptap{line-height:1.6;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.tiptap p{margin:.5em 0}.tiptap p:first-child{margin-top:0}.tiptap p:last-child{margin-bottom:0}.tiptap img{max-width:100%;height:auto;display:block}.tiptap p[style*="text-align: left"] img{margin-left:0;margin-right:auto}.tiptap p[style*="text-align: center"] img{margin-left:auto;margin-right:auto}.tiptap p[style*="text-align: right"] img{margin-left:auto;margin-right:0}.rai-retry-btn{padding:8px 20px;border:none;border-radius:6px;background:var(--rai-accent, #000000);color:var(--rai-error-bg, #ffffff);font-size:14px;font-family:system-ui,-apple-system,sans-serif;cursor:pointer}.rai-retry-btn:hover{opacity:.85}';
10797
10888
  const DEFINED_ATTRS = /* @__PURE__ */ new Set([
10798
10889
  "community-id",
@@ -11104,11 +11195,18 @@ class BaseWidget extends HTMLElement {
11104
11195
  __publicField(this, "hasAttemptedInit", false);
11105
11196
  __publicField(this, "initGeneration", 0);
11106
11197
  __publicField(this, "lottieInstances", []);
11198
+ __publicField(this, "callbackRegistry", new WidgetCallbackRegistry());
11107
11199
  this.shadow = this.attachShadow({ mode: "closed" });
11108
11200
  }
11109
11201
  static get observedAttributes() {
11110
11202
  return ["embed-token", "data-embed-token"];
11111
11203
  }
11204
+ registerCallback(callbackName, callback) {
11205
+ this.callbackRegistry.registerCallback(callbackName, callback);
11206
+ }
11207
+ lockCallbacks() {
11208
+ this.callbackRegistry.lock();
11209
+ }
11112
11210
  connectedCallback() {
11113
11211
  this.config = readConfig(this, void 0);
11114
11212
  this.identitySignature = identitySignatureForConfig(this.config);
@@ -11195,6 +11293,13 @@ class BaseWidget extends HTMLElement {
11195
11293
  })
11196
11294
  );
11197
11295
  }
11296
+ /**
11297
+ * Reads host callback registrations at call time so framework integrations
11298
+ * can register a callback after the custom element is already mounted.
11299
+ */
11300
+ readRuntimeCallbacks() {
11301
+ return this.callbackRegistry.read();
11302
+ }
11198
11303
  // ── Rendering ─────────────────────────────────────────────────────────
11199
11304
  /**
11200
11305
  * Apply widget-defined CSS colors before first paint so the loader uses
@@ -11627,8 +11732,9 @@ class BaseWidget extends HTMLElement {
11627
11732
  () => this.scheduleRefresh(),
11628
11733
  () => this.logoutAndClear(),
11629
11734
  () => this.hideLoader(),
11630
- (type, detail) => this.emit(type, detail)
11735
+ (type, detail) => this.emit(type, detail),
11631
11736
  // #1
11737
+ () => this.readRuntimeCallbacks()
11632
11738
  );
11633
11739
  }
11634
11740
  // ── Bundle mode (no-iframe) ──────────────────────────────────────────
@@ -11698,7 +11804,15 @@ class BaseWidget extends HTMLElement {
11698
11804
  // post. Mirrors the iframe behavior, where `isOpenWidget` is only
11699
11805
  // injected by SSR for the explicit `/open-widget` route.
11700
11806
  isOpenWidget: !this.state.accessToken,
11701
- defaultColorSchema: this.config.theme === "dark" ? "dark" : "light"
11807
+ defaultColorSchema: this.config.theme === "dark" ? "dark" : "light",
11808
+ requestHostCallback: async (callbackName, payload) => {
11809
+ if (this.config.widgetType !== "store" && this.config.widgetType !== "custom" || callbackName !== STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME || payload.scope !== STORE_CALLBACK_FIELD_OPTIONS_SCOPE) {
11810
+ throw new Error("Host callback is only supported for store widgets");
11811
+ }
11812
+ const callback = this.readRuntimeCallbacks()[callbackName];
11813
+ if (!callback) throw new Error("Host callback is not registered");
11814
+ return callback(payload);
11815
+ }
11702
11816
  });
11703
11817
  this.emit("rai-mounted");
11704
11818
  } catch (err) {
@@ -11886,7 +12000,7 @@ class CustomWidget extends BaseWidget {
11886
12000
  }
11887
12001
  }
11888
12002
  }
11889
- console.log(`[rai-widget] v${"1.4.2"}`);
12003
+ console.log(`[rai-widget] v${"1.5.0"}`);
11890
12004
  class StoreWidgetCompat extends StoreWidget {
11891
12005
  }
11892
12006
  const WIDGET_REGISTRY = [
@@ -11950,7 +12064,7 @@ function exposePublicApi() {
11950
12064
  })();
11951
12065
  const widget = container == null ? void 0 : container.querySelector(ALL_WIDGET_SELECTOR);
11952
12066
  window.ReturningAIWidget = {
11953
- version: "1.4.2",
12067
+ version: "1.5.0",
11954
12068
  reload: () => (widget == null ? void 0 : widget.reload()) ?? Promise.resolve(),
11955
12069
  logout: () => (widget == null ? void 0 : widget.logoutPublic()) ?? Promise.resolve(),
11956
12070
  isAuthenticated: () => (widget == null ? void 0 : widget.isAuthenticated()) ?? false,
@@ -11968,6 +12082,9 @@ export {
11968
12082
  CustomWidget,
11969
12083
  MilestoneWidget,
11970
12084
  ReferralWidget,
12085
+ STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME,
12086
+ STORE_CALLBACK_FIELD_OPTIONS_SCOPE,
12087
+ STORE_CALLBACK_FIELD_OPTIONS_TIMEOUT_MS,
11971
12088
  SocialWidget,
11972
12089
  StoreWidget
11973
12090
  };
@@ -1,4 +1,4 @@
1
- import type { WidgetConfig } from "./types";
1
+ import type { ReturningAIWidgetCallback, WidgetConfig } from "./types";
2
2
  export declare function readConfig(el: Element, existingId?: string): WidgetConfig;
3
3
  export declare abstract class BaseWidget extends HTMLElement {
4
4
  static get observedAttributes(): string[];
@@ -16,7 +16,10 @@ export declare abstract class BaseWidget extends HTMLElement {
16
16
  private hasAttemptedInit;
17
17
  private initGeneration;
18
18
  private lottieInstances;
19
+ private callbackRegistry;
19
20
  constructor();
21
+ registerCallback(callbackName: string, callback: ReturningAIWidgetCallback): void;
22
+ lockCallbacks(): void;
20
23
  protected abstract buildWidgetUrl(config: WidgetConfig): string;
21
24
  connectedCallback(): void;
22
25
  disconnectedCallback(): void;
@@ -24,6 +27,11 @@ export declare abstract class BaseWidget extends HTMLElement {
24
27
  private setupIdentityAttributeObserver;
25
28
  private handleIdentityConfigChange;
26
29
  private emit;
30
+ /**
31
+ * Reads host callback registrations at call time so framework integrations
32
+ * can register a callback after the custom element is already mounted.
33
+ */
34
+ private readRuntimeCallbacks;
27
35
  /**
28
36
  * Apply widget-defined CSS colors before first paint so the loader uses
29
37
  * the community's actual theme — not generic light/dark — from frame 1.
@@ -0,0 +1,15 @@
1
+ import type { ReturningAIWidgetCallback, ReturningAIWidgetCallbacks } from '../types';
2
+ /**
3
+ * Owns callback registration for a single widget element.
4
+ *
5
+ * Callback registration is intentionally per element so pages with multiple
6
+ * widgets can lock each widget's callback behavior independently.
7
+ */
8
+ export declare class WidgetCallbackRegistry {
9
+ private registeredCallbacks;
10
+ private locked;
11
+ get isLocked(): boolean;
12
+ registerCallback(callbackName: string, callback: ReturningAIWidgetCallback): void;
13
+ lock(): void;
14
+ read(): ReturningAIWidgetCallbacks;
15
+ }
@@ -1,3 +1,3 @@
1
- import type { WidgetConfig, WidgetState } from '../types';
1
+ import type { ReturningAIWidgetCallbacks, WidgetConfig, WidgetState } from '../types';
2
2
  export declare function sendTokenToWidget(config: WidgetConfig, state: WidgetState, iframe: HTMLIFrameElement): void;
3
- export declare function setupMessageListener(config: WidgetConfig, state: WidgetState, _shadow: ShadowRoot, iframe: HTMLIFrameElement, onRefreshScheduled?: () => void, onLogout?: () => Promise<void>, hideLoader?: () => void, emit?: (type: string, detail?: Record<string, unknown>) => void): () => void;
3
+ export declare function setupMessageListener(config: WidgetConfig, state: WidgetState, _shadow: ShadowRoot, iframe: HTMLIFrameElement, onRefreshScheduled?: () => void, onLogout?: () => Promise<void>, hideLoader?: () => void, emit?: (type: string, detail?: Record<string, unknown>) => void, getCallbacks?: () => ReturningAIWidgetCallbacks): () => void;
@@ -6,14 +6,18 @@ import { CurrencyWidget } from './CurrencyWidget';
6
6
  import { ReferralWidget } from './ReferralWidget';
7
7
  import { CustomWidget } from './CustomWidget';
8
8
  declare global {
9
+ interface ReturningAIWidgetGlobal {
10
+ version?: string;
11
+ reload?: () => Promise<void>;
12
+ logout?: () => Promise<void>;
13
+ isAuthenticated?: () => boolean;
14
+ getTokenInfo?: () => object;
15
+ }
9
16
  interface Window {
10
- ReturningAIWidget: {
11
- version: string;
12
- reload: () => Promise<void>;
13
- logout: () => Promise<void>;
14
- isAuthenticated: () => boolean;
15
- getTokenInfo: () => object;
16
- };
17
+ ReturningAIWidget?: ReturningAIWidgetGlobal;
17
18
  }
18
19
  }
19
20
  export { StoreWidget, ChannelWidget, MilestoneWidget, SocialWidget, CurrencyWidget, ReferralWidget, CustomWidget };
21
+ export type { ReturningAIStoreCallbackFieldOptionsCallback, ReturningAIWidgetCallback, ReturningAIWidgetCallbackRegistration, ReturningAIWidgetActionMessage, ReturningAIWidgetActionResultMessage, ReturningAIWidgetCallbacks, StoreCallbackFieldOptionsContext, StoreCallbackFieldOptionsField, StoreCallbackFieldOptionsFieldType, StoreCallbackFieldOptionsPayload, StoreCallbackFieldOptionsResult, } from './types';
22
+ export { STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME, STORE_CALLBACK_FIELD_OPTIONS_SCOPE, STORE_CALLBACK_FIELD_OPTIONS_TIMEOUT_MS, } from './types';
23
+ export type {} from './jsx';
@@ -0,0 +1,55 @@
1
+ // Shared attribute shape for all widget elements
2
+ interface RaiWidgetAttributes {
3
+ 'community-id': string
4
+ 'channel-id'?: string
5
+ 'widget-id'?: string // deprecated — use 'community-id'
6
+ 'data-email'?: string
7
+ 'widget-type'?: 'store' | 'channel' | 'milestone' | 'social' | 'currency-view' | 'referral-conditions' | 'custom'
8
+ theme?: 'light' | 'dark'
9
+ width?: string
10
+ height?: string
11
+ 'api-url'?: string
12
+ 'widget-url'?: string
13
+ 'bundle-url'?: string
14
+ 'domain-key'?: string
15
+ 'v2-api-url'?: string
16
+ 'embed-token'?: string
17
+ 'auth-url'?: string
18
+ 'auto-refresh'?: string
19
+ 'data-container'?: string
20
+ debug?: string
21
+ class?: string
22
+ style?: string
23
+ }
24
+
25
+ // ── React ──────────────────────────────────────────────────────────────────
26
+ declare namespace React {
27
+ namespace JSX {
28
+ interface IntrinsicElements {
29
+ 'rai-store-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
30
+ 'rai-channel-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
31
+ 'rai-milestone-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
32
+ 'rai-social-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
33
+ 'rai-currency-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
34
+ 'rai-referral-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
35
+ 'rai-custom-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes
36
+ 'rai-widget': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & RaiWidgetAttributes // deprecated
37
+ }
38
+ }
39
+ }
40
+
41
+ // ── Vue 3 (Volar / vue-tsc) ────────────────────────────────────────────────
42
+ declare module '@vue/runtime-core' {
43
+ interface GlobalComponents {
44
+ RaiStoreWidget: { $props: RaiWidgetAttributes }
45
+ RaiChannelWidget: { $props: RaiWidgetAttributes }
46
+ RaiMilestoneWidget: { $props: RaiWidgetAttributes }
47
+ RaiSocialWidget: { $props: RaiWidgetAttributes }
48
+ RaiCurrencyWidget: { $props: RaiWidgetAttributes }
49
+ RaiReferralWidget: { $props: RaiWidgetAttributes }
50
+ RaiCustomWidget: { $props: RaiWidgetAttributes }
51
+ RaiWidget: { $props: RaiWidgetAttributes } // deprecated
52
+ }
53
+ }
54
+
55
+ export {}
@@ -1,3 +1,59 @@
1
+ export declare const STORE_CALLBACK_FIELD_OPTIONS_SCOPE: "store.callback_field_options";
2
+ export declare const STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME: "callbackFieldOptions";
3
+ export declare const STORE_CALLBACK_FIELD_OPTIONS_TIMEOUT_MS = 15000;
4
+ export type StoreCallbackFieldOptionsFieldType = 'single-select';
5
+ export interface StoreCallbackFieldOptionsField {
6
+ id: string;
7
+ name: string;
8
+ type: StoreCallbackFieldOptionsFieldType;
9
+ }
10
+ export interface StoreCallbackFieldOptionsContext {
11
+ productId: string;
12
+ productName?: string;
13
+ fields: StoreCallbackFieldOptionsField[];
14
+ }
15
+ export interface StoreCallbackFieldOptionsPayload {
16
+ scope: typeof STORE_CALLBACK_FIELD_OPTIONS_SCOPE;
17
+ callbackName: typeof STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME;
18
+ context: StoreCallbackFieldOptionsContext;
19
+ }
20
+ export interface StoreCallbackFieldOptionsResult {
21
+ fieldOptions: Record<string, string[]>;
22
+ signature?: string;
23
+ }
24
+ export type ReturningAIWidgetCallback<TPayload = any, TResult = any> = (payload: TPayload) => Promise<TResult> | TResult;
25
+ export type ReturningAIStoreCallbackFieldOptionsCallback = (payload: StoreCallbackFieldOptionsPayload) => Promise<StoreCallbackFieldOptionsResult> | StoreCallbackFieldOptionsResult;
26
+ export type ReturningAIWidgetCallbacks = {
27
+ 'callbackFieldOptions'?: ReturningAIStoreCallbackFieldOptionsCallback;
28
+ [callbackName: string]: ReturningAIWidgetCallback | undefined;
29
+ };
30
+ export interface ReturningAIWidgetCallbackRegistration {
31
+ registerCallback(callbackName: typeof STORE_CALLBACK_FIELD_OPTIONS_CALLBACK_NAME, callback: ReturningAIStoreCallbackFieldOptionsCallback): void;
32
+ registerCallback(callbackName: string, callback: ReturningAIWidgetCallback): void;
33
+ lockCallbacks(): void;
34
+ }
35
+ export interface ReturningAIWidgetActionMessage {
36
+ type: 'RETURNINGAI_WIDGET_ACTION';
37
+ requestId: string;
38
+ widgetType: 'store';
39
+ action: 'store:host-callback';
40
+ containerId?: string;
41
+ widgetId?: string;
42
+ callbackName: string;
43
+ timeoutMs?: number;
44
+ payload: StoreCallbackFieldOptionsPayload;
45
+ }
46
+ export interface ReturningAIWidgetActionResultMessage {
47
+ type: 'RETURNINGAI_WIDGET_ACTION_RESULT';
48
+ requestId: string;
49
+ action: 'store:host-callback';
50
+ ok: boolean;
51
+ status: 'success' | 'failed';
52
+ value?: StoreCallbackFieldOptionsResult;
53
+ error?: {
54
+ message: string;
55
+ };
56
+ }
1
57
  export interface WidgetConfig {
2
58
  /** The community this widget belongs to. Maps to the `community-id` HTML attribute. */
3
59
  communityId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@returningai/widget-sdk",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "Shadow DOM isolated widget SDK for ReturningAI",
5
5
  "main": "dist/rai-widget.iife.js",
6
6
  "module": "dist/rai-widget.js",
@@ -21,7 +21,9 @@
21
21
  "dev": "vite",
22
22
  "build": "vite build",
23
23
  "build:min": "vite build --mode production",
24
- "types": "tsc --emitDeclarationOnly --outDir dist/types",
24
+ "types": "tsc --emitDeclarationOnly --outDir dist/types && cp src/jsx.d.ts dist/types/jsx.d.ts",
25
+ "test": "npm run test:host-callback",
26
+ "test:host-callback": "rm -rf test/.tmp && tsc -p test/tsconfig.json && node test/.tmp/test/postmessage-host-callback.test.js",
25
27
  "prepublishOnly": "npm run build:min && npm run types"
26
28
  },
27
29
  "devDependencies": {