@salla.sa/embedded-sdk 0.2.2 → 0.2.4

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.
@@ -4,6 +4,22 @@
4
4
  */
5
5
  declare type ActionClickCallback = (value: string) => void;
6
6
 
7
+ /**
8
+ * Addon information returned by getAddons.
9
+ */
10
+ declare interface AddonInfo {
11
+ /** Unique slug identifier */
12
+ slug: string;
13
+ /** Internal product ID */
14
+ product_id: number;
15
+ /** Internal price ID */
16
+ product_price_id: number;
17
+ /** Display name */
18
+ name: string;
19
+ /** Price amount */
20
+ price: number;
21
+ }
22
+
7
23
  /**
8
24
  * Auth module interface.
9
25
  */
@@ -36,6 +52,30 @@ export declare interface AuthModule {
36
52
  introspect(options?: IntrospectOptions): Promise<IntrospectResponse>;
37
53
  }
38
54
 
55
+ /**
56
+ * Optional configuration for checkout creation.
57
+ */
58
+ export declare interface CheckoutCreateConfig {
59
+ /** Optional context to persist across 3DS redirects.
60
+ * Stored on the host side and returned in onResult after redirect. */
61
+ context?: unknown;
62
+ }
63
+
64
+ /**
65
+ * @fileoverview Type definitions for the checkout module.
66
+ */
67
+ /**
68
+ * Checkout item with type information.
69
+ */
70
+ export declare interface CheckoutItem {
71
+ /** Item type */
72
+ type: "addon";
73
+ /** Item slug identifier */
74
+ slug: string;
75
+ /** Quantity (default: 1) */
76
+ quantity?: number;
77
+ }
78
+
39
79
  /**
40
80
  * Checkout module interface.
41
81
  */
@@ -43,36 +83,94 @@ export declare interface CheckoutModule {
43
83
  /**
44
84
  * Create/initiate a checkout flow.
45
85
  *
46
- * @param payload - Checkout data
86
+ * Accepts a single item or an array of items for multi-item checkout.
87
+ *
88
+ * @param input - Single checkout item or array of items
89
+ * @param config - Optional configuration
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * // Single item
94
+ * embedded.checkout.create(
95
+ * { type: "addon", slug: "premium-analytics", quantity: 1 },
96
+ * { context: { route: "/pricing", plan: "premium" } },
97
+ * );
98
+ *
99
+ * // Multiple items
100
+ * embedded.checkout.create([
101
+ * { type: "addon", slug: "premium-analytics", quantity: 2 },
102
+ * { type: "addon", slug: "extra-storage" },
103
+ * ]);
104
+ * ```
105
+ */
106
+ create(input: CheckoutItem | CheckoutItem[], config?: CheckoutCreateConfig): void;
107
+ /**
108
+ * Subscribe to checkout results.
109
+ * Context from create() is returned here after 3DS redirect.
110
+ *
111
+ * @param callback - Function called when checkout completes
112
+ * @returns Unsubscribe function
47
113
  *
48
114
  * @example
49
115
  * ```typescript
50
- * embedded.checkout.create({
51
- * items: [{ productId: 123, quantity: 1 }],
52
- * amount: 99.99,
53
- * currency: 'SAR'
116
+ * const unsubscribe = embedded.checkout.onResult((result) => {
117
+ * if (result.context?.route) {
118
+ * router.push(result.context.route);
119
+ * }
120
+ * if (result.success) {
121
+ * console.log("Order:", result.order_id);
122
+ * }
54
123
  * });
55
124
  * ```
56
125
  */
57
- create(payload: CheckoutPayload): void;
126
+ onResult(callback: CheckoutResultCallback): () => void;
127
+ /**
128
+ * Get available addons for the current app.
129
+ * Results are cached on the host side (30 min TTL).
130
+ *
131
+ * @returns Promise resolving to addon list
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * const result = await embedded.checkout.getAddons();
136
+ * if (result.success) {
137
+ * console.log('Available addons:', result.addons);
138
+ * } else {
139
+ * console.error('Error:', result.error);
140
+ * }
141
+ * ```
142
+ */
143
+ getAddons(): Promise<GetAddonsResult>;
144
+ /**
145
+ * Clean up module resources (message listeners, subscriptions).
146
+ * Called automatically by EmbeddedApp.destroy().
147
+ */
148
+ destroy(): void;
58
149
  }
59
150
 
60
151
  /**
61
- * @fileoverview Type definitions for the checkout module.
62
- */
152
+ * Checkout result returned after payment.
153
+ */
154
+ export declare interface CheckoutResult {
155
+ /** Whether the checkout was successful */
156
+ success: boolean;
157
+ /** Order ID if successful */
158
+ order_id?: string;
159
+ /** Payment status */
160
+ status: "paid" | "pending" | "failed" | "cancelled" | "success";
161
+ /** Error details if failed */
162
+ error?: {
163
+ code: string;
164
+ message: string;
165
+ };
166
+ /** Developer context passed to create(), restored after 3DS redirect */
167
+ context?: unknown;
168
+ }
169
+
63
170
  /**
64
- * Checkout payload structure.
171
+ * Callback for checkout result.
65
172
  */
66
- export declare interface CheckoutPayload {
67
- /** Cart items or product IDs */
68
- items?: unknown[];
69
- /** Total amount */
70
- amount?: number;
71
- /** Currency code */
72
- currency?: string;
73
- /** Additional checkout data */
74
- [key: string]: unknown;
75
- }
173
+ export declare type CheckoutResultCallback = (result: CheckoutResult) => void;
76
174
 
77
175
  /**
78
176
  * Confirm dialog options.
@@ -110,14 +208,17 @@ export declare const embedded: EmbeddedApp;
110
208
  * Provides the primary interface for third-party apps to communicate with the Salla host.
111
209
  */
112
210
  export declare class EmbeddedApp {
113
- private config;
114
- private state;
115
- private themeCallbacks;
116
- private initCallbacks;
211
+ private initialized;
212
+ private initializing;
213
+ private debugMode;
117
214
  private appReady;
215
+ private layout;
216
+ private themeSubscription;
217
+ private initSubscription;
218
+ private postInitHooks;
118
219
  /** Auth module for token management */
119
220
  auth: AuthModule;
120
- /** Page module for navigation and resize */
221
+ /** Page module for navigation */
121
222
  page: PageModule;
122
223
  /** Nav module for primary actions */
123
224
  nav: NavModule;
@@ -127,113 +228,46 @@ export declare class EmbeddedApp {
127
228
  checkout: CheckoutModule;
128
229
  constructor();
129
230
  /**
130
- * Get current SDK state (layout info only, no token).
231
+ * Register a hook to run after successful init handshake.
232
+ * Used by modules to process context data.
131
233
  */
132
- getState(): Readonly<EmbeddedState>;
234
+ private registerPostInitHook;
133
235
  /**
134
- * Get current SDK configuration.
236
+ * Set up core event listeners.
135
237
  */
136
- getConfig(): Readonly<EmbeddedConfig>;
238
+ private setupListeners;
137
239
  /**
138
- * Check if SDK is initialized.
240
+ * Get current SDK state.
139
241
  */
140
- isReady(): boolean;
141
- /**
142
- * Unified internal logging function that supports all console log types.
143
- *
144
- * @param type - Log type (log, warn, error, info, debug)
145
- * @param args - Arguments to log
146
- */
147
- private internalLog;
148
- /**
149
- * Set up listener for theme changes from host.
150
- */
151
- private setupThemeListener;
242
+ getState(): Readonly<EmbeddedState>;
152
243
  /**
153
- * Set up listeners for async response events from host.
244
+ * Check if SDK is initialized and ready.
154
245
  */
155
- private setupResponseListeners;
246
+ isReady(): boolean;
156
247
  /**
157
248
  * Subscribe to theme changes.
158
- *
159
- * @param callback - Function called when theme changes
160
- * @returns Unsubscribe function
161
- *
162
- * @example
163
- * ```typescript
164
- * const unsubscribe = embedded.onThemeChange((theme) => {
165
- * document.body.classList.toggle('dark-mode', theme === 'dark');
166
- * });
167
- * ```
168
249
  */
169
- onThemeChange(callback: ThemeChangeCallback): () => void;
250
+ onThemeChange(callback: (theme: "light" | "dark") => void): () => void;
170
251
  /**
171
- * Subscribe to init completion. If called after init, fires immediately.
172
- *
173
- * @param callback - Function called when init completes
174
- * @returns Unsubscribe function
175
- *
176
- * @example
177
- * ```typescript
178
- * embedded.onInit((state) => {
179
- * console.log('SDK initialized with layout:', state.layout);
180
- * });
181
- * ```
252
+ * Subscribe to init completion. Fires immediately if already initialized.
182
253
  */
183
254
  onInit(callback: InitCallback): () => void;
184
255
  /**
185
256
  * Signal that the app is fully loaded and ready.
186
- * This removes the host's loading overlay.
187
- *
188
- * @example
189
- * ```typescript
190
- * // After verifying token and loading initial data
191
- * embedded.ready();
192
- * ```
193
257
  */
194
258
  ready(): void;
195
259
  /**
196
260
  * Initialize the SDK and establish connection with the host.
197
- *
198
- * @param options - Initialization options (optional)
199
- * @returns Promise that resolves with layout info
200
- *
201
- * @example
202
- * ```typescript
203
- * const { layout } = await embedded.init({ debug: true });
204
- * console.log('Theme:', layout.theme);
205
- * console.log('Locale:', layout.locale);
206
- * ```
207
261
  */
208
262
  init(options?: InitOptions): Promise<{
209
263
  layout: LayoutInfo;
210
264
  }>;
211
- /**
212
- * Wait for initialization to complete.
213
- * Useful when multiple calls to init() might happen.
214
- */
215
- private waitForInit;
216
265
  /**
217
266
  * Destroy the SDK instance and clean up resources.
218
- * Sends a destroy event to the host to navigate away from the embedded view.
219
- *
220
- * @example
221
- * ```typescript
222
- * // On auth failure or when app needs to exit
223
- * embedded.destroy();
224
- * ```
225
267
  */
226
268
  destroy(): void;
227
269
  }
228
270
 
229
- /**
230
- * Internal configuration after initialization.
231
- */
232
- declare interface EmbeddedConfig {
233
- debug: boolean;
234
- initialized: boolean;
235
- }
236
-
237
271
  /**
238
272
  * Current state of the embedded SDK.
239
273
  */
@@ -257,6 +291,21 @@ export declare interface ExtendedAction {
257
291
  disabled?: boolean;
258
292
  }
259
293
 
294
+ /**
295
+ * Result of getAddons call.
296
+ */
297
+ declare interface GetAddonsResult {
298
+ /** Whether the fetch was successful */
299
+ success: boolean;
300
+ /** List of available addons (if success) */
301
+ addons?: AddonInfo[];
302
+ /** Error details (if failed) */
303
+ error?: {
304
+ code: string;
305
+ message: string;
306
+ };
307
+ }
308
+
260
309
  /**
261
310
  * Get the singleton EmbeddedApp instance.
262
311
  */
@@ -484,28 +533,6 @@ export declare interface PageModule {
484
533
  * ```
485
534
  */
486
535
  navTo(path: string, options?: NavToOptions): void;
487
- /**
488
- * Update the iframe height.
489
- *
490
- * @param height - Height in pixels
491
- *
492
- * @example
493
- * ```typescript
494
- * embedded.page.resize(800);
495
- * ```
496
- */
497
- resize(height: number): void;
498
- /**
499
- * Auto-resize iframe to content height.
500
- * Measures document.documentElement.scrollHeight and sends resize.
501
- *
502
- * @example
503
- * ```typescript
504
- * // After content changes
505
- * embedded.page.autoResize();
506
- * ```
507
- */
508
- autoResize(): void;
509
536
  /**
510
537
  * Set the page title in the host document.
511
538
  *
@@ -517,6 +544,12 @@ export declare interface PageModule {
517
544
  * ```
518
545
  */
519
546
  setTitle(title: string): void;
547
+ /** @deprecated No effect - host manages iframe height automatically. */
548
+ resize(height: number): void;
549
+ /** @deprecated No effect - host manages iframe height automatically. */
550
+ autoResize(): void;
551
+ /** @deprecated No effect - host manages iframe height automatically. */
552
+ stopAutoResize(): void;
520
553
  }
521
554
 
522
555
  /**
@@ -538,23 +571,15 @@ export declare interface PrimaryActionConfig {
538
571
  }
539
572
 
540
573
  /**
541
- * Reset the singleton (mainly for testing).
574
+ * Reset the singleton (for testing).
542
575
  */
543
576
  export declare function resetEmbeddedApp(): void;
544
577
 
545
- /**
546
- * @fileoverview Core type definitions for the Embedded SDK.
547
- */
548
578
  /**
549
579
  * Theme type for the SDK.
550
580
  */
551
581
  declare type Theme = "light" | "dark";
552
582
 
553
- /**
554
- * Theme change callback type.
555
- */
556
- declare type ThemeChangeCallback = (theme: "light" | "dark") => void;
557
-
558
583
  /**
559
584
  * Toast notification options.
560
585
  */
package/dist/umd/index.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(l,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(l=typeof globalThis<"u"?globalThis:l||self,s(l.SallaEmbeddedSDK={}))})(this,function(l){"use strict";const s="embedded::",E={INIT:`${s}iframe.ready`,RESIZE:`${s}iframe.resize`,READY:`${s}ready`,DESTROY:`${s}destroy`},O={PROVIDE:`${s}context.provide`,THEME_CHANGE:`${s}theme.change`},h={LOADING:`${s}ui.loading`,TOAST:`${s}ui.toast`,CONFIRM:`${s}ui.confirm`,CONFIRM_RESPONSE:`${s}ui.confirm.response`},H={},_={REFRESH:`${s}auth.refresh`},p={NAVIGATE:`${s}page.navigate`,REDIRECT:`${s}page.redirect`,SET_TITLE:`${s}page.setTitle`},v={SET_ACTION:`${s}nav.setAction`,CLEAR_ACTION:`${s}nav.clearAction`,ACTION_CLICK:`${s}nav.actionClick`},D={CREATE:`${s}checkout.create`},I=H.version,K=1e4,G=["localhost","merchants.workers.dev","s.salla.sa",".salla.group",".salla.sa"];let w={showVersion:!0,debug:!1};function X(e){w={...w,...e}}function x(e){return`%c${e}`}function M(e,t="#fff"){return`background-color: ${e}; color: ${t}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`}function T(e,...t){if(e==="debug"&&!w.debug)return;const r=[],i=[];r.push(x("EmbeddedSDK")),i.push(M("#10b981","#fff")),w.showVersion&&(r.push(x(`v${I}`)),i.push(M("#6b7280","#fff")));const n=r.join("").trim();(console[e]||console.log)(n,...i,...t)}const u={log:(...e)=>{T("log",...e)},warn:(...e)=>{T("warn",...e)},error:(...e)=>{T("error",...e)},info:(...e)=>{T("info",...e)},debug:(...e)=>{T("debug",...e)}};function Y(e){try{const r=new URL(e).hostname;return G.some(i=>i.startsWith(".")?r.endsWith(i)||r===i.slice(1):r===i||r.startsWith(`${i}:`))}catch{return!1}}function W(){return typeof window>"u"||window.parent===window?null:window.parent}function o(e,t,r="*",i,n){const a=W();if(!a){u.warn("Not running in an iframe, cannot post to host");return}const d={event:e,payload:t||{},timestamp:Date.now(),source:"embedded-app",...i&&{requestId:i},metadata:{version:I}};a.postMessage(d,r)}const g=new Map;let A=!1;function U(e){if(process.env.NODE_ENV==="production"&&!Y(e.origin))return;const t=e.data;if(!t||typeof t.event!="string"||!t.payload||typeof t.timestamp!="number"||!t.source){u.warn("Invalid message structure received:",t);return}const r=g.get(t.event);r&&r.forEach(n=>{try{n(t)}catch(a){u.error("Error in message handler:",a)}});const i=g.get("*");i&&i.forEach(n=>{try{n(t)}catch(a){u.error("Error in wildcard handler:",a)}})}function B(){A||typeof window>"u"||(window.addEventListener("message",U),A=!0)}function R(e,t){B(),g.has(e)||g.set(e,new Set);const r=g.get(e);return r.add(t),()=>{r.delete(t),r.size===0&&g.delete(e)}}function Z(e,t=K){return new Promise((r,i)=>{const n=setTimeout(()=>{a(),i(new Error(`[EmbeddedSDK] Timeout waiting for "${e}" message`))},t),a=R(e,d=>{clearTimeout(n),a(),r(d)})})}function J(){g.clear(),A&&typeof window<"u"&&(window.removeEventListener("message",U),A=!1)}function Q(){return typeof window>"u"?!1:window.parent!==window}const m=new Map,ee=3e4;function te(){const e=Date.now(),t=Math.random().toString(36).slice(2,9);return`req_${e}_${t}`}function re(e,t={},r=ee){const i=te();return new Promise((n,a)=>{const d=setTimeout(()=>{m.get(i)&&(m.delete(i),a(new Error(`[EmbeddedSDK] Request "${e}" timed out after ${r}ms`)))},r);m.set(i,{resolve:n,reject:a,timeout:d,event:e}),o(e,t,"*",i)})}function ie(e,t,r){const i=m.get(e);if(!i){u.warn(`Received response for unknown request: ${e}`);return}clearTimeout(i.timeout),m.delete(e),i.resolve(t)}function ne(e="SDK cleanup"){m.forEach((t,r)=>{clearTimeout(t.timeout),t.reject(new Error(`[EmbeddedSDK] Request ${r} cancelled: ${e}`))}),m.clear()}const ae="https://api.salla.dev";class y extends Error{constructor(t,r,i){super(t),this.status=r,this.response=i,this.name="ApiError"}}async function se(e,t={}){const{method:r="GET",headers:i={},body:n,timeout:a=3e4}=t,d=`${ae}${e}`,$=new AbortController,j=setTimeout(()=>{$.abort()},a);try{const c=await fetch(d,{method:r,headers:{"Content-Type":"application/json",...i},body:n?JSON.stringify(n):void 0,signal:$.signal});clearTimeout(j);let S;const k=c.headers.get("content-type");if(k!=null&&k.includes("application/json")?S=await c.json():S=await c.text(),!c.ok)throw new y(`API request failed: ${c.statusText}`,c.status,S);return S}catch(c){throw clearTimeout(j),c instanceof y?c:c instanceof Error?c.name==="AbortError"?new y(`Request timeout after ${a}ms`):new y(`Request failed: ${c.message}`):new y("Unknown error occurred")}}function C(e){return{isVerified:!1,isError:!0,error:e,data:null}}async function oe(e){const{token:t,appId:r,refreshOnError:i=!0}=e;if(!t){const n="Token is required. Provide it as a parameter or in URL as ?token=XXX";return u.error("Error in introspect:",n),C(n)}if(!r){const n="App ID is required. Provide it as a parameter or in URL as ?app_id=XXX";return u.error("Error in introspect:",n),C(n)}try{const n=await se("/exchange-authority/v1/introspect",{method:"POST",headers:{"S-Source":r,"Content-Type":"application/json"},body:{env:"prod",token:t,iss:"merchant-dashboard",subject:"embedded-page"}}),a=n.success;return{isVerified:a,isError:!a,error:a?void 0:"API request failed",data:a?n.data:null}}catch(n){i&&(L().ui.toast.error((n==null?void 0:n.toString())??"Introspect error"),o(_.REFRESH,{})),u.error("Error in introspect:",n);const a=n instanceof Error?n.message:n;return C(a)}}function ue(e){return{getToken(){return new URLSearchParams(window.location.search).get("token")},getAppId(){return new URLSearchParams(window.location.search).get("app_id")},refresh(){o(_.REFRESH,{})},async introspect(t={}){const r=t.token??this.getToken()??"",i=t.appId??this.getAppId()??"";return oe({token:r,appId:i,refreshOnError:t.refreshOnError})}}}const q=["success","error","warning","info"];function ce(e){const t=[];return e.type===void 0||e.type===null?t.push("Toast type is required"):(typeof e.type!="string"||!q.includes(e.type))&&t.push(`Invalid toast type "${e.type}". Expected: ${q.join(" | ")}`),e.message===void 0||e.message===null?t.push("Toast message is required"):typeof e.message!="string"?t.push("Toast message must be a string"):e.message.trim()===""&&t.push("Toast message cannot be empty"),e.duration!==void 0&&e.duration!==null&&(typeof e.duration!="number"?t.push("Toast duration must be a number"):e.duration<0&&t.push("Toast duration cannot be negative")),{valid:t.length===0,errors:t}}function le(e){const t=[];return typeof e!="object"||e===null?(t.push("Checkout payload must be an object"),{valid:!1,errors:t}):(e.amount!==void 0&&e.amount!==null&&(typeof e.amount!="number"?t.push("Checkout amount must be a number"):e.amount<0&&t.push("Checkout amount cannot be negative")),e.currency!==void 0&&e.currency!==null&&(typeof e.currency!="string"?t.push("Checkout currency must be a string"):e.currency.trim()===""&&t.push("Checkout currency cannot be empty")),e.items!==void 0&&e.items!==null&&(Array.isArray(e.items)||t.push("Checkout items must be an array")),{valid:t.length===0,errors:t})}function de(e){const t=[];return e.path===void 0||e.path===null?t.push("Navigation path is required"):typeof e.path!="string"?t.push("Navigation path must be a string"):e.path.trim()===""&&t.push("Navigation path cannot be empty"),e.replace!==void 0&&typeof e.replace!="boolean"&&t.push("Navigation replace option must be a boolean"),{valid:t.length===0,errors:t}}function fe(e){const t=[];if(e.url===void 0||e.url===null)t.push("Redirect URL is required");else if(typeof e.url!="string")t.push("Redirect URL must be a string");else if(e.url.trim()==="")t.push("Redirect URL cannot be empty");else try{new URL(e.url)}catch{t.push(`Invalid redirect URL: "${e.url}"`)}return{valid:t.length===0,errors:t}}function he(e){const t=[];return e.title?typeof e.title!="string"&&t.push("Nav action title must be a string"):t.push("Nav action title is required"),e.value?typeof e.value!="string"&&t.push("Nav action value must be a string"):t.push("Nav action value is required"),e.subTitle!==void 0&&e.subTitle!==null&&typeof e.subTitle!="string"&&t.push("Nav action subTitle must be a string"),e.icon!==void 0&&e.icon!==null&&typeof e.icon!="string"&&t.push("Nav action icon must be a string"),e.disabled!==void 0&&e.disabled!==null&&typeof e.disabled!="boolean"&&t.push("Nav action disabled must be a boolean"),e.extendedActions!==void 0&&e.extendedActions!==null&&(Array.isArray(e.extendedActions)?e.extendedActions.forEach((r,i)=>{if(typeof r!="object"||r===null){t.push(`Extended action at index ${i} must be an object`);return}const n=r;(!n.title||typeof n.title!="string")&&t.push(`Extended action at index ${i} is missing required "title" property`),(!n.value||typeof n.value!="string")&&t.push(`Extended action at index ${i} is missing required "value" property`),n.subTitle!==void 0&&typeof n.subTitle!="string"&&t.push(`Extended action at index ${i} subTitle must be a string`),n.icon!==void 0&&typeof n.icon!="string"&&t.push(`Extended action at index ${i} icon must be a string`),n.disabled!==void 0&&typeof n.disabled!="boolean"&&t.push(`Extended action at index ${i} disabled must be a boolean`)}):t.push("Nav action extendedActions must be an array")),{valid:t.length===0,errors:t}}const V=["danger","warning","info"];function ge(e){const t=[];return e.title===void 0||e.title===null?t.push("Confirm dialog title is required"):typeof e.title!="string"?t.push("Confirm dialog title must be a string"):e.title.trim()===""&&t.push("Confirm dialog title cannot be empty"),e.message===void 0||e.message===null?t.push("Confirm dialog message is required"):typeof e.message!="string"?t.push("Confirm dialog message must be a string"):e.message.trim()===""&&t.push("Confirm dialog message cannot be empty"),e.confirmText!==void 0&&e.confirmText!==null&&typeof e.confirmText!="string"&&t.push("Confirm dialog confirmText must be a string"),e.cancelText!==void 0&&e.cancelText!==null&&typeof e.cancelText!="string"&&t.push("Confirm dialog cancelText must be a string"),e.variant!==void 0&&e.variant!==null&&(typeof e.variant!="string"||!V.includes(e.variant))&&t.push(`Invalid confirm variant "${e.variant}". Expected: ${V.join(" | ")}`),{valid:t.length===0,errors:t}}function f(e,t){u.error(`Validation failed for ${e}:
2
- `+t.map(r=>` • ${r}`).join(`
3
- `))}function me(){return{navigate(e,t){const r=de({path:e,...t});if(!r.valid){f(p.NAVIGATE,r.errors);return}o(p.NAVIGATE,{path:e,state:t==null?void 0:t.state,replace:t==null?void 0:t.replace})},redirect(e){const t=fe({url:e});if(!t.valid){f(p.REDIRECT,t.errors);return}o(p.REDIRECT,{url:e})},navTo(e,t){if(e.startsWith("http://")||e.startsWith("https://")){this.redirect(e);return}this.navigate(e,t)},resize(e){if(typeof e!="number"||e<0){f(E.RESIZE,["Height must be a non-negative number"]);return}o(E.RESIZE,{height:e})},autoResize(){const e=document.documentElement.scrollHeight;this.resize(e)},setTitle(e){if(typeof e!="string"||!e.trim()){f(p.SET_TITLE,["Title must be a non-empty string"]);return}o(p.SET_TITLE,{title:e})}}}function pe(){const e=new Set;return R(v.ACTION_CLICK,r=>{e.forEach(i=>{try{i(r.payload.value)}catch(n){u.error("Error in action click callback:",n)}})}),{setAction(r){var n;const i=he(r);if(!i.valid){f(v.SET_ACTION,i.errors);return}o(v.SET_ACTION,{title:r.title,value:r.value,subTitle:r.subTitle,icon:r.icon,disabled:r.disabled,extendedActions:(n=r.extendedActions)==null?void 0:n.map(a=>({title:a.title,value:a.value,subTitle:a.subTitle,icon:a.icon,disabled:a.disabled}))})},clearAction(){o(v.CLEAR_ACTION,{})},onActionClick(r){return e.add(r),()=>{e.delete(r)}}}}function be(){return{show(){o(h.LOADING,{action:"show"})},hide(){o(h.LOADING,{action:"hide"})}}}function Ee(){const e=t=>{const r=ce(t);if(!r.valid){f(h.TOAST,r.errors);return}o(h.TOAST,{type:t.type,message:t.message,duration:t.duration})};return{show:e,success(t,r){e({type:"success",message:t,duration:r})},error(t,r){e({type:"error",message:t,duration:r})},warning(t,r){e({type:"warning",message:t,duration:r})},info(t,r){e({type:"info",message:t,duration:r})}}}function Te(){return async e=>{const t=ge(e);return t.valid?re(h.CONFIRM,{title:e.title,message:e.message,confirmText:e.confirmText??"Confirm",cancelText:e.cancelText??"Cancel",variant:e.variant??"info"}):(f(h.CONFIRM,t.errors),Promise.reject(new Error(t.errors.join(", "))))}}function ye(){return{loading:be(),toast:Ee(),confirm:Te()}}function ve(){return{create(e){const t=le(e);if(!t.valid){f(D.CREATE,t.errors);return}o(D.CREATE,e)}}}const z={debug:!1,initialized:!1},F={ready:!1,initializing:!1,layout:{...{theme:"light",width:0,locale:"ar",currency:"SAR"}}};class P{constructor(){this.config={...z},this.state={...F},this.themeCallbacks=new Set,this.initCallbacks=new Set,this.appReady=!1,this.auth=ue(),this.page=me(),this.nav=pe(),this.ui=ye(),this.checkout=ve(),this.setupThemeListener(),this.setupResponseListeners()}getState(){return{ready:this.state.ready,initializing:this.state.initializing,layout:{...this.state.layout}}}getConfig(){return{...this.config}}isReady(){return this.state.ready}internalLog(t,...r){switch(t){case"log":u.log(...r);break;case"warn":u.warn(...r);break;case"error":u.error(...r);break;case"info":u.info(...r);break;case"debug":u.debug(...r);break}}setupThemeListener(){R(O.THEME_CHANGE,t=>{this.state.layout.theme=t.payload.theme,this.internalLog("debug","Theme changed:",t.payload.theme),this.themeCallbacks.forEach(r=>{try{r(t.payload.theme)}catch(i){this.internalLog("error","Error in theme callback:",i)}})})}setupResponseListeners(){R(h.CONFIRM_RESPONSE,t=>{this.internalLog("debug","Received confirm response:",t),t.requestId&&ie(t.requestId,{confirmed:t.payload.confirmed})})}onThemeChange(t){return this.themeCallbacks.add(t),()=>{this.themeCallbacks.delete(t)}}onInit(t){if(this.config.initialized)try{t(this.getState())}catch(r){this.internalLog("error","Error in init callback:",r)}return this.initCallbacks.add(t),()=>{this.initCallbacks.delete(t)}}ready(){if(this.appReady){this.internalLog("debug","App already signaled as ready");return}if(!this.config.initialized){this.internalLog("warn","Cannot signal ready before init() is called");return}this.appReady=!0,o(E.READY,{}),this.internalLog("debug","Sent ready signal to host")}async init(t={}){if(this.config.initialized)return this.internalLog("debug","Already initialized, returning current layout"),{layout:{...this.state.layout}};if(this.state.initializing)return this.internalLog("warn","Initialization already in progress"),this.waitForInit();Q()||this.internalLog("warn","Not running in an iframe. Some features may not work."),this.config={debug:t.debug??!1,initialized:!1},X({debug:this.config.debug}),this.state.initializing=!0,this.internalLog("debug","Initializing SDK...");try{o(E.INIT,{height:document.documentElement.scrollHeight}),this.internalLog("debug","Sent iframe.ready message, waiting for context...");const r=await Z(O.PROVIDE);this.internalLog("debug","Received context from host:",r);const i=r.payload.layout;this.state={ready:!0,initializing:!1,layout:{theme:(i==null?void 0:i.theme)??"light",width:(i==null?void 0:i.width)??0,locale:(i==null?void 0:i.locale)??"ar",currency:(i==null?void 0:i.currency)??"SAR"}},this.config.initialized=!0,this.internalLog("debug","Initialization complete. Layout:",this.state.layout);const n=this.getState();return this.initCallbacks.forEach(a=>{try{a(n)}catch(d){this.internalLog("error","Error in init callback:",d)}}),{layout:{...this.state.layout}}}catch(r){throw this.state.initializing=!1,this.state.ready=!1,r}}waitForInit(){return new Promise(t=>{const r=this.onInit(i=>{r(),t({layout:{...i.layout}})})})}destroy(){this.internalLog("debug","Destroying SDK instance"),this.config.initialized&&(o(E.DESTROY,{}),this.internalLog("debug","Sent destroy event to host")),ne("SDK destroyed"),J(),this.themeCallbacks.clear(),this.initCallbacks.clear(),this.config={...z},this.state={...F},this.appReady=!1}}let b=null;function L(){return b||(b=new P),b}function we(){b&&(b.destroy(),b=null)}const N=L(),Ae=I;typeof window<"u"&&(window.salla=window.salla||window.Salla||{},window.Salla=window.salla,window.salla.embedded||(window.salla.embedded=N),window.Salla.embedded||(window.Salla.embedded=N)),l.EmbeddedApp=P,l.embedded=N,l.getEmbeddedApp=L,l.resetEmbeddedApp=we,l.version=Ae,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
1
+ (function(l,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(l=typeof globalThis<"u"?globalThis:l||self,o(l.SallaEmbeddedSDK={}))})(this,function(l){"use strict";const o="embedded::",C={INIT:`${o}iframe.ready`,READY:`${o}ready`,DESTROY:`${o}destroy`},L={PROVIDE:`${o}context.provide`,THEME_CHANGE:`${o}theme.change`},h={LOADING:`${o}ui.loading`,TOAST:`${o}ui.toast`,CONFIRM:`${o}ui.confirm`,CONFIRM_RESPONSE:`${o}ui.confirm.response`},W={},k={REFRESH:`${o}auth.refresh`},m={NAVIGATE:`${o}page.navigate`,REDIRECT:`${o}page.redirect`,SET_TITLE:`${o}page.setTitle`},w={SET_ACTION:`${o}nav.setAction`,CLEAR_ACTION:`${o}nav.clearAction`,ACTION_CLICK:`${o}nav.actionClick`},E={CREATE:`${o}checkout.create`,RESPONSE:`${o}checkout.response`,GET_ADDONS:`${o}checkout.getAddons`,GET_ADDONS_RESPONSE:`${o}checkout.getAddons.response`},S=W.version||"",Y=1e4,B=["localhost","merchants.workers.dev","s.salla.sa",".salla.group",".salla.sa"];let A={showVersion:!0,debug:!1};function Q(t){A={...A,...t}}function q(t){return`%c${t}`}function M(t,e="#fff"){return`background-color: ${t}; color: ${e}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`}function T(t,...e){if(t==="debug"&&!A.debug)return;const r=[],i=[];r.push(q("EmbeddedSDK")),i.push(M("#10b981","#fff")),A.showVersion&&(r.push(q(`v${S}`)),i.push(M("#6b7280","#fff")));const n=r.join("").trim();(console[t]||console.log)(n,...i,...e)}const a={log:(...t)=>{T("log",...t)},warn:(...t)=>{T("warn",...t)},error:(...t)=>{T("error",...t)},info:(...t)=>{T("info",...t)},debug:(...t)=>{T("debug",...t)}};function J(t){try{const r=new URL(t).hostname;return B.some(i=>i.startsWith(".")?r.endsWith(i)||r===i.slice(1):r===i||r.startsWith(`${i}:`))}catch{return!1}}function Z(){return typeof window>"u"||window.parent===window?null:window.parent}function u(t,e,r="*",i,n){const s=Z();if(!s){a.warn("Not running in an iframe, cannot post to host");return}const c={event:t,payload:e||{},timestamp:Date.now(),source:"embedded-app",...i&&{requestId:i},metadata:{version:S}};s.postMessage(c,r)}const f=new Map;let R=!1;function z(t){if(process.env.NODE_ENV==="production"&&!J(t.origin))return;const e=t.data;if(!e||typeof e.event!="string"||!e.payload||typeof e.timestamp!="number"||!e.source){a.warn("Invalid message structure received:",e);return}const r=f.get(e.event);r&&r.forEach(n=>{try{n(e)}catch(s){a.error("Error in message handler:",s)}});const i=f.get("*");i&&i.forEach(n=>{try{n(e)}catch(s){a.error("Error in wildcard handler:",s)}})}function ee(){R||typeof window>"u"||(window.addEventListener("message",z),R=!0)}function y(t,e){ee(),f.has(t)||f.set(t,new Set);const r=f.get(t);return r.add(e),()=>{r.delete(e),r.size===0&&f.delete(t)}}function te(t,e=Y){return new Promise((r,i)=>{const n=setTimeout(()=>{s(),i(new Error(`[EmbeddedSDK] Timeout waiting for "${t}" message`))},e),s=y(t,c=>{clearTimeout(n),s(),r(c)})})}function re(){f.clear(),R&&typeof window<"u"&&(window.removeEventListener("message",z),R=!1)}function ie(){return typeof window>"u"?!1:window.parent!==window}function ne(t,e,r){const i={event:t,payload:e,timestamp:Date.now(),source:"merchant-dashboard",...r,metadata:{version:S,synthetic:!0}},n=f.get(t);n==null||n.forEach(s=>{try{s(i)}catch(c){a.error("Error in message handler:",c)}})}const g=new Map,se=3e4;function P(){const t=Date.now(),e=Math.random().toString(36).slice(2,9);return`req_${t}_${e}`}function U(t,e={},r=se){const i=P();return new Promise((n,s)=>{const c=setTimeout(()=>{g.get(i)&&(g.delete(i),s(new Error(`[EmbeddedSDK] Request "${t}" timed out after ${r}ms`)))},r);g.set(i,{resolve:n,reject:s,timeout:c,event:t}),u(t,e,"*",i)})}function V(t,e,r){const i=g.get(t);if(!i){a.warn(`Received response for unknown request: ${t}`);return}clearTimeout(i.timeout),g.delete(t),i.resolve(e)}function ae(t="SDK cleanup"){g.forEach((e,r)=>{clearTimeout(e.timeout),e.reject(new Error(`[EmbeddedSDK] Request ${r} cancelled: ${t}`))}),g.clear()}function I(){const t=new Set;return{subscribe(e){return t.add(e),()=>{t.delete(e)}},notify(...e){t.forEach(r=>{try{r(...e)}catch(i){a.error("Error in subscription callback:",i)}})},clear(){t.clear()},size(){return t.size}}}const oe="https://api.salla.dev";class v extends Error{constructor(e,r,i){super(e),this.status=r,this.response=i,this.name="ApiError"}}async function ue(t,e={}){const{method:r="GET",headers:i={},body:n,timeout:s=3e4}=e,c=`${oe}${t}`,D=new AbortController,X=setTimeout(()=>{D.abort()},s);try{const d=await fetch(c,{method:r,headers:{"Content-Type":"application/json",...i},body:n?JSON.stringify(n):void 0,signal:D.signal});clearTimeout(X);let N;const x=d.headers.get("content-type");if(x!=null&&x.includes("application/json")?N=await d.json():N=await d.text(),!d.ok)throw new v(`API request failed: ${d.statusText}`,d.status,N);return N}catch(d){throw clearTimeout(X),d instanceof v?d:d instanceof Error?d.name==="AbortError"?new v(`Request timeout after ${s}ms`):new v(`Request failed: ${d.message}`):new v("Unknown error occurred")}}function $(t){return{isVerified:!1,isError:!0,error:t,data:null}}async function ce(t){const{token:e,appId:r,refreshOnError:i=!0}=t;if(!e){const n="Token is required. Provide it as a parameter or in URL as ?token=XXX";return a.error("Error in introspect:",n),$(n)}if(!r){const n="App ID is required. Provide it as a parameter or in URL as ?app_id=XXX";return a.error("Error in introspect:",n),$(n)}try{const n=await ue("/exchange-authority/v1/introspect",{method:"POST",headers:{"S-Source":r,"Content-Type":"application/json"},body:{env:"prod",token:e,iss:"merchant-dashboard",subject:"embedded-page"}}),s=n.success;return{isVerified:s,isError:!s,error:s?void 0:"API request failed",data:s?n.data:null}}catch(n){i&&(O().ui.toast.error((n==null?void 0:n.toString())??"Introspect error"),u(k.REFRESH,{})),a.error("Error in introspect:",n);const s=n instanceof Error?n.message:n;return $(s)}}function de(t){return{getToken(){return new URLSearchParams(window.location.search).get("token")},getAppId(){return new URLSearchParams(window.location.search).get("app_id")},refresh(){u(k.REFRESH,{})},async introspect(e={}){const r=e.token??this.getToken()??"",i=e.appId??this.getAppId()??"";return ce({token:r,appId:i,refreshOnError:e.refreshOnError})}}}const j=["success","error","warning","info"];function le(t){const e=[];return t.type===void 0||t.type===null?e.push("Toast type is required"):(typeof t.type!="string"||!j.includes(t.type))&&e.push(`Invalid toast type "${t.type}". Expected: ${j.join(" | ")}`),t.message===void 0||t.message===null?e.push("Toast message is required"):typeof t.message!="string"?e.push("Toast message must be a string"):t.message.trim()===""&&e.push("Toast message cannot be empty"),t.duration!==void 0&&t.duration!==null&&(typeof t.duration!="number"?e.push("Toast duration must be a number"):t.duration<0&&e.push("Toast duration cannot be negative")),{valid:e.length===0,errors:e}}function F(t,e){const r=[];return typeof t!="object"||t===null?(r.push(`${e} must be an object`),r):((typeof t.type!="string"||t.type.trim()==="")&&r.push(`${e} must have a valid type`),(typeof t.slug!="string"||t.slug.trim()==="")&&r.push(`${e} must have a valid slug`),t.quantity!==void 0&&(typeof t.quantity!="number"||t.quantity<1)&&r.push(`${e} must have a quantity >= 1`),r)}function fe(t){const e=[];if(typeof t!="object"||t===null)return e.push("Checkout options must be an object"),{valid:!1,errors:e};const r="item"in t,i="items"in t;if(!r&&!i)return e.push("Checkout requires either 'item' or 'items'"),{valid:!1,errors:e};if(r){const n=F(t.item,"Item");return e.push(...n),{valid:e.length===0,errors:e}}return Array.isArray(t.items)?t.items.length===0?(e.push("At least one item is required"),{valid:!1,errors:e}):(t.items.forEach((n,s)=>{const c=F(n,`Item at index ${s}`);e.push(...c)}),{valid:e.length===0,errors:e}):(e.push("Checkout items must be an array"),{valid:!1,errors:e})}function he(t){const e=[];return t.path===void 0||t.path===null?e.push("Navigation path is required"):typeof t.path!="string"?e.push("Navigation path must be a string"):t.path.trim()===""&&e.push("Navigation path cannot be empty"),t.replace!==void 0&&typeof t.replace!="boolean"&&e.push("Navigation replace option must be a boolean"),{valid:e.length===0,errors:e}}function ge(t){const e=[];if(t.url===void 0||t.url===null)e.push("Redirect URL is required");else if(typeof t.url!="string")e.push("Redirect URL must be a string");else if(t.url.trim()==="")e.push("Redirect URL cannot be empty");else try{new URL(t.url)}catch{e.push(`Invalid redirect URL: "${t.url}"`)}return{valid:e.length===0,errors:e}}function pe(t){const e=[];return t.title?typeof t.title!="string"&&e.push("Nav action title must be a string"):e.push("Nav action title is required"),t.value?typeof t.value!="string"&&e.push("Nav action value must be a string"):e.push("Nav action value is required"),t.subTitle!==void 0&&t.subTitle!==null&&typeof t.subTitle!="string"&&e.push("Nav action subTitle must be a string"),t.icon!==void 0&&t.icon!==null&&typeof t.icon!="string"&&e.push("Nav action icon must be a string"),t.disabled!==void 0&&t.disabled!==null&&typeof t.disabled!="boolean"&&e.push("Nav action disabled must be a boolean"),t.extendedActions!==void 0&&t.extendedActions!==null&&(Array.isArray(t.extendedActions)?t.extendedActions.forEach((r,i)=>{if(typeof r!="object"||r===null){e.push(`Extended action at index ${i} must be an object`);return}const n=r;(!n.title||typeof n.title!="string")&&e.push(`Extended action at index ${i} is missing required "title" property`),(!n.value||typeof n.value!="string")&&e.push(`Extended action at index ${i} is missing required "value" property`),n.subTitle!==void 0&&typeof n.subTitle!="string"&&e.push(`Extended action at index ${i} subTitle must be a string`),n.icon!==void 0&&typeof n.icon!="string"&&e.push(`Extended action at index ${i} icon must be a string`),n.disabled!==void 0&&typeof n.disabled!="boolean"&&e.push(`Extended action at index ${i} disabled must be a boolean`)}):e.push("Nav action extendedActions must be an array")),{valid:e.length===0,errors:e}}const H=["danger","warning","info"];function me(t){const e=[];return t.title===void 0||t.title===null?e.push("Confirm dialog title is required"):typeof t.title!="string"?e.push("Confirm dialog title must be a string"):t.title.trim()===""&&e.push("Confirm dialog title cannot be empty"),t.message===void 0||t.message===null?e.push("Confirm dialog message is required"):typeof t.message!="string"?e.push("Confirm dialog message must be a string"):t.message.trim()===""&&e.push("Confirm dialog message cannot be empty"),t.confirmText!==void 0&&t.confirmText!==null&&typeof t.confirmText!="string"&&e.push("Confirm dialog confirmText must be a string"),t.cancelText!==void 0&&t.cancelText!==null&&typeof t.cancelText!="string"&&e.push("Confirm dialog cancelText must be a string"),t.variant!==void 0&&t.variant!==null&&(typeof t.variant!="string"||!H.includes(t.variant))&&e.push(`Invalid confirm variant "${t.variant}". Expected: ${H.join(" | ")}`),{valid:e.length===0,errors:e}}function p(t,e){a.error(`Validation failed for ${t}:
2
+ `+e.map(r=>` • ${r}`).join(`
3
+ `))}function Ee(){return{resize:i=>{},autoResize:()=>{},stopAutoResize:()=>{}}}function ye(){const{resize:t,autoResize:e,stopAutoResize:r}=Ee();return{navigate(i,n){const s=he({path:i,...n});if(!s.valid){p(m.NAVIGATE,s.errors);return}u(m.NAVIGATE,{path:i,state:n==null?void 0:n.state,replace:n==null?void 0:n.replace})},redirect(i){const n=ge({url:i});if(!n.valid){p(m.REDIRECT,n.errors);return}u(m.REDIRECT,{url:i})},navTo(i,n){if(i.startsWith("http://")||i.startsWith("https://")){this.redirect(i);return}this.navigate(i,n)},setTitle(i){if(typeof i!="string"||!i.trim()){p(m.SET_TITLE,["Title must be a non-empty string"]);return}u(m.SET_TITLE,{title:i})},resize:t,autoResize:e,stopAutoResize:r}}function be(){const t=I();return y(w.ACTION_CLICK,e=>{t.notify(e.payload.value)}),{setAction(e){var i;const r=pe(e);if(!r.valid){p(w.SET_ACTION,r.errors);return}u(w.SET_ACTION,{title:e.title,value:e.value,subTitle:e.subTitle,icon:e.icon,disabled:e.disabled,extendedActions:(i=e.extendedActions)==null?void 0:i.map(n=>({title:n.title,value:n.value,subTitle:n.subTitle,icon:n.icon,disabled:n.disabled}))})},clearAction(){u(w.CLEAR_ACTION,{})},onActionClick(e){return t.subscribe(e)}}}function Te(){return{show(){u(h.LOADING,{action:"show"})},hide(){u(h.LOADING,{action:"hide"})}}}function ve(){const t=e=>{const r=le(e);if(!r.valid){p(h.TOAST,r.errors);return}u(h.TOAST,{type:e.type,message:e.message,duration:e.duration})};return{show:t,success(e,r){t({type:"success",message:e,duration:r})},error(e,r){t({type:"error",message:e,duration:r})},warning(e,r){t({type:"warning",message:e,duration:r})},info(e,r){t({type:"info",message:e,duration:r})}}}function we(){return async t=>{const e=me(t);return e.valid?U(h.CONFIRM,{title:t.title,message:t.message,confirmText:t.confirmText??"Confirm",cancelText:t.cancelText??"Cancel",variant:t.variant??"info"}):(p(h.CONFIRM,e.errors),Promise.reject(new Error(e.errors.join(", "))))}}function Se(){return{loading:Te(),toast:ve(),confirm:we()}}function Ae(){const t=I(),e=[];return e.push(y(E.RESPONSE,r=>{t.notify({success:r.payload.success,order_id:r.payload.order_id,status:r.payload.status,error:r.payload.error,context:r.payload.context})})),e.push(y(E.GET_ADDONS_RESPONSE,r=>{r.requestId&&V(r.requestId,{success:r.payload.success,addons:r.payload.addons,error:r.payload.error})})),{create(r,i){const n=Array.isArray(r)?r:[r],s=fe({items:n});if(!s.valid)throw p(E.CREATE,s.errors),new Error(s.errors[0]);u(E.CREATE,{items:n.map(c=>({type:c.type,slug:c.slug,quantity:c.quantity??1})),...(i==null?void 0:i.context)!==void 0&&{context:i.context}},"*",P())},onResult(r){return t.subscribe(r)},async getAddons(){try{return await U(E.GET_ADDONS,{},3e4)}catch(r){return{success:!1,error:{code:"REQUEST_FAILED",message:r instanceof Error?r.message:"Unknown error"}}}},destroy(){e.forEach(r=>r()),e.length=0,t.clear()}}}const G={theme:"light",width:0,locale:"ar",currency:"SAR"};class K{constructor(){this.initialized=!1,this.initializing=!1,this.debugMode=!1,this.appReady=!1,this.layout={...G},this.postInitHooks=[],this.themeSubscription=I(),this.initSubscription=I(),this.auth=de(),this.page=ye(),this.nav=be(),this.ui=Se(),this.checkout=Ae(),this.registerPostInitHook(e=>{const r=e.payload.pendingCheckoutResult;r&&(a.debug("Dispatching pending checkout result:",r),queueMicrotask(()=>{ne(E.RESPONSE,{success:r.success,status:r.status,error:r.error,context:r.context})}))}),this.setupListeners()}registerPostInitHook(e){this.postInitHooks.push(e)}setupListeners(){y(L.THEME_CHANGE,e=>{this.layout.theme=e.payload.theme,a.debug("Theme changed:",e.payload.theme),this.themeSubscription.notify(e.payload.theme)}),y(h.CONFIRM_RESPONSE,e=>{a.debug("Received confirm response:",e),e.requestId&&V(e.requestId,{confirmed:e.payload.confirmed})})}getState(){return{ready:this.initialized,initializing:this.initializing,layout:{...this.layout}}}isReady(){return this.initialized}onThemeChange(e){return this.themeSubscription.subscribe(e)}onInit(e){if(this.initialized)try{e(this.getState())}catch(r){a.error("Error in init callback:",r)}return this.initSubscription.subscribe(e)}ready(){if(this.appReady){a.debug("App already signaled as ready");return}if(!this.initialized){a.warn("Cannot signal ready before init() is called");return}this.appReady=!0,u(C.READY,{}),a.debug("Sent ready signal to host")}async init(e={}){if(this.initialized)return a.debug("Already initialized, returning current layout"),{layout:{...this.layout}};if(this.initializing)return a.warn("Initialization already in progress"),new Promise(r=>{const i=this.onInit(n=>{i(),r({layout:{...n.layout}})})});this.initializing=!0,this.debugMode=e.debug??!1,Q({debug:this.debugMode}),ie()||a.warn("Not running in an iframe. Some features may not work."),a.debug("Initializing SDK...");try{u(C.INIT,{height:document.documentElement.scrollHeight}),a.debug("Sent iframe.ready message, waiting for context...");const r=await te(L.PROVIDE);a.debug("Received context from host:",r);const{layout:i}=r.payload;return this.layout={theme:(i==null?void 0:i.theme)??"light",width:(i==null?void 0:i.width)??0,locale:(i==null?void 0:i.locale)??"ar",currency:(i==null?void 0:i.currency)??"SAR"},this.postInitHooks.forEach(n=>{try{n(r)}catch(s){a.error("Error in post-init hook:",s)}}),this.initialized=!0,this.initializing=!1,a.debug("Initialization complete. Layout:",this.layout),this.initSubscription.notify(this.getState()),{layout:{...this.layout}}}catch(r){throw this.initializing=!1,r}}destroy(){a.debug("Destroying SDK instance"),this.initialized&&(u(C.DESTROY,{}),a.debug("Sent destroy event to host")),this.checkout.destroy(),ae("SDK destroyed"),re(),this.themeSubscription.clear(),this.initSubscription.clear(),this.postInitHooks=[],this.initialized=!1,this.initializing=!1,this.appReady=!1,this.layout={...G}}}let b=null;function O(){return b||(b=new K),b}function Re(){b&&(b.destroy(),b=null)}const _=O(),Ie=S;typeof window<"u"&&(window.salla=window.salla||window.Salla||{},window.Salla=window.salla,window.salla.embedded||(window.salla.embedded=_),window.Salla.embedded||(window.Salla.embedded=_)),l.EmbeddedApp=K,l.embedded=_,l.getEmbeddedApp=O,l.resetEmbeddedApp=Re,l.version=Ie,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
4
4
  //# sourceMappingURL=index.js.map