{"version":3,"file":"bnpl-shared-CL900HFN.mjs","names":["submitPayment: TInternalFuncs[\"submitPayment\"]","requestBody: BnplStartRequest","localStates: BnplStates"],"sources":["../src/payment-methods/bnpl-shared.ts"],"sourcesContent":["/**\n * Shared BNPL (Buy Now Pay Later) payment method factory.\n * Used by Klarna, Afterpay, and Affirm payment methods.\n */\n\nimport type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\n\nexport type BnplCustomerInfo = {\n  first_name: string;\n  last_name: string;\n  email?: string;\n};\n\nexport type BnplStartRequest = {\n  processor_id: string;\n  customer_info: BnplCustomerInfo;\n  fraud_metadata: {\n    ipAddress?: string;\n    browserInfo?: { [key: string]: unknown };\n    processorFraudInfo?: { [key: string]: unknown };\n  };\n  setup_future_usage?: boolean;\n};\n\nexport type BnplStartResponse = {\n  approval_url: string;\n  popup_token: string;\n  checkout_attempt_id: string;\n};\n\nexport type BnplStatusResponse = {\n  completed: boolean;\n  status: \"success\" | \"failed\" | \"cancelled\";\n  result?: unknown;\n  error?: string;\n};\n\nexport type BnplCheckoutResponse = {\n  id: string;\n  checkoutAttemptId: string;\n  checkoutSessionId: string;\n  state: string;\n  customerId?: string;\n  paymentMethodId?: string;\n  processorUsed?: string;\n  subscriptionId?: string;\n  invoiceId?: string;\n  invoiceNumber?: number;\n};\n\nexport type BnplSubmitOptions = {\n  processorId: string;\n  customerInfo: BnplCustomerInfo;\n  setupFutureUsage?: boolean;\n};\n\ntype BnplStates = PaymentKitStates & {\n  popup?: Window | null;\n  pollInterval?: ReturnType<typeof setInterval>;\n};\n\nexport type BnplProviderConfig = {\n  name: string;\n  endpointPath: string;\n  supportsSetupFutureUsage?: boolean;\n};\n\nconst createSubmitPayment = (states: BnplStates, config: BnplProviderConfig) => {\n  const { name, endpointPath, supportsSetupFutureUsage } = config;\n  const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);\n\n  const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n    const { apiBaseUrl, secureToken, environment } = states;\n    const bnplOptions = options as BnplSubmitOptions;\n\n    if (!bnplOptions?.processorId) {\n      return { errors: { processor_id: \"Processor ID is required\" } as PaymentKitErrors };\n    }\n\n    if (!bnplOptions?.customerInfo?.first_name || !bnplOptions?.customerInfo?.last_name) {\n      return {\n        errors: {\n          customer_name: \"Customer first and last name are required\",\n        } as PaymentKitErrors,\n      };\n    }\n\n    try {\n      const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n\n      const requestBody: BnplStartRequest = {\n        processor_id: bnplOptions.processorId,\n        customer_info: bnplOptions.customerInfo,\n        fraud_metadata: collectFraudMetadata(),\n      };\n\n      if (supportsSetupFutureUsage && bnplOptions.setupFutureUsage !== undefined) {\n        requestBody.setup_future_usage = bnplOptions.setupFutureUsage;\n      }\n\n      const startResponse = await fetch(`${apiBaseUrl}/api/checkout/${secureToken}/stripe/${endpointPath}/start`, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          \"x-request-id\": checkoutRequestId,\n        },\n        body: JSON.stringify(requestBody),\n      });\n\n      if (!startResponse.ok) {\n        let errorMessage = `Failed to start ${capitalizedName} checkout (${startResponse.status})`;\n        try {\n          const errorData = await startResponse.json();\n          errorMessage = errorData.detail || errorMessage;\n        } catch {\n          errorMessage = startResponse.statusText || errorMessage;\n        }\n        return {\n          errors: {\n            [name]: errorMessage,\n          } as PaymentKitErrors,\n        };\n      }\n\n      const { approval_url, popup_token, checkout_attempt_id } = (await startResponse.json()) as BnplStartResponse;\n\n      const popup = window.open(approval_url, capitalizedName, \"width=600,height=700\");\n\n      if (!popup) {\n        return {\n          errors: {\n            [name]: `Failed to open ${capitalizedName} popup. Please allow popups for this site.`,\n          } as PaymentKitErrors,\n        };\n      }\n\n      states.popup = popup;\n\n      return new Promise((resolve) => {\n        let popupClosedGracePolls = 0;\n        const MAX_GRACE_POLLS = 5;\n\n        const pollInterval = setInterval(async () => {\n          try {\n            const statusResponse = await fetch(\n              `${apiBaseUrl}/api/checkout/${secureToken}/popup/status?popup_token=${popup_token}`,\n            );\n\n            if (!statusResponse.ok) {\n              clearInterval(pollInterval);\n              popup.close();\n              resolve({\n                errors: {\n                  [name]: `Failed to check ${capitalizedName} status`,\n                } as PaymentKitErrors,\n              });\n              return;\n            }\n\n            const statusResult = (await statusResponse.json()) as BnplStatusResponse;\n\n            if (statusResult.completed) {\n              clearInterval(pollInterval);\n              popup.close();\n\n              if (statusResult.status === \"success\") {\n                // Result is returned directly from popup status endpoint\n                const result = statusResult.result || {\n                  id: checkout_attempt_id,\n                  checkoutAttemptId: checkout_attempt_id,\n                  checkoutSessionId: secureToken,\n                  state: \"checkout_succeeded\",\n                };\n\n                resolve({ data: result });\n              } else {\n                resolve({\n                  errors: {\n                    [name]: statusResult.error || `${capitalizedName} checkout ${statusResult.status}`,\n                  } as PaymentKitErrors,\n                });\n              }\n              return;\n            }\n\n            if (popup.closed) {\n              popupClosedGracePolls++;\n              if (popupClosedGracePolls >= MAX_GRACE_POLLS) {\n                clearInterval(pollInterval);\n                resolve({\n                  errors: {\n                    [name]: `${capitalizedName} popup closed by user`,\n                  } as PaymentKitErrors,\n                });\n              }\n              return;\n            }\n          } catch (error) {\n            clearInterval(pollInterval);\n            popup.close();\n            resolve({\n              errors: {\n                [name]: `Polling error: ${error}`,\n              } as PaymentKitErrors,\n            });\n          }\n        }, 2000);\n\n        states.pollInterval = pollInterval;\n      });\n    } catch (error) {\n      return {\n        errors: {\n          [name]: `${capitalizedName} checkout error: ${error}`,\n        } as PaymentKitErrors,\n      };\n    }\n  };\n\n  return submitPayment;\n};\n\nexport function createBnplPaymentMethod(config: BnplProviderConfig) {\n  return definePaymentMethod((paymentKitStates) => {\n    const localStates: BnplStates = { ...paymentKitStates };\n\n    return {\n      name: config.name,\n      externalFuncs: {},\n      internalFuncs: {\n        submitPayment: createSubmitPayment(localStates, config),\n        cleanup: () => {\n          if (localStates.pollInterval) {\n            clearInterval(localStates.pollInterval);\n          }\n          if (localStates.popup && !localStates.popup.closed) {\n            localStates.popup.close();\n          }\n        },\n      },\n    };\n  });\n}\n"],"mappings":"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"}