@payment-kit-js/vanilla 0.5.17 → 0.5.18
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/{bnpl-shared-DGs1YzS9.mjs → bnpl-shared-CL900HFN.mjs} +2 -2
- package/dist/{bnpl-shared-DGs1YzS9.mjs.map → bnpl-shared-CL900HFN.mjs.map} +1 -1
- package/dist/{bnpl-shared-BQwCBD45.d.mts → bnpl-shared-D-Kd58Qz.d.mts} +2 -2
- package/dist/{bnpl-shared-BQwCBD45.d.mts.map → bnpl-shared-D-Kd58Qz.d.mts.map} +1 -1
- package/dist/cdn/paymentkit.js +186 -51
- package/dist/cdn/paymentkit.js.map +3 -3
- package/dist/cdn/paymentkit.min.js +24 -24
- package/dist/cdn/paymentkit.min.js.map +3 -3
- package/dist/connect-card-CZhzK_Tp.d.mts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +11 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{next-action-handlers-CLOt1wzO.mjs → next-action-handlers-BZ5gynXe.mjs} +18 -18
- package/dist/next-action-handlers-BZ5gynXe.mjs.map +1 -0
- package/dist/payment-methods/affirm.d.mts +2 -2
- package/dist/payment-methods/affirm.mjs +2 -2
- package/dist/payment-methods/afterpay.d.mts +2 -2
- package/dist/payment-methods/afterpay.mjs +2 -2
- package/dist/payment-methods/apple-pay.d.mts +2 -2
- package/dist/payment-methods/apple-pay.d.mts.map +1 -1
- package/dist/payment-methods/apple-pay.mjs +2 -2
- package/dist/payment-methods/apple-pay.mjs.map +1 -1
- package/dist/payment-methods/bnpl-shared.d.mts +2 -2
- package/dist/payment-methods/bnpl-shared.mjs +2 -2
- package/dist/payment-methods/card.d.mts +1 -1
- package/dist/payment-methods/card.d.mts.map +1 -1
- package/dist/payment-methods/card.mjs +8 -4
- package/dist/payment-methods/card.mjs.map +1 -1
- package/dist/payment-methods/google-pay.d.mts +25 -3
- package/dist/payment-methods/google-pay.d.mts.map +1 -1
- package/dist/payment-methods/google-pay.mjs +131 -10
- package/dist/payment-methods/google-pay.mjs.map +1 -1
- package/dist/payment-methods/klarna.d.mts +2 -2
- package/dist/payment-methods/klarna.mjs +2 -2
- package/dist/payment-methods/next-action-handlers.mjs +1 -1
- package/dist/payment-methods/paypal.d.mts +1 -1
- package/dist/payment-methods/paypal.mjs +1 -1
- package/dist/{types-B3mjYfOm.d.mts → types-Cjcc3xak.d.mts} +6 -9
- package/dist/types-Cjcc3xak.d.mts.map +1 -0
- package/dist/{utils-Dc6zwOe1.mjs → utils-DIqrx4XF.mjs} +10 -7
- package/dist/utils-DIqrx4XF.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/next-action-handlers-CLOt1wzO.mjs.map +0 -1
- package/dist/types-B3mjYfOm.d.mts.map +0 -1
- package/dist/utils-Dc6zwOe1.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-pay.mjs","names":["preparedStripeState: PreparedStripeApplePayState | null","preparedAirwallexState: PreparedAirwallexState | null","applePayScriptLoadPromise: Promise<void> | null","airwallexMockScenario: AirwallexApplePayMockScenario","config: AirwallexApplePayConfig","submitPayment: TInternalFuncs[\"submitPayment\"]","paymentResult","confirmResult","paymentMethodId","billingDetails","autoPrepareConfig: AutoPrepareConfig | null","onApplePayReadyCallbacks: ((isReady: boolean) => void)[]","pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: string } | null","pendingPrepareResolvers: (() => void)[]"],"sources":["../../src/payment-methods/apple-pay.ts"],"sourcesContent":["import type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\nimport {\n AirwallexApplePayAdapter,\n type AirwallexApplePayConfig,\n AirwallexApplePayMockScenario,\n type ApplePayEncryptedToken,\n} from \"./airwallex-apple-pay-adapter\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { ApplePayMockScenario, StripeApplePayAdapter } from \"./stripe-apple-pay-adapter\";\n\n// Apple Pay-specific types\nexport type ApplePayCustomerInfo = {\n first_name: string;\n last_name: string;\n email?: string;\n};\n\nexport type ApplePayStartRequest = {\n processor_id: string;\n // Airwallex-only fields. Stripe /apple-pay/start is a pure read and\n // ignores these — customer_info/fraud_metadata are sent to /apple-pay/confirm\n // instead, where the customer + checkout attempt + PaymentIntent are created.\n customer_info?: ApplePayCustomerInfo;\n fraud_metadata?: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n mock_scenario?: string;\n // Airwallex-specific fields (sent on /start for merchant validation)\n validation_url?: string;\n initiative_context?: string;\n};\n\nexport type ApplePayStartResponse = {\n amount: number;\n currency: string;\n country: string;\n\n // Stripe-specific (when calling /apple-pay/start)\n stripe_pk?: string;\n\n // Airwallex-specific (when calling /airwallex/apple-pay/start). Stripe's\n // /start does not create a checkout attempt — it's deferred to /confirm.\n checkout_attempt_id?: string;\n merchant_session?: { [key: string]: unknown }; // Apple merchant session for completeMerchantValidation()\n};\n\n// Airwallex 3DS next action type (matches backend snake_case response)\nexport type Airwallex3dsNextAction = {\n type: \"airwallex_3ds\";\n url: string;\n};\n\nexport type ApplePayConfirmRequest = {\n // Stripe-only: moved from /start (where they used to drive customer/PI\n // creation). At confirm time, the Stripe path creates the customer, checkout\n // attempt, and PaymentIntent in a single call.\n processor_id?: string;\n customer_info?: ApplePayCustomerInfo;\n fraud_metadata?: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n // Stripe: Send PaymentMethod ID\n payment_method_id?: string;\n // Airwallex: Send encrypted Apple Pay token\n apple_pay_token?: ApplePayEncryptedToken | { [key: string]: unknown };\n // Email from payment sheet (Stripe Apple Pay) — used to fill missing customer email\n payer_email?: string;\n // Name from payment sheet — used to fill missing customer name\n payer_first_name?: string;\n payer_last_name?: string;\n mock_scenario?: string;\n};\n\nexport type ApplePayConfirmResponse = {\n charge_status: \"success\" | \"fail\" | \"pending\";\n transaction_id?: string;\n error_code?: string;\n error_message_for_customer?: string;\n error_message_for_debug?: string;\n checkout_attempt_id: string;\n checkout_session_id?: string;\n next_action?: Airwallex3dsNextAction; // Present when charge_status=\"pending\" for 3DS\n payment_intent_id?: string;\n customer_id?: string;\n payment_method_id?: string;\n processor_used?: string;\n subscription_id?: string;\n invoice_id?: string;\n invoice_number?: number;\n card_brand?: string;\n card_last4?: string;\n card_exp_month?: number;\n card_exp_year?: number;\n};\n\nexport type ApplePaySubmitOptions = {\n /** Processor external ID — optional when using auto-prepare (SDK fetches from checkout session) */\n processorId?: string;\n processorType?: \"stripe\" | \"airwallex\";\n customerInfo: ApplePayCustomerInfo;\n mockScenario?: ApplePayMockScenario;\n amount?: number; // Amount in atomic units (cents) for Apple Pay sheet display\n currency?: string; // Currency code (e.g., \"usd\")\n /** Country code — optional when using auto-prepare (fetched from backend) */\n country?: string;\n merchantName?: string; // Merchant display name on Apple Pay sheet\n};\n\ntype ApplePayResult =\n | { data: { [key: string]: unknown }; errors?: undefined }\n | { data?: undefined; errors: PaymentKitErrors };\n\n// =============================================================================\n// Prepared Payment State (for Stripe pre-fetching before click)\n// =============================================================================\n\ntype PreparedStripeApplePayState = {\n processor: \"stripe\";\n adapter: StripeApplePayAdapter;\n startData: ApplePayStartResponse;\n mockScenarioStr?: string;\n checkoutRequestId: string;\n};\n\n// Global state to store prepared Apple Pay data (Stripe only - Airwallex uses native session)\nlet preparedStripeState: PreparedStripeApplePayState | null = null;\n\n// Prepared Airwallex state — persists options from prepare call for use at submit time\n// The amount field is fetched from the session via /session-info endpoint to fix\n// the $0.00 bug where options.amount was undefined and defaulted to 0.\ntype PreparedAirwallexState = {\n country: string;\n currency?: string;\n amount?: number;\n merchantName?: string;\n};\nlet preparedAirwallexState: PreparedAirwallexState | null = null;\n\n// Response type for Airwallex Apple Pay session-info endpoint\ntype AirwallexSessionInfoResponse = {\n amount: number;\n currency: string;\n country: string;\n};\n\n// =============================================================================\n// Auto-Prepare State\n// =============================================================================\n\ntype AutoPrepareConfig = {\n processorId: string;\n processorType: \"airwallex\" | \"stripe\" | undefined;\n};\n\ntype CheckoutSessionConfig = {\n express_checkout_processor_id?: string | null;\n express_checkout_processor_type?: string | null;\n};\n\n// =============================================================================\n// Apple Pay SDK Loader\n// =============================================================================\n\n// Loads Apple's JS SDK, which makes window.ApplePaySession available in non-Safari\n// browsers (Chrome, Firefox, etc.) and enables the \"Scan Code with iPhone\" QR flow.\nlet applePayScriptLoadPromise: Promise<void> | null = null;\nasync function loadApplePayScript(): Promise<void> {\n if (typeof window === \"undefined\") return;\n if (window.ApplePaySession) return;\n if (document.getElementById(\"__pk_apple_pay_sdk\")) {\n // Tag exists — if we have a cached promise, wait for it; otherwise the tag\n // already resolved (e.g. after a module reload) so return immediately.\n return applePayScriptLoadPromise ?? Promise.resolve();\n }\n applePayScriptLoadPromise = new Promise<void>((resolve, reject) => {\n const script = document.createElement(\"script\");\n script.id = \"__pk_apple_pay_sdk\";\n script.src = \"https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js\";\n script.crossOrigin = \"anonymous\";\n // NOTE: Apple doesn't publish stable SRI hashes for the 1.latest pointer,\n // so integrity checking is omitted. CSP must allow script-src https://applepay.cdn-apple.com.\n script.onload = () => resolve();\n script.onerror = () => {\n // Clear cached state so the next prepareApplePay call can retry.\n applePayScriptLoadPromise = null;\n document.getElementById(\"__pk_apple_pay_sdk\")?.remove();\n reject(new Error(\"Failed to load Apple Pay SDK\"));\n };\n document.head.appendChild(script);\n });\n return applePayScriptLoadPromise;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\nasync function apiCall<T>(\n url: string,\n options: RequestInit,\n checkoutRequestId?: string,\n): Promise<{ data?: T; error?: string }> {\n const headers = new Headers(options.headers);\n if (checkoutRequestId) {\n headers.set(\"x-request-id\", checkoutRequestId);\n }\n\n const response = await fetch(url, { ...options, headers });\n if (!response.ok) {\n let errorMessage = `Request failed (${response.status})`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.detail || errorMessage;\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n return { error: errorMessage };\n }\n return { data: await response.json() };\n}\n\nfunction validateOptions(options: ApplePaySubmitOptions): PaymentKitErrors | null {\n if (!options?.processorId) {\n return { processor_id: \"Processor ID is required\" };\n }\n // For Airwallex, country is required (either directly or from prepared state)\n if (options.processorType === \"airwallex\" && !options.country && !preparedAirwallexState?.country) {\n return { country: \"Country is required for Airwallex Apple Pay\" };\n }\n return null;\n}\n\nfunction getMockScenarioStr(mockScenario?: ApplePayMockScenario): string | undefined {\n return mockScenario && mockScenario !== ApplePayMockScenario.None ? mockScenario : undefined;\n}\n\n// =============================================================================\n// Stripe Apple Pay Flow\n// =============================================================================\n\nasync function callStripeStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n checkoutRequestId?: string,\n): Promise<{ data?: ApplePayStartResponse; error?: string }> {\n // /apple-pay/start is now a pure read: it returns stripe_pk + sheet data\n // (amount/currency/country). Customer/CheckoutAttempt/PaymentIntent are\n // created in /apple-pay/confirm once the user authorizes the sheet.\n return apiCall<ApplePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/apple-pay/start`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n } as ApplePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\nfunction initializeStripeAdapter(\n stripePk: string,\n mockScenario?: ApplePayMockScenario,\n): { adapter?: StripeApplePayAdapter; error?: string } {\n const adapter = new StripeApplePayAdapter(mockScenario);\n\n if (!adapter.initialize(stripePk)) {\n return { error: 'Stripe.js not loaded. Add <script src=\"https://js.stripe.com/v3/\"></script> to your page.' };\n }\n\n return { adapter };\n}\n\nasync function callStripeConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n paymentMethodId: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<ApplePayResult> {\n // /apple-pay/confirm now carries the fields that used to live on /start —\n // processor_id, customer_info, fraud_metadata — because the customer,\n // checkout attempt, and Stripe PaymentIntent are all created here.\n const result = await apiCall<ApplePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/apple-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n customer_info: options.customerInfo,\n fraud_metadata: collectFraudMetadata(),\n payment_method_id: paymentMethodId,\n payer_email: payerEmail,\n mock_scenario: mockScenarioStr,\n } as ApplePayConfirmRequest),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return { errors: { apple_pay: result.error || \"Failed to confirm payment\" } };\n }\n\n const confirmData = result.data;\n\n if (confirmData.charge_status === \"success\") {\n return {\n data: {\n id: confirmData.transaction_id,\n checkoutAttemptId: confirmData.checkout_attempt_id,\n checkoutSessionId: confirmData.checkout_session_id ?? secureToken,\n state: \"checkout_succeeded\",\n paymentIntentId: confirmData.payment_intent_id,\n customerId: confirmData.customer_id,\n paymentMethodId: confirmData.payment_method_id,\n processorUsed: confirmData.processor_used,\n subscriptionId: confirmData.subscription_id,\n invoiceId: confirmData.invoice_id,\n invoiceNumber: confirmData.invoice_number,\n cardBrand: confirmData.card_brand,\n cardLast4: confirmData.card_last4,\n cardExpMonth: confirmData.card_exp_month,\n cardExpYear: confirmData.card_exp_year,\n errorCode: confirmData.error_code,\n errorMessageForCustomer: confirmData.error_message_for_customer,\n errorMessageForDebug: confirmData.error_message_for_debug,\n nextAction: confirmData.next_action,\n },\n };\n }\n\n return {\n errors: {\n apple_pay: confirmData.error_message_for_customer || confirmData.error_message_for_debug || \"Payment failed\",\n },\n };\n}\n\n// =============================================================================\n// Prepare Function (call BEFORE the click handler)\n// =============================================================================\n\n/**\n * Pre-fetch Apple Pay data and prepare the PaymentRequest.\n * Call this when the checkout page loads, NOT in the click handler.\n *\n * For Stripe: pre-fetches data and prepares PaymentRequest for immediate show.\n * For Airwallex: returns success with processor=\"airwallex\" so submit uses native ApplePaySession.\n *\n * @deprecated The SDK now calls this automatically on init. Use `onApplePayReady` to observe\n * readiness and `notifyAmountChanged` to trigger re-prepare after amount changes.\n */\nexport async function prepareApplePay(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n environment: string,\n): Promise<{ success: boolean; error?: string; applePay?: boolean }> {\n console.log(\"[ApplePay] prepareApplePay called\");\n\n // Clear any previous state\n preparedStripeState = null;\n\n const mockScenarioStr = getMockScenarioStr(options.mockScenario);\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[ApplePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Airwallex: Load Apple Pay SDK (enables QR code flow in non-Safari browsers),\n // then fetch session info to get the correct amount from line items.\n // This fixes the $0.00 bug where options.amount was undefined and defaulted to 0.\n if (options.processorType === \"airwallex\") {\n console.log(\"[ApplePay] Airwallex processor - loading Apple Pay SDK, fetching session info for amount\");\n\n // In mock mode, skip SDK loading and availability check (jsdom has no ApplePaySession)\n if (!mockScenarioStr) {\n try {\n await loadApplePayScript();\n } catch (err) {\n console.error(\"[ApplePay] Failed to load Apple Pay SDK:\", err);\n return { success: false, error: \"Failed to load Apple Pay\" };\n }\n\n let canMake = false;\n try {\n canMake = !!window.ApplePaySession?.canMakePayments();\n } catch {\n canMake = false;\n }\n if (!canMake) {\n console.log(\"[ApplePay] Apple Pay not available on this device/browser\");\n return { success: false, error: \"Apple Pay not available on this device\" };\n }\n }\n\n // Fetch session info (amount, currency, country) from backend\n const sessionInfoResult = await callAirwallexSessionInfoEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n if (sessionInfoResult.error || !sessionInfoResult.data) {\n console.error(\"[ApplePay] Failed to fetch session info:\", sessionInfoResult.error);\n return { success: false, error: sessionInfoResult.error || \"Failed to fetch Apple Pay session info\" };\n }\n\n console.log(\"[ApplePay] Got session info:\", sessionInfoResult.data);\n const resolvedAmount = sessionInfoResult.data.amount;\n const resolvedCurrency = sessionInfoResult.data.currency;\n const resolvedCountry = sessionInfoResult.data.country || options.country;\n\n preparedAirwallexState = {\n country: resolvedCountry,\n currency: resolvedCurrency,\n amount: resolvedAmount,\n merchantName: options.merchantName,\n };\n console.log(\"[ApplePay] Airwallex prepared state:\", preparedAirwallexState);\n return { success: true, applePay: true };\n }\n\n // Call Stripe start endpoint to fetch stripe_pk + sheet display data\n const startResult = await callStripeStartEndpoint(\n apiBaseUrl,\n secureToken,\n options,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { success: false, error: startResult.error || \"Failed to start Apple Pay\" };\n }\n\n const startData = startResult.data;\n\n // Initialize Stripe adapter\n if (!startData.stripe_pk) {\n return { success: false, error: \"Stripe publishable key not provided\" };\n }\n\n const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, options.mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Create PaymentRequest and call canMakePayment() (required before show())\n const prepareResult = await adapter.preparePaymentRequest({\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: {\n label: \"Total\",\n amount: startData.amount,\n },\n });\n\n if (!prepareResult.success) {\n return {\n success: false,\n error: prepareResult.error || \"Failed to prepare payment request\",\n applePay: prepareResult.applePay,\n };\n }\n\n if (!prepareResult.applePay) {\n return {\n success: false,\n error: \"Apple Pay is not available on this device or Stripe account\",\n applePay: false,\n };\n }\n\n // Store the prepared state\n preparedStripeState = {\n processor: \"stripe\",\n adapter,\n startData,\n mockScenarioStr,\n checkoutRequestId,\n };\n\n console.log(\"[ApplePay] prepareApplePay success (Stripe), ready for click\");\n return { success: true, applePay: true };\n}\n\n/**\n * Check if Apple Pay has been prepared and is ready.\n */\nexport function isApplePayPrepared(): boolean {\n return (preparedStripeState?.adapter.isPrepared() ?? false) || preparedAirwallexState !== null;\n}\n\n/**\n * Clear prepared state (call on unmount or when checkout changes).\n */\nexport function clearPreparedApplePay(): void {\n if (preparedStripeState) {\n preparedStripeState.adapter.clearPrepared();\n }\n preparedStripeState = null;\n preparedAirwallexState = null;\n}\n\n// =============================================================================\n// Airwallex Apple Pay Flow\n// =============================================================================\n\n/**\n * Fetch session info (amount, currency, country) from the backend.\n * Called during prepareApplePay to get the correct amount BEFORE showing the payment sheet.\n * This fixes the $0.00 bug where options.amount was undefined and defaulted to 0.\n */\nasync function callAirwallexSessionInfoEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<{ data?: AirwallexSessionInfoResponse; error?: string }> {\n return apiCall<AirwallexSessionInfoResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/session-info`,\n {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n checkoutRequestId,\n );\n}\n\nasync function callAirwallexStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n validationUrl: string,\n initiativeContext: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<{ data?: ApplePayStartResponse; error?: string }> {\n return apiCall<ApplePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/start`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n customer_info: options.customerInfo,\n fraud_metadata: collectFraudMetadata(),\n validation_url: validationUrl,\n initiative_context: initiativeContext,\n mock_scenario: mockScenarioStr,\n } as ApplePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\nasync function callAirwallexConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n applePayToken: ApplePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n payerFirstName?: string,\n payerLastName?: string,\n): Promise<ApplePayConfirmResponse> {\n const result = await apiCall<ApplePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n apple_pay_token: applePayToken,\n payer_email: payerEmail,\n payer_first_name: payerFirstName,\n payer_last_name: payerLastName,\n mock_scenario: mockScenarioStr,\n } as ApplePayConfirmRequest),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message_for_debug: result.error || \"Failed to confirm payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\nasync function callAirwallexVerifyEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<ApplePayConfirmResponse> {\n const result = await apiCall<ApplePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/verify`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message_for_debug: result.error || \"Failed to verify payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\nfunction toApplePayResult(response: ApplePayConfirmResponse, secureToken: string): ApplePayResult {\n if (response.charge_status === \"success\") {\n return {\n data: {\n id: response.transaction_id,\n checkoutAttemptId: response.checkout_attempt_id,\n checkoutSessionId: response.checkout_session_id ?? secureToken,\n state: \"checkout_succeeded\",\n paymentIntentId: response.payment_intent_id,\n customerId: response.customer_id,\n paymentMethodId: response.payment_method_id,\n processorUsed: response.processor_used,\n subscriptionId: response.subscription_id,\n invoiceId: response.invoice_id,\n invoiceNumber: response.invoice_number,\n cardBrand: response.card_brand,\n cardLast4: response.card_last4,\n cardExpMonth: response.card_exp_month,\n cardExpYear: response.card_exp_year,\n errorCode: response.error_code,\n errorMessageForCustomer: response.error_message_for_customer,\n errorMessageForDebug: response.error_message_for_debug,\n nextAction: response.next_action,\n },\n };\n }\n return {\n errors: {\n apple_pay: response.error_message_for_customer || response.error_message_for_debug || \"Payment failed\",\n },\n };\n}\n\nconst MAX_USER_ACTIONS = 5;\n\n/**\n * Run the Airwallex Apple Pay flow with 3DS loop support.\n *\n * Flow:\n * 1. Show native ApplePaySession, call /start for merchant validation\n * 2. On payment authorized, call /confirm with token\n * 3. If 3DS required, handle it and call /verify\n * 4. Loop if more 3DS needed\n */\nasync function runAirwallexFlow(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<ApplePayResult> {\n // Convert mock scenario\n let airwallexMockScenario: AirwallexApplePayMockScenario = AirwallexApplePayMockScenario.None;\n if (options.mockScenario === ApplePayMockScenario.Success) {\n airwallexMockScenario = AirwallexApplePayMockScenario.Success;\n } else if (options.mockScenario === ApplePayMockScenario.Cancelled) {\n airwallexMockScenario = AirwallexApplePayMockScenario.Cancelled;\n }\n\n // Defense-in-depth: validateOptions should catch this earlier, but guard against\n // future callers that bypass validation to avoid an unhandled TypeError on `.toUpperCase()`\n if (!options.country) {\n return { errors: { apple_pay: \"Country is required for Airwallex Apple Pay\" } };\n }\n\n // Auto-fetch amount from session if not provided (e.g. merchant didn't call prepareApplePay first)\n if (!options.amount) {\n const sessionInfoResult = await callAirwallexSessionInfoEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n if (sessionInfoResult.data) {\n options.amount = sessionInfoResult.data.amount;\n options.currency = options.currency || sessionInfoResult.data.currency;\n options.country = options.country || sessionInfoResult.data.country;\n }\n }\n\n // Initialize adapter\n const adapter = new AirwallexApplePayAdapter(airwallexMockScenario);\n\n const config: AirwallexApplePayConfig = {\n amount: options.amount || 0,\n currency: (options.currency || \"USD\").toUpperCase(),\n country: options.country.toUpperCase(),\n merchantName: options.merchantName || \"Total\",\n };\n\n if (!adapter.initialize(config)) {\n return { errors: { apple_pay: \"Apple Pay not available on this device\" } };\n }\n\n const canPay = await adapter.canMakePayment();\n if (!canPay) {\n return { errors: { apple_pay: \"Apple Pay not available on this device\" } };\n }\n\n // Get current domain for initiative_context\n const initiativeContext = typeof window !== \"undefined\" ? window.location.hostname : \"\";\n\n // In mock mode, call /start first to create checkout attempt (mock adapter skips merchant validation)\n if (airwallexMockScenario !== AirwallexApplePayMockScenario.None) {\n const startResult = await callAirwallexStartEndpoint(\n apiBaseUrl,\n secureToken,\n options,\n \"https://mock-apple-pay-gateway.example.com/paymentservices/startSession\",\n initiativeContext,\n mockScenarioStr,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { errors: { apple_pay: startResult.error || \"Failed to start mock checkout\" } };\n }\n }\n\n // Show Apple Pay sheet with merchant validation callback\n const paymentResult = await adapter.showPaymentSheet(async (validationUrl: string) => {\n // Call /start endpoint for merchant validation\n const startResult = await callAirwallexStartEndpoint(\n apiBaseUrl,\n secureToken,\n options,\n validationUrl,\n initiativeContext,\n mockScenarioStr,\n checkoutRequestId,\n );\n\n if (startResult.error || !startResult.data) {\n return { error: startResult.error || \"Merchant validation failed\" };\n }\n\n if (!startResult.data.merchant_session) {\n return { error: \"No merchant session returned from server\" };\n }\n\n return { merchantSession: startResult.data.merchant_session };\n });\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { errors: { apple_pay: \"Apple Pay cancelled by user\" } };\n }\n return { errors: { apple_pay: paymentResult.error || \"Apple Pay failed\" } };\n }\n\n const { token, complete, payerEmail, payerFirstName, payerLastName } = paymentResult;\n\n // Call /confirm with the token\n let response = await callAirwallexConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n token,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n payerFirstName,\n payerLastName,\n );\n\n // Handle 3DS loop\n let userActionCount = 0;\n while (response.charge_status === \"pending\" && response.next_action && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n\n // Handle 3DS challenge — Airwallex3dsNextAction is structurally identical to SDK's Airwallex3dsAction\n const nextAction = response.next_action as Airwallex3dsNextAction;\n const actionResult = await handleNextAction({ type: nextAction.type, url: nextAction.url });\n\n // Call verify endpoint\n const verifyResponse = await callAirwallexVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n // Check if another 3DS action is required\n if (verifyResponse.charge_status === \"pending\" && verifyResponse.next_action) {\n if (!actionResult.success) {\n console.log(\"[ApplePay:Airwallex] 3DS failed but retry available, continuing loop...\");\n }\n response = verifyResponse;\n continue;\n }\n\n // No more actions - check final result\n if (!actionResult.success) {\n complete(\"fail\");\n return {\n errors: {\n apple_pay:\n verifyResponse.error_message_for_customer ||\n verifyResponse.error_message_for_debug ||\n actionResult.error ||\n \"3DS authentication failed\",\n },\n };\n }\n\n // 3DS succeeded\n complete(verifyResponse.charge_status === \"success\" ? \"success\" : \"fail\");\n return toApplePayResult(verifyResponse, secureToken);\n }\n\n // Check for max attempts exceeded\n if (userActionCount >= MAX_USER_ACTIONS) {\n complete(\"fail\");\n return { errors: { apple_pay: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // No 3DS required - complete with result\n complete(response.charge_status === \"success\" ? \"success\" : \"fail\");\n return toApplePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Main Submit Function\n// =============================================================================\n\nconst defSubmitPayment = (\n states: PaymentKitStates,\n getAutoPrepareConfig: () => AutoPrepareConfig | null,\n onClearPrepared: () => void,\n) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n const { apiBaseUrl, secureToken, environment } = states;\n const applePayOptions = options as ApplePaySubmitOptions;\n\n // Fill in processorId/processorType from auto-prepare config if merchant didn't provide them\n const autoPrepareConfig = getAutoPrepareConfig();\n if (!applePayOptions.processorId && autoPrepareConfig?.processorId) {\n applePayOptions.processorId = autoPrepareConfig.processorId;\n }\n if (!applePayOptions.processorType && autoPrepareConfig?.processorType) {\n applePayOptions.processorType = autoPrepareConfig.processorType;\n }\n\n // Validate options\n const validationError = validateOptions(applePayOptions);\n if (validationError) {\n return { errors: validationError };\n }\n\n try {\n const mockScenarioStr = getMockScenarioStr(applePayOptions.mockScenario);\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[ApplePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Check if we have prepared Stripe state\n if (preparedStripeState?.adapter.isPrepared()) {\n console.log(\"[ApplePay] Using prepared Stripe state for immediate sheet display\");\n\n // Show Apple Pay sheet IMMEDIATELY using the prepared PaymentRequest\n const paymentResultPromise = preparedStripeState.adapter.showPreparedPaymentSheet();\n const paymentResult = await paymentResultPromise;\n\n if (!paymentResult.success) {\n clearPreparedApplePay();\n\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { errors: { apple_pay: \"Apple Pay cancelled by user\" } };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { errors: { apple_pay: errorMessage } };\n }\n\n const { paymentMethodId, paymentMethodEvent, billingDetails } = paymentResult;\n\n // Confirm with backend using the PaymentMethod ID\n const confirmResult = await callStripeConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n applePayOptions,\n paymentMethodId,\n mockScenarioStr,\n preparedStripeState.checkoutRequestId,\n billingDetails?.email,\n );\n\n // Complete Apple Pay UI based on result\n if (confirmResult.data) {\n paymentMethodEvent.complete(\"success\");\n clearPreparedApplePay();\n return confirmResult;\n } else {\n paymentMethodEvent.complete(\"fail\");\n clearPreparedApplePay();\n return confirmResult;\n }\n }\n\n // Check if this is an Airwallex processor - route directly to Airwallex flow\n if (applePayOptions.processorType === \"airwallex\") {\n console.log(\"[ApplePay] Running Airwallex flow (processorType=airwallex)\");\n // Merge prepare-time state into submit options so country/currency/amount/merchantName\n // are available even if the merchant only provided them at prepare time\n if (preparedAirwallexState) {\n if (applePayOptions.country == null) applePayOptions.country = preparedAirwallexState.country;\n if (applePayOptions.currency == null) applePayOptions.currency = preparedAirwallexState.currency;\n if (applePayOptions.amount == null) applePayOptions.amount = preparedAirwallexState.amount;\n if (applePayOptions.merchantName == null) applePayOptions.merchantName = preparedAirwallexState.merchantName;\n }\n try {\n return await runAirwallexFlow(apiBaseUrl, secureToken, applePayOptions, mockScenarioStr, checkoutRequestId);\n } finally {\n preparedAirwallexState = null;\n }\n }\n\n // No prepared state for Stripe - call start endpoint\n const startResult = await callStripeStartEndpoint(\n apiBaseUrl,\n secureToken,\n applePayOptions,\n checkoutRequestId,\n );\n\n if (startResult.error || !startResult.data) {\n return { errors: { apple_pay: startResult.error || \"Failed to start Apple Pay\" } };\n }\n\n const startData = startResult.data;\n\n // Stripe flow without prepared state - this may fail due to user gesture requirements\n console.warn(\"[ApplePay] Stripe flow without prepared state - may fail due to user gesture requirements\");\n\n if (!startData.stripe_pk) {\n return { errors: { apple_pay: \"Stripe publishable key not provided\" } };\n }\n\n const { adapter, error: adapterError } = initializeStripeAdapter(\n startData.stripe_pk,\n applePayOptions.mockScenario,\n );\n if (!adapter) {\n return { errors: { apple_pay: adapterError || \"Failed to initialize Stripe adapter\" } };\n }\n\n // This will likely fail due to user gesture requirements\n const prepareResult = await adapter.preparePaymentRequest({\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: { label: \"Total\", amount: startData.amount },\n });\n\n if (!prepareResult.success || !prepareResult.applePay) {\n return { errors: { apple_pay: prepareResult.error || \"Apple Pay not available\" } };\n }\n\n const paymentResult = await adapter.showPreparedPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { errors: { apple_pay: \"Apple Pay cancelled by user\" } };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { errors: { apple_pay: errorMessage } };\n }\n\n const { paymentMethodId, paymentMethodEvent, billingDetails } = paymentResult;\n\n const confirmResult = await callStripeConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n applePayOptions,\n paymentMethodId,\n mockScenarioStr,\n checkoutRequestId,\n billingDetails?.email,\n );\n\n if (confirmResult.data) {\n paymentMethodEvent.complete(\"success\");\n return confirmResult;\n } else {\n paymentMethodEvent.complete(\"fail\");\n return confirmResult;\n }\n } catch (error) {\n onClearPrepared();\n return { errors: { apple_pay: `Apple Pay error: ${error}` } };\n }\n };\n\n return submitPayment;\n};\n\n// =============================================================================\n// Payment Method Definition\n// =============================================================================\n\nconst ApplePayPaymentMethod = definePaymentMethod((paymentKitStates) => {\n const { apiBaseUrl, secureToken, environment } = paymentKitStates;\n\n // Per-instance auto-prepare state — isolated from other ApplePayPaymentMethod instances.\n // Note: preparedStripeState and preparedAirwallexState remain module-level globals (pre-existing\n // architectural constraint shared across the file). Full per-instance isolation for those fields\n // would require threading them through prepareApplePay, runAirwallexFlow, validateOptions, and\n // defSubmitPayment — tracked as tech debt.\n let autoPrepareConfig: AutoPrepareConfig | null = null;\n let onApplePayReadyCallbacks: ((isReady: boolean) => void)[] = [];\n let isApplePayReadyState = false;\n let autoPrepareInProgress = false;\n // Incremented by cleanup() so that in-flight prepares can detect staleness and skip writes.\n let cleanupGeneration = 0;\n // Stores pending retry args when notifyAmountChanged is called while a prepare is in flight.\n let pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: string } | null = null;\n // Resolvers waiting for a queued retry to complete (for correct notifyAmountChanged await).\n let pendingPrepareResolvers: (() => void)[] = [];\n\n function instanceSetApplePayReady(ready: boolean): void {\n isApplePayReadyState = ready;\n for (const cb of onApplePayReadyCallbacks) cb(ready);\n }\n\n function instanceClearPreparedApplePay(): void {\n clearPreparedApplePay();\n instanceSetApplePayReady(false);\n }\n\n async function instanceAutoPrepare(apBase: string, sToken: string, env: string): Promise<void> {\n if (autoPrepareInProgress) {\n // A prepare is already in flight; queue a retry and return a promise that resolves after it.\n pendingAutoPrepareArgs = { apiBaseUrl: apBase, secureToken: sToken, environment: env };\n return new Promise<void>((resolve) => pendingPrepareResolvers.push(resolve));\n }\n autoPrepareInProgress = true;\n // Capture generation so we can detect if cleanup() is called while we await.\n const capturedGeneration = cleanupGeneration;\n instanceSetApplePayReady(false);\n\n try {\n const result = await apiCall<CheckoutSessionConfig>(`${apBase}/api/checkout-sessions/token/${sToken}`, {\n method: \"GET\",\n });\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n if (result.error || !result.data) {\n console.warn(\"[ApplePay] Auto-prepare: failed to fetch session config:\", result.error);\n return;\n }\n\n const processorId = result.data.express_checkout_processor_id;\n if (!processorId) {\n console.log(\"[ApplePay] Auto-prepare: no express checkout processor configured\");\n return;\n }\n\n const processorTypeRaw = result.data.express_checkout_processor_type;\n const processorType =\n processorTypeRaw === \"airwallex\" || processorTypeRaw === \"stripe\" ? processorTypeRaw : undefined;\n\n autoPrepareConfig = { processorId, processorType };\n\n const prepareResult = await prepareApplePay(\n apBase,\n sToken,\n { processorId, processorType, customerInfo: { first_name: \"\", last_name: \"\" } },\n env,\n );\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n instanceSetApplePayReady(prepareResult.success && prepareResult.applePay === true);\n } catch (err) {\n if (cleanupGeneration === capturedGeneration) {\n console.error(\"[ApplePay] Auto-prepare failed:\", err);\n }\n } finally {\n autoPrepareInProgress = false;\n const stale = cleanupGeneration !== capturedGeneration;\n const pending = pendingAutoPrepareArgs;\n const resolvers = pendingPrepareResolvers.splice(0);\n if (!stale && pending) {\n pendingAutoPrepareArgs = null;\n // Run the retry and resolve all callers that were waiting for it.\n instanceAutoPrepare(pending.apiBaseUrl, pending.secureToken, pending.environment).then(() => {\n for (const r of resolvers) r();\n });\n } else {\n pendingAutoPrepareArgs = null;\n for (const r of resolvers) r();\n }\n }\n }\n\n // Start auto-prepare immediately so the button is ready before first user interaction.\n instanceAutoPrepare(apiBaseUrl, secureToken, environment).catch((err) =>\n console.error(\"[ApplePay] Unhandled init error:\", err),\n );\n\n return {\n name: \"apple_pay\",\n externalFuncs: {\n /**\n * @deprecated The SDK now prepares automatically on init. Use `onApplePayReady` to observe\n * readiness and `notifyAmountChanged` to trigger re-prepare after amount changes.\n */\n prepareApplePay: (options: ApplePaySubmitOptions) =>\n prepareApplePay(apiBaseUrl, secureToken, options, environment),\n\n /**\n * Register a callback to be notified when Apple Pay becomes ready (or stops being ready).\n * Fires immediately with the current state, then on every state change.\n * Multiple registrations are all notified — none are silently overwritten.\n *\n * @example\n * paymentKit.apple_pay.onApplePayReady((isReady) => {\n * applePayButton.disabled = !isReady;\n * });\n */\n onApplePayReady: (callback: (isReady: boolean) => void): void => {\n onApplePayReadyCallbacks.push(callback);\n // Fire immediately with current state so caller doesn't miss a completed prepare.\n callback(isApplePayReadyState);\n },\n\n /**\n * Notify the SDK that the payment amount has changed (e.g. coupon applied).\n * The SDK will disable Apple Pay, re-prepare with the new amount, then re-enable.\n * The returned promise resolves when re-prepare is fully complete.\n *\n * @example\n * await paymentKit.apple_pay.notifyAmountChanged();\n */\n notifyAmountChanged: (): Promise<void> => {\n instanceClearPreparedApplePay();\n autoPrepareConfig = null;\n return instanceAutoPrepare(apiBaseUrl, secureToken, environment);\n },\n },\n internalFuncs: {\n submitPayment: defSubmitPayment(paymentKitStates, () => autoPrepareConfig, instanceClearPreparedApplePay),\n cleanup: () => {\n cleanupGeneration++;\n onApplePayReadyCallbacks = [];\n isApplePayReadyState = false;\n autoPrepareConfig = null;\n pendingAutoPrepareArgs = null;\n pendingPrepareResolvers = [];\n autoPrepareInProgress = false;\n clearPreparedApplePay();\n },\n },\n };\n});\n\nexport { ApplePayMockScenario };\n\nexport default ApplePayPaymentMethod;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"apple-pay.mjs","names":["preparedStripeState: PreparedStripeApplePayState | null","preparedAirwallexState: PreparedAirwallexState | null","applePayScriptLoadPromise: Promise<void> | null","airwallexMockScenario: AirwallexApplePayMockScenario","config: AirwallexApplePayConfig","submitPayment: TInternalFuncs[\"submitPayment\"]","paymentResult","confirmResult","paymentMethodId","billingDetails","autoPrepareConfig: AutoPrepareConfig | null","onApplePayReadyCallbacks: ((isReady: boolean) => void)[]","pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: PaymentKitEnvironment } | null","pendingPrepareResolvers: (() => void)[]"],"sources":["../../src/payment-methods/apple-pay.ts"],"sourcesContent":["import type { PaymentKitEnvironment, PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\nimport {\n AirwallexApplePayAdapter,\n type AirwallexApplePayConfig,\n AirwallexApplePayMockScenario,\n type ApplePayEncryptedToken,\n} from \"./airwallex-apple-pay-adapter\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { ApplePayMockScenario, StripeApplePayAdapter } from \"./stripe-apple-pay-adapter\";\n\n// Apple Pay-specific types\nexport type ApplePayCustomerInfo = {\n first_name: string;\n last_name: string;\n email?: string;\n};\n\nexport type ApplePayStartRequest = {\n processor_id: string;\n // Airwallex-only fields. Stripe /apple-pay/start is a pure read and\n // ignores these — customer_info/fraud_metadata are sent to /apple-pay/confirm\n // instead, where the customer + checkout attempt + PaymentIntent are created.\n customer_info?: ApplePayCustomerInfo;\n fraud_metadata?: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n mock_scenario?: string;\n // Airwallex-specific fields (sent on /start for merchant validation)\n validation_url?: string;\n initiative_context?: string;\n};\n\nexport type ApplePayStartResponse = {\n amount: number;\n currency: string;\n country: string;\n\n // Stripe-specific (when calling /apple-pay/start)\n stripe_pk?: string;\n\n // Airwallex-specific (when calling /airwallex/apple-pay/start). Stripe's\n // /start does not create a checkout attempt — it's deferred to /confirm.\n checkout_attempt_id?: string;\n merchant_session?: { [key: string]: unknown }; // Apple merchant session for completeMerchantValidation()\n};\n\n// Airwallex 3DS next action type (matches backend snake_case response)\nexport type Airwallex3dsNextAction = {\n type: \"airwallex_3ds\";\n url: string;\n};\n\nexport type ApplePayConfirmRequest = {\n // Stripe-only: moved from /start (where they used to drive customer/PI\n // creation). At confirm time, the Stripe path creates the customer, checkout\n // attempt, and PaymentIntent in a single call.\n processor_id?: string;\n customer_info?: ApplePayCustomerInfo;\n fraud_metadata?: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n // Stripe: Send PaymentMethod ID\n payment_method_id?: string;\n // Airwallex: Send encrypted Apple Pay token\n apple_pay_token?: ApplePayEncryptedToken | { [key: string]: unknown };\n // Email from payment sheet (Stripe Apple Pay) — used to fill missing customer email\n payer_email?: string;\n // Name from payment sheet — used to fill missing customer name\n payer_first_name?: string;\n payer_last_name?: string;\n mock_scenario?: string;\n};\n\nexport type ApplePayConfirmResponse = {\n charge_status: \"success\" | \"fail\" | \"pending\";\n transaction_id?: string;\n error_code?: string;\n error_message_for_customer?: string;\n error_message_for_debug?: string;\n checkout_attempt_id: string;\n checkout_session_id?: string;\n next_action?: Airwallex3dsNextAction; // Present when charge_status=\"pending\" for 3DS\n payment_intent_id?: string;\n customer_id?: string;\n payment_method_id?: string;\n processor_used?: string;\n subscription_id?: string;\n invoice_id?: string;\n invoice_number?: number;\n card_brand?: string;\n card_last4?: string;\n card_exp_month?: number;\n card_exp_year?: number;\n};\n\nexport type ApplePaySubmitOptions = {\n /** Processor external ID — optional when using auto-prepare (SDK fetches from checkout session) */\n processorId?: string;\n processorType?: \"stripe\" | \"airwallex\";\n customerInfo: ApplePayCustomerInfo;\n mockScenario?: ApplePayMockScenario;\n amount?: number; // Amount in atomic units (cents) for Apple Pay sheet display\n currency?: string; // Currency code (e.g., \"usd\")\n /** Country code — optional when using auto-prepare (fetched from backend) */\n country?: string;\n merchantName?: string; // Merchant display name on Apple Pay sheet\n};\n\ntype ApplePayResult =\n | { data: { [key: string]: unknown }; errors?: undefined }\n | { data?: undefined; errors: PaymentKitErrors };\n\n// =============================================================================\n// Prepared Payment State (for Stripe pre-fetching before click)\n// =============================================================================\n\ntype PreparedStripeApplePayState = {\n processor: \"stripe\";\n adapter: StripeApplePayAdapter;\n startData: ApplePayStartResponse;\n mockScenarioStr?: string;\n checkoutRequestId: string;\n};\n\n// Global state to store prepared Apple Pay data (Stripe only - Airwallex uses native session)\nlet preparedStripeState: PreparedStripeApplePayState | null = null;\n\n// Prepared Airwallex state — persists options from prepare call for use at submit time\n// The amount field is fetched from the session via /session-info endpoint to fix\n// the $0.00 bug where options.amount was undefined and defaulted to 0.\ntype PreparedAirwallexState = {\n country: string;\n currency?: string;\n amount?: number;\n merchantName?: string;\n};\nlet preparedAirwallexState: PreparedAirwallexState | null = null;\n\n// Response type for Airwallex Apple Pay session-info endpoint\ntype AirwallexSessionInfoResponse = {\n amount: number;\n currency: string;\n country: string;\n};\n\n// =============================================================================\n// Auto-Prepare State\n// =============================================================================\n\ntype AutoPrepareConfig = {\n processorId: string;\n processorType: \"airwallex\" | \"stripe\" | undefined;\n};\n\ntype CheckoutSessionConfig = {\n express_checkout_processor_id?: string | null;\n express_checkout_processor_type?: string | null;\n};\n\n// =============================================================================\n// Apple Pay SDK Loader\n// =============================================================================\n\n// Loads Apple's JS SDK, which makes window.ApplePaySession available in non-Safari\n// browsers (Chrome, Firefox, etc.) and enables the \"Scan Code with iPhone\" QR flow.\nlet applePayScriptLoadPromise: Promise<void> | null = null;\nasync function loadApplePayScript(): Promise<void> {\n if (typeof window === \"undefined\") return;\n if (window.ApplePaySession) return;\n if (document.getElementById(\"__pk_apple_pay_sdk\")) {\n // Tag exists — if we have a cached promise, wait for it; otherwise the tag\n // already resolved (e.g. after a module reload) so return immediately.\n return applePayScriptLoadPromise ?? Promise.resolve();\n }\n applePayScriptLoadPromise = new Promise<void>((resolve, reject) => {\n const script = document.createElement(\"script\");\n script.id = \"__pk_apple_pay_sdk\";\n script.src = \"https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js\";\n script.crossOrigin = \"anonymous\";\n // NOTE: Apple doesn't publish stable SRI hashes for the 1.latest pointer,\n // so integrity checking is omitted. CSP must allow script-src https://applepay.cdn-apple.com.\n script.onload = () => resolve();\n script.onerror = () => {\n // Clear cached state so the next prepareApplePay call can retry.\n applePayScriptLoadPromise = null;\n document.getElementById(\"__pk_apple_pay_sdk\")?.remove();\n reject(new Error(\"Failed to load Apple Pay SDK\"));\n };\n document.head.appendChild(script);\n });\n return applePayScriptLoadPromise;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\nasync function apiCall<T>(\n url: string,\n options: RequestInit,\n checkoutRequestId?: string,\n): Promise<{ data?: T; error?: string }> {\n const headers = new Headers(options.headers);\n if (checkoutRequestId) {\n headers.set(\"x-request-id\", checkoutRequestId);\n }\n\n const response = await fetch(url, { ...options, headers });\n if (!response.ok) {\n let errorMessage = `Request failed (${response.status})`;\n try {\n const errorData = await response.json();\n errorMessage = errorData.detail || errorMessage;\n } catch {\n errorMessage = response.statusText || errorMessage;\n }\n return { error: errorMessage };\n }\n return { data: await response.json() };\n}\n\nfunction validateOptions(options: ApplePaySubmitOptions): PaymentKitErrors | null {\n if (!options?.processorId) {\n return { processor_id: \"Processor ID is required\" };\n }\n // For Airwallex, country is required (either directly or from prepared state)\n if (options.processorType === \"airwallex\" && !options.country && !preparedAirwallexState?.country) {\n return { country: \"Country is required for Airwallex Apple Pay\" };\n }\n return null;\n}\n\nfunction getMockScenarioStr(mockScenario?: ApplePayMockScenario): string | undefined {\n return mockScenario && mockScenario !== ApplePayMockScenario.None ? mockScenario : undefined;\n}\n\n// =============================================================================\n// Stripe Apple Pay Flow\n// =============================================================================\n\nasync function callStripeStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n checkoutRequestId?: string,\n): Promise<{ data?: ApplePayStartResponse; error?: string }> {\n // /apple-pay/start is now a pure read: it returns stripe_pk + sheet data\n // (amount/currency/country). Customer/CheckoutAttempt/PaymentIntent are\n // created in /apple-pay/confirm once the user authorizes the sheet.\n return apiCall<ApplePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/apple-pay/start`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n } as ApplePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\nfunction initializeStripeAdapter(\n stripePk: string,\n mockScenario?: ApplePayMockScenario,\n): { adapter?: StripeApplePayAdapter; error?: string } {\n const adapter = new StripeApplePayAdapter(mockScenario);\n\n if (!adapter.initialize(stripePk)) {\n return { error: 'Stripe.js not loaded. Add <script src=\"https://js.stripe.com/v3/\"></script> to your page.' };\n }\n\n return { adapter };\n}\n\nasync function callStripeConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n paymentMethodId: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<ApplePayResult> {\n // /apple-pay/confirm now carries the fields that used to live on /start —\n // processor_id, customer_info, fraud_metadata — because the customer,\n // checkout attempt, and Stripe PaymentIntent are all created here.\n const result = await apiCall<ApplePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/apple-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n customer_info: options.customerInfo,\n fraud_metadata: collectFraudMetadata(),\n payment_method_id: paymentMethodId,\n payer_email: payerEmail,\n mock_scenario: mockScenarioStr,\n } as ApplePayConfirmRequest),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return { errors: { apple_pay: result.error || \"Failed to confirm payment\" } };\n }\n\n const confirmData = result.data;\n\n if (confirmData.charge_status === \"success\") {\n return {\n data: {\n id: confirmData.transaction_id,\n checkoutAttemptId: confirmData.checkout_attempt_id,\n checkoutSessionId: confirmData.checkout_session_id ?? secureToken,\n state: \"checkout_succeeded\",\n paymentIntentId: confirmData.payment_intent_id,\n customerId: confirmData.customer_id,\n paymentMethodId: confirmData.payment_method_id,\n processorUsed: confirmData.processor_used,\n subscriptionId: confirmData.subscription_id,\n invoiceId: confirmData.invoice_id,\n invoiceNumber: confirmData.invoice_number,\n cardBrand: confirmData.card_brand,\n cardLast4: confirmData.card_last4,\n cardExpMonth: confirmData.card_exp_month,\n cardExpYear: confirmData.card_exp_year,\n errorCode: confirmData.error_code,\n errorMessageForCustomer: confirmData.error_message_for_customer,\n errorMessageForDebug: confirmData.error_message_for_debug,\n nextAction: confirmData.next_action,\n },\n };\n }\n\n return {\n errors: {\n apple_pay: confirmData.error_message_for_customer || confirmData.error_message_for_debug || \"Payment failed\",\n },\n };\n}\n\n// =============================================================================\n// Prepare Function (call BEFORE the click handler)\n// =============================================================================\n\n/**\n * Pre-fetch Apple Pay data and prepare the PaymentRequest.\n * Call this when the checkout page loads, NOT in the click handler.\n *\n * For Stripe: pre-fetches data and prepares PaymentRequest for immediate show.\n * For Airwallex: returns success with processor=\"airwallex\" so submit uses native ApplePaySession.\n *\n * @deprecated The SDK now calls this automatically on init. Use `onApplePayReady` to observe\n * readiness and `notifyAmountChanged` to trigger re-prepare after amount changes.\n */\nexport async function prepareApplePay(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n environment: PaymentKitEnvironment,\n): Promise<{ success: boolean; error?: string; applePay?: boolean }> {\n console.log(\"[ApplePay] prepareApplePay called\");\n\n // Clear any previous state\n preparedStripeState = null;\n\n const mockScenarioStr = getMockScenarioStr(options.mockScenario);\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[ApplePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Airwallex: Load Apple Pay SDK (enables QR code flow in non-Safari browsers),\n // then fetch session info to get the correct amount from line items.\n // This fixes the $0.00 bug where options.amount was undefined and defaulted to 0.\n if (options.processorType === \"airwallex\") {\n console.log(\"[ApplePay] Airwallex processor - loading Apple Pay SDK, fetching session info for amount\");\n\n // In mock mode, skip SDK loading and availability check (jsdom has no ApplePaySession)\n if (!mockScenarioStr) {\n try {\n await loadApplePayScript();\n } catch (err) {\n console.error(\"[ApplePay] Failed to load Apple Pay SDK:\", err);\n return { success: false, error: \"Failed to load Apple Pay\" };\n }\n\n let canMake = false;\n try {\n canMake = !!window.ApplePaySession?.canMakePayments();\n } catch {\n canMake = false;\n }\n if (!canMake) {\n console.log(\"[ApplePay] Apple Pay not available on this device/browser\");\n return { success: false, error: \"Apple Pay not available on this device\" };\n }\n }\n\n // Fetch session info (amount, currency, country) from backend\n const sessionInfoResult = await callAirwallexSessionInfoEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n if (sessionInfoResult.error || !sessionInfoResult.data) {\n console.error(\"[ApplePay] Failed to fetch session info:\", sessionInfoResult.error);\n return { success: false, error: sessionInfoResult.error || \"Failed to fetch Apple Pay session info\" };\n }\n\n console.log(\"[ApplePay] Got session info:\", sessionInfoResult.data);\n const resolvedAmount = sessionInfoResult.data.amount;\n const resolvedCurrency = sessionInfoResult.data.currency;\n const resolvedCountry = sessionInfoResult.data.country || options.country;\n\n preparedAirwallexState = {\n country: resolvedCountry,\n currency: resolvedCurrency,\n amount: resolvedAmount,\n merchantName: options.merchantName,\n };\n console.log(\"[ApplePay] Airwallex prepared state:\", preparedAirwallexState);\n return { success: true, applePay: true };\n }\n\n // Call Stripe start endpoint to fetch stripe_pk + sheet display data\n const startResult = await callStripeStartEndpoint(apiBaseUrl, secureToken, options, checkoutRequestId);\n if (startResult.error || !startResult.data) {\n return { success: false, error: startResult.error || \"Failed to start Apple Pay\" };\n }\n\n const startData = startResult.data;\n\n // Initialize Stripe adapter\n if (!startData.stripe_pk) {\n return { success: false, error: \"Stripe publishable key not provided\" };\n }\n\n const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, options.mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Create PaymentRequest and call canMakePayment() (required before show())\n const prepareResult = await adapter.preparePaymentRequest({\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: {\n label: \"Total\",\n amount: startData.amount,\n },\n });\n\n if (!prepareResult.success) {\n return {\n success: false,\n error: prepareResult.error || \"Failed to prepare payment request\",\n applePay: prepareResult.applePay,\n };\n }\n\n if (!prepareResult.applePay) {\n return {\n success: false,\n error: \"Apple Pay is not available on this device or Stripe account\",\n applePay: false,\n };\n }\n\n // Store the prepared state\n preparedStripeState = {\n processor: \"stripe\",\n adapter,\n startData,\n mockScenarioStr,\n checkoutRequestId,\n };\n\n console.log(\"[ApplePay] prepareApplePay success (Stripe), ready for click\");\n return { success: true, applePay: true };\n}\n\n/**\n * Check if Apple Pay has been prepared and is ready.\n */\nexport function isApplePayPrepared(): boolean {\n return (preparedStripeState?.adapter.isPrepared() ?? false) || preparedAirwallexState !== null;\n}\n\n/**\n * Clear prepared state (call on unmount or when checkout changes).\n */\nexport function clearPreparedApplePay(): void {\n if (preparedStripeState) {\n preparedStripeState.adapter.clearPrepared();\n }\n preparedStripeState = null;\n preparedAirwallexState = null;\n}\n\n// =============================================================================\n// Airwallex Apple Pay Flow\n// =============================================================================\n\n/**\n * Fetch session info (amount, currency, country) from the backend.\n * Called during prepareApplePay to get the correct amount BEFORE showing the payment sheet.\n * This fixes the $0.00 bug where options.amount was undefined and defaulted to 0.\n */\nasync function callAirwallexSessionInfoEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<{ data?: AirwallexSessionInfoResponse; error?: string }> {\n return apiCall<AirwallexSessionInfoResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/session-info`,\n {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n checkoutRequestId,\n );\n}\n\nasync function callAirwallexStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n validationUrl: string,\n initiativeContext: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<{ data?: ApplePayStartResponse; error?: string }> {\n return apiCall<ApplePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/start`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n processor_id: options.processorId,\n customer_info: options.customerInfo,\n fraud_metadata: collectFraudMetadata(),\n validation_url: validationUrl,\n initiative_context: initiativeContext,\n mock_scenario: mockScenarioStr,\n } as ApplePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\nasync function callAirwallexConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n applePayToken: ApplePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n payerFirstName?: string,\n payerLastName?: string,\n): Promise<ApplePayConfirmResponse> {\n const result = await apiCall<ApplePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n apple_pay_token: applePayToken,\n payer_email: payerEmail,\n payer_first_name: payerFirstName,\n payer_last_name: payerLastName,\n mock_scenario: mockScenarioStr,\n } as ApplePayConfirmRequest),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message_for_debug: result.error || \"Failed to confirm payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\nasync function callAirwallexVerifyEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<ApplePayConfirmResponse> {\n const result = await apiCall<ApplePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/verify`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message_for_debug: result.error || \"Failed to verify payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\nfunction toApplePayResult(response: ApplePayConfirmResponse, secureToken: string): ApplePayResult {\n if (response.charge_status === \"success\") {\n return {\n data: {\n id: response.transaction_id,\n checkoutAttemptId: response.checkout_attempt_id,\n checkoutSessionId: response.checkout_session_id ?? secureToken,\n state: \"checkout_succeeded\",\n paymentIntentId: response.payment_intent_id,\n customerId: response.customer_id,\n paymentMethodId: response.payment_method_id,\n processorUsed: response.processor_used,\n subscriptionId: response.subscription_id,\n invoiceId: response.invoice_id,\n invoiceNumber: response.invoice_number,\n cardBrand: response.card_brand,\n cardLast4: response.card_last4,\n cardExpMonth: response.card_exp_month,\n cardExpYear: response.card_exp_year,\n errorCode: response.error_code,\n errorMessageForCustomer: response.error_message_for_customer,\n errorMessageForDebug: response.error_message_for_debug,\n nextAction: response.next_action,\n },\n };\n }\n return {\n errors: {\n apple_pay: response.error_message_for_customer || response.error_message_for_debug || \"Payment failed\",\n },\n };\n}\n\nconst MAX_USER_ACTIONS = 5;\n\n/**\n * Run the Airwallex Apple Pay flow with 3DS loop support.\n *\n * Flow:\n * 1. Show native ApplePaySession, call /start for merchant validation\n * 2. On payment authorized, call /confirm with token\n * 3. If 3DS required, handle it and call /verify\n * 4. Loop if more 3DS needed\n */\nasync function runAirwallexFlow(\n apiBaseUrl: string,\n secureToken: string,\n options: ApplePaySubmitOptions,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<ApplePayResult> {\n // Convert mock scenario\n let airwallexMockScenario: AirwallexApplePayMockScenario = AirwallexApplePayMockScenario.None;\n if (options.mockScenario === ApplePayMockScenario.Success) {\n airwallexMockScenario = AirwallexApplePayMockScenario.Success;\n } else if (options.mockScenario === ApplePayMockScenario.Cancelled) {\n airwallexMockScenario = AirwallexApplePayMockScenario.Cancelled;\n }\n\n // Defense-in-depth: validateOptions should catch this earlier, but guard against\n // future callers that bypass validation to avoid an unhandled TypeError on `.toUpperCase()`\n if (!options.country) {\n return { errors: { apple_pay: \"Country is required for Airwallex Apple Pay\" } };\n }\n\n // Auto-fetch amount from session if not provided (e.g. merchant didn't call prepareApplePay first)\n if (!options.amount) {\n const sessionInfoResult = await callAirwallexSessionInfoEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n if (sessionInfoResult.data) {\n options.amount = sessionInfoResult.data.amount;\n options.currency = options.currency || sessionInfoResult.data.currency;\n options.country = options.country || sessionInfoResult.data.country;\n }\n }\n\n // Initialize adapter\n const adapter = new AirwallexApplePayAdapter(airwallexMockScenario);\n\n const config: AirwallexApplePayConfig = {\n amount: options.amount || 0,\n currency: (options.currency || \"USD\").toUpperCase(),\n country: options.country.toUpperCase(),\n merchantName: options.merchantName || \"Total\",\n };\n\n if (!adapter.initialize(config)) {\n return { errors: { apple_pay: \"Apple Pay not available on this device\" } };\n }\n\n const canPay = await adapter.canMakePayment();\n if (!canPay) {\n return { errors: { apple_pay: \"Apple Pay not available on this device\" } };\n }\n\n // Get current domain for initiative_context\n const initiativeContext = typeof window !== \"undefined\" ? window.location.hostname : \"\";\n\n // In mock mode, call /start first to create checkout attempt (mock adapter skips merchant validation)\n if (airwallexMockScenario !== AirwallexApplePayMockScenario.None) {\n const startResult = await callAirwallexStartEndpoint(\n apiBaseUrl,\n secureToken,\n options,\n \"https://mock-apple-pay-gateway.example.com/paymentservices/startSession\",\n initiativeContext,\n mockScenarioStr,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { errors: { apple_pay: startResult.error || \"Failed to start mock checkout\" } };\n }\n }\n\n // Show Apple Pay sheet with merchant validation callback\n const paymentResult = await adapter.showPaymentSheet(async (validationUrl: string) => {\n // Call /start endpoint for merchant validation\n const startResult = await callAirwallexStartEndpoint(\n apiBaseUrl,\n secureToken,\n options,\n validationUrl,\n initiativeContext,\n mockScenarioStr,\n checkoutRequestId,\n );\n\n if (startResult.error || !startResult.data) {\n return { error: startResult.error || \"Merchant validation failed\" };\n }\n\n if (!startResult.data.merchant_session) {\n return { error: \"No merchant session returned from server\" };\n }\n\n return { merchantSession: startResult.data.merchant_session };\n });\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { errors: { apple_pay: \"Apple Pay cancelled by user\" } };\n }\n return { errors: { apple_pay: paymentResult.error || \"Apple Pay failed\" } };\n }\n\n const { token, complete, payerEmail, payerFirstName, payerLastName } = paymentResult;\n\n // Call /confirm with the token\n let response = await callAirwallexConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n token,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n payerFirstName,\n payerLastName,\n );\n\n // Handle 3DS loop\n let userActionCount = 0;\n while (response.charge_status === \"pending\" && response.next_action && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n\n // Handle 3DS challenge — Airwallex3dsNextAction is structurally identical to SDK's Airwallex3dsAction\n const nextAction = response.next_action as Airwallex3dsNextAction;\n const actionResult = await handleNextAction({ type: nextAction.type, url: nextAction.url });\n\n // Call verify endpoint\n const verifyResponse = await callAirwallexVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n // Check if another 3DS action is required\n if (verifyResponse.charge_status === \"pending\" && verifyResponse.next_action) {\n if (!actionResult.success) {\n console.log(\"[ApplePay:Airwallex] 3DS failed but retry available, continuing loop...\");\n }\n response = verifyResponse;\n continue;\n }\n\n // No more actions - check final result\n if (!actionResult.success) {\n complete(\"fail\");\n return {\n errors: {\n apple_pay:\n verifyResponse.error_message_for_customer ||\n verifyResponse.error_message_for_debug ||\n actionResult.error ||\n \"3DS authentication failed\",\n },\n };\n }\n\n // 3DS succeeded\n complete(verifyResponse.charge_status === \"success\" ? \"success\" : \"fail\");\n return toApplePayResult(verifyResponse, secureToken);\n }\n\n // Check for max attempts exceeded\n if (userActionCount >= MAX_USER_ACTIONS) {\n complete(\"fail\");\n return { errors: { apple_pay: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // No 3DS required - complete with result\n complete(response.charge_status === \"success\" ? \"success\" : \"fail\");\n return toApplePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Main Submit Function\n// =============================================================================\n\nconst defSubmitPayment = (\n states: PaymentKitStates,\n getAutoPrepareConfig: () => AutoPrepareConfig | null,\n onClearPrepared: () => void,\n) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n const { apiBaseUrl, secureToken, environment } = states;\n const applePayOptions = options as ApplePaySubmitOptions;\n\n // Fill in processorId/processorType from auto-prepare config if merchant didn't provide them\n const autoPrepareConfig = getAutoPrepareConfig();\n if (!applePayOptions.processorId && autoPrepareConfig?.processorId) {\n applePayOptions.processorId = autoPrepareConfig.processorId;\n }\n if (!applePayOptions.processorType && autoPrepareConfig?.processorType) {\n applePayOptions.processorType = autoPrepareConfig.processorType;\n }\n\n // Validate options\n const validationError = validateOptions(applePayOptions);\n if (validationError) {\n return { errors: validationError };\n }\n\n try {\n const mockScenarioStr = getMockScenarioStr(applePayOptions.mockScenario);\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[ApplePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Check if we have prepared Stripe state\n if (preparedStripeState?.adapter.isPrepared()) {\n console.log(\"[ApplePay] Using prepared Stripe state for immediate sheet display\");\n\n // Show Apple Pay sheet IMMEDIATELY using the prepared PaymentRequest\n const paymentResultPromise = preparedStripeState.adapter.showPreparedPaymentSheet();\n const paymentResult = await paymentResultPromise;\n\n if (!paymentResult.success) {\n clearPreparedApplePay();\n\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { errors: { apple_pay: \"Apple Pay cancelled by user\" } };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { errors: { apple_pay: errorMessage } };\n }\n\n const { paymentMethodId, paymentMethodEvent, billingDetails } = paymentResult;\n\n // Confirm with backend using the PaymentMethod ID\n const confirmResult = await callStripeConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n applePayOptions,\n paymentMethodId,\n mockScenarioStr,\n preparedStripeState.checkoutRequestId,\n billingDetails?.email,\n );\n\n // Complete Apple Pay UI based on result\n if (confirmResult.data) {\n paymentMethodEvent.complete(\"success\");\n clearPreparedApplePay();\n return confirmResult;\n } else {\n paymentMethodEvent.complete(\"fail\");\n clearPreparedApplePay();\n return confirmResult;\n }\n }\n\n // Check if this is an Airwallex processor - route directly to Airwallex flow\n if (applePayOptions.processorType === \"airwallex\") {\n console.log(\"[ApplePay] Running Airwallex flow (processorType=airwallex)\");\n // Merge prepare-time state into submit options so country/currency/amount/merchantName\n // are available even if the merchant only provided them at prepare time\n if (preparedAirwallexState) {\n if (applePayOptions.country == null) applePayOptions.country = preparedAirwallexState.country;\n if (applePayOptions.currency == null) applePayOptions.currency = preparedAirwallexState.currency;\n if (applePayOptions.amount == null) applePayOptions.amount = preparedAirwallexState.amount;\n if (applePayOptions.merchantName == null) applePayOptions.merchantName = preparedAirwallexState.merchantName;\n }\n try {\n return await runAirwallexFlow(apiBaseUrl, secureToken, applePayOptions, mockScenarioStr, checkoutRequestId);\n } finally {\n preparedAirwallexState = null;\n }\n }\n\n // No prepared state for Stripe - call start endpoint\n const startResult = await callStripeStartEndpoint(apiBaseUrl, secureToken, applePayOptions, checkoutRequestId);\n\n if (startResult.error || !startResult.data) {\n return { errors: { apple_pay: startResult.error || \"Failed to start Apple Pay\" } };\n }\n\n const startData = startResult.data;\n\n // Stripe flow without prepared state - this may fail due to user gesture requirements\n console.warn(\"[ApplePay] Stripe flow without prepared state - may fail due to user gesture requirements\");\n\n if (!startData.stripe_pk) {\n return { errors: { apple_pay: \"Stripe publishable key not provided\" } };\n }\n\n const { adapter, error: adapterError } = initializeStripeAdapter(\n startData.stripe_pk,\n applePayOptions.mockScenario,\n );\n if (!adapter) {\n return { errors: { apple_pay: adapterError || \"Failed to initialize Stripe adapter\" } };\n }\n\n // This will likely fail due to user gesture requirements\n const prepareResult = await adapter.preparePaymentRequest({\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: { label: \"Total\", amount: startData.amount },\n });\n\n if (!prepareResult.success || !prepareResult.applePay) {\n return { errors: { apple_pay: prepareResult.error || \"Apple Pay not available\" } };\n }\n\n const paymentResult = await adapter.showPreparedPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { errors: { apple_pay: \"Apple Pay cancelled by user\" } };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { errors: { apple_pay: errorMessage } };\n }\n\n const { paymentMethodId, paymentMethodEvent, billingDetails } = paymentResult;\n\n const confirmResult = await callStripeConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n applePayOptions,\n paymentMethodId,\n mockScenarioStr,\n checkoutRequestId,\n billingDetails?.email,\n );\n\n if (confirmResult.data) {\n paymentMethodEvent.complete(\"success\");\n return confirmResult;\n } else {\n paymentMethodEvent.complete(\"fail\");\n return confirmResult;\n }\n } catch (error) {\n onClearPrepared();\n return { errors: { apple_pay: `Apple Pay error: ${error}` } };\n }\n };\n\n return submitPayment;\n};\n\n// =============================================================================\n// Payment Method Definition\n// =============================================================================\n\nconst ApplePayPaymentMethod = definePaymentMethod((paymentKitStates) => {\n const { apiBaseUrl, secureToken, environment } = paymentKitStates;\n\n // Per-instance auto-prepare state — isolated from other ApplePayPaymentMethod instances.\n // Note: preparedStripeState and preparedAirwallexState remain module-level globals (pre-existing\n // architectural constraint shared across the file). Full per-instance isolation for those fields\n // would require threading them through prepareApplePay, runAirwallexFlow, validateOptions, and\n // defSubmitPayment — tracked as tech debt.\n let autoPrepareConfig: AutoPrepareConfig | null = null;\n let onApplePayReadyCallbacks: ((isReady: boolean) => void)[] = [];\n let isApplePayReadyState = false;\n let autoPrepareInProgress = false;\n // Incremented by cleanup() so that in-flight prepares can detect staleness and skip writes.\n let cleanupGeneration = 0;\n // Stores pending retry args when notifyAmountChanged is called while a prepare is in flight.\n let pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: PaymentKitEnvironment } | null =\n null;\n // Resolvers waiting for a queued retry to complete (for correct notifyAmountChanged await).\n let pendingPrepareResolvers: (() => void)[] = [];\n\n function instanceSetApplePayReady(ready: boolean): void {\n isApplePayReadyState = ready;\n for (const cb of onApplePayReadyCallbacks) cb(ready);\n }\n\n function instanceClearPreparedApplePay(): void {\n clearPreparedApplePay();\n instanceSetApplePayReady(false);\n }\n\n async function instanceAutoPrepare(apBase: string, sToken: string, env: PaymentKitEnvironment): Promise<void> {\n if (autoPrepareInProgress) {\n // A prepare is already in flight; queue a retry and return a promise that resolves after it.\n pendingAutoPrepareArgs = { apiBaseUrl: apBase, secureToken: sToken, environment: env };\n return new Promise<void>((resolve) => pendingPrepareResolvers.push(resolve));\n }\n autoPrepareInProgress = true;\n // Capture generation so we can detect if cleanup() is called while we await.\n const capturedGeneration = cleanupGeneration;\n instanceSetApplePayReady(false);\n\n try {\n const result = await apiCall<CheckoutSessionConfig>(`${apBase}/api/checkout-sessions/token/${sToken}`, {\n method: \"GET\",\n });\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n if (result.error || !result.data) {\n console.warn(\"[ApplePay] Auto-prepare: failed to fetch session config:\", result.error);\n return;\n }\n\n const processorId = result.data.express_checkout_processor_id;\n if (!processorId) {\n console.log(\"[ApplePay] Auto-prepare: no express checkout processor configured\");\n return;\n }\n\n const processorTypeRaw = result.data.express_checkout_processor_type;\n const processorType =\n processorTypeRaw === \"airwallex\" || processorTypeRaw === \"stripe\" ? processorTypeRaw : undefined;\n\n autoPrepareConfig = { processorId, processorType };\n\n const prepareResult = await prepareApplePay(\n apBase,\n sToken,\n { processorId, processorType, customerInfo: { first_name: \"\", last_name: \"\" } },\n env,\n );\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n instanceSetApplePayReady(prepareResult.success && prepareResult.applePay === true);\n } catch (err) {\n if (cleanupGeneration === capturedGeneration) {\n console.error(\"[ApplePay] Auto-prepare failed:\", err);\n }\n } finally {\n autoPrepareInProgress = false;\n const stale = cleanupGeneration !== capturedGeneration;\n const pending = pendingAutoPrepareArgs;\n const resolvers = pendingPrepareResolvers.splice(0);\n if (!stale && pending) {\n pendingAutoPrepareArgs = null;\n // Run the retry and resolve all callers that were waiting for it.\n instanceAutoPrepare(pending.apiBaseUrl, pending.secureToken, pending.environment).then(() => {\n for (const r of resolvers) r();\n });\n } else {\n pendingAutoPrepareArgs = null;\n for (const r of resolvers) r();\n }\n }\n }\n\n // Start auto-prepare immediately so the button is ready before first user interaction.\n instanceAutoPrepare(apiBaseUrl, secureToken, environment).catch((err) =>\n console.error(\"[ApplePay] Unhandled init error:\", err),\n );\n\n return {\n name: \"apple_pay\",\n externalFuncs: {\n /**\n * @deprecated The SDK now prepares automatically on init. Use `onApplePayReady` to observe\n * readiness and `notifyAmountChanged` to trigger re-prepare after amount changes.\n */\n prepareApplePay: (options: ApplePaySubmitOptions) =>\n prepareApplePay(apiBaseUrl, secureToken, options, environment),\n\n /**\n * Register a callback to be notified when Apple Pay becomes ready (or stops being ready).\n * Fires immediately with the current state, then on every state change.\n * Multiple registrations are all notified — none are silently overwritten.\n *\n * @example\n * paymentKit.apple_pay.onApplePayReady((isReady) => {\n * applePayButton.disabled = !isReady;\n * });\n */\n onApplePayReady: (callback: (isReady: boolean) => void): void => {\n onApplePayReadyCallbacks.push(callback);\n // Fire immediately with current state so caller doesn't miss a completed prepare.\n callback(isApplePayReadyState);\n },\n\n /**\n * Notify the SDK that the payment amount has changed (e.g. coupon applied).\n * The SDK will disable Apple Pay, re-prepare with the new amount, then re-enable.\n * The returned promise resolves when re-prepare is fully complete.\n *\n * @example\n * await paymentKit.apple_pay.notifyAmountChanged();\n */\n notifyAmountChanged: (): Promise<void> => {\n instanceClearPreparedApplePay();\n autoPrepareConfig = null;\n return instanceAutoPrepare(apiBaseUrl, secureToken, environment);\n },\n },\n internalFuncs: {\n submitPayment: defSubmitPayment(paymentKitStates, () => autoPrepareConfig, instanceClearPreparedApplePay),\n cleanup: () => {\n cleanupGeneration++;\n onApplePayReadyCallbacks = [];\n isApplePayReadyState = false;\n autoPrepareConfig = null;\n pendingAutoPrepareArgs = null;\n pendingPrepareResolvers = [];\n autoPrepareInProgress = false;\n clearPreparedApplePay();\n },\n },\n };\n});\n\nexport { ApplePayMockScenario };\n\nexport default ApplePayPaymentMethod;\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../types-
|
|
1
|
+
import "../types-Cjcc3xak.mjs";
|
|
2
2
|
import "../connect-card-CZhzK_Tp.mjs";
|
|
3
3
|
import "../connect-tunnel-x-BKtMfoGh.mjs";
|
|
4
|
-
import { a as BnplStartResponse, c as createBnplPaymentMethod, i as BnplStartRequest, n as BnplCustomerInfo, o as BnplStatusResponse, r as BnplProviderConfig, s as BnplSubmitOptions, t as BnplCheckoutResponse } from "../bnpl-shared-
|
|
4
|
+
import { a as BnplStartResponse, c as createBnplPaymentMethod, i as BnplStartRequest, n as BnplCustomerInfo, o as BnplStatusResponse, r as BnplProviderConfig, s as BnplSubmitOptions, t as BnplCheckoutResponse } from "../bnpl-shared-D-Kd58Qz.mjs";
|
|
5
5
|
export { BnplCheckoutResponse, BnplCustomerInfo, BnplProviderConfig, BnplStartRequest, BnplStartResponse, BnplStatusResponse, BnplSubmitOptions, createBnplPaymentMethod };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as PaymentMethod } from "../types-Cjcc3xak.mjs";
|
|
2
2
|
import { n as CardInputType$1, o as connectToCardIframe, r as CheckoutResponse$1 } from "../connect-card-CZhzK_Tp.mjs";
|
|
3
3
|
import "../connect-tunnel-x-BKtMfoGh.mjs";
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.d.mts","names":[],"sources":["../../src/payment-methods/card.ts"],"sourcesContent":[],"mappings":";;;;;KAQY,aAAA,GAAgB;KAChB,gBAAA,GAAmB;KAsG1B,oBAAA,GAAuB,QAAQ,kBAAkB;UAC5C;EAxGE,WAAA,CAAA,EAAA,MAAa;AACzB,CAAA;AAAsD,
|
|
1
|
+
{"version":3,"file":"card.d.mts","names":[],"sources":["../../src/payment-methods/card.ts"],"sourcesContent":[],"mappings":";;;;;KAQY,aAAA,GAAgB;KAChB,gBAAA,GAAmB;KAsG1B,oBAAA,GAAuB,QAAQ,kBAAkB;UAC5C;EAxGE,WAAA,CAAA,EAAA,MAAa;AACzB,CAAA;AAAsD,cAu0BhD,iBAjuBmB,EAQyC,aARzC,CAAA;EAA6B,aAAA,EAAA,CAAA,IAAA,EAQtC,eARsC,EAAA,OAAA,EAQR,oBARQ,EAAA,GAAA;IAAlB,KAAA,EAAA,CAAA,cAAA,EAAA,MAAA,EAAA,GAAA;MAAR,OAAA,EAAA,GAAA,GAAA,IAAA;IAClB,CAAA;EAAM,CAAA;AAAA,CAAA,EAAA,MAguBV,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as AnalyticsService } from "../analytics-Blvs2DW7.mjs";
|
|
2
2
|
import "../penpal-CBrj43M5.mjs";
|
|
3
3
|
import { t as TunnelXManager } from "../connect-tunnel-x-5XOct5Tm.mjs";
|
|
4
|
-
import { a as validateFormFields, i as definePaymentMethod, n as collectFraudMetadata, r as createCheckoutIFrame, s as withRequestId, t as $ } from "../utils-
|
|
5
|
-
import { t as handleNextAction } from "../next-action-handlers-
|
|
4
|
+
import { a as validateFormFields, i as definePaymentMethod, n as collectFraudMetadata, r as createCheckoutIFrame, s as withRequestId, t as $ } from "../utils-DIqrx4XF.mjs";
|
|
5
|
+
import { t as handleNextAction } from "../next-action-handlers-BZ5gynXe.mjs";
|
|
6
6
|
import { t as connectToCardIframe } from "../connect-card-kXLdSNTL.mjs";
|
|
7
7
|
import { n as initVgsCollect, r as loadVgsCollectScript, t as createVgsCardFields } from "../vgs-collect-loader-CTLSv4qv.mjs";
|
|
8
8
|
|
|
@@ -198,7 +198,10 @@ const defSubmitPayment = (states) => {
|
|
|
198
198
|
timingTracker.trackSubmit();
|
|
199
199
|
const requestOptions = withRequestId(checkoutRequestId);
|
|
200
200
|
const tunnelX = await TunnelXManager.createFromPenpalConnection(states.tunnelXConnection);
|
|
201
|
-
const validateFormResult = options?.skipCustomerValidation === true ? {
|
|
201
|
+
const validateFormResult = options?.skipCustomerValidation === true ? {
|
|
202
|
+
isSuccess: true,
|
|
203
|
+
errors: {}
|
|
204
|
+
} : await validateFormFields(fields);
|
|
202
205
|
if (!isVgsMode) {
|
|
203
206
|
const validateCardResult = await validateCardFields(states);
|
|
204
207
|
if (!(validateCardResult.isSuccess && validateFormResult.isSuccess)) {
|
|
@@ -477,6 +480,7 @@ const submitVgsCardFields = async (states, tunnelX) => {
|
|
|
477
480
|
};
|
|
478
481
|
}
|
|
479
482
|
const { pan_alias, cvc_alias, exp_month, exp_year } = cardResult.data.attributes;
|
|
483
|
+
if (!cvc_alias) console.warn(`${logPrefix} VGS createCard response missing cvc_alias (303 dedup):`, JSON.stringify(cardResult.data.attributes));
|
|
480
484
|
const fullYear = exp_year < 100 ? 2e3 + exp_year : exp_year;
|
|
481
485
|
const formattedExp = `${String(exp_month).padStart(2, "0")}/${fullYear}`;
|
|
482
486
|
const cmpCardId = cardResult.data.id;
|
|
@@ -487,7 +491,7 @@ const submitVgsCardFields = async (states, tunnelX) => {
|
|
|
487
491
|
updateCardSetupIntentReq: {
|
|
488
492
|
cardPan: pan_alias,
|
|
489
493
|
cardExp: formattedExp,
|
|
490
|
-
cardCvc: cvc_alias,
|
|
494
|
+
...cvc_alias ? { cardCvc: cvc_alias } : {},
|
|
491
495
|
cmpCardId,
|
|
492
496
|
fraudMetadata: collectFraudMetadata()
|
|
493
497
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.mjs","names":["taxIds: string[] | undefined","cleanupVgs: (() => void) | undefined","cleanupDirect: (() => void) | undefined","cdnTimeoutId: ReturnType<typeof setTimeout>","params: Record<string, string>","submitPayment: TInternalFuncs[\"submitPayment\"]","VGS_FIELD_MAP: Record<string, keyof PaymentKitErrors>","accessToken: string","cardResult: VGSCreateCardResponse","createCardTimeoutId: ReturnType<typeof setTimeout>","errors: PaymentKitErrors"],"sources":["../../src/payment-methods/card.ts"],"sourcesContent":["import {\n connectToCardIframe,\n type IFrameConnection,\n type CardInputType as PenpalCardInputType,\n type CheckoutResponse as PenpalCheckoutResponse,\n} from \"../penpal/connect-card\";\n\n// Re-export types for public API\nexport type CardInputType = PenpalCardInputType;\nexport type CheckoutResponse = PenpalCheckoutResponse;\n\nimport { AnalyticsService } from \"../analytics\";\nimport { TunnelXManager } from \"../penpal/connect-tunnel-x\";\nimport type { PaymentKitErrors, PaymentKitFields, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport {\n $,\n collectFraudMetadata,\n createCheckoutIFrame,\n definePaymentMethod,\n validateFormFields,\n withRequestId,\n} from \"../utils\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { createVgsCardFields, initVgsCollect, loadVgsCollectScript } from \"./vgs-collect-loader\";\n\n/**\n * Splits a full name into first name and last name.\n * First word becomes firstName, rest becomes lastName.\n */\nconst splitName = (fullName: string): { firstName: string; lastName?: string } => {\n const trimmed = fullName.trim();\n const spaceIndex = trimmed.indexOf(\" \");\n if (spaceIndex === -1) {\n return { firstName: trimmed };\n }\n return {\n firstName: trimmed.substring(0, spaceIndex),\n lastName: trimmed.substring(spaceIndex + 1).trim() || undefined,\n };\n};\n\n/**\n * Maps PaymentKitFields to the customerInfo structure expected by the API.\n */\nconst mapFieldsToCustomerInfo = (fields: PaymentKitFields) => {\n const { firstName, lastName } = splitName(fields.customer_name);\n\n const hasBillingAddress =\n fields.customer_country ||\n fields.customer_zip_code ||\n fields.customer_address_line1 ||\n fields.customer_address_line2 ||\n fields.customer_city ||\n fields.customer_state;\n\n const hasShippingAddress =\n fields.shipping_address_line1 ||\n fields.shipping_address_line2 ||\n fields.shipping_city ||\n fields.shipping_state ||\n fields.shipping_zip_code ||\n fields.shipping_country;\n\n let taxIds: string[] | undefined;\n if (fields.customer_tax_ids) {\n try {\n taxIds = JSON.parse(fields.customer_tax_ids);\n } catch {\n taxIds = undefined;\n }\n }\n\n return {\n email: fields.customer_email || undefined,\n firstName,\n lastName,\n businessName: fields.customer_business_name || undefined,\n taxIds: taxIds?.length ? taxIds : undefined,\n billingAddress: hasBillingAddress\n ? {\n country: fields.customer_country || undefined,\n zipCode: fields.customer_zip_code || undefined,\n line1: fields.customer_address_line1 || undefined,\n line2: fields.customer_address_line2 || undefined,\n city: fields.customer_city || undefined,\n state: fields.customer_state || undefined,\n }\n : undefined,\n shippingAddress: hasShippingAddress\n ? {\n line1: fields.shipping_address_line1 || undefined,\n line2: fields.shipping_address_line2 || undefined,\n city: fields.shipping_city || undefined,\n state: fields.shipping_state || undefined,\n zipCode: fields.shipping_zip_code || undefined,\n country: fields.shipping_country || undefined,\n }\n : undefined,\n };\n};\n\ntype CardStates = PaymentKitStates & {\n cardSetupIntentId?: string;\n cardInputConnections: Partial<Record<PenpalCardInputType, IFrameConnection>>;\n vgsForm?: VGSCollectForm;\n vgsFieldsCleanup?: () => void;\n vgsFocusCallbacks?: Partial<Record<PenpalCardInputType, (isFocused: boolean) => void>>;\n vgsMountSelectors?: Partial<Record<PenpalCardInputType, string>>;\n vgsPlaceholders?: Partial<Record<PenpalCardInputType, string>>;\n};\n\ntype CreateElementOptions = Partial<Parameters<typeof connectToCardIframe>[1]> & {\n style?: Record<string, string>;\n placeholder?: string;\n};\n\nconst defCreateElement = (states: CardStates) => {\n const { baseUrl, apiBaseUrl, cardInputConnections, secureToken, timingTracker } = states;\n\n return (type: PenpalCardInputType, options: CreateElementOptions) => {\n const { style, onLoaded, onFocusChange, placeholder } = options;\n\n const mountIFrame = (parentSelector: string) => {\n // Mutable cleanup callbacks — set once mode is determined and mount completes\n let cleanupVgs: (() => void) | undefined;\n let cleanupDirect: (() => void) | undefined;\n // Cancellation flag: prevents deferred doMount from executing after unmount.\n // Needed because React strict mode may call unmount before the deferred\n // _sessionConfigReady promise resolves.\n let cancelled = false;\n\n /**\n * Performs the actual DOM mount after the tokenization mode is known.\n * Runs synchronously when mode is explicitly provided, or after the\n * auto-detect fetch resolves.\n */\n // Store mount selector so VGS init (triggered by card_pan) can read\n // the exp/cvc selectors that were registered by their own createElement calls.\n if (!states.vgsMountSelectors) states.vgsMountSelectors = {};\n states.vgsMountSelectors[type] = parentSelector;\n\n const doMount = () => {\n if (cancelled) return;\n const isVgsMode = states.cardTokenizationMode === \"vgs\";\n console.log(\n `[PaymentKit] card.doMount(${type}) — mode: ${states.cardTokenizationMode}, vgsVaultId: ${states.vgsVaultId ?? \"unset\"}, vgsEnvironment: ${states.vgsEnvironment ?? \"unset\"}`,\n );\n\n // VGS mode: initialize VGS Collect form and mount fields on card_pan\n if (isVgsMode && states.vgsVaultId && states.vgsEnvironment) {\n // Store per-field focus callbacks and placeholders so createVgsCardFields\n // can wire each field to its own callback/placeholder. All three createElement\n // calls complete before the CDN script loads, so all values are available by then.\n if (onFocusChange) {\n if (!states.vgsFocusCallbacks) states.vgsFocusCallbacks = {};\n states.vgsFocusCallbacks[type] = onFocusChange;\n }\n if (placeholder) {\n if (!states.vgsPlaceholders) states.vgsPlaceholders = {};\n states.vgsPlaceholders[type] = placeholder;\n }\n\n if (type === \"card_pan\") {\n const vaultId = states.vgsVaultId;\n const vgsEnv = states.vgsEnvironment;\n\n console.log(`[PaymentKit] VGS mode active — loading VGS Collect CDN for vault ${vaultId} (${vgsEnv})...`);\n const VGS_CDN_TIMEOUT_MS = 15_000;\n let cdnTimeoutId: ReturnType<typeof setTimeout>;\n Promise.race([\n loadVgsCollectScript(),\n new Promise<never>((_, reject) => {\n cdnTimeoutId = setTimeout(() => {\n console.warn(`[PaymentKit] VGS Collect CDN load timed out after ${VGS_CDN_TIMEOUT_MS / 1000}s`);\n reject(new Error(\"VGS Collect CDN load timed out\"));\n }, VGS_CDN_TIMEOUT_MS);\n }),\n ])\n .finally(() => clearTimeout(cdnTimeoutId))\n .then(() => {\n if (cancelled) return;\n console.log(\"[PaymentKit] VGS Collect CDN loaded — initializing form...\");\n const form = initVgsCollect(vaultId, vgsEnv);\n if (cancelled) {\n form.unmount();\n return;\n }\n states.vgsForm = form;\n\n const css = style\n ? Object.fromEntries(\n Object.entries(style).map(([k, v]) => [k.replace(/([A-Z])/g, \"-$1\").toLowerCase(), v]),\n )\n : undefined;\n\n // Read exp/cvc selectors from shared state.\n // Each createElement(\"card_exp/card_cvc\").mount(selector) stores its\n // selector before this async callback runs, so they're available here.\n const expSelector = states.vgsMountSelectors?.card_exp;\n const cvcSelector = states.vgsMountSelectors?.card_cvc;\n if (!expSelector || !cvcSelector) {\n const msg =\n `[PaymentKit] VGS mode requires all three card fields to be mounted. ` +\n `Missing: ${!expSelector ? \"card_exp\" : \"\"}${!expSelector && !cvcSelector ? \", \" : \"\"}${!cvcSelector ? \"card_cvc\" : \"\"}`;\n console.error(msg);\n onLoaded?.();\n return;\n }\n console.log(\n `[PaymentKit] Creating VGS card fields — pan: ${parentSelector}, exp: ${expSelector}, cvc: ${cvcSelector}`,\n );\n states.vgsFieldsCleanup = createVgsCardFields(\n form,\n {\n pan: parentSelector,\n exp: expSelector,\n cvc: cvcSelector,\n },\n css,\n states.vgsFocusCallbacks,\n states.vgsPlaceholders,\n );\n\n console.log(\"[PaymentKit] VGS card fields created successfully\");\n timingTracker.trackInputReady();\n onLoaded?.();\n })\n .catch((err) => {\n console.error(\"[PaymentKit] Failed to load VGS Collect script. Card input will not be available:\", err);\n // Signal loaded so the form exits loading state rather than hanging forever.\n // Card fields won't render, but submit will fail with a clear error.\n onLoaded?.();\n });\n }\n\n // For non-pan fields in VGS mode, signal loaded immediately since\n // VGS handles all three fields from the card_pan mount.\n if (type !== \"card_pan\") {\n onLoaded?.();\n }\n\n cleanupVgs = () => {\n if (type === \"card_pan\" && states.vgsForm) {\n try {\n states.vgsFieldsCleanup?.();\n } catch {\n // VGS may try to remove iframes from containers already removed by React\n }\n states.vgsFieldsCleanup = undefined;\n try {\n states.vgsForm.unmount();\n } catch {\n // VGS unmount may fail if DOM nodes are already detached\n }\n states.vgsForm = undefined;\n }\n };\n return;\n }\n\n // If we got here and mode was \"vgs\", it means VGS config was incomplete\n if (isVgsMode) {\n console.warn(\n `[PaymentKit] VGS mode requested but config incomplete (vgsVaultId: ${states.vgsVaultId ?? \"unset\"}, vgsEnvironment: ${states.vgsEnvironment ?? \"unset\"}) — using direct mode`,\n );\n }\n\n // Direct mode: existing penpal iframe logic\n const parent = $(parentSelector) as HTMLElement;\n\n // Read container padding so the embed input matches the merchant's\n // visual intent. The iframe uses absolute positioning to fill the\n // full container, so the input needs its own padding for alignment.\n const computed = getComputedStyle(parent);\n const containerPadding = computed.padding !== \"0px\" ? computed.padding : undefined;\n const enhancedStyle = {\n ...(style ?? {}),\n height: \"100%\",\n boxSizing: \"border-box\",\n ...(containerPadding ? { padding: containerPadding } : {}),\n };\n\n const params: Record<string, string> = {\n checkout_token: secureToken,\n api_base_url: apiBaseUrl,\n style: JSON.stringify(enhancedStyle),\n };\n\n const iframe = createCheckoutIFrame(type.replace(\"_\", \"-\"), baseUrl, params);\n\n // Use absolute positioning so the iframe covers the full container\n // including any padding the merchant's CSS applies.\n if (computed.position === \"static\") {\n parent.style.position = \"relative\";\n }\n iframe.style.position = \"absolute\";\n iframe.style.inset = \"0\";\n\n // Set cleanup before DOM mutation to avoid leaking the iframe if\n // unmount() is called between appendChild and onload.\n cleanupDirect = () => {\n const connection = cardInputConnections[type];\n connection?.destroy();\n try {\n parent.removeChild(iframe);\n } catch {\n // Parent may already be detached from DOM by React\n }\n states.cardInputConnections[type] = undefined;\n };\n\n parent.appendChild(iframe);\n\n iframe.onload = () => {\n if (type === \"card_pan\") {\n timingTracker.trackInputReady();\n }\n\n const connection = connectToCardIframe(iframe, {\n onLoaded: onLoaded || (() => {}),\n onFocusChange: onFocusChange || (() => {}),\n });\n\n states.cardInputConnections[type] = connection;\n };\n };\n\n // If session config needs auto-detection, wait for it; otherwise mount synchronously\n if (states._sessionConfigReady) {\n states._sessionConfigReady.then(doMount);\n } else {\n doMount();\n }\n\n return {\n unmount: () => {\n cancelled = true;\n cleanupVgs?.();\n cleanupDirect?.();\n },\n };\n };\n\n return { mount: mountIFrame };\n };\n};\n\nconst defSubmitPayment = (states: CardStates) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (fields, options) => {\n // Ensure session config is loaded (no-op if explicitly provided)\n if (states._sessionConfigReady) await states._sessionConfigReady;\n const isVgsMode = states.cardTokenizationMode === \"vgs\";\n\n const { timingTracker, checkoutRequestId } = states;\n\n // Track submit event\n timingTracker.trackSubmit();\n\n // Use the checkout request ID from states (generated on page load)\n const requestOptions = withRequestId(checkoutRequestId);\n\n const tunnelX = await TunnelXManager.createFromPenpalConnection(states.tunnelXConnection);\n\n // Step 1. Validate form values.\n // Form field validation is shared across both modes.\n // In VGS mode, card field validation is handled by VGS Collect (built-in validators).\n // In direct mode, card field validation is handled by penpal iframes.\n const skipCustomerValidation = options?.skipCustomerValidation === true;\n const validateFormResult = skipCustomerValidation ? { isSuccess: true as const } : await validateFormFields(fields);\n if (!isVgsMode) {\n const validateCardResult = await validateCardFields(states);\n if (!(validateCardResult.isSuccess && validateFormResult.isSuccess)) {\n timingTracker.trackFail(null, \"validation_error\", \"Form validation failed\");\n return { errors: { ...validateCardResult.errors, ...validateFormResult.errors } };\n }\n } else if (!validateFormResult.isSuccess) {\n timingTracker.trackFail(null, \"validation_error\", \"Form validation failed\");\n return { errors: validateFormResult.errors };\n }\n\n // Step 2. Create card setup intent if not present\n if (!states.cardSetupIntentId) {\n const res = await tunnelX.publicEndpoints.createCardSetupIntent({\n checkoutToken: states.secureToken,\n });\n states.cardSetupIntentId = res.cardSetupIntentId;\n }\n\n // Step 3. Submit card values.\n if (isVgsMode) {\n // VGS mode: create card via CMP, then send aliases to backend\n console.log(\"[PaymentKit] Submitting card via VGS CMP...\");\n const vgsSubmitResult = await submitVgsCardFields(states, tunnelX);\n if (!vgsSubmitResult.isSuccess) {\n // Include field-level error details for PostHog visibility\n const errorDetail = Object.entries(vgsSubmitResult.errors)\n .map(([k, v]) => `${k}: ${v}`)\n .join(\", \");\n timingTracker.trackFail(null, \"card_submit_error\", errorDetail || \"VGS card submission failed\");\n return { errors: vgsSubmitResult.errors };\n }\n } else {\n // Direct mode: submit via penpal iframes\n const submitCardResult = await submitCardFields(states);\n if (!submitCardResult.isSuccess) {\n timingTracker.trackFail(null, \"card_submit_error\", \"Card submission failed\");\n return { errors: submitCardResult.errors };\n }\n }\n\n // Step 4. Get card setup intent.\n const cardSetupIntent = await tunnelX.publicEndpoints.getCardSetupIntent({\n cardSetupIntentId: states.cardSetupIntentId,\n checkoutToken: states.secureToken,\n });\n if (!cardSetupIntent.isCardAllSet) {\n const errors = {} as PaymentKitErrors;\n if (!cardSetupIntent.isCardPanSet) errors.card_pan = \"required\";\n if (!cardSetupIntent.isCardExpSet) errors.card_exp = \"required\";\n if (!cardSetupIntent.isCardCvcSet) errors.card_cvc = \"required\";\n timingTracker.trackFail(null, \"card_setup_incomplete\", \"Card details incomplete\");\n return { errors };\n }\n\n console.log(\"Card setup intent is set ✅\", cardSetupIntent);\n console.log(\"Fields\", fields);\n\n // Step 5. Submit card checkout with customer info and fraud metadata\n let currentResult = await tunnelX.publicEndpoints.cardCheckout(\n {\n checkoutToken: states.secureToken,\n publicCardCheckoutRequest: {\n cardSetupIntentId: states.cardSetupIntentId,\n customerInfo: mapFieldsToCustomerInfo(fields),\n fraudMetadata: collectFraudMetadata(),\n },\n },\n requestOptions,\n );\n\n console.log(\"Card checkout result:\", currentResult);\n\n // Step 6. Handle next actions in a loop (supports multiple 3DS challenges)\n // This loop handles the case where one processor fails and we try another\n // that also requires 3DS authentication.\n const MAX_USER_ACTIONS = 5; // Safety limit to prevent infinite loops\n let userActionCount = 0;\n\n while (currentResult.nextAction && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n console.log(`Handling user action ${userActionCount}/${MAX_USER_ACTIONS}...`);\n\n const actionResult = await handleNextAction(currentResult.nextAction);\n\n // Always call verify endpoint so backend can properly conclude the checkout.\n // This is needed even on 3DS failure so the backend can transition from\n // user_actions_requested to card_payment_concluded with proper failure state.\n console.log(\"User action completed, verifying checkout...\");\n const verifyResult = await tunnelX.publicEndpoints.cardCheckoutVerify(\n {\n checkoutToken: states.secureToken,\n },\n requestOptions,\n );\n\n // Check if another action is required (e.g., cascade to next processor with 3DS)\n // This must be checked BEFORE returning error, as cascade may offer a new 3DS challenge\n if (verifyResult.nextAction) {\n if (!actionResult.success) {\n console.log(\"3DS failed but cascade triggered new action, continuing loop...\");\n } else {\n console.log(\"Another user action required, continuing loop...\");\n }\n currentResult = verifyResult;\n continue;\n }\n\n if (!actionResult.success) {\n // 3DS failed and no cascade/retry available - return error\n // Include verifyResult as checkout_response so error_code is available to frontend\n console.log(\"3DS authentication failed, checkout concluded:\", verifyResult);\n timingTracker.trackFail(\n verifyResult.checkoutAttemptId || null,\n verifyResult.errorCode || \"3ds_failed\",\n verifyResult.errorMessageForCustomer || actionResult.error,\n );\n return {\n errors: {\n root: verifyResult.errorMessageForCustomer || actionResult.error,\n checkout_response: verifyResult,\n },\n };\n }\n\n console.log(\"Card checkout verified ✅\", verifyResult);\n\n // No more actions needed, return the result\n timingTracker.trackSuccess(verifyResult.checkoutAttemptId || \"unknown\");\n return { data: verifyResult as { [key: string]: unknown } };\n }\n\n if (userActionCount >= MAX_USER_ACTIONS) {\n console.error(\"Max user actions exceeded\");\n timingTracker.trackFail(null, \"max_actions_exceeded\", \"Too many authentication attempts\");\n return { errors: { root: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // Check if checkout succeeded or failed\n // States: checkout_succeeded (success), payment_failed (failure)\n if (currentResult.state === \"payment_failed\" || currentResult.state === \"checkout_failed\") {\n console.log(\"Card checkout failed:\", currentResult);\n timingTracker.trackFail(\n currentResult.checkoutAttemptId || null,\n currentResult.errorCode || \"payment_failed\",\n currentResult.errorMessageForCustomer || \"Payment failed\",\n );\n // Return the full response as errors so frontend can display error details\n // including error_code, error_message_for_customer, error_message_for_debug\n return {\n errors: {\n root: currentResult.errorMessageForCustomer || \"Payment failed\",\n checkout_response: currentResult,\n },\n };\n }\n\n console.log(\"Card checkout completed ✅\", currentResult);\n timingTracker.trackSuccess(currentResult.checkoutAttemptId || \"unknown\");\n return { data: currentResult as { [key: string]: unknown } };\n };\n return submitPayment;\n};\n\n/**\n * Fetches a VGS CMP access token from the backend.\n * Uses AbortController with 10s timeout to prevent indefinite hangs on slow networks.\n */\nconst FETCH_COLLECT_TOKEN_TIMEOUT_MS = 10_000;\n\nconst fetchCollectToken = async (apiBaseUrl: string, secureToken: string): Promise<string> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_COLLECT_TOKEN_TIMEOUT_MS);\n\n try {\n const resp = await fetch(`${apiBaseUrl}/api/card-setup-intents/${secureToken}/collect-token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n signal: controller.signal,\n });\n if (!resp.ok) {\n throw new Error(`Failed to get collect token: ${resp.status}`);\n }\n const data = await resp.json();\n return data.access_token;\n } finally {\n clearTimeout(timeoutId);\n }\n};\n\n/**\n * Creates a card via VGS CMP and sends aliases to our backend.\n *\n * Flow:\n * 1. Fetch CMP access token from our backend\n * 2. Call form.createCard() → VGS creates card, returns aliases\n * 3. Send aliases + fraud metadata to our backend via updateCardSetupIntent\n */\n/**\n * Map VGS field-level error keys to PaymentKitErrors field keys.\n *\n * VGS CMP errorCallback uses short field names (\"pan\", \"cvc\", \"exp-date\")\n * matching the CMP field type, NOT the longer CSS-style names. Both forms\n * are mapped here for robustness.\n */\nconst VGS_FIELD_MAP: Record<string, keyof PaymentKitErrors> = {\n // Actual VGS CMP error keys (verified empirically)\n pan: \"card_pan\",\n cvc: \"card_cvc\",\n \"exp-date\": \"card_exp\",\n // Alternative key formats (VGS documentation references)\n \"card-number\": \"card_pan\",\n \"card-security-code\": \"card_cvc\",\n \"card-expiration-date\": \"card_exp\",\n};\n\n/**\n * Safely stringify an error for console logging.\n * VGS errors are plain objects that print as [object Object] without this.\n */\nconst stringifyError = (err: unknown): string => {\n if (err instanceof Error) return err.message;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n};\n\nconst submitVgsCardFields = async (\n states: CardStates,\n tunnelX: Awaited<ReturnType<typeof TunnelXManager.createFromPenpalConnection>>,\n): Promise<{ errors: PaymentKitErrors; isSuccess: boolean }> => {\n const { vgsForm, cardSetupIntentId, secureToken, apiBaseUrl, checkoutRequestId } = states;\n const logPrefix = `[PaymentKit] [${checkoutRequestId}]`;\n const errors = {} as PaymentKitErrors;\n\n if (!vgsForm) {\n errors.card_pan = \"required\";\n return { errors, isSuccess: false };\n }\n\n if (!cardSetupIntentId) {\n errors.root = \"Card setup intent not created\";\n return { errors, isSuccess: false };\n }\n\n // Step 1: Get CMP access token from our backend\n let accessToken: string;\n const collectTokenStart = performance.now();\n try {\n accessToken = await fetchCollectToken(apiBaseUrl, secureToken);\n const collectTokenDuration = Math.round(performance.now() - collectTokenStart);\n AnalyticsService.capture(\"vgs_collect_token_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: collectTokenDuration,\n success: true,\n });\n } catch (err) {\n const collectTokenDuration = Math.round(performance.now() - collectTokenStart);\n const isAbortError = err instanceof DOMException && err.name === \"AbortError\";\n AnalyticsService.capture(\"vgs_collect_token_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: collectTokenDuration,\n success: false,\n error_type: isAbortError ? \"FETCH_TIMEOUT\" : \"FETCH_ERROR\",\n });\n console.error(`${logPrefix} VGS auth token fetch failed:`, stringifyError(err));\n errors.root = isAbortError\n ? \"Card authentication timed out — please try again\"\n : \"Card authentication failed — please try again\";\n return { errors, isSuccess: false };\n }\n\n // Step 2: Create card via VGS CMP — returns aliases for PAN/CVC, plain text expiry\n let cardResult: VGSCreateCardResponse;\n const VGS_CREATE_CARD_TIMEOUT_MS = 120_000;\n const createCardStart = performance.now();\n try {\n let createCardTimeoutId: ReturnType<typeof setTimeout>;\n cardResult = await Promise.race([\n new Promise<VGSCreateCardResponse>((resolve, reject) => {\n vgsForm.createCard(\n {\n auth: accessToken,\n data: { cardholder: {} },\n },\n (_status, cardObject) => resolve(cardObject),\n (error) => reject(error),\n );\n }),\n new Promise<never>((_, reject) => {\n createCardTimeoutId = setTimeout(() => reject(new Error(\"VGS_TIMEOUT\")), VGS_CREATE_CARD_TIMEOUT_MS);\n }),\n ]).finally(() => clearTimeout(createCardTimeoutId));\n\n // Emit timing event on success\n const createCardDuration = Math.round(performance.now() - createCardStart);\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: true,\n });\n } catch (err) {\n const createCardDuration = Math.round(performance.now() - createCardStart);\n const errStr = stringifyError(err);\n console.error(`${logPrefix} VGS createCard failed:`, errStr);\n\n // Distinguish timeout from VGS field validation errors\n if (err instanceof Error && err.message === \"VGS_TIMEOUT\") {\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: false,\n error_type: \"VGS_TIMEOUT\",\n });\n errors.root = \"Card processing timed out — please try again\";\n return { errors, isSuccess: false };\n }\n\n // VGS errorCallback returns field-level errors as a plain object,\n // e.g. { \"card-number\": { errorMessages: [\"Card number is not valid\"] } }\n // Map them to per-field errors so inline validation shows on the right field.\n if (err && typeof err === \"object\" && !(err instanceof Error)) {\n const vgsErrors = err as Record<string, unknown>;\n for (const [vgsKey, fieldKey] of Object.entries(VGS_FIELD_MAP)) {\n if (vgsKey in vgsErrors) {\n const fieldErr = vgsErrors[vgsKey] as Record<string, unknown> | undefined;\n const messages = fieldErr?.errorMessages;\n errors[fieldKey] = Array.isArray(messages) ? messages[0] : \"invalid\";\n }\n }\n if (Object.keys(errors).length > 0) {\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: false,\n error_type: \"VGS_VALIDATION_ERROR\",\n });\n return { errors, isSuccess: false };\n }\n }\n\n // Generic VGS error\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: false,\n error_type: \"VGS_ERROR\",\n });\n errors.root = \"Card validation failed — please check your card details and try again\";\n return { errors, isSuccess: false };\n }\n\n // Step 3: Extract aliases and expiry from CMP response\n if (!cardResult?.data?.attributes) {\n console.error(`${logPrefix} VGS createCard returned invalid response:`, stringifyError(cardResult));\n errors.root = \"Card processing returned an invalid response — please try again\";\n return { errors, isSuccess: false };\n }\n const { pan_alias, cvc_alias, exp_month, exp_year } = cardResult.data.attributes;\n const fullYear = exp_year < 100 ? 2000 + exp_year : exp_year;\n const formattedExp = `${String(exp_month).padStart(2, \"0\")}/${fullYear}`;\n\n // Capture CMP card ID for network token tracking\n const cmpCardId = cardResult.data.id;\n\n // Step 4: Send aliases + fraud metadata to our backend.\n // CVC is sent as a VGS alias from createCard. Additionally, the CVC is\n // submitted via the vault inbound proxy (REDACT route) as a fallback for\n // the 303 deduplication path where VGS returns an existing card without\n // a fresh cvc_alias.\n try {\n const updateIntentCall = tunnelX.publicEndpoints.updateCardSetupIntent({\n checkoutToken: secureToken,\n cardSetupIntentId: cardSetupIntentId,\n updateCardSetupIntentReq: {\n cardPan: pan_alias,\n cardExp: formattedExp,\n cardCvc: cvc_alias,\n cmpCardId: cmpCardId,\n fraudMetadata: collectFraudMetadata(),\n },\n });\n\n const proxyCvcCall = new Promise<void>((resolve, reject) => {\n if (!vgsForm.submit) {\n reject(new Error(\"VGS form.submit not available\"));\n return;\n }\n vgsForm.submit(\n `/api/card-setup-intents/${secureToken}/${cardSetupIntentId}`,\n {\n method: \"post\",\n headers: { \"Content-Type\": \"application/json\" },\n data: (fields: Record<string, unknown>) => ({ card_cvc: fields.cvc }),\n },\n (_status: number) => resolve(),\n (err: unknown) => reject(err),\n );\n });\n\n await Promise.all([updateIntentCall, proxyCvcCall]);\n } catch (err) {\n console.error(`${logPrefix} updateCardSetupIntent failed:`, stringifyError(err));\n errors.root = \"Failed to save card details — please try again\";\n return { errors, isSuccess: false };\n }\n\n return { errors: {}, isSuccess: true };\n};\n\nconst submitCardFields = async (states: CardStates) => {\n const errors = {} as PaymentKitErrors;\n const { cardSetupIntentId, cardInputConnections } = states;\n\n const submitPromises = Object.entries(cardInputConnections).map(async ([_type, connection]) => {\n const type = _type as PenpalCardInputType;\n\n const remote = await connection.promise;\n const result = await remote.onSubmit(cardSetupIntentId || \"\");\n\n if (\"error\" in result) {\n errors[type] = result.error;\n }\n });\n\n await Promise.allSettled(submitPromises);\n\n return {\n errors,\n isSuccess: Object.keys(errors).length === 0,\n };\n};\n\nconst validateCardFields = async (states: CardStates) => {\n const errors: PaymentKitErrors = {};\n const { cardInputConnections } = states;\n\n const validatePromises = Object.entries(cardInputConnections).map(async ([_type, connection]) => {\n const type = _type as PenpalCardInputType;\n\n if (!connection) {\n errors[type] = \"penpal_not_connected\";\n return;\n }\n\n const remote = await connection.promise;\n const errorMsg = await remote.onValidate();\n\n if (errorMsg) {\n errors[type] = errorMsg;\n }\n });\n\n await Promise.allSettled(validatePromises);\n\n return {\n errors,\n isSuccess: Object.keys(errors).length === 0,\n };\n};\n\nconst CardPaymentMethod = definePaymentMethod((paymentKitStates) => {\n // Object.create() creates prototype delegation: reads fall through to the shared\n // paymentKitStates (preserving auto-detected VGS config), writes stay local.\n // This prevents card-specific properties (cardInputConnections, vgsForm, etc.)\n // from leaking onto the shared paymentKitStates object.\n const localStates = Object.create(paymentKitStates) as CardStates;\n localStates.cardInputConnections = {};\n\n return {\n name: \"card\",\n externalFuncs: {\n createElement: defCreateElement(localStates),\n },\n internalFuncs: {\n submitPayment: defSubmitPayment(localStates),\n cleanup: () => {\n // Clean up VGS form if present\n if (localStates.vgsForm) {\n localStates.vgsFieldsCleanup?.();\n localStates.vgsFieldsCleanup = undefined;\n localStates.vgsForm.unmount();\n localStates.vgsForm = undefined;\n }\n // Clean up all card input iframe connections\n for (const connection of Object.values(localStates.cardInputConnections)) {\n connection?.destroy();\n }\n localStates.cardInputConnections = {};\n },\n },\n };\n});\n\nexport default CardPaymentMethod;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"card.mjs","names":["taxIds: string[] | undefined","cleanupVgs: (() => void) | undefined","cleanupDirect: (() => void) | undefined","cdnTimeoutId: ReturnType<typeof setTimeout>","params: Record<string, string>","submitPayment: TInternalFuncs[\"submitPayment\"]","VGS_FIELD_MAP: Record<string, keyof PaymentKitErrors>","accessToken: string","cardResult: VGSCreateCardResponse","createCardTimeoutId: ReturnType<typeof setTimeout>","errors: PaymentKitErrors"],"sources":["../../src/payment-methods/card.ts"],"sourcesContent":["import {\n connectToCardIframe,\n type IFrameConnection,\n type CardInputType as PenpalCardInputType,\n type CheckoutResponse as PenpalCheckoutResponse,\n} from \"../penpal/connect-card\";\n\n// Re-export types for public API\nexport type CardInputType = PenpalCardInputType;\nexport type CheckoutResponse = PenpalCheckoutResponse;\n\nimport { AnalyticsService } from \"../analytics\";\nimport { TunnelXManager } from \"../penpal/connect-tunnel-x\";\nimport type { PaymentKitErrors, PaymentKitFields, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport {\n $,\n collectFraudMetadata,\n createCheckoutIFrame,\n definePaymentMethod,\n validateFormFields,\n withRequestId,\n} from \"../utils\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { createVgsCardFields, initVgsCollect, loadVgsCollectScript } from \"./vgs-collect-loader\";\n\n/**\n * Splits a full name into first name and last name.\n * First word becomes firstName, rest becomes lastName.\n */\nconst splitName = (fullName: string): { firstName: string; lastName?: string } => {\n const trimmed = fullName.trim();\n const spaceIndex = trimmed.indexOf(\" \");\n if (spaceIndex === -1) {\n return { firstName: trimmed };\n }\n return {\n firstName: trimmed.substring(0, spaceIndex),\n lastName: trimmed.substring(spaceIndex + 1).trim() || undefined,\n };\n};\n\n/**\n * Maps PaymentKitFields to the customerInfo structure expected by the API.\n */\nconst mapFieldsToCustomerInfo = (fields: PaymentKitFields) => {\n const { firstName, lastName } = splitName(fields.customer_name);\n\n const hasBillingAddress =\n fields.customer_country ||\n fields.customer_zip_code ||\n fields.customer_address_line1 ||\n fields.customer_address_line2 ||\n fields.customer_city ||\n fields.customer_state;\n\n const hasShippingAddress =\n fields.shipping_address_line1 ||\n fields.shipping_address_line2 ||\n fields.shipping_city ||\n fields.shipping_state ||\n fields.shipping_zip_code ||\n fields.shipping_country;\n\n let taxIds: string[] | undefined;\n if (fields.customer_tax_ids) {\n try {\n taxIds = JSON.parse(fields.customer_tax_ids);\n } catch {\n taxIds = undefined;\n }\n }\n\n return {\n email: fields.customer_email || undefined,\n firstName,\n lastName,\n businessName: fields.customer_business_name || undefined,\n taxIds: taxIds?.length ? taxIds : undefined,\n billingAddress: hasBillingAddress\n ? {\n country: fields.customer_country || undefined,\n zipCode: fields.customer_zip_code || undefined,\n line1: fields.customer_address_line1 || undefined,\n line2: fields.customer_address_line2 || undefined,\n city: fields.customer_city || undefined,\n state: fields.customer_state || undefined,\n }\n : undefined,\n shippingAddress: hasShippingAddress\n ? {\n line1: fields.shipping_address_line1 || undefined,\n line2: fields.shipping_address_line2 || undefined,\n city: fields.shipping_city || undefined,\n state: fields.shipping_state || undefined,\n zipCode: fields.shipping_zip_code || undefined,\n country: fields.shipping_country || undefined,\n }\n : undefined,\n };\n};\n\ntype CardStates = PaymentKitStates & {\n cardSetupIntentId?: string;\n cardInputConnections: Partial<Record<PenpalCardInputType, IFrameConnection>>;\n vgsForm?: VGSCollectForm;\n vgsFieldsCleanup?: () => void;\n vgsFocusCallbacks?: Partial<Record<PenpalCardInputType, (isFocused: boolean) => void>>;\n vgsMountSelectors?: Partial<Record<PenpalCardInputType, string>>;\n vgsPlaceholders?: Partial<Record<PenpalCardInputType, string>>;\n};\n\ntype CreateElementOptions = Partial<Parameters<typeof connectToCardIframe>[1]> & {\n style?: Record<string, string>;\n placeholder?: string;\n};\n\nconst defCreateElement = (states: CardStates) => {\n const { baseUrl, apiBaseUrl, cardInputConnections, secureToken, timingTracker } = states;\n\n return (type: PenpalCardInputType, options: CreateElementOptions) => {\n const { style, onLoaded, onFocusChange, placeholder } = options;\n\n const mountIFrame = (parentSelector: string) => {\n // Mutable cleanup callbacks — set once mode is determined and mount completes\n let cleanupVgs: (() => void) | undefined;\n let cleanupDirect: (() => void) | undefined;\n // Cancellation flag: prevents deferred doMount from executing after unmount.\n // Needed because React strict mode may call unmount before the deferred\n // _sessionConfigReady promise resolves.\n let cancelled = false;\n\n /**\n * Performs the actual DOM mount after the tokenization mode is known.\n * Runs synchronously when mode is explicitly provided, or after the\n * auto-detect fetch resolves.\n */\n // Store mount selector so VGS init (triggered by card_pan) can read\n // the exp/cvc selectors that were registered by their own createElement calls.\n if (!states.vgsMountSelectors) states.vgsMountSelectors = {};\n states.vgsMountSelectors[type] = parentSelector;\n\n const doMount = () => {\n if (cancelled) return;\n const isVgsMode = states.cardTokenizationMode === \"vgs\";\n console.log(\n `[PaymentKit] card.doMount(${type}) — mode: ${states.cardTokenizationMode}, vgsVaultId: ${states.vgsVaultId ?? \"unset\"}, vgsEnvironment: ${states.vgsEnvironment ?? \"unset\"}`,\n );\n\n // VGS mode: initialize VGS Collect form and mount fields on card_pan\n if (isVgsMode && states.vgsVaultId && states.vgsEnvironment) {\n // Store per-field focus callbacks and placeholders so createVgsCardFields\n // can wire each field to its own callback/placeholder. All three createElement\n // calls complete before the CDN script loads, so all values are available by then.\n if (onFocusChange) {\n if (!states.vgsFocusCallbacks) states.vgsFocusCallbacks = {};\n states.vgsFocusCallbacks[type] = onFocusChange;\n }\n if (placeholder) {\n if (!states.vgsPlaceholders) states.vgsPlaceholders = {};\n states.vgsPlaceholders[type] = placeholder;\n }\n\n if (type === \"card_pan\") {\n const vaultId = states.vgsVaultId;\n const vgsEnv = states.vgsEnvironment;\n\n console.log(`[PaymentKit] VGS mode active — loading VGS Collect CDN for vault ${vaultId} (${vgsEnv})...`);\n const VGS_CDN_TIMEOUT_MS = 15_000;\n let cdnTimeoutId: ReturnType<typeof setTimeout>;\n Promise.race([\n loadVgsCollectScript(),\n new Promise<never>((_, reject) => {\n cdnTimeoutId = setTimeout(() => {\n console.warn(`[PaymentKit] VGS Collect CDN load timed out after ${VGS_CDN_TIMEOUT_MS / 1000}s`);\n reject(new Error(\"VGS Collect CDN load timed out\"));\n }, VGS_CDN_TIMEOUT_MS);\n }),\n ])\n .finally(() => clearTimeout(cdnTimeoutId))\n .then(() => {\n if (cancelled) return;\n console.log(\"[PaymentKit] VGS Collect CDN loaded — initializing form...\");\n const form = initVgsCollect(vaultId, vgsEnv);\n if (cancelled) {\n form.unmount();\n return;\n }\n states.vgsForm = form;\n\n const css = style\n ? Object.fromEntries(\n Object.entries(style).map(([k, v]) => [k.replace(/([A-Z])/g, \"-$1\").toLowerCase(), v]),\n )\n : undefined;\n\n // Read exp/cvc selectors from shared state.\n // Each createElement(\"card_exp/card_cvc\").mount(selector) stores its\n // selector before this async callback runs, so they're available here.\n const expSelector = states.vgsMountSelectors?.card_exp;\n const cvcSelector = states.vgsMountSelectors?.card_cvc;\n if (!expSelector || !cvcSelector) {\n const msg =\n `[PaymentKit] VGS mode requires all three card fields to be mounted. ` +\n `Missing: ${!expSelector ? \"card_exp\" : \"\"}${!expSelector && !cvcSelector ? \", \" : \"\"}${!cvcSelector ? \"card_cvc\" : \"\"}`;\n console.error(msg);\n onLoaded?.();\n return;\n }\n console.log(\n `[PaymentKit] Creating VGS card fields — pan: ${parentSelector}, exp: ${expSelector}, cvc: ${cvcSelector}`,\n );\n states.vgsFieldsCleanup = createVgsCardFields(\n form,\n {\n pan: parentSelector,\n exp: expSelector,\n cvc: cvcSelector,\n },\n css,\n states.vgsFocusCallbacks,\n states.vgsPlaceholders,\n );\n\n console.log(\"[PaymentKit] VGS card fields created successfully\");\n timingTracker.trackInputReady();\n onLoaded?.();\n })\n .catch((err) => {\n console.error(\"[PaymentKit] Failed to load VGS Collect script. Card input will not be available:\", err);\n // Signal loaded so the form exits loading state rather than hanging forever.\n // Card fields won't render, but submit will fail with a clear error.\n onLoaded?.();\n });\n }\n\n // For non-pan fields in VGS mode, signal loaded immediately since\n // VGS handles all three fields from the card_pan mount.\n if (type !== \"card_pan\") {\n onLoaded?.();\n }\n\n cleanupVgs = () => {\n if (type === \"card_pan\" && states.vgsForm) {\n try {\n states.vgsFieldsCleanup?.();\n } catch {\n // VGS may try to remove iframes from containers already removed by React\n }\n states.vgsFieldsCleanup = undefined;\n try {\n states.vgsForm.unmount();\n } catch {\n // VGS unmount may fail if DOM nodes are already detached\n }\n states.vgsForm = undefined;\n }\n };\n return;\n }\n\n // If we got here and mode was \"vgs\", it means VGS config was incomplete\n if (isVgsMode) {\n console.warn(\n `[PaymentKit] VGS mode requested but config incomplete (vgsVaultId: ${states.vgsVaultId ?? \"unset\"}, vgsEnvironment: ${states.vgsEnvironment ?? \"unset\"}) — using direct mode`,\n );\n }\n\n // Direct mode: existing penpal iframe logic\n const parent = $(parentSelector) as HTMLElement;\n\n // Read container padding so the embed input matches the merchant's\n // visual intent. The iframe uses absolute positioning to fill the\n // full container, so the input needs its own padding for alignment.\n const computed = getComputedStyle(parent);\n const containerPadding = computed.padding !== \"0px\" ? computed.padding : undefined;\n const enhancedStyle = {\n ...(style ?? {}),\n height: \"100%\",\n boxSizing: \"border-box\",\n ...(containerPadding ? { padding: containerPadding } : {}),\n };\n\n const params: Record<string, string> = {\n checkout_token: secureToken,\n api_base_url: apiBaseUrl,\n style: JSON.stringify(enhancedStyle),\n };\n\n const iframe = createCheckoutIFrame(type.replace(\"_\", \"-\"), baseUrl, params);\n\n // Use absolute positioning so the iframe covers the full container\n // including any padding the merchant's CSS applies.\n if (computed.position === \"static\") {\n parent.style.position = \"relative\";\n }\n iframe.style.position = \"absolute\";\n iframe.style.inset = \"0\";\n\n // Set cleanup before DOM mutation to avoid leaking the iframe if\n // unmount() is called between appendChild and onload.\n cleanupDirect = () => {\n const connection = cardInputConnections[type];\n connection?.destroy();\n try {\n parent.removeChild(iframe);\n } catch {\n // Parent may already be detached from DOM by React\n }\n states.cardInputConnections[type] = undefined;\n };\n\n parent.appendChild(iframe);\n\n iframe.onload = () => {\n if (type === \"card_pan\") {\n timingTracker.trackInputReady();\n }\n\n const connection = connectToCardIframe(iframe, {\n onLoaded: onLoaded || (() => {}),\n onFocusChange: onFocusChange || (() => {}),\n });\n\n states.cardInputConnections[type] = connection;\n };\n };\n\n // If session config needs auto-detection, wait for it; otherwise mount synchronously\n if (states._sessionConfigReady) {\n states._sessionConfigReady.then(doMount);\n } else {\n doMount();\n }\n\n return {\n unmount: () => {\n cancelled = true;\n cleanupVgs?.();\n cleanupDirect?.();\n },\n };\n };\n\n return { mount: mountIFrame };\n };\n};\n\nconst defSubmitPayment = (states: CardStates) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (fields, options) => {\n // Ensure session config is loaded (no-op if explicitly provided)\n if (states._sessionConfigReady) await states._sessionConfigReady;\n const isVgsMode = states.cardTokenizationMode === \"vgs\";\n\n const { timingTracker, checkoutRequestId } = states;\n\n // Track submit event\n timingTracker.trackSubmit();\n\n // Use the checkout request ID from states (generated on page load)\n const requestOptions = withRequestId(checkoutRequestId);\n\n const tunnelX = await TunnelXManager.createFromPenpalConnection(states.tunnelXConnection);\n\n // Step 1. Validate form values.\n // Form field validation is shared across both modes.\n // In VGS mode, card field validation is handled by VGS Collect (built-in validators).\n // In direct mode, card field validation is handled by penpal iframes.\n const skipCustomerValidation = options?.skipCustomerValidation === true;\n const validateFormResult = skipCustomerValidation\n ? { isSuccess: true as const, errors: {} as PaymentKitErrors }\n : await validateFormFields(fields);\n if (!isVgsMode) {\n const validateCardResult = await validateCardFields(states);\n if (!(validateCardResult.isSuccess && validateFormResult.isSuccess)) {\n timingTracker.trackFail(null, \"validation_error\", \"Form validation failed\");\n return { errors: { ...validateCardResult.errors, ...validateFormResult.errors } };\n }\n } else if (!validateFormResult.isSuccess) {\n timingTracker.trackFail(null, \"validation_error\", \"Form validation failed\");\n return { errors: validateFormResult.errors };\n }\n\n // Step 2. Create card setup intent if not present\n if (!states.cardSetupIntentId) {\n const res = await tunnelX.publicEndpoints.createCardSetupIntent({\n checkoutToken: states.secureToken,\n });\n states.cardSetupIntentId = res.cardSetupIntentId;\n }\n\n // Step 3. Submit card values.\n if (isVgsMode) {\n // VGS mode: create card via CMP, then send aliases to backend\n console.log(\"[PaymentKit] Submitting card via VGS CMP...\");\n const vgsSubmitResult = await submitVgsCardFields(states, tunnelX);\n if (!vgsSubmitResult.isSuccess) {\n // Include field-level error details for PostHog visibility\n const errorDetail = Object.entries(vgsSubmitResult.errors)\n .map(([k, v]) => `${k}: ${v}`)\n .join(\", \");\n timingTracker.trackFail(null, \"card_submit_error\", errorDetail || \"VGS card submission failed\");\n return { errors: vgsSubmitResult.errors };\n }\n } else {\n // Direct mode: submit via penpal iframes\n const submitCardResult = await submitCardFields(states);\n if (!submitCardResult.isSuccess) {\n timingTracker.trackFail(null, \"card_submit_error\", \"Card submission failed\");\n return { errors: submitCardResult.errors };\n }\n }\n\n // Step 4. Get card setup intent.\n const cardSetupIntent = await tunnelX.publicEndpoints.getCardSetupIntent({\n cardSetupIntentId: states.cardSetupIntentId,\n checkoutToken: states.secureToken,\n });\n if (!cardSetupIntent.isCardAllSet) {\n const errors = {} as PaymentKitErrors;\n if (!cardSetupIntent.isCardPanSet) errors.card_pan = \"required\";\n if (!cardSetupIntent.isCardExpSet) errors.card_exp = \"required\";\n if (!cardSetupIntent.isCardCvcSet) errors.card_cvc = \"required\";\n timingTracker.trackFail(null, \"card_setup_incomplete\", \"Card details incomplete\");\n return { errors };\n }\n\n console.log(\"Card setup intent is set ✅\", cardSetupIntent);\n console.log(\"Fields\", fields);\n\n // Step 5. Submit card checkout with customer info and fraud metadata\n let currentResult = await tunnelX.publicEndpoints.cardCheckout(\n {\n checkoutToken: states.secureToken,\n publicCardCheckoutRequest: {\n cardSetupIntentId: states.cardSetupIntentId,\n customerInfo: mapFieldsToCustomerInfo(fields),\n fraudMetadata: collectFraudMetadata(),\n },\n },\n requestOptions,\n );\n\n console.log(\"Card checkout result:\", currentResult);\n\n // Step 6. Handle next actions in a loop (supports multiple 3DS challenges)\n // This loop handles the case where one processor fails and we try another\n // that also requires 3DS authentication.\n const MAX_USER_ACTIONS = 5; // Safety limit to prevent infinite loops\n let userActionCount = 0;\n\n while (currentResult.nextAction && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n console.log(`Handling user action ${userActionCount}/${MAX_USER_ACTIONS}...`);\n\n const actionResult = await handleNextAction(currentResult.nextAction);\n\n // Always call verify endpoint so backend can properly conclude the checkout.\n // This is needed even on 3DS failure so the backend can transition from\n // user_actions_requested to card_payment_concluded with proper failure state.\n console.log(\"User action completed, verifying checkout...\");\n const verifyResult = await tunnelX.publicEndpoints.cardCheckoutVerify(\n {\n checkoutToken: states.secureToken,\n },\n requestOptions,\n );\n\n // Check if another action is required (e.g., cascade to next processor with 3DS)\n // This must be checked BEFORE returning error, as cascade may offer a new 3DS challenge\n if (verifyResult.nextAction) {\n if (!actionResult.success) {\n console.log(\"3DS failed but cascade triggered new action, continuing loop...\");\n } else {\n console.log(\"Another user action required, continuing loop...\");\n }\n currentResult = verifyResult;\n continue;\n }\n\n if (!actionResult.success) {\n // 3DS failed and no cascade/retry available - return error\n // Include verifyResult as checkout_response so error_code is available to frontend\n console.log(\"3DS authentication failed, checkout concluded:\", verifyResult);\n timingTracker.trackFail(\n verifyResult.checkoutAttemptId || null,\n verifyResult.errorCode || \"3ds_failed\",\n verifyResult.errorMessageForCustomer || actionResult.error,\n );\n return {\n errors: {\n root: verifyResult.errorMessageForCustomer || actionResult.error,\n checkout_response: verifyResult,\n },\n };\n }\n\n console.log(\"Card checkout verified ✅\", verifyResult);\n\n // No more actions needed, return the result\n timingTracker.trackSuccess(verifyResult.checkoutAttemptId || \"unknown\");\n return { data: verifyResult as { [key: string]: unknown } };\n }\n\n if (userActionCount >= MAX_USER_ACTIONS) {\n console.error(\"Max user actions exceeded\");\n timingTracker.trackFail(null, \"max_actions_exceeded\", \"Too many authentication attempts\");\n return { errors: { root: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // Check if checkout succeeded or failed\n // States: checkout_succeeded (success), payment_failed (failure)\n if (currentResult.state === \"payment_failed\" || currentResult.state === \"checkout_failed\") {\n console.log(\"Card checkout failed:\", currentResult);\n timingTracker.trackFail(\n currentResult.checkoutAttemptId || null,\n currentResult.errorCode || \"payment_failed\",\n currentResult.errorMessageForCustomer || \"Payment failed\",\n );\n // Return the full response as errors so frontend can display error details\n // including error_code, error_message_for_customer, error_message_for_debug\n return {\n errors: {\n root: currentResult.errorMessageForCustomer || \"Payment failed\",\n checkout_response: currentResult,\n },\n };\n }\n\n console.log(\"Card checkout completed ✅\", currentResult);\n timingTracker.trackSuccess(currentResult.checkoutAttemptId || \"unknown\");\n return { data: currentResult as { [key: string]: unknown } };\n };\n return submitPayment;\n};\n\n/**\n * Fetches a VGS CMP access token from the backend.\n * Uses AbortController with 10s timeout to prevent indefinite hangs on slow networks.\n */\nconst FETCH_COLLECT_TOKEN_TIMEOUT_MS = 10_000;\n\nconst fetchCollectToken = async (apiBaseUrl: string, secureToken: string): Promise<string> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_COLLECT_TOKEN_TIMEOUT_MS);\n\n try {\n const resp = await fetch(`${apiBaseUrl}/api/card-setup-intents/${secureToken}/collect-token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n signal: controller.signal,\n });\n if (!resp.ok) {\n throw new Error(`Failed to get collect token: ${resp.status}`);\n }\n const data = await resp.json();\n return data.access_token;\n } finally {\n clearTimeout(timeoutId);\n }\n};\n\n/**\n * Creates a card via VGS CMP and sends aliases to our backend.\n *\n * Flow:\n * 1. Fetch CMP access token from our backend\n * 2. Call form.createCard() → VGS creates card, returns aliases\n * 3. Send aliases + fraud metadata to our backend via updateCardSetupIntent\n */\n/**\n * Map VGS field-level error keys to PaymentKitErrors field keys.\n *\n * VGS CMP errorCallback uses short field names (\"pan\", \"cvc\", \"exp-date\")\n * matching the CMP field type, NOT the longer CSS-style names. Both forms\n * are mapped here for robustness.\n */\nconst VGS_FIELD_MAP: Record<string, keyof PaymentKitErrors> = {\n // Actual VGS CMP error keys (verified empirically)\n pan: \"card_pan\",\n cvc: \"card_cvc\",\n \"exp-date\": \"card_exp\",\n // Alternative key formats (VGS documentation references)\n \"card-number\": \"card_pan\",\n \"card-security-code\": \"card_cvc\",\n \"card-expiration-date\": \"card_exp\",\n};\n\n/**\n * Safely stringify an error for console logging.\n * VGS errors are plain objects that print as [object Object] without this.\n */\nconst stringifyError = (err: unknown): string => {\n if (err instanceof Error) return err.message;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n};\n\nconst submitVgsCardFields = async (\n states: CardStates,\n tunnelX: Awaited<ReturnType<typeof TunnelXManager.createFromPenpalConnection>>,\n): Promise<{ errors: PaymentKitErrors; isSuccess: boolean }> => {\n const { vgsForm, cardSetupIntentId, secureToken, apiBaseUrl, checkoutRequestId } = states;\n const logPrefix = `[PaymentKit] [${checkoutRequestId}]`;\n const errors = {} as PaymentKitErrors;\n\n if (!vgsForm) {\n errors.card_pan = \"required\";\n return { errors, isSuccess: false };\n }\n\n if (!cardSetupIntentId) {\n errors.root = \"Card setup intent not created\";\n return { errors, isSuccess: false };\n }\n\n // Step 1: Get CMP access token from our backend\n let accessToken: string;\n const collectTokenStart = performance.now();\n try {\n accessToken = await fetchCollectToken(apiBaseUrl, secureToken);\n const collectTokenDuration = Math.round(performance.now() - collectTokenStart);\n AnalyticsService.capture(\"vgs_collect_token_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: collectTokenDuration,\n success: true,\n });\n } catch (err) {\n const collectTokenDuration = Math.round(performance.now() - collectTokenStart);\n const isAbortError = err instanceof DOMException && err.name === \"AbortError\";\n AnalyticsService.capture(\"vgs_collect_token_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: collectTokenDuration,\n success: false,\n error_type: isAbortError ? \"FETCH_TIMEOUT\" : \"FETCH_ERROR\",\n });\n console.error(`${logPrefix} VGS auth token fetch failed:`, stringifyError(err));\n errors.root = isAbortError\n ? \"Card authentication timed out — please try again\"\n : \"Card authentication failed — please try again\";\n return { errors, isSuccess: false };\n }\n\n // Step 2: Create card via VGS CMP — returns aliases for PAN/CVC, plain text expiry\n let cardResult: VGSCreateCardResponse;\n const VGS_CREATE_CARD_TIMEOUT_MS = 120_000;\n const createCardStart = performance.now();\n try {\n let createCardTimeoutId: ReturnType<typeof setTimeout>;\n cardResult = await Promise.race([\n new Promise<VGSCreateCardResponse>((resolve, reject) => {\n vgsForm.createCard(\n {\n auth: accessToken,\n data: { cardholder: {} },\n },\n (_status, cardObject) => resolve(cardObject),\n (error) => reject(error),\n );\n }),\n new Promise<never>((_, reject) => {\n createCardTimeoutId = setTimeout(() => reject(new Error(\"VGS_TIMEOUT\")), VGS_CREATE_CARD_TIMEOUT_MS);\n }),\n ]).finally(() => clearTimeout(createCardTimeoutId));\n\n // Emit timing event on success\n const createCardDuration = Math.round(performance.now() - createCardStart);\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: true,\n });\n } catch (err) {\n const createCardDuration = Math.round(performance.now() - createCardStart);\n const errStr = stringifyError(err);\n console.error(`${logPrefix} VGS createCard failed:`, errStr);\n\n // Distinguish timeout from VGS field validation errors\n if (err instanceof Error && err.message === \"VGS_TIMEOUT\") {\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: false,\n error_type: \"VGS_TIMEOUT\",\n });\n errors.root = \"Card processing timed out — please try again\";\n return { errors, isSuccess: false };\n }\n\n // VGS errorCallback returns field-level errors as a plain object,\n // e.g. { \"card-number\": { errorMessages: [\"Card number is not valid\"] } }\n // Map them to per-field errors so inline validation shows on the right field.\n if (err && typeof err === \"object\" && !(err instanceof Error)) {\n const vgsErrors = err as Record<string, unknown>;\n for (const [vgsKey, fieldKey] of Object.entries(VGS_FIELD_MAP)) {\n if (vgsKey in vgsErrors) {\n const fieldErr = vgsErrors[vgsKey] as Record<string, unknown> | undefined;\n const messages = fieldErr?.errorMessages;\n errors[fieldKey] = Array.isArray(messages) ? messages[0] : \"invalid\";\n }\n }\n if (Object.keys(errors).length > 0) {\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: false,\n error_type: \"VGS_VALIDATION_ERROR\",\n });\n return { errors, isSuccess: false };\n }\n }\n\n // Generic VGS error\n AnalyticsService.capture(\"vgs_create_card_timing\", {\n checkout_session_id: secureToken,\n request_id: checkoutRequestId,\n duration_ms: createCardDuration,\n success: false,\n error_type: \"VGS_ERROR\",\n });\n errors.root = \"Card validation failed — please check your card details and try again\";\n return { errors, isSuccess: false };\n }\n\n // Step 3: Extract aliases and expiry from CMP response\n if (!cardResult?.data?.attributes) {\n console.error(`${logPrefix} VGS createCard returned invalid response:`, stringifyError(cardResult));\n errors.root = \"Card processing returned an invalid response — please try again\";\n return { errors, isSuccess: false };\n }\n const { pan_alias, cvc_alias, exp_month, exp_year } = cardResult.data.attributes;\n\n if (!cvc_alias) {\n console.warn(\n `${logPrefix} VGS createCard response missing cvc_alias (303 dedup):`,\n JSON.stringify(cardResult.data.attributes),\n );\n }\n\n const fullYear = exp_year < 100 ? 2000 + exp_year : exp_year;\n const formattedExp = `${String(exp_month).padStart(2, \"0\")}/${fullYear}`;\n\n // Capture CMP card ID for network token tracking\n const cmpCardId = cardResult.data.id;\n\n // Step 4: Send aliases + fraud metadata to our backend.\n // CVC is sent as a VGS alias from createCard. Additionally, the CVC is\n // submitted via the vault inbound proxy (REDACT route) as a fallback for\n // the 303 deduplication path where VGS returns an existing card without\n // a fresh cvc_alias.\n try {\n const updateIntentCall = tunnelX.publicEndpoints.updateCardSetupIntent({\n checkoutToken: secureToken,\n cardSetupIntentId: cardSetupIntentId,\n updateCardSetupIntentReq: {\n cardPan: pan_alias,\n cardExp: formattedExp,\n ...(cvc_alias ? { cardCvc: cvc_alias } : {}),\n cmpCardId: cmpCardId,\n fraudMetadata: collectFraudMetadata(),\n },\n });\n\n const proxyCvcCall = new Promise<void>((resolve, reject) => {\n if (!vgsForm.submit) {\n reject(new Error(\"VGS form.submit not available\"));\n return;\n }\n vgsForm.submit(\n `/api/card-setup-intents/${secureToken}/${cardSetupIntentId}`,\n {\n method: \"post\",\n headers: { \"Content-Type\": \"application/json\" },\n data: (fields: Record<string, unknown>) => ({ card_cvc: fields.cvc }),\n },\n (_status: number) => resolve(),\n (err: unknown) => reject(err),\n );\n });\n\n await Promise.all([updateIntentCall, proxyCvcCall]);\n } catch (err) {\n console.error(`${logPrefix} updateCardSetupIntent failed:`, stringifyError(err));\n errors.root = \"Failed to save card details — please try again\";\n return { errors, isSuccess: false };\n }\n\n return { errors: {}, isSuccess: true };\n};\n\nconst submitCardFields = async (states: CardStates) => {\n const errors = {} as PaymentKitErrors;\n const { cardSetupIntentId, cardInputConnections } = states;\n\n const submitPromises = Object.entries(cardInputConnections).map(async ([_type, connection]) => {\n const type = _type as PenpalCardInputType;\n\n const remote = await connection.promise;\n const result = await remote.onSubmit(cardSetupIntentId || \"\");\n\n if (\"error\" in result) {\n errors[type] = result.error;\n }\n });\n\n await Promise.allSettled(submitPromises);\n\n return {\n errors,\n isSuccess: Object.keys(errors).length === 0,\n };\n};\n\nconst validateCardFields = async (states: CardStates) => {\n const errors: PaymentKitErrors = {};\n const { cardInputConnections } = states;\n\n const validatePromises = Object.entries(cardInputConnections).map(async ([_type, connection]) => {\n const type = _type as PenpalCardInputType;\n\n if (!connection) {\n errors[type] = \"penpal_not_connected\";\n return;\n }\n\n const remote = await connection.promise;\n const errorMsg = await remote.onValidate();\n\n if (errorMsg) {\n errors[type] = errorMsg;\n }\n });\n\n await Promise.allSettled(validatePromises);\n\n return {\n errors,\n isSuccess: Object.keys(errors).length === 0,\n };\n};\n\nconst CardPaymentMethod = definePaymentMethod((paymentKitStates) => {\n // Object.create() creates prototype delegation: reads fall through to the shared\n // paymentKitStates (preserving auto-detected VGS config), writes stay local.\n // This prevents card-specific properties (cardInputConnections, vgsForm, etc.)\n // from leaking onto the shared paymentKitStates object.\n const localStates = Object.create(paymentKitStates) as CardStates;\n localStates.cardInputConnections = {};\n\n return {\n name: \"card\",\n externalFuncs: {\n createElement: defCreateElement(localStates),\n },\n internalFuncs: {\n submitPayment: defSubmitPayment(localStates),\n cleanup: () => {\n // Clean up VGS form if present\n if (localStates.vgsForm) {\n localStates.vgsFieldsCleanup?.();\n localStates.vgsFieldsCleanup = undefined;\n localStates.vgsForm.unmount();\n localStates.vgsForm = undefined;\n }\n // Clean up all card input iframe connections\n for (const connection of Object.values(localStates.cardInputConnections)) {\n connection?.destroy();\n }\n localStates.cardInputConnections = {};\n },\n },\n };\n});\n\nexport default CardPaymentMethod;\n"],"mappings":";;;;;;;;;;;;;AA6BA,MAAM,aAAa,aAA+D;CAChF,MAAM,UAAU,SAAS,MAAM;CAC/B,MAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,KAAI,eAAe,GACjB,QAAO,EAAE,WAAW,SAAS;AAE/B,QAAO;EACL,WAAW,QAAQ,UAAU,GAAG,WAAW;EAC3C,UAAU,QAAQ,UAAU,aAAa,EAAE,CAAC,MAAM,IAAI;EACvD;;;;;AAMH,MAAM,2BAA2B,WAA6B;CAC5D,MAAM,EAAE,WAAW,aAAa,UAAU,OAAO,cAAc;CAE/D,MAAM,oBACJ,OAAO,oBACP,OAAO,qBACP,OAAO,0BACP,OAAO,0BACP,OAAO,iBACP,OAAO;CAET,MAAM,qBACJ,OAAO,0BACP,OAAO,0BACP,OAAO,iBACP,OAAO,kBACP,OAAO,qBACP,OAAO;CAET,IAAIA;AACJ,KAAI,OAAO,iBACT,KAAI;AACF,WAAS,KAAK,MAAM,OAAO,iBAAiB;SACtC;AACN,WAAS;;AAIb,QAAO;EACL,OAAO,OAAO,kBAAkB;EAChC;EACA;EACA,cAAc,OAAO,0BAA0B;EAC/C,QAAQ,QAAQ,SAAS,SAAS;EAClC,gBAAgB,oBACZ;GACE,SAAS,OAAO,oBAAoB;GACpC,SAAS,OAAO,qBAAqB;GACrC,OAAO,OAAO,0BAA0B;GACxC,OAAO,OAAO,0BAA0B;GACxC,MAAM,OAAO,iBAAiB;GAC9B,OAAO,OAAO,kBAAkB;GACjC,GACD;EACJ,iBAAiB,qBACb;GACE,OAAO,OAAO,0BAA0B;GACxC,OAAO,OAAO,0BAA0B;GACxC,MAAM,OAAO,iBAAiB;GAC9B,OAAO,OAAO,kBAAkB;GAChC,SAAS,OAAO,qBAAqB;GACrC,SAAS,OAAO,oBAAoB;GACrC,GACD;EACL;;AAkBH,MAAM,oBAAoB,WAAuB;CAC/C,MAAM,EAAE,SAAS,YAAY,sBAAsB,aAAa,kBAAkB;AAElF,SAAQ,MAA2B,YAAkC;EACnE,MAAM,EAAE,OAAO,UAAU,eAAe,gBAAgB;EAExD,MAAM,eAAe,mBAA2B;GAE9C,IAAIC;GACJ,IAAIC;GAIJ,IAAI,YAAY;;;;;;AAShB,OAAI,CAAC,OAAO,kBAAmB,QAAO,oBAAoB,EAAE;AAC5D,UAAO,kBAAkB,QAAQ;GAEjC,MAAM,gBAAgB;AACpB,QAAI,UAAW;IACf,MAAM,YAAY,OAAO,yBAAyB;AAClD,YAAQ,IACN,6BAA6B,KAAK,YAAY,OAAO,qBAAqB,gBAAgB,OAAO,cAAc,QAAQ,oBAAoB,OAAO,kBAAkB,UACrK;AAGD,QAAI,aAAa,OAAO,cAAc,OAAO,gBAAgB;AAI3D,SAAI,eAAe;AACjB,UAAI,CAAC,OAAO,kBAAmB,QAAO,oBAAoB,EAAE;AAC5D,aAAO,kBAAkB,QAAQ;;AAEnC,SAAI,aAAa;AACf,UAAI,CAAC,OAAO,gBAAiB,QAAO,kBAAkB,EAAE;AACxD,aAAO,gBAAgB,QAAQ;;AAGjC,SAAI,SAAS,YAAY;MACvB,MAAM,UAAU,OAAO;MACvB,MAAM,SAAS,OAAO;AAEtB,cAAQ,IAAI,oEAAoE,QAAQ,IAAI,OAAO,MAAM;MACzG,MAAM,qBAAqB;MAC3B,IAAIC;AACJ,cAAQ,KAAK,CACX,sBAAsB,EACtB,IAAI,SAAgB,GAAG,WAAW;AAChC,sBAAe,iBAAiB;AAC9B,gBAAQ,KAAK,qDAAqD,qBAAqB,IAAK,GAAG;AAC/F,+BAAO,IAAI,MAAM,iCAAiC,CAAC;UAClD,mBAAmB;QACtB,CACH,CAAC,CACC,cAAc,aAAa,aAAa,CAAC,CACzC,WAAW;AACV,WAAI,UAAW;AACf,eAAQ,IAAI,6DAA6D;OACzE,MAAM,OAAO,eAAe,SAAS,OAAO;AAC5C,WAAI,WAAW;AACb,aAAK,SAAS;AACd;;AAEF,cAAO,UAAU;OAEjB,MAAM,MAAM,QACR,OAAO,YACL,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,EAAE,QAAQ,YAAY,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC,CACvF,GACD;OAKJ,MAAM,cAAc,OAAO,mBAAmB;OAC9C,MAAM,cAAc,OAAO,mBAAmB;AAC9C,WAAI,CAAC,eAAe,CAAC,aAAa;QAChC,MAAM,MACJ,gFACY,CAAC,cAAc,aAAa,KAAK,CAAC,eAAe,CAAC,cAAc,OAAO,KAAK,CAAC,cAAc,aAAa;AACtH,gBAAQ,MAAM,IAAI;AAClB,oBAAY;AACZ;;AAEF,eAAQ,IACN,gDAAgD,eAAe,SAAS,YAAY,SAAS,cAC9F;AACD,cAAO,mBAAmB,oBACxB,MACA;QACE,KAAK;QACL,KAAK;QACL,KAAK;QACN,EACD,KACA,OAAO,mBACP,OAAO,gBACR;AAED,eAAQ,IAAI,oDAAoD;AAChE,qBAAc,iBAAiB;AAC/B,mBAAY;QACZ,CACD,OAAO,QAAQ;AACd,eAAQ,MAAM,qFAAqF,IAAI;AAGvG,mBAAY;QACZ;;AAKN,SAAI,SAAS,WACX,aAAY;AAGd,wBAAmB;AACjB,UAAI,SAAS,cAAc,OAAO,SAAS;AACzC,WAAI;AACF,eAAO,oBAAoB;eACrB;AAGR,cAAO,mBAAmB;AAC1B,WAAI;AACF,eAAO,QAAQ,SAAS;eAClB;AAGR,cAAO,UAAU;;;AAGrB;;AAIF,QAAI,UACF,SAAQ,KACN,sEAAsE,OAAO,cAAc,QAAQ,oBAAoB,OAAO,kBAAkB,QAAQ,uBACzJ;IAIH,MAAM,SAAS,EAAE,eAAe;IAKhC,MAAM,WAAW,iBAAiB,OAAO;IACzC,MAAM,mBAAmB,SAAS,YAAY,QAAQ,SAAS,UAAU;IACzE,MAAM,gBAAgB;KACpB,GAAI,SAAS,EAAE;KACf,QAAQ;KACR,WAAW;KACX,GAAI,mBAAmB,EAAE,SAAS,kBAAkB,GAAG,EAAE;KAC1D;IAED,MAAMC,SAAiC;KACrC,gBAAgB;KAChB,cAAc;KACd,OAAO,KAAK,UAAU,cAAc;KACrC;IAED,MAAM,SAAS,qBAAqB,KAAK,QAAQ,KAAK,IAAI,EAAE,SAAS,OAAO;AAI5E,QAAI,SAAS,aAAa,SACxB,QAAO,MAAM,WAAW;AAE1B,WAAO,MAAM,WAAW;AACxB,WAAO,MAAM,QAAQ;AAIrB,0BAAsB;AAEpB,KADmB,qBAAqB,OAC5B,SAAS;AACrB,SAAI;AACF,aAAO,YAAY,OAAO;aACpB;AAGR,YAAO,qBAAqB,QAAQ;;AAGtC,WAAO,YAAY,OAAO;AAE1B,WAAO,eAAe;AACpB,SAAI,SAAS,WACX,eAAc,iBAAiB;KAGjC,MAAM,aAAa,oBAAoB,QAAQ;MAC7C,UAAU,mBAAmB;MAC7B,eAAe,wBAAwB;MACxC,CAAC;AAEF,YAAO,qBAAqB,QAAQ;;;AAKxC,OAAI,OAAO,oBACT,QAAO,oBAAoB,KAAK,QAAQ;OAExC,UAAS;AAGX,UAAO,EACL,eAAe;AACb,gBAAY;AACZ,kBAAc;AACd,qBAAiB;MAEpB;;AAGH,SAAO,EAAE,OAAO,aAAa;;;AAIjC,MAAM,oBAAoB,WAAuB;CAC/C,MAAMC,gBAAiD,OAAO,QAAQ,YAAY;AAEhF,MAAI,OAAO,oBAAqB,OAAM,OAAO;EAC7C,MAAM,YAAY,OAAO,yBAAyB;EAElD,MAAM,EAAE,eAAe,sBAAsB;AAG7C,gBAAc,aAAa;EAG3B,MAAM,iBAAiB,cAAc,kBAAkB;EAEvD,MAAM,UAAU,MAAM,eAAe,2BAA2B,OAAO,kBAAkB;EAOzF,MAAM,qBADyB,SAAS,2BAA2B,OAE/D;GAAE,WAAW;GAAe,QAAQ,EAAE;GAAsB,GAC5D,MAAM,mBAAmB,OAAO;AACpC,MAAI,CAAC,WAAW;GACd,MAAM,qBAAqB,MAAM,mBAAmB,OAAO;AAC3D,OAAI,EAAE,mBAAmB,aAAa,mBAAmB,YAAY;AACnE,kBAAc,UAAU,MAAM,oBAAoB,yBAAyB;AAC3E,WAAO,EAAE,QAAQ;KAAE,GAAG,mBAAmB;KAAQ,GAAG,mBAAmB;KAAQ,EAAE;;aAE1E,CAAC,mBAAmB,WAAW;AACxC,iBAAc,UAAU,MAAM,oBAAoB,yBAAyB;AAC3E,UAAO,EAAE,QAAQ,mBAAmB,QAAQ;;AAI9C,MAAI,CAAC,OAAO,kBAIV,QAAO,qBAHK,MAAM,QAAQ,gBAAgB,sBAAsB,EAC9D,eAAe,OAAO,aACvB,CAAC,EAC6B;AAIjC,MAAI,WAAW;AAEb,WAAQ,IAAI,8CAA8C;GAC1D,MAAM,kBAAkB,MAAM,oBAAoB,QAAQ,QAAQ;AAClE,OAAI,CAAC,gBAAgB,WAAW;IAE9B,MAAM,cAAc,OAAO,QAAQ,gBAAgB,OAAO,CACvD,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,IAAI,IAAI,CAC7B,KAAK,KAAK;AACb,kBAAc,UAAU,MAAM,qBAAqB,eAAe,6BAA6B;AAC/F,WAAO,EAAE,QAAQ,gBAAgB,QAAQ;;SAEtC;GAEL,MAAM,mBAAmB,MAAM,iBAAiB,OAAO;AACvD,OAAI,CAAC,iBAAiB,WAAW;AAC/B,kBAAc,UAAU,MAAM,qBAAqB,yBAAyB;AAC5E,WAAO,EAAE,QAAQ,iBAAiB,QAAQ;;;EAK9C,MAAM,kBAAkB,MAAM,QAAQ,gBAAgB,mBAAmB;GACvE,mBAAmB,OAAO;GAC1B,eAAe,OAAO;GACvB,CAAC;AACF,MAAI,CAAC,gBAAgB,cAAc;GACjC,MAAM,SAAS,EAAE;AACjB,OAAI,CAAC,gBAAgB,aAAc,QAAO,WAAW;AACrD,OAAI,CAAC,gBAAgB,aAAc,QAAO,WAAW;AACrD,OAAI,CAAC,gBAAgB,aAAc,QAAO,WAAW;AACrD,iBAAc,UAAU,MAAM,yBAAyB,0BAA0B;AACjF,UAAO,EAAE,QAAQ;;AAGnB,UAAQ,IAAI,8BAA8B,gBAAgB;AAC1D,UAAQ,IAAI,UAAU,OAAO;EAG7B,IAAI,gBAAgB,MAAM,QAAQ,gBAAgB,aAChD;GACE,eAAe,OAAO;GACtB,2BAA2B;IACzB,mBAAmB,OAAO;IAC1B,cAAc,wBAAwB,OAAO;IAC7C,eAAe,sBAAsB;IACtC;GACF,EACD,eACD;AAED,UAAQ,IAAI,yBAAyB,cAAc;EAKnD,MAAM,mBAAmB;EACzB,IAAI,kBAAkB;AAEtB,SAAO,cAAc,cAAc,kBAAkB,kBAAkB;AACrE;AACA,WAAQ,IAAI,wBAAwB,gBAAgB,GAAG,iBAAiB,KAAK;GAE7E,MAAM,eAAe,MAAM,iBAAiB,cAAc,WAAW;AAKrE,WAAQ,IAAI,+CAA+C;GAC3D,MAAM,eAAe,MAAM,QAAQ,gBAAgB,mBACjD,EACE,eAAe,OAAO,aACvB,EACD,eACD;AAID,OAAI,aAAa,YAAY;AAC3B,QAAI,CAAC,aAAa,QAChB,SAAQ,IAAI,kEAAkE;QAE9E,SAAQ,IAAI,mDAAmD;AAEjE,oBAAgB;AAChB;;AAGF,OAAI,CAAC,aAAa,SAAS;AAGzB,YAAQ,IAAI,kDAAkD,aAAa;AAC3E,kBAAc,UACZ,aAAa,qBAAqB,MAClC,aAAa,aAAa,cAC1B,aAAa,2BAA2B,aAAa,MACtD;AACD,WAAO,EACL,QAAQ;KACN,MAAM,aAAa,2BAA2B,aAAa;KAC3D,mBAAmB;KACpB,EACF;;AAGH,WAAQ,IAAI,4BAA4B,aAAa;AAGrD,iBAAc,aAAa,aAAa,qBAAqB,UAAU;AACvE,UAAO,EAAE,MAAM,cAA4C;;AAG7D,MAAI,mBAAmB,kBAAkB;AACvC,WAAQ,MAAM,4BAA4B;AAC1C,iBAAc,UAAU,MAAM,wBAAwB,mCAAmC;AACzF,UAAO,EAAE,QAAQ,EAAE,MAAM,uDAAuD,EAAE;;AAKpF,MAAI,cAAc,UAAU,oBAAoB,cAAc,UAAU,mBAAmB;AACzF,WAAQ,IAAI,yBAAyB,cAAc;AACnD,iBAAc,UACZ,cAAc,qBAAqB,MACnC,cAAc,aAAa,kBAC3B,cAAc,2BAA2B,iBAC1C;AAGD,UAAO,EACL,QAAQ;IACN,MAAM,cAAc,2BAA2B;IAC/C,mBAAmB;IACpB,EACF;;AAGH,UAAQ,IAAI,6BAA6B,cAAc;AACvD,gBAAc,aAAa,cAAc,qBAAqB,UAAU;AACxE,SAAO,EAAE,MAAM,eAA6C;;AAE9D,QAAO;;;;;;AAOT,MAAM,iCAAiC;AAEvC,MAAM,oBAAoB,OAAO,YAAoB,gBAAyC;CAC5F,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,+BAA+B;AAEtF,KAAI;EACF,MAAM,OAAO,MAAM,MAAM,GAAG,WAAW,0BAA0B,YAAY,iBAAiB;GAC5F,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,QAAQ,WAAW;GACpB,CAAC;AACF,MAAI,CAAC,KAAK,GACR,OAAM,IAAI,MAAM,gCAAgC,KAAK,SAAS;AAGhE,UADa,MAAM,KAAK,MAAM,EAClB;WACJ;AACR,eAAa,UAAU;;;;;;;;;;;;;;;;;;AAmB3B,MAAMC,gBAAwD;CAE5D,KAAK;CACL,KAAK;CACL,YAAY;CAEZ,eAAe;CACf,sBAAsB;CACtB,wBAAwB;CACzB;;;;;AAMD,MAAM,kBAAkB,QAAyB;AAC/C,KAAI,eAAe,MAAO,QAAO,IAAI;AACrC,KAAI;AACF,SAAO,KAAK,UAAU,IAAI;SACpB;AACN,SAAO,OAAO,IAAI;;;AAItB,MAAM,sBAAsB,OAC1B,QACA,YAC8D;CAC9D,MAAM,EAAE,SAAS,mBAAmB,aAAa,YAAY,sBAAsB;CACnF,MAAM,YAAY,iBAAiB,kBAAkB;CACrD,MAAM,SAAS,EAAE;AAEjB,KAAI,CAAC,SAAS;AACZ,SAAO,WAAW;AAClB,SAAO;GAAE;GAAQ,WAAW;GAAO;;AAGrC,KAAI,CAAC,mBAAmB;AACtB,SAAO,OAAO;AACd,SAAO;GAAE;GAAQ,WAAW;GAAO;;CAIrC,IAAIC;CACJ,MAAM,oBAAoB,YAAY,KAAK;AAC3C,KAAI;AACF,gBAAc,MAAM,kBAAkB,YAAY,YAAY;EAC9D,MAAM,uBAAuB,KAAK,MAAM,YAAY,KAAK,GAAG,kBAAkB;AAC9E,mBAAiB,QAAQ,4BAA4B;GACnD,qBAAqB;GACrB,YAAY;GACZ,aAAa;GACb,SAAS;GACV,CAAC;UACK,KAAK;EACZ,MAAM,uBAAuB,KAAK,MAAM,YAAY,KAAK,GAAG,kBAAkB;EAC9E,MAAM,eAAe,eAAe,gBAAgB,IAAI,SAAS;AACjE,mBAAiB,QAAQ,4BAA4B;GACnD,qBAAqB;GACrB,YAAY;GACZ,aAAa;GACb,SAAS;GACT,YAAY,eAAe,kBAAkB;GAC9C,CAAC;AACF,UAAQ,MAAM,GAAG,UAAU,gCAAgC,eAAe,IAAI,CAAC;AAC/E,SAAO,OAAO,eACV,qDACA;AACJ,SAAO;GAAE;GAAQ,WAAW;GAAO;;CAIrC,IAAIC;CACJ,MAAM,6BAA6B;CACnC,MAAM,kBAAkB,YAAY,KAAK;AACzC,KAAI;EACF,IAAIC;AACJ,eAAa,MAAM,QAAQ,KAAK,CAC9B,IAAI,SAAgC,SAAS,WAAW;AACtD,WAAQ,WACN;IACE,MAAM;IACN,MAAM,EAAE,YAAY,EAAE,EAAE;IACzB,GACA,SAAS,eAAe,QAAQ,WAAW,GAC3C,UAAU,OAAO,MAAM,CACzB;IACD,EACF,IAAI,SAAgB,GAAG,WAAW;AAChC,yBAAsB,iBAAiB,uBAAO,IAAI,MAAM,cAAc,CAAC,EAAE,2BAA2B;IACpG,CACH,CAAC,CAAC,cAAc,aAAa,oBAAoB,CAAC;EAGnD,MAAM,qBAAqB,KAAK,MAAM,YAAY,KAAK,GAAG,gBAAgB;AAC1E,mBAAiB,QAAQ,0BAA0B;GACjD,qBAAqB;GACrB,YAAY;GACZ,aAAa;GACb,SAAS;GACV,CAAC;UACK,KAAK;EACZ,MAAM,qBAAqB,KAAK,MAAM,YAAY,KAAK,GAAG,gBAAgB;EAC1E,MAAM,SAAS,eAAe,IAAI;AAClC,UAAQ,MAAM,GAAG,UAAU,0BAA0B,OAAO;AAG5D,MAAI,eAAe,SAAS,IAAI,YAAY,eAAe;AACzD,oBAAiB,QAAQ,0BAA0B;IACjD,qBAAqB;IACrB,YAAY;IACZ,aAAa;IACb,SAAS;IACT,YAAY;IACb,CAAC;AACF,UAAO,OAAO;AACd,UAAO;IAAE;IAAQ,WAAW;IAAO;;AAMrC,MAAI,OAAO,OAAO,QAAQ,YAAY,EAAE,eAAe,QAAQ;GAC7D,MAAM,YAAY;AAClB,QAAK,MAAM,CAAC,QAAQ,aAAa,OAAO,QAAQ,cAAc,CAC5D,KAAI,UAAU,WAAW;IAEvB,MAAM,WADW,UAAU,SACA;AAC3B,WAAO,YAAY,MAAM,QAAQ,SAAS,GAAG,SAAS,KAAK;;AAG/D,OAAI,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG;AAClC,qBAAiB,QAAQ,0BAA0B;KACjD,qBAAqB;KACrB,YAAY;KACZ,aAAa;KACb,SAAS;KACT,YAAY;KACb,CAAC;AACF,WAAO;KAAE;KAAQ,WAAW;KAAO;;;AAKvC,mBAAiB,QAAQ,0BAA0B;GACjD,qBAAqB;GACrB,YAAY;GACZ,aAAa;GACb,SAAS;GACT,YAAY;GACb,CAAC;AACF,SAAO,OAAO;AACd,SAAO;GAAE;GAAQ,WAAW;GAAO;;AAIrC,KAAI,CAAC,YAAY,MAAM,YAAY;AACjC,UAAQ,MAAM,GAAG,UAAU,6CAA6C,eAAe,WAAW,CAAC;AACnG,SAAO,OAAO;AACd,SAAO;GAAE;GAAQ,WAAW;GAAO;;CAErC,MAAM,EAAE,WAAW,WAAW,WAAW,aAAa,WAAW,KAAK;AAEtE,KAAI,CAAC,UACH,SAAQ,KACN,GAAG,UAAU,0DACb,KAAK,UAAU,WAAW,KAAK,WAAW,CAC3C;CAGH,MAAM,WAAW,WAAW,MAAM,MAAO,WAAW;CACpD,MAAM,eAAe,GAAG,OAAO,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG;CAG9D,MAAM,YAAY,WAAW,KAAK;AAOlC,KAAI;EACF,MAAM,mBAAmB,QAAQ,gBAAgB,sBAAsB;GACrE,eAAe;GACI;GACnB,0BAA0B;IACxB,SAAS;IACT,SAAS;IACT,GAAI,YAAY,EAAE,SAAS,WAAW,GAAG,EAAE;IAChC;IACX,eAAe,sBAAsB;IACtC;GACF,CAAC;EAEF,MAAM,eAAe,IAAI,SAAe,SAAS,WAAW;AAC1D,OAAI,CAAC,QAAQ,QAAQ;AACnB,2BAAO,IAAI,MAAM,gCAAgC,CAAC;AAClD;;AAEF,WAAQ,OACN,2BAA2B,YAAY,GAAG,qBAC1C;IACE,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,OAAO,YAAqC,EAAE,UAAU,OAAO,KAAK;IACrE,GACA,YAAoB,SAAS,GAC7B,QAAiB,OAAO,IAAI,CAC9B;IACD;AAEF,QAAM,QAAQ,IAAI,CAAC,kBAAkB,aAAa,CAAC;UAC5C,KAAK;AACZ,UAAQ,MAAM,GAAG,UAAU,iCAAiC,eAAe,IAAI,CAAC;AAChF,SAAO,OAAO;AACd,SAAO;GAAE;GAAQ,WAAW;GAAO;;AAGrC,QAAO;EAAE,QAAQ,EAAE;EAAE,WAAW;EAAM;;AAGxC,MAAM,mBAAmB,OAAO,WAAuB;CACrD,MAAM,SAAS,EAAE;CACjB,MAAM,EAAE,mBAAmB,yBAAyB;CAEpD,MAAM,iBAAiB,OAAO,QAAQ,qBAAqB,CAAC,IAAI,OAAO,CAAC,OAAO,gBAAgB;EAC7F,MAAM,OAAO;EAGb,MAAM,SAAS,OADA,MAAM,WAAW,SACJ,SAAS,qBAAqB,GAAG;AAE7D,MAAI,WAAW,OACb,QAAO,QAAQ,OAAO;GAExB;AAEF,OAAM,QAAQ,WAAW,eAAe;AAExC,QAAO;EACL;EACA,WAAW,OAAO,KAAK,OAAO,CAAC,WAAW;EAC3C;;AAGH,MAAM,qBAAqB,OAAO,WAAuB;CACvD,MAAMC,SAA2B,EAAE;CACnC,MAAM,EAAE,yBAAyB;CAEjC,MAAM,mBAAmB,OAAO,QAAQ,qBAAqB,CAAC,IAAI,OAAO,CAAC,OAAO,gBAAgB;EAC/F,MAAM,OAAO;AAEb,MAAI,CAAC,YAAY;AACf,UAAO,QAAQ;AACf;;EAIF,MAAM,WAAW,OADF,MAAM,WAAW,SACF,YAAY;AAE1C,MAAI,SACF,QAAO,QAAQ;GAEjB;AAEF,OAAM,QAAQ,WAAW,iBAAiB;AAE1C,QAAO;EACL;EACA,WAAW,OAAO,KAAK,OAAO,CAAC,WAAW;EAC3C;;AAGH,MAAM,oBAAoB,qBAAqB,qBAAqB;CAKlE,MAAM,cAAc,OAAO,OAAO,iBAAiB;AACnD,aAAY,uBAAuB,EAAE;AAErC,QAAO;EACL,MAAM;EACN,eAAe,EACb,eAAe,iBAAiB,YAAY,EAC7C;EACD,eAAe;GACb,eAAe,iBAAiB,YAAY;GAC5C,eAAe;AAEb,QAAI,YAAY,SAAS;AACvB,iBAAY,oBAAoB;AAChC,iBAAY,mBAAmB;AAC/B,iBAAY,QAAQ,SAAS;AAC7B,iBAAY,UAAU;;AAGxB,SAAK,MAAM,cAAc,OAAO,OAAO,YAAY,qBAAqB,CACtE,aAAY,SAAS;AAEvB,gBAAY,uBAAuB,EAAE;;GAExC;EACF;EACD;AAEF,mBAAe"}
|