{"version":3,"file":"paypal.mjs","names":["submitPayment: TInternalFuncs[\"submitPayment\"]","localStates: PayPalStates"],"sources":["../../src/payment-methods/paypal.ts"],"sourcesContent":["import type { PaymentKitErrors, PaymentKitStates, TInternalFuncs } from \"../types\";\nimport { collectFraudMetadata, definePaymentMethod, getOrCreateCheckoutRequestId } from \"../utils\";\n\n// PayPal-specific types\nexport type PayPalCustomerInfo = {\n  first_name: string;\n  last_name: string;\n};\n\nexport type PayPalStartRequest = {\n  processor_id: string;\n  customer_info: PayPalCustomerInfo;\n  fraud_metadata: {\n    ipAddress?: string;\n    browserInfo?: { [key: string]: unknown };\n    processorFraudInfo?: { [key: string]: unknown };\n  };\n};\n\nexport type PayPalStartResponse = {\n  approval_url: string;\n  popup_token: string;\n  checkout_attempt_id: string;\n};\n\nexport type PayPalStatusResponse = {\n  completed: boolean;\n  status: \"success\" | \"failed\" | \"cancelled\";\n  result?: unknown;\n  error?: string;\n};\n\nexport type PayPalCheckoutResponse = {\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 PayPalSubmitOptions = {\n  processorId: string;\n  customerInfo: PayPalCustomerInfo;\n};\n\ntype PayPalStates = PaymentKitStates & {\n  popup?: Window | null;\n  pollInterval?: number;\n};\n\nconst defSubmitPayment = (states: PayPalStates) => {\n  const submitPayment: TInternalFuncs[\"submitPayment\"] = async (_fields, options) => {\n    const { apiBaseUrl, secureToken, environment } = states;\n    const paypalOptions = options as PayPalSubmitOptions;\n\n    if (!paypalOptions?.processorId) {\n      return { errors: { processor_id: \"Processor ID is required\" } as PaymentKitErrors };\n    }\n\n    if (!paypalOptions?.customerInfo?.first_name || !paypalOptions?.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      // Get or create checkout request ID for correlating all API calls\n      const checkoutRequestId = getOrCreateCheckoutRequestId(environment);\n      console.log(`[PayPal] Using checkout_request_id: ${checkoutRequestId}`);\n\n      // Step 1: Call PayPal start endpoint\n      const startResponse = await fetch(`${apiBaseUrl}/api/checkout/${secureToken}/paypal/start`, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          \"x-request-id\": checkoutRequestId,\n        },\n        body: JSON.stringify({\n          processor_id: paypalOptions.processorId,\n          customer_info: paypalOptions.customerInfo,\n          fraud_metadata: collectFraudMetadata(),\n        } as PayPalStartRequest),\n      });\n\n      if (!startResponse.ok) {\n        let errorMessage = `Failed to start PayPal checkout (${startResponse.status})`;\n        try {\n          const errorData = await startResponse.json();\n          errorMessage = errorData.detail || errorMessage;\n        } catch {\n          // Response body is not JSON, use status text\n          errorMessage = startResponse.statusText || errorMessage;\n        }\n        return {\n          errors: {\n            paypal: errorMessage,\n          } as PaymentKitErrors,\n        };\n      }\n\n      const { approval_url, popup_token, checkout_attempt_id } = (await startResponse.json()) as PayPalStartResponse;\n\n      // Step 2: Open PayPal popup\n      const popup = window.open(approval_url, \"PayPal\", \"width=600,height=700\");\n\n      if (!popup) {\n        return {\n          errors: {\n            paypal: \"Failed to open PayPal popup. Please allow popups for this site.\",\n          } as PaymentKitErrors,\n        };\n      }\n\n      states.popup = popup;\n\n      // Step 3: Poll for completion\n      return new Promise((resolve) => {\n        const pollInterval = setInterval(async () => {\n          try {\n            // Check status FIRST - popup might close after successful callback\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                  paypal: \"Failed to check PayPal status\",\n                } as PaymentKitErrors,\n              });\n              return;\n            }\n\n            const statusResult = (await statusResponse.json()) as PayPalStatusResponse;\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                    paypal: statusResult.error || `PayPal checkout ${statusResult.status}`,\n                  } as PaymentKitErrors,\n                });\n              }\n              return;\n            }\n\n            // Only check popup.closed AFTER confirming status is not completed\n            // This avoids race condition where popup closes from successful callback\n            if (popup.closed) {\n              clearInterval(pollInterval);\n              resolve({\n                errors: {\n                  paypal: \"PayPal popup closed by user\",\n                } as PaymentKitErrors,\n              });\n              return;\n            }\n          } catch (error) {\n            clearInterval(pollInterval);\n            popup.close();\n            resolve({\n              errors: {\n                paypal: `Polling error: ${error}`,\n              } as PaymentKitErrors,\n            });\n          }\n        }, 2000); // Poll every 2 seconds\n\n        states.pollInterval = pollInterval as unknown as number;\n      });\n    } catch (error) {\n      return {\n        errors: {\n          paypal: `PayPal checkout error: ${error}`,\n        } as PaymentKitErrors,\n      };\n    }\n  };\n\n  return submitPayment;\n};\n\nconst PayPalPaymentMethod = definePaymentMethod((paymentKitStates) => {\n  const localStates: PayPalStates = { ...paymentKitStates };\n\n  return {\n    name: \"paypal\",\n    externalFuncs: {\n      // PayPal doesn't need createElement like card iframes\n    },\n    internalFuncs: {\n      submitPayment: defSubmitPayment(localStates),\n      cleanup: () => {\n        // Clean up popup and polling interval if still active\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\nexport default PayPalPaymentMethod;\n"],"mappings":";;;AAuDA,MAAM,oBAAoB,WAAyB;CACjD,MAAMA,gBAAiD,OAAO,SAAS,YAAY;EACjF,MAAM,EAAE,YAAY,aAAa,gBAAgB;EACjD,MAAM,gBAAgB;AAEtB,MAAI,CAAC,eAAe,YAClB,QAAO,EAAE,QAAQ,EAAE,cAAc,4BAA4B,EAAsB;AAGrF,MAAI,CAAC,eAAe,cAAc,cAAc,CAAC,eAAe,cAAc,UAC5E,QAAO,EACL,QAAQ,EACN,eAAe,6CAChB,EACF;AAGH,MAAI;GAEF,MAAM,oBAAoB,6BAA6B,YAAY;AACnE,WAAQ,IAAI,uCAAuC,oBAAoB;GAGvE,MAAM,gBAAgB,MAAM,MAAM,GAAG,WAAW,gBAAgB,YAAY,gBAAgB;IAC1F,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,gBAAgB;KACjB;IACD,MAAM,KAAK,UAAU;KACnB,cAAc,cAAc;KAC5B,eAAe,cAAc;KAC7B,gBAAgB,sBAAsB;KACvC,CAAuB;IACzB,CAAC;AAEF,OAAI,CAAC,cAAc,IAAI;IACrB,IAAI,eAAe,oCAAoC,cAAc,OAAO;AAC5E,QAAI;AAEF,qBADkB,MAAM,cAAc,MAAM,EACnB,UAAU;YAC7B;AAEN,oBAAe,cAAc,cAAc;;AAE7C,WAAO,EACL,QAAQ,EACN,QAAQ,cACT,EACF;;GAGH,MAAM,EAAE,cAAc,aAAa,wBAAyB,MAAM,cAAc,MAAM;GAGtF,MAAM,QAAQ,OAAO,KAAK,cAAc,UAAU,uBAAuB;AAEzE,OAAI,CAAC,MACH,QAAO,EACL,QAAQ,EACN,QAAQ,mEACT,EACF;AAGH,UAAO,QAAQ;AAGf,UAAO,IAAI,SAAS,YAAY;IAC9B,MAAM,eAAe,YAAY,YAAY;AAC3C,SAAI;MAEF,MAAM,iBAAiB,MAAM,MAC3B,GAAG,WAAW,gBAAgB,YAAY,4BAA4B,cACvE;AAED,UAAI,CAAC,eAAe,IAAI;AACtB,qBAAc,aAAa;AAC3B,aAAM,OAAO;AACb,eAAQ,EACN,QAAQ,EACN,QAAQ,iCACT,EACF,CAAC;AACF;;MAGF,MAAM,eAAgB,MAAM,eAAe,MAAM;AAEjD,UAAI,aAAa,WAAW;AAC1B,qBAAc,aAAa;AAC3B,aAAM,OAAO;AAEb,WAAI,aAAa,WAAW,UAS1B,SAAQ,EAAE,MAPK,aAAa,UAAU;QACpC,IAAI;QACJ,mBAAmB;QACnB,mBAAmB;QACnB,OAAO;QACR,EAEuB,CAAC;WAEzB,SAAQ,EACN,QAAQ,EACN,QAAQ,aAAa,SAAS,mBAAmB,aAAa,UAC/D,EACF,CAAC;AAEJ;;AAKF,UAAI,MAAM,QAAQ;AAChB,qBAAc,aAAa;AAC3B,eAAQ,EACN,QAAQ,EACN,QAAQ,+BACT,EACF,CAAC;AACF;;cAEK,OAAO;AACd,oBAAc,aAAa;AAC3B,YAAM,OAAO;AACb,cAAQ,EACN,QAAQ,EACN,QAAQ,kBAAkB,SAC3B,EACF,CAAC;;OAEH,IAAK;AAER,WAAO,eAAe;KACtB;WACK,OAAO;AACd,UAAO,EACL,QAAQ,EACN,QAAQ,0BAA0B,SACnC,EACF;;;AAIL,QAAO;;AAGT,MAAM,sBAAsB,qBAAqB,qBAAqB;CACpE,MAAMC,cAA4B,EAAE,GAAG,kBAAkB;AAEzD,QAAO;EACL,MAAM;EACN,eAAe,EAEd;EACD,eAAe;GACb,eAAe,iBAAiB,YAAY;GAC5C,eAAe;AAEb,QAAI,YAAY,aACd,eAAc,YAAY,aAAa;AAEzC,QAAI,YAAY,SAAS,CAAC,YAAY,MAAM,OAC1C,aAAY,MAAM,OAAO;;GAG9B;EACF;EACD;AAEF,qBAAe"}