@salla.sa/embedded-sdk 0.1.0-beta.4 → 0.1.0-beta.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/core/events.ts","../../src/modules/auth/events.ts","../../src/modules/page/events.ts","../../src/modules/nav/events.ts","../../src/modules/ui/events.ts","../../src/modules/checkout/events.ts","../../src/core/constants.ts","../../src/core/messenger.ts","../../src/core/requests.ts","../../src/modules/auth/index.ts","../../src/core/validation/toast.ts","../../src/core/validation/checkout.ts","../../src/core/validation/navigation.ts","../../src/core/validation/nav-action.ts","../../src/core/validation/confirm.ts","../../src/core/validation/utils.ts","../../src/modules/page/index.ts","../../src/modules/nav/index.ts","../../src/modules/ui/components/loading.ts","../../src/modules/ui/components/toast.ts","../../src/modules/ui/components/modal.ts","../../src/modules/ui/components/confirm.ts","../../src/modules/ui/index.ts","../../src/modules/checkout/index.ts","../../src/core/EmbeddedApp.ts","../../src/index.ts"],"sourcesContent":["/**\n * @fileoverview Core event constants.\n * Event naming convention: `embedded::{module}.{action}`\n */\n\n/**\n * Event prefix for all embedded events.\n */\nexport const EVENT_PREFIX = \"embedded::\" as const;\n\n/**\n * Iframe lifecycle events.\n */\nexport const IFRAME_EVENTS = {\n /** Initialize handshake - iframe signals it's ready to receive context */\n INIT: `${EVENT_PREFIX}iframe.ready`,\n /** Request iframe resize */\n RESIZE: `${EVENT_PREFIX}iframe.resize`,\n /** App signals it's fully loaded and ready */\n READY: `${EVENT_PREFIX}ready`,\n /** App requests to be destroyed and navigate away */\n DESTROY: `${EVENT_PREFIX}destroy`,\n} as const;\n\n/**\n * Context events (Host → Iframe).\n */\nexport const CONTEXT_EVENTS = {\n /** Context data provision */\n PROVIDE: `${EVENT_PREFIX}context.provide`,\n /** Theme change notification */\n THEME_CHANGE: `${EVENT_PREFIX}theme.change`,\n} as const;\n\n/**\n * Log events.\n */\nexport const LOG_EVENTS = {\n /** Send log message to host */\n LOG: `${EVENT_PREFIX}log`,\n} as const;\n","/**\n * @fileoverview Authentication module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Authentication events.\n */\nexport const AUTH_EVENTS = {\n /** Request token refresh (re-renders iframe with new token) */\n REFRESH: `${EVENT_PREFIX}auth.refresh`,\n} as const;\n","/**\n * @fileoverview Page module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Page navigation events.\n */\nexport const PAGE_EVENTS = {\n /** Navigate using React Router (SPA navigation) */\n NAVIGATE: `${EVENT_PREFIX}page.navigate`,\n /** Redirect using window.location (full page reload) */\n REDIRECT: `${EVENT_PREFIX}page.redirect`,\n /** Set page title */\n SET_TITLE: `${EVENT_PREFIX}page.setTitle`,\n} as const;\n","/**\n * @fileoverview Nav module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Navigation action events.\n */\nexport const NAV_EVENTS = {\n /** Set primary action button in navbar */\n SET_ACTION: `${EVENT_PREFIX}nav.setAction`,\n /** Notification when action button is clicked (host → iframe) */\n ACTION_CLICK: `${EVENT_PREFIX}nav.actionClick`,\n} as const;\n","/**\n * @fileoverview UI module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * UI state events.\n */\nexport const UI_EVENTS = {\n /** Set loading state */\n LOADING: `${EVENT_PREFIX}ui.loading`,\n /** Show toast notification */\n TOAST: `${EVENT_PREFIX}ui.toast`,\n /** Control modal state */\n MODAL: `${EVENT_PREFIX}ui.modal`,\n /** Show confirm dialog (async request) */\n CONFIRM: `${EVENT_PREFIX}ui.confirm`,\n /** Confirm dialog response (from host) */\n CONFIRM_RESPONSE: `${EVENT_PREFIX}ui.confirm.response`,\n /** Modal response (from host) */\n MODAL_RESPONSE: `${EVENT_PREFIX}ui.modal.response`,\n} as const;\n","/**\n * @fileoverview Checkout module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Checkout events.\n */\nexport const CHECKOUT_EVENTS = {\n /** Initialize checkout flow */\n CREATE: `${EVENT_PREFIX}checkout.create`,\n} as const;\n","import pkg from \"../../package.json\" assert { type: \"json\" };\n\n/**\n * @fileoverview Constants for the Embedded SDK.\n * Re-exports all module events for backward compatibility.\n */\n\n// Re-export core events\nexport {\n EVENT_PREFIX,\n IFRAME_EVENTS,\n CONTEXT_EVENTS,\n LOG_EVENTS,\n} from \"./events\";\n\n// Re-export module events\nexport { AUTH_EVENTS } from \"../modules/auth/events\";\nexport { PAGE_EVENTS } from \"../modules/page/events\";\nexport { NAV_EVENTS } from \"../modules/nav/events\";\nexport { UI_EVENTS } from \"../modules/ui/events\";\nexport { CHECKOUT_EVENTS } from \"../modules/checkout/events\";\n\n/**\n * SDK version for debugging and compatibility checks.\n */\nexport const SDK_VERSION: string = pkg.version;\n\n/**\n * Default timeout for waiting for host responses (ms).\n */\nexport const DEFAULT_TIMEOUT = 10000;\n\n/**\n * Trusted domains for message validation.\n * The host will validate based on iframe URL, but SDK validates for host messages.\n */\nexport const TRUSTED_DOMAINS = [\n \"localhost\",\n \"merchants.workers.dev\",\n \"s.salla.sa\",\n \".salla.group\",\n \".salla.sa\",\n] as const;\n","/**\n * @fileoverview PostMessage utilities for communicating with the host.\n */\n\nimport { DEFAULT_TIMEOUT, TRUSTED_DOMAINS } from \"./constants\";\nimport type { BaseMessage, MessageCallback, Unsubscribe } from \"./types\";\n\n/**\n * Check if an origin is trusted.\n */\nfunction isTrustedOrigin(origin: string): boolean {\n try {\n const url = new URL(origin);\n const hostname = url.hostname;\n\n return TRUSTED_DOMAINS.some((domain) => {\n if (domain.startsWith(\".\")) {\n // Suffix match (e.g., \".salla.sa\" matches \"app.salla.sa\")\n return hostname.endsWith(domain) || hostname === domain.slice(1);\n }\n // Exact match\n return hostname === domain || hostname.startsWith(`${domain}:`);\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Get the parent window (host) reference.\n * Returns null if not in an iframe.\n */\nfunction getParentWindow(): Window | null {\n if (typeof window === \"undefined\") return null;\n if (window.parent === window) return null;\n return window.parent;\n}\n\n/**\n * Send a message to the host (parent window).\n *\n * @param event - The event name\n * @param data - Additional data to send with the message\n * @param targetOrigin - Target origin for security (defaults to \"*\")\n */\nexport function postToHost<T extends Record<string, unknown>>(\n event: string,\n data?: T,\n targetOrigin: string = \"*\",\n): void {\n const parent = getParentWindow();\n\n if (!parent) {\n console.warn(\"[EmbeddedSDK] Not running in an iframe, cannot post to host\");\n return;\n }\n\n const message: BaseMessage = {\n event,\n ...data,\n };\n\n parent.postMessage(message, targetOrigin);\n}\n\n/**\n * Message listener registry.\n */\nconst listeners: Map<string, Set<MessageCallback>> = new Map();\n\n/**\n * Global message handler.\n */\nlet isListening = false;\n\nfunction handleMessage(event: MessageEvent): void {\n // Validate origin in production\n if (process.env.NODE_ENV === \"production\" && !isTrustedOrigin(event.origin)) {\n return;\n }\n\n const data = event.data as BaseMessage;\n\n if (!data || typeof data.event !== \"string\") {\n return;\n }\n\n const eventListeners = listeners.get(data.event);\n if (eventListeners) {\n eventListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n console.error(`[EmbeddedSDK] Error in message handler:`, error);\n }\n });\n }\n\n // Also notify wildcard listeners\n const wildcardListeners = listeners.get(\"*\");\n if (wildcardListeners) {\n wildcardListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n console.error(`[EmbeddedSDK] Error in wildcard handler:`, error);\n }\n });\n }\n}\n\n/**\n * Start listening for messages if not already.\n */\nfunction startListening(): void {\n if (isListening || typeof window === \"undefined\") return;\n\n window.addEventListener(\"message\", handleMessage);\n isListening = true;\n}\n\n/**\n * Subscribe to messages from the host.\n *\n * @param event - The event name to listen for, or \"*\" for all events\n * @param callback - Callback function when message is received\n * @returns Unsubscribe function\n */\nexport function onMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n callback: MessageCallback<T>,\n): Unsubscribe {\n startListening();\n\n if (!listeners.has(event)) {\n listeners.set(event, new Set());\n }\n\n const eventListeners = listeners.get(event)!;\n eventListeners.add(callback as MessageCallback);\n\n return () => {\n eventListeners.delete(callback as MessageCallback);\n if (eventListeners.size === 0) {\n listeners.delete(event);\n }\n };\n}\n\n/**\n * Wait for a specific message from the host.\n *\n * @param event - The event name to wait for\n * @param timeout - Timeout in milliseconds (defaults to DEFAULT_TIMEOUT)\n * @returns Promise that resolves with the message data\n */\nexport function waitForMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n timeout: number = DEFAULT_TIMEOUT,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n unsubscribe();\n reject(new Error(`[EmbeddedSDK] Timeout waiting for \"${event}\" message`));\n }, timeout);\n\n const unsubscribe = onMessage<T>(event, (data) => {\n clearTimeout(timer);\n unsubscribe();\n resolve(data);\n });\n });\n}\n\n/**\n * Remove all message listeners.\n */\nexport function removeAllListeners(): void {\n listeners.clear();\n\n if (isListening && typeof window !== \"undefined\") {\n window.removeEventListener(\"message\", handleMessage);\n isListening = false;\n }\n}\n\n/**\n * Check if running inside an iframe.\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") return false;\n return window.parent !== window;\n}\n","/**\n * @fileoverview Request-response tracking for async operations over postMessage.\n * Enables Promise-based APIs for operations that need host responses (e.g., confirm dialogs).\n */\n\nimport { postToHost } from \"./messenger\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Pending request entry with resolve/reject functions and timeout.\n */\ninterface PendingRequest<T = unknown> {\n resolve: (value: T) => void;\n reject: (reason: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n event: string;\n}\n\n// ============================================================================\n// State\n// ============================================================================\n\n/**\n * Map of pending requests by requestId.\n */\nconst pendingRequests = new Map<string, PendingRequest>();\n\n/**\n * Default timeout for requests (30 seconds).\n */\nconst DEFAULT_REQUEST_TIMEOUT = 30000;\n\n// ============================================================================\n// Request ID Generation\n// ============================================================================\n\n/**\n * Generate a unique request ID.\n * Format: req_{timestamp}_{random}\n */\nexport function generateRequestId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 9);\n return `req_${timestamp}_${random}`;\n}\n\n// ============================================================================\n// Request/Response Functions\n// ============================================================================\n\n/**\n * Send a request to the host and return a Promise that resolves when the response is received.\n *\n * @param event - The event name to send\n * @param data - Additional data to send with the request\n * @param timeout - Timeout in milliseconds (defaults to 30000)\n * @returns Promise that resolves with the response data\n *\n * @example\n * ```typescript\n * const result = await sendRequest<{ confirmed: boolean }>(\n * 'embedded::ui.confirm',\n * { title: 'Delete?', message: 'Are you sure?' }\n * );\n * if (result.confirmed) {\n * // User confirmed\n * }\n * ```\n */\nexport function sendRequest<T>(\n event: string,\n data: Record<string, unknown> = {},\n timeout: number = DEFAULT_REQUEST_TIMEOUT,\n): Promise<T> {\n const requestId = generateRequestId();\n\n return new Promise<T>((resolve, reject) => {\n // Set up timeout\n const timer = setTimeout(() => {\n const pending = pendingRequests.get(requestId);\n if (pending) {\n pendingRequests.delete(requestId);\n reject(\n new Error(\n `[EmbeddedSDK] Request \"${event}\" timed out after ${timeout}ms`,\n ),\n );\n }\n }, timeout);\n\n // Store the pending request\n pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timer,\n event,\n });\n\n // Send the request to host\n postToHost(event, { ...data, requestId });\n });\n}\n\n/**\n * Handle a response from the host for a pending request.\n * Called by the message listener when a response event is received.\n *\n * @param requestId - The request ID from the response\n * @param result - The result data to resolve with\n * @param error - Optional error message to reject with\n *\n * @example\n * ```typescript\n * // In message listener:\n * onMessage('embedded::ui.confirm.response', (msg) => {\n * handleResponse(msg.requestId, { confirmed: msg.confirmed });\n * });\n * ```\n */\nexport function handleResponse<T = unknown>(\n requestId: string,\n result: T,\n error?: string,\n): void {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n // Request may have already timed out or been handled\n console.warn(\n `[EmbeddedSDK] Received response for unknown request: ${requestId}`,\n );\n return;\n }\n\n // Clear the timeout\n clearTimeout(pending.timeout);\n\n // Remove from pending requests\n pendingRequests.delete(requestId);\n\n // Resolve or reject the promise\n if (error) {\n pending.reject(new Error(error));\n } else {\n pending.resolve(result);\n }\n}\n\n/**\n * Check if there are any pending requests.\n * Useful for cleanup or debugging.\n */\nexport function hasPendingRequests(): boolean {\n return pendingRequests.size > 0;\n}\n\n/**\n * Get the count of pending requests.\n * Useful for debugging.\n */\nexport function getPendingRequestCount(): number {\n return pendingRequests.size;\n}\n\n/**\n * Cancel all pending requests.\n * Useful for cleanup when the SDK is being destroyed.\n *\n * @param reason - Optional reason for cancellation\n */\nexport function cancelAllRequests(reason: string = \"SDK cleanup\"): void {\n pendingRequests.forEach((pending, requestId) => {\n clearTimeout(pending.timeout);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n });\n pendingRequests.clear();\n}\n\n/**\n * Cancel a specific pending request.\n *\n * @param requestId - The request ID to cancel\n * @param reason - Optional reason for cancellation\n * @returns true if the request was found and cancelled, false otherwise\n */\nexport function cancelRequest(\n requestId: string,\n reason: string = \"Cancelled\",\n): boolean {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n return false;\n }\n\n clearTimeout(pending.timeout);\n pendingRequests.delete(requestId);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n\n return true;\n}\n","/**\n * @fileoverview Auth module for token and authentication management.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { AUTH_EVENTS } from \"./events\";\nimport type { AuthModule, StateGetter } from \"./types\";\n\nexport type { AuthModule } from \"./types\";\n\n/**\n * Create the auth module.\n *\n * @param _getState - Function to get current SDK state (kept for consistency)\n * @returns Auth module instance\n */\nexport function createAuthModule(_getState: StateGetter): AuthModule {\n return {\n /**\n * Get the token from the URL query parameter.\n * The token is passed to the iframe via ?token=XXX\n *\n * @example\n * ```typescript\n * const token = embedded.auth.getToken();\n * if (token) {\n * await verifyWithBackend(token);\n * }\n * ```\n */\n getToken(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"token\");\n },\n\n /**\n * Request a token refresh from the host.\n * This will re-render the iframe with a new token URL.\n *\n * @example\n * ```typescript\n * // When token is about to expire\n * embedded.auth.refresh();\n * ```\n */\n refresh(): void {\n postToHost(AUTH_EVENTS.REFRESH, {});\n },\n };\n}\n","/**\n * @fileoverview Toast notification validation.\n */\n\nimport type { ToastType } from \"../types\";\nimport type { ValidationResult, ToastValidationInput } from \"./types\";\n\nconst VALID_TOAST_TYPES: ToastType[] = [\"success\", \"error\", \"warning\", \"info\"];\n\n/**\n * Validate toast notification options.\n */\nexport function validateToast(options: ToastValidationInput): ValidationResult {\n const errors: string[] = [];\n\n // Type validation\n if (options.type === undefined || options.type === null) {\n errors.push(\"Toast type is required\");\n } else if (\n typeof options.type !== \"string\" ||\n !VALID_TOAST_TYPES.includes(options.type as ToastType)\n ) {\n errors.push(\n `Invalid toast type \"${options.type}\". Expected: ${VALID_TOAST_TYPES.join(\" | \")}`,\n );\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Toast message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Toast message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Toast message cannot be empty\");\n }\n\n // Duration validation (optional)\n if (options.duration !== undefined && options.duration !== null) {\n if (typeof options.duration !== \"number\") {\n errors.push(\"Toast duration must be a number\");\n } else if (options.duration < 0) {\n errors.push(\"Toast duration cannot be negative\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Checkout payload validation.\n */\n\nimport type { ValidationResult, CheckoutValidationInput } from \"./types\";\n\n/**\n * Validate checkout payload.\n */\nexport function validateCheckout(\n payload: CheckoutValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n if (typeof payload !== \"object\" || payload === null) {\n errors.push(\"Checkout payload must be an object\");\n return { valid: false, errors };\n }\n\n // Amount validation (optional but if provided must be valid)\n if (payload.amount !== undefined && payload.amount !== null) {\n if (typeof payload.amount !== \"number\") {\n errors.push(\"Checkout amount must be a number\");\n } else if (payload.amount < 0) {\n errors.push(\"Checkout amount cannot be negative\");\n }\n }\n\n // Currency validation (optional but if provided must be valid)\n if (payload.currency !== undefined && payload.currency !== null) {\n if (typeof payload.currency !== \"string\") {\n errors.push(\"Checkout currency must be a string\");\n } else if (payload.currency.trim() === \"\") {\n errors.push(\"Checkout currency cannot be empty\");\n }\n }\n\n // Items validation (optional but if provided must be array)\n if (payload.items !== undefined && payload.items !== null) {\n if (!Array.isArray(payload.items)) {\n errors.push(\"Checkout items must be an array\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Page navigation and redirect validation.\n */\n\nimport type {\n ValidationResult,\n NavigateValidationInput,\n RedirectValidationInput,\n} from \"./types\";\n\n/**\n * Validate page navigation options.\n */\nexport function validateNavigate(\n options: NavigateValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Path validation\n if (options.path === undefined || options.path === null) {\n errors.push(\"Navigation path is required\");\n } else if (typeof options.path !== \"string\") {\n errors.push(\"Navigation path must be a string\");\n } else if (options.path.trim() === \"\") {\n errors.push(\"Navigation path cannot be empty\");\n }\n\n // Replace validation (optional)\n if (options.replace !== undefined && typeof options.replace !== \"boolean\") {\n errors.push(\"Navigation replace option must be a boolean\");\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Validate page redirect options.\n */\nexport function validateRedirect(\n options: RedirectValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // URL validation\n if (options.url === undefined || options.url === null) {\n errors.push(\"Redirect URL is required\");\n } else if (typeof options.url !== \"string\") {\n errors.push(\"Redirect URL must be a string\");\n } else if (options.url.trim() === \"\") {\n errors.push(\"Redirect URL cannot be empty\");\n } else {\n // Validate URL format\n try {\n new URL(options.url);\n } catch {\n errors.push(`Invalid redirect URL: \"${options.url}\"`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Nav action validation.\n */\n\nimport type { ValidationResult, NavActionValidationInput } from \"./types\";\n\n/**\n * Validate nav action options.\n */\nexport function validateNavAction(\n options: NavActionValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation (required)\n if (options.title === undefined || options.title === null) {\n errors.push(\"Nav action title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Nav action title must be a string\");\n }\n\n // onClick validation (optional, should be a function)\n if (options.onClick !== undefined && options.onClick !== null) {\n if (typeof options.onClick !== \"function\") {\n errors.push(\"Nav action onClick must be a function\");\n }\n }\n\n // Value validation (optional)\n if (options.value !== undefined && options.value !== null) {\n if (typeof options.value !== \"string\") {\n errors.push(\"Nav action value must be a string\");\n }\n }\n\n // subTitle validation (optional)\n if (options.subTitle !== undefined && options.subTitle !== null) {\n if (typeof options.subTitle !== \"string\") {\n errors.push(\"Nav action subTitle must be a string\");\n }\n }\n\n // icon validation (optional)\n if (options.icon !== undefined && options.icon !== null) {\n if (typeof options.icon !== \"string\") {\n errors.push(\"Nav action icon must be a string\");\n }\n }\n\n // disabled validation (optional)\n if (options.disabled !== undefined && options.disabled !== null) {\n if (typeof options.disabled !== \"boolean\") {\n errors.push(\"Nav action disabled must be a boolean\");\n }\n }\n\n // Extended actions validation (optional)\n if (\n options.extendedActions !== undefined &&\n options.extendedActions !== null\n ) {\n if (!Array.isArray(options.extendedActions)) {\n errors.push(\"Nav action extendedActions must be an array\");\n } else {\n options.extendedActions.forEach((action: unknown, index: number) => {\n if (typeof action !== \"object\" || action === null) {\n errors.push(`Extended action at index ${index} must be an object`);\n return;\n }\n const ext = action as {\n title?: unknown;\n subTitle?: unknown;\n url?: unknown;\n value?: unknown;\n icon?: unknown;\n disabled?: unknown;\n };\n if (!ext.title || typeof ext.title !== \"string\") {\n errors.push(\n `Extended action at index ${index} is missing required \"title\" property`,\n );\n }\n if (ext.subTitle !== undefined && typeof ext.subTitle !== \"string\") {\n errors.push(\n `Extended action at index ${index} subTitle must be a string`,\n );\n }\n if (ext.url !== undefined && typeof ext.url !== \"string\") {\n errors.push(`Extended action at index ${index} url must be a string`);\n }\n if (ext.value !== undefined && typeof ext.value !== \"string\") {\n errors.push(\n `Extended action at index ${index} value must be a string`,\n );\n }\n if (ext.icon !== undefined && typeof ext.icon !== \"string\") {\n errors.push(\n `Extended action at index ${index} icon must be a string`,\n );\n }\n if (ext.disabled !== undefined && typeof ext.disabled !== \"boolean\") {\n errors.push(\n `Extended action at index ${index} disabled must be a boolean`,\n );\n }\n });\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Confirm dialog validation.\n */\n\nimport type { ValidationResult, ConfirmValidationInput } from \"./types\";\n\nconst VALID_CONFIRM_VARIANTS = [\"danger\", \"warning\", \"info\"];\n\n/**\n * Validate confirm dialog options.\n */\nexport function validateConfirm(\n options: ConfirmValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation\n if (options.title === undefined || options.title === null) {\n errors.push(\"Confirm dialog title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Confirm dialog title must be a string\");\n } else if (options.title.trim() === \"\") {\n errors.push(\"Confirm dialog title cannot be empty\");\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Confirm dialog message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Confirm dialog message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Confirm dialog message cannot be empty\");\n }\n\n // Confirm text validation (optional)\n if (options.confirmText !== undefined && options.confirmText !== null) {\n if (typeof options.confirmText !== \"string\") {\n errors.push(\"Confirm dialog confirmText must be a string\");\n }\n }\n\n // Cancel text validation (optional)\n if (options.cancelText !== undefined && options.cancelText !== null) {\n if (typeof options.cancelText !== \"string\") {\n errors.push(\"Confirm dialog cancelText must be a string\");\n }\n }\n\n // Variant validation (optional)\n if (options.variant !== undefined && options.variant !== null) {\n if (\n typeof options.variant !== \"string\" ||\n !VALID_CONFIRM_VARIANTS.includes(options.variant)\n ) {\n errors.push(\n `Invalid confirm variant \"${options.variant}\". Expected: ${VALID_CONFIRM_VARIANTS.join(\" | \")}`,\n );\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Validation utility functions.\n */\n\n/**\n * Log validation errors to console with helpful formatting.\n *\n * @param method - The SDK method that failed validation\n * @param errors - Array of error messages\n */\nexport function logValidationErrors(method: string, errors: string[]): void {\n console.error(\n `[EmbeddedSDK] Validation failed for ${method}:\\n` +\n errors.map((e) => ` • ${e}`).join(\"\\n\"),\n );\n}\n","/**\n * @fileoverview Page module for navigation and resize.\n */\n\nimport { IFRAME_EVENTS } from \"../../core/events\";\nimport { postToHost } from \"../../core/messenger\";\nimport {\n validateNavigate,\n validateRedirect,\n logValidationErrors,\n} from \"../../core/validation\";\nimport { PAGE_EVENTS } from \"./events\";\nimport type { PageModule, NavToOptions } from \"./types\";\n\nexport type { PageModule, NavToOptions } from \"./types\";\n\n/**\n * Create the page module.\n *\n * @returns Page module instance\n */\nexport function createPageModule(): PageModule {\n return {\n /**\n * Navigate to a path using React Router (SPA navigation).\n */\n navigate(path: string, options?: NavToOptions): void {\n const validation = validateNavigate({ path, ...options });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.NAVIGATE, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.NAVIGATE, {\n path,\n state: options?.state,\n replace: options?.replace,\n });\n },\n\n /**\n * Redirect to a URL (full page reload).\n */\n redirect(url: string): void {\n const validation = validateRedirect({ url });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.REDIRECT, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.REDIRECT, { url });\n },\n\n /**\n * Navigate to a path - auto-detects internal vs external.\n */\n navTo(path: string, options?: NavToOptions): void {\n // External URLs use redirect\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n this.redirect(path);\n return;\n }\n\n // Internal navigation\n this.navigate(path, options);\n },\n\n /**\n * Update the iframe height.\n */\n resize(height: number): void {\n if (typeof height !== \"number\" || height < 0) {\n logValidationErrors(IFRAME_EVENTS.RESIZE, [\n \"Height must be a non-negative number\",\n ]);\n return;\n }\n postToHost(IFRAME_EVENTS.RESIZE, { height });\n },\n\n /**\n * Auto-resize iframe to content height.\n */\n autoResize(): void {\n const height = document.documentElement.scrollHeight;\n this.resize(height);\n },\n\n /**\n * Set the page title in the host document.\n */\n setTitle(title: string): void {\n if (typeof title !== \"string\" || !title.trim()) {\n logValidationErrors(PAGE_EVENTS.SET_TITLE, [\n \"Title must be a non-empty string\",\n ]);\n return;\n }\n postToHost(PAGE_EVENTS.SET_TITLE, { title });\n },\n };\n}\n","/**\n * @fileoverview Nav module for navigation actions.\n */\n\nimport { postToHost, onMessage } from \"../../core/messenger\";\nimport { validateNavAction, logValidationErrors } from \"../../core/validation\";\nimport type { NavActionClickMessage, Unsubscribe } from \"../../core/types\";\nimport { NAV_EVENTS } from \"./events\";\nimport type {\n NavModule,\n PrimaryActionConfig,\n ActionClickCallback,\n} from \"./types\";\n\nexport type { NavModule, PrimaryActionConfig } from \"./types\";\n\n/**\n * Create the nav module.\n *\n * @returns Nav module instance\n */\nexport function createNavModule(): NavModule {\n const clickCallbacks: Set<ActionClickCallback> = new Set();\n let currentOnClickCallback: (() => void) | null = null;\n let onClickUnsubscribe: Unsubscribe | null = null;\n\n // Set up listener for action click events from host\n onMessage<NavActionClickMessage>(NAV_EVENTS.ACTION_CLICK, (data) => {\n // Call the current onClick callback if set\n if (currentOnClickCallback) {\n try {\n currentOnClickCallback();\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in onClick callback:\", error);\n }\n }\n\n // Call all registered callbacks\n clickCallbacks.forEach((callback) => {\n try {\n callback(data.url, data.value);\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in action click callback:\", error);\n }\n });\n });\n\n const navModule: NavModule = {\n /**\n * Set the primary action button.\n */\n setAction(config: PrimaryActionConfig): void {\n const validation = validateNavAction(config);\n if (!validation.valid) {\n logValidationErrors(NAV_EVENTS.SET_ACTION, validation.errors);\n return;\n }\n\n // Clean up previous onClick subscription if exists\n if (onClickUnsubscribe) {\n onClickUnsubscribe();\n onClickUnsubscribe = null;\n }\n\n // Store onClick callback if provided\n if (config.onClick) {\n currentOnClickCallback = config.onClick;\n } else {\n currentOnClickCallback = null;\n }\n\n // Send message with onClick flag if callback is provided\n postToHost(NAV_EVENTS.SET_ACTION, {\n title: config.title,\n onClick: config.onClick ? true : undefined,\n value: config.value,\n subTitle: config.subTitle,\n icon: config.icon,\n disabled: config.disabled,\n extendedActions: config.extendedActions?.map((ext) => ({\n title: ext.title,\n subTitle: ext.subTitle,\n url: ext.url,\n value: ext.value,\n icon: ext.icon,\n disabled: ext.disabled,\n })),\n });\n },\n\n /**\n * Clear the primary action button.\n */\n clearAction(): void {\n // Clean up onClick callback\n if (onClickUnsubscribe) {\n onClickUnsubscribe();\n onClickUnsubscribe = null;\n }\n currentOnClickCallback = null;\n\n postToHost(NAV_EVENTS.SET_ACTION, {\n title: \"\",\n });\n },\n\n /**\n * Subscribe to action button clicks.\n */\n onActionClick(callback: ActionClickCallback): Unsubscribe {\n clickCallbacks.add(callback);\n return () => {\n clickCallbacks.delete(callback);\n };\n },\n\n // Legacy aliases\n primaryAction(config: PrimaryActionConfig): void {\n this.setAction(config);\n },\n\n clearPrimaryAction(): void {\n this.clearAction();\n },\n };\n\n return navModule;\n}\n","/**\n * @fileoverview Loading component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { UI_EVENTS } from \"../events\";\nimport type { LoadingSubModule, LoadingMode } from \"../types\";\n\n/**\n * Create the loading sub-module.\n */\nexport function createLoadingSubModule(): LoadingSubModule {\n return {\n /**\n * Show loading indicator.\n * @param mode - Display mode ('full' for full page, 'component' for inline)\n */\n show(mode: LoadingMode = \"full\"): void {\n // Note: status: false means \"show loading\" (content not ready)\n postToHost(UI_EVENTS.LOADING, { status: false, mode });\n },\n\n /**\n * Hide loading indicator.\n */\n hide(): void {\n // Note: status: true means \"hide loading\" (content ready)\n postToHost(UI_EVENTS.LOADING, { status: true, mode: \"full\" });\n },\n };\n}\n","/**\n * @fileoverview Toast notification component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { validateToast, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ToastSubModule, ToastOptions } from \"../types\";\n\n/**\n * Create the toast sub-module.\n */\nexport function createToastSubModule(): ToastSubModule {\n const showToast = (options: ToastOptions): void => {\n const validation = validateToast(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.TOAST, validation.errors);\n return;\n }\n postToHost(UI_EVENTS.TOAST, {\n type: options.type,\n message: options.message,\n duration: options.duration,\n });\n };\n\n return {\n /**\n * Show a toast notification.\n */\n show: showToast,\n\n /**\n * Show success toast.\n */\n success(message: string, duration?: number): void {\n showToast({ type: \"success\", message, duration });\n },\n\n /**\n * Show error toast.\n */\n error(message: string, duration?: number): void {\n showToast({ type: \"error\", message, duration });\n },\n\n /**\n * Show warning toast.\n */\n warning(message: string, duration?: number): void {\n showToast({ type: \"warning\", message, duration });\n },\n\n /**\n * Show info toast.\n */\n info(message: string, duration?: number): void {\n showToast({ type: \"info\", message, duration });\n },\n };\n}\n","/**\n * @fileoverview Modal component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ModalSubModule } from \"../types\";\n\n/**\n * Create the modal sub-module.\n */\nexport function createModalSubModule(): ModalSubModule {\n return {\n /**\n * Open a modal.\n */\n open(id?: string, content?: unknown): void {\n postToHost(UI_EVENTS.MODAL, {\n action: \"open\",\n id,\n content,\n });\n },\n\n /**\n * Close a modal.\n */\n close(id?: string): void {\n postToHost(UI_EVENTS.MODAL, {\n action: \"close\",\n id,\n });\n },\n };\n}\n","/**\n * @fileoverview Confirm dialog component.\n */\n\nimport { sendRequest } from \"../../../core/requests\";\nimport { validateConfirm, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ConfirmOptions, ConfirmResult } from \"../../../core/types\";\n\n/**\n * Create the confirm function.\n */\nexport function createConfirmFunction(): (\n options: ConfirmOptions,\n) => Promise<ConfirmResult> {\n return async (options: ConfirmOptions): Promise<ConfirmResult> => {\n const validation = validateConfirm(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.CONFIRM, validation.errors);\n return Promise.reject(new Error(validation.errors.join(\", \")));\n }\n\n return sendRequest<ConfirmResult>(UI_EVENTS.CONFIRM, {\n title: options.title,\n message: options.message,\n confirmText: options.confirmText ?? \"Confirm\",\n cancelText: options.cancelText ?? \"Cancel\",\n variant: options.variant ?? \"info\",\n });\n };\n}\n","/**\n * @fileoverview UI module with nested sub-modules for loading, toast, modal, and confirm.\n */\n\nimport {\n createLoadingSubModule,\n createToastSubModule,\n createModalSubModule,\n createConfirmFunction,\n} from \"./components\";\nimport type { UIModule } from \"./types\";\n\nexport type {\n UIModule,\n LoadingSubModule,\n ToastSubModule,\n ModalSubModule,\n LoadingMode,\n ToastOptions,\n ToastType,\n ModalOptions,\n ModalAction,\n} from \"./types\";\n\n/**\n * Create the UI module with nested sub-modules.\n *\n * @returns UI module instance\n */\nexport function createUIModule(): UIModule {\n return {\n loading: createLoadingSubModule(),\n toast: createToastSubModule(),\n modal: createModalSubModule(),\n confirm: createConfirmFunction(),\n };\n}\n","/**\n * @fileoverview Checkout module for checkout flow integration.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { validateCheckout, logValidationErrors } from \"../../core/validation\";\nimport { CHECKOUT_EVENTS } from \"./events\";\nimport type { CheckoutModule, CheckoutPayload } from \"./types\";\n\nexport type { CheckoutModule, CheckoutPayload } from \"./types\";\n\n/**\n * Create the checkout module.\n *\n * @returns Checkout module instance\n */\nexport function createCheckoutModule(): CheckoutModule {\n return {\n /**\n * Create/initiate a checkout.\n */\n create(payload: CheckoutPayload): void {\n const validation = validateCheckout(payload);\n if (!validation.valid) {\n logValidationErrors(CHECKOUT_EVENTS.CREATE, validation.errors);\n return;\n }\n postToHost(CHECKOUT_EVENTS.CREATE, { payload });\n },\n };\n}\n","/**\n * @fileoverview Main EmbeddedApp singleton class.\n * This is the core of the SDK that manages initialization and state.\n */\n\nimport { SDK_VERSION } from \"./constants\";\nimport { IFRAME_EVENTS, CONTEXT_EVENTS, LOG_EVENTS } from \"./events\";\nimport { UI_EVENTS } from \"../modules/ui/events\";\nimport {\n postToHost,\n waitForMessage,\n removeAllListeners,\n isInIframe,\n onMessage,\n} from \"./messenger\";\nimport type {\n InitOptions,\n EmbeddedConfig,\n EmbeddedState,\n LayoutInfo,\n ContextProvideResponse,\n ThemeChangeMessage,\n ConfirmResponseMessage,\n ModalResponseMessage,\n LogLevel,\n InitCallback,\n} from \"./types\";\nimport { handleResponse, cancelAllRequests } from \"./requests\";\n\n// Import modules\nimport { createAuthModule, type AuthModule } from \"../modules/auth\";\nimport { createPageModule, type PageModule } from \"../modules/page\";\nimport { createNavModule, type NavModule } from \"../modules/nav\";\nimport { createUIModule, type UIModule } from \"../modules/ui\";\nimport { createCheckoutModule, type CheckoutModule } from \"../modules/checkout\";\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG: EmbeddedConfig = {\n debug: false,\n initialized: false,\n};\n\n/**\n * Default layout values.\n */\nconst DEFAULT_LAYOUT: LayoutInfo = {\n theme: \"light\",\n width: 0,\n locale: \"ar\",\n currency: \"SAR\",\n};\n\n/**\n * Default state values.\n */\nconst DEFAULT_STATE: EmbeddedState = {\n ready: false,\n initializing: false,\n layout: { ...DEFAULT_LAYOUT },\n};\n\n/**\n * Theme change callback type.\n */\ntype ThemeChangeCallback = (theme: \"light\" | \"dark\") => void;\n\n/**\n * Main Embedded SDK class.\n * Provides the primary interface for third-party apps to communicate with the Salla host.\n */\nclass EmbeddedApp {\n private config: EmbeddedConfig = { ...DEFAULT_CONFIG };\n private state: EmbeddedState = { ...DEFAULT_STATE };\n private themeCallbacks: Set<ThemeChangeCallback> = new Set();\n private initCallbacks: Set<InitCallback> = new Set();\n private appReady: boolean = false;\n\n /** Auth module for token management */\n public auth: AuthModule;\n\n /** Page module for navigation and resize */\n public page: PageModule;\n\n /** Nav module for primary actions */\n public nav: NavModule;\n\n /** UI module for loading, overlay, toast, modal */\n public ui: UIModule;\n\n /** Checkout module for checkout flow */\n public checkout: CheckoutModule;\n\n constructor() {\n // Initialize modules with reference to this instance\n this.auth = createAuthModule(() => this.getState());\n this.page = createPageModule();\n this.nav = createNavModule();\n this.ui = createUIModule();\n this.checkout = createCheckoutModule();\n\n // Set up event listeners\n this.setupThemeListener();\n this.setupResponseListeners();\n }\n\n /**\n * Get current SDK state (layout info only, no token).\n */\n getState(): Readonly<EmbeddedState> {\n return {\n ready: this.state.ready,\n initializing: this.state.initializing,\n layout: { ...this.state.layout },\n };\n }\n\n /**\n * Get current SDK configuration.\n */\n getConfig(): Readonly<EmbeddedConfig> {\n return { ...this.config };\n }\n\n /**\n * Check if SDK is initialized.\n */\n isReady(): boolean {\n return this.state.ready;\n }\n\n /**\n * Log debug messages if debug mode is enabled.\n */\n private debugLog(...args: unknown[]): void {\n if (this.config.debug) {\n console.log(`[EmbeddedSDK v${SDK_VERSION}]`, ...args);\n }\n }\n\n /**\n * Log warnings.\n */\n private warn(...args: unknown[]): void {\n console.warn(`[EmbeddedSDK v${SDK_VERSION}]`, ...args);\n }\n\n /**\n * Set up listener for theme changes from host.\n */\n private setupThemeListener(): void {\n onMessage<ThemeChangeMessage>(CONTEXT_EVENTS.THEME_CHANGE, (data) => {\n this.state.layout.theme = data.theme;\n this.debugLog(\"Theme changed:\", data.theme);\n\n // Notify all theme callbacks\n this.themeCallbacks.forEach((callback) => {\n try {\n callback(data.theme);\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in theme callback:\", error);\n }\n });\n });\n }\n\n /**\n * Set up listeners for async response events from host.\n */\n private setupResponseListeners(): void {\n // Listen for confirm dialog responses\n onMessage<ConfirmResponseMessage>(UI_EVENTS.CONFIRM_RESPONSE, (data) => {\n this.debugLog(\"Received confirm response:\", data);\n handleResponse(data.requestId, { confirmed: data.confirmed });\n });\n\n // Listen for modal responses\n onMessage<ModalResponseMessage>(UI_EVENTS.MODAL_RESPONSE, (data) => {\n this.debugLog(\"Received modal response:\", data);\n handleResponse(data.requestId, data.result, data.error);\n });\n }\n\n /**\n * Subscribe to theme changes.\n *\n * @param callback - Function called when theme changes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = embedded.onThemeChange((theme) => {\n * document.body.classList.toggle('dark-mode', theme === 'dark');\n * });\n * ```\n */\n onThemeChange(callback: ThemeChangeCallback): () => void {\n this.themeCallbacks.add(callback);\n return () => {\n this.themeCallbacks.delete(callback);\n };\n }\n\n /**\n * Subscribe to init completion. If called after init, fires immediately.\n *\n * @param callback - Function called when init completes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * embedded.onInit((state) => {\n * console.log('SDK initialized with layout:', state.layout);\n * });\n * ```\n */\n onInit(callback: InitCallback): () => void {\n // If already initialized, fire immediately\n if (this.config.initialized) {\n try {\n callback(this.getState());\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in init callback:\", error);\n }\n }\n\n this.initCallbacks.add(callback);\n return () => {\n this.initCallbacks.delete(callback);\n };\n }\n\n /**\n * Send log message to host for debugging/monitoring.\n *\n * @param level - Log level (info, warn, error)\n * @param message - Log message\n * @param context - Additional context\n *\n * @example\n * ```typescript\n * embedded.log('error', 'Failed to load data', { endpoint: '/api/data' });\n * ```\n */\n log(\n level: LogLevel,\n message: string,\n context?: Record<string, unknown>,\n ): void {\n postToHost(LOG_EVENTS.LOG, {\n level,\n message,\n context,\n });\n }\n\n /**\n * Signal that the app is fully loaded and ready.\n * This removes the host's loading overlay.\n *\n * @example\n * ```typescript\n * // After verifying token and loading initial data\n * embedded.ready();\n * ```\n */\n ready(): void {\n if (this.appReady) {\n this.debugLog(\"App already signaled as ready\");\n return;\n }\n\n if (!this.config.initialized) {\n this.warn(\"Cannot signal ready before init() is called\");\n return;\n }\n\n this.appReady = true;\n postToHost(IFRAME_EVENTS.READY, {});\n this.debugLog(\"Sent ready signal to host\");\n }\n\n /**\n * Initialize the SDK and establish connection with the host.\n *\n * @param options - Initialization options (optional)\n * @returns Promise that resolves with layout info\n *\n * @example\n * ```typescript\n * const { layout } = await embedded.init({ debug: true });\n * console.log('Theme:', layout.theme);\n * console.log('Locale:', layout.locale);\n * ```\n */\n async init(options: InitOptions = {}): Promise<{ layout: LayoutInfo }> {\n // Check if already initialized\n if (this.config.initialized) {\n this.debugLog(\"Already initialized, returning current layout\");\n return { layout: { ...this.state.layout } };\n }\n\n // Check if initialization is in progress\n if (this.state.initializing) {\n this.warn(\"Initialization already in progress\");\n return this.waitForInit();\n }\n\n // Check if running in iframe\n if (!isInIframe()) {\n this.warn(\"Not running in an iframe. Some features may not work.\");\n }\n\n // Set configuration\n this.config = {\n debug: options.debug ?? false,\n initialized: false,\n };\n\n this.state.initializing = true;\n\n this.debugLog(\"Initializing SDK...\");\n\n try {\n // Send ready message to host\n postToHost(IFRAME_EVENTS.INIT, {\n height: document.documentElement.scrollHeight,\n });\n\n this.debugLog(\"Sent iframe.ready message, waiting for context...\");\n\n // Wait for host to provide context\n const response = await waitForMessage<ContextProvideResponse>(\n CONTEXT_EVENTS.PROVIDE,\n );\n\n this.debugLog(\"Received context from host:\", response);\n\n // Update state with layout data\n this.state = {\n ready: true,\n initializing: false,\n layout: {\n theme: response.layout?.theme ?? \"light\",\n width: response.layout?.width ?? 0,\n locale: response.layout?.locale ?? \"ar\",\n currency: response.layout?.currency ?? \"SAR\",\n },\n };\n\n this.config.initialized = true;\n\n this.debugLog(\"Initialization complete. Layout:\", this.state.layout);\n\n // Notify all init callbacks\n const state = this.getState();\n this.initCallbacks.forEach((callback) => {\n try {\n callback(state);\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in init callback:\", error);\n }\n });\n\n return { layout: { ...this.state.layout } };\n } catch (error) {\n this.state.initializing = false;\n this.state.ready = false;\n\n throw error;\n }\n }\n\n /**\n * Wait for initialization to complete.\n * Useful when multiple calls to init() might happen.\n */\n private waitForInit(): Promise<{ layout: LayoutInfo }> {\n return new Promise((resolve) => {\n const check = () => {\n if (this.state.ready) {\n resolve({ layout: { ...this.state.layout } });\n } else {\n setTimeout(check, 100);\n }\n };\n check();\n });\n }\n\n /**\n * Destroy the SDK instance and clean up resources.\n * Sends a destroy event to the host to navigate away from the embedded view.\n *\n * @example\n * ```typescript\n * // On auth failure or when app needs to exit\n * embedded.destroy();\n * ```\n */\n destroy(): void {\n this.debugLog(\"Destroying SDK instance\");\n\n // Send destroy event to host (navigates to app page)\n if (this.config.initialized) {\n postToHost(IFRAME_EVENTS.DESTROY, {});\n this.debugLog(\"Sent destroy event to host\");\n }\n\n // Clean up internal state\n cancelAllRequests(\"SDK destroyed\");\n removeAllListeners();\n this.themeCallbacks.clear();\n this.initCallbacks.clear();\n this.config = { ...DEFAULT_CONFIG };\n this.state = { ...DEFAULT_STATE };\n this.appReady = false;\n }\n}\n\n// Singleton instance\nlet instance: EmbeddedApp | null = null;\n\n/**\n * Get the singleton EmbeddedApp instance.\n */\nexport function getEmbeddedApp(): EmbeddedApp {\n if (!instance) {\n instance = new EmbeddedApp();\n }\n return instance;\n}\n\n/**\n * Reset the singleton (mainly for testing).\n */\nexport function resetEmbeddedApp(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n\nexport { EmbeddedApp };\n","/**\n * @fileoverview Main entry point for the Salla Embedded SDK.\n *\n * This SDK provides a communication bridge between embedded third-party apps\n * and the Salla Dashboard host.\n *\n * @example Using window global\n * ```typescript\n * await salla.embedded.init({ app_id: 'my-app' });\n * salla.embedded.ui.hideLoading();\n * ```\n *\n * @example Using ES module import\n * ```typescript\n * import { embedded } from '@salla.sa/embedded-sdk';\n * await embedded.init({ app_id: 'my-app' });\n * ```\n */\n\nimport { getEmbeddedApp, EmbeddedApp } from \"./core/EmbeddedApp\";\nimport { SDK_VERSION } from \"./core/constants\";\n\n// Re-export types\nexport type {\n InitOptions,\n EmbeddedState,\n ExtendedAction,\n ToastType,\n ModalAction,\n ConfirmOptions,\n ConfirmResult,\n ConfirmVariant,\n} from \"./core/types\";\n\n// Re-export validation types for advanced use cases\nexport type { ValidationResult } from \"./core/validation\";\n\nexport type { AuthModule } from \"./modules/auth\";\nexport type { PageModule, NavToOptions } from \"./modules/page\";\nexport type { NavModule, PrimaryActionConfig } from \"./modules/nav\";\nexport type {\n UIModule,\n LoadingMode,\n ToastOptions,\n ModalOptions,\n} from \"./modules/ui\";\nexport type { CheckoutModule, CheckoutPayload } from \"./modules/checkout\";\n\n// Export the singleton instance\nexport const embedded = getEmbeddedApp();\n\n// Export version and events\nexport const version = SDK_VERSION;\n\n// Export class for advanced use cases\nexport { EmbeddedApp };\n\n// Re-export getEmbeddedApp for advanced use cases\nexport { getEmbeddedApp, resetEmbeddedApp } from \"./core/EmbeddedApp\";\n\n// ============================================================================\n// Window Global Setup\n// ============================================================================\n\n/**\n * Salla interface extension for the embedded SDK.\n */\ninterface SallaEmbedded {\n embedded: EmbeddedApp;\n}\n\ndeclare global {\n interface Window {\n salla: SallaEmbedded & Record<string, unknown>;\n Salla: SallaEmbedded & Record<string, unknown>;\n }\n}\n\n/**\n * Set up window globals.\n * Supports both window.salla.embedded and window.Salla.embedded\n */\nif (typeof window !== \"undefined\") {\n // Initialize salla object if it doesn't exist\n window.salla = window.salla || window.Salla || {};\n window.Salla = window.salla;\n\n // Attach embedded SDK\n if (!window.salla.embedded) {\n window.salla.embedded = embedded;\n }\n if (!window.Salla.embedded) {\n window.Salla.embedded = embedded;\n }\n}\n"],"names":["EVENT_PREFIX","IFRAME_EVENTS","CONTEXT_EVENTS","LOG_EVENTS","AUTH_EVENTS","PAGE_EVENTS","NAV_EVENTS","UI_EVENTS","CHECKOUT_EVENTS","SDK_VERSION","pkg","DEFAULT_TIMEOUT","TRUSTED_DOMAINS","isTrustedOrigin","origin","hostname","domain","getParentWindow","postToHost","event","data","targetOrigin","parent","message","listeners","isListening","handleMessage","eventListeners","callback","error","wildcardListeners","startListening","onMessage","waitForMessage","timeout","resolve","reject","timer","unsubscribe","removeAllListeners","isInIframe","pendingRequests","DEFAULT_REQUEST_TIMEOUT","generateRequestId","timestamp","random","sendRequest","requestId","handleResponse","result","pending","cancelAllRequests","reason","createAuthModule","_getState","VALID_TOAST_TYPES","validateToast","options","errors","validateCheckout","payload","validateNavigate","validateRedirect","validateNavAction","action","index","ext","VALID_CONFIRM_VARIANTS","validateConfirm","logValidationErrors","method","e","createPageModule","path","validation","url","height","title","createNavModule","clickCallbacks","currentOnClickCallback","config","_a","createLoadingSubModule","mode","createToastSubModule","showToast","duration","createModalSubModule","id","content","createConfirmFunction","createUIModule","createCheckoutModule","DEFAULT_CONFIG","DEFAULT_STATE","EmbeddedApp","args","level","context","response","_b","_c","_d","state","check","exports","instance","getEmbeddedApp","resetEmbeddedApp","embedded","version"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/core/events.ts","../../src/modules/auth/events.ts","../../src/modules/page/events.ts","../../src/modules/nav/events.ts","../../src/modules/ui/events.ts","../../src/modules/checkout/events.ts","../../src/core/constants.ts","../../src/core/messenger.ts","../../src/core/requests.ts","../../src/core/api.ts","../../src/modules/auth/index.ts","../../src/core/validation/toast.ts","../../src/core/validation/checkout.ts","../../src/core/validation/navigation.ts","../../src/core/validation/nav-action.ts","../../src/core/validation/confirm.ts","../../src/core/validation/utils.ts","../../src/modules/page/index.ts","../../src/modules/nav/index.ts","../../src/modules/ui/components/loading.ts","../../src/modules/ui/components/toast.ts","../../src/modules/ui/components/modal.ts","../../src/modules/ui/components/confirm.ts","../../src/modules/ui/index.ts","../../src/modules/checkout/index.ts","../../src/core/EmbeddedApp.ts","../../src/index.ts"],"sourcesContent":["/**\n * @fileoverview Core event constants.\n * Event naming convention: `embedded::{module}.{action}`\n */\n\n/**\n * Event prefix for all embedded events.\n */\nexport const EVENT_PREFIX = \"embedded::\" as const;\n\n/**\n * Iframe lifecycle events.\n */\nexport const IFRAME_EVENTS = {\n /** Initialize handshake - iframe signals it's ready to receive context */\n INIT: `${EVENT_PREFIX}iframe.ready`,\n /** Request iframe resize */\n RESIZE: `${EVENT_PREFIX}iframe.resize`,\n /** App signals it's fully loaded and ready */\n READY: `${EVENT_PREFIX}ready`,\n /** App requests to be destroyed and navigate away */\n DESTROY: `${EVENT_PREFIX}destroy`,\n} as const;\n\n/**\n * Context events (Host → Iframe).\n */\nexport const CONTEXT_EVENTS = {\n /** Context data provision */\n PROVIDE: `${EVENT_PREFIX}context.provide`,\n /** Theme change notification */\n THEME_CHANGE: `${EVENT_PREFIX}theme.change`,\n} as const;\n\n/**\n * Log events.\n */\nexport const LOG_EVENTS = {\n /** Send log message to host */\n LOG: `${EVENT_PREFIX}log`,\n} as const;\n","/**\n * @fileoverview Authentication module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Authentication events.\n */\nexport const AUTH_EVENTS = {\n /** Request token refresh (re-renders iframe with new token) */\n REFRESH: `${EVENT_PREFIX}auth.refresh`,\n} as const;\n","/**\n * @fileoverview Page module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Page navigation events.\n */\nexport const PAGE_EVENTS = {\n /** Navigate using React Router (SPA navigation) */\n NAVIGATE: `${EVENT_PREFIX}page.navigate`,\n /** Redirect using window.location (full page reload) */\n REDIRECT: `${EVENT_PREFIX}page.redirect`,\n /** Set page title */\n SET_TITLE: `${EVENT_PREFIX}page.setTitle`,\n} as const;\n","/**\n * @fileoverview Nav module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Navigation action events.\n */\nexport const NAV_EVENTS = {\n /** Set primary action button in navbar */\n SET_ACTION: `${EVENT_PREFIX}nav.setAction`,\n /** Notification when action button is clicked (host → iframe) */\n ACTION_CLICK: `${EVENT_PREFIX}nav.actionClick`,\n} as const;\n","/**\n * @fileoverview UI module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * UI state events.\n */\nexport const UI_EVENTS = {\n /** Set loading state */\n LOADING: `${EVENT_PREFIX}ui.loading`,\n /** Show toast notification */\n TOAST: `${EVENT_PREFIX}ui.toast`,\n /** Control modal state */\n MODAL: `${EVENT_PREFIX}ui.modal`,\n /** Show confirm dialog (async request) */\n CONFIRM: `${EVENT_PREFIX}ui.confirm`,\n /** Confirm dialog response (from host) */\n CONFIRM_RESPONSE: `${EVENT_PREFIX}ui.confirm.response`,\n /** Modal response (from host) */\n MODAL_RESPONSE: `${EVENT_PREFIX}ui.modal.response`,\n} as const;\n","/**\n * @fileoverview Checkout module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Checkout events.\n */\nexport const CHECKOUT_EVENTS = {\n /** Initialize checkout flow */\n CREATE: `${EVENT_PREFIX}checkout.create`,\n} as const;\n","import pkg from \"../../package.json\" assert { type: \"json\" };\n\n/**\n * @fileoverview Constants for the Embedded SDK.\n * Re-exports all module events for backward compatibility.\n */\n\n// Re-export core events\nexport {\n EVENT_PREFIX,\n IFRAME_EVENTS,\n CONTEXT_EVENTS,\n LOG_EVENTS,\n} from \"./events\";\n\n// Re-export module events\nexport { AUTH_EVENTS } from \"../modules/auth/events\";\nexport { PAGE_EVENTS } from \"../modules/page/events\";\nexport { NAV_EVENTS } from \"../modules/nav/events\";\nexport { UI_EVENTS } from \"../modules/ui/events\";\nexport { CHECKOUT_EVENTS } from \"../modules/checkout/events\";\n\n/**\n * SDK version for debugging and compatibility checks.\n */\nexport const SDK_VERSION: string = pkg.version;\n\n/**\n * Default timeout for waiting for host responses (ms).\n */\nexport const DEFAULT_TIMEOUT = 10000;\n\n/**\n * Trusted domains for message validation.\n * The host will validate based on iframe URL, but SDK validates for host messages.\n */\nexport const TRUSTED_DOMAINS = [\n \"localhost\",\n \"merchants.workers.dev\",\n \"s.salla.sa\",\n \".salla.group\",\n \".salla.sa\",\n] as const;\n","/**\n * @fileoverview PostMessage utilities for communicating with the host.\n */\n\nimport { DEFAULT_TIMEOUT, TRUSTED_DOMAINS } from \"./constants\";\nimport type { BaseMessage, MessageCallback, Unsubscribe } from \"./types\";\n\n/**\n * Check if an origin is trusted.\n */\nfunction isTrustedOrigin(origin: string): boolean {\n try {\n const url = new URL(origin);\n const hostname = url.hostname;\n\n return TRUSTED_DOMAINS.some((domain) => {\n if (domain.startsWith(\".\")) {\n // Suffix match (e.g., \".salla.sa\" matches \"app.salla.sa\")\n return hostname.endsWith(domain) || hostname === domain.slice(1);\n }\n // Exact match\n return hostname === domain || hostname.startsWith(`${domain}:`);\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Get the parent window (host) reference.\n * Returns null if not in an iframe.\n */\nfunction getParentWindow(): Window | null {\n if (typeof window === \"undefined\") return null;\n if (window.parent === window) return null;\n return window.parent;\n}\n\n/**\n * Send a message to the host (parent window).\n *\n * @param event - The event name\n * @param data - Additional data to send with the message\n * @param targetOrigin - Target origin for security (defaults to \"*\")\n */\nexport function postToHost<T extends Record<string, unknown>>(\n event: string,\n data?: T,\n targetOrigin: string = \"*\",\n): void {\n const parent = getParentWindow();\n\n if (!parent) {\n console.warn(\"[EmbeddedSDK] Not running in an iframe, cannot post to host\");\n return;\n }\n\n const message: BaseMessage = {\n event,\n ...data,\n };\n\n parent.postMessage(message, targetOrigin);\n}\n\n/**\n * Message listener registry.\n */\nconst listeners: Map<string, Set<MessageCallback>> = new Map();\n\n/**\n * Global message handler.\n */\nlet isListening = false;\n\nfunction handleMessage(event: MessageEvent): void {\n // Validate origin in production\n if (process.env.NODE_ENV === \"production\" && !isTrustedOrigin(event.origin)) {\n return;\n }\n\n const data = event.data as BaseMessage;\n\n if (!data || typeof data.event !== \"string\") {\n return;\n }\n\n const eventListeners = listeners.get(data.event);\n if (eventListeners) {\n eventListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n console.error(`[EmbeddedSDK] Error in message handler:`, error);\n }\n });\n }\n\n // Also notify wildcard listeners\n const wildcardListeners = listeners.get(\"*\");\n if (wildcardListeners) {\n wildcardListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n console.error(`[EmbeddedSDK] Error in wildcard handler:`, error);\n }\n });\n }\n}\n\n/**\n * Start listening for messages if not already.\n */\nfunction startListening(): void {\n if (isListening || typeof window === \"undefined\") return;\n\n window.addEventListener(\"message\", handleMessage);\n isListening = true;\n}\n\n/**\n * Subscribe to messages from the host.\n *\n * @param event - The event name to listen for, or \"*\" for all events\n * @param callback - Callback function when message is received\n * @returns Unsubscribe function\n */\nexport function onMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n callback: MessageCallback<T>,\n): Unsubscribe {\n startListening();\n\n if (!listeners.has(event)) {\n listeners.set(event, new Set());\n }\n\n const eventListeners = listeners.get(event)!;\n eventListeners.add(callback as MessageCallback);\n\n return () => {\n eventListeners.delete(callback as MessageCallback);\n if (eventListeners.size === 0) {\n listeners.delete(event);\n }\n };\n}\n\n/**\n * Wait for a specific message from the host.\n *\n * @param event - The event name to wait for\n * @param timeout - Timeout in milliseconds (defaults to DEFAULT_TIMEOUT)\n * @returns Promise that resolves with the message data\n */\nexport function waitForMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n timeout: number = DEFAULT_TIMEOUT,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n unsubscribe();\n reject(new Error(`[EmbeddedSDK] Timeout waiting for \"${event}\" message`));\n }, timeout);\n\n const unsubscribe = onMessage<T>(event, (data) => {\n clearTimeout(timer);\n unsubscribe();\n resolve(data);\n });\n });\n}\n\n/**\n * Remove all message listeners.\n */\nexport function removeAllListeners(): void {\n listeners.clear();\n\n if (isListening && typeof window !== \"undefined\") {\n window.removeEventListener(\"message\", handleMessage);\n isListening = false;\n }\n}\n\n/**\n * Check if running inside an iframe.\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") return false;\n return window.parent !== window;\n}\n","/**\n * @fileoverview Request-response tracking for async operations over postMessage.\n * Enables Promise-based APIs for operations that need host responses (e.g., confirm dialogs).\n */\n\nimport { postToHost } from \"./messenger\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Pending request entry with resolve/reject functions and timeout.\n */\ninterface PendingRequest<T = unknown> {\n resolve: (value: T) => void;\n reject: (reason: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n event: string;\n}\n\n// ============================================================================\n// State\n// ============================================================================\n\n/**\n * Map of pending requests by requestId.\n */\nconst pendingRequests = new Map<string, PendingRequest>();\n\n/**\n * Default timeout for requests (30 seconds).\n */\nconst DEFAULT_REQUEST_TIMEOUT = 30000;\n\n// ============================================================================\n// Request ID Generation\n// ============================================================================\n\n/**\n * Generate a unique request ID.\n * Format: req_{timestamp}_{random}\n */\nexport function generateRequestId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 9);\n return `req_${timestamp}_${random}`;\n}\n\n// ============================================================================\n// Request/Response Functions\n// ============================================================================\n\n/**\n * Send a request to the host and return a Promise that resolves when the response is received.\n *\n * @param event - The event name to send\n * @param data - Additional data to send with the request\n * @param timeout - Timeout in milliseconds (defaults to 30000)\n * @returns Promise that resolves with the response data\n *\n * @example\n * ```typescript\n * const result = await sendRequest<{ confirmed: boolean }>(\n * 'embedded::ui.confirm',\n * { title: 'Delete?', message: 'Are you sure?' }\n * );\n * if (result.confirmed) {\n * // User confirmed\n * }\n * ```\n */\nexport function sendRequest<T>(\n event: string,\n data: Record<string, unknown> = {},\n timeout: number = DEFAULT_REQUEST_TIMEOUT,\n): Promise<T> {\n const requestId = generateRequestId();\n\n return new Promise<T>((resolve, reject) => {\n // Set up timeout\n const timer = setTimeout(() => {\n const pending = pendingRequests.get(requestId);\n if (pending) {\n pendingRequests.delete(requestId);\n reject(\n new Error(\n `[EmbeddedSDK] Request \"${event}\" timed out after ${timeout}ms`,\n ),\n );\n }\n }, timeout);\n\n // Store the pending request\n pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timer,\n event,\n });\n\n // Send the request to host\n postToHost(event, { ...data, requestId });\n });\n}\n\n/**\n * Handle a response from the host for a pending request.\n * Called by the message listener when a response event is received.\n *\n * @param requestId - The request ID from the response\n * @param result - The result data to resolve with\n * @param error - Optional error message to reject with\n *\n * @example\n * ```typescript\n * // In message listener:\n * onMessage('embedded::ui.confirm.response', (msg) => {\n * handleResponse(msg.requestId, { confirmed: msg.confirmed });\n * });\n * ```\n */\nexport function handleResponse<T = unknown>(\n requestId: string,\n result: T,\n error?: string,\n): void {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n // Request may have already timed out or been handled\n console.warn(\n `[EmbeddedSDK] Received response for unknown request: ${requestId}`,\n );\n return;\n }\n\n // Clear the timeout\n clearTimeout(pending.timeout);\n\n // Remove from pending requests\n pendingRequests.delete(requestId);\n\n // Resolve or reject the promise\n if (error) {\n pending.reject(new Error(error));\n } else {\n pending.resolve(result);\n }\n}\n\n/**\n * Check if there are any pending requests.\n * Useful for cleanup or debugging.\n */\nexport function hasPendingRequests(): boolean {\n return pendingRequests.size > 0;\n}\n\n/**\n * Get the count of pending requests.\n * Useful for debugging.\n */\nexport function getPendingRequestCount(): number {\n return pendingRequests.size;\n}\n\n/**\n * Cancel all pending requests.\n * Useful for cleanup when the SDK is being destroyed.\n *\n * @param reason - Optional reason for cancellation\n */\nexport function cancelAllRequests(reason: string = \"SDK cleanup\"): void {\n pendingRequests.forEach((pending, requestId) => {\n clearTimeout(pending.timeout);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n });\n pendingRequests.clear();\n}\n\n/**\n * Cancel a specific pending request.\n *\n * @param requestId - The request ID to cancel\n * @param reason - Optional reason for cancellation\n * @returns true if the request was found and cancelled, false otherwise\n */\nexport function cancelRequest(\n requestId: string,\n reason: string = \"Cancelled\",\n): boolean {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n return false;\n }\n\n clearTimeout(pending.timeout);\n pendingRequests.delete(requestId);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n\n return true;\n}\n","/**\n * @fileoverview API client wrapper for making requests to Salla API.\n */\n\n/**\n * Base URL for Salla API.\n */\nconst API_BASE_URL = \"https://api.salla.dev\";\n\n/**\n * Options for API requests.\n */\nexport interface ApiRequestOptions {\n /** Request method */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n /** Request headers */\n headers?: Record<string, string>;\n /** Request body */\n body?: unknown;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * API error class for handling API request failures.\n */\nexport class ApiError extends Error {\n constructor(\n message: string,\n public status?: number,\n public response?: unknown,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\n/**\n * Make a request to the Salla API.\n *\n * @param endpoint - API endpoint path (e.g., \"/exchange-authority/v1/introspect\")\n * @param options - Request options\n * @returns Promise that resolves with the response data\n * @throws {ApiError} If the request fails\n *\n * @example\n * ```typescript\n * const response = await apiRequest(\"/exchange-authority/v1/introspect\", {\n * method: \"POST\",\n * headers: { \"S-Source\": \"app-id\", \"Content-Type\": \"application/json\" },\n * body: { token: \"xxx\", env: \"prod\" }\n * });\n * ```\n */\nexport async function apiRequest<T = unknown>(\n endpoint: string,\n options: ApiRequestOptions = {},\n): Promise<T> {\n const { method = \"GET\", headers = {}, body, timeout = 30000 } = options;\n\n const url = `${API_BASE_URL}${endpoint}`;\n\n // Create AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...headers,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n let data: unknown;\n const contentType = response.headers.get(\"content-type\");\n if (contentType && contentType.includes(\"application/json\")) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n // Check if response is successful\n if (!response.ok) {\n throw new ApiError(\n `API request failed: ${response.statusText}`,\n response.status,\n data,\n );\n }\n\n return data as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new ApiError(`Request timeout after ${timeout}ms`);\n }\n throw new ApiError(`Request failed: ${error.message}`);\n }\n\n throw new ApiError(\"Unknown error occurred\");\n }\n}\n","/**\n * @fileoverview Auth module for token and authentication management.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { apiRequest } from \"../../core/api\";\nimport { AUTH_EVENTS } from \"./events\";\nimport type {\n AuthModule,\n StateGetter,\n IntrospectOptions,\n IntrospectResponse,\n} from \"./types\";\n\nexport type {\n AuthModule,\n IntrospectOptions,\n IntrospectResponse,\n} from \"./types\";\n\n/**\n * Create the auth module.\n *\n * @param _getState - Function to get current SDK state (kept for consistency)\n * @returns Auth module instance\n */\nexport function createAuthModule(_getState: StateGetter): AuthModule {\n return {\n /**\n * Get the token from the URL query parameter.\n * The token is passed to the iframe via ?token=XXX\n *\n * @example\n * ```typescript\n * const token = embedded.auth.getToken();\n * if (token) {\n * await verifyWithBackend(token);\n * }\n * ```\n */\n getToken(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"token\");\n },\n\n /**\n * Get the app ID from the URL query parameter.\n * The app ID is passed to the iframe via ?app_id=XXX\n */\n getAppId(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"app_id\");\n },\n\n /**\n * Request a token refresh from the host.\n * This will re-render the iframe with a new token URL.\n *\n * @example\n * ```typescript\n * // When token is about to expire\n * embedded.auth.refresh();\n * ```\n */\n refresh(): void {\n postToHost(AUTH_EVENTS.REFRESH, {});\n },\n\n /**\n * Introspect (verify) a short-lived token with Salla's API.\n * This method verifies the token and returns token information.\n *\n * @param options - Optional parameters (appId and token). If not provided, will be extracted from URL params.\n * @returns Promise that resolves with the introspect response\n * @throws {Error} If appId or token is missing, or if the API request fails\n *\n */\n async introspect(\n options: IntrospectOptions = {},\n ): Promise<IntrospectResponse> {\n const token = options.token ?? this.getToken();\n if (!token) {\n throw new Error(\n \"Token is required. Provide it as a parameter or in URL as ?token=XXX\",\n );\n }\n\n const appId = options.appId ?? this.getAppId();\n if (!appId) {\n throw new Error(\n \"App ID is required. Provide it as a parameter or in URL as ?app_id=XXX\",\n );\n }\n\n const response = await apiRequest<IntrospectResponse>(\n \"/exchange-authority/v1/introspect\",\n {\n method: \"POST\",\n headers: {\n \"S-Source\": appId,\n \"Content-Type\": \"application/json\",\n },\n body: {\n env: \"prod\",\n token,\n iss: \"merchant-dashboard\",\n subject: \"embedded-page\",\n },\n },\n );\n\n return response;\n },\n };\n}\n","/**\n * @fileoverview Toast notification validation.\n */\n\nimport type { ToastType } from \"../types\";\nimport type { ValidationResult, ToastValidationInput } from \"./types\";\n\nconst VALID_TOAST_TYPES: ToastType[] = [\"success\", \"error\", \"warning\", \"info\"];\n\n/**\n * Validate toast notification options.\n */\nexport function validateToast(options: ToastValidationInput): ValidationResult {\n const errors: string[] = [];\n\n // Type validation\n if (options.type === undefined || options.type === null) {\n errors.push(\"Toast type is required\");\n } else if (\n typeof options.type !== \"string\" ||\n !VALID_TOAST_TYPES.includes(options.type as ToastType)\n ) {\n errors.push(\n `Invalid toast type \"${options.type}\". Expected: ${VALID_TOAST_TYPES.join(\" | \")}`,\n );\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Toast message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Toast message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Toast message cannot be empty\");\n }\n\n // Duration validation (optional)\n if (options.duration !== undefined && options.duration !== null) {\n if (typeof options.duration !== \"number\") {\n errors.push(\"Toast duration must be a number\");\n } else if (options.duration < 0) {\n errors.push(\"Toast duration cannot be negative\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Checkout payload validation.\n */\n\nimport type { ValidationResult, CheckoutValidationInput } from \"./types\";\n\n/**\n * Validate checkout payload.\n */\nexport function validateCheckout(\n payload: CheckoutValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n if (typeof payload !== \"object\" || payload === null) {\n errors.push(\"Checkout payload must be an object\");\n return { valid: false, errors };\n }\n\n // Amount validation (optional but if provided must be valid)\n if (payload.amount !== undefined && payload.amount !== null) {\n if (typeof payload.amount !== \"number\") {\n errors.push(\"Checkout amount must be a number\");\n } else if (payload.amount < 0) {\n errors.push(\"Checkout amount cannot be negative\");\n }\n }\n\n // Currency validation (optional but if provided must be valid)\n if (payload.currency !== undefined && payload.currency !== null) {\n if (typeof payload.currency !== \"string\") {\n errors.push(\"Checkout currency must be a string\");\n } else if (payload.currency.trim() === \"\") {\n errors.push(\"Checkout currency cannot be empty\");\n }\n }\n\n // Items validation (optional but if provided must be array)\n if (payload.items !== undefined && payload.items !== null) {\n if (!Array.isArray(payload.items)) {\n errors.push(\"Checkout items must be an array\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Page navigation and redirect validation.\n */\n\nimport type {\n ValidationResult,\n NavigateValidationInput,\n RedirectValidationInput,\n} from \"./types\";\n\n/**\n * Validate page navigation options.\n */\nexport function validateNavigate(\n options: NavigateValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Path validation\n if (options.path === undefined || options.path === null) {\n errors.push(\"Navigation path is required\");\n } else if (typeof options.path !== \"string\") {\n errors.push(\"Navigation path must be a string\");\n } else if (options.path.trim() === \"\") {\n errors.push(\"Navigation path cannot be empty\");\n }\n\n // Replace validation (optional)\n if (options.replace !== undefined && typeof options.replace !== \"boolean\") {\n errors.push(\"Navigation replace option must be a boolean\");\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Validate page redirect options.\n */\nexport function validateRedirect(\n options: RedirectValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // URL validation\n if (options.url === undefined || options.url === null) {\n errors.push(\"Redirect URL is required\");\n } else if (typeof options.url !== \"string\") {\n errors.push(\"Redirect URL must be a string\");\n } else if (options.url.trim() === \"\") {\n errors.push(\"Redirect URL cannot be empty\");\n } else {\n // Validate URL format\n try {\n new URL(options.url);\n } catch {\n errors.push(`Invalid redirect URL: \"${options.url}\"`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Nav action validation.\n */\n\nimport type { ValidationResult, NavActionValidationInput } from \"./types\";\n\n/**\n * Validate nav action options.\n */\nexport function validateNavAction(\n options: NavActionValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation (required)\n if (options.title === undefined || options.title === null) {\n errors.push(\"Nav action title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Nav action title must be a string\");\n }\n\n // onClick validation (optional, should be a function)\n if (options.onClick !== undefined && options.onClick !== null) {\n if (typeof options.onClick !== \"function\") {\n errors.push(\"Nav action onClick must be a function\");\n }\n }\n\n // Value validation (optional)\n if (options.value !== undefined && options.value !== null) {\n if (typeof options.value !== \"string\") {\n errors.push(\"Nav action value must be a string\");\n }\n }\n\n // subTitle validation (optional)\n if (options.subTitle !== undefined && options.subTitle !== null) {\n if (typeof options.subTitle !== \"string\") {\n errors.push(\"Nav action subTitle must be a string\");\n }\n }\n\n // icon validation (optional)\n if (options.icon !== undefined && options.icon !== null) {\n if (typeof options.icon !== \"string\") {\n errors.push(\"Nav action icon must be a string\");\n }\n }\n\n // disabled validation (optional)\n if (options.disabled !== undefined && options.disabled !== null) {\n if (typeof options.disabled !== \"boolean\") {\n errors.push(\"Nav action disabled must be a boolean\");\n }\n }\n\n // Extended actions validation (optional)\n if (\n options.extendedActions !== undefined &&\n options.extendedActions !== null\n ) {\n if (!Array.isArray(options.extendedActions)) {\n errors.push(\"Nav action extendedActions must be an array\");\n } else {\n options.extendedActions.forEach((action: unknown, index: number) => {\n if (typeof action !== \"object\" || action === null) {\n errors.push(`Extended action at index ${index} must be an object`);\n return;\n }\n const ext = action as {\n title?: unknown;\n subTitle?: unknown;\n url?: unknown;\n value?: unknown;\n icon?: unknown;\n disabled?: unknown;\n };\n if (!ext.title || typeof ext.title !== \"string\") {\n errors.push(\n `Extended action at index ${index} is missing required \"title\" property`,\n );\n }\n if (ext.subTitle !== undefined && typeof ext.subTitle !== \"string\") {\n errors.push(\n `Extended action at index ${index} subTitle must be a string`,\n );\n }\n if (ext.url !== undefined && typeof ext.url !== \"string\") {\n errors.push(`Extended action at index ${index} url must be a string`);\n }\n if (ext.value !== undefined && typeof ext.value !== \"string\") {\n errors.push(\n `Extended action at index ${index} value must be a string`,\n );\n }\n if (ext.icon !== undefined && typeof ext.icon !== \"string\") {\n errors.push(\n `Extended action at index ${index} icon must be a string`,\n );\n }\n if (ext.disabled !== undefined && typeof ext.disabled !== \"boolean\") {\n errors.push(\n `Extended action at index ${index} disabled must be a boolean`,\n );\n }\n });\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Confirm dialog validation.\n */\n\nimport type { ValidationResult, ConfirmValidationInput } from \"./types\";\n\nconst VALID_CONFIRM_VARIANTS = [\"danger\", \"warning\", \"info\"];\n\n/**\n * Validate confirm dialog options.\n */\nexport function validateConfirm(\n options: ConfirmValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation\n if (options.title === undefined || options.title === null) {\n errors.push(\"Confirm dialog title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Confirm dialog title must be a string\");\n } else if (options.title.trim() === \"\") {\n errors.push(\"Confirm dialog title cannot be empty\");\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Confirm dialog message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Confirm dialog message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Confirm dialog message cannot be empty\");\n }\n\n // Confirm text validation (optional)\n if (options.confirmText !== undefined && options.confirmText !== null) {\n if (typeof options.confirmText !== \"string\") {\n errors.push(\"Confirm dialog confirmText must be a string\");\n }\n }\n\n // Cancel text validation (optional)\n if (options.cancelText !== undefined && options.cancelText !== null) {\n if (typeof options.cancelText !== \"string\") {\n errors.push(\"Confirm dialog cancelText must be a string\");\n }\n }\n\n // Variant validation (optional)\n if (options.variant !== undefined && options.variant !== null) {\n if (\n typeof options.variant !== \"string\" ||\n !VALID_CONFIRM_VARIANTS.includes(options.variant)\n ) {\n errors.push(\n `Invalid confirm variant \"${options.variant}\". Expected: ${VALID_CONFIRM_VARIANTS.join(\" | \")}`,\n );\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Validation utility functions.\n */\n\n/**\n * Log validation errors to console with helpful formatting.\n *\n * @param method - The SDK method that failed validation\n * @param errors - Array of error messages\n */\nexport function logValidationErrors(method: string, errors: string[]): void {\n console.error(\n `[EmbeddedSDK] Validation failed for ${method}:\\n` +\n errors.map((e) => ` • ${e}`).join(\"\\n\"),\n );\n}\n","/**\n * @fileoverview Page module for navigation and resize.\n */\n\nimport { IFRAME_EVENTS } from \"../../core/events\";\nimport { postToHost } from \"../../core/messenger\";\nimport {\n validateNavigate,\n validateRedirect,\n logValidationErrors,\n} from \"../../core/validation\";\nimport { PAGE_EVENTS } from \"./events\";\nimport type { PageModule, NavToOptions } from \"./types\";\n\nexport type { PageModule, NavToOptions } from \"./types\";\n\n/**\n * Create the page module.\n *\n * @returns Page module instance\n */\nexport function createPageModule(): PageModule {\n return {\n /**\n * Navigate to a path using React Router (SPA navigation).\n */\n navigate(path: string, options?: NavToOptions): void {\n const validation = validateNavigate({ path, ...options });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.NAVIGATE, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.NAVIGATE, {\n path,\n state: options?.state,\n replace: options?.replace,\n });\n },\n\n /**\n * Redirect to a URL (full page reload).\n */\n redirect(url: string): void {\n const validation = validateRedirect({ url });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.REDIRECT, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.REDIRECT, { url });\n },\n\n /**\n * Navigate to a path - auto-detects internal vs external.\n */\n navTo(path: string, options?: NavToOptions): void {\n // External URLs use redirect\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n this.redirect(path);\n return;\n }\n\n // Internal navigation\n this.navigate(path, options);\n },\n\n /**\n * Update the iframe height.\n */\n resize(height: number): void {\n if (typeof height !== \"number\" || height < 0) {\n logValidationErrors(IFRAME_EVENTS.RESIZE, [\n \"Height must be a non-negative number\",\n ]);\n return;\n }\n postToHost(IFRAME_EVENTS.RESIZE, { height });\n },\n\n /**\n * Auto-resize iframe to content height.\n */\n autoResize(): void {\n const height = document.documentElement.scrollHeight;\n this.resize(height);\n },\n\n /**\n * Set the page title in the host document.\n */\n setTitle(title: string): void {\n if (typeof title !== \"string\" || !title.trim()) {\n logValidationErrors(PAGE_EVENTS.SET_TITLE, [\n \"Title must be a non-empty string\",\n ]);\n return;\n }\n postToHost(PAGE_EVENTS.SET_TITLE, { title });\n },\n };\n}\n","/**\n * @fileoverview Nav module for navigation actions.\n */\n\nimport { postToHost, onMessage } from \"../../core/messenger\";\nimport { validateNavAction, logValidationErrors } from \"../../core/validation\";\nimport type { NavActionClickMessage, Unsubscribe } from \"../../core/types\";\nimport { NAV_EVENTS } from \"./events\";\nimport type {\n NavModule,\n PrimaryActionConfig,\n ActionClickCallback,\n} from \"./types\";\n\nexport type { NavModule, PrimaryActionConfig } from \"./types\";\n\n/**\n * Create the nav module.\n *\n * @returns Nav module instance\n */\nexport function createNavModule(): NavModule {\n const clickCallbacks = new Set<ActionClickCallback>();\n let currentOnClickCallback: (() => void) | null = null;\n let onClickUnsubscribe: Unsubscribe | null = null;\n\n // Set up listener for action click events from host\n onMessage<NavActionClickMessage>(NAV_EVENTS.ACTION_CLICK, (data) => {\n // Call the current onClick callback if set\n if (currentOnClickCallback) {\n try {\n currentOnClickCallback();\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in onClick callback:\", error);\n }\n }\n\n // Call all registered callbacks\n clickCallbacks.forEach((callback) => {\n try {\n callback(data.url, data.value);\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in action click callback:\", error);\n }\n });\n });\n\n const navModule: NavModule = {\n /**\n * Set the primary action button.\n */\n setAction(config: PrimaryActionConfig): void {\n const validation = validateNavAction(config);\n if (!validation.valid) {\n logValidationErrors(NAV_EVENTS.SET_ACTION, validation.errors);\n return;\n }\n\n // Clean up previous onClick subscription if exists\n if (onClickUnsubscribe) {\n onClickUnsubscribe();\n onClickUnsubscribe = null;\n }\n\n // Store onClick callback if provided\n if (config.onClick) {\n currentOnClickCallback = config.onClick;\n } else {\n currentOnClickCallback = null;\n }\n\n // Send message with onClick flag if callback is provided\n postToHost(NAV_EVENTS.SET_ACTION, {\n title: config.title,\n onClick: config.onClick ? true : undefined,\n value: config.value,\n subTitle: config.subTitle,\n icon: config.icon,\n disabled: config.disabled,\n extendedActions: config.extendedActions?.map((ext) => ({\n title: ext.title,\n subTitle: ext.subTitle,\n url: ext.url,\n value: ext.value,\n icon: ext.icon,\n disabled: ext.disabled,\n })),\n });\n },\n\n /**\n * Clear the primary action button.\n */\n clearAction(): void {\n // Clean up onClick callback\n if (onClickUnsubscribe) {\n onClickUnsubscribe();\n onClickUnsubscribe = null;\n }\n currentOnClickCallback = null;\n\n postToHost(NAV_EVENTS.SET_ACTION, {\n title: \"\",\n });\n },\n\n /**\n * Subscribe to action button clicks.\n */\n onActionClick(callback: ActionClickCallback): Unsubscribe {\n clickCallbacks.add(callback);\n return () => {\n clickCallbacks.delete(callback);\n };\n },\n\n // Legacy aliases\n primaryAction(config: PrimaryActionConfig): void {\n this.setAction(config);\n },\n\n clearPrimaryAction(): void {\n this.clearAction();\n },\n };\n\n return navModule;\n}\n","/**\n * @fileoverview Loading component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { UI_EVENTS } from \"../events\";\nimport type { LoadingSubModule, LoadingMode } from \"../types\";\n\n/**\n * Create the loading sub-module.\n */\nexport function createLoadingSubModule(): LoadingSubModule {\n return {\n /**\n * Show loading indicator.\n * @param mode - Display mode ('full' for full page, 'component' for inline)\n */\n show(mode: LoadingMode = \"full\"): void {\n // Note: status: false means \"show loading\" (content not ready)\n postToHost(UI_EVENTS.LOADING, { status: false, mode });\n },\n\n /**\n * Hide loading indicator.\n */\n hide(): void {\n // Note: status: true means \"hide loading\" (content ready)\n postToHost(UI_EVENTS.LOADING, { status: true, mode: \"full\" });\n },\n };\n}\n","/**\n * @fileoverview Toast notification component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { validateToast, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ToastSubModule, ToastOptions } from \"../types\";\n\n/**\n * Create the toast sub-module.\n */\nexport function createToastSubModule(): ToastSubModule {\n const showToast = (options: ToastOptions): void => {\n const validation = validateToast(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.TOAST, validation.errors);\n return;\n }\n postToHost(UI_EVENTS.TOAST, {\n type: options.type,\n message: options.message,\n duration: options.duration,\n });\n };\n\n return {\n /**\n * Show a toast notification.\n */\n show: showToast,\n\n /**\n * Show success toast.\n */\n success(message: string, duration?: number): void {\n showToast({ type: \"success\", message, duration });\n },\n\n /**\n * Show error toast.\n */\n error(message: string, duration?: number): void {\n showToast({ type: \"error\", message, duration });\n },\n\n /**\n * Show warning toast.\n */\n warning(message: string, duration?: number): void {\n showToast({ type: \"warning\", message, duration });\n },\n\n /**\n * Show info toast.\n */\n info(message: string, duration?: number): void {\n showToast({ type: \"info\", message, duration });\n },\n };\n}\n","/**\n * @fileoverview Modal component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ModalSubModule } from \"../types\";\n\n/**\n * Create the modal sub-module.\n */\nexport function createModalSubModule(): ModalSubModule {\n return {\n /**\n * Open a modal.\n */\n open(id?: string, content?: unknown): void {\n postToHost(UI_EVENTS.MODAL, {\n action: \"open\",\n id,\n content,\n });\n },\n\n /**\n * Close a modal.\n */\n close(id?: string): void {\n postToHost(UI_EVENTS.MODAL, {\n action: \"close\",\n id,\n });\n },\n };\n}\n","/**\n * @fileoverview Confirm dialog component.\n */\n\nimport { sendRequest } from \"../../../core/requests\";\nimport { validateConfirm, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ConfirmOptions, ConfirmResult } from \"../../../core/types\";\n\n/**\n * Create the confirm function.\n */\nexport function createConfirmFunction(): (\n options: ConfirmOptions,\n) => Promise<ConfirmResult> {\n return async (options: ConfirmOptions): Promise<ConfirmResult> => {\n const validation = validateConfirm(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.CONFIRM, validation.errors);\n return Promise.reject(new Error(validation.errors.join(\", \")));\n }\n\n return sendRequest<ConfirmResult>(UI_EVENTS.CONFIRM, {\n title: options.title,\n message: options.message,\n confirmText: options.confirmText ?? \"Confirm\",\n cancelText: options.cancelText ?? \"Cancel\",\n variant: options.variant ?? \"info\",\n });\n };\n}\n","/**\n * @fileoverview UI module with nested sub-modules for loading, toast, modal, and confirm.\n */\n\nimport {\n createLoadingSubModule,\n createToastSubModule,\n createModalSubModule,\n createConfirmFunction,\n} from \"./components\";\nimport type { UIModule } from \"./types\";\n\nexport type {\n UIModule,\n LoadingSubModule,\n ToastSubModule,\n ModalSubModule,\n LoadingMode,\n ToastOptions,\n ToastType,\n ModalOptions,\n ModalAction,\n} from \"./types\";\n\n/**\n * Create the UI module with nested sub-modules.\n *\n * @returns UI module instance\n */\nexport function createUIModule(): UIModule {\n return {\n loading: createLoadingSubModule(),\n toast: createToastSubModule(),\n modal: createModalSubModule(),\n confirm: createConfirmFunction(),\n };\n}\n","/**\n * @fileoverview Checkout module for checkout flow integration.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { validateCheckout, logValidationErrors } from \"../../core/validation\";\nimport { CHECKOUT_EVENTS } from \"./events\";\nimport type { CheckoutModule, CheckoutPayload } from \"./types\";\n\nexport type { CheckoutModule, CheckoutPayload } from \"./types\";\n\n/**\n * Create the checkout module.\n *\n * @returns Checkout module instance\n */\nexport function createCheckoutModule(): CheckoutModule {\n return {\n /**\n * Create/initiate a checkout.\n */\n create(payload: CheckoutPayload): void {\n const validation = validateCheckout(payload);\n if (!validation.valid) {\n logValidationErrors(CHECKOUT_EVENTS.CREATE, validation.errors);\n return;\n }\n postToHost(CHECKOUT_EVENTS.CREATE, { payload });\n },\n };\n}\n","/**\n * @fileoverview Main EmbeddedApp singleton class.\n * This is the core of the SDK that manages initialization and state.\n */\n\nimport { SDK_VERSION } from \"./constants\";\nimport { IFRAME_EVENTS, CONTEXT_EVENTS, LOG_EVENTS } from \"./events\";\nimport { UI_EVENTS } from \"../modules/ui/events\";\nimport {\n postToHost,\n waitForMessage,\n removeAllListeners,\n isInIframe,\n onMessage,\n} from \"./messenger\";\nimport type {\n InitOptions,\n EmbeddedConfig,\n EmbeddedState,\n LayoutInfo,\n ContextProvideResponse,\n ThemeChangeMessage,\n ConfirmResponseMessage,\n ModalResponseMessage,\n LogLevel,\n InitCallback,\n} from \"./types\";\nimport { handleResponse, cancelAllRequests } from \"./requests\";\n\n// Import modules\nimport { createAuthModule, type AuthModule } from \"../modules/auth\";\nimport { createPageModule, type PageModule } from \"../modules/page\";\nimport { createNavModule, type NavModule } from \"../modules/nav\";\nimport { createUIModule, type UIModule } from \"../modules/ui\";\nimport { createCheckoutModule, type CheckoutModule } from \"../modules/checkout\";\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG: EmbeddedConfig = {\n debug: false,\n initialized: false,\n};\n\n/**\n * Default layout values.\n */\nconst DEFAULT_LAYOUT: LayoutInfo = {\n theme: \"light\",\n width: 0,\n locale: \"ar\",\n currency: \"SAR\",\n};\n\n/**\n * Default state values.\n */\nconst DEFAULT_STATE: EmbeddedState = {\n ready: false,\n initializing: false,\n layout: { ...DEFAULT_LAYOUT },\n};\n\n/**\n * Theme change callback type.\n */\ntype ThemeChangeCallback = (theme: \"light\" | \"dark\") => void;\n\n/**\n * Main Embedded SDK class.\n * Provides the primary interface for third-party apps to communicate with the Salla host.\n */\nclass EmbeddedApp {\n private config: EmbeddedConfig = { ...DEFAULT_CONFIG };\n private state: EmbeddedState = { ...DEFAULT_STATE };\n private themeCallbacks: Set<ThemeChangeCallback> = new Set();\n private initCallbacks: Set<InitCallback> = new Set();\n private appReady: boolean = false;\n\n /** Auth module for token management */\n public auth: AuthModule;\n\n /** Page module for navigation and resize */\n public page: PageModule;\n\n /** Nav module for primary actions */\n public nav: NavModule;\n\n /** UI module for loading, overlay, toast, modal */\n public ui: UIModule;\n\n /** Checkout module for checkout flow */\n public checkout: CheckoutModule;\n\n constructor() {\n // Initialize modules with reference to this instance\n this.auth = createAuthModule(() => this.getState());\n this.page = createPageModule();\n this.nav = createNavModule();\n this.ui = createUIModule();\n this.checkout = createCheckoutModule();\n\n // Set up event listeners\n this.setupThemeListener();\n this.setupResponseListeners();\n }\n\n /**\n * Get current SDK state (layout info only, no token).\n */\n getState(): Readonly<EmbeddedState> {\n return {\n ready: this.state.ready,\n initializing: this.state.initializing,\n layout: { ...this.state.layout },\n };\n }\n\n /**\n * Get current SDK configuration.\n */\n getConfig(): Readonly<EmbeddedConfig> {\n return { ...this.config };\n }\n\n /**\n * Check if SDK is initialized.\n */\n isReady(): boolean {\n return this.state.ready;\n }\n\n /**\n * Log debug messages if debug mode is enabled.\n */\n private debugLog(...args: unknown[]): void {\n if (this.config.debug) {\n console.log(`[EmbeddedSDK v${SDK_VERSION}]`, ...args);\n }\n }\n\n /**\n * Log warnings.\n */\n private warn(...args: unknown[]): void {\n console.warn(`[EmbeddedSDK v${SDK_VERSION}]`, ...args);\n }\n\n /**\n * Set up listener for theme changes from host.\n */\n private setupThemeListener(): void {\n onMessage<ThemeChangeMessage>(CONTEXT_EVENTS.THEME_CHANGE, (data) => {\n this.state.layout.theme = data.theme;\n this.debugLog(\"Theme changed:\", data.theme);\n\n // Notify all theme callbacks\n this.themeCallbacks.forEach((callback) => {\n try {\n callback(data.theme);\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in theme callback:\", error);\n }\n });\n });\n }\n\n /**\n * Set up listeners for async response events from host.\n */\n private setupResponseListeners(): void {\n // Listen for confirm dialog responses\n onMessage<ConfirmResponseMessage>(UI_EVENTS.CONFIRM_RESPONSE, (data) => {\n this.debugLog(\"Received confirm response:\", data);\n handleResponse(data.requestId, { confirmed: data.confirmed });\n });\n\n // Listen for modal responses\n onMessage<ModalResponseMessage>(UI_EVENTS.MODAL_RESPONSE, (data) => {\n this.debugLog(\"Received modal response:\", data);\n handleResponse(data.requestId, data.result, data.error);\n });\n }\n\n /**\n * Subscribe to theme changes.\n *\n * @param callback - Function called when theme changes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = embedded.onThemeChange((theme) => {\n * document.body.classList.toggle('dark-mode', theme === 'dark');\n * });\n * ```\n */\n onThemeChange(callback: ThemeChangeCallback): () => void {\n this.themeCallbacks.add(callback);\n return () => {\n this.themeCallbacks.delete(callback);\n };\n }\n\n /**\n * Subscribe to init completion. If called after init, fires immediately.\n *\n * @param callback - Function called when init completes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * embedded.onInit((state) => {\n * console.log('SDK initialized with layout:', state.layout);\n * });\n * ```\n */\n onInit(callback: InitCallback): () => void {\n // If already initialized, fire immediately\n if (this.config.initialized) {\n try {\n callback(this.getState());\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in init callback:\", error);\n }\n }\n\n this.initCallbacks.add(callback);\n return () => {\n this.initCallbacks.delete(callback);\n };\n }\n\n /**\n * Send log message to host for debugging/monitoring.\n *\n * @param level - Log level (info, warn, error)\n * @param message - Log message\n * @param context - Additional context\n *\n * @example\n * ```typescript\n * embedded.log('error', 'Failed to load data', { endpoint: '/api/data' });\n * ```\n */\n log(\n level: LogLevel,\n message: string,\n context?: Record<string, unknown>,\n ): void {\n postToHost(LOG_EVENTS.LOG, {\n level,\n message,\n context,\n });\n }\n\n /**\n * Signal that the app is fully loaded and ready.\n * This removes the host's loading overlay.\n *\n * @example\n * ```typescript\n * // After verifying token and loading initial data\n * embedded.ready();\n * ```\n */\n ready(): void {\n if (this.appReady) {\n this.debugLog(\"App already signaled as ready\");\n return;\n }\n\n if (!this.config.initialized) {\n this.warn(\"Cannot signal ready before init() is called\");\n return;\n }\n\n this.appReady = true;\n postToHost(IFRAME_EVENTS.READY, {});\n this.debugLog(\"Sent ready signal to host\");\n }\n\n /**\n * Initialize the SDK and establish connection with the host.\n *\n * @param options - Initialization options (optional)\n * @returns Promise that resolves with layout info\n *\n * @example\n * ```typescript\n * const { layout } = await embedded.init({ debug: true });\n * console.log('Theme:', layout.theme);\n * console.log('Locale:', layout.locale);\n * ```\n */\n async init(options: InitOptions = {}): Promise<{ layout: LayoutInfo }> {\n // Check if already initialized\n if (this.config.initialized) {\n this.debugLog(\"Already initialized, returning current layout\");\n return { layout: { ...this.state.layout } };\n }\n\n // Check if initialization is in progress\n if (this.state.initializing) {\n this.warn(\"Initialization already in progress\");\n return this.waitForInit();\n }\n\n // Check if running in iframe\n if (!isInIframe()) {\n this.warn(\"Not running in an iframe. Some features may not work.\");\n }\n\n // Set configuration\n this.config = {\n debug: options.debug ?? false,\n initialized: false,\n };\n\n this.state.initializing = true;\n\n this.debugLog(\"Initializing SDK...\");\n\n try {\n // Send ready message to host\n postToHost(IFRAME_EVENTS.INIT, {\n height: document.documentElement.scrollHeight,\n });\n\n this.debugLog(\"Sent iframe.ready message, waiting for context...\");\n\n // Wait for host to provide context\n const response = await waitForMessage<ContextProvideResponse>(\n CONTEXT_EVENTS.PROVIDE,\n );\n\n this.debugLog(\"Received context from host:\", response);\n\n // Update state with layout data\n this.state = {\n ready: true,\n initializing: false,\n layout: {\n theme: response.layout?.theme ?? \"light\",\n width: response.layout?.width ?? 0,\n locale: response.layout?.locale ?? \"ar\",\n currency: response.layout?.currency ?? \"SAR\",\n },\n };\n\n this.config.initialized = true;\n\n this.debugLog(\"Initialization complete. Layout:\", this.state.layout);\n\n // Notify all init callbacks\n const state = this.getState();\n this.initCallbacks.forEach((callback) => {\n try {\n callback(state);\n } catch (error) {\n console.error(\"[EmbeddedSDK] Error in init callback:\", error);\n }\n });\n\n return { layout: { ...this.state.layout } };\n } catch (error) {\n this.state.initializing = false;\n this.state.ready = false;\n\n throw error;\n }\n }\n\n /**\n * Wait for initialization to complete.\n * Useful when multiple calls to init() might happen.\n */\n private waitForInit(): Promise<{ layout: LayoutInfo }> {\n return new Promise((resolve) => {\n const unsubscribe = this.onInit((state) => {\n unsubscribe();\n resolve({ layout: { ...state.layout } });\n });\n });\n }\n\n /**\n * Destroy the SDK instance and clean up resources.\n * Sends a destroy event to the host to navigate away from the embedded view.\n *\n * @example\n * ```typescript\n * // On auth failure or when app needs to exit\n * embedded.destroy();\n * ```\n */\n destroy(): void {\n this.debugLog(\"Destroying SDK instance\");\n\n // Send destroy event to host (navigates to app page)\n if (this.config.initialized) {\n postToHost(IFRAME_EVENTS.DESTROY, {});\n this.debugLog(\"Sent destroy event to host\");\n }\n\n // Clean up internal state\n cancelAllRequests(\"SDK destroyed\");\n removeAllListeners();\n this.themeCallbacks.clear();\n this.initCallbacks.clear();\n this.config = { ...DEFAULT_CONFIG };\n this.state = { ...DEFAULT_STATE };\n this.appReady = false;\n }\n}\n\n// Singleton instance\nlet instance: EmbeddedApp | null = null;\n\n/**\n * Get the singleton EmbeddedApp instance.\n */\nexport function getEmbeddedApp(): EmbeddedApp {\n if (!instance) {\n instance = new EmbeddedApp();\n }\n return instance;\n}\n\n/**\n * Reset the singleton (mainly for testing).\n */\nexport function resetEmbeddedApp(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n\nexport { EmbeddedApp };\n","/**\n * @fileoverview Main entry point for the Salla Embedded SDK.\n *\n * This SDK provides a communication bridge between embedded third-party apps\n * and the Salla Dashboard host.\n *\n * @example Using window global\n * ```typescript\n * await salla.embedded.init({ app_id: 'my-app' });\n * salla.embedded.ui.hideLoading();\n * ```\n *\n * @example Using ES module import\n * ```typescript\n * import { embedded } from '@salla.sa/embedded-sdk';\n * await embedded.init({ app_id: 'my-app' });\n * ```\n */\n\nimport { getEmbeddedApp, EmbeddedApp } from \"./core/EmbeddedApp\";\nimport { SDK_VERSION } from \"./core/constants\";\n\n// Re-export types\nexport type {\n InitOptions,\n EmbeddedState,\n ExtendedAction,\n ToastType,\n ModalAction,\n ConfirmOptions,\n ConfirmResult,\n ConfirmVariant,\n} from \"./core/types\";\n\n// Re-export validation types for advanced use cases\nexport type { ValidationResult } from \"./core/validation\";\n\nexport type { AuthModule } from \"./modules/auth\";\nexport type { PageModule, NavToOptions } from \"./modules/page\";\nexport type { NavModule, PrimaryActionConfig } from \"./modules/nav\";\nexport type {\n UIModule,\n LoadingMode,\n ToastOptions,\n ModalOptions,\n} from \"./modules/ui\";\nexport type { CheckoutModule, CheckoutPayload } from \"./modules/checkout\";\n\n// Export the singleton instance\nexport const embedded = getEmbeddedApp();\n\n// Export version and events\nexport const version = SDK_VERSION;\n\n// Export class for advanced use cases\nexport { EmbeddedApp };\n\n// Re-export getEmbeddedApp for advanced use cases\nexport { getEmbeddedApp, resetEmbeddedApp } from \"./core/EmbeddedApp\";\n\n// ============================================================================\n// Window Global Setup\n// ============================================================================\n\n/**\n * Salla interface extension for the embedded SDK.\n */\ninterface SallaEmbedded {\n embedded: EmbeddedApp;\n}\n\ndeclare global {\n interface Window {\n salla: SallaEmbedded & Record<string, unknown>;\n Salla: SallaEmbedded & Record<string, unknown>;\n }\n}\n\n/**\n * Set up window globals.\n * Supports both window.salla.embedded and window.Salla.embedded\n */\nif (typeof window !== \"undefined\") {\n // Initialize salla object if it doesn't exist\n window.salla = window.salla || window.Salla || {};\n window.Salla = window.salla;\n\n // Attach embedded SDK\n if (!window.salla.embedded) {\n window.salla.embedded = embedded;\n }\n if (!window.Salla.embedded) {\n window.Salla.embedded = embedded;\n }\n}\n"],"names":["EVENT_PREFIX","IFRAME_EVENTS","CONTEXT_EVENTS","LOG_EVENTS","AUTH_EVENTS","PAGE_EVENTS","NAV_EVENTS","UI_EVENTS","CHECKOUT_EVENTS","SDK_VERSION","pkg","DEFAULT_TIMEOUT","TRUSTED_DOMAINS","isTrustedOrigin","origin","hostname","domain","getParentWindow","postToHost","event","data","targetOrigin","parent","message","listeners","isListening","handleMessage","eventListeners","callback","error","wildcardListeners","startListening","onMessage","waitForMessage","timeout","resolve","reject","timer","unsubscribe","removeAllListeners","isInIframe","pendingRequests","DEFAULT_REQUEST_TIMEOUT","generateRequestId","timestamp","random","sendRequest","requestId","handleResponse","result","pending","cancelAllRequests","reason","API_BASE_URL","ApiError","status","response","apiRequest","endpoint","options","method","headers","body","url","controller","timeoutId","contentType","createAuthModule","_getState","token","appId","VALID_TOAST_TYPES","validateToast","errors","validateCheckout","payload","validateNavigate","validateRedirect","validateNavAction","action","index","ext","VALID_CONFIRM_VARIANTS","validateConfirm","logValidationErrors","e","createPageModule","path","validation","height","title","createNavModule","clickCallbacks","currentOnClickCallback","config","_a","createLoadingSubModule","mode","createToastSubModule","showToast","duration","createModalSubModule","id","content","createConfirmFunction","createUIModule","createCheckoutModule","DEFAULT_CONFIG","DEFAULT_STATE","EmbeddedApp","args","level","context","_b","_c","_d","state","exports","instance","getEmbeddedApp","resetEmbeddedApp","embedded","version"],"mappings":"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"}
package/dist/umd/index.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(u,T){typeof exports=="object"&&typeof module<"u"?T(exports):typeof define=="function"&&define.amd?define(["exports"],T):(u=typeof globalThis<"u"?globalThis:u||self,T(u.SallaEmbeddedSDK={}))})(this,function(u){"use strict";const _={version:"0.1.0-beta.4"},s="embedded::",E={INIT:`${s}iframe.ready`,RESIZE:`${s}iframe.resize`,READY:`${s}ready`,DESTROY:`${s}destroy`},S={PROVIDE:`${s}context.provide`,THEME_CHANGE:`${s}theme.change`},M={LOG:`${s}log`},x={REFRESH:`${s}auth.refresh`},m={NAVIGATE:`${s}page.navigate`,REDIRECT:`${s}page.redirect`,SET_TITLE:`${s}page.setTitle`},y={SET_ACTION:`${s}nav.setAction`,ACTION_CLICK:`${s}nav.actionClick`},d={LOADING:`${s}ui.loading`,TOAST:`${s}ui.toast`,MODAL:`${s}ui.modal`,CONFIRM:`${s}ui.confirm`,CONFIRM_RESPONSE:`${s}ui.confirm.response`,MODAL_RESPONSE:`${s}ui.modal.response`},A={CREATE:`${s}checkout.create`},p=_.version,K=1e4,z=["localhost","merchants.workers.dev","s.salla.sa",".salla.group",".salla.sa"];function U(e){try{const n=new URL(e).hostname;return z.some(i=>i.startsWith(".")?n.endsWith(i)||n===i.slice(1):n===i||n.startsWith(`${i}:`))}catch{return!1}}function V(){return typeof window>"u"||window.parent===window?null:window.parent}function a(e,t,n="*"){const i=V();if(!i){console.warn("[EmbeddedSDK] Not running in an iframe, cannot post to host");return}const r={event:e,...t};i.postMessage(r,n)}const f=new Map;let v=!1;function C(e){if(process.env.NODE_ENV==="production"&&!U(e.origin))return;const t=e.data;if(!t||typeof t.event!="string")return;const n=f.get(t.event);n&&n.forEach(r=>{try{r(t)}catch(l){console.error("[EmbeddedSDK] Error in message handler:",l)}});const i=f.get("*");i&&i.forEach(r=>{try{r(t)}catch(l){console.error("[EmbeddedSDK] Error in wildcard handler:",l)}})}function F(){v||typeof window>"u"||(window.addEventListener("message",C),v=!0)}function b(e,t){F(),f.has(e)||f.set(e,new Set);const n=f.get(e);return n.add(t),()=>{n.delete(t),n.size===0&&f.delete(e)}}function P(e,t=K){return new Promise((n,i)=>{const r=setTimeout(()=>{l(),i(new Error(`[EmbeddedSDK] Timeout waiting for "${e}" message`))},t),l=b(e,o=>{clearTimeout(r),l(),n(o)})})}function q(){f.clear(),v&&typeof window<"u"&&(window.removeEventListener("message",C),v=!1)}function G(){return typeof window>"u"?!1:window.parent!==window}const h=new Map,j=3e4;function H(){const e=Date.now(),t=Math.random().toString(36).slice(2,9);return`req_${e}_${t}`}function Y(e,t={},n=j){const i=H();return new Promise((r,l)=>{const o=setTimeout(()=>{h.get(i)&&(h.delete(i),l(new Error(`[EmbeddedSDK] Request "${e}" timed out after ${n}ms`)))},n);h.set(i,{resolve:r,reject:l,timeout:o,event:e}),a(e,{...t,requestId:i})})}function R(e,t,n){const i=h.get(e);if(!i){console.warn(`[EmbeddedSDK] Received response for unknown request: ${e}`);return}clearTimeout(i.timeout),h.delete(e),n?i.reject(new Error(n)):i.resolve(t)}function W(e="SDK cleanup"){h.forEach((t,n)=>{clearTimeout(t.timeout),t.reject(new Error(`[EmbeddedSDK] Request ${n} cancelled: ${e}`))}),h.clear()}function Z(e){return{getToken(){return new URLSearchParams(window.location.search).get("token")},refresh(){a(x.REFRESH,{})}}}const I=["success","error","warning","info"];function X(e){const t=[];return e.type===void 0||e.type===null?t.push("Toast type is required"):(typeof e.type!="string"||!I.includes(e.type))&&t.push(`Invalid toast type "${e.type}". Expected: ${I.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 Q(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 B(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 J(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 ee(e){const t=[];return e.title===void 0||e.title===null?t.push("Nav action title is required"):typeof e.title!="string"&&t.push("Nav action title must be a string"),e.onClick!==void 0&&e.onClick!==null&&typeof e.onClick!="function"&&t.push("Nav action onClick must be a function"),e.value!==void 0&&e.value!==null&&typeof e.value!="string"&&t.push("Nav action value must be a string"),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((n,i)=>{if(typeof n!="object"||n===null){t.push(`Extended action at index ${i} must be an object`);return}const r=n;(!r.title||typeof r.title!="string")&&t.push(`Extended action at index ${i} is missing required "title" property`),r.subTitle!==void 0&&typeof r.subTitle!="string"&&t.push(`Extended action at index ${i} subTitle must be a string`),r.url!==void 0&&typeof r.url!="string"&&t.push(`Extended action at index ${i} url must be a string`),r.value!==void 0&&typeof r.value!="string"&&t.push(`Extended action at index ${i} value must be a string`),r.icon!==void 0&&typeof r.icon!="string"&&t.push(`Extended action at index ${i} icon must be a string`),r.disabled!==void 0&&typeof r.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 L=["danger","warning","info"];function te(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"||!L.includes(e.variant))&&t.push(`Invalid confirm variant "${e.variant}". Expected: ${L.join(" | ")}`),{valid:t.length===0,errors:t}}function c(e,t){console.error(`[EmbeddedSDK] Validation failed for ${e}:
2
- `+t.map(n=>` • ${n}`).join(`
3
- `))}function ie(){return{navigate(e,t){const n=B({path:e,...t});if(!n.valid){c(m.NAVIGATE,n.errors);return}a(m.NAVIGATE,{path:e,state:t==null?void 0:t.state,replace:t==null?void 0:t.replace})},redirect(e){const t=J({url:e});if(!t.valid){c(m.REDIRECT,t.errors);return}a(m.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){c(E.RESIZE,["Height must be a non-negative number"]);return}a(E.RESIZE,{height:e})},autoResize(){const e=document.documentElement.scrollHeight;this.resize(e)},setTitle(e){if(typeof e!="string"||!e.trim()){c(m.SET_TITLE,["Title must be a non-empty string"]);return}a(m.SET_TITLE,{title:e})}}}function ne(){const e=new Set;let t=null;return b(y.ACTION_CLICK,i=>{if(t)try{t()}catch(r){console.error("[EmbeddedSDK] Error in onClick callback:",r)}e.forEach(r=>{try{r(i.url,i.value)}catch(l){console.error("[EmbeddedSDK] Error in action click callback:",l)}})}),{setAction(i){var l;const r=ee(i);if(!r.valid){c(y.SET_ACTION,r.errors);return}i.onClick?t=i.onClick:t=null,a(y.SET_ACTION,{title:i.title,onClick:i.onClick?!0:void 0,value:i.value,subTitle:i.subTitle,icon:i.icon,disabled:i.disabled,extendedActions:(l=i.extendedActions)==null?void 0:l.map(o=>({title:o.title,subTitle:o.subTitle,url:o.url,value:o.value,icon:o.icon,disabled:o.disabled}))})},clearAction(){t=null,a(y.SET_ACTION,{title:""})},onActionClick(i){return e.add(i),()=>{e.delete(i)}},primaryAction(i){this.setAction(i)},clearPrimaryAction(){this.clearAction()}}}function re(){return{show(e="full"){a(d.LOADING,{status:!1,mode:e})},hide(){a(d.LOADING,{status:!0,mode:"full"})}}}function se(){const e=t=>{const n=X(t);if(!n.valid){c(d.TOAST,n.errors);return}a(d.TOAST,{type:t.type,message:t.message,duration:t.duration})};return{show:e,success(t,n){e({type:"success",message:t,duration:n})},error(t,n){e({type:"error",message:t,duration:n})},warning(t,n){e({type:"warning",message:t,duration:n})},info(t,n){e({type:"info",message:t,duration:n})}}}function ae(){return{open(e,t){a(d.MODAL,{action:"open",id:e,content:t})},close(e){a(d.MODAL,{action:"close",id:e})}}}function oe(){return async e=>{const t=te(e);return t.valid?Y(d.CONFIRM,{title:e.title,message:e.message,confirmText:e.confirmText??"Confirm",cancelText:e.cancelText??"Cancel",variant:e.variant??"info"}):(c(d.CONFIRM,t.errors),Promise.reject(new Error(t.errors.join(", "))))}}function le(){return{loading:re(),toast:se(),modal:ae(),confirm:oe()}}function ue(){return{create(e){const t=Q(e);if(!t.valid){c(A.CREATE,t.errors);return}a(A.CREATE,{payload:e})}}}const N={debug:!1,initialized:!1},D={ready:!1,initializing:!1,layout:{...{theme:"light",width:0,locale:"ar",currency:"SAR"}}};class O{constructor(){this.config={...N},this.state={...D},this.themeCallbacks=new Set,this.initCallbacks=new Set,this.appReady=!1,this.auth=Z(),this.page=ie(),this.nav=ne(),this.ui=le(),this.checkout=ue(),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}debugLog(...t){this.config.debug&&console.log(`[EmbeddedSDK v${p}]`,...t)}warn(...t){console.warn(`[EmbeddedSDK v${p}]`,...t)}setupThemeListener(){b(S.THEME_CHANGE,t=>{this.state.layout.theme=t.theme,this.debugLog("Theme changed:",t.theme),this.themeCallbacks.forEach(n=>{try{n(t.theme)}catch(i){console.error("[EmbeddedSDK] Error in theme callback:",i)}})})}setupResponseListeners(){b(d.CONFIRM_RESPONSE,t=>{this.debugLog("Received confirm response:",t),R(t.requestId,{confirmed:t.confirmed})}),b(d.MODAL_RESPONSE,t=>{this.debugLog("Received modal response:",t),R(t.requestId,t.result,t.error)})}onThemeChange(t){return this.themeCallbacks.add(t),()=>{this.themeCallbacks.delete(t)}}onInit(t){if(this.config.initialized)try{t(this.getState())}catch(n){console.error("[EmbeddedSDK] Error in init callback:",n)}return this.initCallbacks.add(t),()=>{this.initCallbacks.delete(t)}}log(t,n,i){a(M.LOG,{level:t,message:n,context:i})}ready(){if(this.appReady){this.debugLog("App already signaled as ready");return}if(!this.config.initialized){this.warn("Cannot signal ready before init() is called");return}this.appReady=!0,a(E.READY,{}),this.debugLog("Sent ready signal to host")}async init(t={}){var n,i,r,l;if(this.config.initialized)return this.debugLog("Already initialized, returning current layout"),{layout:{...this.state.layout}};if(this.state.initializing)return this.warn("Initialization already in progress"),this.waitForInit();G()||this.warn("Not running in an iframe. Some features may not work."),this.config={debug:t.debug??!1,initialized:!1},this.state.initializing=!0,this.debugLog("Initializing SDK...");try{a(E.INIT,{height:document.documentElement.scrollHeight}),this.debugLog("Sent iframe.ready message, waiting for context...");const o=await P(S.PROVIDE);this.debugLog("Received context from host:",o),this.state={ready:!0,initializing:!1,layout:{theme:((n=o.layout)==null?void 0:n.theme)??"light",width:((i=o.layout)==null?void 0:i.width)??0,locale:((r=o.layout)==null?void 0:r.locale)??"ar",currency:((l=o.layout)==null?void 0:l.currency)??"SAR"}},this.config.initialized=!0,this.debugLog("Initialization complete. Layout:",this.state.layout);const k=this.getState();return this.initCallbacks.forEach(fe=>{try{fe(k)}catch(he){console.error("[EmbeddedSDK] Error in init callback:",he)}}),{layout:{...this.state.layout}}}catch(o){throw this.state.initializing=!1,this.state.ready=!1,o}}waitForInit(){return new Promise(t=>{const n=()=>{this.state.ready?t({layout:{...this.state.layout}}):setTimeout(n,100)};n()})}destroy(){this.debugLog("Destroying SDK instance"),this.config.initialized&&(a(E.DESTROY,{}),this.debugLog("Sent destroy event to host")),W("SDK destroyed"),q(),this.themeCallbacks.clear(),this.initCallbacks.clear(),this.config={...N},this.state={...D},this.appReady=!1}}let g=null;function $(){return g||(g=new O),g}function de(){g&&(g.destroy(),g=null)}const w=$(),ce=p;typeof window<"u"&&(window.salla=window.salla||window.Salla||{},window.Salla=window.salla,window.salla.embedded||(window.salla.embedded=w),window.Salla.embedded||(window.Salla.embedded=w)),u.EmbeddedApp=O,u.embedded=w,u.getEmbeddedApp=$,u.resetEmbeddedApp=de,u.version=ce,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,v){typeof exports=="object"&&typeof module<"u"?v(exports):typeof define=="function"&&define.amd?define(["exports"],v):(d=typeof globalThis<"u"?globalThis:d||self,v(d.SallaEmbeddedSDK={}))})(this,function(d){"use strict";const P={version:"0.1.0-beta.5"},s="embedded::",b={INIT:`${s}iframe.ready`,RESIZE:`${s}iframe.resize`,READY:`${s}ready`,DESTROY:`${s}destroy`},L={PROVIDE:`${s}context.provide`,THEME_CHANGE:`${s}theme.change`},q={LOG:`${s}log`},z={REFRESH:`${s}auth.refresh`},g={NAVIGATE:`${s}page.navigate`,REDIRECT:`${s}page.redirect`,SET_TITLE:`${s}page.setTitle`},w={SET_ACTION:`${s}nav.setAction`,ACTION_CLICK:`${s}nav.actionClick`},c={LOADING:`${s}ui.loading`,TOAST:`${s}ui.toast`,MODAL:`${s}ui.modal`,CONFIRM:`${s}ui.confirm`,CONFIRM_RESPONSE:`${s}ui.confirm.response`,MODAL_RESPONSE:`${s}ui.modal.response`},N={CREATE:`${s}checkout.create`},R=P.version,V=1e4,F=["localhost","merchants.workers.dev","s.salla.sa",".salla.group",".salla.sa"];function j(t){try{const n=new URL(t).hostname;return F.some(i=>i.startsWith(".")?n.endsWith(i)||n===i.slice(1):n===i||n.startsWith(`${i}:`))}catch{return!1}}function G(){return typeof window>"u"||window.parent===window?null:window.parent}function l(t,e,n="*"){const i=G();if(!i){console.warn("[EmbeddedSDK] Not running in an iframe, cannot post to host");return}const r={event:t,...e};i.postMessage(r,n)}const h=new Map;let S=!1;function D(t){if(process.env.NODE_ENV==="production"&&!j(t.origin))return;const e=t.data;if(!e||typeof e.event!="string")return;const n=h.get(e.event);n&&n.forEach(r=>{try{r(e)}catch(a){console.error("[EmbeddedSDK] Error in message handler:",a)}});const i=h.get("*");i&&i.forEach(r=>{try{r(e)}catch(a){console.error("[EmbeddedSDK] Error in wildcard handler:",a)}})}function H(){S||typeof window>"u"||(window.addEventListener("message",D),S=!0)}function T(t,e){H(),h.has(t)||h.set(t,new Set);const n=h.get(t);return n.add(e),()=>{n.delete(e),n.size===0&&h.delete(t)}}function X(t,e=V){return new Promise((n,i)=>{const r=setTimeout(()=>{a(),i(new Error(`[EmbeddedSDK] Timeout waiting for "${t}" message`))},e),a=T(t,o=>{clearTimeout(r),a(),n(o)})})}function Y(){h.clear(),S&&typeof window<"u"&&(window.removeEventListener("message",D),S=!1)}function W(){return typeof window>"u"?!1:window.parent!==window}const m=new Map,Z=3e4;function B(){const t=Date.now(),e=Math.random().toString(36).slice(2,9);return`req_${t}_${e}`}function J(t,e={},n=Z){const i=B();return new Promise((r,a)=>{const o=setTimeout(()=>{m.get(i)&&(m.delete(i),a(new Error(`[EmbeddedSDK] Request "${t}" timed out after ${n}ms`)))},n);m.set(i,{resolve:r,reject:a,timeout:o,event:t}),l(t,{...e,requestId:i})})}function $(t,e,n){const i=m.get(t);if(!i){console.warn(`[EmbeddedSDK] Received response for unknown request: ${t}`);return}clearTimeout(i.timeout),m.delete(t),n?i.reject(new Error(n)):i.resolve(e)}function Q(t="SDK cleanup"){m.forEach((e,n)=>{clearTimeout(e.timeout),e.reject(new Error(`[EmbeddedSDK] Request ${n} cancelled: ${t}`))}),m.clear()}const ee="https://api.salla.dev";class p extends Error{constructor(e,n,i){super(e),this.status=n,this.response=i,this.name="ApiError"}}async function te(t,e={}){const{method:n="GET",headers:i={},body:r,timeout:a=3e4}=e,o=`${ee}${t}`,y=new AbortController,A=setTimeout(()=>y.abort(),a);try{const u=await fetch(o,{method:n,headers:{"Content-Type":"application/json",...i},body:r?JSON.stringify(r):void 0,signal:y.signal});clearTimeout(A);let C;const K=u.headers.get("content-type");if(K&&K.includes("application/json")?C=await u.json():C=await u.text(),!u.ok)throw new p(`API request failed: ${u.statusText}`,u.status,C);return C}catch(u){throw clearTimeout(A),u instanceof p?u:u instanceof Error?u.name==="AbortError"?new p(`Request timeout after ${a}ms`):new p(`Request failed: ${u.message}`):new p("Unknown error occurred")}}function ie(t){return{getToken(){return new URLSearchParams(window.location.search).get("token")},getAppId(){return new URLSearchParams(window.location.search).get("app_id")},refresh(){l(z.REFRESH,{})},async introspect(e={}){const n=e.token??this.getToken();if(!n)throw new Error("Token is required. Provide it as a parameter or in URL as ?token=XXX");const i=e.appId??this.getAppId();if(!i)throw new Error("App ID is required. Provide it as a parameter or in URL as ?app_id=XXX");return await te("/exchange-authority/v1/introspect",{method:"POST",headers:{"S-Source":i,"Content-Type":"application/json"},body:{env:"prod",token:n,iss:"merchant-dashboard",subject:"embedded-page"}})}}}const O=["success","error","warning","info"];function ne(t){const e=[];return t.type===void 0||t.type===null?e.push("Toast type is required"):(typeof t.type!="string"||!O.includes(t.type))&&e.push(`Invalid toast type "${t.type}". Expected: ${O.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 re(t){const e=[];return typeof t!="object"||t===null?(e.push("Checkout payload must be an object"),{valid:!1,errors:e}):(t.amount!==void 0&&t.amount!==null&&(typeof t.amount!="number"?e.push("Checkout amount must be a number"):t.amount<0&&e.push("Checkout amount cannot be negative")),t.currency!==void 0&&t.currency!==null&&(typeof t.currency!="string"?e.push("Checkout currency must be a string"):t.currency.trim()===""&&e.push("Checkout currency cannot be empty")),t.items!==void 0&&t.items!==null&&(Array.isArray(t.items)||e.push("Checkout items must be an array")),{valid:e.length===0,errors:e})}function se(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 ae(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 oe(t){const e=[];return t.title===void 0||t.title===null?e.push("Nav action title is required"):typeof t.title!="string"&&e.push("Nav action title must be a string"),t.onClick!==void 0&&t.onClick!==null&&typeof t.onClick!="function"&&e.push("Nav action onClick must be a function"),t.value!==void 0&&t.value!==null&&typeof t.value!="string"&&e.push("Nav action value must be a string"),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((n,i)=>{if(typeof n!="object"||n===null){e.push(`Extended action at index ${i} must be an object`);return}const r=n;(!r.title||typeof r.title!="string")&&e.push(`Extended action at index ${i} is missing required "title" property`),r.subTitle!==void 0&&typeof r.subTitle!="string"&&e.push(`Extended action at index ${i} subTitle must be a string`),r.url!==void 0&&typeof r.url!="string"&&e.push(`Extended action at index ${i} url must be a string`),r.value!==void 0&&typeof r.value!="string"&&e.push(`Extended action at index ${i} value must be a string`),r.icon!==void 0&&typeof r.icon!="string"&&e.push(`Extended action at index ${i} icon must be a string`),r.disabled!==void 0&&typeof r.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 k=["danger","warning","info"];function le(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"||!k.includes(t.variant))&&e.push(`Invalid confirm variant "${t.variant}". Expected: ${k.join(" | ")}`),{valid:e.length===0,errors:e}}function f(t,e){console.error(`[EmbeddedSDK] Validation failed for ${t}:
2
+ `+e.map(n=>` • ${n}`).join(`
3
+ `))}function ue(){return{navigate(t,e){const n=se({path:t,...e});if(!n.valid){f(g.NAVIGATE,n.errors);return}l(g.NAVIGATE,{path:t,state:e==null?void 0:e.state,replace:e==null?void 0:e.replace})},redirect(t){const e=ae({url:t});if(!e.valid){f(g.REDIRECT,e.errors);return}l(g.REDIRECT,{url:t})},navTo(t,e){if(t.startsWith("http://")||t.startsWith("https://")){this.redirect(t);return}this.navigate(t,e)},resize(t){if(typeof t!="number"||t<0){f(b.RESIZE,["Height must be a non-negative number"]);return}l(b.RESIZE,{height:t})},autoResize(){const t=document.documentElement.scrollHeight;this.resize(t)},setTitle(t){if(typeof t!="string"||!t.trim()){f(g.SET_TITLE,["Title must be a non-empty string"]);return}l(g.SET_TITLE,{title:t})}}}function de(){const t=new Set;let e=null;return T(w.ACTION_CLICK,i=>{if(e)try{e()}catch(r){console.error("[EmbeddedSDK] Error in onClick callback:",r)}t.forEach(r=>{try{r(i.url,i.value)}catch(a){console.error("[EmbeddedSDK] Error in action click callback:",a)}})}),{setAction(i){var a;const r=oe(i);if(!r.valid){f(w.SET_ACTION,r.errors);return}i.onClick?e=i.onClick:e=null,l(w.SET_ACTION,{title:i.title,onClick:i.onClick?!0:void 0,value:i.value,subTitle:i.subTitle,icon:i.icon,disabled:i.disabled,extendedActions:(a=i.extendedActions)==null?void 0:a.map(o=>({title:o.title,subTitle:o.subTitle,url:o.url,value:o.value,icon:o.icon,disabled:o.disabled}))})},clearAction(){e=null,l(w.SET_ACTION,{title:""})},onActionClick(i){return t.add(i),()=>{t.delete(i)}},primaryAction(i){this.setAction(i)},clearPrimaryAction(){this.clearAction()}}}function ce(){return{show(t="full"){l(c.LOADING,{status:!1,mode:t})},hide(){l(c.LOADING,{status:!0,mode:"full"})}}}function fe(){const t=e=>{const n=ne(e);if(!n.valid){f(c.TOAST,n.errors);return}l(c.TOAST,{type:e.type,message:e.message,duration:e.duration})};return{show:t,success(e,n){t({type:"success",message:e,duration:n})},error(e,n){t({type:"error",message:e,duration:n})},warning(e,n){t({type:"warning",message:e,duration:n})},info(e,n){t({type:"info",message:e,duration:n})}}}function he(){return{open(t,e){l(c.MODAL,{action:"open",id:t,content:e})},close(t){l(c.MODAL,{action:"close",id:t})}}}function me(){return async t=>{const e=le(t);return e.valid?J(c.CONFIRM,{title:t.title,message:t.message,confirmText:t.confirmText??"Confirm",cancelText:t.cancelText??"Cancel",variant:t.variant??"info"}):(f(c.CONFIRM,e.errors),Promise.reject(new Error(e.errors.join(", "))))}}function ge(){return{loading:ce(),toast:fe(),modal:he(),confirm:me()}}function Ee(){return{create(t){const e=re(t);if(!e.valid){f(N.CREATE,e.errors);return}l(N.CREATE,{payload:t})}}}const _={debug:!1,initialized:!1},M={ready:!1,initializing:!1,layout:{...{theme:"light",width:0,locale:"ar",currency:"SAR"}}};class x{constructor(){this.config={..._},this.state={...M},this.themeCallbacks=new Set,this.initCallbacks=new Set,this.appReady=!1,this.auth=ie(),this.page=ue(),this.nav=de(),this.ui=ge(),this.checkout=Ee(),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}debugLog(...e){this.config.debug&&console.log(`[EmbeddedSDK v${R}]`,...e)}warn(...e){console.warn(`[EmbeddedSDK v${R}]`,...e)}setupThemeListener(){T(L.THEME_CHANGE,e=>{this.state.layout.theme=e.theme,this.debugLog("Theme changed:",e.theme),this.themeCallbacks.forEach(n=>{try{n(e.theme)}catch(i){console.error("[EmbeddedSDK] Error in theme callback:",i)}})})}setupResponseListeners(){T(c.CONFIRM_RESPONSE,e=>{this.debugLog("Received confirm response:",e),$(e.requestId,{confirmed:e.confirmed})}),T(c.MODAL_RESPONSE,e=>{this.debugLog("Received modal response:",e),$(e.requestId,e.result,e.error)})}onThemeChange(e){return this.themeCallbacks.add(e),()=>{this.themeCallbacks.delete(e)}}onInit(e){if(this.config.initialized)try{e(this.getState())}catch(n){console.error("[EmbeddedSDK] Error in init callback:",n)}return this.initCallbacks.add(e),()=>{this.initCallbacks.delete(e)}}log(e,n,i){l(q.LOG,{level:e,message:n,context:i})}ready(){if(this.appReady){this.debugLog("App already signaled as ready");return}if(!this.config.initialized){this.warn("Cannot signal ready before init() is called");return}this.appReady=!0,l(b.READY,{}),this.debugLog("Sent ready signal to host")}async init(e={}){var n,i,r,a;if(this.config.initialized)return this.debugLog("Already initialized, returning current layout"),{layout:{...this.state.layout}};if(this.state.initializing)return this.warn("Initialization already in progress"),this.waitForInit();W()||this.warn("Not running in an iframe. Some features may not work."),this.config={debug:e.debug??!1,initialized:!1},this.state.initializing=!0,this.debugLog("Initializing SDK...");try{l(b.INIT,{height:document.documentElement.scrollHeight}),this.debugLog("Sent iframe.ready message, waiting for context...");const o=await X(L.PROVIDE);this.debugLog("Received context from host:",o),this.state={ready:!0,initializing:!1,layout:{theme:((n=o.layout)==null?void 0:n.theme)??"light",width:((i=o.layout)==null?void 0:i.width)??0,locale:((r=o.layout)==null?void 0:r.locale)??"ar",currency:((a=o.layout)==null?void 0:a.currency)??"SAR"}},this.config.initialized=!0,this.debugLog("Initialization complete. Layout:",this.state.layout);const y=this.getState();return this.initCallbacks.forEach(A=>{try{A(y)}catch(u){console.error("[EmbeddedSDK] Error in init callback:",u)}}),{layout:{...this.state.layout}}}catch(o){throw this.state.initializing=!1,this.state.ready=!1,o}}waitForInit(){return new Promise(e=>{const n=this.onInit(i=>{n(),e({layout:{...i.layout}})})})}destroy(){this.debugLog("Destroying SDK instance"),this.config.initialized&&(l(b.DESTROY,{}),this.debugLog("Sent destroy event to host")),Q("SDK destroyed"),Y(),this.themeCallbacks.clear(),this.initCallbacks.clear(),this.config={..._},this.state={...M},this.appReady=!1}}let E=null;function U(){return E||(E=new x),E}function be(){E&&(E.destroy(),E=null)}const I=U(),Te=R;typeof window<"u"&&(window.salla=window.salla||window.Salla||{},window.Salla=window.salla,window.salla.embedded||(window.salla.embedded=I),window.Salla.embedded||(window.Salla.embedded=I)),d.EmbeddedApp=x,d.embedded=I,d.getEmbeddedApp=U,d.resetEmbeddedApp=be,d.version=Te,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
4
4
  //# sourceMappingURL=index.js.map