@payment-kit-js/vanilla 0.5.17 → 0.5.19

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.
Files changed (46) hide show
  1. package/README.md +14 -0
  2. package/dist/{bnpl-shared-DGs1YzS9.mjs → bnpl-shared-CL900HFN.mjs} +2 -2
  3. package/dist/{bnpl-shared-DGs1YzS9.mjs.map → bnpl-shared-CL900HFN.mjs.map} +1 -1
  4. package/dist/{bnpl-shared-BQwCBD45.d.mts → bnpl-shared-D-Kd58Qz.d.mts} +2 -2
  5. package/dist/{bnpl-shared-BQwCBD45.d.mts.map → bnpl-shared-D-Kd58Qz.d.mts.map} +1 -1
  6. package/dist/cdn/paymentkit.js +263 -61
  7. package/dist/cdn/paymentkit.js.map +3 -3
  8. package/dist/cdn/paymentkit.min.js +24 -24
  9. package/dist/cdn/paymentkit.min.js.map +3 -3
  10. package/dist/index.d.mts +2 -2
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +75 -6
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/{next-action-handlers-CLOt1wzO.mjs → next-action-handlers-DzhzSvEB.mjs} +19 -19
  15. package/dist/next-action-handlers-DzhzSvEB.mjs.map +1 -0
  16. package/dist/payment-methods/affirm.d.mts +2 -2
  17. package/dist/payment-methods/affirm.mjs +2 -2
  18. package/dist/payment-methods/afterpay.d.mts +2 -2
  19. package/dist/payment-methods/afterpay.mjs +2 -2
  20. package/dist/payment-methods/apple-pay.d.mts +2 -2
  21. package/dist/payment-methods/apple-pay.d.mts.map +1 -1
  22. package/dist/payment-methods/apple-pay.mjs +2 -2
  23. package/dist/payment-methods/apple-pay.mjs.map +1 -1
  24. package/dist/payment-methods/bnpl-shared.d.mts +2 -2
  25. package/dist/payment-methods/bnpl-shared.mjs +2 -2
  26. package/dist/payment-methods/card.d.mts +1 -1
  27. package/dist/payment-methods/card.d.mts.map +1 -1
  28. package/dist/payment-methods/card.mjs +14 -8
  29. package/dist/payment-methods/card.mjs.map +1 -1
  30. package/dist/payment-methods/google-pay.d.mts +25 -3
  31. package/dist/payment-methods/google-pay.d.mts.map +1 -1
  32. package/dist/payment-methods/google-pay.mjs +131 -10
  33. package/dist/payment-methods/google-pay.mjs.map +1 -1
  34. package/dist/payment-methods/klarna.d.mts +2 -2
  35. package/dist/payment-methods/klarna.mjs +2 -2
  36. package/dist/payment-methods/next-action-handlers.mjs +1 -1
  37. package/dist/payment-methods/paypal.d.mts +1 -1
  38. package/dist/payment-methods/paypal.mjs +1 -1
  39. package/dist/{types-B3mjYfOm.d.mts → types-Cjcc3xak.d.mts} +6 -9
  40. package/dist/types-Cjcc3xak.d.mts.map +1 -0
  41. package/dist/{utils-Dc6zwOe1.mjs → utils-DIqrx4XF.mjs} +10 -7
  42. package/dist/utils-DIqrx4XF.mjs.map +1 -0
  43. package/package.json +2 -2
  44. package/dist/next-action-handlers-CLOt1wzO.mjs.map +0 -1
  45. package/dist/types-B3mjYfOm.d.mts.map +0 -1
  46. package/dist/utils-Dc6zwOe1.mjs.map +0 -1
@@ -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 iframe.remove();\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 // Include processor_fraud_info with airwallex_device_id for fraud fingerprinting\n const fraudMetadata = {\n ...collectFraudMetadata(),\n processorFraudInfo: {\n airwallexDeviceId: states.checkoutRequestId,\n },\n };\n let currentResult = await tunnelX.publicEndpoints.cardCheckout(\n {\n checkoutToken: states.secureToken,\n publicCardCheckoutRequest: {\n cardSetupIntentId: states.cardSetupIntentId,\n customerInfo: mapFieldsToCustomerInfo(fields),\n fraudMetadata,\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":"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"}
@@ -1,4 +1,4 @@
1
- import { r as PaymentMethod } from "../types-B3mjYfOm.mjs";
1
+ import { i as PaymentMethod } from "../types-Cjcc3xak.mjs";
2
2
  import "../connect-card-CZhzK_Tp.mjs";
3
3
  import "../connect-tunnel-x-BKtMfoGh.mjs";
4
4
  import { a as GooglePayEncryptedToken } from "../airwallex-google-pay-adapter-D-AxVLLq.mjs";
@@ -72,11 +72,33 @@ type GooglePayConfirmResponse = {
72
72
  card_exp_year?: number;
73
73
  };
74
74
  type GooglePaySubmitOptions = {
75
- processorId: string;
75
+ /** Processor external ID — optional when using auto-prepare (SDK fetches from checkout session) */
76
+ processorId?: string;
76
77
  customerInfo: GooglePayCustomerInfo;
77
78
  mockScenario?: GooglePayMockScenario;
78
79
  };
79
- declare const GooglePayPaymentMethod: PaymentMethod<{}, "google_pay">;
80
+ declare const GooglePayPaymentMethod: PaymentMethod<{
81
+ /**
82
+ * Register a callback to be notified when Google Pay becomes ready (or stops being ready).
83
+ * Fires immediately with the current state, then on every state change.
84
+ * Multiple registrations are all notified — none are silently overwritten.
85
+ *
86
+ * @example
87
+ * paymentKit.google_pay.onGooglePayReady((isReady) => {
88
+ * googlePayButton.disabled = !isReady;
89
+ * });
90
+ */
91
+ onGooglePayReady: (callback: (isReady: boolean) => void) => void;
92
+ /**
93
+ * Notify the SDK that the payment amount has changed (e.g. coupon applied).
94
+ * The SDK will disable Google Pay, re-prepare with the new amount, then re-enable.
95
+ * The returned promise resolves when re-prepare is fully complete.
96
+ *
97
+ * @example
98
+ * await paymentKit.google_pay.notifyAmountChanged();
99
+ */
100
+ notifyAmountChanged: () => Promise<void>;
101
+ }, "google_pay">;
80
102
  //#endregion
81
103
  export { Airwallex3dsNextAction, GooglePayConfirmRequest, GooglePayConfirmResponse, GooglePayCustomerInfo, GooglePayMockScenario, GooglePayStartRequest, GooglePayStartResponse, GooglePaySubmitOptions, GooglePayPaymentMethod as default };
82
104
  //# sourceMappingURL=google-pay.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-pay.d.mts","names":[],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":[],"mappings":";;;;;;;KAYY,qBAAA;;;;;AAAA,KAMA,qBAAA,GANqB;EAMrB,YAAA,EAAA,MAAA;EAWA,aAAA,EATK,qBASiB;EAuBtB,cAAA,EAAA;IAOA,SAAA,CAAA,EAAA,MAAA;IAOA,WAAA,CAAA,EAAA;MAuBA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAsB;IAmhB5B,CAAA;;;;;;;KA/kBM,sBAAA;;;;;;;;;;;;;;KAuBA,uBAAA;qBACS;;;;KAMT,sBAAA;;;;;;KAOA,wBAAA;;;;;;;;;gBASI;;;;;;;;;;;;;KAcJ,sBAAA;;gBAEI;iBACC;;cAghBX,wBASJ"}
1
+ {"version":3,"file":"google-pay.d.mts","names":[],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":[],"mappings":";;;;;;;KAYY,qBAAA;;;;;AAAA,KAMA,qBAAA,GANqB;EAMrB,YAAA,EAAA,MAAA;EAWA,aAAA,EATK,qBASiB;EAuBtB,cAAA,EAAA;IAOA,SAAA,CAAA,EAAA,MAAA;IAOA,WAAA,CAAA,EAAA;MAuBA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAsB;IA2lB5B,CAAA;;;;;;;KAvpBM,sBAAA;;;;;;;;;;;;;;KAuBA,uBAAA;qBACS;;;;KAMT,sBAAA;;;;;;KAOA,wBAAA;;;;;;;;;gBASI;;;;;;;;;;;;;KAcJ,sBAAA;;;gBAGI;iBACC;;cAulBX,wBAsHgC;;;;;;;;;;;;;;;;;;;;6BAAP"}
@@ -1,6 +1,6 @@
1
- import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "../utils-Dc6zwOe1.mjs";
1
+ import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "../utils-DIqrx4XF.mjs";
2
2
  import { n as AirwallexGooglePayMockScenario, t as AirwallexGooglePayAdapter } from "../airwallex-google-pay-adapter-BvlROwj_.mjs";
3
- import { t as handleNextAction } from "../next-action-handlers-CLOt1wzO.mjs";
3
+ import { t as handleNextAction } from "../next-action-handlers-DzhzSvEB.mjs";
4
4
  import { n as StripeGooglePayAdapter, t as GooglePayMockScenario } from "../stripe-google-pay-adapter-B346KXt4.mjs";
5
5
 
6
6
  //#region src/payment-methods/google-pay.ts
@@ -22,10 +22,42 @@ async function apiCall(url, options, checkoutRequestId) {
22
22
  }
23
23
  return { data: await response.json() };
24
24
  }
25
- function validateOptions(options) {
26
- if (!options?.processorId) return { processor_id: "Processor ID is required" };
25
+ function validateOptions(options, autoPrepareConfig) {
26
+ if (!options?.processorId && !autoPrepareConfig?.processorId) return { processor_id: "Processor ID is required" };
27
27
  return null;
28
28
  }
29
+ /**
30
+ * Check if Google Pay is available on this device/browser.
31
+ * Uses the Google Pay API's isReadyToPay() method.
32
+ */
33
+ async function checkGooglePayAvailability() {
34
+ if (!window.google?.payments?.api?.PaymentsClient) {
35
+ console.log("[GooglePay] Google Pay API not loaded");
36
+ return false;
37
+ }
38
+ try {
39
+ return (await new window.google.payments.api.PaymentsClient({ environment: "TEST" }).isReadyToPay({
40
+ apiVersion: 2,
41
+ apiVersionMinor: 0,
42
+ allowedPaymentMethods: [{
43
+ type: "CARD",
44
+ parameters: {
45
+ allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
46
+ allowedCardNetworks: [
47
+ "VISA",
48
+ "MASTERCARD",
49
+ "AMEX",
50
+ "DISCOVER",
51
+ "JCB"
52
+ ]
53
+ }
54
+ }]
55
+ })).result;
56
+ } catch (error) {
57
+ console.error("[GooglePay] availability check error:", error);
58
+ return false;
59
+ }
60
+ }
29
61
  function getMockScenarioStr(mockScenario) {
30
62
  return mockScenario && mockScenario !== GooglePayMockScenario.None ? mockScenario : void 0;
31
63
  }
@@ -241,17 +273,22 @@ async function confirmAirwallexGooglePay(apiBaseUrl, secureToken, googlePayToken
241
273
  if (userActionCount >= MAX_USER_ACTIONS) return { errors: { google_pay: "Too many authentication attempts. Please try again." } };
242
274
  return toGooglePayResult(response, secureToken);
243
275
  }
244
- const defSubmitPayment = (states) => {
276
+ const defSubmitPayment = (states, getAutoPrepareConfig) => {
245
277
  const submitPayment = async (_fields, options) => {
246
278
  const { apiBaseUrl, secureToken, environment } = states;
247
279
  const gpayOptions = options;
248
- const validationError = validateOptions(gpayOptions);
280
+ const autoPrepareConfig = getAutoPrepareConfig();
281
+ const validationError = validateOptions(gpayOptions, autoPrepareConfig);
249
282
  if (validationError) return { errors: validationError };
283
+ const effectiveOptions = {
284
+ ...gpayOptions,
285
+ processorId: gpayOptions.processorId || autoPrepareConfig?.processorId || ""
286
+ };
250
287
  try {
251
288
  const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);
252
289
  const checkoutRequestId = getOrCreateCheckoutRequestId(environment);
253
290
  console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);
254
- const startResult = await callStartEndpoint(apiBaseUrl, secureToken, gpayOptions, mockScenarioStr, checkoutRequestId);
291
+ const startResult = await callStartEndpoint(apiBaseUrl, secureToken, effectiveOptions, mockScenarioStr, checkoutRequestId);
255
292
  if (startResult.error || !startResult.data) return { errors: { google_pay: startResult.error || "Failed to start Google Pay" } };
256
293
  const startData = startResult.data;
257
294
  if (startData.processor === "stripe") {
@@ -273,12 +310,96 @@ const defSubmitPayment = (states) => {
273
310
  return submitPayment;
274
311
  };
275
312
  const GooglePayPaymentMethod = definePaymentMethod((paymentKitStates) => {
313
+ const { apiBaseUrl, secureToken, environment } = paymentKitStates;
314
+ let autoPrepareConfig = null;
315
+ let onGooglePayReadyCallbacks = [];
316
+ let isGooglePayReadyState = false;
317
+ let autoPrepareInProgress = false;
318
+ let cleanupGeneration = 0;
319
+ let pendingAutoPrepareArgs = null;
320
+ let pendingPrepareResolvers = [];
321
+ function instanceSetGooglePayReady(ready) {
322
+ isGooglePayReadyState = ready;
323
+ for (const cb of onGooglePayReadyCallbacks) cb(ready);
324
+ }
325
+ function instanceClearPreparedGooglePay() {
326
+ instanceSetGooglePayReady(false);
327
+ }
328
+ async function instanceAutoPrepare(apBase, sToken, env) {
329
+ if (autoPrepareInProgress) {
330
+ pendingAutoPrepareArgs = {
331
+ apiBaseUrl: apBase,
332
+ secureToken: sToken,
333
+ environment: env
334
+ };
335
+ return new Promise((resolve) => pendingPrepareResolvers.push(resolve));
336
+ }
337
+ autoPrepareInProgress = true;
338
+ const capturedGeneration = cleanupGeneration;
339
+ instanceSetGooglePayReady(false);
340
+ try {
341
+ const result = await apiCall(`${apBase}/api/checkout-sessions/token/${sToken}`, { method: "GET" });
342
+ if (cleanupGeneration !== capturedGeneration) return;
343
+ if (result.error || !result.data) {
344
+ console.warn("[GooglePay] Auto-prepare: failed to fetch session config:", result.error);
345
+ return;
346
+ }
347
+ const processorId = result.data.express_checkout_processor_id;
348
+ if (!processorId) {
349
+ console.log("[GooglePay] Auto-prepare: no express checkout processor configured");
350
+ return;
351
+ }
352
+ const processorTypeRaw = result.data.express_checkout_processor_type;
353
+ autoPrepareConfig = {
354
+ processorId,
355
+ processorType: processorTypeRaw === "airwallex" || processorTypeRaw === "stripe" ? processorTypeRaw : void 0
356
+ };
357
+ const isAvailable = await checkGooglePayAvailability();
358
+ if (cleanupGeneration !== capturedGeneration) return;
359
+ instanceSetGooglePayReady(isAvailable);
360
+ } catch (err) {
361
+ if (cleanupGeneration === capturedGeneration) console.error("[GooglePay] Auto-prepare failed:", err);
362
+ } finally {
363
+ autoPrepareInProgress = false;
364
+ const stale = cleanupGeneration !== capturedGeneration;
365
+ const pending = pendingAutoPrepareArgs;
366
+ const resolvers = pendingPrepareResolvers.splice(0);
367
+ if (!stale && pending) {
368
+ pendingAutoPrepareArgs = null;
369
+ instanceAutoPrepare(pending.apiBaseUrl, pending.secureToken, pending.environment).then(() => {
370
+ for (const r of resolvers) r();
371
+ });
372
+ } else {
373
+ pendingAutoPrepareArgs = null;
374
+ for (const r of resolvers) r();
375
+ }
376
+ }
377
+ }
378
+ instanceAutoPrepare(apiBaseUrl, secureToken, environment).catch((err) => console.error("[GooglePay] Unhandled init error:", err));
276
379
  return {
277
380
  name: "google_pay",
278
- externalFuncs: {},
381
+ externalFuncs: {
382
+ onGooglePayReady: (callback) => {
383
+ onGooglePayReadyCallbacks.push(callback);
384
+ callback(isGooglePayReadyState);
385
+ },
386
+ notifyAmountChanged: () => {
387
+ instanceClearPreparedGooglePay();
388
+ autoPrepareConfig = null;
389
+ return instanceAutoPrepare(apiBaseUrl, secureToken, environment);
390
+ }
391
+ },
279
392
  internalFuncs: {
280
- submitPayment: defSubmitPayment(paymentKitStates),
281
- cleanup: () => {}
393
+ submitPayment: defSubmitPayment(paymentKitStates, () => autoPrepareConfig),
394
+ cleanup: () => {
395
+ cleanupGeneration++;
396
+ onGooglePayReadyCallbacks = [];
397
+ isGooglePayReadyState = false;
398
+ autoPrepareConfig = null;
399
+ pendingAutoPrepareArgs = null;
400
+ pendingPrepareResolvers = [];
401
+ autoPrepareInProgress = false;
402
+ }
282
403
  }
283
404
  };
284
405
  });
@@ -1 +1 @@
1
- {"version":3,"file":"google-pay.mjs","names":["airwallexMockScenario: AirwallexGooglePayMockScenario","config: AirwallexGooglePayConfig","requestBody: GooglePayConfirmRequest","submitPayment: TInternalFuncs[\"submitPayment\"]"],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":["import type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\nimport {\n AirwallexGooglePayAdapter,\n type AirwallexGooglePayConfig,\n AirwallexGooglePayMockScenario,\n type GooglePayEncryptedToken,\n} from \"./airwallex-google-pay-adapter\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { GooglePayMockScenario, StripeGooglePayAdapter } from \"./stripe-google-pay-adapter\";\n\n// Google Pay-specific types\nexport type GooglePayCustomerInfo = {\n first_name: string;\n last_name: string;\n email?: string;\n};\n\nexport type GooglePayStartRequest = {\n processor_id: string;\n customer_info: GooglePayCustomerInfo;\n fraud_metadata: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n mock_scenario?: string;\n};\n\nexport type GooglePayStartResponse = {\n checkout_attempt_id: string;\n amount: number;\n amount_display: string; // Formatted for Google Pay (e.g., \"100.00\" for USD, \"1000\" for JPY)\n currency: string;\n country: string;\n\n // Processor discriminator\n processor: \"stripe\" | \"airwallex\";\n\n // Environment flag\n is_sandbox?: boolean;\n\n // Stripe-specific fields (when processor=\"stripe\")\n client_secret?: string;\n stripe_pk?: string;\n\n // Airwallex-specific fields (when processor=\"airwallex\")\n merchant_name?: string;\n airwallex_account_id?: string;\n google_merchant_id?: string; // Google-assigned merchant ID for production (BCR2DN...)\n};\n\nexport type GooglePayConfirmRequest = {\n google_pay_token?: GooglePayEncryptedToken; // Required for Airwallex\n payer_email?: string; // Email from payment sheet (Stripe Google Pay)\n mock_scenario?: string;\n};\n\n// Airwallex 3DS next action type (matches backend snake_case response)\nexport type Airwallex3dsNextAction = {\n type: \"airwallex_3ds\";\n url: string;\n method: string;\n payment_intent_id: string;\n};\n\nexport type GooglePayConfirmResponse = {\n charge_status: \"success\" | \"fail\" | \"pending\";\n transaction_id?: string;\n error_code?: string;\n error_message?: 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 GooglePaySubmitOptions = {\n processorId: string;\n customerInfo: GooglePayCustomerInfo;\n mockScenario?: GooglePayMockScenario;\n};\n\ntype GooglePayResult =\n | { data: { [key: string]: unknown }; errors?: never }\n | { data?: never; errors: PaymentKitErrors };\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 // Add x-request-id header if provided\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: GooglePaySubmitOptions): PaymentKitErrors | null {\n if (!options?.processorId) {\n return { processor_id: \"Processor ID is required\" };\n }\n // Customer name is optional — Google Pay collects it from the payment sheet\n return null;\n}\n\nfunction getMockScenarioStr(mockScenario?: GooglePayMockScenario): string | undefined {\n return mockScenario && mockScenario !== GooglePayMockScenario.None ? mockScenario : undefined;\n}\n\nasync function callStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: GooglePaySubmitOptions,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<{ data?: GooglePayStartResponse; error?: string }> {\n return apiCall<GooglePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-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 mock_scenario: mockScenarioStr,\n } as GooglePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\n// =============================================================================\n// Stripe Flow\n// =============================================================================\n\nfunction initializeStripeAdapter(\n stripePk: string,\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): { adapter?: StripeGooglePayAdapter; error?: string } {\n const adapter = new StripeGooglePayAdapter(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 const prConfig = {\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: { label: \"Total\", amount: startData.amount },\n requestPayerName: true,\n requestPayerEmail: true,\n };\n adapter.createPaymentRequest(prConfig);\n return { adapter };\n}\n\nasync function runStripeFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; error?: string; payerEmail?: string }> {\n if (!startData.stripe_pk || !startData.client_secret) {\n return { success: false, error: \"Stripe credentials not provided\" };\n }\n\n // Initialize Stripe adapter\n const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Confirm with Stripe SDK\n const confirmResult = await adapter.confirmCardSetup(startData.client_secret, paymentResult.paymentMethodId);\n\n if (!confirmResult.success) {\n paymentResult.complete(\"fail\");\n return { success: false, error: \"error\" in confirmResult ? confirmResult.error : \"Card setup failed\" };\n }\n\n paymentResult.complete(\"success\");\n return { success: true, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Airwallex Flow\n// =============================================================================\n\nfunction initializeAirwallexAdapter(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): {\n adapter?: AirwallexGooglePayAdapter;\n error?: string;\n} {\n if (!startData.merchant_name || !startData.airwallex_account_id) {\n return { error: \"Airwallex Google Pay credentials not provided\" };\n }\n\n // Convert GooglePayMockScenario to AirwallexGooglePayMockScenario\n let airwallexMockScenario: AirwallexGooglePayMockScenario = AirwallexGooglePayMockScenario.None;\n if (mockScenario === GooglePayMockScenario.Success) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Success;\n } else if (mockScenario === GooglePayMockScenario.Cancelled) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Cancelled;\n }\n\n const adapter = new AirwallexGooglePayAdapter(airwallexMockScenario);\n\n const config: AirwallexGooglePayConfig = {\n merchantId: startData.merchant_name,\n gatewayMerchantId: startData.airwallex_account_id,\n amountDisplay: startData.amount_display,\n currency: startData.currency,\n country: startData.country,\n isProduction: startData.is_sandbox === false,\n googleMerchantId: startData.google_merchant_id,\n };\n\n if (!adapter.initialize(config)) {\n return {\n error:\n 'Google Pay API not loaded. Add <script src=\"https://pay.google.com/gp/p/js/pay.js\"></script> to your page.',\n };\n }\n\n return { adapter };\n}\n\nasync function runAirwallexFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; token?: GooglePayEncryptedToken; payerEmail?: string; error?: string }> {\n // Initialize Airwallex adapter\n const { adapter, error: adapterError } = initializeAirwallexAdapter(startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Return the token and payer email for passing to backend\n return { success: true, token: paymentResult.token, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Confirm & Verify Endpoints\n// =============================================================================\n\n/**\n * Call /confirm endpoint - processes Google Pay token (Airwallex) or records setup (Stripe).\n * For Airwallex, may return next_action if 3DS is required.\n */\nasync function callConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken?: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayConfirmResponse> {\n const requestBody: GooglePayConfirmRequest = {\n mock_scenario: mockScenarioStr,\n };\n\n if (googlePayToken) {\n requestBody.google_pay_token = googlePayToken;\n }\n\n if (payerEmail) {\n requestBody.payer_email = payerEmail;\n }\n\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(requestBody),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message: result.error || \"Failed to confirm payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Call /verify endpoint - verifies 3DS completion for Airwallex.\n * Called after user completes 3DS challenge. May return another next_action for retry.\n */\nasync function callVerifyEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<GooglePayConfirmResponse> {\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-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: result.error || \"Failed to verify payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Convert GooglePayConfirmResponse to GooglePayResult for return to caller.\n */\nfunction toGooglePayResult(response: GooglePayConfirmResponse, secureToken: string): GooglePayResult {\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 google_pay:\n response.error_message_for_customer ||\n response.error_message_for_debug ||\n response.error_message ||\n \"Payment failed\",\n },\n };\n}\n\n// =============================================================================\n// Stripe Confirm (Simple - No 3DS Loop)\n// =============================================================================\n\n/**\n * Confirm Stripe Google Pay - simple flow without 3DS loop.\n * Stripe.js handles 3DS internally during confirmCardSetup().\n */\nasync function confirmStripeGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n const response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n undefined,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Airwallex Confirm with 3DS Loop\n// =============================================================================\n\nconst MAX_USER_ACTIONS = 5;\n\n/**\n * Confirm Airwallex Google Pay with 3DS loop support.\n *\n * Flow:\n * 1. Call /confirm with token → may return next_action (3DS)\n * 2. If next_action: handle 3DS, then call /verify\n * 3. Loop if /verify returns another next_action (3DS retry)\n * 4. Return final result\n *\n * This mirrors the card.ts pattern for consistency.\n */\nasync function confirmAirwallexGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n let userActionCount = 0;\n\n // Step 1: Initial confirm with token\n let response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n googlePayToken,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n\n // Step 2: Handle 3DS loop (if required)\n while (response.charge_status === \"pending\" && response.next_action && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n\n // Handle 3DS challenge\n const actionResult = await handleNextAction(response.next_action);\n\n // Always call verify endpoint so backend can conclude properly\n // (even if 3DS failed, backend needs to know)\n const verifyResponse = await callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n // Check if another 3DS action is required (retry scenario)\n if (verifyResponse.charge_status === \"pending\" && verifyResponse.next_action) {\n if (!actionResult.success) {\n console.log(\"[GooglePay: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 // 3DS failed and no retry available\n return {\n errors: {\n google_pay: verifyResponse.error_message || actionResult.error || \"3DS authentication failed\",\n },\n };\n }\n\n // 3DS succeeded - return verify result\n return toGooglePayResult(verifyResponse, secureToken);\n }\n\n // Check for max attempts exceeded\n if (userActionCount >= MAX_USER_ACTIONS) {\n return { errors: { google_pay: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // No 3DS required - return initial confirm result\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Main Submit Function\n// =============================================================================\n\nconst defSubmitPayment = (states: PaymentKitStates) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n const { apiBaseUrl, secureToken, environment } = states;\n const gpayOptions = options as GooglePaySubmitOptions;\n\n // Validate options\n const validationError = validateOptions(gpayOptions);\n if (validationError) {\n return { errors: validationError };\n }\n\n try {\n const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);\n\n // Get or create checkout request ID for correlating all API calls\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Step 1: Start Google Pay flow - backend selects processor\n const startResult = await callStartEndpoint(\n apiBaseUrl,\n secureToken,\n gpayOptions,\n mockScenarioStr,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { errors: { google_pay: startResult.error || \"Failed to start Google Pay\" } };\n }\n\n const startData = startResult.data;\n\n // Step 2 & 3: Run processor-specific flow and confirm\n if (startData.processor === \"stripe\") {\n // Stripe flow: Uses Stripe.js PaymentRequest API (handles 3DS internally)\n const stripeResult = await runStripeFlow(startData, gpayOptions.mockScenario);\n if (!stripeResult.success) {\n return { errors: { google_pay: stripeResult.error } };\n }\n // Confirm with backend (no token needed, Stripe handled it)\n return await confirmStripeGooglePay(\n apiBaseUrl,\n secureToken,\n mockScenarioStr,\n checkoutRequestId,\n stripeResult.payerEmail,\n );\n }\n\n if (startData.processor === \"airwallex\") {\n // Airwallex flow: Uses Google Pay API directly, may need 3DS\n const airwallexResult = await runAirwallexFlow(startData, gpayOptions.mockScenario);\n if (!airwallexResult.success) {\n return { errors: { google_pay: airwallexResult.error } };\n }\n if (!airwallexResult.token) {\n return { errors: { google_pay: \"Google Pay token not received\" } };\n }\n // Confirm with 3DS loop support\n return await confirmAirwallexGooglePay(\n apiBaseUrl,\n secureToken,\n airwallexResult.token,\n mockScenarioStr,\n checkoutRequestId,\n airwallexResult.payerEmail,\n );\n }\n\n return { errors: { google_pay: `Unsupported processor: ${startData.processor}` } };\n } catch (error) {\n return { errors: { google_pay: `Google Pay error: ${error}` } };\n }\n };\n\n return submitPayment;\n};\n\n// =============================================================================\n// Payment Method Definition\n// =============================================================================\n\nconst GooglePayPaymentMethod = definePaymentMethod((paymentKitStates) => {\n return {\n name: \"google_pay\",\n externalFuncs: {},\n internalFuncs: {\n submitPayment: defSubmitPayment(paymentKitStates),\n cleanup: () => {},\n },\n };\n});\n\nexport { GooglePayMockScenario };\n\nexport default GooglePayPaymentMethod;\n"],"mappings":"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"}
1
+ {"version":3,"file":"google-pay.mjs","names":["airwallexMockScenario: AirwallexGooglePayMockScenario","config: AirwallexGooglePayConfig","requestBody: GooglePayConfirmRequest","submitPayment: TInternalFuncs[\"submitPayment\"]","effectiveOptions: GooglePaySubmitOptions","autoPrepareConfig: AutoPrepareConfig | null","onGooglePayReadyCallbacks: ((isReady: boolean) => void)[]","pendingAutoPrepareArgs: { apiBaseUrl: string; secureToken: string; environment: string } | null","pendingPrepareResolvers: (() => void)[]"],"sources":["../../src/payment-methods/google-pay.ts"],"sourcesContent":["import type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\nimport {\n AirwallexGooglePayAdapter,\n type AirwallexGooglePayConfig,\n AirwallexGooglePayMockScenario,\n type GooglePayEncryptedToken,\n} from \"./airwallex-google-pay-adapter\";\nimport { handleNextAction } from \"./next-action-handlers\";\nimport { GooglePayMockScenario, StripeGooglePayAdapter } from \"./stripe-google-pay-adapter\";\n\n// Google Pay-specific types\nexport type GooglePayCustomerInfo = {\n first_name: string;\n last_name: string;\n email?: string;\n};\n\nexport type GooglePayStartRequest = {\n processor_id: string;\n customer_info: GooglePayCustomerInfo;\n fraud_metadata: {\n ipAddress?: string;\n browserInfo?: { [key: string]: unknown };\n processorFraudInfo?: { [key: string]: unknown };\n };\n mock_scenario?: string;\n};\n\nexport type GooglePayStartResponse = {\n checkout_attempt_id: string;\n amount: number;\n amount_display: string; // Formatted for Google Pay (e.g., \"100.00\" for USD, \"1000\" for JPY)\n currency: string;\n country: string;\n\n // Processor discriminator\n processor: \"stripe\" | \"airwallex\";\n\n // Environment flag\n is_sandbox?: boolean;\n\n // Stripe-specific fields (when processor=\"stripe\")\n client_secret?: string;\n stripe_pk?: string;\n\n // Airwallex-specific fields (when processor=\"airwallex\")\n merchant_name?: string;\n airwallex_account_id?: string;\n google_merchant_id?: string; // Google-assigned merchant ID for production (BCR2DN...)\n};\n\nexport type GooglePayConfirmRequest = {\n google_pay_token?: GooglePayEncryptedToken; // Required for Airwallex\n payer_email?: string; // Email from payment sheet (Stripe Google Pay)\n mock_scenario?: string;\n};\n\n// Airwallex 3DS next action type (matches backend snake_case response)\nexport type Airwallex3dsNextAction = {\n type: \"airwallex_3ds\";\n url: string;\n method: string;\n payment_intent_id: string;\n};\n\nexport type GooglePayConfirmResponse = {\n charge_status: \"success\" | \"fail\" | \"pending\";\n transaction_id?: string;\n error_code?: string;\n error_message?: 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 GooglePaySubmitOptions = {\n /** Processor external ID — optional when using auto-prepare (SDK fetches from checkout session) */\n processorId?: string;\n customerInfo: GooglePayCustomerInfo;\n mockScenario?: GooglePayMockScenario;\n};\n\ntype GooglePayResult =\n | { data: { [key: string]: unknown }; errors?: never }\n | { data?: never; errors: PaymentKitErrors };\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 // Add x-request-id header if provided\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(\n options: GooglePaySubmitOptions,\n autoPrepareConfig: AutoPrepareConfig | null,\n): PaymentKitErrors | null {\n // processorId is optional when autoPrepareConfig provides it\n if (!options?.processorId && !autoPrepareConfig?.processorId) {\n return { processor_id: \"Processor ID is required\" };\n }\n // Customer name is optional — Google Pay collects it from the payment sheet\n return null;\n}\n\n// =============================================================================\n// Auto-Prepare Types\n// =============================================================================\n\ntype CheckoutSessionConfig = {\n express_checkout_processor_id?: string | null;\n express_checkout_processor_type?: string | null;\n};\n\ntype AutoPrepareConfig = {\n processorId: string;\n processorType?: \"stripe\" | \"airwallex\";\n};\n\n/**\n * Check if Google Pay is available on this device/browser.\n * Uses the Google Pay API's isReadyToPay() method.\n */\nasync function checkGooglePayAvailability(): Promise<boolean> {\n // Check if Google Pay API is loaded\n if (!window.google?.payments?.api?.PaymentsClient) {\n console.log(\"[GooglePay] Google Pay API not loaded\");\n return false;\n }\n\n try {\n // Per Google Pay docs, TEST mode is appropriate for isReadyToPay() availability checks.\n // The actual payment flow uses the production environment configured in submit().\n const client = new window.google.payments.api.PaymentsClient({\n environment: \"TEST\",\n });\n\n const request = {\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: [\n {\n type: \"CARD\" as const,\n parameters: {\n allowedAuthMethods: [\"PAN_ONLY\", \"CRYPTOGRAM_3DS\"] as (\"PAN_ONLY\" | \"CRYPTOGRAM_3DS\")[],\n allowedCardNetworks: [\"VISA\", \"MASTERCARD\", \"AMEX\", \"DISCOVER\", \"JCB\"] as (\n | \"VISA\"\n | \"MASTERCARD\"\n | \"AMEX\"\n | \"DISCOVER\"\n | \"JCB\"\n )[],\n },\n },\n ],\n };\n\n const response = await client.isReadyToPay(request);\n return response.result;\n } catch (error) {\n console.error(\"[GooglePay] availability check error:\", error);\n return false;\n }\n}\n\nfunction getMockScenarioStr(mockScenario?: GooglePayMockScenario): string | undefined {\n return mockScenario && mockScenario !== GooglePayMockScenario.None ? mockScenario : undefined;\n}\n\nasync function callStartEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n options: GooglePaySubmitOptions,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n): Promise<{ data?: GooglePayStartResponse; error?: string }> {\n return apiCall<GooglePayStartResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-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 mock_scenario: mockScenarioStr,\n } as GooglePayStartRequest),\n },\n checkoutRequestId,\n );\n}\n\n// =============================================================================\n// Stripe Flow\n// =============================================================================\n\nfunction initializeStripeAdapter(\n stripePk: string,\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): { adapter?: StripeGooglePayAdapter; error?: string } {\n const adapter = new StripeGooglePayAdapter(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 const prConfig = {\n country: startData.country,\n currency: startData.currency.toLowerCase(),\n total: { label: \"Total\", amount: startData.amount },\n requestPayerName: true,\n requestPayerEmail: true,\n };\n adapter.createPaymentRequest(prConfig);\n return { adapter };\n}\n\nasync function runStripeFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; error?: string; payerEmail?: string }> {\n if (!startData.stripe_pk || !startData.client_secret) {\n return { success: false, error: \"Stripe credentials not provided\" };\n }\n\n // Initialize Stripe adapter\n const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Confirm with Stripe SDK\n const confirmResult = await adapter.confirmCardSetup(startData.client_secret, paymentResult.paymentMethodId);\n\n if (!confirmResult.success) {\n paymentResult.complete(\"fail\");\n return { success: false, error: \"error\" in confirmResult ? confirmResult.error : \"Card setup failed\" };\n }\n\n paymentResult.complete(\"success\");\n return { success: true, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Airwallex Flow\n// =============================================================================\n\nfunction initializeAirwallexAdapter(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): {\n adapter?: AirwallexGooglePayAdapter;\n error?: string;\n} {\n if (!startData.merchant_name || !startData.airwallex_account_id) {\n return { error: \"Airwallex Google Pay credentials not provided\" };\n }\n\n // Convert GooglePayMockScenario to AirwallexGooglePayMockScenario\n let airwallexMockScenario: AirwallexGooglePayMockScenario = AirwallexGooglePayMockScenario.None;\n if (mockScenario === GooglePayMockScenario.Success) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Success;\n } else if (mockScenario === GooglePayMockScenario.Cancelled) {\n airwallexMockScenario = AirwallexGooglePayMockScenario.Cancelled;\n }\n\n const adapter = new AirwallexGooglePayAdapter(airwallexMockScenario);\n\n const config: AirwallexGooglePayConfig = {\n merchantId: startData.merchant_name,\n gatewayMerchantId: startData.airwallex_account_id,\n amountDisplay: startData.amount_display,\n currency: startData.currency,\n country: startData.country,\n isProduction: startData.is_sandbox === false,\n googleMerchantId: startData.google_merchant_id,\n };\n\n if (!adapter.initialize(config)) {\n return {\n error:\n 'Google Pay API not loaded. Add <script src=\"https://pay.google.com/gp/p/js/pay.js\"></script> to your page.',\n };\n }\n\n return { adapter };\n}\n\nasync function runAirwallexFlow(\n startData: GooglePayStartResponse,\n mockScenario?: GooglePayMockScenario,\n): Promise<{ success: boolean; token?: GooglePayEncryptedToken; payerEmail?: string; error?: string }> {\n // Initialize Airwallex adapter\n const { adapter, error: adapterError } = initializeAirwallexAdapter(startData, mockScenario);\n if (!adapter) {\n return { success: false, error: adapterError };\n }\n\n // Check availability\n const isAvailable = await adapter.canMakePayment();\n\n if (!isAvailable) {\n return { success: false, error: \"Google Pay not available on this device\" };\n }\n\n // Show payment sheet\n const paymentResult = await adapter.showPaymentSheet();\n\n if (!paymentResult.success) {\n if (\"cancelled\" in paymentResult && paymentResult.cancelled) {\n return { success: false, error: \"Google Pay cancelled by user\" };\n }\n const errorMessage = \"error\" in paymentResult ? paymentResult.error : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n\n // Return the token and payer email for passing to backend\n return { success: true, token: paymentResult.token, payerEmail: paymentResult.payerEmail };\n}\n\n// =============================================================================\n// Confirm & Verify Endpoints\n// =============================================================================\n\n/**\n * Call /confirm endpoint - processes Google Pay token (Airwallex) or records setup (Stripe).\n * For Airwallex, may return next_action if 3DS is required.\n */\nasync function callConfirmEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken?: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayConfirmResponse> {\n const requestBody: GooglePayConfirmRequest = {\n mock_scenario: mockScenarioStr,\n };\n\n if (googlePayToken) {\n requestBody.google_pay_token = googlePayToken;\n }\n\n if (payerEmail) {\n requestBody.payer_email = payerEmail;\n }\n\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/confirm`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(requestBody),\n },\n checkoutRequestId,\n );\n\n if (result.error || !result.data) {\n return {\n charge_status: \"fail\",\n error_message: result.error || \"Failed to confirm payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Call /verify endpoint - verifies 3DS completion for Airwallex.\n * Called after user completes 3DS challenge. May return another next_action for retry.\n */\nasync function callVerifyEndpoint(\n apiBaseUrl: string,\n secureToken: string,\n checkoutRequestId?: string,\n): Promise<GooglePayConfirmResponse> {\n const result = await apiCall<GooglePayConfirmResponse>(\n `${apiBaseUrl}/api/checkout/${secureToken}/google-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: result.error || \"Failed to verify payment\",\n checkout_attempt_id: \"\",\n };\n }\n\n return result.data;\n}\n\n/**\n * Convert GooglePayConfirmResponse to GooglePayResult for return to caller.\n */\nfunction toGooglePayResult(response: GooglePayConfirmResponse, secureToken: string): GooglePayResult {\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 google_pay:\n response.error_message_for_customer ||\n response.error_message_for_debug ||\n response.error_message ||\n \"Payment failed\",\n },\n };\n}\n\n// =============================================================================\n// Stripe Confirm (Simple - No 3DS Loop)\n// =============================================================================\n\n/**\n * Confirm Stripe Google Pay - simple flow without 3DS loop.\n * Stripe.js handles 3DS internally during confirmCardSetup().\n */\nasync function confirmStripeGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n const response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n undefined,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Airwallex Confirm with 3DS Loop\n// =============================================================================\n\nconst MAX_USER_ACTIONS = 5;\n\n/**\n * Confirm Airwallex Google Pay with 3DS loop support.\n *\n * Flow:\n * 1. Call /confirm with token → may return next_action (3DS)\n * 2. If next_action: handle 3DS, then call /verify\n * 3. Loop if /verify returns another next_action (3DS retry)\n * 4. Return final result\n *\n * This mirrors the card.ts pattern for consistency.\n */\nasync function confirmAirwallexGooglePay(\n apiBaseUrl: string,\n secureToken: string,\n googlePayToken: GooglePayEncryptedToken,\n mockScenarioStr?: string,\n checkoutRequestId?: string,\n payerEmail?: string,\n): Promise<GooglePayResult> {\n let userActionCount = 0;\n\n // Step 1: Initial confirm with token\n let response = await callConfirmEndpoint(\n apiBaseUrl,\n secureToken,\n googlePayToken,\n mockScenarioStr,\n checkoutRequestId,\n payerEmail,\n );\n\n // Step 2: Handle 3DS loop (if required)\n while (response.charge_status === \"pending\" && response.next_action && userActionCount < MAX_USER_ACTIONS) {\n userActionCount++;\n\n // Handle 3DS challenge\n const actionResult = await handleNextAction(response.next_action);\n\n // Always call verify endpoint so backend can conclude properly\n // (even if 3DS failed, backend needs to know)\n const verifyResponse = await callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);\n\n // Check if another 3DS action is required (retry scenario)\n if (verifyResponse.charge_status === \"pending\" && verifyResponse.next_action) {\n if (!actionResult.success) {\n console.log(\"[GooglePay: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 // 3DS failed and no retry available\n return {\n errors: {\n google_pay: verifyResponse.error_message || actionResult.error || \"3DS authentication failed\",\n },\n };\n }\n\n // 3DS succeeded - return verify result\n return toGooglePayResult(verifyResponse, secureToken);\n }\n\n // Check for max attempts exceeded\n if (userActionCount >= MAX_USER_ACTIONS) {\n return { errors: { google_pay: \"Too many authentication attempts. Please try again.\" } };\n }\n\n // No 3DS required - return initial confirm result\n return toGooglePayResult(response, secureToken);\n}\n\n// =============================================================================\n// Main Submit Function\n// =============================================================================\n\nconst defSubmitPayment = (states: PaymentKitStates, getAutoPrepareConfig: () => AutoPrepareConfig | null) => {\n const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n const { apiBaseUrl, secureToken, environment } = states;\n const gpayOptions = options as GooglePaySubmitOptions;\n const autoPrepareConfig = getAutoPrepareConfig();\n\n // Validate options\n const validationError = validateOptions(gpayOptions, autoPrepareConfig);\n if (validationError) {\n return { errors: validationError };\n }\n\n // Use autoPrepareConfig as fallback for processorId\n const effectiveOptions: GooglePaySubmitOptions = {\n ...gpayOptions,\n processorId: gpayOptions.processorId || autoPrepareConfig?.processorId || \"\",\n };\n\n try {\n const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);\n\n // Get or create checkout request ID for correlating all API calls\n const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);\n\n // Step 1: Start Google Pay flow - backend selects processor\n const startResult = await callStartEndpoint(\n apiBaseUrl,\n secureToken,\n effectiveOptions,\n mockScenarioStr,\n checkoutRequestId,\n );\n if (startResult.error || !startResult.data) {\n return { errors: { google_pay: startResult.error || \"Failed to start Google Pay\" } };\n }\n\n const startData = startResult.data;\n\n // Step 2 & 3: Run processor-specific flow and confirm\n if (startData.processor === \"stripe\") {\n // Stripe flow: Uses Stripe.js PaymentRequest API (handles 3DS internally)\n const stripeResult = await runStripeFlow(startData, gpayOptions.mockScenario);\n if (!stripeResult.success) {\n return { errors: { google_pay: stripeResult.error } };\n }\n // Confirm with backend (no token needed, Stripe handled it)\n return await confirmStripeGooglePay(\n apiBaseUrl,\n secureToken,\n mockScenarioStr,\n checkoutRequestId,\n stripeResult.payerEmail,\n );\n }\n\n if (startData.processor === \"airwallex\") {\n // Airwallex flow: Uses Google Pay API directly, may need 3DS\n const airwallexResult = await runAirwallexFlow(startData, gpayOptions.mockScenario);\n if (!airwallexResult.success) {\n return { errors: { google_pay: airwallexResult.error } };\n }\n if (!airwallexResult.token) {\n return { errors: { google_pay: \"Google Pay token not received\" } };\n }\n // Confirm with 3DS loop support\n return await confirmAirwallexGooglePay(\n apiBaseUrl,\n secureToken,\n airwallexResult.token,\n mockScenarioStr,\n checkoutRequestId,\n airwallexResult.payerEmail,\n );\n }\n\n return { errors: { google_pay: `Unsupported processor: ${startData.processor}` } };\n } catch (error) {\n return { errors: { google_pay: `Google Pay error: ${error}` } };\n }\n };\n\n return submitPayment;\n};\n\n// =============================================================================\n// Payment Method Definition\n// =============================================================================\n\nconst GooglePayPaymentMethod = definePaymentMethod((paymentKitStates) => {\n const { apiBaseUrl, secureToken, environment } = paymentKitStates;\n\n // Per-instance auto-prepare state — isolated from other GooglePayPaymentMethod instances.\n let autoPrepareConfig: AutoPrepareConfig | null = null;\n let onGooglePayReadyCallbacks: ((isReady: boolean) => void)[] = [];\n let isGooglePayReadyState = 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 instanceSetGooglePayReady(ready: boolean): void {\n isGooglePayReadyState = ready;\n for (const cb of onGooglePayReadyCallbacks) cb(ready);\n }\n\n function instanceClearPreparedGooglePay(): void {\n instanceSetGooglePayReady(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 instanceSetGooglePayReady(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(\"[GooglePay] 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(\"[GooglePay] 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 isAvailable = await checkGooglePayAvailability();\n\n if (cleanupGeneration !== capturedGeneration) return;\n\n instanceSetGooglePayReady(isAvailable);\n } catch (err) {\n if (cleanupGeneration === capturedGeneration) {\n console.error(\"[GooglePay] 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(\"[GooglePay] Unhandled init error:\", err),\n );\n\n return {\n name: \"google_pay\",\n externalFuncs: {\n /**\n * Register a callback to be notified when Google 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.google_pay.onGooglePayReady((isReady) => {\n * googlePayButton.disabled = !isReady;\n * });\n */\n onGooglePayReady: (callback: (isReady: boolean) => void): void => {\n onGooglePayReadyCallbacks.push(callback);\n // Fire immediately with current state so caller doesn't miss a completed prepare.\n callback(isGooglePayReadyState);\n },\n\n /**\n * Notify the SDK that the payment amount has changed (e.g. coupon applied).\n * The SDK will disable Google 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.google_pay.notifyAmountChanged();\n */\n notifyAmountChanged: (): Promise<void> => {\n instanceClearPreparedGooglePay();\n autoPrepareConfig = null;\n return instanceAutoPrepare(apiBaseUrl, secureToken, environment);\n },\n },\n internalFuncs: {\n submitPayment: defSubmitPayment(paymentKitStates, () => autoPrepareConfig),\n cleanup: () => {\n cleanupGeneration++;\n onGooglePayReadyCallbacks = [];\n isGooglePayReadyState = false;\n autoPrepareConfig = null;\n pendingAutoPrepareArgs = null;\n pendingPrepareResolvers = [];\n autoPrepareInProgress = false;\n },\n },\n };\n});\n\nexport { GooglePayMockScenario };\n\nexport default GooglePayPaymentMethod;\n"],"mappings":"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"}