@commercengine/js 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -76,7 +76,11 @@ interface CheckoutConfig {
76
76
  onClose?: () => void;
77
77
  onComplete?: (order: OrderData) => void;
78
78
  onCartUpdate?: (cart: CartData) => void;
79
- onAuthChange?: (auth: AuthChangeData) => void;
79
+ onLogin?: (data: AuthLoginData) => void;
80
+ onLogout?: (data: AuthLogoutData) => void;
81
+ onTokenRefresh?: (data: AuthRefreshData) => void;
82
+ onSessionError?: () => void;
83
+ onError?: (error: ErrorData) => void;
80
84
  }
81
85
  ```
82
86
 
@@ -102,13 +106,18 @@ const checkout = await Commercengine.init({
102
106
  onCartUpdate: (cart) => {
103
107
  updateCartBadge(cart.count);
104
108
  },
105
- onAuthChange: ({ type, accessToken }) => {
106
- if (type === "login") {
107
- // User logged in via checkout - sync to your auth system
108
- saveUserSession(accessToken);
109
- } else if (type === "logout") {
110
- clearUserSession();
111
- }
109
+ onLogin: ({ accessToken, user, loginMethod }) => {
110
+ // User logged in via checkout - sync to your auth system
111
+ console.log("User logged in via", loginMethod, ":", user?.email || user?.phone);
112
+ saveUserSession(accessToken);
113
+ },
114
+ onLogout: () => {
115
+ // User logged out - they now have anonymous tokens
116
+ clearUserSession();
117
+ },
118
+ onSessionError: () => {
119
+ // Session corrupted - SDK cleared all tokens, user needs to re-authenticate
120
+ clearUserSession();
112
121
  },
113
122
  });
114
123
  ```
@@ -214,7 +223,11 @@ Subscribe via callbacks (in config) or the event emitter.
214
223
  | `close` | `onClose` | - | All drawers closed |
215
224
  | `complete` | `onComplete` | `OrderData` | Order placed successfully |
216
225
  | `cart:updated` | `onCartUpdate` | `CartData` | Cart state changed |
217
- | `auth:change` | `onAuthChange` | `AuthChangeData` | Auth state changed |
226
+ | `auth:login` | `onLogin` | `AuthLoginData` | User logged in |
227
+ | `auth:logout` | `onLogout` | `AuthLogoutData` | User logged out |
228
+ | `auth:refresh` | `onTokenRefresh` | `AuthRefreshData` | Tokens auto-refreshed |
229
+ | `auth:session-error` | `onSessionError` | - | Session corrupted, tokens cleared |
230
+ | `error` | `onError` | `ErrorData` | Configuration error |
218
231
 
219
232
  ### Event Data Types
220
233
 
@@ -230,10 +243,52 @@ interface CartData {
230
243
  currency: string; // Currency code (e.g., "USD", "INR")
231
244
  }
232
245
 
233
- interface AuthChangeData {
234
- type: "login" | "logout" | "refresh";
235
- accessToken?: string; // New token (on login/refresh)
236
- refreshToken?: string; // New refresh token
246
+ interface AuthLoginData {
247
+ accessToken: string;
248
+ refreshToken?: string;
249
+ user?: UserInfo;
250
+ loginMethod?: LoginMethod;
251
+ }
252
+
253
+ interface AuthLogoutData {
254
+ accessToken: string; // New anonymous token
255
+ refreshToken?: string;
256
+ user?: UserInfo; // Anonymous user info
257
+ }
258
+
259
+ interface AuthRefreshData {
260
+ accessToken: string;
261
+ refreshToken?: string;
262
+ }
263
+
264
+ interface ErrorData {
265
+ message: string;
266
+ }
267
+
268
+ type LoginMethod = "whatsapp" | "phone" | "email";
269
+
270
+ interface Channel {
271
+ id: string;
272
+ name: string;
273
+ type: string;
274
+ }
275
+
276
+ interface UserInfo {
277
+ id: string;
278
+ email: string | null;
279
+ phone: string | null;
280
+ username: string;
281
+ firstName: string | null;
282
+ lastName: string | null;
283
+ storeId: string;
284
+ isLoggedIn: boolean;
285
+ isAnonymous: boolean;
286
+ customerId: string | null;
287
+ customerGroupId: string | null;
288
+ anonymousId: string;
289
+ channel: Channel;
290
+ tokenExpiry: Date;
291
+ tokenIssuedAt: Date;
237
292
  }
238
293
  ```
239
294
 
@@ -266,11 +321,9 @@ User will be prompted to login within checkout (WhatsApp, Phone, or Email OTP).
266
321
  const checkout = await Commercengine.init({
267
322
  storeId: "store_xxx",
268
323
  apiKey: "ak_xxx",
269
- onAuthChange: ({ type, accessToken, refreshToken }) => {
270
- if (type === "login") {
271
- // Save tokens to your auth system
272
- saveSession({ accessToken, refreshToken });
273
- }
324
+ onLogin: ({ accessToken, refreshToken }) => {
325
+ // Save tokens to your auth system
326
+ saveSession({ accessToken, refreshToken });
274
327
  },
275
328
  });
276
329
  ```
@@ -317,7 +370,13 @@ import {
317
370
  type Environment,
318
371
  type CartData,
319
372
  type OrderData,
320
- type AuthChangeData,
373
+ type AuthLoginData,
374
+ type AuthLogoutData,
375
+ type AuthRefreshData,
376
+ type ErrorData,
377
+ type UserInfo,
378
+ type Channel,
379
+ type LoginMethod,
321
380
  } from "@commercengine/js";
322
381
  ```
323
382
 
package/dist/index.cjs CHANGED
@@ -75,6 +75,7 @@ var IframeManager = class {
75
75
  `;
76
76
  this.iframe = document.createElement("iframe");
77
77
  this.iframe.id = "commercengine-checkout-iframe";
78
+ this.iframe.title = "Shopping cart and checkout";
78
79
  this.iframe.src = url;
79
80
  this.iframe.allow = "payment";
80
81
  this.iframe.style.cssText = `
@@ -274,19 +275,16 @@ var Checkout = class extends EventEmitter {
274
275
  this.handleCartUpdate(data);
275
276
  break;
276
277
  case "auth:login":
277
- this.handleAuthChange({
278
- type: "login",
279
- ...data
280
- });
278
+ this.handleLogin(data);
281
279
  break;
282
280
  case "auth:logout":
283
- this.handleAuthChange({ type: "logout" });
281
+ this.handleLogout(data);
284
282
  break;
285
283
  case "auth:refresh":
286
- this.handleAuthChange({
287
- type: "refresh",
288
- ...data
289
- });
284
+ this.handleTokenRefresh(data);
285
+ break;
286
+ case "auth:session-error":
287
+ this.handleSessionError();
290
288
  break;
291
289
  }
292
290
  }
@@ -322,9 +320,21 @@ var Checkout = class extends EventEmitter {
322
320
  this.config.onCartUpdate?.(data);
323
321
  this.emit("cart:updated", data);
324
322
  }
325
- handleAuthChange(data) {
326
- this.config.onAuthChange?.(data);
327
- this.emit("auth:change", data);
323
+ handleLogin(data) {
324
+ this.config.onLogin?.(data);
325
+ this.emit("auth:login", data);
326
+ }
327
+ handleLogout(data) {
328
+ this.config.onLogout?.(data);
329
+ this.emit("auth:logout", data);
330
+ }
331
+ handleTokenRefresh(data) {
332
+ this.config.onTokenRefresh?.(data);
333
+ this.emit("auth:refresh", data);
334
+ }
335
+ handleSessionError() {
336
+ this.config.onSessionError?.();
337
+ this.emit("auth:session-error");
328
338
  }
329
339
  /**
330
340
  * Open the cart drawer
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["onceListener: EventListener<T>","CHECKOUT_URLS: Record<Environment, string>","baseUrl: string","Commercengine: CommercengineGlobal"],"sources":["../src/events.ts","../src/iframe-manager.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":["/**\n * Simple Event Emitter\n *\n * Provides pub/sub functionality for checkout events.\n */\n\nimport type { CheckoutEventType, EventListener } from \"./types\";\n\nexport class EventEmitter {\n private listeners: Map<CheckoutEventType, Set<EventListener>> = new Map();\n\n /**\n * Subscribe to an event\n */\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)?.add(listener as EventListener);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener);\n }\n }\n\n /**\n * Subscribe to an event (once)\n */\n once<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const onceListener: EventListener<T> = (data) => {\n this.off(event, onceListener);\n listener(data);\n };\n this.on(event, onceListener);\n }\n\n /**\n * Emit an event to all subscribers\n */\n protected emit<T = unknown>(event: CheckoutEventType, data?: T): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(`[Commercengine] Error in ${event} listener:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners\n */\n protected removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * Iframe Manager\n *\n * Handles iframe creation, lifecycle, and visibility management.\n * The iframe is pre-mounted (hidden) on init and shown on demand.\n */\n\nimport type { OutgoingEventType } from \"./types\";\n\nexport class IframeManager {\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLDivElement | null = null;\n private checkoutOrigin: string | null = null;\n\n /**\n * Create and mount the iframe (hidden initially)\n */\n create(url: string, zIndex: number): void {\n if (this.container) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Iframe already created\");\n return;\n }\n\n // Store origin for postMessage security\n this.checkoutOrigin = new URL(url).origin;\n\n // Create container (covers viewport, initially non-interactive)\n this.container = document.createElement(\"div\");\n this.container.id = \"commercengine-checkout\";\n this.container.style.cssText = `\n position: fixed;\n inset: 0;\n z-index: ${zIndex};\n pointer-events: none;\n `;\n\n // Create iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"commercengine-checkout-iframe\";\n this.iframe.src = url;\n this.iframe.allow = \"payment\";\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n pointer-events: inherit;\n background-color: transparent;\n `;\n\n this.container.appendChild(this.iframe);\n document.body.appendChild(this.container);\n }\n\n /**\n * Show the checkout overlay (enable pointer events)\n */\n show(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"auto\";\n document.body.style.overflow = \"hidden\";\n }\n }\n\n /**\n * Hide the checkout overlay (disable pointer events)\n */\n hide(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"none\";\n document.body.style.overflow = \"\";\n }\n }\n\n /**\n * Check if iframe is visible\n */\n isVisible(): boolean {\n return this.container?.style.pointerEvents === \"auto\";\n }\n\n /**\n * Send a message to the checkout iframe\n */\n postMessage(type: OutgoingEventType, data?: unknown): void {\n if (!this.iframe?.contentWindow) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Cannot send message - iframe not ready\");\n return;\n }\n\n // Use specific origin for security - never use \"*\"\n if (!this.checkoutOrigin) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for security\n console.warn(\"[Commercengine] Cannot send message - checkout origin not established\");\n return;\n }\n this.iframe.contentWindow.postMessage({ type, data }, this.checkoutOrigin);\n }\n\n /**\n * Get the checkout origin for message validation\n */\n getCheckoutOrigin(): string | null {\n return this.checkoutOrigin;\n }\n\n /**\n * Destroy the iframe and clean up\n */\n destroy(): void {\n if (this.container) {\n this.container.remove();\n this.container = null;\n }\n this.iframe = null;\n this.checkoutOrigin = null;\n\n // Restore body scroll\n document.body.style.overflow = \"\";\n }\n}\n","/**\n * Checkout Class\n *\n * Main entry point for Commerce Engine Checkout integration.\n * Manages iframe lifecycle, event handling, and provides public API.\n */\n\nimport { EventEmitter } from \"./events\";\nimport { IframeManager } from \"./iframe-manager\";\nimport type {\n AuthChangeData,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n EventListener,\n IncomingEventType,\n OrderData,\n} from \"./types\";\n\n// =============================================================================\n// URL RESOLUTION\n// =============================================================================\n\n/** Checkout URLs by environment */\nconst CHECKOUT_URLS: Record<Environment, string> = {\n production: \"https://checkout.commercengine.com\",\n staging: \"https://staging.checkout.commercengine.com\",\n};\n\n/**\n * Build checkout iframe URL\n */\nfunction buildCheckoutUrl(storeId: string, apiKey: string, environment: Environment): string {\n const baseUrl = CHECKOUT_URLS[environment];\n return `${baseUrl}?store_id=${storeId}&api_key=${apiKey}&environment=${environment}&mode=iframe`;\n}\n\n// =============================================================================\n// CHECKOUT CLASS\n// =============================================================================\n\nexport class Checkout extends EventEmitter {\n private config: CheckoutConfig;\n private iframe: IframeManager;\n private isReady = false;\n private isOpen = false;\n private cartState: CartData = { count: 0, total: 0, currency: \"INR\" };\n private boundMessageHandler: (event: MessageEvent) => void;\n private hasQuickBuyParams = false; // Track if we detected quick buy params\n\n constructor(config: CheckoutConfig) {\n super();\n this.config = config;\n this.iframe = new IframeManager();\n this.boundMessageHandler = this.handleMessage.bind(this);\n this.initialize();\n }\n\n // ===========================================================================\n // INITIALIZATION\n // ===========================================================================\n\n private initialize(): void {\n // Build checkout URL - use direct URL if provided, otherwise resolve from credentials\n let baseUrl: string;\n if (this.config.url) {\n // Direct URL provided (local development)\n baseUrl = this.config.url;\n } else if (this.config.storeId && this.config.apiKey) {\n // Build URL from credentials + environment\n const env = this.config.environment || \"production\";\n baseUrl = buildCheckoutUrl(this.config.storeId, this.config.apiKey, env);\n } else {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided.\"\n );\n }\n\n const url = new URL(baseUrl);\n\n // Always set iframe mode\n url.searchParams.set(\"mode\", \"iframe\");\n\n // Add store credentials if provided and not already in URL\n if (this.config.storeId && !url.searchParams.has(\"store_id\")) {\n url.searchParams.set(\"store_id\", this.config.storeId);\n }\n if (this.config.apiKey && !url.searchParams.has(\"api_key\")) {\n url.searchParams.set(\"api_key\", this.config.apiKey);\n }\n if (this.config.environment && !url.searchParams.has(\"environment\")) {\n url.searchParams.set(\"environment\", this.config.environment);\n }\n\n // Add theme preference\n if (this.config.theme) {\n url.searchParams.set(\"theme\", this.config.theme);\n }\n\n // Add auth config\n if (this.config.authMode) {\n url.searchParams.set(\"auth_mode\", this.config.authMode);\n }\n if (this.config.accessToken) {\n url.searchParams.set(\"token\", this.config.accessToken);\n }\n if (this.config.refreshToken) {\n url.searchParams.set(\"refresh_token\", this.config.refreshToken);\n }\n\n // Auto-detect quick buy params from parent URL (if enabled and no explicit quickBuy)\n let quickBuy = this.config.quickBuy;\n let sessionMode = this.config.sessionMode;\n\n if (this.config.autoDetectQuickBuy && !quickBuy) {\n const parentParams = new URLSearchParams(window.location.search);\n const productId = parentParams.get(\"product_id\");\n const variantId = parentParams.get(\"variant_id\");\n\n if (productId) {\n quickBuy = {\n productId,\n variantId: variantId ?? null,\n quantity: parseInt(parentParams.get(\"qty\") || parentParams.get(\"quantity\") || \"1\", 10),\n };\n\n // Also check for session_mode in parent URL\n const parentSessionMode = parentParams.get(\"session_mode\");\n if (parentSessionMode === \"force-new\" || parentSessionMode === \"continue-existing\") {\n sessionMode = parentSessionMode;\n }\n\n // Clean quick buy params from URL to prevent duplicate adds on refresh\n // Deferred to next tick to handle React StrictMode double-mounting\n setTimeout(() => this.cleanQuickBuyParamsFromUrl(), 0);\n }\n }\n\n // Add quick buy params\n if (quickBuy) {\n this.hasQuickBuyParams = true;\n url.searchParams.set(\"product_id\", quickBuy.productId);\n if (quickBuy.variantId) {\n url.searchParams.set(\"variant_id\", quickBuy.variantId);\n }\n if (quickBuy.quantity && quickBuy.quantity !== 1) {\n url.searchParams.set(\"qty\", String(quickBuy.quantity));\n }\n }\n\n // Add session mode\n if (sessionMode) {\n url.searchParams.set(\"session_mode\", sessionMode);\n }\n\n // Pass parent origin for postMessage security\n // This allows the iframe to validate incoming messages and send responses to the correct origin\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"parent_origin\", window.location.origin);\n }\n\n // Create iframe (hidden initially, will show when ready + opened)\n const zIndex = this.config.appearance?.zIndex ?? 99999;\n this.iframe.create(url.toString(), zIndex);\n\n // Listen for messages from checkout iframe\n window.addEventListener(\"message\", this.boundMessageHandler);\n }\n\n // ===========================================================================\n // URL CLEANUP\n // ===========================================================================\n\n /**\n * Remove quick buy params from the parent URL to prevent duplicate adds on refresh\n * Uses replaceState to avoid adding to browser history\n */\n private cleanQuickBuyParamsFromUrl(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n const paramsToRemove = [\"product_id\", \"variant_id\", \"qty\", \"quantity\", \"session_mode\"];\n\n let hasChanges = false;\n for (const param of paramsToRemove) {\n if (url.searchParams.has(param)) {\n url.searchParams.delete(param);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n window.history.replaceState({}, \"\", url.toString());\n }\n }\n\n // ===========================================================================\n // MESSAGE HANDLING\n // ===========================================================================\n\n private handleMessage(event: MessageEvent): void {\n // Validate origin for security - reject if no expected origin or mismatch\n const expectedOrigin = this.iframe.getCheckoutOrigin();\n if (!expectedOrigin || event.origin !== expectedOrigin) {\n return;\n }\n\n const { type, data } = event.data || {};\n if (!type) return;\n\n switch (type as IncomingEventType) {\n case \"checkout:ready\":\n this.handleReady();\n break;\n\n case \"checkout:open\":\n this.handleOpen();\n break;\n\n case \"checkout:close\":\n this.handleClose();\n break;\n\n case \"checkout:complete\":\n this.handleComplete(data as OrderData);\n break;\n\n case \"checkout:error\":\n this.handleError(data as { message: string });\n break;\n\n case \"cart:updated\":\n this.handleCartUpdate(data as CartData);\n break;\n\n case \"auth:login\":\n this.handleAuthChange({ type: \"login\", ...data });\n break;\n\n case \"auth:logout\":\n this.handleAuthChange({ type: \"logout\" });\n break;\n\n case \"auth:refresh\":\n this.handleAuthChange({ type: \"refresh\", ...data });\n break;\n }\n }\n\n private handleReady(): void {\n this.isReady = true;\n this.config.onReady?.();\n this.emit(\"ready\");\n\n // Auto-open cart if we have quick buy params (from config or auto-detected URL)\n if (this.hasQuickBuyParams) {\n this.openCart();\n }\n }\n\n private handleError(data: { message: string }): void {\n // Set ready so user can still interact (they'll see the error drawer)\n this.isReady = true;\n this.config.onError?.(data);\n this.emit(\"error\", data);\n }\n\n private handleOpen(): void {\n this.iframe.show();\n this.isOpen = true;\n this.config.onOpen?.();\n this.emit(\"open\");\n }\n\n private handleClose(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.config.onClose?.();\n this.emit(\"close\");\n }\n\n private handleComplete(data: OrderData): void {\n this.config.onComplete?.(data);\n this.emit(\"complete\", data);\n }\n\n private handleCartUpdate(data: CartData): void {\n this.cartState = data;\n this.config.onCartUpdate?.(data);\n this.emit(\"cart:updated\", data);\n }\n\n private handleAuthChange(data: AuthChangeData): void {\n this.config.onAuthChange?.(data);\n this.emit(\"auth:change\", data);\n }\n\n // ===========================================================================\n // PUBLIC API\n // ===========================================================================\n\n /**\n * Open the cart drawer\n */\n openCart(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-cart\");\n }\n\n /**\n * Open the checkout drawer directly (e.g., for Buy Now flow)\n */\n openCheckout(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-checkout\");\n }\n\n /**\n * Close the checkout overlay\n */\n close(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.iframe.postMessage(\"checkout:close\");\n }\n\n /**\n * Update authentication tokens\n * Use this when user logs in/out on the parent site\n */\n updateTokens(accessToken: string, refreshToken?: string): void {\n if (!this.isReady) {\n // Store for when ready\n this.config.accessToken = accessToken;\n this.config.refreshToken = refreshToken;\n return;\n }\n\n this.iframe.postMessage(\"checkout:update-tokens\", { accessToken, refreshToken });\n }\n\n /**\n * Add an item to cart and open the cart drawer\n *\n * @param productId - Product ID (required)\n * @param variantId - Variant ID (required, null for non-variant products)\n * @param quantity - Quantity to add (default: 1)\n */\n addToCart(productId: string, variantId: string | null, quantity = 1): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.postMessage(\"checkout:add-item\", {\n productId,\n variantId,\n quantity,\n });\n\n // Auto-open cart to show the added item\n this.openCart();\n }\n\n /**\n * Get current cart state\n */\n getCart(): CartData {\n return { ...this.cartState };\n }\n\n /**\n * Check if checkout is ready\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Check if checkout overlay is currently open\n */\n get open(): boolean {\n return this.isOpen;\n }\n\n /**\n * Subscribe to an event\n * @override EventEmitter.on with typed overloads\n */\n on(event: \"ready\", listener: EventListener<void>): void;\n on(event: \"open\", listener: EventListener<void>): void;\n on(event: \"close\", listener: EventListener<void>): void;\n on(event: \"complete\", listener: EventListener<OrderData>): void;\n on(event: \"cart:updated\", listener: EventListener<CartData>): void;\n on(event: \"auth:change\", listener: EventListener<AuthChangeData>): void;\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n super.on(event, listener);\n }\n\n /**\n * Destroy the checkout instance\n * Removes iframe and cleans up event listeners\n */\n destroy(): void {\n window.removeEventListener(\"message\", this.boundMessageHandler);\n this.iframe.destroy();\n this.removeAllListeners();\n this.isReady = false;\n this.isOpen = false;\n }\n}\n","/**\n * Commerce Engine Checkout\n *\n * @commercengine/js - Embeddable checkout SDK\n *\n * @example CDN Usage (Vanilla JS):\n * ```html\n * <script src=\"https://cdn.commercengine.com/v1.js\" async></script>\n * <script>\n * window.Commercengine.onLoad = async () => {\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"dark\",\n * onComplete: (order) => console.log(\"Order:\", order.orderNumber),\n * });\n *\n * document.getElementById(\"cart-btn\").onclick = () => checkout.openCart();\n * };\n * </script>\n * ```\n *\n * @example ESM Import:\n * ```typescript\n * import { Commercengine } from \"@commercengine/js\";\n *\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * });\n *\n * checkout.on(\"cart:updated\", (cart) => updateBadge(cart.count));\n * checkout.openCart();\n * ```\n */\n\nimport { Checkout } from \"./checkout\";\nimport type { CheckoutConfig } from \"./types\";\n\n// Re-export types for consumers\nexport type {\n AddToCartItem,\n AuthChangeData,\n AuthMode,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n ErrorData,\n OrderData,\n QuickBuyConfig,\n SessionMode,\n} from \"./types\";\n\nexport { Checkout };\n\n// =============================================================================\n// GLOBAL API\n// =============================================================================\n\n/**\n * Global Commercengine object interface\n */\ninterface CommercengineGlobal {\n /**\n * Initialize checkout with configuration\n * @returns Promise that resolves to Checkout instance\n */\n init: (config: CheckoutConfig) => Promise<Checkout>;\n\n /**\n * Callback invoked when script has loaded\n * Set this BEFORE including the script to be notified when ready\n */\n onLoad?: () => void;\n\n /**\n * Current checkout instance (if initialized)\n */\n instance?: Checkout;\n}\n\n/**\n * Global Commercengine namespace\n */\nconst Commercengine: CommercengineGlobal = {\n /**\n * Initialize checkout\n *\n * @param config - Checkout configuration\n * @returns Checkout instance\n *\n * @example\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"system\",\n * });\n */\n init: async (config: CheckoutConfig): Promise<Checkout> => {\n // Validate required fields - either url (for dev) or storeId+apiKey (for prod)\n if (!config.url && (!config.storeId || !config.apiKey)) {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided\"\n );\n }\n\n // Destroy existing instance if any\n if (Commercengine.instance) {\n Commercengine.instance.destroy();\n }\n\n // Create new instance\n const checkout = new Checkout(config);\n Commercengine.instance = checkout;\n\n // Wait for ready or error with timeout\n return new Promise((resolve, reject) => {\n if (checkout.ready) {\n resolve(checkout);\n return;\n }\n\n const timeoutMs = 30000; // 30 second timeout\n const timeout = setTimeout(() => {\n reject(new Error(\"Checkout initialization timed out\"));\n }, timeoutMs);\n\n // Resolve on ready\n checkout.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n\n // Also resolve on error (checkout is still usable, will show error drawer)\n checkout.once(\"error\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n });\n },\n};\n\n// =============================================================================\n// GLOBAL SETUP\n// =============================================================================\n\n// Expose on window for CDN usage\nif (typeof window !== \"undefined\") {\n // Preserve any existing onLoad callback set before script loaded\n const existingOnLoad = (window as unknown as { Commercengine?: CommercengineGlobal })\n .Commercengine?.onLoad;\n\n // Set global\n (window as unknown as { Commercengine: CommercengineGlobal }).Commercengine = Commercengine;\n\n // Restore and call onLoad if it was set\n if (existingOnLoad) {\n Commercengine.onLoad = existingOnLoad;\n try {\n existingOnLoad();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(\"[Commercengine] Error in onLoad callback:\", error);\n }\n }\n}\n\nexport { Commercengine };\nexport default Commercengine;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["onceListener: EventListener<T>","CHECKOUT_URLS: Record<Environment, string>","baseUrl: string","Commercengine: CommercengineGlobal"],"sources":["../src/events.ts","../src/iframe-manager.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":["/**\n * Simple Event Emitter\n *\n * Provides pub/sub functionality for checkout events.\n */\n\nimport type { CheckoutEventType, EventListener } from \"./types\";\n\nexport class EventEmitter {\n private listeners: Map<CheckoutEventType, Set<EventListener>> = new Map();\n\n /**\n * Subscribe to an event\n */\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)?.add(listener as EventListener);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener);\n }\n }\n\n /**\n * Subscribe to an event (once)\n */\n once<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const onceListener: EventListener<T> = (data) => {\n this.off(event, onceListener);\n listener(data);\n };\n this.on(event, onceListener);\n }\n\n /**\n * Emit an event to all subscribers\n */\n protected emit<T = unknown>(event: CheckoutEventType, data?: T): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(`[Commercengine] Error in ${event} listener:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners\n */\n protected removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * Iframe Manager\n *\n * Handles iframe creation, lifecycle, and visibility management.\n * The iframe is pre-mounted (hidden) on init and shown on demand.\n */\n\nimport type { OutgoingEventType } from \"./types\";\n\nexport class IframeManager {\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLDivElement | null = null;\n private checkoutOrigin: string | null = null;\n\n /**\n * Create and mount the iframe (hidden initially)\n */\n create(url: string, zIndex: number): void {\n if (this.container) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Iframe already created\");\n return;\n }\n\n // Store origin for postMessage security\n this.checkoutOrigin = new URL(url).origin;\n\n // Create container (covers viewport, initially non-interactive)\n this.container = document.createElement(\"div\");\n this.container.id = \"commercengine-checkout\";\n this.container.style.cssText = `\n position: fixed;\n inset: 0;\n z-index: ${zIndex};\n pointer-events: none;\n `;\n\n // Create iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"commercengine-checkout-iframe\";\n this.iframe.title = \"Shopping cart and checkout\";\n this.iframe.src = url;\n this.iframe.allow = \"payment\";\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n pointer-events: inherit;\n background-color: transparent;\n `;\n\n this.container.appendChild(this.iframe);\n document.body.appendChild(this.container);\n }\n\n /**\n * Show the checkout overlay (enable pointer events)\n */\n show(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"auto\";\n document.body.style.overflow = \"hidden\";\n }\n }\n\n /**\n * Hide the checkout overlay (disable pointer events)\n */\n hide(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"none\";\n document.body.style.overflow = \"\";\n }\n }\n\n /**\n * Check if iframe is visible\n */\n isVisible(): boolean {\n return this.container?.style.pointerEvents === \"auto\";\n }\n\n /**\n * Send a message to the checkout iframe\n */\n postMessage(type: OutgoingEventType, data?: unknown): void {\n if (!this.iframe?.contentWindow) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Cannot send message - iframe not ready\");\n return;\n }\n\n // Use specific origin for security - never use \"*\"\n if (!this.checkoutOrigin) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for security\n console.warn(\"[Commercengine] Cannot send message - checkout origin not established\");\n return;\n }\n this.iframe.contentWindow.postMessage({ type, data }, this.checkoutOrigin);\n }\n\n /**\n * Get the checkout origin for message validation\n */\n getCheckoutOrigin(): string | null {\n return this.checkoutOrigin;\n }\n\n /**\n * Destroy the iframe and clean up\n */\n destroy(): void {\n if (this.container) {\n this.container.remove();\n this.container = null;\n }\n this.iframe = null;\n this.checkoutOrigin = null;\n\n // Restore body scroll\n document.body.style.overflow = \"\";\n }\n}\n","/**\n * Checkout Class\n *\n * Main entry point for Commerce Engine Checkout integration.\n * Manages iframe lifecycle, event handling, and provides public API.\n */\n\nimport { EventEmitter } from \"./events\";\nimport { IframeManager } from \"./iframe-manager\";\nimport type {\n AuthLoginData,\n AuthLogoutData,\n AuthRefreshData,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n EventListener,\n IncomingEventType,\n OrderData,\n} from \"./types\";\n\n// =============================================================================\n// URL RESOLUTION\n// =============================================================================\n\n/** Checkout URLs by environment */\nconst CHECKOUT_URLS: Record<Environment, string> = {\n production: \"https://checkout.commercengine.com\",\n staging: \"https://staging.checkout.commercengine.com\",\n};\n\n/**\n * Build checkout iframe URL\n */\nfunction buildCheckoutUrl(storeId: string, apiKey: string, environment: Environment): string {\n const baseUrl = CHECKOUT_URLS[environment];\n return `${baseUrl}?store_id=${storeId}&api_key=${apiKey}&environment=${environment}&mode=iframe`;\n}\n\n// =============================================================================\n// CHECKOUT CLASS\n// =============================================================================\n\nexport class Checkout extends EventEmitter {\n private config: CheckoutConfig;\n private iframe: IframeManager;\n private isReady = false;\n private isOpen = false;\n private cartState: CartData = { count: 0, total: 0, currency: \"INR\" };\n private boundMessageHandler: (event: MessageEvent) => void;\n private hasQuickBuyParams = false; // Track if we detected quick buy params\n\n constructor(config: CheckoutConfig) {\n super();\n this.config = config;\n this.iframe = new IframeManager();\n this.boundMessageHandler = this.handleMessage.bind(this);\n this.initialize();\n }\n\n // ===========================================================================\n // INITIALIZATION\n // ===========================================================================\n\n private initialize(): void {\n // Build checkout URL - use direct URL if provided, otherwise resolve from credentials\n let baseUrl: string;\n if (this.config.url) {\n // Direct URL provided (local development)\n baseUrl = this.config.url;\n } else if (this.config.storeId && this.config.apiKey) {\n // Build URL from credentials + environment\n const env = this.config.environment || \"production\";\n baseUrl = buildCheckoutUrl(this.config.storeId, this.config.apiKey, env);\n } else {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided.\"\n );\n }\n\n const url = new URL(baseUrl);\n\n // Always set iframe mode\n url.searchParams.set(\"mode\", \"iframe\");\n\n // Add store credentials if provided and not already in URL\n if (this.config.storeId && !url.searchParams.has(\"store_id\")) {\n url.searchParams.set(\"store_id\", this.config.storeId);\n }\n if (this.config.apiKey && !url.searchParams.has(\"api_key\")) {\n url.searchParams.set(\"api_key\", this.config.apiKey);\n }\n if (this.config.environment && !url.searchParams.has(\"environment\")) {\n url.searchParams.set(\"environment\", this.config.environment);\n }\n\n // Add theme preference\n if (this.config.theme) {\n url.searchParams.set(\"theme\", this.config.theme);\n }\n\n // Add auth config\n if (this.config.authMode) {\n url.searchParams.set(\"auth_mode\", this.config.authMode);\n }\n if (this.config.accessToken) {\n url.searchParams.set(\"token\", this.config.accessToken);\n }\n if (this.config.refreshToken) {\n url.searchParams.set(\"refresh_token\", this.config.refreshToken);\n }\n\n // Auto-detect quick buy params from parent URL (if enabled and no explicit quickBuy)\n let quickBuy = this.config.quickBuy;\n let sessionMode = this.config.sessionMode;\n\n if (this.config.autoDetectQuickBuy && !quickBuy) {\n const parentParams = new URLSearchParams(window.location.search);\n const productId = parentParams.get(\"product_id\");\n const variantId = parentParams.get(\"variant_id\");\n\n if (productId) {\n quickBuy = {\n productId,\n variantId: variantId ?? null,\n quantity: parseInt(parentParams.get(\"qty\") || parentParams.get(\"quantity\") || \"1\", 10),\n };\n\n // Also check for session_mode in parent URL\n const parentSessionMode = parentParams.get(\"session_mode\");\n if (parentSessionMode === \"force-new\" || parentSessionMode === \"continue-existing\") {\n sessionMode = parentSessionMode;\n }\n\n // Clean quick buy params from URL to prevent duplicate adds on refresh\n // Deferred to next tick to handle React StrictMode double-mounting\n setTimeout(() => this.cleanQuickBuyParamsFromUrl(), 0);\n }\n }\n\n // Add quick buy params\n if (quickBuy) {\n this.hasQuickBuyParams = true;\n url.searchParams.set(\"product_id\", quickBuy.productId);\n if (quickBuy.variantId) {\n url.searchParams.set(\"variant_id\", quickBuy.variantId);\n }\n if (quickBuy.quantity && quickBuy.quantity !== 1) {\n url.searchParams.set(\"qty\", String(quickBuy.quantity));\n }\n }\n\n // Add session mode\n if (sessionMode) {\n url.searchParams.set(\"session_mode\", sessionMode);\n }\n\n // Pass parent origin for postMessage security\n // This allows the iframe to validate incoming messages and send responses to the correct origin\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"parent_origin\", window.location.origin);\n }\n\n // Create iframe (hidden initially, will show when ready + opened)\n const zIndex = this.config.appearance?.zIndex ?? 99999;\n this.iframe.create(url.toString(), zIndex);\n\n // Listen for messages from checkout iframe\n window.addEventListener(\"message\", this.boundMessageHandler);\n }\n\n // ===========================================================================\n // URL CLEANUP\n // ===========================================================================\n\n /**\n * Remove quick buy params from the parent URL to prevent duplicate adds on refresh\n * Uses replaceState to avoid adding to browser history\n */\n private cleanQuickBuyParamsFromUrl(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n const paramsToRemove = [\"product_id\", \"variant_id\", \"qty\", \"quantity\", \"session_mode\"];\n\n let hasChanges = false;\n for (const param of paramsToRemove) {\n if (url.searchParams.has(param)) {\n url.searchParams.delete(param);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n window.history.replaceState({}, \"\", url.toString());\n }\n }\n\n // ===========================================================================\n // MESSAGE HANDLING\n // ===========================================================================\n\n private handleMessage(event: MessageEvent): void {\n // Validate origin for security - reject if no expected origin or mismatch\n const expectedOrigin = this.iframe.getCheckoutOrigin();\n if (!expectedOrigin || event.origin !== expectedOrigin) {\n return;\n }\n\n const { type, data } = event.data || {};\n if (!type) return;\n\n switch (type as IncomingEventType) {\n case \"checkout:ready\":\n this.handleReady();\n break;\n\n case \"checkout:open\":\n this.handleOpen();\n break;\n\n case \"checkout:close\":\n this.handleClose();\n break;\n\n case \"checkout:complete\":\n this.handleComplete(data as OrderData);\n break;\n\n case \"checkout:error\":\n this.handleError(data as { message: string });\n break;\n\n case \"cart:updated\":\n this.handleCartUpdate(data as CartData);\n break;\n\n case \"auth:login\":\n this.handleLogin(data as AuthLoginData);\n break;\n\n case \"auth:logout\":\n this.handleLogout(data as AuthLogoutData);\n break;\n\n case \"auth:refresh\":\n this.handleTokenRefresh(data as AuthRefreshData);\n break;\n\n case \"auth:session-error\":\n this.handleSessionError();\n break;\n }\n }\n\n private handleReady(): void {\n this.isReady = true;\n this.config.onReady?.();\n this.emit(\"ready\");\n\n // Auto-open cart if we have quick buy params (from config or auto-detected URL)\n if (this.hasQuickBuyParams) {\n this.openCart();\n }\n }\n\n private handleError(data: { message: string }): void {\n // Set ready so user can still interact (they'll see the error drawer)\n this.isReady = true;\n this.config.onError?.(data);\n this.emit(\"error\", data);\n }\n\n private handleOpen(): void {\n this.iframe.show();\n this.isOpen = true;\n this.config.onOpen?.();\n this.emit(\"open\");\n }\n\n private handleClose(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.config.onClose?.();\n this.emit(\"close\");\n }\n\n private handleComplete(data: OrderData): void {\n this.config.onComplete?.(data);\n this.emit(\"complete\", data);\n }\n\n private handleCartUpdate(data: CartData): void {\n this.cartState = data;\n this.config.onCartUpdate?.(data);\n this.emit(\"cart:updated\", data);\n }\n\n private handleLogin(data: AuthLoginData): void {\n this.config.onLogin?.(data);\n this.emit(\"auth:login\", data);\n }\n\n private handleLogout(data: AuthLogoutData): void {\n this.config.onLogout?.(data);\n this.emit(\"auth:logout\", data);\n }\n\n private handleTokenRefresh(data: AuthRefreshData): void {\n this.config.onTokenRefresh?.(data);\n this.emit(\"auth:refresh\", data);\n }\n\n private handleSessionError(): void {\n this.config.onSessionError?.();\n this.emit(\"auth:session-error\");\n }\n\n // ===========================================================================\n // PUBLIC API\n // ===========================================================================\n\n /**\n * Open the cart drawer\n */\n openCart(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-cart\");\n }\n\n /**\n * Open the checkout drawer directly (e.g., for Buy Now flow)\n */\n openCheckout(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-checkout\");\n }\n\n /**\n * Close the checkout overlay\n */\n close(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.iframe.postMessage(\"checkout:close\");\n }\n\n /**\n * Update authentication tokens\n * Use this when user logs in/out on the parent site\n */\n updateTokens(accessToken: string, refreshToken?: string): void {\n if (!this.isReady) {\n // Store for when ready\n this.config.accessToken = accessToken;\n this.config.refreshToken = refreshToken;\n return;\n }\n\n this.iframe.postMessage(\"checkout:update-tokens\", { accessToken, refreshToken });\n }\n\n /**\n * Add an item to cart and open the cart drawer\n *\n * @param productId - Product ID (required)\n * @param variantId - Variant ID (required, null for non-variant products)\n * @param quantity - Quantity to add (default: 1)\n */\n addToCart(productId: string, variantId: string | null, quantity = 1): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.postMessage(\"checkout:add-item\", {\n productId,\n variantId,\n quantity,\n });\n\n // Auto-open cart to show the added item\n this.openCart();\n }\n\n /**\n * Get current cart state\n */\n getCart(): CartData {\n return { ...this.cartState };\n }\n\n /**\n * Check if checkout is ready\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Check if checkout overlay is currently open\n */\n get open(): boolean {\n return this.isOpen;\n }\n\n /**\n * Subscribe to an event\n * @override EventEmitter.on with typed overloads\n */\n on(event: \"ready\", listener: EventListener<void>): void;\n on(event: \"open\", listener: EventListener<void>): void;\n on(event: \"close\", listener: EventListener<void>): void;\n on(event: \"complete\", listener: EventListener<OrderData>): void;\n on(event: \"cart:updated\", listener: EventListener<CartData>): void;\n on(event: \"auth:login\", listener: EventListener<AuthLoginData>): void;\n on(event: \"auth:logout\", listener: EventListener<AuthLogoutData>): void;\n on(event: \"auth:refresh\", listener: EventListener<AuthRefreshData>): void;\n on(event: \"auth:session-error\", listener: EventListener<void>): void;\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n super.on(event, listener);\n }\n\n /**\n * Destroy the checkout instance\n * Removes iframe and cleans up event listeners\n */\n destroy(): void {\n window.removeEventListener(\"message\", this.boundMessageHandler);\n this.iframe.destroy();\n this.removeAllListeners();\n this.isReady = false;\n this.isOpen = false;\n }\n}\n","/**\n * Commerce Engine Checkout\n *\n * @commercengine/js - Embeddable checkout SDK\n *\n * @example CDN Usage (Vanilla JS):\n * ```html\n * <script src=\"https://cdn.commercengine.com/v1.js\" async></script>\n * <script>\n * window.Commercengine.onLoad = async () => {\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"dark\",\n * onComplete: (order) => console.log(\"Order:\", order.orderNumber),\n * });\n *\n * document.getElementById(\"cart-btn\").onclick = () => checkout.openCart();\n * };\n * </script>\n * ```\n *\n * @example ESM Import:\n * ```typescript\n * import { Commercengine } from \"@commercengine/js\";\n *\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * });\n *\n * checkout.on(\"cart:updated\", (cart) => updateBadge(cart.count));\n * checkout.openCart();\n * ```\n */\n\nimport { Checkout } from \"./checkout\";\nimport type { CheckoutConfig } from \"./types\";\n\n// Re-export types for consumers\nexport type {\n AddToCartItem,\n AuthLoginData,\n AuthLogoutData,\n AuthMode,\n AuthRefreshData,\n CartData,\n Channel,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n ErrorData,\n LoginMethod,\n OrderData,\n QuickBuyConfig,\n SessionMode,\n UserInfo,\n} from \"./types\";\n\nexport { Checkout };\n\n// =============================================================================\n// GLOBAL API\n// =============================================================================\n\n/**\n * Global Commercengine object interface\n */\ninterface CommercengineGlobal {\n /**\n * Initialize checkout with configuration\n * @returns Promise that resolves to Checkout instance\n */\n init: (config: CheckoutConfig) => Promise<Checkout>;\n\n /**\n * Callback invoked when script has loaded\n * Set this BEFORE including the script to be notified when ready\n */\n onLoad?: () => void;\n\n /**\n * Current checkout instance (if initialized)\n */\n instance?: Checkout;\n}\n\n/**\n * Global Commercengine namespace\n */\nconst Commercengine: CommercengineGlobal = {\n /**\n * Initialize checkout\n *\n * @param config - Checkout configuration\n * @returns Checkout instance\n *\n * @example\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"system\",\n * });\n */\n init: async (config: CheckoutConfig): Promise<Checkout> => {\n // Validate required fields - either url (for dev) or storeId+apiKey (for prod)\n if (!config.url && (!config.storeId || !config.apiKey)) {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided\"\n );\n }\n\n // Destroy existing instance if any\n if (Commercengine.instance) {\n Commercengine.instance.destroy();\n }\n\n // Create new instance\n const checkout = new Checkout(config);\n Commercengine.instance = checkout;\n\n // Wait for ready or error with timeout\n return new Promise((resolve, reject) => {\n if (checkout.ready) {\n resolve(checkout);\n return;\n }\n\n const timeoutMs = 30000; // 30 second timeout\n const timeout = setTimeout(() => {\n reject(new Error(\"Checkout initialization timed out\"));\n }, timeoutMs);\n\n // Resolve on ready\n checkout.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n\n // Also resolve on error (checkout is still usable, will show error drawer)\n checkout.once(\"error\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n });\n },\n};\n\n// =============================================================================\n// GLOBAL SETUP\n// =============================================================================\n\n// Expose on window for CDN usage\nif (typeof window !== \"undefined\") {\n // Preserve any existing onLoad callback set before script loaded\n const existingOnLoad = (window as unknown as { Commercengine?: CommercengineGlobal })\n .Commercengine?.onLoad;\n\n // Set global\n (window as unknown as { Commercengine: CommercengineGlobal }).Commercengine = Commercengine;\n\n // Restore and call onLoad if it was set\n if (existingOnLoad) {\n Commercengine.onLoad = existingOnLoad;\n try {\n existingOnLoad();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(\"[Commercengine] Error in onLoad callback:\", error);\n }\n }\n}\n\nexport { Commercengine };\nexport default Commercengine;\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -165,9 +165,22 @@ interface CheckoutConfig {
165
165
  */
166
166
  onCartUpdate?: (cart: CartData) => void;
167
167
  /**
168
- * Called when auth state changes (login, logout, token refresh)
168
+ * Called when user logs in via checkout
169
169
  */
170
- onAuthChange?: (auth: AuthChangeData) => void;
170
+ onLogin?: (data: AuthLoginData) => void;
171
+ /**
172
+ * Called when user logs out (receives new anonymous tokens)
173
+ */
174
+ onLogout?: (data: AuthLogoutData) => void;
175
+ /**
176
+ * Called when tokens are auto-refreshed by SDK
177
+ */
178
+ onTokenRefresh?: (data: AuthRefreshData) => void;
179
+ /**
180
+ * Called when session is corrupted and SDK clears all tokens.
181
+ * User needs to re-authenticate.
182
+ */
183
+ onSessionError?: () => void;
171
184
  /**
172
185
  * Called when checkout encounters a configuration error
173
186
  * This happens when credentials are missing or invalid.
@@ -176,6 +189,39 @@ interface CheckoutConfig {
176
189
  */
177
190
  onError?: (error: ErrorData) => void;
178
191
  }
192
+ /**
193
+ * Channel information from token
194
+ */
195
+ interface Channel {
196
+ id: string;
197
+ name: string;
198
+ type: string;
199
+ }
200
+ /**
201
+ * User information decoded from JWT token
202
+ * Matches @commercengine/storefront-sdk UserInfo 1:1
203
+ */
204
+ interface UserInfo {
205
+ id: string;
206
+ email: string | null;
207
+ phone: string | null;
208
+ username: string;
209
+ firstName: string | null;
210
+ lastName: string | null;
211
+ storeId: string;
212
+ isLoggedIn: boolean;
213
+ isAnonymous: boolean;
214
+ customerId: string | null;
215
+ customerGroupId: string | null;
216
+ anonymousId: string;
217
+ channel: Channel;
218
+ tokenExpiry: Date;
219
+ tokenIssuedAt: Date;
220
+ }
221
+ /**
222
+ * Login method used for authentication
223
+ */
224
+ type LoginMethod = "whatsapp" | "phone" | "email";
179
225
  /**
180
226
  * Cart state data emitted on cart:updated event
181
227
  */
@@ -197,14 +243,27 @@ interface OrderData {
197
243
  orderNumber: string;
198
244
  }
199
245
  /**
200
- * Auth change data emitted on auth events
246
+ * Data emitted on login event
201
247
  */
202
- interface AuthChangeData {
203
- /** Type of auth change */
204
- type: "login" | "logout" | "refresh";
205
- /** New access token (for login/refresh) */
206
- accessToken?: string;
207
- /** New refresh token (for login/refresh) */
248
+ interface AuthLoginData {
249
+ accessToken: string;
250
+ refreshToken?: string;
251
+ user?: UserInfo;
252
+ loginMethod?: LoginMethod;
253
+ }
254
+ /**
255
+ * Data emitted on logout event
256
+ */
257
+ interface AuthLogoutData {
258
+ accessToken: string;
259
+ refreshToken?: string;
260
+ user?: UserInfo;
261
+ }
262
+ /**
263
+ * Data emitted on token refresh event
264
+ */
265
+ interface AuthRefreshData {
266
+ accessToken: string;
208
267
  refreshToken?: string;
209
268
  }
210
269
  /**
@@ -217,7 +276,7 @@ interface ErrorData {
217
276
  /**
218
277
  * Events emitted by checkout
219
278
  */
220
- type CheckoutEventType = "ready" | "open" | "close" | "complete" | "error" | "cart:updated" | "auth:change";
279
+ type CheckoutEventType = "ready" | "open" | "close" | "complete" | "error" | "cart:updated" | "auth:login" | "auth:logout" | "auth:refresh" | "auth:session-error";
221
280
  /**
222
281
  * Event listener function type
223
282
  */
@@ -271,7 +330,10 @@ declare class Checkout extends EventEmitter {
271
330
  private handleClose;
272
331
  private handleComplete;
273
332
  private handleCartUpdate;
274
- private handleAuthChange;
333
+ private handleLogin;
334
+ private handleLogout;
335
+ private handleTokenRefresh;
336
+ private handleSessionError;
275
337
  /**
276
338
  * Open the cart drawer
277
339
  */
@@ -318,7 +380,10 @@ declare class Checkout extends EventEmitter {
318
380
  on(event: "close", listener: EventListener<void>): void;
319
381
  on(event: "complete", listener: EventListener<OrderData>): void;
320
382
  on(event: "cart:updated", listener: EventListener<CartData>): void;
321
- on(event: "auth:change", listener: EventListener<AuthChangeData>): void;
383
+ on(event: "auth:login", listener: EventListener<AuthLoginData>): void;
384
+ on(event: "auth:logout", listener: EventListener<AuthLogoutData>): void;
385
+ on(event: "auth:refresh", listener: EventListener<AuthRefreshData>): void;
386
+ on(event: "auth:session-error", listener: EventListener<void>): void;
322
387
  /**
323
388
  * Destroy the checkout instance
324
389
  * Removes iframe and cleans up event listeners
@@ -351,5 +416,5 @@ interface CommercengineGlobal {
351
416
  */
352
417
  declare const Commercengine: CommercengineGlobal;
353
418
  //#endregion
354
- export { type AddToCartItem, type AuthChangeData, type AuthMode, type CartData, Checkout, type CheckoutConfig, type CheckoutEventType, Commercengine, Commercengine as default, type Environment, type ErrorData, type OrderData, type QuickBuyConfig, type SessionMode };
419
+ export { type AddToCartItem, type AuthLoginData, type AuthLogoutData, type AuthMode, type AuthRefreshData, type CartData, type Channel, Checkout, type CheckoutConfig, type CheckoutEventType, Commercengine, Commercengine as default, type Environment, type ErrorData, type LoginMethod, type OrderData, type QuickBuyConfig, type SessionMode, type UserInfo };
355
420
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/events.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;AAkBA;AASA;AAsBA;AA2BA;AAWA;AAQA;;;;;;;AAwIwB,KArNZ,QAAA,GAqNY,SAAA,GAAA,UAAA;;;AAkBxB;AAYiB,UA1OA,aAAA,CA0OS;EAUT;AAYjB;AAYA;EAYY,SAAA,EAAA,MAAa;;;;EC3SZ,SAAA,EAAA,MAAY,GAAA,IAAA;EAMA;;;;EAU4C,QAAA,CAAA,EAAA,MAAA;;;;;;AAqBN,UDI9C,cAAA,CCJ8C;EAAC;;;;ECHnD;;;EA2WkB,SAAA,EAAA,MAAA,GAAA,IAAA;EACD;;;;EAGsB,QAAA,CAAA,EAAA,MAAA;;;;;;;KF7UxC,WAAA;;AGtBQ;;;;AAyBP,KHQD,WAAA,GGRC,YAAA,GAAA,SAAA;;AAAQ;;;;;UHgBJ,cAAA;;;;;;;;gBAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsDH;;;;;;;;;;;;;aAoBA;;;;;gBAMG;;;;;;;;;;;;;;;;;;;;;;;;uBAiCO;;;;;wBAMC;;;;wBAKA;;;;;;;oBAQJ;;;;;UAUH,QAAA;;;;;;;;;;;UAYA,SAAA;;;;;;;;;UAUA,cAAA;;;;;;;;;;;UAYA,SAAA;;;;;;;KAYL,iBAAA;;;;KAYA,oCAAoC;;;AApN/B,cCvFJ,YAAA,CDuFkB;EAYf,QAAA,SAAA;EAsDH;;;EA2DU,EAAA,CAAA,IAAA,OAAA,CAAA,CAAA,KAAA,EC9ME,iBD8MF,EAAA,QAAA,EC9M+B,aD8M/B,CC9M6C,CD8M7C,CAAA,CAAA,EAAA,IAAA;EAMC;;;EAaK,GAAA,CAAA,IAAA,OAAA,CAAA,CAAA,KAAA,ECvNH,iBDuNG,EAAA,QAAA,ECvN0B,aDuN1B,CCvNwC,CDuNxC,CAAA,CAAA,EAAA,IAAA;EAUZ;AAYjB;AAUA;EAYiB,IAAA,CAAA,IAAA,OAAS,CAAA,CAAA,KAAA,ECzPC,iBDyPD,EAAA,QAAA,ECzP8B,aDyP9B,CCzP4C,CDyP5C,CAAA,CAAA,EAAA,IAAA;EAYd;AAYZ;;qCCtQqC,0BAA0B;;AArC/D;;EAMoE,UAAA,kBAAA,CAAA,CAAA,EAAA,IAAA;;;;ADmJvD,cEvHA,QAAA,SAAiB,YAAA,CFuHjB;EAoBA,QAAA,MAAA;EAMG,QAAA,MAAA;EAiCO,QAAA,OAAA;EAMC,QAAA,MAAA;EAKA,QAAA,SAAA;EAQJ,QAAA,mBAAA;EAAS,QAAA,iBAAA;EAUZ,WAAQ,CAAA,MAAA,EEtMH,cFsMG;EAYR,QAAA,UAAS;EAUT;AAYjB;AAYA;AAYA;;;;EC3Sa,QAAA,WAAY;EAMA,QAAA,UAAA;EAA2C,QAAA,WAAA;EAAd,QAAA,cAAA;EAU5B,QAAA,gBAAA;EAA2C,QAAA,gBAAA;EAAd;;;EAUC,QAAA,CAAA,CAAA,EAAA,IAAA;EAWnB;;;;;;ACHrC;EASsB,KAAA,CAAA,CAAA,EAAA,IAAA;EA4UT;;;;EAyBmC,YAAA,CAAA,WAAA,EAAA,MAAA,EAAA,YAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAd;;;;;;;;;;AClWd;EAcH,OAAA,CAAA,CAAA,ED2TJ,QC3TI;EAA2B;;;EAWvB,IAAA,KAAA,CAAA,CAAA,EAAA,OAAA;EAMf;;;;;;;;+BDgUyB;8BACD;+BACC;kCACG,cAAc;sCACV,cAAc;qCACf,cAAc;;;;;;;;;;;AAhXnD;UCqBU,mBAAA,CDZY;EA4UT;;;;EAyBmC,IAAA,EAAA,CAAA,MAAA,ECpV/B,cDoV+B,EAAA,GCpVZ,ODoVY,CCpVJ,QDoVI,CAAA;EAAd;;;;EAEG,MAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAhXP;;;aCqCjB;;AAzBO;;;cA+Bd,aAjB8B,EAiBf,mBAjBe"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/events.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -165,9 +165,22 @@ interface CheckoutConfig {
165
165
  */
166
166
  onCartUpdate?: (cart: CartData) => void;
167
167
  /**
168
- * Called when auth state changes (login, logout, token refresh)
168
+ * Called when user logs in via checkout
169
169
  */
170
- onAuthChange?: (auth: AuthChangeData) => void;
170
+ onLogin?: (data: AuthLoginData) => void;
171
+ /**
172
+ * Called when user logs out (receives new anonymous tokens)
173
+ */
174
+ onLogout?: (data: AuthLogoutData) => void;
175
+ /**
176
+ * Called when tokens are auto-refreshed by SDK
177
+ */
178
+ onTokenRefresh?: (data: AuthRefreshData) => void;
179
+ /**
180
+ * Called when session is corrupted and SDK clears all tokens.
181
+ * User needs to re-authenticate.
182
+ */
183
+ onSessionError?: () => void;
171
184
  /**
172
185
  * Called when checkout encounters a configuration error
173
186
  * This happens when credentials are missing or invalid.
@@ -176,6 +189,39 @@ interface CheckoutConfig {
176
189
  */
177
190
  onError?: (error: ErrorData) => void;
178
191
  }
192
+ /**
193
+ * Channel information from token
194
+ */
195
+ interface Channel {
196
+ id: string;
197
+ name: string;
198
+ type: string;
199
+ }
200
+ /**
201
+ * User information decoded from JWT token
202
+ * Matches @commercengine/storefront-sdk UserInfo 1:1
203
+ */
204
+ interface UserInfo {
205
+ id: string;
206
+ email: string | null;
207
+ phone: string | null;
208
+ username: string;
209
+ firstName: string | null;
210
+ lastName: string | null;
211
+ storeId: string;
212
+ isLoggedIn: boolean;
213
+ isAnonymous: boolean;
214
+ customerId: string | null;
215
+ customerGroupId: string | null;
216
+ anonymousId: string;
217
+ channel: Channel;
218
+ tokenExpiry: Date;
219
+ tokenIssuedAt: Date;
220
+ }
221
+ /**
222
+ * Login method used for authentication
223
+ */
224
+ type LoginMethod = "whatsapp" | "phone" | "email";
179
225
  /**
180
226
  * Cart state data emitted on cart:updated event
181
227
  */
@@ -197,14 +243,27 @@ interface OrderData {
197
243
  orderNumber: string;
198
244
  }
199
245
  /**
200
- * Auth change data emitted on auth events
246
+ * Data emitted on login event
201
247
  */
202
- interface AuthChangeData {
203
- /** Type of auth change */
204
- type: "login" | "logout" | "refresh";
205
- /** New access token (for login/refresh) */
206
- accessToken?: string;
207
- /** New refresh token (for login/refresh) */
248
+ interface AuthLoginData {
249
+ accessToken: string;
250
+ refreshToken?: string;
251
+ user?: UserInfo;
252
+ loginMethod?: LoginMethod;
253
+ }
254
+ /**
255
+ * Data emitted on logout event
256
+ */
257
+ interface AuthLogoutData {
258
+ accessToken: string;
259
+ refreshToken?: string;
260
+ user?: UserInfo;
261
+ }
262
+ /**
263
+ * Data emitted on token refresh event
264
+ */
265
+ interface AuthRefreshData {
266
+ accessToken: string;
208
267
  refreshToken?: string;
209
268
  }
210
269
  /**
@@ -217,7 +276,7 @@ interface ErrorData {
217
276
  /**
218
277
  * Events emitted by checkout
219
278
  */
220
- type CheckoutEventType = "ready" | "open" | "close" | "complete" | "error" | "cart:updated" | "auth:change";
279
+ type CheckoutEventType = "ready" | "open" | "close" | "complete" | "error" | "cart:updated" | "auth:login" | "auth:logout" | "auth:refresh" | "auth:session-error";
221
280
  /**
222
281
  * Event listener function type
223
282
  */
@@ -271,7 +330,10 @@ declare class Checkout extends EventEmitter {
271
330
  private handleClose;
272
331
  private handleComplete;
273
332
  private handleCartUpdate;
274
- private handleAuthChange;
333
+ private handleLogin;
334
+ private handleLogout;
335
+ private handleTokenRefresh;
336
+ private handleSessionError;
275
337
  /**
276
338
  * Open the cart drawer
277
339
  */
@@ -318,7 +380,10 @@ declare class Checkout extends EventEmitter {
318
380
  on(event: "close", listener: EventListener<void>): void;
319
381
  on(event: "complete", listener: EventListener<OrderData>): void;
320
382
  on(event: "cart:updated", listener: EventListener<CartData>): void;
321
- on(event: "auth:change", listener: EventListener<AuthChangeData>): void;
383
+ on(event: "auth:login", listener: EventListener<AuthLoginData>): void;
384
+ on(event: "auth:logout", listener: EventListener<AuthLogoutData>): void;
385
+ on(event: "auth:refresh", listener: EventListener<AuthRefreshData>): void;
386
+ on(event: "auth:session-error", listener: EventListener<void>): void;
322
387
  /**
323
388
  * Destroy the checkout instance
324
389
  * Removes iframe and cleans up event listeners
@@ -351,5 +416,5 @@ interface CommercengineGlobal {
351
416
  */
352
417
  declare const Commercengine: CommercengineGlobal;
353
418
  //#endregion
354
- export { type AddToCartItem, type AuthChangeData, type AuthMode, type CartData, Checkout, type CheckoutConfig, type CheckoutEventType, Commercengine, Commercengine as default, type Environment, type ErrorData, type OrderData, type QuickBuyConfig, type SessionMode };
419
+ export { type AddToCartItem, type AuthLoginData, type AuthLogoutData, type AuthMode, type AuthRefreshData, type CartData, type Channel, Checkout, type CheckoutConfig, type CheckoutEventType, Commercengine, Commercengine as default, type Environment, type ErrorData, type LoginMethod, type OrderData, type QuickBuyConfig, type SessionMode, type UserInfo };
355
420
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/events.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;AAkBA;AASA;AAsBA;AA2BA;AAWA;AAQA;;;;;;;AAwIwB,KArNZ,QAAA,GAqNY,SAAA,GAAA,UAAA;;;AAkBxB;AAYiB,UA1OA,aAAA,CA0OS;EAUT;AAYjB;AAYA;EAYY,SAAA,EAAA,MAAa;;;;EC3SZ,SAAA,EAAA,MAAY,GAAA,IAAA;EAMA;;;;EAU4C,QAAA,CAAA,EAAA,MAAA;;;;;;AAqBN,UDI9C,cAAA,CCJ8C;EAAC;;;;ECHnD;;;EA2WkB,SAAA,EAAA,MAAA,GAAA,IAAA;EACD;;;;EAGsB,QAAA,CAAA,EAAA,MAAA;;;;;;;KF7UxC,WAAA;;AGtBQ;;;;AAyBP,KHQD,WAAA,GGRC,YAAA,GAAA,SAAA;;AAAQ;;;;;UHgBJ,cAAA;;;;;;;;gBAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsDH;;;;;;;;;;;;;aAoBA;;;;;gBAMG;;;;;;;;;;;;;;;;;;;;;;;;uBAiCO;;;;;wBAMC;;;;wBAKA;;;;;;;oBAQJ;;;;;UAUH,QAAA;;;;;;;;;;;UAYA,SAAA;;;;;;;;;UAUA,cAAA;;;;;;;;;;;UAYA,SAAA;;;;;;;KAYL,iBAAA;;;;KAYA,oCAAoC;;;AApN/B,cCvFJ,YAAA,CDuFkB;EAYf,QAAA,SAAA;EAsDH;;;EA2DU,EAAA,CAAA,IAAA,OAAA,CAAA,CAAA,KAAA,EC9ME,iBD8MF,EAAA,QAAA,EC9M+B,aD8M/B,CC9M6C,CD8M7C,CAAA,CAAA,EAAA,IAAA;EAMC;;;EAaK,GAAA,CAAA,IAAA,OAAA,CAAA,CAAA,KAAA,ECvNH,iBDuNG,EAAA,QAAA,ECvN0B,aDuN1B,CCvNwC,CDuNxC,CAAA,CAAA,EAAA,IAAA;EAUZ;AAYjB;AAUA;EAYiB,IAAA,CAAA,IAAA,OAAS,CAAA,CAAA,KAAA,ECzPC,iBDyPD,EAAA,QAAA,ECzP8B,aDyP9B,CCzP4C,CDyP5C,CAAA,CAAA,EAAA,IAAA;EAYd;AAYZ;;qCCtQqC,0BAA0B;;AArC/D;;EAMoE,UAAA,kBAAA,CAAA,CAAA,EAAA,IAAA;;;;ADmJvD,cEvHA,QAAA,SAAiB,YAAA,CFuHjB;EAoBA,QAAA,MAAA;EAMG,QAAA,MAAA;EAiCO,QAAA,OAAA;EAMC,QAAA,MAAA;EAKA,QAAA,SAAA;EAQJ,QAAA,mBAAA;EAAS,QAAA,iBAAA;EAUZ,WAAQ,CAAA,MAAA,EEtMH,cFsMG;EAYR,QAAA,UAAS;EAUT;AAYjB;AAYA;AAYA;;;;EC3Sa,QAAA,WAAY;EAMA,QAAA,UAAA;EAA2C,QAAA,WAAA;EAAd,QAAA,cAAA;EAU5B,QAAA,gBAAA;EAA2C,QAAA,gBAAA;EAAd;;;EAUC,QAAA,CAAA,CAAA,EAAA,IAAA;EAWnB;;;;;;ACHrC;EASsB,KAAA,CAAA,CAAA,EAAA,IAAA;EA4UT;;;;EAyBmC,YAAA,CAAA,WAAA,EAAA,MAAA,EAAA,YAAA,CAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAd;;;;;;;;;;AClWd;EAcH,OAAA,CAAA,CAAA,ED2TJ,QC3TI;EAA2B;;;EAWvB,IAAA,KAAA,CAAA,CAAA,EAAA,OAAA;EAMf;;;;;;;;+BDgUyB;8BACD;+BACC;kCACG,cAAc;sCACV,cAAc;qCACf,cAAc;;;;;;;;;;;AAhXnD;UCqBU,mBAAA,CDZY;EA4UT;;;;EAyBmC,IAAA,EAAA,CAAA,MAAA,ECpV/B,cDoV+B,EAAA,GCpVZ,ODoVY,CCpVJ,QDoVI,CAAA;EAAd;;;;EAEG,MAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAhXP;;;aCqCjB;;AAzBO;;;cA+Bd,aAjB8B,EAiBf,mBAjBe"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/events.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
@@ -77,6 +77,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
77
77
  `;
78
78
  this.iframe = document.createElement("iframe");
79
79
  this.iframe.id = "commercengine-checkout-iframe";
80
+ this.iframe.title = "Shopping cart and checkout";
80
81
  this.iframe.src = url;
81
82
  this.iframe.allow = "payment";
82
83
  this.iframe.style.cssText = `
@@ -276,19 +277,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
276
277
  this.handleCartUpdate(data);
277
278
  break;
278
279
  case "auth:login":
279
- this.handleAuthChange({
280
- type: "login",
281
- ...data
282
- });
280
+ this.handleLogin(data);
283
281
  break;
284
282
  case "auth:logout":
285
- this.handleAuthChange({ type: "logout" });
283
+ this.handleLogout(data);
286
284
  break;
287
285
  case "auth:refresh":
288
- this.handleAuthChange({
289
- type: "refresh",
290
- ...data
291
- });
286
+ this.handleTokenRefresh(data);
287
+ break;
288
+ case "auth:session-error":
289
+ this.handleSessionError();
292
290
  break;
293
291
  }
294
292
  }
@@ -324,9 +322,21 @@ Object.defineProperty(exports, '__esModule', { value: true });
324
322
  this.config.onCartUpdate?.(data);
325
323
  this.emit("cart:updated", data);
326
324
  }
327
- handleAuthChange(data) {
328
- this.config.onAuthChange?.(data);
329
- this.emit("auth:change", data);
325
+ handleLogin(data) {
326
+ this.config.onLogin?.(data);
327
+ this.emit("auth:login", data);
328
+ }
329
+ handleLogout(data) {
330
+ this.config.onLogout?.(data);
331
+ this.emit("auth:logout", data);
332
+ }
333
+ handleTokenRefresh(data) {
334
+ this.config.onTokenRefresh?.(data);
335
+ this.emit("auth:refresh", data);
336
+ }
337
+ handleSessionError() {
338
+ this.config.onSessionError?.();
339
+ this.emit("auth:session-error");
330
340
  }
331
341
  /**
332
342
  * Open the cart drawer
@@ -1 +1 @@
1
- {"version":3,"file":"index.iife.js","names":["onceListener: EventListener<T>","CHECKOUT_URLS: Record<Environment, string>","baseUrl: string","Commercengine: CommercengineGlobal"],"sources":["../src/events.ts","../src/iframe-manager.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":["/**\n * Simple Event Emitter\n *\n * Provides pub/sub functionality for checkout events.\n */\n\nimport type { CheckoutEventType, EventListener } from \"./types\";\n\nexport class EventEmitter {\n private listeners: Map<CheckoutEventType, Set<EventListener>> = new Map();\n\n /**\n * Subscribe to an event\n */\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)?.add(listener as EventListener);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener);\n }\n }\n\n /**\n * Subscribe to an event (once)\n */\n once<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const onceListener: EventListener<T> = (data) => {\n this.off(event, onceListener);\n listener(data);\n };\n this.on(event, onceListener);\n }\n\n /**\n * Emit an event to all subscribers\n */\n protected emit<T = unknown>(event: CheckoutEventType, data?: T): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(`[Commercengine] Error in ${event} listener:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners\n */\n protected removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * Iframe Manager\n *\n * Handles iframe creation, lifecycle, and visibility management.\n * The iframe is pre-mounted (hidden) on init and shown on demand.\n */\n\nimport type { OutgoingEventType } from \"./types\";\n\nexport class IframeManager {\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLDivElement | null = null;\n private checkoutOrigin: string | null = null;\n\n /**\n * Create and mount the iframe (hidden initially)\n */\n create(url: string, zIndex: number): void {\n if (this.container) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Iframe already created\");\n return;\n }\n\n // Store origin for postMessage security\n this.checkoutOrigin = new URL(url).origin;\n\n // Create container (covers viewport, initially non-interactive)\n this.container = document.createElement(\"div\");\n this.container.id = \"commercengine-checkout\";\n this.container.style.cssText = `\n position: fixed;\n inset: 0;\n z-index: ${zIndex};\n pointer-events: none;\n `;\n\n // Create iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"commercengine-checkout-iframe\";\n this.iframe.src = url;\n this.iframe.allow = \"payment\";\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n pointer-events: inherit;\n background-color: transparent;\n `;\n\n this.container.appendChild(this.iframe);\n document.body.appendChild(this.container);\n }\n\n /**\n * Show the checkout overlay (enable pointer events)\n */\n show(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"auto\";\n document.body.style.overflow = \"hidden\";\n }\n }\n\n /**\n * Hide the checkout overlay (disable pointer events)\n */\n hide(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"none\";\n document.body.style.overflow = \"\";\n }\n }\n\n /**\n * Check if iframe is visible\n */\n isVisible(): boolean {\n return this.container?.style.pointerEvents === \"auto\";\n }\n\n /**\n * Send a message to the checkout iframe\n */\n postMessage(type: OutgoingEventType, data?: unknown): void {\n if (!this.iframe?.contentWindow) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Cannot send message - iframe not ready\");\n return;\n }\n\n // Use specific origin for security - never use \"*\"\n if (!this.checkoutOrigin) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for security\n console.warn(\"[Commercengine] Cannot send message - checkout origin not established\");\n return;\n }\n this.iframe.contentWindow.postMessage({ type, data }, this.checkoutOrigin);\n }\n\n /**\n * Get the checkout origin for message validation\n */\n getCheckoutOrigin(): string | null {\n return this.checkoutOrigin;\n }\n\n /**\n * Destroy the iframe and clean up\n */\n destroy(): void {\n if (this.container) {\n this.container.remove();\n this.container = null;\n }\n this.iframe = null;\n this.checkoutOrigin = null;\n\n // Restore body scroll\n document.body.style.overflow = \"\";\n }\n}\n","/**\n * Checkout Class\n *\n * Main entry point for Commerce Engine Checkout integration.\n * Manages iframe lifecycle, event handling, and provides public API.\n */\n\nimport { EventEmitter } from \"./events\";\nimport { IframeManager } from \"./iframe-manager\";\nimport type {\n AuthChangeData,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n EventListener,\n IncomingEventType,\n OrderData,\n} from \"./types\";\n\n// =============================================================================\n// URL RESOLUTION\n// =============================================================================\n\n/** Checkout URLs by environment */\nconst CHECKOUT_URLS: Record<Environment, string> = {\n production: \"https://checkout.commercengine.com\",\n staging: \"https://staging.checkout.commercengine.com\",\n};\n\n/**\n * Build checkout iframe URL\n */\nfunction buildCheckoutUrl(storeId: string, apiKey: string, environment: Environment): string {\n const baseUrl = CHECKOUT_URLS[environment];\n return `${baseUrl}?store_id=${storeId}&api_key=${apiKey}&environment=${environment}&mode=iframe`;\n}\n\n// =============================================================================\n// CHECKOUT CLASS\n// =============================================================================\n\nexport class Checkout extends EventEmitter {\n private config: CheckoutConfig;\n private iframe: IframeManager;\n private isReady = false;\n private isOpen = false;\n private cartState: CartData = { count: 0, total: 0, currency: \"INR\" };\n private boundMessageHandler: (event: MessageEvent) => void;\n private hasQuickBuyParams = false; // Track if we detected quick buy params\n\n constructor(config: CheckoutConfig) {\n super();\n this.config = config;\n this.iframe = new IframeManager();\n this.boundMessageHandler = this.handleMessage.bind(this);\n this.initialize();\n }\n\n // ===========================================================================\n // INITIALIZATION\n // ===========================================================================\n\n private initialize(): void {\n // Build checkout URL - use direct URL if provided, otherwise resolve from credentials\n let baseUrl: string;\n if (this.config.url) {\n // Direct URL provided (local development)\n baseUrl = this.config.url;\n } else if (this.config.storeId && this.config.apiKey) {\n // Build URL from credentials + environment\n const env = this.config.environment || \"production\";\n baseUrl = buildCheckoutUrl(this.config.storeId, this.config.apiKey, env);\n } else {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided.\"\n );\n }\n\n const url = new URL(baseUrl);\n\n // Always set iframe mode\n url.searchParams.set(\"mode\", \"iframe\");\n\n // Add store credentials if provided and not already in URL\n if (this.config.storeId && !url.searchParams.has(\"store_id\")) {\n url.searchParams.set(\"store_id\", this.config.storeId);\n }\n if (this.config.apiKey && !url.searchParams.has(\"api_key\")) {\n url.searchParams.set(\"api_key\", this.config.apiKey);\n }\n if (this.config.environment && !url.searchParams.has(\"environment\")) {\n url.searchParams.set(\"environment\", this.config.environment);\n }\n\n // Add theme preference\n if (this.config.theme) {\n url.searchParams.set(\"theme\", this.config.theme);\n }\n\n // Add auth config\n if (this.config.authMode) {\n url.searchParams.set(\"auth_mode\", this.config.authMode);\n }\n if (this.config.accessToken) {\n url.searchParams.set(\"token\", this.config.accessToken);\n }\n if (this.config.refreshToken) {\n url.searchParams.set(\"refresh_token\", this.config.refreshToken);\n }\n\n // Auto-detect quick buy params from parent URL (if enabled and no explicit quickBuy)\n let quickBuy = this.config.quickBuy;\n let sessionMode = this.config.sessionMode;\n\n if (this.config.autoDetectQuickBuy && !quickBuy) {\n const parentParams = new URLSearchParams(window.location.search);\n const productId = parentParams.get(\"product_id\");\n const variantId = parentParams.get(\"variant_id\");\n\n if (productId) {\n quickBuy = {\n productId,\n variantId: variantId ?? null,\n quantity: parseInt(parentParams.get(\"qty\") || parentParams.get(\"quantity\") || \"1\", 10),\n };\n\n // Also check for session_mode in parent URL\n const parentSessionMode = parentParams.get(\"session_mode\");\n if (parentSessionMode === \"force-new\" || parentSessionMode === \"continue-existing\") {\n sessionMode = parentSessionMode;\n }\n\n // Clean quick buy params from URL to prevent duplicate adds on refresh\n // Deferred to next tick to handle React StrictMode double-mounting\n setTimeout(() => this.cleanQuickBuyParamsFromUrl(), 0);\n }\n }\n\n // Add quick buy params\n if (quickBuy) {\n this.hasQuickBuyParams = true;\n url.searchParams.set(\"product_id\", quickBuy.productId);\n if (quickBuy.variantId) {\n url.searchParams.set(\"variant_id\", quickBuy.variantId);\n }\n if (quickBuy.quantity && quickBuy.quantity !== 1) {\n url.searchParams.set(\"qty\", String(quickBuy.quantity));\n }\n }\n\n // Add session mode\n if (sessionMode) {\n url.searchParams.set(\"session_mode\", sessionMode);\n }\n\n // Pass parent origin for postMessage security\n // This allows the iframe to validate incoming messages and send responses to the correct origin\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"parent_origin\", window.location.origin);\n }\n\n // Create iframe (hidden initially, will show when ready + opened)\n const zIndex = this.config.appearance?.zIndex ?? 99999;\n this.iframe.create(url.toString(), zIndex);\n\n // Listen for messages from checkout iframe\n window.addEventListener(\"message\", this.boundMessageHandler);\n }\n\n // ===========================================================================\n // URL CLEANUP\n // ===========================================================================\n\n /**\n * Remove quick buy params from the parent URL to prevent duplicate adds on refresh\n * Uses replaceState to avoid adding to browser history\n */\n private cleanQuickBuyParamsFromUrl(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n const paramsToRemove = [\"product_id\", \"variant_id\", \"qty\", \"quantity\", \"session_mode\"];\n\n let hasChanges = false;\n for (const param of paramsToRemove) {\n if (url.searchParams.has(param)) {\n url.searchParams.delete(param);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n window.history.replaceState({}, \"\", url.toString());\n }\n }\n\n // ===========================================================================\n // MESSAGE HANDLING\n // ===========================================================================\n\n private handleMessage(event: MessageEvent): void {\n // Validate origin for security - reject if no expected origin or mismatch\n const expectedOrigin = this.iframe.getCheckoutOrigin();\n if (!expectedOrigin || event.origin !== expectedOrigin) {\n return;\n }\n\n const { type, data } = event.data || {};\n if (!type) return;\n\n switch (type as IncomingEventType) {\n case \"checkout:ready\":\n this.handleReady();\n break;\n\n case \"checkout:open\":\n this.handleOpen();\n break;\n\n case \"checkout:close\":\n this.handleClose();\n break;\n\n case \"checkout:complete\":\n this.handleComplete(data as OrderData);\n break;\n\n case \"checkout:error\":\n this.handleError(data as { message: string });\n break;\n\n case \"cart:updated\":\n this.handleCartUpdate(data as CartData);\n break;\n\n case \"auth:login\":\n this.handleAuthChange({ type: \"login\", ...data });\n break;\n\n case \"auth:logout\":\n this.handleAuthChange({ type: \"logout\" });\n break;\n\n case \"auth:refresh\":\n this.handleAuthChange({ type: \"refresh\", ...data });\n break;\n }\n }\n\n private handleReady(): void {\n this.isReady = true;\n this.config.onReady?.();\n this.emit(\"ready\");\n\n // Auto-open cart if we have quick buy params (from config or auto-detected URL)\n if (this.hasQuickBuyParams) {\n this.openCart();\n }\n }\n\n private handleError(data: { message: string }): void {\n // Set ready so user can still interact (they'll see the error drawer)\n this.isReady = true;\n this.config.onError?.(data);\n this.emit(\"error\", data);\n }\n\n private handleOpen(): void {\n this.iframe.show();\n this.isOpen = true;\n this.config.onOpen?.();\n this.emit(\"open\");\n }\n\n private handleClose(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.config.onClose?.();\n this.emit(\"close\");\n }\n\n private handleComplete(data: OrderData): void {\n this.config.onComplete?.(data);\n this.emit(\"complete\", data);\n }\n\n private handleCartUpdate(data: CartData): void {\n this.cartState = data;\n this.config.onCartUpdate?.(data);\n this.emit(\"cart:updated\", data);\n }\n\n private handleAuthChange(data: AuthChangeData): void {\n this.config.onAuthChange?.(data);\n this.emit(\"auth:change\", data);\n }\n\n // ===========================================================================\n // PUBLIC API\n // ===========================================================================\n\n /**\n * Open the cart drawer\n */\n openCart(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-cart\");\n }\n\n /**\n * Open the checkout drawer directly (e.g., for Buy Now flow)\n */\n openCheckout(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-checkout\");\n }\n\n /**\n * Close the checkout overlay\n */\n close(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.iframe.postMessage(\"checkout:close\");\n }\n\n /**\n * Update authentication tokens\n * Use this when user logs in/out on the parent site\n */\n updateTokens(accessToken: string, refreshToken?: string): void {\n if (!this.isReady) {\n // Store for when ready\n this.config.accessToken = accessToken;\n this.config.refreshToken = refreshToken;\n return;\n }\n\n this.iframe.postMessage(\"checkout:update-tokens\", { accessToken, refreshToken });\n }\n\n /**\n * Add an item to cart and open the cart drawer\n *\n * @param productId - Product ID (required)\n * @param variantId - Variant ID (required, null for non-variant products)\n * @param quantity - Quantity to add (default: 1)\n */\n addToCart(productId: string, variantId: string | null, quantity = 1): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.postMessage(\"checkout:add-item\", {\n productId,\n variantId,\n quantity,\n });\n\n // Auto-open cart to show the added item\n this.openCart();\n }\n\n /**\n * Get current cart state\n */\n getCart(): CartData {\n return { ...this.cartState };\n }\n\n /**\n * Check if checkout is ready\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Check if checkout overlay is currently open\n */\n get open(): boolean {\n return this.isOpen;\n }\n\n /**\n * Subscribe to an event\n * @override EventEmitter.on with typed overloads\n */\n on(event: \"ready\", listener: EventListener<void>): void;\n on(event: \"open\", listener: EventListener<void>): void;\n on(event: \"close\", listener: EventListener<void>): void;\n on(event: \"complete\", listener: EventListener<OrderData>): void;\n on(event: \"cart:updated\", listener: EventListener<CartData>): void;\n on(event: \"auth:change\", listener: EventListener<AuthChangeData>): void;\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n super.on(event, listener);\n }\n\n /**\n * Destroy the checkout instance\n * Removes iframe and cleans up event listeners\n */\n destroy(): void {\n window.removeEventListener(\"message\", this.boundMessageHandler);\n this.iframe.destroy();\n this.removeAllListeners();\n this.isReady = false;\n this.isOpen = false;\n }\n}\n","/**\n * Commerce Engine Checkout\n *\n * @commercengine/js - Embeddable checkout SDK\n *\n * @example CDN Usage (Vanilla JS):\n * ```html\n * <script src=\"https://cdn.commercengine.com/v1.js\" async></script>\n * <script>\n * window.Commercengine.onLoad = async () => {\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"dark\",\n * onComplete: (order) => console.log(\"Order:\", order.orderNumber),\n * });\n *\n * document.getElementById(\"cart-btn\").onclick = () => checkout.openCart();\n * };\n * </script>\n * ```\n *\n * @example ESM Import:\n * ```typescript\n * import { Commercengine } from \"@commercengine/js\";\n *\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * });\n *\n * checkout.on(\"cart:updated\", (cart) => updateBadge(cart.count));\n * checkout.openCart();\n * ```\n */\n\nimport { Checkout } from \"./checkout\";\nimport type { CheckoutConfig } from \"./types\";\n\n// Re-export types for consumers\nexport type {\n AddToCartItem,\n AuthChangeData,\n AuthMode,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n ErrorData,\n OrderData,\n QuickBuyConfig,\n SessionMode,\n} from \"./types\";\n\nexport { Checkout };\n\n// =============================================================================\n// GLOBAL API\n// =============================================================================\n\n/**\n * Global Commercengine object interface\n */\ninterface CommercengineGlobal {\n /**\n * Initialize checkout with configuration\n * @returns Promise that resolves to Checkout instance\n */\n init: (config: CheckoutConfig) => Promise<Checkout>;\n\n /**\n * Callback invoked when script has loaded\n * Set this BEFORE including the script to be notified when ready\n */\n onLoad?: () => void;\n\n /**\n * Current checkout instance (if initialized)\n */\n instance?: Checkout;\n}\n\n/**\n * Global Commercengine namespace\n */\nconst Commercengine: CommercengineGlobal = {\n /**\n * Initialize checkout\n *\n * @param config - Checkout configuration\n * @returns Checkout instance\n *\n * @example\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"system\",\n * });\n */\n init: async (config: CheckoutConfig): Promise<Checkout> => {\n // Validate required fields - either url (for dev) or storeId+apiKey (for prod)\n if (!config.url && (!config.storeId || !config.apiKey)) {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided\"\n );\n }\n\n // Destroy existing instance if any\n if (Commercengine.instance) {\n Commercengine.instance.destroy();\n }\n\n // Create new instance\n const checkout = new Checkout(config);\n Commercengine.instance = checkout;\n\n // Wait for ready or error with timeout\n return new Promise((resolve, reject) => {\n if (checkout.ready) {\n resolve(checkout);\n return;\n }\n\n const timeoutMs = 30000; // 30 second timeout\n const timeout = setTimeout(() => {\n reject(new Error(\"Checkout initialization timed out\"));\n }, timeoutMs);\n\n // Resolve on ready\n checkout.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n\n // Also resolve on error (checkout is still usable, will show error drawer)\n checkout.once(\"error\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n });\n },\n};\n\n// =============================================================================\n// GLOBAL SETUP\n// =============================================================================\n\n// Expose on window for CDN usage\nif (typeof window !== \"undefined\") {\n // Preserve any existing onLoad callback set before script loaded\n const existingOnLoad = (window as unknown as { Commercengine?: CommercengineGlobal })\n .Commercengine?.onLoad;\n\n // Set global\n (window as unknown as { Commercengine: CommercengineGlobal }).Commercengine = Commercengine;\n\n // Restore and call onLoad if it was set\n if (existingOnLoad) {\n Commercengine.onLoad = existingOnLoad;\n try {\n existingOnLoad();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(\"[Commercengine] Error in onLoad callback:\", error);\n }\n }\n}\n\nexport { Commercengine };\nexport default Commercengine;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.iife.js","names":["onceListener: EventListener<T>","CHECKOUT_URLS: Record<Environment, string>","baseUrl: string","Commercengine: CommercengineGlobal"],"sources":["../src/events.ts","../src/iframe-manager.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":["/**\n * Simple Event Emitter\n *\n * Provides pub/sub functionality for checkout events.\n */\n\nimport type { CheckoutEventType, EventListener } from \"./types\";\n\nexport class EventEmitter {\n private listeners: Map<CheckoutEventType, Set<EventListener>> = new Map();\n\n /**\n * Subscribe to an event\n */\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)?.add(listener as EventListener);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener);\n }\n }\n\n /**\n * Subscribe to an event (once)\n */\n once<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const onceListener: EventListener<T> = (data) => {\n this.off(event, onceListener);\n listener(data);\n };\n this.on(event, onceListener);\n }\n\n /**\n * Emit an event to all subscribers\n */\n protected emit<T = unknown>(event: CheckoutEventType, data?: T): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(`[Commercengine] Error in ${event} listener:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners\n */\n protected removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * Iframe Manager\n *\n * Handles iframe creation, lifecycle, and visibility management.\n * The iframe is pre-mounted (hidden) on init and shown on demand.\n */\n\nimport type { OutgoingEventType } from \"./types\";\n\nexport class IframeManager {\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLDivElement | null = null;\n private checkoutOrigin: string | null = null;\n\n /**\n * Create and mount the iframe (hidden initially)\n */\n create(url: string, zIndex: number): void {\n if (this.container) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Iframe already created\");\n return;\n }\n\n // Store origin for postMessage security\n this.checkoutOrigin = new URL(url).origin;\n\n // Create container (covers viewport, initially non-interactive)\n this.container = document.createElement(\"div\");\n this.container.id = \"commercengine-checkout\";\n this.container.style.cssText = `\n position: fixed;\n inset: 0;\n z-index: ${zIndex};\n pointer-events: none;\n `;\n\n // Create iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"commercengine-checkout-iframe\";\n this.iframe.title = \"Shopping cart and checkout\";\n this.iframe.src = url;\n this.iframe.allow = \"payment\";\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n pointer-events: inherit;\n background-color: transparent;\n `;\n\n this.container.appendChild(this.iframe);\n document.body.appendChild(this.container);\n }\n\n /**\n * Show the checkout overlay (enable pointer events)\n */\n show(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"auto\";\n document.body.style.overflow = \"hidden\";\n }\n }\n\n /**\n * Hide the checkout overlay (disable pointer events)\n */\n hide(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"none\";\n document.body.style.overflow = \"\";\n }\n }\n\n /**\n * Check if iframe is visible\n */\n isVisible(): boolean {\n return this.container?.style.pointerEvents === \"auto\";\n }\n\n /**\n * Send a message to the checkout iframe\n */\n postMessage(type: OutgoingEventType, data?: unknown): void {\n if (!this.iframe?.contentWindow) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Cannot send message - iframe not ready\");\n return;\n }\n\n // Use specific origin for security - never use \"*\"\n if (!this.checkoutOrigin) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for security\n console.warn(\"[Commercengine] Cannot send message - checkout origin not established\");\n return;\n }\n this.iframe.contentWindow.postMessage({ type, data }, this.checkoutOrigin);\n }\n\n /**\n * Get the checkout origin for message validation\n */\n getCheckoutOrigin(): string | null {\n return this.checkoutOrigin;\n }\n\n /**\n * Destroy the iframe and clean up\n */\n destroy(): void {\n if (this.container) {\n this.container.remove();\n this.container = null;\n }\n this.iframe = null;\n this.checkoutOrigin = null;\n\n // Restore body scroll\n document.body.style.overflow = \"\";\n }\n}\n","/**\n * Checkout Class\n *\n * Main entry point for Commerce Engine Checkout integration.\n * Manages iframe lifecycle, event handling, and provides public API.\n */\n\nimport { EventEmitter } from \"./events\";\nimport { IframeManager } from \"./iframe-manager\";\nimport type {\n AuthLoginData,\n AuthLogoutData,\n AuthRefreshData,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n EventListener,\n IncomingEventType,\n OrderData,\n} from \"./types\";\n\n// =============================================================================\n// URL RESOLUTION\n// =============================================================================\n\n/** Checkout URLs by environment */\nconst CHECKOUT_URLS: Record<Environment, string> = {\n production: \"https://checkout.commercengine.com\",\n staging: \"https://staging.checkout.commercengine.com\",\n};\n\n/**\n * Build checkout iframe URL\n */\nfunction buildCheckoutUrl(storeId: string, apiKey: string, environment: Environment): string {\n const baseUrl = CHECKOUT_URLS[environment];\n return `${baseUrl}?store_id=${storeId}&api_key=${apiKey}&environment=${environment}&mode=iframe`;\n}\n\n// =============================================================================\n// CHECKOUT CLASS\n// =============================================================================\n\nexport class Checkout extends EventEmitter {\n private config: CheckoutConfig;\n private iframe: IframeManager;\n private isReady = false;\n private isOpen = false;\n private cartState: CartData = { count: 0, total: 0, currency: \"INR\" };\n private boundMessageHandler: (event: MessageEvent) => void;\n private hasQuickBuyParams = false; // Track if we detected quick buy params\n\n constructor(config: CheckoutConfig) {\n super();\n this.config = config;\n this.iframe = new IframeManager();\n this.boundMessageHandler = this.handleMessage.bind(this);\n this.initialize();\n }\n\n // ===========================================================================\n // INITIALIZATION\n // ===========================================================================\n\n private initialize(): void {\n // Build checkout URL - use direct URL if provided, otherwise resolve from credentials\n let baseUrl: string;\n if (this.config.url) {\n // Direct URL provided (local development)\n baseUrl = this.config.url;\n } else if (this.config.storeId && this.config.apiKey) {\n // Build URL from credentials + environment\n const env = this.config.environment || \"production\";\n baseUrl = buildCheckoutUrl(this.config.storeId, this.config.apiKey, env);\n } else {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided.\"\n );\n }\n\n const url = new URL(baseUrl);\n\n // Always set iframe mode\n url.searchParams.set(\"mode\", \"iframe\");\n\n // Add store credentials if provided and not already in URL\n if (this.config.storeId && !url.searchParams.has(\"store_id\")) {\n url.searchParams.set(\"store_id\", this.config.storeId);\n }\n if (this.config.apiKey && !url.searchParams.has(\"api_key\")) {\n url.searchParams.set(\"api_key\", this.config.apiKey);\n }\n if (this.config.environment && !url.searchParams.has(\"environment\")) {\n url.searchParams.set(\"environment\", this.config.environment);\n }\n\n // Add theme preference\n if (this.config.theme) {\n url.searchParams.set(\"theme\", this.config.theme);\n }\n\n // Add auth config\n if (this.config.authMode) {\n url.searchParams.set(\"auth_mode\", this.config.authMode);\n }\n if (this.config.accessToken) {\n url.searchParams.set(\"token\", this.config.accessToken);\n }\n if (this.config.refreshToken) {\n url.searchParams.set(\"refresh_token\", this.config.refreshToken);\n }\n\n // Auto-detect quick buy params from parent URL (if enabled and no explicit quickBuy)\n let quickBuy = this.config.quickBuy;\n let sessionMode = this.config.sessionMode;\n\n if (this.config.autoDetectQuickBuy && !quickBuy) {\n const parentParams = new URLSearchParams(window.location.search);\n const productId = parentParams.get(\"product_id\");\n const variantId = parentParams.get(\"variant_id\");\n\n if (productId) {\n quickBuy = {\n productId,\n variantId: variantId ?? null,\n quantity: parseInt(parentParams.get(\"qty\") || parentParams.get(\"quantity\") || \"1\", 10),\n };\n\n // Also check for session_mode in parent URL\n const parentSessionMode = parentParams.get(\"session_mode\");\n if (parentSessionMode === \"force-new\" || parentSessionMode === \"continue-existing\") {\n sessionMode = parentSessionMode;\n }\n\n // Clean quick buy params from URL to prevent duplicate adds on refresh\n // Deferred to next tick to handle React StrictMode double-mounting\n setTimeout(() => this.cleanQuickBuyParamsFromUrl(), 0);\n }\n }\n\n // Add quick buy params\n if (quickBuy) {\n this.hasQuickBuyParams = true;\n url.searchParams.set(\"product_id\", quickBuy.productId);\n if (quickBuy.variantId) {\n url.searchParams.set(\"variant_id\", quickBuy.variantId);\n }\n if (quickBuy.quantity && quickBuy.quantity !== 1) {\n url.searchParams.set(\"qty\", String(quickBuy.quantity));\n }\n }\n\n // Add session mode\n if (sessionMode) {\n url.searchParams.set(\"session_mode\", sessionMode);\n }\n\n // Pass parent origin for postMessage security\n // This allows the iframe to validate incoming messages and send responses to the correct origin\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"parent_origin\", window.location.origin);\n }\n\n // Create iframe (hidden initially, will show when ready + opened)\n const zIndex = this.config.appearance?.zIndex ?? 99999;\n this.iframe.create(url.toString(), zIndex);\n\n // Listen for messages from checkout iframe\n window.addEventListener(\"message\", this.boundMessageHandler);\n }\n\n // ===========================================================================\n // URL CLEANUP\n // ===========================================================================\n\n /**\n * Remove quick buy params from the parent URL to prevent duplicate adds on refresh\n * Uses replaceState to avoid adding to browser history\n */\n private cleanQuickBuyParamsFromUrl(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n const paramsToRemove = [\"product_id\", \"variant_id\", \"qty\", \"quantity\", \"session_mode\"];\n\n let hasChanges = false;\n for (const param of paramsToRemove) {\n if (url.searchParams.has(param)) {\n url.searchParams.delete(param);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n window.history.replaceState({}, \"\", url.toString());\n }\n }\n\n // ===========================================================================\n // MESSAGE HANDLING\n // ===========================================================================\n\n private handleMessage(event: MessageEvent): void {\n // Validate origin for security - reject if no expected origin or mismatch\n const expectedOrigin = this.iframe.getCheckoutOrigin();\n if (!expectedOrigin || event.origin !== expectedOrigin) {\n return;\n }\n\n const { type, data } = event.data || {};\n if (!type) return;\n\n switch (type as IncomingEventType) {\n case \"checkout:ready\":\n this.handleReady();\n break;\n\n case \"checkout:open\":\n this.handleOpen();\n break;\n\n case \"checkout:close\":\n this.handleClose();\n break;\n\n case \"checkout:complete\":\n this.handleComplete(data as OrderData);\n break;\n\n case \"checkout:error\":\n this.handleError(data as { message: string });\n break;\n\n case \"cart:updated\":\n this.handleCartUpdate(data as CartData);\n break;\n\n case \"auth:login\":\n this.handleLogin(data as AuthLoginData);\n break;\n\n case \"auth:logout\":\n this.handleLogout(data as AuthLogoutData);\n break;\n\n case \"auth:refresh\":\n this.handleTokenRefresh(data as AuthRefreshData);\n break;\n\n case \"auth:session-error\":\n this.handleSessionError();\n break;\n }\n }\n\n private handleReady(): void {\n this.isReady = true;\n this.config.onReady?.();\n this.emit(\"ready\");\n\n // Auto-open cart if we have quick buy params (from config or auto-detected URL)\n if (this.hasQuickBuyParams) {\n this.openCart();\n }\n }\n\n private handleError(data: { message: string }): void {\n // Set ready so user can still interact (they'll see the error drawer)\n this.isReady = true;\n this.config.onError?.(data);\n this.emit(\"error\", data);\n }\n\n private handleOpen(): void {\n this.iframe.show();\n this.isOpen = true;\n this.config.onOpen?.();\n this.emit(\"open\");\n }\n\n private handleClose(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.config.onClose?.();\n this.emit(\"close\");\n }\n\n private handleComplete(data: OrderData): void {\n this.config.onComplete?.(data);\n this.emit(\"complete\", data);\n }\n\n private handleCartUpdate(data: CartData): void {\n this.cartState = data;\n this.config.onCartUpdate?.(data);\n this.emit(\"cart:updated\", data);\n }\n\n private handleLogin(data: AuthLoginData): void {\n this.config.onLogin?.(data);\n this.emit(\"auth:login\", data);\n }\n\n private handleLogout(data: AuthLogoutData): void {\n this.config.onLogout?.(data);\n this.emit(\"auth:logout\", data);\n }\n\n private handleTokenRefresh(data: AuthRefreshData): void {\n this.config.onTokenRefresh?.(data);\n this.emit(\"auth:refresh\", data);\n }\n\n private handleSessionError(): void {\n this.config.onSessionError?.();\n this.emit(\"auth:session-error\");\n }\n\n // ===========================================================================\n // PUBLIC API\n // ===========================================================================\n\n /**\n * Open the cart drawer\n */\n openCart(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-cart\");\n }\n\n /**\n * Open the checkout drawer directly (e.g., for Buy Now flow)\n */\n openCheckout(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-checkout\");\n }\n\n /**\n * Close the checkout overlay\n */\n close(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.iframe.postMessage(\"checkout:close\");\n }\n\n /**\n * Update authentication tokens\n * Use this when user logs in/out on the parent site\n */\n updateTokens(accessToken: string, refreshToken?: string): void {\n if (!this.isReady) {\n // Store for when ready\n this.config.accessToken = accessToken;\n this.config.refreshToken = refreshToken;\n return;\n }\n\n this.iframe.postMessage(\"checkout:update-tokens\", { accessToken, refreshToken });\n }\n\n /**\n * Add an item to cart and open the cart drawer\n *\n * @param productId - Product ID (required)\n * @param variantId - Variant ID (required, null for non-variant products)\n * @param quantity - Quantity to add (default: 1)\n */\n addToCart(productId: string, variantId: string | null, quantity = 1): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.postMessage(\"checkout:add-item\", {\n productId,\n variantId,\n quantity,\n });\n\n // Auto-open cart to show the added item\n this.openCart();\n }\n\n /**\n * Get current cart state\n */\n getCart(): CartData {\n return { ...this.cartState };\n }\n\n /**\n * Check if checkout is ready\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Check if checkout overlay is currently open\n */\n get open(): boolean {\n return this.isOpen;\n }\n\n /**\n * Subscribe to an event\n * @override EventEmitter.on with typed overloads\n */\n on(event: \"ready\", listener: EventListener<void>): void;\n on(event: \"open\", listener: EventListener<void>): void;\n on(event: \"close\", listener: EventListener<void>): void;\n on(event: \"complete\", listener: EventListener<OrderData>): void;\n on(event: \"cart:updated\", listener: EventListener<CartData>): void;\n on(event: \"auth:login\", listener: EventListener<AuthLoginData>): void;\n on(event: \"auth:logout\", listener: EventListener<AuthLogoutData>): void;\n on(event: \"auth:refresh\", listener: EventListener<AuthRefreshData>): void;\n on(event: \"auth:session-error\", listener: EventListener<void>): void;\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n super.on(event, listener);\n }\n\n /**\n * Destroy the checkout instance\n * Removes iframe and cleans up event listeners\n */\n destroy(): void {\n window.removeEventListener(\"message\", this.boundMessageHandler);\n this.iframe.destroy();\n this.removeAllListeners();\n this.isReady = false;\n this.isOpen = false;\n }\n}\n","/**\n * Commerce Engine Checkout\n *\n * @commercengine/js - Embeddable checkout SDK\n *\n * @example CDN Usage (Vanilla JS):\n * ```html\n * <script src=\"https://cdn.commercengine.com/v1.js\" async></script>\n * <script>\n * window.Commercengine.onLoad = async () => {\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"dark\",\n * onComplete: (order) => console.log(\"Order:\", order.orderNumber),\n * });\n *\n * document.getElementById(\"cart-btn\").onclick = () => checkout.openCart();\n * };\n * </script>\n * ```\n *\n * @example ESM Import:\n * ```typescript\n * import { Commercengine } from \"@commercengine/js\";\n *\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * });\n *\n * checkout.on(\"cart:updated\", (cart) => updateBadge(cart.count));\n * checkout.openCart();\n * ```\n */\n\nimport { Checkout } from \"./checkout\";\nimport type { CheckoutConfig } from \"./types\";\n\n// Re-export types for consumers\nexport type {\n AddToCartItem,\n AuthLoginData,\n AuthLogoutData,\n AuthMode,\n AuthRefreshData,\n CartData,\n Channel,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n ErrorData,\n LoginMethod,\n OrderData,\n QuickBuyConfig,\n SessionMode,\n UserInfo,\n} from \"./types\";\n\nexport { Checkout };\n\n// =============================================================================\n// GLOBAL API\n// =============================================================================\n\n/**\n * Global Commercengine object interface\n */\ninterface CommercengineGlobal {\n /**\n * Initialize checkout with configuration\n * @returns Promise that resolves to Checkout instance\n */\n init: (config: CheckoutConfig) => Promise<Checkout>;\n\n /**\n * Callback invoked when script has loaded\n * Set this BEFORE including the script to be notified when ready\n */\n onLoad?: () => void;\n\n /**\n * Current checkout instance (if initialized)\n */\n instance?: Checkout;\n}\n\n/**\n * Global Commercengine namespace\n */\nconst Commercengine: CommercengineGlobal = {\n /**\n * Initialize checkout\n *\n * @param config - Checkout configuration\n * @returns Checkout instance\n *\n * @example\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"system\",\n * });\n */\n init: async (config: CheckoutConfig): Promise<Checkout> => {\n // Validate required fields - either url (for dev) or storeId+apiKey (for prod)\n if (!config.url && (!config.storeId || !config.apiKey)) {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided\"\n );\n }\n\n // Destroy existing instance if any\n if (Commercengine.instance) {\n Commercengine.instance.destroy();\n }\n\n // Create new instance\n const checkout = new Checkout(config);\n Commercengine.instance = checkout;\n\n // Wait for ready or error with timeout\n return new Promise((resolve, reject) => {\n if (checkout.ready) {\n resolve(checkout);\n return;\n }\n\n const timeoutMs = 30000; // 30 second timeout\n const timeout = setTimeout(() => {\n reject(new Error(\"Checkout initialization timed out\"));\n }, timeoutMs);\n\n // Resolve on ready\n checkout.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n\n // Also resolve on error (checkout is still usable, will show error drawer)\n checkout.once(\"error\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n });\n },\n};\n\n// =============================================================================\n// GLOBAL SETUP\n// =============================================================================\n\n// Expose on window for CDN usage\nif (typeof window !== \"undefined\") {\n // Preserve any existing onLoad callback set before script loaded\n const existingOnLoad = (window as unknown as { Commercengine?: CommercengineGlobal })\n .Commercengine?.onLoad;\n\n // Set global\n (window as unknown as { Commercengine: CommercengineGlobal }).Commercengine = Commercengine;\n\n // Restore and call onLoad if it was set\n if (existingOnLoad) {\n Commercengine.onLoad = existingOnLoad;\n try {\n existingOnLoad();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(\"[Commercengine] Error in onLoad callback:\", error);\n }\n }\n}\n\nexport { Commercengine };\nexport default Commercengine;\n"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -73,6 +73,7 @@ var IframeManager = class {
73
73
  `;
74
74
  this.iframe = document.createElement("iframe");
75
75
  this.iframe.id = "commercengine-checkout-iframe";
76
+ this.iframe.title = "Shopping cart and checkout";
76
77
  this.iframe.src = url;
77
78
  this.iframe.allow = "payment";
78
79
  this.iframe.style.cssText = `
@@ -272,19 +273,16 @@ var Checkout = class extends EventEmitter {
272
273
  this.handleCartUpdate(data);
273
274
  break;
274
275
  case "auth:login":
275
- this.handleAuthChange({
276
- type: "login",
277
- ...data
278
- });
276
+ this.handleLogin(data);
279
277
  break;
280
278
  case "auth:logout":
281
- this.handleAuthChange({ type: "logout" });
279
+ this.handleLogout(data);
282
280
  break;
283
281
  case "auth:refresh":
284
- this.handleAuthChange({
285
- type: "refresh",
286
- ...data
287
- });
282
+ this.handleTokenRefresh(data);
283
+ break;
284
+ case "auth:session-error":
285
+ this.handleSessionError();
288
286
  break;
289
287
  }
290
288
  }
@@ -320,9 +318,21 @@ var Checkout = class extends EventEmitter {
320
318
  this.config.onCartUpdate?.(data);
321
319
  this.emit("cart:updated", data);
322
320
  }
323
- handleAuthChange(data) {
324
- this.config.onAuthChange?.(data);
325
- this.emit("auth:change", data);
321
+ handleLogin(data) {
322
+ this.config.onLogin?.(data);
323
+ this.emit("auth:login", data);
324
+ }
325
+ handleLogout(data) {
326
+ this.config.onLogout?.(data);
327
+ this.emit("auth:logout", data);
328
+ }
329
+ handleTokenRefresh(data) {
330
+ this.config.onTokenRefresh?.(data);
331
+ this.emit("auth:refresh", data);
332
+ }
333
+ handleSessionError() {
334
+ this.config.onSessionError?.();
335
+ this.emit("auth:session-error");
326
336
  }
327
337
  /**
328
338
  * Open the cart drawer
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["onceListener: EventListener<T>","CHECKOUT_URLS: Record<Environment, string>","baseUrl: string","Commercengine: CommercengineGlobal"],"sources":["../src/events.ts","../src/iframe-manager.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":["/**\n * Simple Event Emitter\n *\n * Provides pub/sub functionality for checkout events.\n */\n\nimport type { CheckoutEventType, EventListener } from \"./types\";\n\nexport class EventEmitter {\n private listeners: Map<CheckoutEventType, Set<EventListener>> = new Map();\n\n /**\n * Subscribe to an event\n */\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)?.add(listener as EventListener);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener);\n }\n }\n\n /**\n * Subscribe to an event (once)\n */\n once<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const onceListener: EventListener<T> = (data) => {\n this.off(event, onceListener);\n listener(data);\n };\n this.on(event, onceListener);\n }\n\n /**\n * Emit an event to all subscribers\n */\n protected emit<T = unknown>(event: CheckoutEventType, data?: T): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(`[Commercengine] Error in ${event} listener:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners\n */\n protected removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * Iframe Manager\n *\n * Handles iframe creation, lifecycle, and visibility management.\n * The iframe is pre-mounted (hidden) on init and shown on demand.\n */\n\nimport type { OutgoingEventType } from \"./types\";\n\nexport class IframeManager {\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLDivElement | null = null;\n private checkoutOrigin: string | null = null;\n\n /**\n * Create and mount the iframe (hidden initially)\n */\n create(url: string, zIndex: number): void {\n if (this.container) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Iframe already created\");\n return;\n }\n\n // Store origin for postMessage security\n this.checkoutOrigin = new URL(url).origin;\n\n // Create container (covers viewport, initially non-interactive)\n this.container = document.createElement(\"div\");\n this.container.id = \"commercengine-checkout\";\n this.container.style.cssText = `\n position: fixed;\n inset: 0;\n z-index: ${zIndex};\n pointer-events: none;\n `;\n\n // Create iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"commercengine-checkout-iframe\";\n this.iframe.src = url;\n this.iframe.allow = \"payment\";\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n pointer-events: inherit;\n background-color: transparent;\n `;\n\n this.container.appendChild(this.iframe);\n document.body.appendChild(this.container);\n }\n\n /**\n * Show the checkout overlay (enable pointer events)\n */\n show(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"auto\";\n document.body.style.overflow = \"hidden\";\n }\n }\n\n /**\n * Hide the checkout overlay (disable pointer events)\n */\n hide(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"none\";\n document.body.style.overflow = \"\";\n }\n }\n\n /**\n * Check if iframe is visible\n */\n isVisible(): boolean {\n return this.container?.style.pointerEvents === \"auto\";\n }\n\n /**\n * Send a message to the checkout iframe\n */\n postMessage(type: OutgoingEventType, data?: unknown): void {\n if (!this.iframe?.contentWindow) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Cannot send message - iframe not ready\");\n return;\n }\n\n // Use specific origin for security - never use \"*\"\n if (!this.checkoutOrigin) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for security\n console.warn(\"[Commercengine] Cannot send message - checkout origin not established\");\n return;\n }\n this.iframe.contentWindow.postMessage({ type, data }, this.checkoutOrigin);\n }\n\n /**\n * Get the checkout origin for message validation\n */\n getCheckoutOrigin(): string | null {\n return this.checkoutOrigin;\n }\n\n /**\n * Destroy the iframe and clean up\n */\n destroy(): void {\n if (this.container) {\n this.container.remove();\n this.container = null;\n }\n this.iframe = null;\n this.checkoutOrigin = null;\n\n // Restore body scroll\n document.body.style.overflow = \"\";\n }\n}\n","/**\n * Checkout Class\n *\n * Main entry point for Commerce Engine Checkout integration.\n * Manages iframe lifecycle, event handling, and provides public API.\n */\n\nimport { EventEmitter } from \"./events\";\nimport { IframeManager } from \"./iframe-manager\";\nimport type {\n AuthChangeData,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n EventListener,\n IncomingEventType,\n OrderData,\n} from \"./types\";\n\n// =============================================================================\n// URL RESOLUTION\n// =============================================================================\n\n/** Checkout URLs by environment */\nconst CHECKOUT_URLS: Record<Environment, string> = {\n production: \"https://checkout.commercengine.com\",\n staging: \"https://staging.checkout.commercengine.com\",\n};\n\n/**\n * Build checkout iframe URL\n */\nfunction buildCheckoutUrl(storeId: string, apiKey: string, environment: Environment): string {\n const baseUrl = CHECKOUT_URLS[environment];\n return `${baseUrl}?store_id=${storeId}&api_key=${apiKey}&environment=${environment}&mode=iframe`;\n}\n\n// =============================================================================\n// CHECKOUT CLASS\n// =============================================================================\n\nexport class Checkout extends EventEmitter {\n private config: CheckoutConfig;\n private iframe: IframeManager;\n private isReady = false;\n private isOpen = false;\n private cartState: CartData = { count: 0, total: 0, currency: \"INR\" };\n private boundMessageHandler: (event: MessageEvent) => void;\n private hasQuickBuyParams = false; // Track if we detected quick buy params\n\n constructor(config: CheckoutConfig) {\n super();\n this.config = config;\n this.iframe = new IframeManager();\n this.boundMessageHandler = this.handleMessage.bind(this);\n this.initialize();\n }\n\n // ===========================================================================\n // INITIALIZATION\n // ===========================================================================\n\n private initialize(): void {\n // Build checkout URL - use direct URL if provided, otherwise resolve from credentials\n let baseUrl: string;\n if (this.config.url) {\n // Direct URL provided (local development)\n baseUrl = this.config.url;\n } else if (this.config.storeId && this.config.apiKey) {\n // Build URL from credentials + environment\n const env = this.config.environment || \"production\";\n baseUrl = buildCheckoutUrl(this.config.storeId, this.config.apiKey, env);\n } else {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided.\"\n );\n }\n\n const url = new URL(baseUrl);\n\n // Always set iframe mode\n url.searchParams.set(\"mode\", \"iframe\");\n\n // Add store credentials if provided and not already in URL\n if (this.config.storeId && !url.searchParams.has(\"store_id\")) {\n url.searchParams.set(\"store_id\", this.config.storeId);\n }\n if (this.config.apiKey && !url.searchParams.has(\"api_key\")) {\n url.searchParams.set(\"api_key\", this.config.apiKey);\n }\n if (this.config.environment && !url.searchParams.has(\"environment\")) {\n url.searchParams.set(\"environment\", this.config.environment);\n }\n\n // Add theme preference\n if (this.config.theme) {\n url.searchParams.set(\"theme\", this.config.theme);\n }\n\n // Add auth config\n if (this.config.authMode) {\n url.searchParams.set(\"auth_mode\", this.config.authMode);\n }\n if (this.config.accessToken) {\n url.searchParams.set(\"token\", this.config.accessToken);\n }\n if (this.config.refreshToken) {\n url.searchParams.set(\"refresh_token\", this.config.refreshToken);\n }\n\n // Auto-detect quick buy params from parent URL (if enabled and no explicit quickBuy)\n let quickBuy = this.config.quickBuy;\n let sessionMode = this.config.sessionMode;\n\n if (this.config.autoDetectQuickBuy && !quickBuy) {\n const parentParams = new URLSearchParams(window.location.search);\n const productId = parentParams.get(\"product_id\");\n const variantId = parentParams.get(\"variant_id\");\n\n if (productId) {\n quickBuy = {\n productId,\n variantId: variantId ?? null,\n quantity: parseInt(parentParams.get(\"qty\") || parentParams.get(\"quantity\") || \"1\", 10),\n };\n\n // Also check for session_mode in parent URL\n const parentSessionMode = parentParams.get(\"session_mode\");\n if (parentSessionMode === \"force-new\" || parentSessionMode === \"continue-existing\") {\n sessionMode = parentSessionMode;\n }\n\n // Clean quick buy params from URL to prevent duplicate adds on refresh\n // Deferred to next tick to handle React StrictMode double-mounting\n setTimeout(() => this.cleanQuickBuyParamsFromUrl(), 0);\n }\n }\n\n // Add quick buy params\n if (quickBuy) {\n this.hasQuickBuyParams = true;\n url.searchParams.set(\"product_id\", quickBuy.productId);\n if (quickBuy.variantId) {\n url.searchParams.set(\"variant_id\", quickBuy.variantId);\n }\n if (quickBuy.quantity && quickBuy.quantity !== 1) {\n url.searchParams.set(\"qty\", String(quickBuy.quantity));\n }\n }\n\n // Add session mode\n if (sessionMode) {\n url.searchParams.set(\"session_mode\", sessionMode);\n }\n\n // Pass parent origin for postMessage security\n // This allows the iframe to validate incoming messages and send responses to the correct origin\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"parent_origin\", window.location.origin);\n }\n\n // Create iframe (hidden initially, will show when ready + opened)\n const zIndex = this.config.appearance?.zIndex ?? 99999;\n this.iframe.create(url.toString(), zIndex);\n\n // Listen for messages from checkout iframe\n window.addEventListener(\"message\", this.boundMessageHandler);\n }\n\n // ===========================================================================\n // URL CLEANUP\n // ===========================================================================\n\n /**\n * Remove quick buy params from the parent URL to prevent duplicate adds on refresh\n * Uses replaceState to avoid adding to browser history\n */\n private cleanQuickBuyParamsFromUrl(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n const paramsToRemove = [\"product_id\", \"variant_id\", \"qty\", \"quantity\", \"session_mode\"];\n\n let hasChanges = false;\n for (const param of paramsToRemove) {\n if (url.searchParams.has(param)) {\n url.searchParams.delete(param);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n window.history.replaceState({}, \"\", url.toString());\n }\n }\n\n // ===========================================================================\n // MESSAGE HANDLING\n // ===========================================================================\n\n private handleMessage(event: MessageEvent): void {\n // Validate origin for security - reject if no expected origin or mismatch\n const expectedOrigin = this.iframe.getCheckoutOrigin();\n if (!expectedOrigin || event.origin !== expectedOrigin) {\n return;\n }\n\n const { type, data } = event.data || {};\n if (!type) return;\n\n switch (type as IncomingEventType) {\n case \"checkout:ready\":\n this.handleReady();\n break;\n\n case \"checkout:open\":\n this.handleOpen();\n break;\n\n case \"checkout:close\":\n this.handleClose();\n break;\n\n case \"checkout:complete\":\n this.handleComplete(data as OrderData);\n break;\n\n case \"checkout:error\":\n this.handleError(data as { message: string });\n break;\n\n case \"cart:updated\":\n this.handleCartUpdate(data as CartData);\n break;\n\n case \"auth:login\":\n this.handleAuthChange({ type: \"login\", ...data });\n break;\n\n case \"auth:logout\":\n this.handleAuthChange({ type: \"logout\" });\n break;\n\n case \"auth:refresh\":\n this.handleAuthChange({ type: \"refresh\", ...data });\n break;\n }\n }\n\n private handleReady(): void {\n this.isReady = true;\n this.config.onReady?.();\n this.emit(\"ready\");\n\n // Auto-open cart if we have quick buy params (from config or auto-detected URL)\n if (this.hasQuickBuyParams) {\n this.openCart();\n }\n }\n\n private handleError(data: { message: string }): void {\n // Set ready so user can still interact (they'll see the error drawer)\n this.isReady = true;\n this.config.onError?.(data);\n this.emit(\"error\", data);\n }\n\n private handleOpen(): void {\n this.iframe.show();\n this.isOpen = true;\n this.config.onOpen?.();\n this.emit(\"open\");\n }\n\n private handleClose(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.config.onClose?.();\n this.emit(\"close\");\n }\n\n private handleComplete(data: OrderData): void {\n this.config.onComplete?.(data);\n this.emit(\"complete\", data);\n }\n\n private handleCartUpdate(data: CartData): void {\n this.cartState = data;\n this.config.onCartUpdate?.(data);\n this.emit(\"cart:updated\", data);\n }\n\n private handleAuthChange(data: AuthChangeData): void {\n this.config.onAuthChange?.(data);\n this.emit(\"auth:change\", data);\n }\n\n // ===========================================================================\n // PUBLIC API\n // ===========================================================================\n\n /**\n * Open the cart drawer\n */\n openCart(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-cart\");\n }\n\n /**\n * Open the checkout drawer directly (e.g., for Buy Now flow)\n */\n openCheckout(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-checkout\");\n }\n\n /**\n * Close the checkout overlay\n */\n close(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.iframe.postMessage(\"checkout:close\");\n }\n\n /**\n * Update authentication tokens\n * Use this when user logs in/out on the parent site\n */\n updateTokens(accessToken: string, refreshToken?: string): void {\n if (!this.isReady) {\n // Store for when ready\n this.config.accessToken = accessToken;\n this.config.refreshToken = refreshToken;\n return;\n }\n\n this.iframe.postMessage(\"checkout:update-tokens\", { accessToken, refreshToken });\n }\n\n /**\n * Add an item to cart and open the cart drawer\n *\n * @param productId - Product ID (required)\n * @param variantId - Variant ID (required, null for non-variant products)\n * @param quantity - Quantity to add (default: 1)\n */\n addToCart(productId: string, variantId: string | null, quantity = 1): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.postMessage(\"checkout:add-item\", {\n productId,\n variantId,\n quantity,\n });\n\n // Auto-open cart to show the added item\n this.openCart();\n }\n\n /**\n * Get current cart state\n */\n getCart(): CartData {\n return { ...this.cartState };\n }\n\n /**\n * Check if checkout is ready\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Check if checkout overlay is currently open\n */\n get open(): boolean {\n return this.isOpen;\n }\n\n /**\n * Subscribe to an event\n * @override EventEmitter.on with typed overloads\n */\n on(event: \"ready\", listener: EventListener<void>): void;\n on(event: \"open\", listener: EventListener<void>): void;\n on(event: \"close\", listener: EventListener<void>): void;\n on(event: \"complete\", listener: EventListener<OrderData>): void;\n on(event: \"cart:updated\", listener: EventListener<CartData>): void;\n on(event: \"auth:change\", listener: EventListener<AuthChangeData>): void;\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n super.on(event, listener);\n }\n\n /**\n * Destroy the checkout instance\n * Removes iframe and cleans up event listeners\n */\n destroy(): void {\n window.removeEventListener(\"message\", this.boundMessageHandler);\n this.iframe.destroy();\n this.removeAllListeners();\n this.isReady = false;\n this.isOpen = false;\n }\n}\n","/**\n * Commerce Engine Checkout\n *\n * @commercengine/js - Embeddable checkout SDK\n *\n * @example CDN Usage (Vanilla JS):\n * ```html\n * <script src=\"https://cdn.commercengine.com/v1.js\" async></script>\n * <script>\n * window.Commercengine.onLoad = async () => {\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"dark\",\n * onComplete: (order) => console.log(\"Order:\", order.orderNumber),\n * });\n *\n * document.getElementById(\"cart-btn\").onclick = () => checkout.openCart();\n * };\n * </script>\n * ```\n *\n * @example ESM Import:\n * ```typescript\n * import { Commercengine } from \"@commercengine/js\";\n *\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * });\n *\n * checkout.on(\"cart:updated\", (cart) => updateBadge(cart.count));\n * checkout.openCart();\n * ```\n */\n\nimport { Checkout } from \"./checkout\";\nimport type { CheckoutConfig } from \"./types\";\n\n// Re-export types for consumers\nexport type {\n AddToCartItem,\n AuthChangeData,\n AuthMode,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n ErrorData,\n OrderData,\n QuickBuyConfig,\n SessionMode,\n} from \"./types\";\n\nexport { Checkout };\n\n// =============================================================================\n// GLOBAL API\n// =============================================================================\n\n/**\n * Global Commercengine object interface\n */\ninterface CommercengineGlobal {\n /**\n * Initialize checkout with configuration\n * @returns Promise that resolves to Checkout instance\n */\n init: (config: CheckoutConfig) => Promise<Checkout>;\n\n /**\n * Callback invoked when script has loaded\n * Set this BEFORE including the script to be notified when ready\n */\n onLoad?: () => void;\n\n /**\n * Current checkout instance (if initialized)\n */\n instance?: Checkout;\n}\n\n/**\n * Global Commercengine namespace\n */\nconst Commercengine: CommercengineGlobal = {\n /**\n * Initialize checkout\n *\n * @param config - Checkout configuration\n * @returns Checkout instance\n *\n * @example\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"system\",\n * });\n */\n init: async (config: CheckoutConfig): Promise<Checkout> => {\n // Validate required fields - either url (for dev) or storeId+apiKey (for prod)\n if (!config.url && (!config.storeId || !config.apiKey)) {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided\"\n );\n }\n\n // Destroy existing instance if any\n if (Commercengine.instance) {\n Commercengine.instance.destroy();\n }\n\n // Create new instance\n const checkout = new Checkout(config);\n Commercengine.instance = checkout;\n\n // Wait for ready or error with timeout\n return new Promise((resolve, reject) => {\n if (checkout.ready) {\n resolve(checkout);\n return;\n }\n\n const timeoutMs = 30000; // 30 second timeout\n const timeout = setTimeout(() => {\n reject(new Error(\"Checkout initialization timed out\"));\n }, timeoutMs);\n\n // Resolve on ready\n checkout.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n\n // Also resolve on error (checkout is still usable, will show error drawer)\n checkout.once(\"error\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n });\n },\n};\n\n// =============================================================================\n// GLOBAL SETUP\n// =============================================================================\n\n// Expose on window for CDN usage\nif (typeof window !== \"undefined\") {\n // Preserve any existing onLoad callback set before script loaded\n const existingOnLoad = (window as unknown as { Commercengine?: CommercengineGlobal })\n .Commercengine?.onLoad;\n\n // Set global\n (window as unknown as { Commercengine: CommercengineGlobal }).Commercengine = Commercengine;\n\n // Restore and call onLoad if it was set\n if (existingOnLoad) {\n Commercengine.onLoad = existingOnLoad;\n try {\n existingOnLoad();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(\"[Commercengine] Error in onLoad callback:\", error);\n }\n }\n}\n\nexport { Commercengine };\nexport default Commercengine;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["onceListener: EventListener<T>","CHECKOUT_URLS: Record<Environment, string>","baseUrl: string","Commercengine: CommercengineGlobal"],"sources":["../src/events.ts","../src/iframe-manager.ts","../src/checkout.ts","../src/index.ts"],"sourcesContent":["/**\n * Simple Event Emitter\n *\n * Provides pub/sub functionality for checkout events.\n */\n\nimport type { CheckoutEventType, EventListener } from \"./types\";\n\nexport class EventEmitter {\n private listeners: Map<CheckoutEventType, Set<EventListener>> = new Map();\n\n /**\n * Subscribe to an event\n */\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)?.add(listener as EventListener);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener);\n }\n }\n\n /**\n * Subscribe to an event (once)\n */\n once<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n const onceListener: EventListener<T> = (data) => {\n this.off(event, onceListener);\n listener(data);\n };\n this.on(event, onceListener);\n }\n\n /**\n * Emit an event to all subscribers\n */\n protected emit<T = unknown>(event: CheckoutEventType, data?: T): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(`[Commercengine] Error in ${event} listener:`, error);\n }\n }\n }\n }\n\n /**\n * Remove all listeners\n */\n protected removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","/**\n * Iframe Manager\n *\n * Handles iframe creation, lifecycle, and visibility management.\n * The iframe is pre-mounted (hidden) on init and shown on demand.\n */\n\nimport type { OutgoingEventType } from \"./types\";\n\nexport class IframeManager {\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLDivElement | null = null;\n private checkoutOrigin: string | null = null;\n\n /**\n * Create and mount the iframe (hidden initially)\n */\n create(url: string, zIndex: number): void {\n if (this.container) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Iframe already created\");\n return;\n }\n\n // Store origin for postMessage security\n this.checkoutOrigin = new URL(url).origin;\n\n // Create container (covers viewport, initially non-interactive)\n this.container = document.createElement(\"div\");\n this.container.id = \"commercengine-checkout\";\n this.container.style.cssText = `\n position: fixed;\n inset: 0;\n z-index: ${zIndex};\n pointer-events: none;\n `;\n\n // Create iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"commercengine-checkout-iframe\";\n this.iframe.title = \"Shopping cart and checkout\";\n this.iframe.src = url;\n this.iframe.allow = \"payment\";\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n pointer-events: inherit;\n background-color: transparent;\n `;\n\n this.container.appendChild(this.iframe);\n document.body.appendChild(this.container);\n }\n\n /**\n * Show the checkout overlay (enable pointer events)\n */\n show(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"auto\";\n document.body.style.overflow = \"hidden\";\n }\n }\n\n /**\n * Hide the checkout overlay (disable pointer events)\n */\n hide(): void {\n if (this.container) {\n this.container.style.pointerEvents = \"none\";\n document.body.style.overflow = \"\";\n }\n }\n\n /**\n * Check if iframe is visible\n */\n isVisible(): boolean {\n return this.container?.style.pointerEvents === \"auto\";\n }\n\n /**\n * Send a message to the checkout iframe\n */\n postMessage(type: OutgoingEventType, data?: unknown): void {\n if (!this.iframe?.contentWindow) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Cannot send message - iframe not ready\");\n return;\n }\n\n // Use specific origin for security - never use \"*\"\n if (!this.checkoutOrigin) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for security\n console.warn(\"[Commercengine] Cannot send message - checkout origin not established\");\n return;\n }\n this.iframe.contentWindow.postMessage({ type, data }, this.checkoutOrigin);\n }\n\n /**\n * Get the checkout origin for message validation\n */\n getCheckoutOrigin(): string | null {\n return this.checkoutOrigin;\n }\n\n /**\n * Destroy the iframe and clean up\n */\n destroy(): void {\n if (this.container) {\n this.container.remove();\n this.container = null;\n }\n this.iframe = null;\n this.checkoutOrigin = null;\n\n // Restore body scroll\n document.body.style.overflow = \"\";\n }\n}\n","/**\n * Checkout Class\n *\n * Main entry point for Commerce Engine Checkout integration.\n * Manages iframe lifecycle, event handling, and provides public API.\n */\n\nimport { EventEmitter } from \"./events\";\nimport { IframeManager } from \"./iframe-manager\";\nimport type {\n AuthLoginData,\n AuthLogoutData,\n AuthRefreshData,\n CartData,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n EventListener,\n IncomingEventType,\n OrderData,\n} from \"./types\";\n\n// =============================================================================\n// URL RESOLUTION\n// =============================================================================\n\n/** Checkout URLs by environment */\nconst CHECKOUT_URLS: Record<Environment, string> = {\n production: \"https://checkout.commercengine.com\",\n staging: \"https://staging.checkout.commercengine.com\",\n};\n\n/**\n * Build checkout iframe URL\n */\nfunction buildCheckoutUrl(storeId: string, apiKey: string, environment: Environment): string {\n const baseUrl = CHECKOUT_URLS[environment];\n return `${baseUrl}?store_id=${storeId}&api_key=${apiKey}&environment=${environment}&mode=iframe`;\n}\n\n// =============================================================================\n// CHECKOUT CLASS\n// =============================================================================\n\nexport class Checkout extends EventEmitter {\n private config: CheckoutConfig;\n private iframe: IframeManager;\n private isReady = false;\n private isOpen = false;\n private cartState: CartData = { count: 0, total: 0, currency: \"INR\" };\n private boundMessageHandler: (event: MessageEvent) => void;\n private hasQuickBuyParams = false; // Track if we detected quick buy params\n\n constructor(config: CheckoutConfig) {\n super();\n this.config = config;\n this.iframe = new IframeManager();\n this.boundMessageHandler = this.handleMessage.bind(this);\n this.initialize();\n }\n\n // ===========================================================================\n // INITIALIZATION\n // ===========================================================================\n\n private initialize(): void {\n // Build checkout URL - use direct URL if provided, otherwise resolve from credentials\n let baseUrl: string;\n if (this.config.url) {\n // Direct URL provided (local development)\n baseUrl = this.config.url;\n } else if (this.config.storeId && this.config.apiKey) {\n // Build URL from credentials + environment\n const env = this.config.environment || \"production\";\n baseUrl = buildCheckoutUrl(this.config.storeId, this.config.apiKey, env);\n } else {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided.\"\n );\n }\n\n const url = new URL(baseUrl);\n\n // Always set iframe mode\n url.searchParams.set(\"mode\", \"iframe\");\n\n // Add store credentials if provided and not already in URL\n if (this.config.storeId && !url.searchParams.has(\"store_id\")) {\n url.searchParams.set(\"store_id\", this.config.storeId);\n }\n if (this.config.apiKey && !url.searchParams.has(\"api_key\")) {\n url.searchParams.set(\"api_key\", this.config.apiKey);\n }\n if (this.config.environment && !url.searchParams.has(\"environment\")) {\n url.searchParams.set(\"environment\", this.config.environment);\n }\n\n // Add theme preference\n if (this.config.theme) {\n url.searchParams.set(\"theme\", this.config.theme);\n }\n\n // Add auth config\n if (this.config.authMode) {\n url.searchParams.set(\"auth_mode\", this.config.authMode);\n }\n if (this.config.accessToken) {\n url.searchParams.set(\"token\", this.config.accessToken);\n }\n if (this.config.refreshToken) {\n url.searchParams.set(\"refresh_token\", this.config.refreshToken);\n }\n\n // Auto-detect quick buy params from parent URL (if enabled and no explicit quickBuy)\n let quickBuy = this.config.quickBuy;\n let sessionMode = this.config.sessionMode;\n\n if (this.config.autoDetectQuickBuy && !quickBuy) {\n const parentParams = new URLSearchParams(window.location.search);\n const productId = parentParams.get(\"product_id\");\n const variantId = parentParams.get(\"variant_id\");\n\n if (productId) {\n quickBuy = {\n productId,\n variantId: variantId ?? null,\n quantity: parseInt(parentParams.get(\"qty\") || parentParams.get(\"quantity\") || \"1\", 10),\n };\n\n // Also check for session_mode in parent URL\n const parentSessionMode = parentParams.get(\"session_mode\");\n if (parentSessionMode === \"force-new\" || parentSessionMode === \"continue-existing\") {\n sessionMode = parentSessionMode;\n }\n\n // Clean quick buy params from URL to prevent duplicate adds on refresh\n // Deferred to next tick to handle React StrictMode double-mounting\n setTimeout(() => this.cleanQuickBuyParamsFromUrl(), 0);\n }\n }\n\n // Add quick buy params\n if (quickBuy) {\n this.hasQuickBuyParams = true;\n url.searchParams.set(\"product_id\", quickBuy.productId);\n if (quickBuy.variantId) {\n url.searchParams.set(\"variant_id\", quickBuy.variantId);\n }\n if (quickBuy.quantity && quickBuy.quantity !== 1) {\n url.searchParams.set(\"qty\", String(quickBuy.quantity));\n }\n }\n\n // Add session mode\n if (sessionMode) {\n url.searchParams.set(\"session_mode\", sessionMode);\n }\n\n // Pass parent origin for postMessage security\n // This allows the iframe to validate incoming messages and send responses to the correct origin\n if (typeof window !== \"undefined\") {\n url.searchParams.set(\"parent_origin\", window.location.origin);\n }\n\n // Create iframe (hidden initially, will show when ready + opened)\n const zIndex = this.config.appearance?.zIndex ?? 99999;\n this.iframe.create(url.toString(), zIndex);\n\n // Listen for messages from checkout iframe\n window.addEventListener(\"message\", this.boundMessageHandler);\n }\n\n // ===========================================================================\n // URL CLEANUP\n // ===========================================================================\n\n /**\n * Remove quick buy params from the parent URL to prevent duplicate adds on refresh\n * Uses replaceState to avoid adding to browser history\n */\n private cleanQuickBuyParamsFromUrl(): void {\n if (typeof window === \"undefined\") return;\n\n const url = new URL(window.location.href);\n const paramsToRemove = [\"product_id\", \"variant_id\", \"qty\", \"quantity\", \"session_mode\"];\n\n let hasChanges = false;\n for (const param of paramsToRemove) {\n if (url.searchParams.has(param)) {\n url.searchParams.delete(param);\n hasChanges = true;\n }\n }\n\n if (hasChanges) {\n window.history.replaceState({}, \"\", url.toString());\n }\n }\n\n // ===========================================================================\n // MESSAGE HANDLING\n // ===========================================================================\n\n private handleMessage(event: MessageEvent): void {\n // Validate origin for security - reject if no expected origin or mismatch\n const expectedOrigin = this.iframe.getCheckoutOrigin();\n if (!expectedOrigin || event.origin !== expectedOrigin) {\n return;\n }\n\n const { type, data } = event.data || {};\n if (!type) return;\n\n switch (type as IncomingEventType) {\n case \"checkout:ready\":\n this.handleReady();\n break;\n\n case \"checkout:open\":\n this.handleOpen();\n break;\n\n case \"checkout:close\":\n this.handleClose();\n break;\n\n case \"checkout:complete\":\n this.handleComplete(data as OrderData);\n break;\n\n case \"checkout:error\":\n this.handleError(data as { message: string });\n break;\n\n case \"cart:updated\":\n this.handleCartUpdate(data as CartData);\n break;\n\n case \"auth:login\":\n this.handleLogin(data as AuthLoginData);\n break;\n\n case \"auth:logout\":\n this.handleLogout(data as AuthLogoutData);\n break;\n\n case \"auth:refresh\":\n this.handleTokenRefresh(data as AuthRefreshData);\n break;\n\n case \"auth:session-error\":\n this.handleSessionError();\n break;\n }\n }\n\n private handleReady(): void {\n this.isReady = true;\n this.config.onReady?.();\n this.emit(\"ready\");\n\n // Auto-open cart if we have quick buy params (from config or auto-detected URL)\n if (this.hasQuickBuyParams) {\n this.openCart();\n }\n }\n\n private handleError(data: { message: string }): void {\n // Set ready so user can still interact (they'll see the error drawer)\n this.isReady = true;\n this.config.onError?.(data);\n this.emit(\"error\", data);\n }\n\n private handleOpen(): void {\n this.iframe.show();\n this.isOpen = true;\n this.config.onOpen?.();\n this.emit(\"open\");\n }\n\n private handleClose(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.config.onClose?.();\n this.emit(\"close\");\n }\n\n private handleComplete(data: OrderData): void {\n this.config.onComplete?.(data);\n this.emit(\"complete\", data);\n }\n\n private handleCartUpdate(data: CartData): void {\n this.cartState = data;\n this.config.onCartUpdate?.(data);\n this.emit(\"cart:updated\", data);\n }\n\n private handleLogin(data: AuthLoginData): void {\n this.config.onLogin?.(data);\n this.emit(\"auth:login\", data);\n }\n\n private handleLogout(data: AuthLogoutData): void {\n this.config.onLogout?.(data);\n this.emit(\"auth:logout\", data);\n }\n\n private handleTokenRefresh(data: AuthRefreshData): void {\n this.config.onTokenRefresh?.(data);\n this.emit(\"auth:refresh\", data);\n }\n\n private handleSessionError(): void {\n this.config.onSessionError?.();\n this.emit(\"auth:session-error\");\n }\n\n // ===========================================================================\n // PUBLIC API\n // ===========================================================================\n\n /**\n * Open the cart drawer\n */\n openCart(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-cart\");\n }\n\n /**\n * Open the checkout drawer directly (e.g., for Buy Now flow)\n */\n openCheckout(): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.show();\n this.isOpen = true;\n this.iframe.postMessage(\"checkout:open-checkout\");\n }\n\n /**\n * Close the checkout overlay\n */\n close(): void {\n this.iframe.hide();\n this.isOpen = false;\n this.iframe.postMessage(\"checkout:close\");\n }\n\n /**\n * Update authentication tokens\n * Use this when user logs in/out on the parent site\n */\n updateTokens(accessToken: string, refreshToken?: string): void {\n if (!this.isReady) {\n // Store for when ready\n this.config.accessToken = accessToken;\n this.config.refreshToken = refreshToken;\n return;\n }\n\n this.iframe.postMessage(\"checkout:update-tokens\", { accessToken, refreshToken });\n }\n\n /**\n * Add an item to cart and open the cart drawer\n *\n * @param productId - Product ID (required)\n * @param variantId - Variant ID (required, null for non-variant products)\n * @param quantity - Quantity to add (default: 1)\n */\n addToCart(productId: string, variantId: string | null, quantity = 1): void {\n if (!this.isReady) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn(\"[Commercengine] Not ready. Wait for onReady callback or 'ready' event.\");\n return;\n }\n\n this.iframe.postMessage(\"checkout:add-item\", {\n productId,\n variantId,\n quantity,\n });\n\n // Auto-open cart to show the added item\n this.openCart();\n }\n\n /**\n * Get current cart state\n */\n getCart(): CartData {\n return { ...this.cartState };\n }\n\n /**\n * Check if checkout is ready\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Check if checkout overlay is currently open\n */\n get open(): boolean {\n return this.isOpen;\n }\n\n /**\n * Subscribe to an event\n * @override EventEmitter.on with typed overloads\n */\n on(event: \"ready\", listener: EventListener<void>): void;\n on(event: \"open\", listener: EventListener<void>): void;\n on(event: \"close\", listener: EventListener<void>): void;\n on(event: \"complete\", listener: EventListener<OrderData>): void;\n on(event: \"cart:updated\", listener: EventListener<CartData>): void;\n on(event: \"auth:login\", listener: EventListener<AuthLoginData>): void;\n on(event: \"auth:logout\", listener: EventListener<AuthLogoutData>): void;\n on(event: \"auth:refresh\", listener: EventListener<AuthRefreshData>): void;\n on(event: \"auth:session-error\", listener: EventListener<void>): void;\n on<T = unknown>(event: CheckoutEventType, listener: EventListener<T>): void {\n super.on(event, listener);\n }\n\n /**\n * Destroy the checkout instance\n * Removes iframe and cleans up event listeners\n */\n destroy(): void {\n window.removeEventListener(\"message\", this.boundMessageHandler);\n this.iframe.destroy();\n this.removeAllListeners();\n this.isReady = false;\n this.isOpen = false;\n }\n}\n","/**\n * Commerce Engine Checkout\n *\n * @commercengine/js - Embeddable checkout SDK\n *\n * @example CDN Usage (Vanilla JS):\n * ```html\n * <script src=\"https://cdn.commercengine.com/v1.js\" async></script>\n * <script>\n * window.Commercengine.onLoad = async () => {\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"dark\",\n * onComplete: (order) => console.log(\"Order:\", order.orderNumber),\n * });\n *\n * document.getElementById(\"cart-btn\").onclick = () => checkout.openCart();\n * };\n * </script>\n * ```\n *\n * @example ESM Import:\n * ```typescript\n * import { Commercengine } from \"@commercengine/js\";\n *\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * });\n *\n * checkout.on(\"cart:updated\", (cart) => updateBadge(cart.count));\n * checkout.openCart();\n * ```\n */\n\nimport { Checkout } from \"./checkout\";\nimport type { CheckoutConfig } from \"./types\";\n\n// Re-export types for consumers\nexport type {\n AddToCartItem,\n AuthLoginData,\n AuthLogoutData,\n AuthMode,\n AuthRefreshData,\n CartData,\n Channel,\n CheckoutConfig,\n CheckoutEventType,\n Environment,\n ErrorData,\n LoginMethod,\n OrderData,\n QuickBuyConfig,\n SessionMode,\n UserInfo,\n} from \"./types\";\n\nexport { Checkout };\n\n// =============================================================================\n// GLOBAL API\n// =============================================================================\n\n/**\n * Global Commercengine object interface\n */\ninterface CommercengineGlobal {\n /**\n * Initialize checkout with configuration\n * @returns Promise that resolves to Checkout instance\n */\n init: (config: CheckoutConfig) => Promise<Checkout>;\n\n /**\n * Callback invoked when script has loaded\n * Set this BEFORE including the script to be notified when ready\n */\n onLoad?: () => void;\n\n /**\n * Current checkout instance (if initialized)\n */\n instance?: Checkout;\n}\n\n/**\n * Global Commercengine namespace\n */\nconst Commercengine: CommercengineGlobal = {\n /**\n * Initialize checkout\n *\n * @param config - Checkout configuration\n * @returns Checkout instance\n *\n * @example\n * const checkout = await Commercengine.init({\n * storeId: \"store_xxx\",\n * apiKey: \"ak_xxx\",\n * theme: \"system\",\n * });\n */\n init: async (config: CheckoutConfig): Promise<Checkout> => {\n // Validate required fields - either url (for dev) or storeId+apiKey (for prod)\n if (!config.url && (!config.storeId || !config.apiKey)) {\n throw new Error(\n \"[Commercengine] Either 'url' or both 'storeId' and 'apiKey' must be provided\"\n );\n }\n\n // Destroy existing instance if any\n if (Commercengine.instance) {\n Commercengine.instance.destroy();\n }\n\n // Create new instance\n const checkout = new Checkout(config);\n Commercengine.instance = checkout;\n\n // Wait for ready or error with timeout\n return new Promise((resolve, reject) => {\n if (checkout.ready) {\n resolve(checkout);\n return;\n }\n\n const timeoutMs = 30000; // 30 second timeout\n const timeout = setTimeout(() => {\n reject(new Error(\"Checkout initialization timed out\"));\n }, timeoutMs);\n\n // Resolve on ready\n checkout.once(\"ready\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n\n // Also resolve on error (checkout is still usable, will show error drawer)\n checkout.once(\"error\", () => {\n clearTimeout(timeout);\n resolve(checkout);\n });\n });\n },\n};\n\n// =============================================================================\n// GLOBAL SETUP\n// =============================================================================\n\n// Expose on window for CDN usage\nif (typeof window !== \"undefined\") {\n // Preserve any existing onLoad callback set before script loaded\n const existingOnLoad = (window as unknown as { Commercengine?: CommercengineGlobal })\n .Commercengine?.onLoad;\n\n // Set global\n (window as unknown as { Commercengine: CommercengineGlobal }).Commercengine = Commercengine;\n\n // Restore and call onLoad if it was set\n if (existingOnLoad) {\n Commercengine.onLoad = existingOnLoad;\n try {\n existingOnLoad();\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional error logging\n console.error(\"[Commercengine] Error in onLoad callback:\", error);\n }\n }\n}\n\nexport { Commercengine };\nexport default Commercengine;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercengine/js",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Commerce Engine Checkout - Embeddable checkout SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",