@payment-kit-js/vanilla 0.5.14 → 0.5.16

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 (84) hide show
  1. package/dist/{airwallex-apple-pay-adapter-CHAnLP_x.mjs → airwallex-apple-pay-adapter-CPz54c9e.mjs} +8 -2
  2. package/dist/airwallex-apple-pay-adapter-CPz54c9e.mjs.map +1 -0
  3. package/dist/{airwallex-apple-pay-adapter-Bb0CreWN.d.mts → airwallex-apple-pay-adapter-CnnZ7VL6.d.mts} +3 -1
  4. package/dist/airwallex-apple-pay-adapter-CnnZ7VL6.d.mts.map +1 -0
  5. package/dist/{airwallex-google-pay-adapter-C8JTp01q.mjs → airwallex-google-pay-adapter-BvlROwj_.mjs} +1 -1
  6. package/dist/{airwallex-google-pay-adapter-C8JTp01q.mjs.map → airwallex-google-pay-adapter-BvlROwj_.mjs.map} +1 -1
  7. package/dist/{airwallex-google-pay-adapter-adaDktQM.d.mts → airwallex-google-pay-adapter-D-AxVLLq.d.mts} +1 -1
  8. package/dist/{airwallex-google-pay-adapter-adaDktQM.d.mts.map → airwallex-google-pay-adapter-D-AxVLLq.d.mts.map} +1 -1
  9. package/dist/analytics-Blvs2DW7.mjs +333 -0
  10. package/dist/analytics-Blvs2DW7.mjs.map +1 -0
  11. package/dist/{bnpl-shared-B-en2sPr.d.mts → bnpl-shared-BQwCBD45.d.mts} +2 -2
  12. package/dist/{bnpl-shared-B-en2sPr.d.mts.map → bnpl-shared-BQwCBD45.d.mts.map} +1 -1
  13. package/dist/{bnpl-shared-CEAXTL3Q.mjs → bnpl-shared-DGs1YzS9.mjs} +2 -2
  14. package/dist/{bnpl-shared-CEAXTL3Q.mjs.map → bnpl-shared-DGs1YzS9.mjs.map} +1 -1
  15. package/dist/cdn/paymentkit.js +82 -17
  16. package/dist/cdn/paymentkit.js.map +2 -2
  17. package/dist/cdn/paymentkit.min.js +9 -9
  18. package/dist/cdn/paymentkit.min.js.map +3 -3
  19. package/dist/{connect-card-Cra_F1cC.d.mts → connect-card-CZhzK_Tp.d.mts} +1 -1
  20. package/dist/{connect-card-Cra_F1cC.d.mts.map → connect-card-CZhzK_Tp.d.mts.map} +1 -1
  21. package/dist/{connect-card-D3Je4V7p.mjs → connect-card-kXLdSNTL.mjs} +2 -2
  22. package/dist/{connect-card-D3Je4V7p.mjs.map → connect-card-kXLdSNTL.mjs.map} +1 -1
  23. package/dist/{connect-tunnel-x-BhVAej5Q.mjs → connect-tunnel-x-5XOct5Tm.mjs} +2 -2
  24. package/dist/{connect-tunnel-x-BhVAej5Q.mjs.map → connect-tunnel-x-5XOct5Tm.mjs.map} +1 -1
  25. package/dist/{connect-tunnel-x-Wh-JG1O5.d.mts → connect-tunnel-x-BKtMfoGh.d.mts} +1 -1
  26. package/dist/{connect-tunnel-x-Wh-JG1O5.d.mts.map → connect-tunnel-x-BKtMfoGh.d.mts.map} +1 -1
  27. package/dist/index.d.mts +3 -3
  28. package/dist/index.mjs +5 -334
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/{next-action-handlers-BZs04hYb.mjs → next-action-handlers-CLOt1wzO.mjs} +1 -1
  31. package/dist/{next-action-handlers-BZs04hYb.mjs.map → next-action-handlers-CLOt1wzO.mjs.map} +1 -1
  32. package/dist/payment-methods/affirm.d.mts +4 -4
  33. package/dist/payment-methods/affirm.mjs +2 -2
  34. package/dist/payment-methods/afterpay.d.mts +4 -4
  35. package/dist/payment-methods/afterpay.mjs +2 -2
  36. package/dist/payment-methods/airwallex-apple-pay-adapter.d.mts +1 -1
  37. package/dist/payment-methods/airwallex-apple-pay-adapter.mjs +1 -1
  38. package/dist/payment-methods/airwallex-google-pay-adapter.d.mts +1 -1
  39. package/dist/payment-methods/airwallex-google-pay-adapter.mjs +1 -1
  40. package/dist/payment-methods/apple-pay.d.mts +7 -5
  41. package/dist/payment-methods/apple-pay.d.mts.map +1 -1
  42. package/dist/payment-methods/apple-pay.mjs +9 -7
  43. package/dist/payment-methods/apple-pay.mjs.map +1 -1
  44. package/dist/payment-methods/bnpl-shared.d.mts +4 -4
  45. package/dist/payment-methods/bnpl-shared.mjs +2 -2
  46. package/dist/payment-methods/card.d.mts +3 -3
  47. package/dist/payment-methods/card.d.mts.map +1 -1
  48. package/dist/payment-methods/card.mjs +77 -18
  49. package/dist/payment-methods/card.mjs.map +1 -1
  50. package/dist/payment-methods/google-pay.d.mts +5 -5
  51. package/dist/payment-methods/google-pay.mjs +4 -4
  52. package/dist/payment-methods/klarna.d.mts +4 -4
  53. package/dist/payment-methods/klarna.mjs +2 -2
  54. package/dist/payment-methods/next-action-handlers.mjs +1 -1
  55. package/dist/payment-methods/paypal.d.mts +3 -3
  56. package/dist/payment-methods/paypal.mjs +1 -1
  57. package/dist/payment-methods/stripe-apple-pay-adapter.d.mts +1 -1
  58. package/dist/payment-methods/stripe-apple-pay-adapter.mjs +1 -1
  59. package/dist/payment-methods/stripe-google-pay-adapter.d.mts +1 -1
  60. package/dist/payment-methods/stripe-google-pay-adapter.mjs +1 -1
  61. package/dist/payment-methods/vgs-collect-loader.mjs +1 -1
  62. package/dist/penpal/connect-card.d.mts +1 -1
  63. package/dist/penpal/connect-card.mjs +2 -2
  64. package/dist/penpal/connect-tunnel-x.d.mts +1 -1
  65. package/dist/penpal/connect-tunnel-x.mjs +2 -2
  66. package/dist/{penpal-BFKeZTVz.mjs → penpal-CBrj43M5.mjs} +1 -1
  67. package/dist/{penpal-BFKeZTVz.mjs.map → penpal-CBrj43M5.mjs.map} +1 -1
  68. package/dist/{stripe-apple-pay-adapter-BLRjqgDf.mjs → stripe-apple-pay-adapter-7rF6xRIG.mjs} +1 -1
  69. package/dist/{stripe-apple-pay-adapter-BLRjqgDf.mjs.map → stripe-apple-pay-adapter-7rF6xRIG.mjs.map} +1 -1
  70. package/dist/{stripe-apple-pay-adapter-DcuGlQqQ.d.mts → stripe-apple-pay-adapter-D2OJRlAl.d.mts} +1 -1
  71. package/dist/{stripe-apple-pay-adapter-DcuGlQqQ.d.mts.map → stripe-apple-pay-adapter-D2OJRlAl.d.mts.map} +1 -1
  72. package/dist/{stripe-google-pay-adapter-BlQ2jVpE.d.mts → stripe-google-pay-adapter-B330fRiH.d.mts} +1 -1
  73. package/dist/{stripe-google-pay-adapter-BlQ2jVpE.d.mts.map → stripe-google-pay-adapter-B330fRiH.d.mts.map} +1 -1
  74. package/dist/{stripe-google-pay-adapter-CIkgjhw8.mjs → stripe-google-pay-adapter-B346KXt4.mjs} +1 -1
  75. package/dist/{stripe-google-pay-adapter-CIkgjhw8.mjs.map → stripe-google-pay-adapter-B346KXt4.mjs.map} +1 -1
  76. package/dist/{types-CQ8xbgoh.d.mts → types-B3mjYfOm.d.mts} +3 -3
  77. package/dist/{types-CQ8xbgoh.d.mts.map → types-B3mjYfOm.d.mts.map} +1 -1
  78. package/dist/{utils-B70Y8YcZ.mjs → utils-Dc6zwOe1.mjs} +1 -1
  79. package/dist/{utils-B70Y8YcZ.mjs.map → utils-Dc6zwOe1.mjs.map} +1 -1
  80. package/dist/{vgs-collect-loader-l5_Pnmhz.mjs → vgs-collect-loader-CTLSv4qv.mjs} +1 -1
  81. package/dist/{vgs-collect-loader-l5_Pnmhz.mjs.map → vgs-collect-loader-CTLSv4qv.mjs.map} +1 -1
  82. package/package.json +2 -2
  83. package/dist/airwallex-apple-pay-adapter-Bb0CreWN.d.mts.map +0 -1
  84. package/dist/airwallex-apple-pay-adapter-CHAnLP_x.mjs.map +0 -1
@@ -125,6 +125,8 @@ var AirwallexApplePayAdapter = class {
125
125
  transactionIdentifier: "MOCK_TXN_ID"
126
126
  },
127
127
  payerEmail: "mock@example.com",
128
+ payerFirstName: "Mock",
129
+ payerLastName: "User",
128
130
  complete: (status) => console.log(`[MockApplePay:Airwallex] complete: ${status}`)
129
131
  };
130
132
  }
@@ -160,7 +162,7 @@ var AirwallexApplePayAdapter = class {
160
162
  amount,
161
163
  type: "final"
162
164
  },
163
- requiredBillingContactFields: ["email"]
165
+ requiredBillingContactFields: ["email", "name"]
164
166
  };
165
167
  return new Promise((resolve) => {
166
168
  try {
@@ -204,6 +206,8 @@ var AirwallexApplePayAdapter = class {
204
206
  transactionIdentifier: payment.token.transactionIdentifier
205
207
  };
206
208
  const payerEmail = payment.billingContact?.emailAddress ?? payment.shippingContact?.emailAddress ?? void 0;
209
+ const payerFirstName = payment.billingContact?.givenName ?? payment.shippingContact?.givenName ?? void 0;
210
+ const payerLastName = payment.billingContact?.familyName ?? payment.shippingContact?.familyName ?? void 0;
207
211
  const complete = (status) => {
208
212
  console.log("[ApplePay:Airwallex] completing session with status:", status);
209
213
  const appleStatus = status === "success" ? STATUS_SUCCESS : STATUS_FAILURE;
@@ -213,6 +217,8 @@ var AirwallexApplePayAdapter = class {
213
217
  success: true,
214
218
  token,
215
219
  payerEmail,
220
+ payerFirstName,
221
+ payerLastName,
216
222
  complete
217
223
  });
218
224
  };
@@ -238,4 +244,4 @@ var AirwallexApplePayAdapter = class {
238
244
 
239
245
  //#endregion
240
246
  export { AirwallexApplePayMockScenario as n, AirwallexApplePayAdapter as t };
241
- //# sourceMappingURL=airwallex-apple-pay-adapter-CHAnLP_x.mjs.map
247
+ //# sourceMappingURL=airwallex-apple-pay-adapter-CPz54c9e.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airwallex-apple-pay-adapter-CPz54c9e.mjs","names":["paymentRequest: ApplePayJS.ApplePayPaymentRequest","token: ApplePayEncryptedToken"],"sources":["../src/payment-methods/airwallex-apple-pay-adapter.ts"],"sourcesContent":["/**\n * Airwallex Apple Pay Adapter\n *\n * Uses native ApplePaySession API directly (not Stripe.js) to show the payment sheet\n * and extract the encrypted payment token for Airwallex processing.\n *\n * Flow:\n * 1. initialize() - Checks if ApplePaySession is available\n * 2. canMakePayment() - Checks if user can pay with Apple Pay\n * 3. showPaymentSheet() - Shows Apple Pay sheet with merchant validation callback\n *\n * The key difference from Stripe's approach is that we use the native\n * ApplePaySession API and handle merchant validation via Airwallex's\n * payment_session/start API which validates with Apple.\n *\n * Mock scenarios are supported for E2E testing without real Apple Pay.\n */\n\n/// <reference types=\"@types/applepayjs\" />\n\nexport enum AirwallexApplePayMockScenario {\n None = \"none\",\n Success = \"success\",\n Cancelled = \"cancelled\",\n}\n\n// Apple Pay token structure from payment.token\nexport interface ApplePayEncryptedToken {\n paymentData: {\n version?: string;\n data: string;\n signature: string;\n header: {\n ephemeralPublicKey: string;\n publicKeyHash: string;\n transactionId: string;\n };\n };\n paymentMethod: {\n displayName: string;\n network: string;\n type: string;\n };\n transactionIdentifier: string;\n}\n\nexport interface AirwallexApplePayConfig {\n amount: number; // Amount in atomic units (cents)\n currency: string; // e.g., \"USD\"\n country: string; // e.g., \"US\"\n merchantName?: string; // Display name on Apple Pay sheet\n}\n\nexport type AirwallexApplePayShowResult =\n | {\n success: true;\n token: ApplePayEncryptedToken;\n payerEmail?: string;\n payerFirstName?: string;\n payerLastName?: string;\n complete: (status: \"success\" | \"fail\") => void;\n }\n | { success: false; cancelled: true }\n | { success: false; error: string };\n\n// Merchant validation callback type - called during onvalidatemerchant\nexport type MerchantValidationCallback = (\n validationUrl: string,\n) => Promise<{ merchantSession?: object; error?: string }>;\n\nexport class AirwallexApplePayAdapter {\n private config: AirwallexApplePayConfig | null = null;\n private mockScenario: AirwallexApplePayMockScenario;\n\n constructor(mockScenario?: AirwallexApplePayMockScenario) {\n this.mockScenario = mockScenario ?? AirwallexApplePayMockScenario.None;\n }\n\n /**\n * Initialize the adapter with payment configuration.\n * Returns true if Apple Pay is available on this device.\n */\n initialize(config: AirwallexApplePayConfig): boolean {\n // Mock scenarios bypass real Apple Pay initialization\n if (this.mockScenario !== AirwallexApplePayMockScenario.None) {\n console.log(\"[MockApplePay:Airwallex] initialize called (mock mode)\");\n this.config = config;\n return true;\n }\n\n // Check if ApplePaySession is available (Safari on iOS/macOS only)\n if (typeof window === \"undefined\" || !window.ApplePaySession) {\n console.error(\"[ApplePay:Airwallex] ApplePaySession not available (not Safari or unsupported device)\");\n return false;\n }\n\n this.config = config;\n return true;\n }\n\n /**\n * Check if the user can make a payment with Apple Pay.\n * Returns true if Apple Pay is set up on this device.\n */\n async canMakePayment(): Promise<boolean> {\n // Mock scenarios always return true\n if (this.mockScenario !== AirwallexApplePayMockScenario.None) {\n console.log(\"[MockApplePay:Airwallex] canMakePayment: true (mock mode)\");\n return true;\n }\n\n if (!window.ApplePaySession) {\n return false;\n }\n\n try {\n const canMake = window.ApplePaySession.canMakePayments();\n console.log(\"[ApplePay:Airwallex] canMakePayments:\", canMake);\n return canMake;\n } catch (error) {\n console.error(\"[ApplePay:Airwallex] canMakePayment error:\", error);\n return false;\n }\n }\n\n /**\n * Convert atomic units (cents) to display format for Apple Pay.\n * Apple Pay expects a string like \"10.00\" for $10.00.\n */\n private formatAmount(amountAtom: number, currency: string): string {\n // Most currencies use 2 decimal places, some like JPY use 0\n const zeroDecimalCurrencies = [\n \"BIF\",\n \"CLP\",\n \"DJF\",\n \"GNF\",\n \"ISK\",\n \"JPY\",\n \"KMF\",\n \"KRW\",\n \"PYG\",\n \"RWF\",\n \"UGX\",\n \"VND\",\n \"VUV\",\n \"XAF\",\n \"XOF\",\n \"XPF\",\n ];\n const isZeroDecimal = zeroDecimalCurrencies.includes(currency.toUpperCase());\n\n if (isZeroDecimal) {\n return amountAtom.toString();\n }\n\n return (amountAtom / 100).toFixed(2);\n }\n\n /**\n * Show the Apple Pay payment sheet and return the encrypted token.\n *\n * This uses the native ApplePaySession API with a two-step flow:\n * 1. onvalidatemerchant - Called by Apple to validate the merchant\n * The callback should call our backend which calls Airwallex's payment_session/start\n * 2. onpaymentauthorized - Called when user authorizes with Face ID/Touch ID\n * Returns the encrypted token for processing\n *\n * @param onMerchantValidation - Callback to validate merchant with backend\n * @returns Promise with token or error\n */\n async showPaymentSheet(onMerchantValidation: MerchantValidationCallback): Promise<AirwallexApplePayShowResult> {\n // Handle mock scenarios\n if (this.mockScenario === AirwallexApplePayMockScenario.Success) {\n console.log(\"[MockApplePay:Airwallex] showPaymentSheet: returning mock success token\");\n const mockToken: ApplePayEncryptedToken = {\n paymentData: {\n version: \"EC_v1\",\n data: \"MOCK_ENCRYPTED_DATA\",\n signature: \"MOCK_SIGNATURE\",\n header: {\n ephemeralPublicKey: \"MOCK_PUBLIC_KEY\",\n publicKeyHash: \"MOCK_HASH\",\n transactionId: \"mock_txn_123\",\n },\n },\n paymentMethod: {\n displayName: \"Visa 4242\",\n network: \"Visa\",\n type: \"debit\",\n },\n transactionIdentifier: \"MOCK_TXN_ID\",\n };\n return {\n success: true,\n token: mockToken,\n payerEmail: \"mock@example.com\",\n payerFirstName: \"Mock\",\n payerLastName: \"User\",\n complete: (status) => console.log(`[MockApplePay:Airwallex] complete: ${status}`),\n };\n }\n\n if (this.mockScenario === AirwallexApplePayMockScenario.Cancelled) {\n console.log(\"[MockApplePay:Airwallex] showPaymentSheet: returning mock cancelled\");\n return { success: false, cancelled: true };\n }\n\n // Real Apple Pay flow\n if (!this.config) {\n return { success: false, error: \"Apple Pay not initialized\" };\n }\n\n if (!window.ApplePaySession) {\n return { success: false, error: \"ApplePaySession not available\" };\n }\n\n const config = this.config;\n const amount = this.formatAmount(config.amount, config.currency);\n\n // Create the Apple Pay payment request\n const paymentRequest: ApplePayJS.ApplePayPaymentRequest = {\n countryCode: config.country.toUpperCase(),\n currencyCode: config.currency.toUpperCase(),\n supportedNetworks: [\"visa\", \"masterCard\", \"amex\", \"discover\"],\n merchantCapabilities: [\"supports3DS\"],\n total: {\n label: config.merchantName || \"Total\",\n amount: amount,\n type: \"final\",\n },\n // Surface the payer's email and name so the backend can fill missing customer info.\n requiredBillingContactFields: [\"email\", \"name\"],\n };\n\n return new Promise((resolve) => {\n try {\n // Create ApplePaySession (version 3 is widely supported)\n // biome-ignore lint/style/noNonNullAssertion: ApplePaySession is guaranteed to exist (checked in canMakePayments)\n const session = new window.ApplePaySession!(3, paymentRequest);\n\n // Capture status constants at creation time (before optional chaining could yield undefined)\n // biome-ignore lint/style/noNonNullAssertion: ApplePaySession existence verified above\n const STATUS_SUCCESS = window.ApplePaySession!.STATUS_SUCCESS;\n // biome-ignore lint/style/noNonNullAssertion: ApplePaySession existence verified above\n const STATUS_FAILURE = window.ApplePaySession!.STATUS_FAILURE;\n\n // Handle merchant validation\n session.onvalidatemerchant = async (event: ApplePayJS.ApplePayValidateMerchantEvent) => {\n console.log(\"[ApplePay:Airwallex] onvalidatemerchant called\", event.validationURL);\n\n try {\n const validationResult = await onMerchantValidation(event.validationURL);\n\n if (validationResult.error || !validationResult.merchantSession) {\n console.error(\"[ApplePay:Airwallex] Merchant validation failed:\", validationResult.error);\n session.abort();\n resolve({\n success: false,\n error: validationResult.error || \"Merchant validation failed\",\n });\n return;\n }\n\n // Complete merchant validation with the session from Apple\n session.completeMerchantValidation(validationResult.merchantSession);\n console.log(\"[ApplePay:Airwallex] Merchant validation completed\");\n } catch (error) {\n console.error(\"[ApplePay:Airwallex] Merchant validation error:\", error);\n session.abort();\n resolve({\n success: false,\n error: `Merchant validation error: ${error}`,\n });\n }\n };\n\n // Handle payment authorization (user approved with Face ID/Touch ID)\n session.onpaymentauthorized = (event: ApplePayJS.ApplePayPaymentAuthorizedEvent) => {\n console.log(\"[ApplePay:Airwallex] onpaymentauthorized called\");\n\n // Extract the encrypted token\n const payment = event.payment;\n const token: ApplePayEncryptedToken = {\n paymentData: payment.token.paymentData as ApplePayEncryptedToken[\"paymentData\"],\n paymentMethod: {\n displayName: payment.token.paymentMethod.displayName,\n network: payment.token.paymentMethod.network,\n type: payment.token.paymentMethod.type,\n },\n transactionIdentifier: payment.token.transactionIdentifier,\n };\n\n const payerEmail = payment.billingContact?.emailAddress ?? payment.shippingContact?.emailAddress ?? undefined;\n const payerFirstName = payment.billingContact?.givenName ?? payment.shippingContact?.givenName ?? undefined;\n const payerLastName = payment.billingContact?.familyName ?? payment.shippingContact?.familyName ?? undefined;\n\n // Create the complete callback that the caller will use after confirming\n const complete = (status: \"success\" | \"fail\") => {\n console.log(\"[ApplePay:Airwallex] completing session with status:\", status);\n const appleStatus = status === \"success\" ? STATUS_SUCCESS : STATUS_FAILURE;\n session.completePayment({ status: appleStatus });\n };\n\n resolve({\n success: true,\n token,\n payerEmail,\n payerFirstName,\n payerLastName,\n complete,\n });\n };\n\n // Handle cancellation\n session.oncancel = () => {\n console.log(\"[ApplePay:Airwallex] oncancel - user cancelled\");\n resolve({ success: false, cancelled: true });\n };\n\n // Start the session - this shows the Apple Pay sheet\n console.log(\"[ApplePay:Airwallex] Starting Apple Pay session\");\n session.begin();\n } catch (error) {\n console.error(\"[ApplePay:Airwallex] Session creation error:\", error);\n resolve({\n success: false,\n error: `Failed to create Apple Pay session: ${error}`,\n });\n }\n });\n }\n}\n"],"mappings":"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"}
@@ -49,6 +49,8 @@ type AirwallexApplePayShowResult = {
49
49
  success: true;
50
50
  token: ApplePayEncryptedToken;
51
51
  payerEmail?: string;
52
+ payerFirstName?: string;
53
+ payerLastName?: string;
52
54
  complete: (status: "success" | "fail") => void;
53
55
  } | {
54
56
  success: false;
@@ -96,4 +98,4 @@ declare class AirwallexApplePayAdapter {
96
98
  }
97
99
  //#endregion
98
100
  export { ApplePayEncryptedToken as a, AirwallexApplePayShowResult as i, AirwallexApplePayConfig as n, MerchantValidationCallback as o, AirwallexApplePayMockScenario as r, AirwallexApplePayAdapter as t };
99
- //# sourceMappingURL=airwallex-apple-pay-adapter-Bb0CreWN.d.mts.map
101
+ //# sourceMappingURL=airwallex-apple-pay-adapter-CnnZ7VL6.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"airwallex-apple-pay-adapter-CnnZ7VL6.d.mts","names":[],"sources":["../src/payment-methods/airwallex-apple-pay-adapter.ts"],"sourcesContent":[],"mappings":";;AAoBA;AAOA;AAmBA;AAOA;AAaA;AAIA;;;;;;;;;;;aAlDY,6BAAA;;;;;UAOK,sBAAA;;;;;;;;;;;;;;;;;;UAmBA,uBAAA;;;;;;KAOL,2BAAA;;SAGC;;;;;;;;;;;;KAUD,0BAAA,8BAEP;;;;cAEQ,wBAAA;;;6BAIgB;;;;;qBAQR;;;;;oBAsBK;;;;;;;;;;;;;;;;;;yCAkEqB,6BAA6B,QAAQ"}
@@ -168,4 +168,4 @@ var AirwallexGooglePayAdapter = class {
168
168
 
169
169
  //#endregion
170
170
  export { AirwallexGooglePayMockScenario as n, AirwallexGooglePayAdapter as t };
171
- //# sourceMappingURL=airwallex-google-pay-adapter-C8JTp01q.mjs.map
171
+ //# sourceMappingURL=airwallex-google-pay-adapter-BvlROwj_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"airwallex-google-pay-adapter-C8JTp01q.mjs","names":["baseMethod: AllowedPaymentMethod","request: IsReadyToPayRequest","request: PaymentDataRequest"],"sources":["../src/payment-methods/airwallex-google-pay-adapter.ts"],"sourcesContent":["/**\n * Airwallex Google Pay Adapter\n *\n * Uses Google Pay API directly (not Stripe.js) to show the payment sheet\n * and extract the encrypted payment token for Airwallex processing.\n *\n * Flow:\n * 1. initialize() - Checks if Google Pay API is available\n * 2. createPaymentDataRequest() - Configures the payment request\n * 3. canMakePayment() - Checks if user can pay with Google Pay\n * 4. showPaymentSheet() - Shows Google Pay sheet and returns encrypted token\n *\n * Mock scenarios are supported for E2E testing without real Google Pay.\n */\n\nexport enum AirwallexGooglePayMockScenario {\n None = \"none\",\n Success = \"success\",\n Cancelled = \"cancelled\",\n}\n\n// Google Pay API types\n// See: https://developers.google.com/pay/api/web/reference/request-objects\ndeclare global {\n interface Window {\n google?: {\n payments: {\n api: {\n PaymentsClient: new (config: GooglePayClientConfig) => GooglePaymentsClient;\n };\n };\n };\n }\n}\n\ninterface GooglePayClientConfig {\n environment: \"TEST\" | \"PRODUCTION\";\n}\n\ninterface GooglePaymentsClient {\n isReadyToPay(request: IsReadyToPayRequest): Promise<IsReadyToPayResponse>;\n loadPaymentData(request: PaymentDataRequest): Promise<PaymentData>;\n}\n\ninterface IsReadyToPayRequest {\n apiVersion: number;\n apiVersionMinor: number;\n allowedPaymentMethods: AllowedPaymentMethod[];\n}\n\ninterface IsReadyToPayResponse {\n result: boolean;\n}\n\ninterface AllowedPaymentMethod {\n type: \"CARD\";\n parameters: {\n allowedAuthMethods: (\"PAN_ONLY\" | \"CRYPTOGRAM_3DS\")[];\n allowedCardNetworks: (\"VISA\" | \"MASTERCARD\" | \"AMEX\" | \"DISCOVER\" | \"JCB\")[];\n };\n tokenizationSpecification?: TokenizationSpecification;\n}\n\ninterface TokenizationSpecification {\n type: \"PAYMENT_GATEWAY\";\n parameters: {\n gateway: string;\n gatewayMerchantId: string;\n };\n}\n\ninterface PaymentDataRequest extends IsReadyToPayRequest {\n merchantInfo: {\n merchantId?: string;\n merchantName: string;\n };\n transactionInfo: {\n totalPriceStatus: \"FINAL\" | \"ESTIMATED\";\n totalPrice: string;\n currencyCode: string;\n countryCode: string;\n };\n emailRequired?: boolean;\n}\n\ninterface PaymentData {\n email?: string;\n paymentMethodData: {\n type: string;\n tokenizationData: {\n type: string;\n token: string; // JSON string containing the encrypted payment token\n };\n info?: {\n cardNetwork: string;\n cardDetails: string;\n };\n };\n}\n\n// Google Pay encrypted token structure (what's inside tokenizationData.token)\nexport interface GooglePayEncryptedToken {\n protocolVersion: string;\n signature: string;\n intermediateSigningKey: {\n signedKey: string;\n signatures: string[];\n };\n signedMessage: string;\n}\n\nexport interface AirwallexGooglePayConfig {\n merchantId: string; // Business name for display\n gatewayMerchantId: string; // Airwallex account ID (acct_xxxx)\n amountDisplay: string; // Formatted amount for Google Pay (e.g., \"100.00\" for USD, \"1000\" for JPY)\n currency: string; // e.g., \"usd\"\n country: string; // e.g., \"US\"\n isProduction?: boolean; // Default: false (TEST environment)\n googleMerchantId?: string; // Google-assigned merchant ID for production (BCR2DN...)\n}\n\nexport type AirwallexShowPaymentResult =\n | { success: true; token: GooglePayEncryptedToken; payerEmail?: string }\n | { success: false; cancelled: true }\n | { success: false; error: string };\n\nexport class AirwallexGooglePayAdapter {\n private client: GooglePaymentsClient | null = null;\n private config: AirwallexGooglePayConfig | null = null;\n private mockScenario: AirwallexGooglePayMockScenario;\n\n constructor(mockScenario?: AirwallexGooglePayMockScenario) {\n this.mockScenario = mockScenario ?? AirwallexGooglePayMockScenario.None;\n }\n\n /**\n * Initialize the Google Pay client.\n * Returns true if Google Pay API is available.\n */\n initialize(config: AirwallexGooglePayConfig): boolean {\n // Mock scenarios bypass real Google Pay initialization\n if (this.mockScenario !== AirwallexGooglePayMockScenario.None) {\n console.log(\"[MockGooglePay:Airwallex] initialize called (mock mode)\");\n this.config = config;\n return true;\n }\n\n if (!window.google?.payments?.api?.PaymentsClient) {\n console.error(\"[GooglePay:Airwallex] Google Pay API not loaded\");\n return false;\n }\n\n this.config = config;\n this.client = new window.google.payments.api.PaymentsClient({\n environment: config.isProduction ? \"PRODUCTION\" : \"TEST\",\n });\n\n return this.client !== null;\n }\n\n /**\n * Build the allowed payment methods configuration for Google Pay.\n */\n private getAllowedPaymentMethods(includeTokenization: boolean): AllowedPaymentMethod[] {\n if (!this.config) {\n throw new Error(\"Config not set. Call initialize() first.\");\n }\n\n const baseMethod: AllowedPaymentMethod = {\n type: \"CARD\",\n parameters: {\n allowedAuthMethods: [\"PAN_ONLY\", \"CRYPTOGRAM_3DS\"],\n allowedCardNetworks: [\"VISA\", \"MASTERCARD\", \"AMEX\", \"DISCOVER\", \"JCB\"],\n },\n };\n\n if (includeTokenization) {\n baseMethod.tokenizationSpecification = {\n type: \"PAYMENT_GATEWAY\",\n parameters: {\n gateway: \"airwallex\",\n gatewayMerchantId: this.config.gatewayMerchantId,\n },\n };\n }\n\n return [baseMethod];\n }\n\n /**\n * Check if the user can make a payment with Google Pay.\n */\n async canMakePayment(): Promise<boolean> {\n // Mock scenarios always return true\n if (this.mockScenario !== AirwallexGooglePayMockScenario.None) {\n console.log(\"[MockGooglePay:Airwallex] canMakePayment: true (mock mode)\");\n return true;\n }\n\n if (!this.client) {\n return false;\n }\n\n try {\n const request: IsReadyToPayRequest = {\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: this.getAllowedPaymentMethods(false),\n };\n\n const response = await this.client.isReadyToPay(request);\n return response.result;\n } catch (error) {\n console.error(\"[GooglePay:Airwallex] canMakePayment error:\", error);\n return false;\n }\n }\n\n /**\n * Show the Google Pay payment sheet and return the encrypted token.\n */\n async showPaymentSheet(): Promise<AirwallexShowPaymentResult> {\n // Handle mock scenarios\n if (this.mockScenario === AirwallexGooglePayMockScenario.Success) {\n console.log(\"[MockGooglePay:Airwallex] showPaymentSheet: returning mock success token\");\n // Return a mock token that the backend will recognize as mock\n const mockToken: GooglePayEncryptedToken = {\n protocolVersion: \"ECv2\",\n signature: \"MOCK_SIGNATURE\",\n intermediateSigningKey: {\n signedKey: \"MOCK_SIGNED_KEY\",\n signatures: [\"MOCK_SIGNATURE\"],\n },\n signedMessage: \"MOCK_SIGNED_MESSAGE\",\n };\n return { success: true, token: mockToken, payerEmail: \"mock@example.com\" };\n }\n\n if (this.mockScenario === AirwallexGooglePayMockScenario.Cancelled) {\n console.log(\"[MockGooglePay:Airwallex] showPaymentSheet: returning mock cancelled\");\n return { success: false, cancelled: true };\n }\n\n // Real Google Pay flow\n if (!this.client || !this.config) {\n return { success: false, error: \"Google Pay not initialized\" };\n }\n\n try {\n const totalPrice = this.config.amountDisplay;\n\n const request: PaymentDataRequest = {\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: this.getAllowedPaymentMethods(true),\n merchantInfo: {\n merchantName: this.config.merchantId,\n // merchantId is required in PRODUCTION environment\n // It's the Google-assigned merchant ID from Google Pay Business Console\n ...(this.config.isProduction && this.config.googleMerchantId\n ? { merchantId: this.config.googleMerchantId }\n : {}),\n },\n transactionInfo: {\n totalPriceStatus: \"FINAL\",\n totalPrice: totalPrice,\n currencyCode: this.config.currency.toUpperCase(),\n countryCode: this.config.country.toUpperCase(),\n },\n emailRequired: true,\n };\n\n const paymentData = await this.client.loadPaymentData(request);\n\n // Parse the encrypted token from the response\n const tokenString = paymentData.paymentMethodData.tokenizationData.token;\n const token: GooglePayEncryptedToken = JSON.parse(tokenString);\n\n return { success: true, token, payerEmail: paymentData.email };\n } catch (error) {\n // Google Pay API throws an error when user cancels\n if (error instanceof Error && error.message?.includes(\"CANCELED\")) {\n return { success: false, cancelled: true };\n }\n\n // Check for statusCode which indicates user cancelled\n const gpayError = error as { statusCode?: string };\n if (gpayError.statusCode === \"CANCELED\") {\n return { success: false, cancelled: true };\n }\n\n console.error(\"[GooglePay:Airwallex] Payment sheet error:\", error);\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"airwallex-google-pay-adapter-BvlROwj_.mjs","names":["baseMethod: AllowedPaymentMethod","request: IsReadyToPayRequest","request: PaymentDataRequest"],"sources":["../src/payment-methods/airwallex-google-pay-adapter.ts"],"sourcesContent":["/**\n * Airwallex Google Pay Adapter\n *\n * Uses Google Pay API directly (not Stripe.js) to show the payment sheet\n * and extract the encrypted payment token for Airwallex processing.\n *\n * Flow:\n * 1. initialize() - Checks if Google Pay API is available\n * 2. createPaymentDataRequest() - Configures the payment request\n * 3. canMakePayment() - Checks if user can pay with Google Pay\n * 4. showPaymentSheet() - Shows Google Pay sheet and returns encrypted token\n *\n * Mock scenarios are supported for E2E testing without real Google Pay.\n */\n\nexport enum AirwallexGooglePayMockScenario {\n None = \"none\",\n Success = \"success\",\n Cancelled = \"cancelled\",\n}\n\n// Google Pay API types\n// See: https://developers.google.com/pay/api/web/reference/request-objects\ndeclare global {\n interface Window {\n google?: {\n payments: {\n api: {\n PaymentsClient: new (config: GooglePayClientConfig) => GooglePaymentsClient;\n };\n };\n };\n }\n}\n\ninterface GooglePayClientConfig {\n environment: \"TEST\" | \"PRODUCTION\";\n}\n\ninterface GooglePaymentsClient {\n isReadyToPay(request: IsReadyToPayRequest): Promise<IsReadyToPayResponse>;\n loadPaymentData(request: PaymentDataRequest): Promise<PaymentData>;\n}\n\ninterface IsReadyToPayRequest {\n apiVersion: number;\n apiVersionMinor: number;\n allowedPaymentMethods: AllowedPaymentMethod[];\n}\n\ninterface IsReadyToPayResponse {\n result: boolean;\n}\n\ninterface AllowedPaymentMethod {\n type: \"CARD\";\n parameters: {\n allowedAuthMethods: (\"PAN_ONLY\" | \"CRYPTOGRAM_3DS\")[];\n allowedCardNetworks: (\"VISA\" | \"MASTERCARD\" | \"AMEX\" | \"DISCOVER\" | \"JCB\")[];\n };\n tokenizationSpecification?: TokenizationSpecification;\n}\n\ninterface TokenizationSpecification {\n type: \"PAYMENT_GATEWAY\";\n parameters: {\n gateway: string;\n gatewayMerchantId: string;\n };\n}\n\ninterface PaymentDataRequest extends IsReadyToPayRequest {\n merchantInfo: {\n merchantId?: string;\n merchantName: string;\n };\n transactionInfo: {\n totalPriceStatus: \"FINAL\" | \"ESTIMATED\";\n totalPrice: string;\n currencyCode: string;\n countryCode: string;\n };\n emailRequired?: boolean;\n}\n\ninterface PaymentData {\n email?: string;\n paymentMethodData: {\n type: string;\n tokenizationData: {\n type: string;\n token: string; // JSON string containing the encrypted payment token\n };\n info?: {\n cardNetwork: string;\n cardDetails: string;\n };\n };\n}\n\n// Google Pay encrypted token structure (what's inside tokenizationData.token)\nexport interface GooglePayEncryptedToken {\n protocolVersion: string;\n signature: string;\n intermediateSigningKey: {\n signedKey: string;\n signatures: string[];\n };\n signedMessage: string;\n}\n\nexport interface AirwallexGooglePayConfig {\n merchantId: string; // Business name for display\n gatewayMerchantId: string; // Airwallex account ID (acct_xxxx)\n amountDisplay: string; // Formatted amount for Google Pay (e.g., \"100.00\" for USD, \"1000\" for JPY)\n currency: string; // e.g., \"usd\"\n country: string; // e.g., \"US\"\n isProduction?: boolean; // Default: false (TEST environment)\n googleMerchantId?: string; // Google-assigned merchant ID for production (BCR2DN...)\n}\n\nexport type AirwallexShowPaymentResult =\n | { success: true; token: GooglePayEncryptedToken; payerEmail?: string }\n | { success: false; cancelled: true }\n | { success: false; error: string };\n\nexport class AirwallexGooglePayAdapter {\n private client: GooglePaymentsClient | null = null;\n private config: AirwallexGooglePayConfig | null = null;\n private mockScenario: AirwallexGooglePayMockScenario;\n\n constructor(mockScenario?: AirwallexGooglePayMockScenario) {\n this.mockScenario = mockScenario ?? AirwallexGooglePayMockScenario.None;\n }\n\n /**\n * Initialize the Google Pay client.\n * Returns true if Google Pay API is available.\n */\n initialize(config: AirwallexGooglePayConfig): boolean {\n // Mock scenarios bypass real Google Pay initialization\n if (this.mockScenario !== AirwallexGooglePayMockScenario.None) {\n console.log(\"[MockGooglePay:Airwallex] initialize called (mock mode)\");\n this.config = config;\n return true;\n }\n\n if (!window.google?.payments?.api?.PaymentsClient) {\n console.error(\"[GooglePay:Airwallex] Google Pay API not loaded\");\n return false;\n }\n\n this.config = config;\n this.client = new window.google.payments.api.PaymentsClient({\n environment: config.isProduction ? \"PRODUCTION\" : \"TEST\",\n });\n\n return this.client !== null;\n }\n\n /**\n * Build the allowed payment methods configuration for Google Pay.\n */\n private getAllowedPaymentMethods(includeTokenization: boolean): AllowedPaymentMethod[] {\n if (!this.config) {\n throw new Error(\"Config not set. Call initialize() first.\");\n }\n\n const baseMethod: AllowedPaymentMethod = {\n type: \"CARD\",\n parameters: {\n allowedAuthMethods: [\"PAN_ONLY\", \"CRYPTOGRAM_3DS\"],\n allowedCardNetworks: [\"VISA\", \"MASTERCARD\", \"AMEX\", \"DISCOVER\", \"JCB\"],\n },\n };\n\n if (includeTokenization) {\n baseMethod.tokenizationSpecification = {\n type: \"PAYMENT_GATEWAY\",\n parameters: {\n gateway: \"airwallex\",\n gatewayMerchantId: this.config.gatewayMerchantId,\n },\n };\n }\n\n return [baseMethod];\n }\n\n /**\n * Check if the user can make a payment with Google Pay.\n */\n async canMakePayment(): Promise<boolean> {\n // Mock scenarios always return true\n if (this.mockScenario !== AirwallexGooglePayMockScenario.None) {\n console.log(\"[MockGooglePay:Airwallex] canMakePayment: true (mock mode)\");\n return true;\n }\n\n if (!this.client) {\n return false;\n }\n\n try {\n const request: IsReadyToPayRequest = {\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: this.getAllowedPaymentMethods(false),\n };\n\n const response = await this.client.isReadyToPay(request);\n return response.result;\n } catch (error) {\n console.error(\"[GooglePay:Airwallex] canMakePayment error:\", error);\n return false;\n }\n }\n\n /**\n * Show the Google Pay payment sheet and return the encrypted token.\n */\n async showPaymentSheet(): Promise<AirwallexShowPaymentResult> {\n // Handle mock scenarios\n if (this.mockScenario === AirwallexGooglePayMockScenario.Success) {\n console.log(\"[MockGooglePay:Airwallex] showPaymentSheet: returning mock success token\");\n // Return a mock token that the backend will recognize as mock\n const mockToken: GooglePayEncryptedToken = {\n protocolVersion: \"ECv2\",\n signature: \"MOCK_SIGNATURE\",\n intermediateSigningKey: {\n signedKey: \"MOCK_SIGNED_KEY\",\n signatures: [\"MOCK_SIGNATURE\"],\n },\n signedMessage: \"MOCK_SIGNED_MESSAGE\",\n };\n return { success: true, token: mockToken, payerEmail: \"mock@example.com\" };\n }\n\n if (this.mockScenario === AirwallexGooglePayMockScenario.Cancelled) {\n console.log(\"[MockGooglePay:Airwallex] showPaymentSheet: returning mock cancelled\");\n return { success: false, cancelled: true };\n }\n\n // Real Google Pay flow\n if (!this.client || !this.config) {\n return { success: false, error: \"Google Pay not initialized\" };\n }\n\n try {\n const totalPrice = this.config.amountDisplay;\n\n const request: PaymentDataRequest = {\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: this.getAllowedPaymentMethods(true),\n merchantInfo: {\n merchantName: this.config.merchantId,\n // merchantId is required in PRODUCTION environment\n // It's the Google-assigned merchant ID from Google Pay Business Console\n ...(this.config.isProduction && this.config.googleMerchantId\n ? { merchantId: this.config.googleMerchantId }\n : {}),\n },\n transactionInfo: {\n totalPriceStatus: \"FINAL\",\n totalPrice: totalPrice,\n currencyCode: this.config.currency.toUpperCase(),\n countryCode: this.config.country.toUpperCase(),\n },\n emailRequired: true,\n };\n\n const paymentData = await this.client.loadPaymentData(request);\n\n // Parse the encrypted token from the response\n const tokenString = paymentData.paymentMethodData.tokenizationData.token;\n const token: GooglePayEncryptedToken = JSON.parse(tokenString);\n\n return { success: true, token, payerEmail: paymentData.email };\n } catch (error) {\n // Google Pay API throws an error when user cancels\n if (error instanceof Error && error.message?.includes(\"CANCELED\")) {\n return { success: false, cancelled: true };\n }\n\n // Check for statusCode which indicates user cancelled\n const gpayError = error as { statusCode?: string };\n if (gpayError.statusCode === \"CANCELED\") {\n return { success: false, cancelled: true };\n }\n\n console.error(\"[GooglePay:Airwallex] Payment sheet error:\", error);\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n return { success: false, error: errorMessage };\n }\n }\n}\n"],"mappings":"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"}
@@ -140,4 +140,4 @@ declare class AirwallexGooglePayAdapter {
140
140
  }
141
141
  //#endregion
142
142
  export { GooglePayEncryptedToken as a, AirwallexShowPaymentResult as i, AirwallexGooglePayConfig as n, AirwallexGooglePayMockScenario as r, AirwallexGooglePayAdapter as t };
143
- //# sourceMappingURL=airwallex-google-pay-adapter-adaDktQM.d.mts.map
143
+ //# sourceMappingURL=airwallex-google-pay-adapter-D-AxVLLq.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"airwallex-google-pay-adapter-adaDktQM.d.mts","names":[],"sources":["../src/payment-methods/airwallex-google-pay-adapter.ts"],"sourcesContent":[],"mappings":";;AAeA;AAIC;;;;;AASoF;AAOtD;;;;;;AAMiB,aA1BpC,8BAAA;EA0B2C,IAAA,GAAA,MAAA;EAG7C,OAAA,GAAA,SAAA;EAMA,SAAA,GAAA,WAAoB;AAAA;AAUyB,QAG7C,MAAA,CAAA;EAQA,UAAA,MAAA,CAAA;IAcA,MAAA,CAAA,EAAA;MAgBO,QAAA,EAAA;QAUA,GAAA,EAAA;UAUL,cAA0B,EAAA,KAAA,MACV,EA9FW,qBA8FY,EAAA,GA9Fc,oBA8Fd;QAItC,CAAA;MAKgB,CAAA;IAQR,CAAA;EAqDK;;UA7JhB,qBAAA,CA0LkB;EAAO,WAAA,EAAA,MAAA,GAAA,YAAA;;UAtLzB,oBAAA;wBACc,sBAAsB,QAAQ;2BAC3B,qBAAqB,QAAQ;;UAG9C,mBAAA;;;yBAGe;;UAGf,oBAAA;;;UAIA,oBAAA;;;;;;8BAMoB;;UAGpB,yBAAA;;;;;;;UAQA,kBAAA,SAA2B;;;;;;;;;;;;;UAc3B,WAAA;;;;;;;;;;;;;;UAgBO,uBAAA;;;;;;;;;UAUA,wBAAA;;;;;;;;;KAUL,0BAAA;;SACgB;;;;;;;;;cAIf,yBAAA;;;;6BAKgB;;;;;qBAQR;;;;;;;;oBAqDK;;;;sBA6BE,QAAQ"}
1
+ {"version":3,"file":"airwallex-google-pay-adapter-D-AxVLLq.d.mts","names":[],"sources":["../src/payment-methods/airwallex-google-pay-adapter.ts"],"sourcesContent":[],"mappings":";;AAeA;AAIC;;;;;AASoF;AAOtD;;;;;;AAMiB,aA1BpC,8BAAA;EA0B2C,IAAA,GAAA,MAAA;EAG7C,OAAA,GAAA,SAAA;EAMA,SAAA,GAAA,WAAoB;AAAA;AAUyB,QAG7C,MAAA,CAAA;EAQA,UAAA,MAAA,CAAA;IAcA,MAAA,CAAA,EAAA;MAgBO,QAAA,EAAA;QAUA,GAAA,EAAA;UAUL,cAA0B,EAAA,KAAA,MACV,EA9FW,qBA8FY,EAAA,GA9Fc,oBA8Fd;QAItC,CAAA;MAKgB,CAAA;IAQR,CAAA;EAqDK;;UA7JhB,qBAAA,CA0LkB;EAAO,WAAA,EAAA,MAAA,GAAA,YAAA;;UAtLzB,oBAAA;wBACc,sBAAsB,QAAQ;2BAC3B,qBAAqB,QAAQ;;UAG9C,mBAAA;;;yBAGe;;UAGf,oBAAA;;;UAIA,oBAAA;;;;;;8BAMoB;;UAGpB,yBAAA;;;;;;;UAQA,kBAAA,SAA2B;;;;;;;;;;;;;UAc3B,WAAA;;;;;;;;;;;;;;UAgBO,uBAAA;;;;;;;;;UAUA,wBAAA;;;;;;;;;KAUL,0BAAA;;SACgB;;;;;;;;;cAIf,yBAAA;;;;6BAKgB;;;;;qBAQR;;;;;;;;oBAqDK;;;;sBA6BE,QAAQ"}
@@ -0,0 +1,333 @@
1
+ import posthog from "posthog-js";
2
+
3
+ //#region src/analytics/mock-adapter.ts
4
+ /**
5
+ * Mock analytics adapter for testing.
6
+ *
7
+ * Records all captured events for assertion in tests.
8
+ */
9
+ var MockAnalyticsAdapter = class {
10
+ events = [];
11
+ distinctId = null;
12
+ identify(distinctId) {
13
+ this.distinctId = distinctId;
14
+ }
15
+ capture(event, properties) {
16
+ this.events.push({
17
+ event,
18
+ distinct_id: this.distinctId,
19
+ properties,
20
+ timestamp: Date.now()
21
+ });
22
+ }
23
+ isInitialized() {
24
+ return true;
25
+ }
26
+ /**
27
+ * Get all captured events.
28
+ */
29
+ getEvents() {
30
+ return [...this.events];
31
+ }
32
+ /**
33
+ * Get events by name.
34
+ */
35
+ getEventsByName(eventName) {
36
+ return this.events.filter((e) => e.event === eventName);
37
+ }
38
+ /**
39
+ * Clear all captured events.
40
+ */
41
+ clear() {
42
+ this.events = [];
43
+ }
44
+ };
45
+
46
+ //#endregion
47
+ //#region src/analytics/posthog-adapter.ts
48
+ const POSTHOG_API_KEY = "phc_u9YDYUeUxo3CYn16XGrrwpVb8ycXgcjz5DarvIKRAAG";
49
+ /**
50
+ * PostHog implementation of the analytics adapter.
51
+ *
52
+ * Singleton stored in window to ensure only one instance exists across
53
+ * all script loads. Configures PostHog to use the reverse proxy at
54
+ * /ingest to avoid ad blockers.
55
+ */
56
+ var PostHogAdapter = class PostHogAdapter {
57
+ initialized = false;
58
+ /**
59
+ * Get or create the PostHog adapter singleton (stored in window).
60
+ *
61
+ * @param apiBaseUrl - The API base URL for the reverse proxy
62
+ * @throws Error if called with a different apiBaseUrl than the first call
63
+ */
64
+ static getInstance(apiBaseUrl) {
65
+ if (typeof window === "undefined") throw new Error("[PaymentKit Analytics] PostHog requires a browser environment");
66
+ const existing = window.__paymentKitPostHog__;
67
+ if (existing) {
68
+ if (existing.apiBaseUrl !== apiBaseUrl) throw new Error(`[PaymentKit Analytics] PostHog already initialized with apiBaseUrl "${existing.apiBaseUrl}", cannot re-initialize with different apiBaseUrl "${apiBaseUrl}"`);
69
+ return existing.instance;
70
+ }
71
+ const instance = new PostHogAdapter(apiBaseUrl);
72
+ window.__paymentKitPostHog__ = {
73
+ instance,
74
+ apiBaseUrl
75
+ };
76
+ return instance;
77
+ }
78
+ constructor(apiBaseUrl) {
79
+ this.initPostHog(apiBaseUrl);
80
+ }
81
+ initPostHog(apiBaseUrl) {
82
+ try {
83
+ posthog.init(POSTHOG_API_KEY, {
84
+ api_host: `${apiBaseUrl}/ingest`,
85
+ ui_host: "https://us.posthog.com",
86
+ persistence: "memory",
87
+ disable_session_recording: true,
88
+ autocapture: false,
89
+ capture_pageview: false,
90
+ request_batching: false,
91
+ opt_out_useragent_filter: true,
92
+ loaded: () => {
93
+ this.initialized = true;
94
+ }
95
+ });
96
+ } catch (e) {
97
+ console.warn("[PaymentKit Analytics] Failed to initialize PostHog:", e);
98
+ }
99
+ }
100
+ identify(distinctId) {
101
+ try {
102
+ posthog.identify(distinctId);
103
+ } catch (e) {
104
+ console.warn("[PaymentKit Analytics] Failed to identify:", e);
105
+ }
106
+ }
107
+ capture(event, properties) {
108
+ try {
109
+ posthog.capture(event, properties);
110
+ } catch (e) {
111
+ console.warn("[PaymentKit Analytics] Failed to capture event:", e);
112
+ }
113
+ }
114
+ isInitialized() {
115
+ return this.initialized;
116
+ }
117
+ };
118
+
119
+ //#endregion
120
+ //#region src/analytics/service.ts
121
+ /**
122
+ * Analytics service singleton.
123
+ *
124
+ * Provides a global interface for capturing analytics events.
125
+ * Supports multiple adapters that receive all events (composite pattern).
126
+ *
127
+ * Usage:
128
+ * // Initialize (typically done once at SDK init)
129
+ * AnalyticsService.init("http://localhost:9000");
130
+ *
131
+ * // Capture events - broadcasts to all registered adapters
132
+ * AnalyticsService.capture("checkout_page_ready", { session_id: "..." });
133
+ *
134
+ * // For testing - add a mock adapter
135
+ * import { MockAnalyticsAdapter } from "./mock-adapter";
136
+ * const mock = new MockAnalyticsAdapter();
137
+ * AnalyticsService.addAdapter(mock);
138
+ *
139
+ * // Or use the built-in test mock (exposed globally as window.__paymentKitAnalytics__)
140
+ * AnalyticsService.enableTestMode();
141
+ * // Events can be read via window.__paymentKitAnalytics__.getEvents()
142
+ */
143
+ var AnalyticsServiceClass = class {
144
+ adapters = [];
145
+ testMock = null;
146
+ /**
147
+ * Initialize the analytics service with PostHog.
148
+ *
149
+ * @param apiBaseUrl - The API base URL for the reverse proxy
150
+ * @param enableTestMode - Enable test mode for capturing events in tests
151
+ */
152
+ init(apiBaseUrl, enableTestMode) {
153
+ try {
154
+ this.addAdapter(PostHogAdapter.getInstance(apiBaseUrl));
155
+ if (enableTestMode) this.enableTestMode();
156
+ } catch (e) {
157
+ console.warn("[PaymentKit Analytics] Init failed:", e);
158
+ }
159
+ }
160
+ /**
161
+ * Enable test mode by adding a mock adapter and exposing it globally.
162
+ * The mock adapter is accessible via window.__paymentKitAnalytics__
163
+ */
164
+ enableTestMode() {
165
+ if (this.testMock) return;
166
+ this.testMock = new MockAnalyticsAdapter();
167
+ this.addAdapter(this.testMock);
168
+ if (typeof window !== "undefined") window.__paymentKitAnalytics__ = this.testMock;
169
+ }
170
+ /**
171
+ * Get the test mock adapter (if test mode is enabled).
172
+ */
173
+ getTestMock() {
174
+ return this.testMock;
175
+ }
176
+ /**
177
+ * Add an analytics adapter.
178
+ * Events will be broadcast to all registered adapters.
179
+ * Duplicate adapters (same instance) are ignored.
180
+ *
181
+ * @param adapter - The adapter to add
182
+ */
183
+ addAdapter(adapter) {
184
+ if (!this.adapters.includes(adapter)) this.adapters.push(adapter);
185
+ }
186
+ /**
187
+ * Clear all adapters.
188
+ */
189
+ clearAdapters() {
190
+ this.adapters = [];
191
+ this.testMock = null;
192
+ if (typeof window !== "undefined") delete window.__paymentKitAnalytics__;
193
+ }
194
+ /**
195
+ * Set the distinct_id for all adapters.
196
+ * This is used to correlate frontend events with backend events.
197
+ * Should be called with the checkout session secure token.
198
+ */
199
+ identify(distinctId) {
200
+ for (const adapter of this.adapters) try {
201
+ adapter.identify(distinctId);
202
+ } catch {}
203
+ }
204
+ /**
205
+ * Capture an analytics event.
206
+ * Broadcasts to all registered adapters. Silently fails on errors.
207
+ */
208
+ capture(event, properties) {
209
+ for (const adapter of this.adapters) try {
210
+ adapter.capture(event, properties);
211
+ } catch {}
212
+ }
213
+ /**
214
+ * Check if any adapter is initialized.
215
+ */
216
+ isInitialized() {
217
+ return this.adapters.some((adapter) => adapter.isInitialized());
218
+ }
219
+ };
220
+ /**
221
+ * Global analytics service instance.
222
+ */
223
+ const AnalyticsService = new AnalyticsServiceClass();
224
+
225
+ //#endregion
226
+ //#region src/analytics/checkout-timing.ts
227
+ /**
228
+ * Tracks timing metrics throughout the checkout flow.
229
+ *
230
+ * Create one instance per checkout session and call the track methods
231
+ * at appropriate points in the checkout flow.
232
+ *
233
+ * Usage:
234
+ * const requestId = getOrCreateCheckoutRequestId(environment);
235
+ * const tracker = new CheckoutTimingTracker(secureToken, requestId);
236
+ * tracker.trackPageReady();
237
+ * // ... iframe loads ...
238
+ * tracker.trackInputReady();
239
+ * // ... user submits ...
240
+ * tracker.trackSubmit();
241
+ * // ... API response ...
242
+ * tracker.trackSuccess(attemptId);
243
+ */
244
+ var CheckoutTimingTracker = class CheckoutTimingTracker {
245
+ static pageReadyTracked = false;
246
+ startTime;
247
+ checkoutSessionId;
248
+ requestId;
249
+ inputReadyTracked = false;
250
+ constructor(checkoutSessionId, requestId) {
251
+ this.startTime = performance.now();
252
+ this.checkoutSessionId = checkoutSessionId;
253
+ this.requestId = requestId;
254
+ }
255
+ /**
256
+ * Track when SDK is initialized and ready.
257
+ * Call immediately after PaymentKit() initialization.
258
+ * Only tracks once per page load (subsequent calls are no-ops).
259
+ */
260
+ trackPageReady() {
261
+ if (CheckoutTimingTracker.pageReadyTracked) return;
262
+ CheckoutTimingTracker.pageReadyTracked = true;
263
+ AnalyticsService.capture("checkout_page_ready", {
264
+ checkout_session_id: this.checkoutSessionId,
265
+ request_id: this.requestId,
266
+ elapsed_ms: this.getElapsedMs()
267
+ });
268
+ }
269
+ /**
270
+ * Track when card input iframe is loaded and ready for input.
271
+ * Should only be called once (for first iframe, typically card_pan).
272
+ * Subsequent calls are no-ops.
273
+ */
274
+ trackInputReady() {
275
+ if (this.inputReadyTracked) return;
276
+ this.inputReadyTracked = true;
277
+ AnalyticsService.capture("checkout_input_ready", {
278
+ checkout_session_id: this.checkoutSessionId,
279
+ request_id: this.requestId,
280
+ elapsed_ms: this.getElapsedMs()
281
+ });
282
+ }
283
+ /**
284
+ * Track when user clicks submit button.
285
+ */
286
+ trackSubmit() {
287
+ AnalyticsService.capture("checkout_submit", {
288
+ checkout_session_id: this.checkoutSessionId,
289
+ request_id: this.requestId,
290
+ elapsed_ms: this.getElapsedMs()
291
+ });
292
+ }
293
+ /**
294
+ * Track successful checkout.
295
+ *
296
+ * @param checkoutAttemptId - The checkout attempt ID
297
+ */
298
+ trackSuccess(checkoutAttemptId) {
299
+ AnalyticsService.capture("checkout_success", {
300
+ checkout_session_id: this.checkoutSessionId,
301
+ checkout_attempt_id: checkoutAttemptId,
302
+ request_id: this.requestId,
303
+ total_elapsed_ms: this.getElapsedMs()
304
+ });
305
+ }
306
+ /**
307
+ * Track failed checkout.
308
+ *
309
+ * @param checkoutAttemptId - The checkout attempt ID (may be null if failed early)
310
+ * @param errorCode - The error code from the checkout response
311
+ * @param errorMessage - The customer-facing error message
312
+ */
313
+ trackFail(checkoutAttemptId, errorCode, errorMessage) {
314
+ AnalyticsService.capture("checkout_fail", {
315
+ checkout_session_id: this.checkoutSessionId,
316
+ checkout_attempt_id: checkoutAttemptId,
317
+ request_id: this.requestId,
318
+ error_code: errorCode,
319
+ error_message: errorMessage,
320
+ total_elapsed_ms: this.getElapsedMs()
321
+ });
322
+ }
323
+ /**
324
+ * Get elapsed time in milliseconds since tracker creation.
325
+ */
326
+ getElapsedMs() {
327
+ return Math.round(performance.now() - this.startTime);
328
+ }
329
+ };
330
+
331
+ //#endregion
332
+ export { AnalyticsService as n, CheckoutTimingTracker as t };
333
+ //# sourceMappingURL=analytics-Blvs2DW7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-Blvs2DW7.mjs","names":[],"sources":["../src/analytics/mock-adapter.ts","../src/analytics/posthog-adapter.ts","../src/analytics/service.ts","../src/analytics/checkout-timing.ts"],"sourcesContent":["import type { AnalyticsAdapter, CapturedEvent } from \"./types\";\n\n/**\n * Mock analytics adapter for testing.\n *\n * Records all captured events for assertion in tests.\n */\nexport class MockAnalyticsAdapter implements AnalyticsAdapter {\n private events: CapturedEvent[] = [];\n private distinctId: string | null = null;\n\n identify(distinctId: string): void {\n this.distinctId = distinctId;\n }\n\n capture(event: string, properties?: Record<string, unknown>): void {\n this.events.push({\n event,\n distinct_id: this.distinctId,\n properties,\n timestamp: Date.now(),\n });\n }\n\n isInitialized(): boolean {\n return true;\n }\n\n // Test helper methods\n\n /**\n * Get all captured events.\n */\n getEvents(): CapturedEvent[] {\n return [...this.events];\n }\n\n /**\n * Get events by name.\n */\n getEventsByName(eventName: string): CapturedEvent[] {\n return this.events.filter((e) => e.event === eventName);\n }\n\n /**\n * Clear all captured events.\n */\n clear(): void {\n this.events = [];\n }\n}\n","import posthog from \"posthog-js\";\nimport type { AnalyticsAdapter } from \"./types\";\n\n// PostHog API key (PaymentKit internal)\nconst POSTHOG_API_KEY = \"phc_u9YDYUeUxo3CYn16XGrrwpVb8ycXgcjz5DarvIKRAAG\";\n\n/**\n * PostHog implementation of the analytics adapter.\n *\n * Singleton stored in window to ensure only one instance exists across\n * all script loads. Configures PostHog to use the reverse proxy at\n * /ingest to avoid ad blockers.\n */\nexport class PostHogAdapter implements AnalyticsAdapter {\n private initialized = false;\n\n /**\n * Get or create the PostHog adapter singleton (stored in window).\n *\n * @param apiBaseUrl - The API base URL for the reverse proxy\n * @throws Error if called with a different apiBaseUrl than the first call\n */\n static getInstance(apiBaseUrl: string): PostHogAdapter {\n if (typeof window === \"undefined\") {\n throw new Error(\"[PaymentKit Analytics] PostHog requires a browser environment\");\n }\n\n const existing = window.__paymentKitPostHog__;\n if (existing) {\n if (existing.apiBaseUrl !== apiBaseUrl) {\n throw new Error(\n `[PaymentKit Analytics] PostHog already initialized with apiBaseUrl \"${existing.apiBaseUrl}\", ` +\n `cannot re-initialize with different apiBaseUrl \"${apiBaseUrl}\"`,\n );\n }\n return existing.instance;\n }\n\n const instance = new PostHogAdapter(apiBaseUrl);\n window.__paymentKitPostHog__ = { instance, apiBaseUrl };\n return instance;\n }\n\n private constructor(apiBaseUrl: string) {\n this.initPostHog(apiBaseUrl);\n }\n\n private initPostHog(apiBaseUrl: string): void {\n try {\n posthog.init(POSTHOG_API_KEY, {\n // Use reverse proxy to avoid ad blockers\n api_host: `${apiBaseUrl}/ingest`,\n // PostHog UI host (for toolbar, if ever needed)\n ui_host: \"https://us.posthog.com\",\n // Memory persistence - no cookies in embedded checkout iframe\n persistence: \"memory\",\n // Disable session recording - not needed for metrics\n disable_session_recording: true,\n // Manual events only - no autocapture\n autocapture: false,\n // Manual pageview control\n capture_pageview: false,\n // Disable batching - send events immediately to avoid data loss on page close\n request_batching: false,\n // Disable bot detection - allows events from automated tests and debugging environments\n // PostHog detects Playwright/headless browsers as bots by default\n opt_out_useragent_filter: true,\n // Callback when PostHog is ready\n loaded: () => {\n this.initialized = true;\n },\n });\n } catch (e) {\n console.warn(\"[PaymentKit Analytics] Failed to initialize PostHog:\", e);\n }\n }\n\n identify(distinctId: string): void {\n try {\n posthog.identify(distinctId);\n } catch (e) {\n // Silent fail - never break checkout\n console.warn(\"[PaymentKit Analytics] Failed to identify:\", e);\n }\n }\n\n capture(event: string, properties?: Record<string, unknown>): void {\n try {\n posthog.capture(event, properties);\n } catch (e) {\n // Silent fail - never break checkout\n console.warn(\"[PaymentKit Analytics] Failed to capture event:\", e);\n }\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n","import { MockAnalyticsAdapter } from \"./mock-adapter\";\nimport { PostHogAdapter } from \"./posthog-adapter\";\nimport type { AnalyticsAdapter } from \"./types\";\n\n/**\n * Analytics service singleton.\n *\n * Provides a global interface for capturing analytics events.\n * Supports multiple adapters that receive all events (composite pattern).\n *\n * Usage:\n * // Initialize (typically done once at SDK init)\n * AnalyticsService.init(\"http://localhost:9000\");\n *\n * // Capture events - broadcasts to all registered adapters\n * AnalyticsService.capture(\"checkout_page_ready\", { session_id: \"...\" });\n *\n * // For testing - add a mock adapter\n * import { MockAnalyticsAdapter } from \"./mock-adapter\";\n * const mock = new MockAnalyticsAdapter();\n * AnalyticsService.addAdapter(mock);\n *\n * // Or use the built-in test mock (exposed globally as window.__paymentKitAnalytics__)\n * AnalyticsService.enableTestMode();\n * // Events can be read via window.__paymentKitAnalytics__.getEvents()\n */\nclass AnalyticsServiceClass {\n private adapters: AnalyticsAdapter[] = [];\n private testMock: MockAnalyticsAdapter | null = null;\n\n /**\n * Initialize the analytics service with PostHog.\n *\n * @param apiBaseUrl - The API base URL for the reverse proxy\n * @param enableTestMode - Enable test mode for capturing events in tests\n */\n init(apiBaseUrl: string, enableTestMode?: boolean): void {\n try {\n // Add PostHog adapter (singleton - safe to call multiple times with same URL)\n this.addAdapter(PostHogAdapter.getInstance(apiBaseUrl));\n\n // Enable test mode if explicitly requested\n if (enableTestMode) {\n this.enableTestMode();\n }\n } catch (e) {\n // Silent fail - analytics should never break checkout\n console.warn(\"[PaymentKit Analytics] Init failed:\", e);\n }\n }\n\n /**\n * Enable test mode by adding a mock adapter and exposing it globally.\n * The mock adapter is accessible via window.__paymentKitAnalytics__\n */\n enableTestMode(): void {\n if (this.testMock) return; // Already enabled\n\n this.testMock = new MockAnalyticsAdapter();\n this.addAdapter(this.testMock);\n\n // Expose globally for Playwright/test access\n if (typeof window !== \"undefined\") {\n window.__paymentKitAnalytics__ = this.testMock;\n }\n }\n\n /**\n * Get the test mock adapter (if test mode is enabled).\n */\n getTestMock(): MockAnalyticsAdapter | null {\n return this.testMock;\n }\n\n /**\n * Add an analytics adapter.\n * Events will be broadcast to all registered adapters.\n * Duplicate adapters (same instance) are ignored.\n *\n * @param adapter - The adapter to add\n */\n addAdapter(adapter: AnalyticsAdapter): void {\n if (!this.adapters.includes(adapter)) {\n this.adapters.push(adapter);\n }\n }\n\n /**\n * Clear all adapters.\n */\n clearAdapters(): void {\n this.adapters = [];\n this.testMock = null;\n if (typeof window !== \"undefined\") {\n delete window.__paymentKitAnalytics__;\n }\n }\n\n /**\n * Set the distinct_id for all adapters.\n * This is used to correlate frontend events with backend events.\n * Should be called with the checkout session secure token.\n */\n identify(distinctId: string): void {\n for (const adapter of this.adapters) {\n try {\n adapter.identify(distinctId);\n } catch {\n // Silent fail - never break checkout\n }\n }\n }\n\n /**\n * Capture an analytics event.\n * Broadcasts to all registered adapters. Silently fails on errors.\n */\n capture(event: string, properties?: Record<string, unknown>): void {\n for (const adapter of this.adapters) {\n try {\n adapter.capture(event, properties);\n } catch {\n // Silent fail - never break checkout\n }\n }\n }\n\n /**\n * Check if any adapter is initialized.\n */\n isInitialized(): boolean {\n return this.adapters.some((adapter) => adapter.isInitialized());\n }\n}\n\n/**\n * Global analytics service instance.\n */\nexport const AnalyticsService = new AnalyticsServiceClass();\n","import { AnalyticsService } from \"./service\";\n\n/**\n * Tracks timing metrics throughout the checkout flow.\n *\n * Create one instance per checkout session and call the track methods\n * at appropriate points in the checkout flow.\n *\n * Usage:\n * const requestId = getOrCreateCheckoutRequestId(environment);\n * const tracker = new CheckoutTimingTracker(secureToken, requestId);\n * tracker.trackPageReady();\n * // ... iframe loads ...\n * tracker.trackInputReady();\n * // ... user submits ...\n * tracker.trackSubmit();\n * // ... API response ...\n * tracker.trackSuccess(attemptId);\n */\nexport class CheckoutTimingTracker {\n // Class-level guard to prevent duplicate page_ready events across PaymentKit instances\n private static pageReadyTracked = false;\n\n private startTime: number;\n private checkoutSessionId: string;\n private requestId: string;\n private inputReadyTracked = false;\n\n constructor(checkoutSessionId: string, requestId: string) {\n this.startTime = performance.now();\n this.checkoutSessionId = checkoutSessionId;\n this.requestId = requestId;\n }\n\n /**\n * Track when SDK is initialized and ready.\n * Call immediately after PaymentKit() initialization.\n * Only tracks once per page load (subsequent calls are no-ops).\n */\n trackPageReady(): void {\n if (CheckoutTimingTracker.pageReadyTracked) return;\n CheckoutTimingTracker.pageReadyTracked = true;\n\n AnalyticsService.capture(\"checkout_page_ready\", {\n checkout_session_id: this.checkoutSessionId,\n request_id: this.requestId,\n elapsed_ms: this.getElapsedMs(),\n });\n }\n\n /**\n * Track when card input iframe is loaded and ready for input.\n * Should only be called once (for first iframe, typically card_pan).\n * Subsequent calls are no-ops.\n */\n trackInputReady(): void {\n if (this.inputReadyTracked) return;\n this.inputReadyTracked = true;\n\n AnalyticsService.capture(\"checkout_input_ready\", {\n checkout_session_id: this.checkoutSessionId,\n request_id: this.requestId,\n elapsed_ms: this.getElapsedMs(),\n });\n }\n\n /**\n * Track when user clicks submit button.\n */\n trackSubmit(): void {\n AnalyticsService.capture(\"checkout_submit\", {\n checkout_session_id: this.checkoutSessionId,\n request_id: this.requestId,\n elapsed_ms: this.getElapsedMs(),\n });\n }\n\n /**\n * Track successful checkout.\n *\n * @param checkoutAttemptId - The checkout attempt ID\n */\n trackSuccess(checkoutAttemptId: string): void {\n AnalyticsService.capture(\"checkout_success\", {\n checkout_session_id: this.checkoutSessionId,\n checkout_attempt_id: checkoutAttemptId,\n request_id: this.requestId,\n total_elapsed_ms: this.getElapsedMs(),\n });\n }\n\n /**\n * Track failed checkout.\n *\n * @param checkoutAttemptId - The checkout attempt ID (may be null if failed early)\n * @param errorCode - The error code from the checkout response\n * @param errorMessage - The customer-facing error message\n */\n trackFail(checkoutAttemptId: string | null, errorCode: string | null, errorMessage: string | null): void {\n AnalyticsService.capture(\"checkout_fail\", {\n checkout_session_id: this.checkoutSessionId,\n checkout_attempt_id: checkoutAttemptId,\n request_id: this.requestId,\n error_code: errorCode,\n error_message: errorMessage,\n total_elapsed_ms: this.getElapsedMs(),\n });\n }\n\n /**\n * Get elapsed time in milliseconds since tracker creation.\n */\n private getElapsedMs(): number {\n return Math.round(performance.now() - this.startTime);\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { r as PaymentMethod } from "./types-CQ8xbgoh.mjs";
1
+ import { r as PaymentMethod } from "./types-B3mjYfOm.mjs";
2
2
 
3
3
  //#region src/payment-methods/bnpl-shared.d.ts
4
4
 
@@ -61,4 +61,4 @@ type BnplProviderConfig = {
61
61
  declare function createBnplPaymentMethod(config: BnplProviderConfig): PaymentMethod<{}, string>;
62
62
  //#endregion
63
63
  export { BnplStartResponse as a, createBnplPaymentMethod as c, BnplStartRequest as i, BnplCustomerInfo as n, BnplStatusResponse as o, BnplProviderConfig as r, BnplSubmitOptions as s, BnplCheckoutResponse as t };
64
- //# sourceMappingURL=bnpl-shared-B-en2sPr.d.mts.map
64
+ //# sourceMappingURL=bnpl-shared-BQwCBD45.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bnpl-shared-B-en2sPr.d.mts","names":[],"sources":["../src/payment-methods/bnpl-shared.ts"],"sourcesContent":[],"mappings":";;;;;;;AAQA;AAMY,KANA,gBAAA,GAMgB;EAWhB,UAAA,EAAA,MAAA;EAMA,SAAA,EAAA,MAAA;EAOA,KAAA,CAAA,EAAA,MAAA;AAaZ,CAAA;AAWY,KAhDA,gBAAA,GAgDkB;EAiKd,YAAA,EAAA,MAAA;iBA/MC;;;;;;;;;;;;KASL,iBAAA;;;;;KAMA,kBAAA;;;;;;KAOA,oBAAA;;;;;;;;;;;;KAaA,iBAAA;;gBAEI;;;KASJ,kBAAA;;;;;iBAiKI,uBAAA,SAAgC,qBAAkB"}
1
+ {"version":3,"file":"bnpl-shared-BQwCBD45.d.mts","names":[],"sources":["../src/payment-methods/bnpl-shared.ts"],"sourcesContent":[],"mappings":";;;;;;;AAQA;AAMY,KANA,gBAAA,GAMgB;EAWhB,UAAA,EAAA,MAAA;EAMA,SAAA,EAAA,MAAA;EAOA,KAAA,CAAA,EAAA,MAAA;AAaZ,CAAA;AAWY,KAhDA,gBAAA,GAgDkB;EAiKd,YAAA,EAAA,MAAA;iBA/MC;;;;;;;;;;;;KASL,iBAAA;;;;;KAMA,kBAAA;;;;;;KAOA,oBAAA;;;;;;;;;;;;KAaA,iBAAA;;gBAEI;;;KASJ,kBAAA;;;;;iBAiKI,uBAAA,SAAgC,qBAAkB"}
@@ -1,4 +1,4 @@
1
- import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "./utils-B70Y8YcZ.mjs";
1
+ import { i as definePaymentMethod, n as collectFraudMetadata, o as getOrCreateCheckoutRequestId } from "./utils-Dc6zwOe1.mjs";
2
2
 
3
3
  //#region src/payment-methods/bnpl-shared.ts
4
4
  const createSubmitPayment = (states, config) => {
@@ -104,4 +104,4 @@ function createBnplPaymentMethod(config) {
104
104
 
105
105
  //#endregion
106
106
  export { createBnplPaymentMethod as t };
107
- //# sourceMappingURL=bnpl-shared-CEAXTL3Q.mjs.map
107
+ //# sourceMappingURL=bnpl-shared-DGs1YzS9.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bnpl-shared-CEAXTL3Q.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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"}
1
+ {"version":3,"file":"bnpl-shared-DGs1YzS9.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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"}