recur-tw 0.0.2 → 0.0.3-beta.1

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/dist/index.cjs CHANGED
@@ -15,52 +15,7 @@ var PAYUNI_SANDBOX_SDK_URL = "https://sandbox-vendor.payuni.com.tw/sdk/uni-payme
15
15
  var isLoaded = false;
16
16
  var isLoading = false;
17
17
  var loadPromise = null;
18
- function createMockUniPayment() {
19
- return {
20
- createSession: (token, options) => {
21
- console.log("[Mock PAYUNi SDK] Creating session with token:", token.substring(0, 20) + "...");
22
- console.log("[Mock PAYUNi SDK] Options:", options);
23
- const { elements } = options;
24
- const cardNoEl = document.getElementById(elements.CardNo);
25
- const cardExpEl = document.getElementById(elements.CardExp);
26
- const cardCvcEl = document.getElementById(elements.CardCvc);
27
- if (cardNoEl) {
28
- cardNoEl.innerHTML = '<div style="border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;">4242 4242 4242 4242 (Mock)</div>';
29
- }
30
- if (cardExpEl) {
31
- cardExpEl.innerHTML = '<div style="border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;">12 / 25 (Mock)</div>';
32
- }
33
- if (cardCvcEl) {
34
- cardCvcEl.innerHTML = '<div style="border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;">123 (Mock)</div>';
35
- }
36
- return {
37
- start: async () => {
38
- console.log("[Mock PAYUNi SDK] \u2713 Started successfully");
39
- await new Promise((resolve) => setTimeout(resolve, 500));
40
- },
41
- getTradeResult: async () => {
42
- console.log("[Mock PAYUNi SDK] \u2713 Getting trade result");
43
- await new Promise((resolve) => setTimeout(resolve, 800));
44
- return {
45
- Status: "SUCCESS",
46
- Message: "Mock payment successful",
47
- TradeNo: `MOCK${Date.now()}`,
48
- AuthCode: "123456"
49
- };
50
- }
51
- };
52
- }
53
- };
54
- }
55
- async function loadPayUniSDK(isSandbox = false, mockMode = false) {
56
- if (mockMode) {
57
- console.log("[Recur SDK] \u{1F3AD} Mock mode enabled - using mock PAYUNi SDK");
58
- if (typeof window !== "undefined") {
59
- window.UniPayment = createMockUniPayment();
60
- }
61
- isLoaded = true;
62
- return Promise.resolve();
63
- }
18
+ async function loadPayUniSDK(isSandbox = false) {
64
19
  if (isLoaded && window.UniPayment) {
65
20
  return Promise.resolve();
66
21
  }
@@ -124,7 +79,7 @@ function RecurProvider({ children, config: initialConfig = {} }) {
124
79
  if (!options.customerEmail || !options.customerName) {
125
80
  throw new Error("customerEmail and customerName are required");
126
81
  }
127
- const baseUrl = config.baseUrl || (typeof window !== "undefined" ? window.location.origin : "");
82
+ const baseUrl = config.baseUrl || "https://api.recur.tw";
128
83
  console.log("[Recur SDK] Base URL:", baseUrl);
129
84
  const headers = {
130
85
  "Content-Type": "application/json",
@@ -319,7 +274,7 @@ function RecurProvider({ children, config: initialConfig = {} }) {
319
274
  });
320
275
  console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");
321
276
  const isSandbox = tokenResult.environment === "SANDBOX";
322
- await loadPayUniSDK(isSandbox, config.mockMode);
277
+ await loadPayUniSDK(isSandbox);
323
278
  console.log("[Recur SDK] PAYUNi SDK loaded successfully");
324
279
  if (!window.UniPayment) {
325
280
  console.error("[Recur SDK] window.UniPayment is not available after loading");
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/payuni-loader.ts","../src/context.tsx","../src/use-recur.ts"],"names":["createContext","useState","React","useCallback","useMemo","jsx","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * PAYUNi SDK Loader\n * Dynamically loads and initializes the PAYUNi UNi Embed SDK\n */\n\nimport type { UniPaymentInstance } from './types.js';\n\nconst PAYUNI_SDK_URL = 'https://vendor.payuni.com.tw/sdk/uni-payment.js';\nconst PAYUNI_SANDBOX_SDK_URL = 'https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js';\n\nlet isLoaded = false;\nlet isLoading = false;\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Create a mock PAYUNi SDK for testing without backend\n */\nfunction createMockUniPayment() {\n return {\n createSession: (token: string, options: any): UniPaymentInstance => {\n console.log('[Mock PAYUNi SDK] Creating session with token:', token.substring(0, 20) + '...');\n console.log('[Mock PAYUNi SDK] Options:', options);\n\n // Simulate rendering credit card iframes\n const { elements } = options;\n const cardNoEl = document.getElementById(elements.CardNo);\n const cardExpEl = document.getElementById(elements.CardExp);\n const cardCvcEl = document.getElementById(elements.CardCvc);\n\n // Inject mock iframe placeholders\n if (cardNoEl) {\n cardNoEl.innerHTML = '<div style=\"border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;\">4242 4242 4242 4242 (Mock)</div>';\n }\n if (cardExpEl) {\n cardExpEl.innerHTML = '<div style=\"border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;\">12 / 25 (Mock)</div>';\n }\n if (cardCvcEl) {\n cardCvcEl.innerHTML = '<div style=\"border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;\">123 (Mock)</div>';\n }\n\n return {\n start: async () => {\n console.log('[Mock PAYUNi SDK] ✓ Started successfully');\n // Simulate async loading\n await new Promise(resolve => setTimeout(resolve, 500));\n },\n getTradeResult: async () => {\n console.log('[Mock PAYUNi SDK] ✓ Getting trade result');\n // Simulate payment processing\n await new Promise(resolve => setTimeout(resolve, 800));\n return {\n Status: 'SUCCESS',\n Message: 'Mock payment successful',\n TradeNo: `MOCK${Date.now()}`,\n AuthCode: '123456',\n };\n },\n };\n },\n };\n}\n\n/**\n * Load PAYUNi SDK script\n * @param isSandbox - Use sandbox environment\n * @param mockMode - Use mock mode for testing\n */\nexport async function loadPayUniSDK(isSandbox: boolean = false, mockMode: boolean = false): Promise<void> {\n // Mock mode: inject mock SDK immediately\n if (mockMode) {\n console.log('[Recur SDK] 🎭 Mock mode enabled - using mock PAYUNi SDK');\n if (typeof window !== 'undefined') {\n (window as any).UniPayment = createMockUniPayment();\n }\n isLoaded = true;\n return Promise.resolve();\n }\n // Already loaded\n if (isLoaded && window.UniPayment) {\n return Promise.resolve();\n }\n\n // Currently loading\n if (isLoading && loadPromise) {\n return loadPromise;\n }\n\n // Start loading\n isLoading = true;\n loadPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = isSandbox ? PAYUNI_SANDBOX_SDK_URL : PAYUNI_SDK_URL;\n script.async = true;\n\n script.onload = () => {\n isLoaded = true;\n isLoading = false;\n resolve();\n };\n\n script.onerror = () => {\n isLoading = false;\n loadPromise = null;\n reject(new Error('Failed to load PAYUNi SDK'));\n };\n\n document.head.appendChild(script);\n });\n\n return loadPromise;\n}\n\n/**\n * Check if PAYUNi SDK is loaded\n */\nexport function isPayUniSDKLoaded(): boolean {\n return isLoaded && typeof window !== 'undefined' && !!window.UniPayment;\n}\n\n/**\n * Wait for PAYUNi SDK to be ready\n */\nexport async function waitForPayUniSDK(timeout: number = 10000): Promise<void> {\n const startTime = Date.now();\n\n while (!isPayUniSDKLoaded()) {\n if (Date.now() - startTime > timeout) {\n throw new Error('PAYUNi SDK load timeout');\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n","'use client';\n\nimport React, { createContext, useCallback, useState, useMemo } from 'react';\nimport type {\n RecurConfig,\n RecurContextValue,\n CheckoutOptions,\n CheckoutResult,\n CheckoutError,\n PlansResult,\n SdkTokenResult,\n SubscriptionCompleteResult,\n UniPaymentInstance,\n} from './types.js';\nimport { loadPayUniSDK } from './payuni-loader.js';\n\nconst RecurContext = createContext<RecurContextValue | null>(null);\n\nexport interface RecurProviderProps {\n children: React.ReactNode;\n config?: RecurConfig;\n}\n\n/**\n * RecurProvider\n *\n * Provides Recur checkout functionality to your React application\n *\n * @example\n * ```tsx\n * <RecurProvider config={{ publishableKey: 'pk_test_xxx' }}>\n * <App />\n * </RecurProvider>\n * ```\n */\nexport function RecurProvider({ children, config: initialConfig = {} }: RecurProviderProps) {\n const [config, setConfig] = useState<RecurConfig>({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n\n const [isCheckingOut, setIsCheckingOut] = useState(false);\n\n // Update config when initialConfig changes (e.g., when user switches modes)\n React.useEffect(() => {\n setConfig({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n }, [initialConfig.checkoutMode, initialConfig.publishableKey, initialConfig.containerElementId]);\n\n // Reset isCheckingOut when checkout mode changes to allow re-testing\n React.useEffect(() => {\n setIsCheckingOut(false);\n }, [config.checkoutMode]);\n\n const updateConfig = useCallback((newConfig: Partial<RecurConfig>) => {\n setConfig((prev) => ({ ...prev, ...newConfig }));\n }, []);\n\n const checkout = useCallback(\n async (options: CheckoutOptions) => {\n let modalOverlay: HTMLElement | null = null;\n\n try {\n console.log('[Recur SDK] Starting checkout flow...', {\n planId: options.planId,\n checkoutMode: config.checkoutMode,\n containerElementId: config.containerElementId,\n });\n\n setIsCheckingOut(true);\n\n // Validate required fields\n if (!options.planId) {\n throw new Error('planId is required');\n }\n\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n if (!options.customerEmail || !options.customerName) {\n throw new Error('customerEmail and customerName are required');\n }\n\n const baseUrl = config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n console.log('[Recur SDK] Base URL:', baseUrl);\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n };\n\n // Show loading state early for both modal and embedded modes\n let modalContent: HTMLElement | null = null;\n let loadingContainer: HTMLElement | null = null;\n let embeddedContainer: HTMLElement | null = null;\n\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, creating modal with loading state...');\n\n // Create modal overlay\n modalOverlay = document.createElement('div');\n modalOverlay.id = 'recur-modal-overlay';\n modalOverlay.className = 'recur-sdk__modal-overlay';\n modalOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n `;\n\n // Create modal content\n modalContent = document.createElement('div');\n modalContent.className = 'recur-sdk__modal-content';\n modalContent.style.cssText = `\n background: white;\n padding: 32px;\n border-radius: 12px;\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n position: relative;\n `;\n\n // Create close button\n const closeButton = document.createElement('button');\n closeButton.className = 'recur-sdk__close-button';\n closeButton.innerHTML = '✕';\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n closeButton.onclick = () => {\n modalOverlay?.remove();\n setIsCheckingOut(false);\n options.onPaymentCancel?.();\n };\n\n // Create title\n const title = document.createElement('h2');\n title.className = 'recur-sdk__title';\n title.textContent = '訂閱付款';\n title.style.cssText = 'margin: 0 0 24px 0; font-size: 24px; font-weight: 600;';\n\n // Create loading container with spinner\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-modal-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n modalContent.appendChild(closeButton);\n modalContent.appendChild(title);\n modalContent.appendChild(loadingContainer);\n modalOverlay.appendChild(modalContent);\n document.body.appendChild(modalOverlay);\n\n console.log('[Recur SDK] Modal created with loading state');\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, try to show loading in the container if it exists\n console.log('[Recur SDK] Mode is embedded, checking for container...');\n\n if (!config.containerElementId) {\n console.warn('[Recur SDK] No containerElementId provided for embedded mode');\n } else {\n // Poll for the container to appear (wait up to 500ms)\n embeddedContainer = document.getElementById(config.containerElementId);\n\n if (!embeddedContainer) {\n console.log('[Recur SDK] Container not found, polling for container...');\n for (let i = 0; i < 10; i++) {\n await new Promise(resolve => setTimeout(resolve, 50));\n embeddedContainer = document.getElementById(config.containerElementId);\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found after polling');\n break;\n }\n }\n }\n\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found, showing loading state...');\n\n // Show loading state in the embedded container\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-embedded-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n embeddedContainer.appendChild(loadingContainer);\n } else {\n console.log('[Recur SDK] Container not found after polling, will continue without early loading state');\n }\n }\n }\n\n // Step 1: Create subscription\n console.log('[Recur SDK] Step 1: Creating subscription...');\n const subscriptionResponse = await fetch(`${baseUrl}/api/v1/subscriptions`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n planId: options.planId,\n customerName: options.customerName,\n customerEmail: options.customerEmail,\n customerPhone: options.customerPhone,\n }),\n });\n\n if (!subscriptionResponse.ok) {\n const errorData = await subscriptionResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to create subscription:', errorData);\n const errorMessage = errorData.details || errorData.error || 'Failed to create subscription';\n throw new Error(errorMessage);\n }\n\n const subscriptionResult: CheckoutResult = await subscriptionResponse.json();\n console.log('[Recur SDK] Subscription created successfully:', subscriptionResult);\n\n // Call onSuccess callback\n options.onSuccess?.(subscriptionResult);\n\n // Step 2: Get SDK token\n console.log('[Recur SDK] Step 2: Getting SDK token...');\n const tokenResponse = await fetch(`${baseUrl}/api/v1/subscriptions/sdk-token`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n subscriberId: subscriptionResult.subscriber.id,\n iframeDomain: window.location.origin,\n }),\n });\n\n if (!tokenResponse.ok) {\n const errorData = await tokenResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to get SDK token:', errorData);\n throw new Error('Failed to get SDK token');\n }\n\n const tokenResult: SdkTokenResult = await tokenResponse.json();\n console.log('[Recur SDK] SDK token received:', {\n environment: tokenResult.environment,\n creditToken: tokenResult.creditToken,\n tokenExpired: tokenResult.tokenExpired,\n });\n\n // Step 3: Load PAYUNi SDK\n console.log('[Recur SDK] Step 3: Loading PAYUNi SDK...');\n const isSandbox = tokenResult.environment === 'SANDBOX';\n await loadPayUniSDK(isSandbox, config.mockMode);\n console.log('[Recur SDK] PAYUNi SDK loaded successfully');\n\n if (!window.UniPayment) {\n console.error('[Recur SDK] window.UniPayment is not available after loading');\n throw new Error('PAYUNi SDK failed to load');\n }\n\n // Step 4: Determine container element based on checkout mode\n console.log('[Recur SDK] Step 4: Preparing container for checkout mode:', config.checkoutMode);\n console.log('[Recur SDK] Initial containerElementId from config:', config.containerElementId);\n\n let containerElementId = config.containerElementId;\n\n // For modal mode, update the existing modal with payment form container\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, updating modal with payment form...');\n\n if (!loadingContainer || !modalContent) {\n throw new Error('Modal components not initialized');\n }\n\n // Remove loading spinner\n loadingContainer.remove();\n\n // Create container for payment form\n const formContainer = document.createElement('div');\n containerElementId = 'recur-modal-payment-container';\n formContainer.id = containerElementId;\n\n modalContent.appendChild(formContainer);\n\n console.log('[Recur SDK] Modal updated with container ID:', containerElementId);\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, remove loading spinner if it exists\n console.log('[Recur SDK] Mode is embedded, preparing container...');\n\n if (!containerElementId) {\n throw new Error('containerElementId is required for embedded mode');\n }\n\n // Remove loading spinner if we showed it earlier\n if (loadingContainer && embeddedContainer) {\n console.log('[Recur SDK] Removing loading spinner from embedded container');\n loadingContainer.remove();\n }\n }\n\n // Step 5: Initialize PAYUNi form\n console.log('[Recur SDK] Step 5: Initializing PAYUNi form...');\n console.log('[Recur SDK] Available UniPayment methods:', Object.keys(window.UniPayment || {}));\n\n if (!containerElementId) {\n throw new Error('containerElementId is required');\n }\n\n // PAYUNi SDK uses createSession(token, options)\n const uniPayment = window.UniPayment.createSession(tokenResult.sdkToken, {\n env: tokenResult.environment === 'SANDBOX' ? 'S' : 'P',\n elements: {\n CardNo: `${containerElementId}-card-no`,\n CardExp: `${containerElementId}-card-exp`,\n CardCvc: `${containerElementId}-card-cvc`,\n },\n });\n console.log('[Recur SDK] PAYUNi form initialized');\n\n // Step 6: Wait for container and create form elements\n console.log('[Recur SDK] Step 6: Waiting for container element...');\n\n // For embedded mode, wait for the container to appear in DOM\n // (React needs time to render after onSuccess callback)\n let container = document.getElementById(containerElementId);\n if (!container && config.checkoutMode === 'embedded') {\n console.log('[Recur SDK] Container not found, waiting for React to render...');\n // Wait up to 2 seconds for container to appear\n for (let i = 0; i < 20; i++) {\n await new Promise(resolve => setTimeout(resolve, 100));\n container = document.getElementById(containerElementId);\n if (container) {\n console.log('[Recur SDK] Container found after waiting');\n break;\n }\n }\n }\n\n if (!container) {\n throw new Error(`Container element '${containerElementId}' not found`);\n }\n\n console.log('[Recur SDK] Creating loading skeleton...');\n\n // Step 1: Show loading skeleton first\n container.innerHTML = `\n <style>\n /* Recur SDK Styles - CSS Namespace with BEM */\n\n /* Animations */\n @keyframes recur-sdk-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n /* Skeleton Loading State */\n .recur-sdk__skeleton {\n animation: recur-sdk-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background-color: #e5e7eb;\n border-radius: 6px;\n }\n\n /* Form States */\n .recur-sdk__form--hidden {\n display: none;\n }\n\n /* Form Layout */\n .recur-sdk__form-field {\n margin-bottom: 16px;\n }\n\n .recur-sdk__form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n /* Labels and Text */\n .recur-sdk__label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n color: #374151;\n }\n\n .recur-sdk__hint-text {\n margin-top: 4px;\n font-size: 12px;\n color: #6b7280;\n }\n\n /* Input Container (for PAYUNi iframes) */\n .recur-sdk__input-container {\n /* Container styles applied via ID selectors below for PAYUNi compatibility */\n }\n\n /* Button */\n .recur-sdk__button {\n width: 100%;\n padding: 12px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s ease-in-out;\n }\n\n .recur-sdk__button:hover {\n background: #2563eb;\n }\n\n .recur-sdk__button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* PAYUNi SDK 自訂樣式 - 與 shadcn input focus 樣式一致 */\n /* Note: .form-input-focus is applied by PAYUNi SDK, not by our code */\n .form-input-focus {\n border-color: hsl(215 16% 47%) !important;\n outline: 0 !important;\n box-shadow: 0 0 0 3px hsl(215 16% 47% / 0.5) !important;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;\n }\n\n /* 確保 PAYUNi iframe 容器高度一致 */\n /* Note: These IDs are required by PAYUNi SDK and cannot be changed */\n #${containerElementId}-card-no,\n #${containerElementId}-card-exp,\n #${containerElementId}-card-cvc {\n height: 36px !important;\n }\n </style>\n\n <!-- Skeleton Loading State -->\n <div id=\"${containerElementId}-skeleton\" class=\"recur-sdk__skeleton-container\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n </div>\n <!-- Show button during loading to prevent layout shift -->\n <button class=\"recur-sdk__button\" disabled>\n 載入中...\n </button>\n </div>\n\n <!-- Actual Payment Form (hidden initially) -->\n <div id=\"${containerElementId}-form\" class=\"recur-sdk__form recur-sdk__form--hidden\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div id=\"${containerElementId}-card-no\" class=\"recur-sdk__input-container\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div id=\"${containerElementId}-card-exp\" class=\"recur-sdk__input-container\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div id=\"${containerElementId}-card-cvc\" class=\"recur-sdk__input-container\"></div>\n </div>\n </div>\n <button id=\"${containerElementId}-submit-btn\" class=\"recur-sdk__button\">\n 確認付款\n </button>\n </div>\n `;\n\n console.log('[Recur SDK] Starting PAYUNi SDK...');\n await uniPayment.start();\n console.log('[Recur SDK] PAYUNi SDK started successfully');\n\n // Step 2: Hide skeleton and show actual form\n console.log('[Recur SDK] Showing actual form...');\n const skeleton = document.getElementById(`${containerElementId}-skeleton`);\n const form = document.getElementById(`${containerElementId}-form`);\n if (skeleton && form) {\n skeleton.style.display = 'none';\n form.classList.remove('recur-sdk__form--hidden');\n }\n\n // Step 7: Handle form submission\n console.log('[Recur SDK] Step 7: Setting up submit button handler...');\n const submitBtn = document.getElementById(`${containerElementId}-submit-btn`);\n if (!submitBtn) {\n throw new Error('Submit button not found');\n }\n\n submitBtn.addEventListener('click', async () => {\n console.log('[Recur SDK] Submit button clicked');\n submitBtn.setAttribute('disabled', 'true');\n submitBtn.textContent = '處理中...';\n\n try {\n // Get card data from PAYUNi SDK\n console.log('[Recur SDK] Getting trade result from PAYUNi...');\n const tradeResult = await uniPayment.getTradeResult();\n console.log('[Recur SDK] Trade result received:', tradeResult);\n\n // Step 8: Complete subscription\n console.log('[Recur SDK] Step 8: Completing subscription...');\n const completeResponse = await fetch(\n `${baseUrl}/api/v1/subscriptions/${subscriptionResult.subscription.id}/complete`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n sdkToken: tokenResult.sdkToken,\n timestamp: tokenResult.timestamp,\n creditToken: tokenResult.creditToken,\n }),\n }\n );\n\n if (!completeResponse.ok) {\n const errorData = await completeResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to complete subscription:', errorData);\n throw new Error('Failed to complete subscription');\n }\n\n const completeResult: SubscriptionCompleteResult = await completeResponse.json();\n console.log('[Recur SDK] Subscription completed successfully:', completeResult);\n\n // Call payment complete callback\n console.log('[Recur SDK] Calling onPaymentComplete callback...');\n if (options.onPaymentComplete) {\n options.onPaymentComplete({\n id: completeResult.subscription.id,\n status: completeResult.subscription.status,\n planId: subscriptionResult.subscription.planId,\n amount: subscriptionResult.subscription.amount,\n billingPeriod: subscriptionResult.subscription.billingPeriod,\n currentPeriodStart: new Date().toISOString(),\n currentPeriodEnd: new Date().toISOString(),\n });\n }\n\n console.log('[Recur SDK] Checkout flow completed successfully!');\n\n // Close modal if in modal mode\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n setIsCheckingOut(false);\n } catch (error) {\n console.error('[Recur SDK] Error in payment flow:', error);\n const checkoutError: CheckoutError = {\n code: 'PAYMENT_FAILED',\n message: error instanceof Error ? error.message : 'Payment failed',\n };\n options.onError?.(checkoutError);\n\n // Re-enable submit button\n submitBtn.removeAttribute('disabled');\n submitBtn.textContent = '確認付款';\n setIsCheckingOut(false);\n }\n });\n\n console.log('[Recur SDK] Checkout flow initialized, waiting for user input...');\n } catch (error) {\n console.error('[Recur SDK] Checkout error:', error);\n\n // Clean up modal if it exists\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n const checkoutError: CheckoutError = {\n code: 'CHECKOUT_ERROR',\n message: error instanceof Error ? error.message : 'An unknown error occurred',\n };\n\n options.onError?.(checkoutError);\n setIsCheckingOut(false);\n throw error;\n }\n },\n [config]\n );\n\n const fetchPlans = useCallback(\n async (): Promise<PlansResult> => {\n // Check publishable key (required)\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n // Determine base URL\n const baseUrl = config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n\n // Call the plans API (v1)\n const response = await fetch(`${baseUrl}/api/v1/plans`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n },\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || 'Failed to fetch plans');\n }\n\n return await response.json();\n },\n [config]\n );\n\n const value = useMemo(\n () => ({\n config,\n checkout,\n fetchPlans,\n isCheckingOut,\n updateConfig,\n }),\n [config, checkout, fetchPlans, isCheckingOut, updateConfig]\n );\n\n return <RecurContext.Provider value={value}>{children}</RecurContext.Provider>;\n}\n\nexport { RecurContext };\n","'use client';\n\nimport { useContext } from 'react';\nimport { RecurContext } from './context.js';\nimport type { RecurContextValue } from './types.js';\n\n/**\n * useRecur Hook\n *\n * Access Recur checkout functionality from within your components\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { checkout, isCheckingOut } = useRecur();\n *\n * return (\n * <button\n * onClick={() => checkout({ planId: 'pro' })}\n * disabled={isCheckingOut}\n * >\n * {isCheckingOut ? 'Processing...' : 'Subscribe'}\n * </button>\n * );\n * }\n * ```\n *\n * @throws {Error} If used outside of RecurProvider\n */\nexport function useRecur(): RecurContextValue {\n const context = useContext(RecurContext);\n\n if (!context) {\n throw new Error('useRecur must be used within a RecurProvider');\n }\n\n return context;\n}\n"]}
1
+ {"version":3,"sources":["../src/payuni-loader.ts","../src/context.tsx","../src/use-recur.ts"],"names":["createContext","useState","React","useCallback","useMemo","jsx","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * PAYUNi SDK Loader\n * Dynamically loads and initializes the PAYUNi UNi Embed SDK\n */\n\nimport type { UniPaymentInstance } from './types.js';\n\nconst PAYUNI_SDK_URL = 'https://vendor.payuni.com.tw/sdk/uni-payment.js';\nconst PAYUNI_SANDBOX_SDK_URL = 'https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js';\n\nlet isLoaded = false;\nlet isLoading = false;\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Load PAYUNi SDK script\n * @param isSandbox - Use sandbox environment\n */\nexport async function loadPayUniSDK(isSandbox: boolean = false): Promise<void> {\n // Already loaded\n if (isLoaded && window.UniPayment) {\n return Promise.resolve();\n }\n\n // Currently loading\n if (isLoading && loadPromise) {\n return loadPromise;\n }\n\n // Start loading\n isLoading = true;\n loadPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = isSandbox ? PAYUNI_SANDBOX_SDK_URL : PAYUNI_SDK_URL;\n script.async = true;\n\n script.onload = () => {\n isLoaded = true;\n isLoading = false;\n resolve();\n };\n\n script.onerror = () => {\n isLoading = false;\n loadPromise = null;\n reject(new Error('Failed to load PAYUNi SDK'));\n };\n\n document.head.appendChild(script);\n });\n\n return loadPromise;\n}\n\n/**\n * Check if PAYUNi SDK is loaded\n */\nexport function isPayUniSDKLoaded(): boolean {\n return isLoaded && typeof window !== 'undefined' && !!window.UniPayment;\n}\n\n/**\n * Wait for PAYUNi SDK to be ready\n */\nexport async function waitForPayUniSDK(timeout: number = 10000): Promise<void> {\n const startTime = Date.now();\n\n while (!isPayUniSDKLoaded()) {\n if (Date.now() - startTime > timeout) {\n throw new Error('PAYUNi SDK load timeout');\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n","'use client';\n\nimport React, { createContext, useCallback, useState, useMemo } from 'react';\nimport type {\n RecurConfig,\n RecurContextValue,\n CheckoutOptions,\n CheckoutResult,\n CheckoutError,\n PlansResult,\n SdkTokenResult,\n SubscriptionCompleteResult,\n UniPaymentInstance,\n} from './types.js';\nimport { loadPayUniSDK } from './payuni-loader.js';\n\nconst RecurContext = createContext<RecurContextValue | null>(null);\n\nexport interface RecurProviderProps {\n children: React.ReactNode;\n config?: RecurConfig;\n}\n\n/**\n * RecurProvider\n *\n * Provides Recur checkout functionality to your React application\n *\n * @example\n * ```tsx\n * <RecurProvider config={{ publishableKey: 'pk_test_xxx' }}>\n * <App />\n * </RecurProvider>\n * ```\n */\nexport function RecurProvider({ children, config: initialConfig = {} }: RecurProviderProps) {\n const [config, setConfig] = useState<RecurConfig>({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n\n const [isCheckingOut, setIsCheckingOut] = useState(false);\n\n // Update config when initialConfig changes (e.g., when user switches modes)\n React.useEffect(() => {\n setConfig({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n }, [initialConfig.checkoutMode, initialConfig.publishableKey, initialConfig.containerElementId]);\n\n // Reset isCheckingOut when checkout mode changes to allow re-testing\n React.useEffect(() => {\n setIsCheckingOut(false);\n }, [config.checkoutMode]);\n\n const updateConfig = useCallback((newConfig: Partial<RecurConfig>) => {\n setConfig((prev) => ({ ...prev, ...newConfig }));\n }, []);\n\n const checkout = useCallback(\n async (options: CheckoutOptions) => {\n let modalOverlay: HTMLElement | null = null;\n\n try {\n console.log('[Recur SDK] Starting checkout flow...', {\n planId: options.planId,\n checkoutMode: config.checkoutMode,\n containerElementId: config.containerElementId,\n });\n\n setIsCheckingOut(true);\n\n // Validate required fields\n if (!options.planId) {\n throw new Error('planId is required');\n }\n\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n if (!options.customerEmail || !options.customerName) {\n throw new Error('customerEmail and customerName are required');\n }\n\n const baseUrl = config.baseUrl || 'https://api.recur.tw';\n console.log('[Recur SDK] Base URL:', baseUrl);\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n };\n\n // Show loading state early for both modal and embedded modes\n let modalContent: HTMLElement | null = null;\n let loadingContainer: HTMLElement | null = null;\n let embeddedContainer: HTMLElement | null = null;\n\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, creating modal with loading state...');\n\n // Create modal overlay\n modalOverlay = document.createElement('div');\n modalOverlay.id = 'recur-modal-overlay';\n modalOverlay.className = 'recur-sdk__modal-overlay';\n modalOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n `;\n\n // Create modal content\n modalContent = document.createElement('div');\n modalContent.className = 'recur-sdk__modal-content';\n modalContent.style.cssText = `\n background: white;\n padding: 32px;\n border-radius: 12px;\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n position: relative;\n `;\n\n // Create close button\n const closeButton = document.createElement('button');\n closeButton.className = 'recur-sdk__close-button';\n closeButton.innerHTML = '✕';\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n closeButton.onclick = () => {\n modalOverlay?.remove();\n setIsCheckingOut(false);\n options.onPaymentCancel?.();\n };\n\n // Create title\n const title = document.createElement('h2');\n title.className = 'recur-sdk__title';\n title.textContent = '訂閱付款';\n title.style.cssText = 'margin: 0 0 24px 0; font-size: 24px; font-weight: 600;';\n\n // Create loading container with spinner\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-modal-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n modalContent.appendChild(closeButton);\n modalContent.appendChild(title);\n modalContent.appendChild(loadingContainer);\n modalOverlay.appendChild(modalContent);\n document.body.appendChild(modalOverlay);\n\n console.log('[Recur SDK] Modal created with loading state');\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, try to show loading in the container if it exists\n console.log('[Recur SDK] Mode is embedded, checking for container...');\n\n if (!config.containerElementId) {\n console.warn('[Recur SDK] No containerElementId provided for embedded mode');\n } else {\n // Poll for the container to appear (wait up to 500ms)\n embeddedContainer = document.getElementById(config.containerElementId);\n\n if (!embeddedContainer) {\n console.log('[Recur SDK] Container not found, polling for container...');\n for (let i = 0; i < 10; i++) {\n await new Promise(resolve => setTimeout(resolve, 50));\n embeddedContainer = document.getElementById(config.containerElementId);\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found after polling');\n break;\n }\n }\n }\n\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found, showing loading state...');\n\n // Show loading state in the embedded container\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-embedded-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n embeddedContainer.appendChild(loadingContainer);\n } else {\n console.log('[Recur SDK] Container not found after polling, will continue without early loading state');\n }\n }\n }\n\n // Step 1: Create subscription\n console.log('[Recur SDK] Step 1: Creating subscription...');\n\n const subscriptionResponse = await fetch(`${baseUrl}/api/v1/subscriptions`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n planId: options.planId,\n customerName: options.customerName,\n customerEmail: options.customerEmail,\n customerPhone: options.customerPhone,\n }),\n });\n\n if (!subscriptionResponse.ok) {\n const errorData = await subscriptionResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to create subscription:', errorData);\n const errorMessage = errorData.details || errorData.error || 'Failed to create subscription';\n throw new Error(errorMessage);\n }\n\n const subscriptionResult: CheckoutResult = await subscriptionResponse.json();\n console.log('[Recur SDK] Subscription created successfully:', subscriptionResult);\n\n // Call onSuccess callback\n options.onSuccess?.(subscriptionResult);\n\n // Step 2: Get SDK token\n console.log('[Recur SDK] Step 2: Getting SDK token...');\n\n const tokenResponse = await fetch(`${baseUrl}/api/v1/subscriptions/sdk-token`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n subscriberId: subscriptionResult.subscriber.id,\n iframeDomain: window.location.origin,\n }),\n });\n\n if (!tokenResponse.ok) {\n const errorData = await tokenResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to get SDK token:', errorData);\n throw new Error('Failed to get SDK token');\n }\n\n const tokenResult: SdkTokenResult = await tokenResponse.json();\n console.log('[Recur SDK] SDK token received:', {\n environment: tokenResult.environment,\n creditToken: tokenResult.creditToken,\n tokenExpired: tokenResult.tokenExpired,\n });\n\n // Step 3: Load PAYUNi SDK\n console.log('[Recur SDK] Step 3: Loading PAYUNi SDK...');\n const isSandbox = tokenResult.environment === 'SANDBOX';\n await loadPayUniSDK(isSandbox);\n console.log('[Recur SDK] PAYUNi SDK loaded successfully');\n\n if (!window.UniPayment) {\n console.error('[Recur SDK] window.UniPayment is not available after loading');\n throw new Error('PAYUNi SDK failed to load');\n }\n\n // Step 4: Determine container element based on checkout mode\n console.log('[Recur SDK] Step 4: Preparing container for checkout mode:', config.checkoutMode);\n console.log('[Recur SDK] Initial containerElementId from config:', config.containerElementId);\n\n let containerElementId = config.containerElementId;\n\n // For modal mode, update the existing modal with payment form container\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, updating modal with payment form...');\n\n if (!loadingContainer || !modalContent) {\n throw new Error('Modal components not initialized');\n }\n\n // Remove loading spinner\n loadingContainer.remove();\n\n // Create container for payment form\n const formContainer = document.createElement('div');\n containerElementId = 'recur-modal-payment-container';\n formContainer.id = containerElementId;\n\n modalContent.appendChild(formContainer);\n\n console.log('[Recur SDK] Modal updated with container ID:', containerElementId);\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, remove loading spinner if it exists\n console.log('[Recur SDK] Mode is embedded, preparing container...');\n\n if (!containerElementId) {\n throw new Error('containerElementId is required for embedded mode');\n }\n\n // Remove loading spinner if we showed it earlier\n if (loadingContainer && embeddedContainer) {\n console.log('[Recur SDK] Removing loading spinner from embedded container');\n loadingContainer.remove();\n }\n }\n\n // Step 5: Initialize PAYUNi form\n console.log('[Recur SDK] Step 5: Initializing PAYUNi form...');\n console.log('[Recur SDK] Available UniPayment methods:', Object.keys(window.UniPayment || {}));\n\n if (!containerElementId) {\n throw new Error('containerElementId is required');\n }\n\n // PAYUNi SDK uses createSession(token, options)\n const uniPayment = window.UniPayment.createSession(tokenResult.sdkToken, {\n env: tokenResult.environment === 'SANDBOX' ? 'S' : 'P',\n elements: {\n CardNo: `${containerElementId}-card-no`,\n CardExp: `${containerElementId}-card-exp`,\n CardCvc: `${containerElementId}-card-cvc`,\n },\n });\n console.log('[Recur SDK] PAYUNi form initialized');\n\n // Step 6: Wait for container and create form elements\n console.log('[Recur SDK] Step 6: Waiting for container element...');\n\n // For embedded mode, wait for the container to appear in DOM\n // (React needs time to render after onSuccess callback)\n let container = document.getElementById(containerElementId);\n if (!container && config.checkoutMode === 'embedded') {\n console.log('[Recur SDK] Container not found, waiting for React to render...');\n // Wait up to 2 seconds for container to appear\n for (let i = 0; i < 20; i++) {\n await new Promise(resolve => setTimeout(resolve, 100));\n container = document.getElementById(containerElementId);\n if (container) {\n console.log('[Recur SDK] Container found after waiting');\n break;\n }\n }\n }\n\n if (!container) {\n throw new Error(`Container element '${containerElementId}' not found`);\n }\n\n console.log('[Recur SDK] Creating loading skeleton...');\n\n // Step 1: Show loading skeleton first\n container.innerHTML = `\n <style>\n /* Recur SDK Styles - CSS Namespace with BEM */\n\n /* Animations */\n @keyframes recur-sdk-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n /* Skeleton Loading State */\n .recur-sdk__skeleton {\n animation: recur-sdk-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background-color: #e5e7eb;\n border-radius: 6px;\n }\n\n /* Form States */\n .recur-sdk__form--hidden {\n display: none;\n }\n\n /* Form Layout */\n .recur-sdk__form-field {\n margin-bottom: 16px;\n }\n\n .recur-sdk__form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n /* Labels and Text */\n .recur-sdk__label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n color: #374151;\n }\n\n .recur-sdk__hint-text {\n margin-top: 4px;\n font-size: 12px;\n color: #6b7280;\n }\n\n /* Input Container (for PAYUNi iframes) */\n .recur-sdk__input-container {\n /* Container styles applied via ID selectors below for PAYUNi compatibility */\n }\n\n /* Button */\n .recur-sdk__button {\n width: 100%;\n padding: 12px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s ease-in-out;\n }\n\n .recur-sdk__button:hover {\n background: #2563eb;\n }\n\n .recur-sdk__button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* PAYUNi SDK 自訂樣式 - 與 shadcn input focus 樣式一致 */\n /* Note: .form-input-focus is applied by PAYUNi SDK, not by our code */\n .form-input-focus {\n border-color: hsl(215 16% 47%) !important;\n outline: 0 !important;\n box-shadow: 0 0 0 3px hsl(215 16% 47% / 0.5) !important;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;\n }\n\n /* 確保 PAYUNi iframe 容器高度一致 */\n /* Note: These IDs are required by PAYUNi SDK and cannot be changed */\n #${containerElementId}-card-no,\n #${containerElementId}-card-exp,\n #${containerElementId}-card-cvc {\n height: 36px !important;\n }\n </style>\n\n <!-- Skeleton Loading State -->\n <div id=\"${containerElementId}-skeleton\" class=\"recur-sdk__skeleton-container\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n </div>\n <!-- Show button during loading to prevent layout shift -->\n <button class=\"recur-sdk__button\" disabled>\n 載入中...\n </button>\n </div>\n\n <!-- Actual Payment Form (hidden initially) -->\n <div id=\"${containerElementId}-form\" class=\"recur-sdk__form recur-sdk__form--hidden\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div id=\"${containerElementId}-card-no\" class=\"recur-sdk__input-container\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div id=\"${containerElementId}-card-exp\" class=\"recur-sdk__input-container\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div id=\"${containerElementId}-card-cvc\" class=\"recur-sdk__input-container\"></div>\n </div>\n </div>\n <button id=\"${containerElementId}-submit-btn\" class=\"recur-sdk__button\">\n 確認付款\n </button>\n </div>\n `;\n\n console.log('[Recur SDK] Starting PAYUNi SDK...');\n await uniPayment.start();\n console.log('[Recur SDK] PAYUNi SDK started successfully');\n\n // Step 2: Hide skeleton and show actual form\n console.log('[Recur SDK] Showing actual form...');\n const skeleton = document.getElementById(`${containerElementId}-skeleton`);\n const form = document.getElementById(`${containerElementId}-form`);\n if (skeleton && form) {\n skeleton.style.display = 'none';\n form.classList.remove('recur-sdk__form--hidden');\n }\n\n // Step 7: Handle form submission\n console.log('[Recur SDK] Step 7: Setting up submit button handler...');\n const submitBtn = document.getElementById(`${containerElementId}-submit-btn`);\n if (!submitBtn) {\n throw new Error('Submit button not found');\n }\n\n submitBtn.addEventListener('click', async () => {\n console.log('[Recur SDK] Submit button clicked');\n submitBtn.setAttribute('disabled', 'true');\n submitBtn.textContent = '處理中...';\n\n try {\n // Get card data from PAYUNi SDK\n console.log('[Recur SDK] Getting trade result from PAYUNi...');\n const tradeResult = await uniPayment.getTradeResult();\n console.log('[Recur SDK] Trade result received:', tradeResult);\n\n // Step 8: Complete subscription\n console.log('[Recur SDK] Step 8: Completing subscription...');\n const completeResponse = await fetch(\n `${baseUrl}/api/v1/subscriptions/${subscriptionResult.subscription.id}/complete`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n sdkToken: tokenResult.sdkToken,\n timestamp: tokenResult.timestamp,\n creditToken: tokenResult.creditToken,\n }),\n }\n );\n\n if (!completeResponse.ok) {\n const errorData = await completeResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to complete subscription:', errorData);\n throw new Error('Failed to complete subscription');\n }\n\n const completeResult: SubscriptionCompleteResult = await completeResponse.json();\n console.log('[Recur SDK] Subscription completed successfully:', completeResult);\n\n // Call payment complete callback\n console.log('[Recur SDK] Calling onPaymentComplete callback...');\n if (options.onPaymentComplete) {\n options.onPaymentComplete({\n id: completeResult.subscription.id,\n status: completeResult.subscription.status,\n planId: subscriptionResult.subscription.planId,\n amount: subscriptionResult.subscription.amount,\n billingPeriod: subscriptionResult.subscription.billingPeriod,\n currentPeriodStart: new Date().toISOString(),\n currentPeriodEnd: new Date().toISOString(),\n });\n }\n\n console.log('[Recur SDK] Checkout flow completed successfully!');\n\n // Close modal if in modal mode\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n setIsCheckingOut(false);\n } catch (error) {\n console.error('[Recur SDK] Error in payment flow:', error);\n const checkoutError: CheckoutError = {\n code: 'PAYMENT_FAILED',\n message: error instanceof Error ? error.message : 'Payment failed',\n };\n options.onError?.(checkoutError);\n\n // Re-enable submit button\n submitBtn.removeAttribute('disabled');\n submitBtn.textContent = '確認付款';\n setIsCheckingOut(false);\n }\n });\n\n console.log('[Recur SDK] Checkout flow initialized, waiting for user input...');\n } catch (error) {\n console.error('[Recur SDK] Checkout error:', error);\n\n // Clean up modal if it exists\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n const checkoutError: CheckoutError = {\n code: 'CHECKOUT_ERROR',\n message: error instanceof Error ? error.message : 'An unknown error occurred',\n };\n\n options.onError?.(checkoutError);\n setIsCheckingOut(false);\n throw error;\n }\n },\n [config]\n );\n\n const fetchPlans = useCallback(\n async (): Promise<PlansResult> => {\n // Check publishable key (required)\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n // Determine base URL\n const baseUrl = config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n\n // Call the plans API (v1)\n const response = await fetch(`${baseUrl}/api/v1/plans`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n },\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || 'Failed to fetch plans');\n }\n\n return await response.json();\n },\n [config]\n );\n\n const value = useMemo(\n () => ({\n config,\n checkout,\n fetchPlans,\n isCheckingOut,\n updateConfig,\n }),\n [config, checkout, fetchPlans, isCheckingOut, updateConfig]\n );\n\n return <RecurContext.Provider value={value}>{children}</RecurContext.Provider>;\n}\n\nexport { RecurContext };\n","'use client';\n\nimport { useContext } from 'react';\nimport { RecurContext } from './context.js';\nimport type { RecurContextValue } from './types.js';\n\n/**\n * useRecur Hook\n *\n * Access Recur checkout functionality from within your components\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { checkout, isCheckingOut } = useRecur();\n *\n * return (\n * <button\n * onClick={() => checkout({ planId: 'pro' })}\n * disabled={isCheckingOut}\n * >\n * {isCheckingOut ? 'Processing...' : 'Subscribe'}\n * </button>\n * );\n * }\n * ```\n *\n * @throws {Error} If used outside of RecurProvider\n */\nexport function useRecur(): RecurContextValue {\n const context = useContext(RecurContext);\n\n if (!context) {\n throw new Error('useRecur must be used within a RecurProvider');\n }\n\n return context;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -48,21 +48,6 @@ interface RecurConfig {
48
48
  * Where to redirect if user cancels payment
49
49
  */
50
50
  cancelUrl?: string;
51
- /**
52
- * Enable mock mode for testing without backend API
53
- * When enabled, all API calls return mock data
54
- * Perfect for demos, examples, and local development
55
- *
56
- * @default false
57
- * @example
58
- * ```typescript
59
- * const recur = RecurCheckout.init({
60
- * publishableKey: 'mock',
61
- * mockMode: true
62
- * });
63
- * ```
64
- */
65
- mockMode?: boolean;
66
51
  }
67
52
  interface CheckoutOptions {
68
53
  /**
@@ -109,7 +94,7 @@ interface CheckoutResult {
109
94
  planName: string;
110
95
  amount: number;
111
96
  billingPeriod: string;
112
- trialDays: number;
97
+ trialDays: number | null;
113
98
  };
114
99
  /**
115
100
  * Subscriber information
package/dist/index.d.ts CHANGED
@@ -48,21 +48,6 @@ interface RecurConfig {
48
48
  * Where to redirect if user cancels payment
49
49
  */
50
50
  cancelUrl?: string;
51
- /**
52
- * Enable mock mode for testing without backend API
53
- * When enabled, all API calls return mock data
54
- * Perfect for demos, examples, and local development
55
- *
56
- * @default false
57
- * @example
58
- * ```typescript
59
- * const recur = RecurCheckout.init({
60
- * publishableKey: 'mock',
61
- * mockMode: true
62
- * });
63
- * ```
64
- */
65
- mockMode?: boolean;
66
51
  }
67
52
  interface CheckoutOptions {
68
53
  /**
@@ -109,7 +94,7 @@ interface CheckoutResult {
109
94
  planName: string;
110
95
  amount: number;
111
96
  billingPeriod: string;
112
- trialDays: number;
97
+ trialDays: number | null;
113
98
  };
114
99
  /**
115
100
  * Subscriber information
package/dist/index.js CHANGED
@@ -9,52 +9,7 @@ var PAYUNI_SANDBOX_SDK_URL = "https://sandbox-vendor.payuni.com.tw/sdk/uni-payme
9
9
  var isLoaded = false;
10
10
  var isLoading = false;
11
11
  var loadPromise = null;
12
- function createMockUniPayment() {
13
- return {
14
- createSession: (token, options) => {
15
- console.log("[Mock PAYUNi SDK] Creating session with token:", token.substring(0, 20) + "...");
16
- console.log("[Mock PAYUNi SDK] Options:", options);
17
- const { elements } = options;
18
- const cardNoEl = document.getElementById(elements.CardNo);
19
- const cardExpEl = document.getElementById(elements.CardExp);
20
- const cardCvcEl = document.getElementById(elements.CardCvc);
21
- if (cardNoEl) {
22
- cardNoEl.innerHTML = '<div style="border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;">4242 4242 4242 4242 (Mock)</div>';
23
- }
24
- if (cardExpEl) {
25
- cardExpEl.innerHTML = '<div style="border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;">12 / 25 (Mock)</div>';
26
- }
27
- if (cardCvcEl) {
28
- cardCvcEl.innerHTML = '<div style="border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;">123 (Mock)</div>';
29
- }
30
- return {
31
- start: async () => {
32
- console.log("[Mock PAYUNi SDK] \u2713 Started successfully");
33
- await new Promise((resolve) => setTimeout(resolve, 500));
34
- },
35
- getTradeResult: async () => {
36
- console.log("[Mock PAYUNi SDK] \u2713 Getting trade result");
37
- await new Promise((resolve) => setTimeout(resolve, 800));
38
- return {
39
- Status: "SUCCESS",
40
- Message: "Mock payment successful",
41
- TradeNo: `MOCK${Date.now()}`,
42
- AuthCode: "123456"
43
- };
44
- }
45
- };
46
- }
47
- };
48
- }
49
- async function loadPayUniSDK(isSandbox = false, mockMode = false) {
50
- if (mockMode) {
51
- console.log("[Recur SDK] \u{1F3AD} Mock mode enabled - using mock PAYUNi SDK");
52
- if (typeof window !== "undefined") {
53
- window.UniPayment = createMockUniPayment();
54
- }
55
- isLoaded = true;
56
- return Promise.resolve();
57
- }
12
+ async function loadPayUniSDK(isSandbox = false) {
58
13
  if (isLoaded && window.UniPayment) {
59
14
  return Promise.resolve();
60
15
  }
@@ -118,7 +73,7 @@ function RecurProvider({ children, config: initialConfig = {} }) {
118
73
  if (!options.customerEmail || !options.customerName) {
119
74
  throw new Error("customerEmail and customerName are required");
120
75
  }
121
- const baseUrl = config.baseUrl || (typeof window !== "undefined" ? window.location.origin : "");
76
+ const baseUrl = config.baseUrl || "https://api.recur.tw";
122
77
  console.log("[Recur SDK] Base URL:", baseUrl);
123
78
  const headers = {
124
79
  "Content-Type": "application/json",
@@ -313,7 +268,7 @@ function RecurProvider({ children, config: initialConfig = {} }) {
313
268
  });
314
269
  console.log("[Recur SDK] Step 3: Loading PAYUNi SDK...");
315
270
  const isSandbox = tokenResult.environment === "SANDBOX";
316
- await loadPayUniSDK(isSandbox, config.mockMode);
271
+ await loadPayUniSDK(isSandbox);
317
272
  console.log("[Recur SDK] PAYUNi SDK loaded successfully");
318
273
  if (!window.UniPayment) {
319
274
  console.error("[Recur SDK] window.UniPayment is not available after loading");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/payuni-loader.ts","../src/context.tsx","../src/use-recur.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PAYUNi SDK Loader\n * Dynamically loads and initializes the PAYUNi UNi Embed SDK\n */\n\nimport type { UniPaymentInstance } from './types.js';\n\nconst PAYUNI_SDK_URL = 'https://vendor.payuni.com.tw/sdk/uni-payment.js';\nconst PAYUNI_SANDBOX_SDK_URL = 'https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js';\n\nlet isLoaded = false;\nlet isLoading = false;\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Create a mock PAYUNi SDK for testing without backend\n */\nfunction createMockUniPayment() {\n return {\n createSession: (token: string, options: any): UniPaymentInstance => {\n console.log('[Mock PAYUNi SDK] Creating session with token:', token.substring(0, 20) + '...');\n console.log('[Mock PAYUNi SDK] Options:', options);\n\n // Simulate rendering credit card iframes\n const { elements } = options;\n const cardNoEl = document.getElementById(elements.CardNo);\n const cardExpEl = document.getElementById(elements.CardExp);\n const cardCvcEl = document.getElementById(elements.CardCvc);\n\n // Inject mock iframe placeholders\n if (cardNoEl) {\n cardNoEl.innerHTML = '<div style=\"border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;\">4242 4242 4242 4242 (Mock)</div>';\n }\n if (cardExpEl) {\n cardExpEl.innerHTML = '<div style=\"border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;\">12 / 25 (Mock)</div>';\n }\n if (cardCvcEl) {\n cardCvcEl.innerHTML = '<div style=\"border: 1px solid #e5e7eb; padding: 8px; border-radius: 4px; background: white; font-size: 14px; color: #6b7280;\">123 (Mock)</div>';\n }\n\n return {\n start: async () => {\n console.log('[Mock PAYUNi SDK] ✓ Started successfully');\n // Simulate async loading\n await new Promise(resolve => setTimeout(resolve, 500));\n },\n getTradeResult: async () => {\n console.log('[Mock PAYUNi SDK] ✓ Getting trade result');\n // Simulate payment processing\n await new Promise(resolve => setTimeout(resolve, 800));\n return {\n Status: 'SUCCESS',\n Message: 'Mock payment successful',\n TradeNo: `MOCK${Date.now()}`,\n AuthCode: '123456',\n };\n },\n };\n },\n };\n}\n\n/**\n * Load PAYUNi SDK script\n * @param isSandbox - Use sandbox environment\n * @param mockMode - Use mock mode for testing\n */\nexport async function loadPayUniSDK(isSandbox: boolean = false, mockMode: boolean = false): Promise<void> {\n // Mock mode: inject mock SDK immediately\n if (mockMode) {\n console.log('[Recur SDK] 🎭 Mock mode enabled - using mock PAYUNi SDK');\n if (typeof window !== 'undefined') {\n (window as any).UniPayment = createMockUniPayment();\n }\n isLoaded = true;\n return Promise.resolve();\n }\n // Already loaded\n if (isLoaded && window.UniPayment) {\n return Promise.resolve();\n }\n\n // Currently loading\n if (isLoading && loadPromise) {\n return loadPromise;\n }\n\n // Start loading\n isLoading = true;\n loadPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = isSandbox ? PAYUNI_SANDBOX_SDK_URL : PAYUNI_SDK_URL;\n script.async = true;\n\n script.onload = () => {\n isLoaded = true;\n isLoading = false;\n resolve();\n };\n\n script.onerror = () => {\n isLoading = false;\n loadPromise = null;\n reject(new Error('Failed to load PAYUNi SDK'));\n };\n\n document.head.appendChild(script);\n });\n\n return loadPromise;\n}\n\n/**\n * Check if PAYUNi SDK is loaded\n */\nexport function isPayUniSDKLoaded(): boolean {\n return isLoaded && typeof window !== 'undefined' && !!window.UniPayment;\n}\n\n/**\n * Wait for PAYUNi SDK to be ready\n */\nexport async function waitForPayUniSDK(timeout: number = 10000): Promise<void> {\n const startTime = Date.now();\n\n while (!isPayUniSDKLoaded()) {\n if (Date.now() - startTime > timeout) {\n throw new Error('PAYUNi SDK load timeout');\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n","'use client';\n\nimport React, { createContext, useCallback, useState, useMemo } from 'react';\nimport type {\n RecurConfig,\n RecurContextValue,\n CheckoutOptions,\n CheckoutResult,\n CheckoutError,\n PlansResult,\n SdkTokenResult,\n SubscriptionCompleteResult,\n UniPaymentInstance,\n} from './types.js';\nimport { loadPayUniSDK } from './payuni-loader.js';\n\nconst RecurContext = createContext<RecurContextValue | null>(null);\n\nexport interface RecurProviderProps {\n children: React.ReactNode;\n config?: RecurConfig;\n}\n\n/**\n * RecurProvider\n *\n * Provides Recur checkout functionality to your React application\n *\n * @example\n * ```tsx\n * <RecurProvider config={{ publishableKey: 'pk_test_xxx' }}>\n * <App />\n * </RecurProvider>\n * ```\n */\nexport function RecurProvider({ children, config: initialConfig = {} }: RecurProviderProps) {\n const [config, setConfig] = useState<RecurConfig>({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n\n const [isCheckingOut, setIsCheckingOut] = useState(false);\n\n // Update config when initialConfig changes (e.g., when user switches modes)\n React.useEffect(() => {\n setConfig({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n }, [initialConfig.checkoutMode, initialConfig.publishableKey, initialConfig.containerElementId]);\n\n // Reset isCheckingOut when checkout mode changes to allow re-testing\n React.useEffect(() => {\n setIsCheckingOut(false);\n }, [config.checkoutMode]);\n\n const updateConfig = useCallback((newConfig: Partial<RecurConfig>) => {\n setConfig((prev) => ({ ...prev, ...newConfig }));\n }, []);\n\n const checkout = useCallback(\n async (options: CheckoutOptions) => {\n let modalOverlay: HTMLElement | null = null;\n\n try {\n console.log('[Recur SDK] Starting checkout flow...', {\n planId: options.planId,\n checkoutMode: config.checkoutMode,\n containerElementId: config.containerElementId,\n });\n\n setIsCheckingOut(true);\n\n // Validate required fields\n if (!options.planId) {\n throw new Error('planId is required');\n }\n\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n if (!options.customerEmail || !options.customerName) {\n throw new Error('customerEmail and customerName are required');\n }\n\n const baseUrl = config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n console.log('[Recur SDK] Base URL:', baseUrl);\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n };\n\n // Show loading state early for both modal and embedded modes\n let modalContent: HTMLElement | null = null;\n let loadingContainer: HTMLElement | null = null;\n let embeddedContainer: HTMLElement | null = null;\n\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, creating modal with loading state...');\n\n // Create modal overlay\n modalOverlay = document.createElement('div');\n modalOverlay.id = 'recur-modal-overlay';\n modalOverlay.className = 'recur-sdk__modal-overlay';\n modalOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n `;\n\n // Create modal content\n modalContent = document.createElement('div');\n modalContent.className = 'recur-sdk__modal-content';\n modalContent.style.cssText = `\n background: white;\n padding: 32px;\n border-radius: 12px;\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n position: relative;\n `;\n\n // Create close button\n const closeButton = document.createElement('button');\n closeButton.className = 'recur-sdk__close-button';\n closeButton.innerHTML = '✕';\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n closeButton.onclick = () => {\n modalOverlay?.remove();\n setIsCheckingOut(false);\n options.onPaymentCancel?.();\n };\n\n // Create title\n const title = document.createElement('h2');\n title.className = 'recur-sdk__title';\n title.textContent = '訂閱付款';\n title.style.cssText = 'margin: 0 0 24px 0; font-size: 24px; font-weight: 600;';\n\n // Create loading container with spinner\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-modal-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n modalContent.appendChild(closeButton);\n modalContent.appendChild(title);\n modalContent.appendChild(loadingContainer);\n modalOverlay.appendChild(modalContent);\n document.body.appendChild(modalOverlay);\n\n console.log('[Recur SDK] Modal created with loading state');\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, try to show loading in the container if it exists\n console.log('[Recur SDK] Mode is embedded, checking for container...');\n\n if (!config.containerElementId) {\n console.warn('[Recur SDK] No containerElementId provided for embedded mode');\n } else {\n // Poll for the container to appear (wait up to 500ms)\n embeddedContainer = document.getElementById(config.containerElementId);\n\n if (!embeddedContainer) {\n console.log('[Recur SDK] Container not found, polling for container...');\n for (let i = 0; i < 10; i++) {\n await new Promise(resolve => setTimeout(resolve, 50));\n embeddedContainer = document.getElementById(config.containerElementId);\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found after polling');\n break;\n }\n }\n }\n\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found, showing loading state...');\n\n // Show loading state in the embedded container\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-embedded-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n embeddedContainer.appendChild(loadingContainer);\n } else {\n console.log('[Recur SDK] Container not found after polling, will continue without early loading state');\n }\n }\n }\n\n // Step 1: Create subscription\n console.log('[Recur SDK] Step 1: Creating subscription...');\n const subscriptionResponse = await fetch(`${baseUrl}/api/v1/subscriptions`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n planId: options.planId,\n customerName: options.customerName,\n customerEmail: options.customerEmail,\n customerPhone: options.customerPhone,\n }),\n });\n\n if (!subscriptionResponse.ok) {\n const errorData = await subscriptionResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to create subscription:', errorData);\n const errorMessage = errorData.details || errorData.error || 'Failed to create subscription';\n throw new Error(errorMessage);\n }\n\n const subscriptionResult: CheckoutResult = await subscriptionResponse.json();\n console.log('[Recur SDK] Subscription created successfully:', subscriptionResult);\n\n // Call onSuccess callback\n options.onSuccess?.(subscriptionResult);\n\n // Step 2: Get SDK token\n console.log('[Recur SDK] Step 2: Getting SDK token...');\n const tokenResponse = await fetch(`${baseUrl}/api/v1/subscriptions/sdk-token`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n subscriberId: subscriptionResult.subscriber.id,\n iframeDomain: window.location.origin,\n }),\n });\n\n if (!tokenResponse.ok) {\n const errorData = await tokenResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to get SDK token:', errorData);\n throw new Error('Failed to get SDK token');\n }\n\n const tokenResult: SdkTokenResult = await tokenResponse.json();\n console.log('[Recur SDK] SDK token received:', {\n environment: tokenResult.environment,\n creditToken: tokenResult.creditToken,\n tokenExpired: tokenResult.tokenExpired,\n });\n\n // Step 3: Load PAYUNi SDK\n console.log('[Recur SDK] Step 3: Loading PAYUNi SDK...');\n const isSandbox = tokenResult.environment === 'SANDBOX';\n await loadPayUniSDK(isSandbox, config.mockMode);\n console.log('[Recur SDK] PAYUNi SDK loaded successfully');\n\n if (!window.UniPayment) {\n console.error('[Recur SDK] window.UniPayment is not available after loading');\n throw new Error('PAYUNi SDK failed to load');\n }\n\n // Step 4: Determine container element based on checkout mode\n console.log('[Recur SDK] Step 4: Preparing container for checkout mode:', config.checkoutMode);\n console.log('[Recur SDK] Initial containerElementId from config:', config.containerElementId);\n\n let containerElementId = config.containerElementId;\n\n // For modal mode, update the existing modal with payment form container\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, updating modal with payment form...');\n\n if (!loadingContainer || !modalContent) {\n throw new Error('Modal components not initialized');\n }\n\n // Remove loading spinner\n loadingContainer.remove();\n\n // Create container for payment form\n const formContainer = document.createElement('div');\n containerElementId = 'recur-modal-payment-container';\n formContainer.id = containerElementId;\n\n modalContent.appendChild(formContainer);\n\n console.log('[Recur SDK] Modal updated with container ID:', containerElementId);\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, remove loading spinner if it exists\n console.log('[Recur SDK] Mode is embedded, preparing container...');\n\n if (!containerElementId) {\n throw new Error('containerElementId is required for embedded mode');\n }\n\n // Remove loading spinner if we showed it earlier\n if (loadingContainer && embeddedContainer) {\n console.log('[Recur SDK] Removing loading spinner from embedded container');\n loadingContainer.remove();\n }\n }\n\n // Step 5: Initialize PAYUNi form\n console.log('[Recur SDK] Step 5: Initializing PAYUNi form...');\n console.log('[Recur SDK] Available UniPayment methods:', Object.keys(window.UniPayment || {}));\n\n if (!containerElementId) {\n throw new Error('containerElementId is required');\n }\n\n // PAYUNi SDK uses createSession(token, options)\n const uniPayment = window.UniPayment.createSession(tokenResult.sdkToken, {\n env: tokenResult.environment === 'SANDBOX' ? 'S' : 'P',\n elements: {\n CardNo: `${containerElementId}-card-no`,\n CardExp: `${containerElementId}-card-exp`,\n CardCvc: `${containerElementId}-card-cvc`,\n },\n });\n console.log('[Recur SDK] PAYUNi form initialized');\n\n // Step 6: Wait for container and create form elements\n console.log('[Recur SDK] Step 6: Waiting for container element...');\n\n // For embedded mode, wait for the container to appear in DOM\n // (React needs time to render after onSuccess callback)\n let container = document.getElementById(containerElementId);\n if (!container && config.checkoutMode === 'embedded') {\n console.log('[Recur SDK] Container not found, waiting for React to render...');\n // Wait up to 2 seconds for container to appear\n for (let i = 0; i < 20; i++) {\n await new Promise(resolve => setTimeout(resolve, 100));\n container = document.getElementById(containerElementId);\n if (container) {\n console.log('[Recur SDK] Container found after waiting');\n break;\n }\n }\n }\n\n if (!container) {\n throw new Error(`Container element '${containerElementId}' not found`);\n }\n\n console.log('[Recur SDK] Creating loading skeleton...');\n\n // Step 1: Show loading skeleton first\n container.innerHTML = `\n <style>\n /* Recur SDK Styles - CSS Namespace with BEM */\n\n /* Animations */\n @keyframes recur-sdk-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n /* Skeleton Loading State */\n .recur-sdk__skeleton {\n animation: recur-sdk-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background-color: #e5e7eb;\n border-radius: 6px;\n }\n\n /* Form States */\n .recur-sdk__form--hidden {\n display: none;\n }\n\n /* Form Layout */\n .recur-sdk__form-field {\n margin-bottom: 16px;\n }\n\n .recur-sdk__form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n /* Labels and Text */\n .recur-sdk__label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n color: #374151;\n }\n\n .recur-sdk__hint-text {\n margin-top: 4px;\n font-size: 12px;\n color: #6b7280;\n }\n\n /* Input Container (for PAYUNi iframes) */\n .recur-sdk__input-container {\n /* Container styles applied via ID selectors below for PAYUNi compatibility */\n }\n\n /* Button */\n .recur-sdk__button {\n width: 100%;\n padding: 12px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s ease-in-out;\n }\n\n .recur-sdk__button:hover {\n background: #2563eb;\n }\n\n .recur-sdk__button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* PAYUNi SDK 自訂樣式 - 與 shadcn input focus 樣式一致 */\n /* Note: .form-input-focus is applied by PAYUNi SDK, not by our code */\n .form-input-focus {\n border-color: hsl(215 16% 47%) !important;\n outline: 0 !important;\n box-shadow: 0 0 0 3px hsl(215 16% 47% / 0.5) !important;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;\n }\n\n /* 確保 PAYUNi iframe 容器高度一致 */\n /* Note: These IDs are required by PAYUNi SDK and cannot be changed */\n #${containerElementId}-card-no,\n #${containerElementId}-card-exp,\n #${containerElementId}-card-cvc {\n height: 36px !important;\n }\n </style>\n\n <!-- Skeleton Loading State -->\n <div id=\"${containerElementId}-skeleton\" class=\"recur-sdk__skeleton-container\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n </div>\n <!-- Show button during loading to prevent layout shift -->\n <button class=\"recur-sdk__button\" disabled>\n 載入中...\n </button>\n </div>\n\n <!-- Actual Payment Form (hidden initially) -->\n <div id=\"${containerElementId}-form\" class=\"recur-sdk__form recur-sdk__form--hidden\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div id=\"${containerElementId}-card-no\" class=\"recur-sdk__input-container\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div id=\"${containerElementId}-card-exp\" class=\"recur-sdk__input-container\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div id=\"${containerElementId}-card-cvc\" class=\"recur-sdk__input-container\"></div>\n </div>\n </div>\n <button id=\"${containerElementId}-submit-btn\" class=\"recur-sdk__button\">\n 確認付款\n </button>\n </div>\n `;\n\n console.log('[Recur SDK] Starting PAYUNi SDK...');\n await uniPayment.start();\n console.log('[Recur SDK] PAYUNi SDK started successfully');\n\n // Step 2: Hide skeleton and show actual form\n console.log('[Recur SDK] Showing actual form...');\n const skeleton = document.getElementById(`${containerElementId}-skeleton`);\n const form = document.getElementById(`${containerElementId}-form`);\n if (skeleton && form) {\n skeleton.style.display = 'none';\n form.classList.remove('recur-sdk__form--hidden');\n }\n\n // Step 7: Handle form submission\n console.log('[Recur SDK] Step 7: Setting up submit button handler...');\n const submitBtn = document.getElementById(`${containerElementId}-submit-btn`);\n if (!submitBtn) {\n throw new Error('Submit button not found');\n }\n\n submitBtn.addEventListener('click', async () => {\n console.log('[Recur SDK] Submit button clicked');\n submitBtn.setAttribute('disabled', 'true');\n submitBtn.textContent = '處理中...';\n\n try {\n // Get card data from PAYUNi SDK\n console.log('[Recur SDK] Getting trade result from PAYUNi...');\n const tradeResult = await uniPayment.getTradeResult();\n console.log('[Recur SDK] Trade result received:', tradeResult);\n\n // Step 8: Complete subscription\n console.log('[Recur SDK] Step 8: Completing subscription...');\n const completeResponse = await fetch(\n `${baseUrl}/api/v1/subscriptions/${subscriptionResult.subscription.id}/complete`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n sdkToken: tokenResult.sdkToken,\n timestamp: tokenResult.timestamp,\n creditToken: tokenResult.creditToken,\n }),\n }\n );\n\n if (!completeResponse.ok) {\n const errorData = await completeResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to complete subscription:', errorData);\n throw new Error('Failed to complete subscription');\n }\n\n const completeResult: SubscriptionCompleteResult = await completeResponse.json();\n console.log('[Recur SDK] Subscription completed successfully:', completeResult);\n\n // Call payment complete callback\n console.log('[Recur SDK] Calling onPaymentComplete callback...');\n if (options.onPaymentComplete) {\n options.onPaymentComplete({\n id: completeResult.subscription.id,\n status: completeResult.subscription.status,\n planId: subscriptionResult.subscription.planId,\n amount: subscriptionResult.subscription.amount,\n billingPeriod: subscriptionResult.subscription.billingPeriod,\n currentPeriodStart: new Date().toISOString(),\n currentPeriodEnd: new Date().toISOString(),\n });\n }\n\n console.log('[Recur SDK] Checkout flow completed successfully!');\n\n // Close modal if in modal mode\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n setIsCheckingOut(false);\n } catch (error) {\n console.error('[Recur SDK] Error in payment flow:', error);\n const checkoutError: CheckoutError = {\n code: 'PAYMENT_FAILED',\n message: error instanceof Error ? error.message : 'Payment failed',\n };\n options.onError?.(checkoutError);\n\n // Re-enable submit button\n submitBtn.removeAttribute('disabled');\n submitBtn.textContent = '確認付款';\n setIsCheckingOut(false);\n }\n });\n\n console.log('[Recur SDK] Checkout flow initialized, waiting for user input...');\n } catch (error) {\n console.error('[Recur SDK] Checkout error:', error);\n\n // Clean up modal if it exists\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n const checkoutError: CheckoutError = {\n code: 'CHECKOUT_ERROR',\n message: error instanceof Error ? error.message : 'An unknown error occurred',\n };\n\n options.onError?.(checkoutError);\n setIsCheckingOut(false);\n throw error;\n }\n },\n [config]\n );\n\n const fetchPlans = useCallback(\n async (): Promise<PlansResult> => {\n // Check publishable key (required)\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n // Determine base URL\n const baseUrl = config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n\n // Call the plans API (v1)\n const response = await fetch(`${baseUrl}/api/v1/plans`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n },\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || 'Failed to fetch plans');\n }\n\n return await response.json();\n },\n [config]\n );\n\n const value = useMemo(\n () => ({\n config,\n checkout,\n fetchPlans,\n isCheckingOut,\n updateConfig,\n }),\n [config, checkout, fetchPlans, isCheckingOut, updateConfig]\n );\n\n return <RecurContext.Provider value={value}>{children}</RecurContext.Provider>;\n}\n\nexport { RecurContext };\n","'use client';\n\nimport { useContext } from 'react';\nimport { RecurContext } from './context.js';\nimport type { RecurContextValue } from './types.js';\n\n/**\n * useRecur Hook\n *\n * Access Recur checkout functionality from within your components\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { checkout, isCheckingOut } = useRecur();\n *\n * return (\n * <button\n * onClick={() => checkout({ planId: 'pro' })}\n * disabled={isCheckingOut}\n * >\n * {isCheckingOut ? 'Processing...' : 'Subscribe'}\n * </button>\n * );\n * }\n * ```\n *\n * @throws {Error} If used outside of RecurProvider\n */\nexport function useRecur(): RecurContextValue {\n const context = useContext(RecurContext);\n\n if (!context) {\n throw new Error('useRecur must be used within a RecurProvider');\n }\n\n return context;\n}\n"]}
1
+ {"version":3,"sources":["../src/payuni-loader.ts","../src/context.tsx","../src/use-recur.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PAYUNi SDK Loader\n * Dynamically loads and initializes the PAYUNi UNi Embed SDK\n */\n\nimport type { UniPaymentInstance } from './types.js';\n\nconst PAYUNI_SDK_URL = 'https://vendor.payuni.com.tw/sdk/uni-payment.js';\nconst PAYUNI_SANDBOX_SDK_URL = 'https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js';\n\nlet isLoaded = false;\nlet isLoading = false;\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Load PAYUNi SDK script\n * @param isSandbox - Use sandbox environment\n */\nexport async function loadPayUniSDK(isSandbox: boolean = false): Promise<void> {\n // Already loaded\n if (isLoaded && window.UniPayment) {\n return Promise.resolve();\n }\n\n // Currently loading\n if (isLoading && loadPromise) {\n return loadPromise;\n }\n\n // Start loading\n isLoading = true;\n loadPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = isSandbox ? PAYUNI_SANDBOX_SDK_URL : PAYUNI_SDK_URL;\n script.async = true;\n\n script.onload = () => {\n isLoaded = true;\n isLoading = false;\n resolve();\n };\n\n script.onerror = () => {\n isLoading = false;\n loadPromise = null;\n reject(new Error('Failed to load PAYUNi SDK'));\n };\n\n document.head.appendChild(script);\n });\n\n return loadPromise;\n}\n\n/**\n * Check if PAYUNi SDK is loaded\n */\nexport function isPayUniSDKLoaded(): boolean {\n return isLoaded && typeof window !== 'undefined' && !!window.UniPayment;\n}\n\n/**\n * Wait for PAYUNi SDK to be ready\n */\nexport async function waitForPayUniSDK(timeout: number = 10000): Promise<void> {\n const startTime = Date.now();\n\n while (!isPayUniSDKLoaded()) {\n if (Date.now() - startTime > timeout) {\n throw new Error('PAYUNi SDK load timeout');\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n","'use client';\n\nimport React, { createContext, useCallback, useState, useMemo } from 'react';\nimport type {\n RecurConfig,\n RecurContextValue,\n CheckoutOptions,\n CheckoutResult,\n CheckoutError,\n PlansResult,\n SdkTokenResult,\n SubscriptionCompleteResult,\n UniPaymentInstance,\n} from './types.js';\nimport { loadPayUniSDK } from './payuni-loader.js';\n\nconst RecurContext = createContext<RecurContextValue | null>(null);\n\nexport interface RecurProviderProps {\n children: React.ReactNode;\n config?: RecurConfig;\n}\n\n/**\n * RecurProvider\n *\n * Provides Recur checkout functionality to your React application\n *\n * @example\n * ```tsx\n * <RecurProvider config={{ publishableKey: 'pk_test_xxx' }}>\n * <App />\n * </RecurProvider>\n * ```\n */\nexport function RecurProvider({ children, config: initialConfig = {} }: RecurProviderProps) {\n const [config, setConfig] = useState<RecurConfig>({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n\n const [isCheckingOut, setIsCheckingOut] = useState(false);\n\n // Update config when initialConfig changes (e.g., when user switches modes)\n React.useEffect(() => {\n setConfig({\n checkoutMode: 'embedded',\n ...initialConfig,\n });\n }, [initialConfig.checkoutMode, initialConfig.publishableKey, initialConfig.containerElementId]);\n\n // Reset isCheckingOut when checkout mode changes to allow re-testing\n React.useEffect(() => {\n setIsCheckingOut(false);\n }, [config.checkoutMode]);\n\n const updateConfig = useCallback((newConfig: Partial<RecurConfig>) => {\n setConfig((prev) => ({ ...prev, ...newConfig }));\n }, []);\n\n const checkout = useCallback(\n async (options: CheckoutOptions) => {\n let modalOverlay: HTMLElement | null = null;\n\n try {\n console.log('[Recur SDK] Starting checkout flow...', {\n planId: options.planId,\n checkoutMode: config.checkoutMode,\n containerElementId: config.containerElementId,\n });\n\n setIsCheckingOut(true);\n\n // Validate required fields\n if (!options.planId) {\n throw new Error('planId is required');\n }\n\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n if (!options.customerEmail || !options.customerName) {\n throw new Error('customerEmail and customerName are required');\n }\n\n const baseUrl = config.baseUrl || 'https://api.recur.tw';\n console.log('[Recur SDK] Base URL:', baseUrl);\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n };\n\n // Show loading state early for both modal and embedded modes\n let modalContent: HTMLElement | null = null;\n let loadingContainer: HTMLElement | null = null;\n let embeddedContainer: HTMLElement | null = null;\n\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, creating modal with loading state...');\n\n // Create modal overlay\n modalOverlay = document.createElement('div');\n modalOverlay.id = 'recur-modal-overlay';\n modalOverlay.className = 'recur-sdk__modal-overlay';\n modalOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n `;\n\n // Create modal content\n modalContent = document.createElement('div');\n modalContent.className = 'recur-sdk__modal-content';\n modalContent.style.cssText = `\n background: white;\n padding: 32px;\n border-radius: 12px;\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow-y: auto;\n position: relative;\n `;\n\n // Create close button\n const closeButton = document.createElement('button');\n closeButton.className = 'recur-sdk__close-button';\n closeButton.innerHTML = '✕';\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n closeButton.onclick = () => {\n modalOverlay?.remove();\n setIsCheckingOut(false);\n options.onPaymentCancel?.();\n };\n\n // Create title\n const title = document.createElement('h2');\n title.className = 'recur-sdk__title';\n title.textContent = '訂閱付款';\n title.style.cssText = 'margin: 0 0 24px 0; font-size: 24px; font-weight: 600;';\n\n // Create loading container with spinner\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-modal-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n modalContent.appendChild(closeButton);\n modalContent.appendChild(title);\n modalContent.appendChild(loadingContainer);\n modalOverlay.appendChild(modalContent);\n document.body.appendChild(modalOverlay);\n\n console.log('[Recur SDK] Modal created with loading state');\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, try to show loading in the container if it exists\n console.log('[Recur SDK] Mode is embedded, checking for container...');\n\n if (!config.containerElementId) {\n console.warn('[Recur SDK] No containerElementId provided for embedded mode');\n } else {\n // Poll for the container to appear (wait up to 500ms)\n embeddedContainer = document.getElementById(config.containerElementId);\n\n if (!embeddedContainer) {\n console.log('[Recur SDK] Container not found, polling for container...');\n for (let i = 0; i < 10; i++) {\n await new Promise(resolve => setTimeout(resolve, 50));\n embeddedContainer = document.getElementById(config.containerElementId);\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found after polling');\n break;\n }\n }\n }\n\n if (embeddedContainer) {\n console.log('[Recur SDK] Container found, showing loading state...');\n\n // Show loading state in the embedded container\n loadingContainer = document.createElement('div');\n loadingContainer.id = 'recur-embedded-loading';\n loadingContainer.className = 'recur-sdk__loading-container';\n loadingContainer.style.cssText = 'text-align: center; padding: 40px 0;';\n loadingContainer.innerHTML = `\n <style>\n @keyframes recur-sdk-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n .recur-sdk__spinner {\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n width: 40px;\n height: 40px;\n animation: recur-sdk-spin 1s linear infinite;\n margin: 0 auto 16px;\n }\n .recur-sdk__loading-text {\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n }\n </style>\n <div class=\"recur-sdk__spinner\"></div>\n <p class=\"recur-sdk__loading-text\">正在處理訂閱...</p>\n `;\n\n embeddedContainer.appendChild(loadingContainer);\n } else {\n console.log('[Recur SDK] Container not found after polling, will continue without early loading state');\n }\n }\n }\n\n // Step 1: Create subscription\n console.log('[Recur SDK] Step 1: Creating subscription...');\n\n const subscriptionResponse = await fetch(`${baseUrl}/api/v1/subscriptions`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n planId: options.planId,\n customerName: options.customerName,\n customerEmail: options.customerEmail,\n customerPhone: options.customerPhone,\n }),\n });\n\n if (!subscriptionResponse.ok) {\n const errorData = await subscriptionResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to create subscription:', errorData);\n const errorMessage = errorData.details || errorData.error || 'Failed to create subscription';\n throw new Error(errorMessage);\n }\n\n const subscriptionResult: CheckoutResult = await subscriptionResponse.json();\n console.log('[Recur SDK] Subscription created successfully:', subscriptionResult);\n\n // Call onSuccess callback\n options.onSuccess?.(subscriptionResult);\n\n // Step 2: Get SDK token\n console.log('[Recur SDK] Step 2: Getting SDK token...');\n\n const tokenResponse = await fetch(`${baseUrl}/api/v1/subscriptions/sdk-token`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n subscriberId: subscriptionResult.subscriber.id,\n iframeDomain: window.location.origin,\n }),\n });\n\n if (!tokenResponse.ok) {\n const errorData = await tokenResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to get SDK token:', errorData);\n throw new Error('Failed to get SDK token');\n }\n\n const tokenResult: SdkTokenResult = await tokenResponse.json();\n console.log('[Recur SDK] SDK token received:', {\n environment: tokenResult.environment,\n creditToken: tokenResult.creditToken,\n tokenExpired: tokenResult.tokenExpired,\n });\n\n // Step 3: Load PAYUNi SDK\n console.log('[Recur SDK] Step 3: Loading PAYUNi SDK...');\n const isSandbox = tokenResult.environment === 'SANDBOX';\n await loadPayUniSDK(isSandbox);\n console.log('[Recur SDK] PAYUNi SDK loaded successfully');\n\n if (!window.UniPayment) {\n console.error('[Recur SDK] window.UniPayment is not available after loading');\n throw new Error('PAYUNi SDK failed to load');\n }\n\n // Step 4: Determine container element based on checkout mode\n console.log('[Recur SDK] Step 4: Preparing container for checkout mode:', config.checkoutMode);\n console.log('[Recur SDK] Initial containerElementId from config:', config.containerElementId);\n\n let containerElementId = config.containerElementId;\n\n // For modal mode, update the existing modal with payment form container\n if (config.checkoutMode === 'modal') {\n console.log('[Recur SDK] Mode is modal, updating modal with payment form...');\n\n if (!loadingContainer || !modalContent) {\n throw new Error('Modal components not initialized');\n }\n\n // Remove loading spinner\n loadingContainer.remove();\n\n // Create container for payment form\n const formContainer = document.createElement('div');\n containerElementId = 'recur-modal-payment-container';\n formContainer.id = containerElementId;\n\n modalContent.appendChild(formContainer);\n\n console.log('[Recur SDK] Modal updated with container ID:', containerElementId);\n } else if (config.checkoutMode === 'embedded') {\n // For embedded mode, remove loading spinner if it exists\n console.log('[Recur SDK] Mode is embedded, preparing container...');\n\n if (!containerElementId) {\n throw new Error('containerElementId is required for embedded mode');\n }\n\n // Remove loading spinner if we showed it earlier\n if (loadingContainer && embeddedContainer) {\n console.log('[Recur SDK] Removing loading spinner from embedded container');\n loadingContainer.remove();\n }\n }\n\n // Step 5: Initialize PAYUNi form\n console.log('[Recur SDK] Step 5: Initializing PAYUNi form...');\n console.log('[Recur SDK] Available UniPayment methods:', Object.keys(window.UniPayment || {}));\n\n if (!containerElementId) {\n throw new Error('containerElementId is required');\n }\n\n // PAYUNi SDK uses createSession(token, options)\n const uniPayment = window.UniPayment.createSession(tokenResult.sdkToken, {\n env: tokenResult.environment === 'SANDBOX' ? 'S' : 'P',\n elements: {\n CardNo: `${containerElementId}-card-no`,\n CardExp: `${containerElementId}-card-exp`,\n CardCvc: `${containerElementId}-card-cvc`,\n },\n });\n console.log('[Recur SDK] PAYUNi form initialized');\n\n // Step 6: Wait for container and create form elements\n console.log('[Recur SDK] Step 6: Waiting for container element...');\n\n // For embedded mode, wait for the container to appear in DOM\n // (React needs time to render after onSuccess callback)\n let container = document.getElementById(containerElementId);\n if (!container && config.checkoutMode === 'embedded') {\n console.log('[Recur SDK] Container not found, waiting for React to render...');\n // Wait up to 2 seconds for container to appear\n for (let i = 0; i < 20; i++) {\n await new Promise(resolve => setTimeout(resolve, 100));\n container = document.getElementById(containerElementId);\n if (container) {\n console.log('[Recur SDK] Container found after waiting');\n break;\n }\n }\n }\n\n if (!container) {\n throw new Error(`Container element '${containerElementId}' not found`);\n }\n\n console.log('[Recur SDK] Creating loading skeleton...');\n\n // Step 1: Show loading skeleton first\n container.innerHTML = `\n <style>\n /* Recur SDK Styles - CSS Namespace with BEM */\n\n /* Animations */\n @keyframes recur-sdk-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n /* Skeleton Loading State */\n .recur-sdk__skeleton {\n animation: recur-sdk-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n background-color: #e5e7eb;\n border-radius: 6px;\n }\n\n /* Form States */\n .recur-sdk__form--hidden {\n display: none;\n }\n\n /* Form Layout */\n .recur-sdk__form-field {\n margin-bottom: 16px;\n }\n\n .recur-sdk__form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n /* Labels and Text */\n .recur-sdk__label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n color: #374151;\n }\n\n .recur-sdk__hint-text {\n margin-top: 4px;\n font-size: 12px;\n color: #6b7280;\n }\n\n /* Input Container (for PAYUNi iframes) */\n .recur-sdk__input-container {\n /* Container styles applied via ID selectors below for PAYUNi compatibility */\n }\n\n /* Button */\n .recur-sdk__button {\n width: 100%;\n padding: 12px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s ease-in-out;\n }\n\n .recur-sdk__button:hover {\n background: #2563eb;\n }\n\n .recur-sdk__button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* PAYUNi SDK 自訂樣式 - 與 shadcn input focus 樣式一致 */\n /* Note: .form-input-focus is applied by PAYUNi SDK, not by our code */\n .form-input-focus {\n border-color: hsl(215 16% 47%) !important;\n outline: 0 !important;\n box-shadow: 0 0 0 3px hsl(215 16% 47% / 0.5) !important;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important;\n }\n\n /* 確保 PAYUNi iframe 容器高度一致 */\n /* Note: These IDs are required by PAYUNi SDK and cannot be changed */\n #${containerElementId}-card-no,\n #${containerElementId}-card-exp,\n #${containerElementId}-card-cvc {\n height: 36px !important;\n }\n </style>\n\n <!-- Skeleton Loading State -->\n <div id=\"${containerElementId}-skeleton\" class=\"recur-sdk__skeleton-container\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div class=\"recur-sdk__skeleton\" style=\"height: 36px;\"></div>\n </div>\n </div>\n <!-- Show button during loading to prevent layout shift -->\n <button class=\"recur-sdk__button\" disabled>\n 載入中...\n </button>\n </div>\n\n <!-- Actual Payment Form (hidden initially) -->\n <div id=\"${containerElementId}-form\" class=\"recur-sdk__form recur-sdk__form--hidden\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">卡號</label>\n <div id=\"${containerElementId}-card-no\" class=\"recur-sdk__input-container\"></div>\n <p class=\"recur-sdk__hint-text\">請輸入您的 16 位數卡號</p>\n </div>\n <div class=\"recur-sdk__form-row\">\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">有效期限</label>\n <div id=\"${containerElementId}-card-exp\" class=\"recur-sdk__input-container\"></div>\n </div>\n <div class=\"recur-sdk__form-field\">\n <label class=\"recur-sdk__label\">安全碼</label>\n <div id=\"${containerElementId}-card-cvc\" class=\"recur-sdk__input-container\"></div>\n </div>\n </div>\n <button id=\"${containerElementId}-submit-btn\" class=\"recur-sdk__button\">\n 確認付款\n </button>\n </div>\n `;\n\n console.log('[Recur SDK] Starting PAYUNi SDK...');\n await uniPayment.start();\n console.log('[Recur SDK] PAYUNi SDK started successfully');\n\n // Step 2: Hide skeleton and show actual form\n console.log('[Recur SDK] Showing actual form...');\n const skeleton = document.getElementById(`${containerElementId}-skeleton`);\n const form = document.getElementById(`${containerElementId}-form`);\n if (skeleton && form) {\n skeleton.style.display = 'none';\n form.classList.remove('recur-sdk__form--hidden');\n }\n\n // Step 7: Handle form submission\n console.log('[Recur SDK] Step 7: Setting up submit button handler...');\n const submitBtn = document.getElementById(`${containerElementId}-submit-btn`);\n if (!submitBtn) {\n throw new Error('Submit button not found');\n }\n\n submitBtn.addEventListener('click', async () => {\n console.log('[Recur SDK] Submit button clicked');\n submitBtn.setAttribute('disabled', 'true');\n submitBtn.textContent = '處理中...';\n\n try {\n // Get card data from PAYUNi SDK\n console.log('[Recur SDK] Getting trade result from PAYUNi...');\n const tradeResult = await uniPayment.getTradeResult();\n console.log('[Recur SDK] Trade result received:', tradeResult);\n\n // Step 8: Complete subscription\n console.log('[Recur SDK] Step 8: Completing subscription...');\n const completeResponse = await fetch(\n `${baseUrl}/api/v1/subscriptions/${subscriptionResult.subscription.id}/complete`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n sdkToken: tokenResult.sdkToken,\n timestamp: tokenResult.timestamp,\n creditToken: tokenResult.creditToken,\n }),\n }\n );\n\n if (!completeResponse.ok) {\n const errorData = await completeResponse.json().catch(() => ({}));\n console.error('[Recur SDK] Failed to complete subscription:', errorData);\n throw new Error('Failed to complete subscription');\n }\n\n const completeResult: SubscriptionCompleteResult = await completeResponse.json();\n console.log('[Recur SDK] Subscription completed successfully:', completeResult);\n\n // Call payment complete callback\n console.log('[Recur SDK] Calling onPaymentComplete callback...');\n if (options.onPaymentComplete) {\n options.onPaymentComplete({\n id: completeResult.subscription.id,\n status: completeResult.subscription.status,\n planId: subscriptionResult.subscription.planId,\n amount: subscriptionResult.subscription.amount,\n billingPeriod: subscriptionResult.subscription.billingPeriod,\n currentPeriodStart: new Date().toISOString(),\n currentPeriodEnd: new Date().toISOString(),\n });\n }\n\n console.log('[Recur SDK] Checkout flow completed successfully!');\n\n // Close modal if in modal mode\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n setIsCheckingOut(false);\n } catch (error) {\n console.error('[Recur SDK] Error in payment flow:', error);\n const checkoutError: CheckoutError = {\n code: 'PAYMENT_FAILED',\n message: error instanceof Error ? error.message : 'Payment failed',\n };\n options.onError?.(checkoutError);\n\n // Re-enable submit button\n submitBtn.removeAttribute('disabled');\n submitBtn.textContent = '確認付款';\n setIsCheckingOut(false);\n }\n });\n\n console.log('[Recur SDK] Checkout flow initialized, waiting for user input...');\n } catch (error) {\n console.error('[Recur SDK] Checkout error:', error);\n\n // Clean up modal if it exists\n if (modalOverlay) {\n modalOverlay.remove();\n }\n\n const checkoutError: CheckoutError = {\n code: 'CHECKOUT_ERROR',\n message: error instanceof Error ? error.message : 'An unknown error occurred',\n };\n\n options.onError?.(checkoutError);\n setIsCheckingOut(false);\n throw error;\n }\n },\n [config]\n );\n\n const fetchPlans = useCallback(\n async (): Promise<PlansResult> => {\n // Check publishable key (required)\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n // Determine base URL\n const baseUrl = config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n\n // Call the plans API (v1)\n const response = await fetch(`${baseUrl}/api/v1/plans`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': config.publishableKey,\n },\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || 'Failed to fetch plans');\n }\n\n return await response.json();\n },\n [config]\n );\n\n const value = useMemo(\n () => ({\n config,\n checkout,\n fetchPlans,\n isCheckingOut,\n updateConfig,\n }),\n [config, checkout, fetchPlans, isCheckingOut, updateConfig]\n );\n\n return <RecurContext.Provider value={value}>{children}</RecurContext.Provider>;\n}\n\nexport { RecurContext };\n","'use client';\n\nimport { useContext } from 'react';\nimport { RecurContext } from './context.js';\nimport type { RecurContextValue } from './types.js';\n\n/**\n * useRecur Hook\n *\n * Access Recur checkout functionality from within your components\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { checkout, isCheckingOut } = useRecur();\n *\n * return (\n * <button\n * onClick={() => checkout({ planId: 'pro' })}\n * disabled={isCheckingOut}\n * >\n * {isCheckingOut ? 'Processing...' : 'Subscribe'}\n * </button>\n * );\n * }\n * ```\n *\n * @throws {Error} If used outside of RecurProvider\n */\nexport function useRecur(): RecurContextValue {\n const context = useContext(RecurContext);\n\n if (!context) {\n throw new Error('useRecur must be used within a RecurProvider');\n }\n\n return context;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-tw",
3
- "version": "0.0.2",
3
+ "version": "0.0.3-beta.1",
4
4
  "description": "React & Vanilla JS SDK for embedding subscription checkout flows (Taiwan / PAYUNi)",
5
5
  "type": "module",
6
6
  "private": false,
@@ -31,7 +31,8 @@
31
31
  "build": "tsup",
32
32
  "dev": "tsup --watch",
33
33
  "lint": "eslint . --max-warnings 0",
34
- "type-check": "tsc --noEmit"
34
+ "type-check": "tsc --noEmit",
35
+ "examples": "npx http-server examples -p 8080 -o"
35
36
  },
36
37
  "main": "./dist/index.js",
37
38
  "module": "./dist/index.js",
package/dist/recur.umd.js DELETED
@@ -1,145 +0,0 @@
1
- "use strict";var RecurCheckout=(()=>{var d=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var w=(o,e,t)=>e in o?d(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var x=(o,e)=>{for(var t in e)d(o,t,{get:e[t],enumerable:!0})},E=(o,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of g(e))!v.call(o,n)&&n!==t&&d(o,n,{get:()=>e[n],enumerable:!(i=y(e,n))||i.enumerable});return o};var C=o=>E(d({},"__esModule",{value:!0}),o);var r=(o,e,t)=>w(o,typeof e!="symbol"?e+"":e,t);var T={};x(T,{RecurCheckout:()=>l,default:()=>k,init:()=>b});var c=class{constructor(e){r(this,"config");if(!e.publishableKey)throw new Error("publishableKey is required");this.config={baseUrl:typeof window<"u"?window.location.origin:"",...e}}async createSubscription(e){let{planId:t,customerName:i,customerEmail:n,customerPhone:m}=e;if(!t)throw new Error("planId is required");let s=await fetch(`${this.config.baseUrl}/api/v1/subscriptions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({planId:t,customerName:i,customerEmail:n,customerPhone:m})});if(!s.ok){let a=await s.json().catch(()=>({}));throw{code:a.error||"CHECKOUT_FAILED",message:a.message||"Failed to initiate checkout",details:a}}return await s.json()}async fetchPlans(){let e=await fetch(`${this.config.baseUrl}/api/v1/plans`,{method:"GET",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey}});if(!e.ok){let t=await e.json().catch(()=>({}));throw{code:t.error||"FETCH_PLANS_FAILED",message:t.message||"Failed to fetch plans",details:t}}return await e.json()}getConfig(){return{...this.config}}};var u=class{constructor(e){r(this,"overlay",null);r(this,"modal",null);r(this,"iframe",null);r(this,"onClose");r(this,"handleMessage",e=>{e.origin===window.location.origin&&(e.data?.type==="RECUR_PAYMENT_COMPLETE"?this.close():e.data?.type==="RECUR_PAYMENT_CANCEL"&&this.close())});this.onClose=e}open(e){this.overlay=document.createElement("div"),this.overlay.style.cssText=`
2
- position: fixed;
3
- top: 0;
4
- left: 0;
5
- right: 0;
6
- bottom: 0;
7
- background: rgba(0, 0, 0, 0.5);
8
- z-index: 9998;
9
- display: flex;
10
- align-items: center;
11
- justify-content: center;
12
- padding: 20px;
13
- `,this.modal=document.createElement("div"),this.modal.style.cssText=`
14
- position: relative;
15
- background: white;
16
- border-radius: 8px;
17
- width: 100%;
18
- max-width: 600px;
19
- height: 90vh;
20
- max-height: 700px;
21
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
22
- display: flex;
23
- flex-direction: column;
24
- overflow: hidden;
25
- z-index: 9999;
26
- `;let t=document.createElement("button");t.innerHTML="\u2715",t.style.cssText=`
27
- position: absolute;
28
- top: 12px;
29
- right: 12px;
30
- width: 32px;
31
- height: 32px;
32
- border: none;
33
- background: rgba(0, 0, 0, 0.1);
34
- border-radius: 50%;
35
- cursor: pointer;
36
- font-size: 18px;
37
- line-height: 1;
38
- z-index: 10000;
39
- transition: background 0.2s;
40
- color: #333;
41
- `,t.onmouseover=()=>{t.style.background="rgba(0, 0, 0, 0.2)"},t.onmouseout=()=>{t.style.background="rgba(0, 0, 0, 0.1)"},t.onclick=()=>this.close(),this.iframe=document.createElement("iframe"),this.iframe.src=e,this.iframe.style.cssText=`
42
- width: 100%;
43
- height: 100%;
44
- border: none;
45
- border-radius: 8px;
46
- `,this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"),this.modal.appendChild(t),this.modal.appendChild(this.iframe),this.overlay.appendChild(this.modal),document.body.appendChild(this.overlay),document.body.style.overflow="hidden",this.overlay.onclick=i=>{i.target===this.overlay&&this.close()},window.addEventListener("message",this.handleMessage)}close(){this.overlay&&this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay),document.body.style.overflow="",this.overlay=null,this.modal=null,this.iframe=null,window.removeEventListener("message",this.handleMessage),this.onClose&&this.onClose()}};var p=class{constructor(e,t){r(this,"container");r(this,"iframe",null);r(this,"onClose");r(this,"handleMessage",e=>{e.origin===window.location.origin&&(e.data?.type==="RECUR_PAYMENT_COMPLETE"?this.remove():e.data?.type==="RECUR_PAYMENT_CANCEL"&&this.remove())});if(typeof e=="string"){let i=document.querySelector(e);if(!i)throw new Error(`Container element not found: ${e}`);this.container=i}else this.container=e;this.onClose=t}embed(e){this.container.innerHTML="",this.iframe=document.createElement("iframe"),this.iframe.src=e,this.iframe.style.cssText=`
47
- width: 100%;
48
- height: 600px;
49
- border: 1px solid #e5e7eb;
50
- border-radius: 8px;
51
- `,this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"),this.container.appendChild(this.iframe),window.addEventListener("message",this.handleMessage)}remove(){this.iframe&&this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null,window.removeEventListener("message",this.handleMessage),this.onClose&&this.onClose()}};var h=class{constructor(e,t){r(this,"config");r(this,"options");r(this,"container");r(this,"sdkToken",null);r(this,"sdkEnv","S");r(this,"payuniSDK",null);r(this,"isFormValid",!1);if(this.config=e,this.options=t,typeof t.container=="string"){let i=document.querySelector(t.container);if(!i)throw new Error(`Container not found: ${t.container}`);this.container=i}else this.container=t.container}async render(){try{await this.initCheckout(),this.renderHTML(),await this.loadPayUniSDK(),await this.initPayUniSDK(),this.setupFormSubmit()}catch(e){this.handleError(e)}}async initCheckout(){let e=this.config.baseUrl||(typeof window<"u"?window.location.origin:""),t=await fetch(`${e}/api/v1/checkout/init`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({planId:this.options.planId,iframeDomain:window.location.origin})});if(!t.ok){let n=await t.json().catch(()=>({}));throw new Error(n.error||"Failed to initialize checkout")}let i=await t.json();this.sdkToken=i.sdkToken,this.sdkEnv=i.env}renderHTML(){this.container.innerHTML=`
52
- <div class="recur-embedded-checkout" style="max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
53
- <div class="recur-checkout-header" style="margin-bottom: 24px;">
54
- <h2 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;">Subscribe</h2>
55
- <p style="margin: 0; font-size: 14px; color: #666;">Complete your subscription</p>
56
- </div>
57
-
58
- <form id="recur-checkout-form" style="display: flex; flex-direction: column; gap: 16px;">
59
- <div class="recur-field">
60
- <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;">Email</label>
61
- <input
62
- type="email"
63
- id="recur-email"
64
- required
65
- value="${this.options.customerEmail||""}"
66
- style="width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s;"
67
- onfocus="this.style.borderColor='#3b82f6'"
68
- onblur="this.style.borderColor='#d1d5db'"
69
- />
70
- </div>
71
-
72
- <div class="recur-field">
73
- <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;">Name</label>
74
- <input
75
- type="text"
76
- id="recur-name"
77
- required
78
- value="${this.options.customerName||""}"
79
- style="width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s;"
80
- onfocus="this.style.borderColor='#3b82f6'"
81
- onblur="this.style.borderColor='#d1d5db'"
82
- />
83
- </div>
84
-
85
- <div class="recur-field">
86
- <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;">Phone (Optional)</label>
87
- <input
88
- type="tel"
89
- id="recur-phone"
90
- value="${this.options.customerPhone||""}"
91
- style="width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s;"
92
- onfocus="this.style.borderColor='#3b82f6'"
93
- onblur="this.style.borderColor='#d1d5db'"
94
- />
95
- </div>
96
-
97
- <div class="recur-divider" style="height: 1px; background: #e5e7eb; margin: 8px 0;"></div>
98
-
99
- <div class="recur-field">
100
- <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;">Card Number</label>
101
- <div id="recur-card-number" style="padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; min-height: 38px;"></div>
102
- </div>
103
-
104
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
105
- <div class="recur-field">
106
- <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;">Expiry</label>
107
- <div id="recur-card-exp" style="padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; min-height: 38px;"></div>
108
- </div>
109
- <div class="recur-field">
110
- <label style="display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;">CVC</label>
111
- <div id="recur-card-cvc" style="padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; min-height: 38px;"></div>
112
- </div>
113
- </div>
114
-
115
- <div id="recur-error" style="display: none; padding: 12px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 6px; color: #dc2626; font-size: 14px;"></div>
116
-
117
- <button
118
- type="submit"
119
- id="recur-submit-btn"
120
- style="width: 100%; padding: 12px; background: #3b82f6; color: white; border: none; border-radius: 6px; font-size: 16px; font-weight: 500; cursor: pointer; transition: background 0.2s;"
121
- onmouseover="this.style.background='#2563eb'"
122
- onmouseout="this.style.background='#3b82f6'"
123
- disabled
124
- >
125
- Subscribe Now
126
- </button>
127
-
128
- <p style="margin: 12px 0 0 0; text-align: center; font-size: 12px; color: #9ca3af;">
129
- Secure payment powered by PAYUNi
130
- </p>
131
- </form>
132
- </div>
133
- `}async loadPayUniSDK(){return new Promise((e,t)=>{if(window.UniPayment){e();return}let i=document.createElement("script");i.src=this.sdkEnv==="P"?"https://vendor.payuni.com.tw/sdk/uni-payment.js":"https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js",i.async=!0,i.onload=()=>e(),i.onerror=()=>t(new Error("Failed to load PAYUNi SDK")),document.head.appendChild(i)})}async initPayUniSDK(){if(!this.sdkToken)throw new Error("SDK token not initialized");let e=window.UniPayment;if(!e)throw new Error("PAYUNi SDK not loaded");let t={env:this.sdkEnv,useInst:!1,elements:{CardNo:"recur-card-number",CardExp:"recur-card-exp",CardCvc:"recur-card-cvc"},style:{color:"#111827",errorColor:"#dc2626",fontSize:"14px",fontWeight:"400",lineHeight:"24px"}};this.payuniSDK=e.createSession(this.sdkToken,t),await this.payuniSDK.start(),this.payuniSDK.onUpdate(i=>{let n=i?.status;n&&(this.isFormValid=n.CardNo===!0&&n.CardExp===!0&&n.CardCvc===!0,this.updateSubmitButton())})}updateSubmitButton(){let e=document.getElementById("recur-submit-btn");e&&(e.disabled=!this.isFormValid,e.style.opacity=this.isFormValid?"1":"0.5",e.style.cursor=this.isFormValid?"pointer":"not-allowed")}setupFormSubmit(){let e=document.getElementById("recur-checkout-form");e&&e.addEventListener("submit",async t=>{t.preventDefault(),await this.handleSubmit()})}async handleSubmit(){try{this.showLoading(!0),this.hideError();let e=document.getElementById("recur-email").value,t=document.getElementById("recur-name").value,i=document.getElementById("recur-phone").value;if(!e||!t)throw new Error("Please fill in all required fields");if(!this.payuniSDK)throw new Error("Payment system not initialized");let n=await this.payuniSDK.getTradeResult();if(n.Status!=="SUCCESS")throw new Error(n.Message||"Card validation failed");let m=this.config.baseUrl||window.location.origin,s=await fetch(`${m}/api/v1/subscriptions`,{method:"POST",headers:{"Content-Type":"application/json","X-Recur-Publishable-Key":this.config.publishableKey},body:JSON.stringify({planId:this.options.planId,customerEmail:e,customerName:t,customerPhone:i||void 0})});if(!s.ok){let f=await s.json().catch(()=>({}));throw new Error(f.error||"Failed to create subscription")}let a=await s.json();this.options.onSuccess&&this.options.onSuccess(a),this.showSuccess()}catch(e){this.handleError(e)}finally{this.showLoading(!1)}}showLoading(e){let t=document.getElementById("recur-submit-btn");t&&(t.disabled=e,t.textContent=e?"Processing...":"Subscribe Now")}showError(e){let t=document.getElementById("recur-error");t&&(t.textContent=e,t.style.display="block")}hideError(){let e=document.getElementById("recur-error");e&&(e.style.display="none")}showSuccess(){this.container.innerHTML=`
134
- <div style="max-width: 400px; margin: 0 auto; padding: 40px 20px; text-align: center; font-family: system-ui, -apple-system, sans-serif;">
135
- <div style="width: 64px; height: 64px; margin: 0 auto 24px; background: #10b981; border-radius: 50%; display: flex; align-items: center; justify-content: center;">
136
- <svg width="32" height="32" fill="none" stroke="white" stroke-width="3" viewBox="0 0 24 24">
137
- <path d="M5 13l4 4L19 7"/>
138
- </svg>
139
- </div>
140
- <h2 style="margin: 0 0 8px 0; font-size: 24px; font-weight: 600; color: #111;">Subscription Complete!</h2>
141
- <p style="margin: 0; font-size: 16px; color: #666;">Thank you for subscribing. You will receive a confirmation email shortly.</p>
142
- </div>
143
- `}handleError(e){let t=e?.message||"An error occurred";this.showError(t);let i={code:"CHECKOUT_ERROR",message:t};this.options.onError&&this.options.onError(i)}};var l=class{constructor(e){r(this,"core");r(this,"currentModal",null);r(this,"currentIframe",null);this.core=new c(e)}async fetchPlans(){return await this.core.fetchPlans()}async createEmbeddedCheckout(e){let t=this.core.getConfig();await new h(t,e).render()}async checkout(e){try{let t=await this.core.createSubscription(e);switch(e.onSuccess&&e.onSuccess(t),e.mode||"redirect"){case"modal":this.openModal(t.paymentUrl,e.onClose);break;case"iframe":this.embedIframe(t.paymentUrl,e.container,e.onClose);break;case"redirect":default:window.location.href=t.paymentUrl;break}}catch(t){if(e.onError)e.onError(t);else throw console.error("Recur checkout error:",t),t}}openModal(e,t){this.closeModal(),this.currentModal=new u(()=>{this.currentModal=null,t&&t()}),this.currentModal.open(e)}embedIframe(e,t,i){if(!t)throw new Error("Container is required for iframe mode");this.removeIframe(),this.currentIframe=new p(t,()=>{this.currentIframe=null,i&&i()}),this.currentIframe.embed(e)}closeModal(){this.currentModal&&(this.currentModal.close(),this.currentModal=null)}removeIframe(){this.currentIframe&&(this.currentIframe.remove(),this.currentIframe=null)}close(){this.closeModal(),this.removeIframe()}};function b(o){return new l(o)}var k={init:b,RecurCheckout:l};return C(T);})();
144
- if (typeof window !== "undefined") { window.RecurCheckout = RecurCheckout.default; }
145
- //# sourceMappingURL=recur.umd.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/vanilla/index.ts","../src/vanilla/core.ts","../src/vanilla/modal.ts","../src/vanilla/iframe.ts","../src/vanilla/embedded-checkout.ts"],"sourcesContent":["/**\n * Recur Vanilla SDK\n *\n * Standalone JavaScript SDK for embedding subscription checkout\n * No dependencies, works with plain HTML/JavaScript\n */\n\nimport { RecurCore } from './core.js';\nimport { RecurModal } from './modal.js';\nimport { RecurIframe } from './iframe.js';\nimport { EmbeddedCheckout } from './embedded-checkout.js';\nimport type { VanillaRecurConfig, VanillaCheckoutOptions } from './types.js';\nimport type { EmbeddedCheckoutOptions } from './embedded-checkout.js';\n\nexport class RecurCheckout {\n private core: RecurCore;\n private currentModal: RecurModal | null = null;\n private currentIframe: RecurIframe | null = null;\n\n constructor(config: VanillaRecurConfig) {\n this.core = new RecurCore(config);\n }\n\n /**\n * Fetch available subscription plans\n */\n async fetchPlans() {\n return await this.core.fetchPlans();\n }\n\n /**\n * Create embedded checkout form with credit card fields\n * Renders a complete checkout UI in the specified container\n */\n async createEmbeddedCheckout(options: EmbeddedCheckoutOptions): Promise<void> {\n const config = this.core.getConfig();\n const embeddedCheckout = new EmbeddedCheckout(config, options);\n await embeddedCheckout.render();\n }\n\n /**\n * Initiate checkout flow\n */\n async checkout(options: VanillaCheckoutOptions): Promise<void> {\n try {\n // Create subscription\n const result = await this.core.createSubscription(options);\n\n // Call success callback\n if (options.onSuccess) {\n options.onSuccess(result);\n }\n\n // Handle payment URL based on mode\n const mode = options.mode || 'redirect';\n\n switch (mode) {\n case 'modal':\n this.openModal(result.paymentUrl, options.onClose);\n break;\n\n case 'iframe':\n this.embedIframe(result.paymentUrl, options.container, options.onClose);\n break;\n\n case 'redirect':\n default:\n window.location.href = result.paymentUrl;\n break;\n }\n } catch (error) {\n // Call error callback\n if (options.onError) {\n options.onError(error as any);\n } else {\n // Default error handling\n console.error('Recur checkout error:', error);\n throw error;\n }\n }\n }\n\n /**\n * Open payment in modal\n */\n private openModal(paymentUrl: string, onClose?: () => void): void {\n // Close existing modal if any\n this.closeModal();\n\n this.currentModal = new RecurModal(() => {\n this.currentModal = null;\n if (onClose) {\n onClose();\n }\n });\n\n this.currentModal.open(paymentUrl);\n }\n\n /**\n * Embed payment in iframe\n */\n private embedIframe(\n paymentUrl: string,\n container?: string | HTMLElement,\n onClose?: () => void\n ): void {\n if (!container) {\n throw new Error('Container is required for iframe mode');\n }\n\n // Remove existing iframe if any\n this.removeIframe();\n\n this.currentIframe = new RecurIframe(container, () => {\n this.currentIframe = null;\n if (onClose) {\n onClose();\n }\n });\n\n this.currentIframe.embed(paymentUrl);\n }\n\n /**\n * Close modal manually\n */\n closeModal(): void {\n if (this.currentModal) {\n this.currentModal.close();\n this.currentModal = null;\n }\n }\n\n /**\n * Remove iframe manually\n */\n removeIframe(): void {\n if (this.currentIframe) {\n this.currentIframe.remove();\n this.currentIframe = null;\n }\n }\n\n /**\n * Close any active checkout UI (modal or iframe)\n */\n close(): void {\n this.closeModal();\n this.removeIframe();\n }\n}\n\n// Global API for browser usage\nexport function init(config: VanillaRecurConfig): RecurCheckout {\n return new RecurCheckout(config);\n}\n\n// Default export\nexport default {\n init,\n RecurCheckout,\n};\n\n// Expose types for TypeScript users\nexport type * from './types.js';\n","/**\n * Vanilla SDK Core\n *\n * Core API logic for subscription checkout\n */\n\nimport type { VanillaRecurConfig, VanillaCheckoutOptions, CheckoutResult, CheckoutError, PlansResult } from './types.js';\n\nexport class RecurCore {\n private config: VanillaRecurConfig;\n\n constructor(config: VanillaRecurConfig) {\n if (!config.publishableKey) {\n throw new Error('publishableKey is required');\n }\n\n this.config = {\n baseUrl: typeof window !== 'undefined' ? window.location.origin : '',\n ...config,\n };\n }\n\n /**\n * Call the subscription API\n */\n async createSubscription(options: VanillaCheckoutOptions): Promise<CheckoutResult> {\n const { planId, customerName, customerEmail, customerPhone } = options;\n\n if (!planId) {\n throw new Error('planId is required');\n }\n\n const response = await fetch(`${this.config.baseUrl}/api/v1/subscriptions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': this.config.publishableKey,\n },\n body: JSON.stringify({\n planId,\n customerName,\n customerEmail,\n customerPhone,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n const error: CheckoutError = {\n code: errorData.error || 'CHECKOUT_FAILED',\n message: errorData.message || 'Failed to initiate checkout',\n details: errorData,\n };\n throw error;\n }\n\n return await response.json();\n }\n\n /**\n * Fetch available subscription plans\n */\n async fetchPlans(): Promise<PlansResult> {\n const response = await fetch(`${this.config.baseUrl}/api/v1/plans`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': this.config.publishableKey,\n },\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n const error: CheckoutError = {\n code: errorData.error || 'FETCH_PLANS_FAILED',\n message: errorData.message || 'Failed to fetch plans',\n details: errorData,\n };\n throw error;\n }\n\n return await response.json();\n }\n\n getConfig(): VanillaRecurConfig {\n return { ...this.config };\n }\n}\n","/**\n * Vanilla SDK Modal\n *\n * Modal window for payment flow\n */\n\nexport class RecurModal {\n private overlay: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private onClose?: () => void;\n\n constructor(onClose?: () => void) {\n this.onClose = onClose;\n }\n\n /**\n * Open modal with payment URL\n */\n open(paymentUrl: string): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px;\n `;\n\n // Create modal container\n this.modal = document.createElement('div');\n this.modal.style.cssText = `\n position: relative;\n background: white;\n border-radius: 8px;\n width: 100%;\n max-width: 600px;\n height: 90vh;\n max-height: 700px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 9999;\n `;\n\n // Create close button\n const closeButton = document.createElement('button');\n closeButton.innerHTML = '✕';\n closeButton.style.cssText = `\n position: absolute;\n top: 12px;\n right: 12px;\n width: 32px;\n height: 32px;\n border: none;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n cursor: pointer;\n font-size: 18px;\n line-height: 1;\n z-index: 10000;\n transition: background 0.2s;\n color: #333;\n `;\n closeButton.onmouseover = () => {\n closeButton.style.background = 'rgba(0, 0, 0, 0.2)';\n };\n closeButton.onmouseout = () => {\n closeButton.style.background = 'rgba(0, 0, 0, 0.1)';\n };\n closeButton.onclick = () => this.close();\n\n // Create iframe\n this.iframe = document.createElement('iframe');\n this.iframe.src = paymentUrl;\n this.iframe.style.cssText = `\n width: 100%;\n height: 100%;\n border: none;\n border-radius: 8px;\n `;\n\n // Allow payment provider features\n this.iframe.setAttribute('allow', 'payment');\n this.iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation');\n\n // Assemble\n this.modal.appendChild(closeButton);\n this.modal.appendChild(this.iframe);\n this.overlay.appendChild(this.modal);\n document.body.appendChild(this.overlay);\n\n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n\n // Close on overlay click\n this.overlay.onclick = (e) => {\n if (e.target === this.overlay) {\n this.close();\n }\n };\n\n // Listen for payment completion (via postMessage)\n window.addEventListener('message', this.handleMessage);\n }\n\n /**\n * Close modal\n */\n close(): void {\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n }\n\n // Restore body scroll\n document.body.style.overflow = '';\n\n // Clean up\n this.overlay = null;\n this.modal = null;\n this.iframe = null;\n\n // Remove message listener\n window.removeEventListener('message', this.handleMessage);\n\n // Call onClose callback\n if (this.onClose) {\n this.onClose();\n }\n }\n\n /**\n * Handle postMessage from iframe\n */\n private handleMessage = (event: MessageEvent): void => {\n // Only accept messages from same origin\n if (event.origin !== window.location.origin) {\n return;\n }\n\n // Check for payment completion signals\n if (event.data?.type === 'RECUR_PAYMENT_COMPLETE') {\n this.close();\n } else if (event.data?.type === 'RECUR_PAYMENT_CANCEL') {\n this.close();\n }\n };\n}\n","/**\n * Vanilla SDK iframe Embedding\n *\n * Embed payment flow in an iframe\n */\n\nexport class RecurIframe {\n private container: HTMLElement;\n private iframe: HTMLIFrameElement | null = null;\n private onClose?: () => void;\n\n constructor(container: string | HTMLElement, onClose?: () => void) {\n if (typeof container === 'string') {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n this.container = element;\n } else {\n this.container = container;\n }\n\n this.onClose = onClose;\n }\n\n /**\n * Embed iframe with payment URL\n */\n embed(paymentUrl: string): void {\n // Clear existing content\n this.container.innerHTML = '';\n\n // Create iframe\n this.iframe = document.createElement('iframe');\n this.iframe.src = paymentUrl;\n this.iframe.style.cssText = `\n width: 100%;\n height: 600px;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n `;\n\n // Allow payment provider features\n this.iframe.setAttribute('allow', 'payment');\n this.iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation');\n\n // Append to container\n this.container.appendChild(this.iframe);\n\n // Listen for payment completion\n window.addEventListener('message', this.handleMessage);\n }\n\n /**\n * Remove iframe\n */\n remove(): void {\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n }\n\n this.iframe = null;\n\n // Remove message listener\n window.removeEventListener('message', this.handleMessage);\n\n // Call onClose callback\n if (this.onClose) {\n this.onClose();\n }\n }\n\n /**\n * Handle postMessage from iframe\n */\n private handleMessage = (event: MessageEvent): void => {\n // Only accept messages from same origin\n if (event.origin !== window.location.origin) {\n return;\n }\n\n // Check for payment completion signals\n if (event.data?.type === 'RECUR_PAYMENT_COMPLETE') {\n this.remove();\n } else if (event.data?.type === 'RECUR_PAYMENT_CANCEL') {\n this.remove();\n }\n };\n}\n","/**\n * Embedded Checkout\n *\n * Renders a complete checkout form with embedded credit card fields\n * Powered by PAYUNi SDK for secure card input\n */\n\nimport type { VanillaRecurConfig, CheckoutError, CheckoutResult } from './types.js';\n\nexport interface EmbeddedCheckoutOptions {\n planId: string;\n container: string | HTMLElement;\n customerEmail?: string;\n customerName?: string;\n customerPhone?: string;\n onSuccess?: (result: CheckoutResult) => void;\n onError?: (error: CheckoutError) => void;\n}\n\ninterface InitCheckoutResponse {\n sdkToken: string;\n env: 'S' | 'P';\n timestamp: number;\n plan?: {\n id: string;\n name: string;\n price: number;\n billingPeriod: string;\n description?: string;\n trialDays?: number;\n };\n}\n\nexport class EmbeddedCheckout {\n private config: VanillaRecurConfig;\n private options: EmbeddedCheckoutOptions;\n private container: HTMLElement;\n private sdkToken: string | null = null;\n private sdkEnv: 'S' | 'P' = 'S';\n private payuniSDK: any = null;\n private isFormValid: boolean = false;\n\n constructor(config: VanillaRecurConfig, options: EmbeddedCheckoutOptions) {\n this.config = config;\n this.options = options;\n\n // Resolve container\n if (typeof options.container === 'string') {\n const element = document.querySelector(options.container);\n if (!element) {\n throw new Error(`Container not found: ${options.container}`);\n }\n this.container = element as HTMLElement;\n } else {\n this.container = options.container;\n }\n }\n\n /**\n * Initialize and render the checkout form\n */\n async render(): Promise<void> {\n try {\n // 1. Fetch SDK token and plan info\n await this.initCheckout();\n\n // 2. Render HTML structure\n this.renderHTML();\n\n // 3. Load PAYUNi SDK script\n await this.loadPayUniSDK();\n\n // 4. Initialize PAYUNi SDK with card fields\n await this.initPayUniSDK();\n\n // 5. Setup form submission\n this.setupFormSubmit();\n } catch (error: any) {\n this.handleError(error);\n }\n }\n\n /**\n * Initialize checkout session\n */\n private async initCheckout(): Promise<void> {\n const baseUrl = this.config.baseUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n\n const response = await fetch(`${baseUrl}/api/v1/checkout/init`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': this.config.publishableKey,\n },\n body: JSON.stringify({\n planId: this.options.planId,\n iframeDomain: window.location.origin,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error || 'Failed to initialize checkout');\n }\n\n const data: InitCheckoutResponse = await response.json();\n this.sdkToken = data.sdkToken;\n this.sdkEnv = data.env;\n }\n\n /**\n * Render checkout form HTML\n */\n private renderHTML(): void {\n this.container.innerHTML = `\n <div class=\"recur-embedded-checkout\" style=\"max-width: 400px; margin: 0 auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;\">\n <div class=\"recur-checkout-header\" style=\"margin-bottom: 24px;\">\n <h2 style=\"margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #111;\">Subscribe</h2>\n <p style=\"margin: 0; font-size: 14px; color: #666;\">Complete your subscription</p>\n </div>\n\n <form id=\"recur-checkout-form\" style=\"display: flex; flex-direction: column; gap: 16px;\">\n <div class=\"recur-field\">\n <label style=\"display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;\">Email</label>\n <input\n type=\"email\"\n id=\"recur-email\"\n required\n value=\"${this.options.customerEmail || ''}\"\n style=\"width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s;\"\n onfocus=\"this.style.borderColor='#3b82f6'\"\n onblur=\"this.style.borderColor='#d1d5db'\"\n />\n </div>\n\n <div class=\"recur-field\">\n <label style=\"display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;\">Name</label>\n <input\n type=\"text\"\n id=\"recur-name\"\n required\n value=\"${this.options.customerName || ''}\"\n style=\"width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s;\"\n onfocus=\"this.style.borderColor='#3b82f6'\"\n onblur=\"this.style.borderColor='#d1d5db'\"\n />\n </div>\n\n <div class=\"recur-field\">\n <label style=\"display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;\">Phone (Optional)</label>\n <input\n type=\"tel\"\n id=\"recur-phone\"\n value=\"${this.options.customerPhone || ''}\"\n style=\"width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s;\"\n onfocus=\"this.style.borderColor='#3b82f6'\"\n onblur=\"this.style.borderColor='#d1d5db'\"\n />\n </div>\n\n <div class=\"recur-divider\" style=\"height: 1px; background: #e5e7eb; margin: 8px 0;\"></div>\n\n <div class=\"recur-field\">\n <label style=\"display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;\">Card Number</label>\n <div id=\"recur-card-number\" style=\"padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; min-height: 38px;\"></div>\n </div>\n\n <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 12px;\">\n <div class=\"recur-field\">\n <label style=\"display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;\">Expiry</label>\n <div id=\"recur-card-exp\" style=\"padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; min-height: 38px;\"></div>\n </div>\n <div class=\"recur-field\">\n <label style=\"display: block; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #374151;\">CVC</label>\n <div id=\"recur-card-cvc\" style=\"padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; min-height: 38px;\"></div>\n </div>\n </div>\n\n <div id=\"recur-error\" style=\"display: none; padding: 12px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 6px; color: #dc2626; font-size: 14px;\"></div>\n\n <button\n type=\"submit\"\n id=\"recur-submit-btn\"\n style=\"width: 100%; padding: 12px; background: #3b82f6; color: white; border: none; border-radius: 6px; font-size: 16px; font-weight: 500; cursor: pointer; transition: background 0.2s;\"\n onmouseover=\"this.style.background='#2563eb'\"\n onmouseout=\"this.style.background='#3b82f6'\"\n disabled\n >\n Subscribe Now\n </button>\n\n <p style=\"margin: 12px 0 0 0; text-align: center; font-size: 12px; color: #9ca3af;\">\n Secure payment powered by PAYUNi\n </p>\n </form>\n </div>\n `;\n }\n\n /**\n * Load PAYUNi SDK script dynamically\n */\n private async loadPayUniSDK(): Promise<void> {\n return new Promise((resolve, reject) => {\n // Check if already loaded\n if ((window as any).UniPayment) {\n resolve();\n return;\n }\n\n const script = document.createElement('script');\n script.src = this.sdkEnv === 'P'\n ? 'https://vendor.payuni.com.tw/sdk/uni-payment.js'\n : 'https://sandbox-vendor.payuni.com.tw/sdk/uni-payment.js';\n script.async = true;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error('Failed to load PAYUNi SDK'));\n document.head.appendChild(script);\n });\n }\n\n /**\n * Initialize PAYUNi SDK with credit card fields\n */\n private async initPayUniSDK(): Promise<void> {\n if (!this.sdkToken) {\n throw new Error('SDK token not initialized');\n }\n\n const UniPayment = (window as any).UniPayment;\n if (!UniPayment) {\n throw new Error('PAYUNi SDK not loaded');\n }\n\n const options = {\n env: this.sdkEnv,\n useInst: false,\n elements: {\n CardNo: 'recur-card-number',\n CardExp: 'recur-card-exp',\n CardCvc: 'recur-card-cvc',\n },\n style: {\n color: '#111827',\n errorColor: '#dc2626',\n fontSize: '14px',\n fontWeight: '400',\n lineHeight: '24px',\n },\n };\n\n this.payuniSDK = UniPayment.createSession(this.sdkToken, options);\n await this.payuniSDK.start();\n\n // Listen for card validation updates\n this.payuniSDK.onUpdate((update: any) => {\n const status = update?.status;\n if (status) {\n this.isFormValid = status.CardNo === true && status.CardExp === true && status.CardCvc === true;\n this.updateSubmitButton();\n }\n });\n }\n\n /**\n * Update submit button state\n */\n private updateSubmitButton(): void {\n const submitBtn = document.getElementById('recur-submit-btn') as HTMLButtonElement;\n if (submitBtn) {\n submitBtn.disabled = !this.isFormValid;\n submitBtn.style.opacity = this.isFormValid ? '1' : '0.5';\n submitBtn.style.cursor = this.isFormValid ? 'pointer' : 'not-allowed';\n }\n }\n\n /**\n * Setup form submission handler\n */\n private setupFormSubmit(): void {\n const form = document.getElementById('recur-checkout-form') as HTMLFormElement;\n if (!form) return;\n\n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n await this.handleSubmit();\n });\n }\n\n /**\n * Handle form submission\n */\n private async handleSubmit(): Promise<void> {\n try {\n this.showLoading(true);\n this.hideError();\n\n // Get form data\n const email = (document.getElementById('recur-email') as HTMLInputElement).value;\n const name = (document.getElementById('recur-name') as HTMLInputElement).value;\n const phone = (document.getElementById('recur-phone') as HTMLInputElement).value;\n\n // Validate\n if (!email || !name) {\n throw new Error('Please fill in all required fields');\n }\n\n // Bind card data to SDK token\n if (!this.payuniSDK) {\n throw new Error('Payment system not initialized');\n }\n\n const cardResult = await this.payuniSDK.getTradeResult();\n if (cardResult.Status !== 'SUCCESS') {\n throw new Error(cardResult.Message || 'Card validation failed');\n }\n\n // Create subscription\n const baseUrl = this.config.baseUrl || window.location.origin;\n const response = await fetch(`${baseUrl}/api/v1/subscriptions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Recur-Publishable-Key': this.config.publishableKey,\n },\n body: JSON.stringify({\n planId: this.options.planId,\n customerEmail: email,\n customerName: name,\n customerPhone: phone || undefined,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error || 'Failed to create subscription');\n }\n\n const result: CheckoutResult = await response.json();\n\n // Call success callback\n if (this.options.onSuccess) {\n this.options.onSuccess(result);\n }\n\n // Show success message\n this.showSuccess();\n } catch (error: any) {\n this.handleError(error);\n } finally {\n this.showLoading(false);\n }\n }\n\n /**\n * Show loading state\n */\n private showLoading(loading: boolean): void {\n const submitBtn = document.getElementById('recur-submit-btn') as HTMLButtonElement;\n if (submitBtn) {\n submitBtn.disabled = loading;\n submitBtn.textContent = loading ? 'Processing...' : 'Subscribe Now';\n }\n }\n\n /**\n * Show error message\n */\n private showError(message: string): void {\n const errorDiv = document.getElementById('recur-error');\n if (errorDiv) {\n errorDiv.textContent = message;\n errorDiv.style.display = 'block';\n }\n }\n\n /**\n * Hide error message\n */\n private hideError(): void {\n const errorDiv = document.getElementById('recur-error');\n if (errorDiv) {\n errorDiv.style.display = 'none';\n }\n }\n\n /**\n * Show success message\n */\n private showSuccess(): void {\n this.container.innerHTML = `\n <div style=\"max-width: 400px; margin: 0 auto; padding: 40px 20px; text-align: center; font-family: system-ui, -apple-system, sans-serif;\">\n <div style=\"width: 64px; height: 64px; margin: 0 auto 24px; background: #10b981; border-radius: 50%; display: flex; align-items: center; justify-content: center;\">\n <svg width=\"32\" height=\"32\" fill=\"none\" stroke=\"white\" stroke-width=\"3\" viewBox=\"0 0 24 24\">\n <path d=\"M5 13l4 4L19 7\"/>\n </svg>\n </div>\n <h2 style=\"margin: 0 0 8px 0; font-size: 24px; font-weight: 600; color: #111;\">Subscription Complete!</h2>\n <p style=\"margin: 0; font-size: 16px; color: #666;\">Thank you for subscribing. You will receive a confirmation email shortly.</p>\n </div>\n `;\n }\n\n /**\n * Handle errors\n */\n private handleError(error: any): void {\n const message = error?.message || 'An error occurred';\n this.showError(message);\n\n const checkoutError: CheckoutError = {\n code: 'CHECKOUT_ERROR',\n message,\n };\n\n if (this.options.onError) {\n this.options.onError(checkoutError);\n }\n }\n}\n"],"mappings":"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","names":["vanilla_exports","__export","RecurCheckout","vanilla_default","init","RecurCore","config","__publicField","options","planId","customerName","customerEmail","customerPhone","response","errorData","RecurModal","onClose","__publicField","event","paymentUrl","closeButton","e","RecurIframe","container","onClose","__publicField","event","element","paymentUrl","EmbeddedCheckout","config","options","__publicField","element","error","baseUrl","response","data","resolve","reject","script","UniPayment","update","status","submitBtn","form","e","email","name","phone","cardResult","result","loading","message","errorDiv","checkoutError","RecurCheckout","config","__publicField","RecurCore","options","EmbeddedCheckout","result","error","paymentUrl","onClose","RecurModal","container","RecurIframe","init","vanilla_default"]}