{"version":3,"file":"stripe-apple-pay-adapter-7rF6xRIG.mjs","names":[],"sources":["../src/payment-methods/stripe-apple-pay-adapter.ts"],"sourcesContent":["/// <reference types=\"@types/applepayjs\" />\nimport type { PaymentRequest, PaymentRequestPaymentMethodEvent, Stripe, StripeConstructor } from \"@stripe/stripe-js\";\n\n// Stripe.js must be loaded via script tag for PCI compliance\ndeclare global {\n  interface Window {\n    Stripe?: StripeConstructor;\n    ApplePaySession?: typeof ApplePaySession;\n  }\n}\n\nexport interface ApplePayPaymentRequestConfig {\n  country: string;\n  currency: string;\n  total: { label: string; amount: number }; // Amount in cents (atomic units)\n  supportedNetworks?: string[];\n  merchantCapabilities?: string[];\n}\n\nexport type ShowApplePaySheetResult =\n  | {\n      success: true;\n      paymentMethodId: string;\n      paymentMethodEvent: PaymentRequestPaymentMethodEvent;\n      billingDetails?: {\n        email?: string;\n        name?: string;\n        address?: {\n          city?: string | null;\n          country?: string | null;\n          line1?: string | null;\n          line2?: string | null;\n          postal_code?: string | null;\n          state?: string | null;\n        } | null;\n      };\n    }\n  | { success: false; cancelled: true }\n  | { success: false; error: string };\n\nexport type ConfirmResult = { success: true } | { success: false; error: string };\n\nexport enum ApplePayMockScenario {\n  None = \"none\",\n  Success = \"success\",\n  Cancelled = \"cancelled\",\n}\n\n/**\n * Stripe Apple Pay Adapter using Stripe's PaymentRequest API.\n *\n * This uses Stripe's PaymentRequest API instead of the native ApplePaySession API.\n * The key benefit is that Stripe handles merchant validation automatically,\n * which is required for Apple Pay to work correctly.\n *\n * IMPORTANT: To comply with browser security requirements, Apple Pay must be shown\n * synchronously from a user click. The flow is:\n *\n * 1. Call preparePaymentRequest() BEFORE user clicks (e.g., when page loads)\n *    - This creates the PaymentRequest and calls canMakePayment()\n * 2. On user click, call showPreparedPaymentSheet()\n *    - This calls show() on the pre-created PaymentRequest (no async!)\n * 3. Handle the paymentmethod event and call complete()\n */\nexport class StripeApplePayAdapter {\n  private stripe: Stripe | null = null;\n  private mockScenario: ApplePayMockScenario;\n  private preparedPaymentRequest: PaymentRequest | null = null;\n\n  constructor(mockScenario?: ApplePayMockScenario) {\n    this.mockScenario = mockScenario ?? ApplePayMockScenario.None;\n  }\n\n  initialize(publishableKey: string): boolean {\n    switch (this.mockScenario) {\n      case ApplePayMockScenario.None: {\n        console.log(\"[ApplePay] initialize called\");\n        if (!window.Stripe) {\n          console.log(\"[ApplePay] Stripe.js not loaded\");\n          return false;\n        }\n        this.stripe = window.Stripe(publishableKey);\n        const success = this.stripe !== null;\n        console.log(\"[ApplePay] initialize result:\", success);\n        return success;\n      }\n      case ApplePayMockScenario.Success:\n      case ApplePayMockScenario.Cancelled: {\n        console.log(\"[MockApplePay] initialize called\");\n        console.log(\"[MockApplePay] initialize result:\", true);\n        return true;\n      }\n    }\n  }\n\n  /**\n   * Check if Apple Pay is available on this device/browser.\n   * Uses Stripe's PaymentRequest.canMakePayment() which is more reliable\n   * than checking ApplePaySession directly.\n   */\n  static isAvailable(): boolean {\n    // Basic check - ApplePaySession must exist (Safari on iOS/macOS)\n    if (typeof window === \"undefined\" || !window.ApplePaySession) {\n      console.log(\"[ApplePay] ApplePaySession not available\");\n      return false;\n    }\n\n    // Check if device supports Apple Pay\n    const canMakePayments = window.ApplePaySession.canMakePayments();\n    console.log(\"[ApplePay] canMakePayments:\", canMakePayments);\n    return canMakePayments;\n  }\n\n  /**\n   * Check availability using Stripe's PaymentRequest API.\n   * This is more accurate as it checks Stripe's configuration too.\n   */\n  async canMakePayment(): Promise<{ applePay: boolean; googlePay: boolean } | null> {\n    if (!this.stripe) {\n      console.log(\"[ApplePay] Stripe not initialized\");\n      return null;\n    }\n\n    // Create a temporary payment request to check availability\n    const pr = this.stripe.paymentRequest({\n      country: \"US\",\n      currency: \"usd\",\n      total: { label: \"Check\", amount: 100 },\n    });\n\n    const result = await pr.canMakePayment();\n    console.log(\"[ApplePay] canMakePayment result:\", result);\n\n    if (!result) {\n      return null;\n    }\n\n    // Map Stripe's result to our expected format\n    return {\n      applePay: result.applePay ?? false,\n      googlePay: result.googlePay ?? false,\n    };\n  }\n\n  /**\n   * Prepare a PaymentRequest for later use. Call this BEFORE the user clicks.\n   * This creates the PaymentRequest and calls canMakePayment() to validate.\n   *\n   * @returns Promise with success status and whether Apple Pay is available\n   */\n  async preparePaymentRequest(config: ApplePayPaymentRequestConfig): Promise<{\n    success: boolean;\n    applePay?: boolean;\n    googlePay?: boolean;\n    error?: string;\n  }> {\n    if (this.mockScenario !== ApplePayMockScenario.None) {\n      console.log(\"[MockApplePay] preparePaymentRequest called\");\n      this.preparedConfig = config;\n      return { success: true, applePay: true, googlePay: false };\n    }\n\n    console.log(\"[ApplePay] preparePaymentRequest called\", config);\n\n    if (!this.stripe) {\n      return { success: false, error: \"Stripe not initialized\" };\n    }\n\n    // Create the PaymentRequest\n    const paymentRequest = this.stripe.paymentRequest({\n      country: config.country,\n      currency: config.currency.toLowerCase(),\n      total: {\n        label: config.total.label,\n        amount: config.total.amount,\n      },\n      requestPayerName: true,\n      requestPayerEmail: true,\n    });\n\n    // Check availability - this MUST be called before show()\n    const canMakePaymentResult = await paymentRequest.canMakePayment();\n    console.log(\"[ApplePay] preparePaymentRequest canMakePayment:\", canMakePaymentResult);\n\n    if (!canMakePaymentResult) {\n      return {\n        success: false,\n        error: \"Payment methods not available on this device/browser\",\n        applePay: false,\n        googlePay: false,\n      };\n    }\n\n    // Store the prepared PaymentRequest for later use\n    this.preparedPaymentRequest = paymentRequest;\n    this.preparedConfig = config;\n\n    return {\n      success: true,\n      applePay: canMakePaymentResult.applePay ?? false,\n      googlePay: canMakePaymentResult.googlePay ?? false,\n    };\n  }\n\n  /**\n   * Check if a PaymentRequest has been prepared and is ready to show.\n   */\n  isPrepared(): boolean {\n    return this.preparedPaymentRequest !== null || this.mockScenario !== ApplePayMockScenario.None;\n  }\n\n  /**\n   * Clear the prepared PaymentRequest.\n   */\n  clearPrepared(): void {\n    this.preparedPaymentRequest = null;\n    this.preparedConfig = null;\n  }\n\n  /**\n   * Show the prepared Apple Pay payment sheet.\n   * MUST be called synchronously from a user click handler.\n   * Call preparePaymentRequest() before the click to set up the PaymentRequest.\n   */\n  showPreparedPaymentSheet(): Promise<ShowApplePaySheetResult> {\n    switch (this.mockScenario) {\n      case ApplePayMockScenario.None: {\n        console.log(\"[ApplePay] showPreparedPaymentSheet called\");\n\n        if (!this.preparedPaymentRequest) {\n          console.error(\"[ApplePay] No prepared PaymentRequest! Call preparePaymentRequest() first.\");\n          return Promise.resolve({\n            success: false,\n            error: \"PaymentRequest not prepared. Call preparePaymentRequest() before showing the sheet.\",\n          });\n        }\n\n        const paymentRequest = this.preparedPaymentRequest;\n\n        // Return a promise that resolves when the user completes or cancels\n        return new Promise((resolve) => {\n          // Handle successful payment method creation\n          paymentRequest.on(\"paymentmethod\", (evt: PaymentRequestPaymentMethodEvent) => {\n            console.log(\"[ApplePay] paymentmethod event received\", {\n              paymentMethodId: evt.paymentMethod.id,\n              payerEmail: evt.payerEmail,\n              payerName: evt.payerName,\n            });\n\n            // Clear the prepared request after use\n            this.preparedPaymentRequest = null;\n\n            resolve({\n              success: true,\n              paymentMethodId: evt.paymentMethod.id,\n              paymentMethodEvent: evt,\n              billingDetails: {\n                email: evt.payerEmail ?? undefined,\n                name: evt.payerName ?? undefined,\n                address: evt.paymentMethod.billing_details?.address ?? undefined,\n              },\n            });\n          });\n\n          // Handle cancellation\n          paymentRequest.on(\"cancel\", () => {\n            console.log(\"[ApplePay] cancel event - user cancelled\");\n            // Clear the prepared request after cancellation\n            this.preparedPaymentRequest = null;\n            resolve({ success: false, cancelled: true });\n          });\n\n          // Show the payment sheet immediately (no async operations before this!)\n          console.log(\"[ApplePay] showing payment sheet\");\n          paymentRequest.show();\n        });\n      }\n\n      case ApplePayMockScenario.Success: {\n        console.log(\"[MockApplePay] showPreparedPaymentSheet: success\");\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            resolve({\n              success: true,\n              paymentMethodId: \"pm_mock_apple_pay_test\",\n              paymentMethodEvent: {\n                complete: (status: string) => console.log(`[MockApplePay] complete: ${status}`),\n                paymentMethod: {\n                  id: \"pm_mock_apple_pay_test\",\n                  object: \"payment_method\",\n                  type: \"card\",\n                  card: {\n                    brand: \"visa\",\n                    last4: \"4242\",\n                    exp_month: 12,\n                    exp_year: 2030,\n                  },\n                  billing_details: {\n                    email: \"test@example.com\",\n                    name: \"Test User\",\n                  },\n                },\n                payerEmail: \"test@example.com\",\n                payerName: \"Test User\",\n              } as unknown as PaymentRequestPaymentMethodEvent,\n              billingDetails: {\n                email: \"test@example.com\",\n                name: \"Test User\",\n              },\n            });\n          }, 500);\n        });\n      }\n\n      case ApplePayMockScenario.Cancelled: {\n        console.log(\"[MockApplePay] showPreparedPaymentSheet: cancelled\");\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            resolve({ success: false, cancelled: true });\n          }, 500);\n        });\n      }\n    }\n  }\n\n  /**\n   * @deprecated Use preparePaymentRequest() + showPreparedPaymentSheet() instead.\n   * This method creates a new PaymentRequest and shows it, which doesn't work\n   * with browser security requirements (show() must be called synchronously).\n   */\n  async showPaymentSheet(config: ApplePayPaymentRequestConfig): Promise<ShowApplePaySheetResult> {\n    console.warn(\n      \"[ApplePay] showPaymentSheet is deprecated. Use preparePaymentRequest() + showPreparedPaymentSheet() instead.\",\n    );\n\n    // Try to prepare and show in one go (will likely fail due to user gesture requirement)\n    const prepareResult = await this.preparePaymentRequest(config);\n    if (!prepareResult.success) {\n      return { success: false, error: prepareResult.error ?? \"Failed to prepare payment request\" };\n    }\n\n    return this.showPreparedPaymentSheet();\n  }\n\n  /**\n   * Complete the payment flow in the Apple Pay sheet.\n   * Call this after confirming the payment on the server.\n   *\n   * @param evt - The PaymentRequestPaymentMethodEvent from showPaymentSheet\n   * @param status - 'success' or 'fail'\n   */\n  completePayment(evt: PaymentRequestPaymentMethodEvent, status: \"success\" | \"fail\"): void {\n    console.log(\"[ApplePay] completePayment:\", status);\n    evt.complete(status);\n  }\n\n  /**\n   * Confirm PaymentIntent with the PaymentMethod.\n   * This is called after showPaymentSheet to finalize the payment.\n   *\n   * @deprecated - Server-side confirmation is preferred. The backend should\n   * call stripe.PaymentIntent.confirm() with the payment_method_id.\n   */\n  async confirmPaymentIntent(clientSecret: string, paymentMethodId: string): Promise<ConfirmResult> {\n    switch (this.mockScenario) {\n      case ApplePayMockScenario.None: {\n        console.log(\"[ApplePay] confirmPaymentIntent called\", {\n          clientSecret: `${clientSecret.slice(0, 20)}...`,\n          paymentMethodId,\n        });\n        if (!this.stripe) {\n          console.log(\"[ApplePay] confirmPaymentIntent: Stripe not initialized\");\n          return { success: false, error: \"Stripe not initialized\" };\n        }\n\n        const { error } = await this.stripe.confirmCardPayment(clientSecret, {\n          payment_method: paymentMethodId,\n        });\n\n        if (error) {\n          console.log(\"[ApplePay] confirmPaymentIntent error:\", error);\n          return { success: false, error: error.message ?? \"Payment failed\" };\n        }\n\n        console.log(\"[ApplePay] confirmPaymentIntent success\");\n        return { success: true };\n      }\n      case ApplePayMockScenario.Success: {\n        console.log(\"[MockApplePay] confirmPaymentIntent called\", { clientSecret, paymentMethodId });\n        return { success: true };\n      }\n      case ApplePayMockScenario.Cancelled: {\n        throw new Error(\"confirmPaymentIntent should not be called when scenario is Cancelled\");\n      }\n    }\n  }\n}\n"],"mappings":"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"}