@payment-kit-js/vanilla 0.5.9 → 0.5.10

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 (35) hide show
  1. package/dist/{airwallex-apple-pay-adapter-I_pnNYdy.d.mts → airwallex-apple-pay-adapter-BCYt7Jzc.d.mts} +2 -1
  2. package/dist/airwallex-apple-pay-adapter-BCYt7Jzc.d.mts.map +1 -0
  3. package/dist/{airwallex-apple-pay-adapter-BE15xREr.mjs → airwallex-apple-pay-adapter-BFsoDoSf.mjs} +6 -2
  4. package/dist/airwallex-apple-pay-adapter-BFsoDoSf.mjs.map +1 -0
  5. package/dist/cdn/paymentkit.js +1156 -60
  6. package/dist/cdn/paymentkit.js.map +4 -4
  7. package/dist/cdn/paymentkit.min.js +10 -10
  8. package/dist/cdn/paymentkit.min.js.map +4 -4
  9. package/dist/index.d.mts.map +1 -1
  10. package/dist/index.mjs +7 -1
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/payment-methods/airwallex-apple-pay-adapter.d.mts +1 -1
  13. package/dist/payment-methods/airwallex-apple-pay-adapter.mjs +1 -1
  14. package/dist/payment-methods/apple-pay.d.mts +15 -1
  15. package/dist/payment-methods/apple-pay.d.mts.map +1 -1
  16. package/dist/payment-methods/apple-pay.mjs +45 -13
  17. package/dist/payment-methods/apple-pay.mjs.map +1 -1
  18. package/dist/payment-methods/card.d.mts.map +1 -1
  19. package/dist/payment-methods/card.mjs +115 -20
  20. package/dist/payment-methods/card.mjs.map +1 -1
  21. package/dist/payment-methods/google-pay.d.mts +18 -1
  22. package/dist/payment-methods/google-pay.d.mts.map +1 -1
  23. package/dist/payment-methods/google-pay.mjs +28 -9
  24. package/dist/payment-methods/google-pay.mjs.map +1 -1
  25. package/dist/payment-methods/stripe-google-pay-adapter.d.mts +1 -1
  26. package/dist/payment-methods/stripe-google-pay-adapter.mjs +1 -1
  27. package/dist/{stripe-google-pay-adapter-CqcUEoM3.mjs → stripe-google-pay-adapter-3cx0KNjK.mjs} +7 -2
  28. package/dist/stripe-google-pay-adapter-3cx0KNjK.mjs.map +1 -0
  29. package/dist/{stripe-google-pay-adapter-C3NCBSO3.d.mts → stripe-google-pay-adapter-Bdox4xBq.d.mts} +2 -1
  30. package/dist/stripe-google-pay-adapter-Bdox4xBq.d.mts.map +1 -0
  31. package/package.json +4 -7
  32. package/dist/airwallex-apple-pay-adapter-BE15xREr.mjs.map +0 -1
  33. package/dist/airwallex-apple-pay-adapter-I_pnNYdy.d.mts.map +0 -1
  34. package/dist/stripe-google-pay-adapter-C3NCBSO3.d.mts.map +0 -1
  35. package/dist/stripe-google-pay-adapter-CqcUEoM3.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * PaymentKit.js v0.5.9
2
+ * PaymentKit.js v0.5.10
3
3
  * https://paymentkit.com
4
4
  *
5
5
  * @license MIT
@@ -42,7 +42,7 @@ var PaymentKit = (() => {
42
42
  });
43
43
 
44
44
  // package.json
45
- var version = "0.5.9";
45
+ var version = "0.5.10";
46
46
 
47
47
  // src/analytics/mock-adapter.ts
48
48
  var MockAnalyticsAdapter = class {
@@ -6465,6 +6465,7 @@ var PaymentKit = (() => {
6465
6465
  checkout_token: token,
6466
6466
  api_base_url: apiBaseUrl
6467
6467
  });
6468
+ Object.assign(iframe.style, { width: "0", height: "0", position: "absolute", visibility: "hidden" });
6468
6469
  document.body.appendChild(iframe);
6469
6470
  const connection = connectToTunnelXIframe(iframe, {});
6470
6471
  const unmount = () => {
@@ -6597,9 +6598,214 @@ var PaymentKit = (() => {
6597
6598
  };
6598
6599
  var index_default = PaymentKit;
6599
6600
 
6600
- // src/penpal/connect-card.ts
6601
- var connectToCardIframe = (iframe, methods) => {
6602
- return connectToWindow({ window: iframe.contentWindow, methods });
6601
+ // src/payment-methods/airwallex-apple-pay-adapter.ts
6602
+ var AirwallexApplePayAdapter = class {
6603
+ constructor(mockScenario) {
6604
+ __publicField(this, "config", null);
6605
+ __publicField(this, "mockScenario");
6606
+ this.mockScenario = mockScenario ?? "none" /* None */;
6607
+ }
6608
+ /**
6609
+ * Initialize the adapter with payment configuration.
6610
+ * Returns true if Apple Pay is available on this device.
6611
+ */
6612
+ initialize(config) {
6613
+ if (this.mockScenario !== "none" /* None */) {
6614
+ console.log("[MockApplePay:Airwallex] initialize called (mock mode)");
6615
+ this.config = config;
6616
+ return true;
6617
+ }
6618
+ if (typeof window === "undefined" || !window.ApplePaySession) {
6619
+ console.error("[ApplePay:Airwallex] ApplePaySession not available (not Safari or unsupported device)");
6620
+ return false;
6621
+ }
6622
+ this.config = config;
6623
+ return true;
6624
+ }
6625
+ /**
6626
+ * Check if the user can make a payment with Apple Pay.
6627
+ * Returns true if Apple Pay is set up on this device.
6628
+ */
6629
+ async canMakePayment() {
6630
+ if (this.mockScenario !== "none" /* None */) {
6631
+ console.log("[MockApplePay:Airwallex] canMakePayment: true (mock mode)");
6632
+ return true;
6633
+ }
6634
+ if (!window.ApplePaySession) {
6635
+ return false;
6636
+ }
6637
+ try {
6638
+ const canMake = window.ApplePaySession.canMakePayments();
6639
+ console.log("[ApplePay:Airwallex] canMakePayments:", canMake);
6640
+ return canMake;
6641
+ } catch (error) {
6642
+ console.error("[ApplePay:Airwallex] canMakePayment error:", error);
6643
+ return false;
6644
+ }
6645
+ }
6646
+ /**
6647
+ * Convert atomic units (cents) to display format for Apple Pay.
6648
+ * Apple Pay expects a string like "10.00" for $10.00.
6649
+ */
6650
+ formatAmount(amountAtom, currency) {
6651
+ const zeroDecimalCurrencies = [
6652
+ "BIF",
6653
+ "CLP",
6654
+ "DJF",
6655
+ "GNF",
6656
+ "ISK",
6657
+ "JPY",
6658
+ "KMF",
6659
+ "KRW",
6660
+ "PYG",
6661
+ "RWF",
6662
+ "UGX",
6663
+ "VND",
6664
+ "VUV",
6665
+ "XAF",
6666
+ "XOF",
6667
+ "XPF"
6668
+ ];
6669
+ const isZeroDecimal = zeroDecimalCurrencies.includes(currency.toUpperCase());
6670
+ if (isZeroDecimal) {
6671
+ return amountAtom.toString();
6672
+ }
6673
+ return (amountAtom / 100).toFixed(2);
6674
+ }
6675
+ /**
6676
+ * Show the Apple Pay payment sheet and return the encrypted token.
6677
+ *
6678
+ * This uses the native ApplePaySession API with a two-step flow:
6679
+ * 1. onvalidatemerchant - Called by Apple to validate the merchant
6680
+ * The callback should call our backend which calls Airwallex's payment_session/start
6681
+ * 2. onpaymentauthorized - Called when user authorizes with Face ID/Touch ID
6682
+ * Returns the encrypted token for processing
6683
+ *
6684
+ * @param onMerchantValidation - Callback to validate merchant with backend
6685
+ * @returns Promise with token or error
6686
+ */
6687
+ async showPaymentSheet(onMerchantValidation) {
6688
+ if (this.mockScenario === "success" /* Success */) {
6689
+ console.log("[MockApplePay:Airwallex] showPaymentSheet: returning mock success token");
6690
+ const mockToken = {
6691
+ paymentData: {
6692
+ version: "EC_v1",
6693
+ data: "MOCK_ENCRYPTED_DATA",
6694
+ signature: "MOCK_SIGNATURE",
6695
+ header: {
6696
+ ephemeralPublicKey: "MOCK_PUBLIC_KEY",
6697
+ publicKeyHash: "MOCK_HASH",
6698
+ transactionId: "mock_txn_123"
6699
+ }
6700
+ },
6701
+ paymentMethod: {
6702
+ displayName: "Visa 4242",
6703
+ network: "Visa",
6704
+ type: "debit"
6705
+ },
6706
+ transactionIdentifier: "MOCK_TXN_ID"
6707
+ };
6708
+ return {
6709
+ success: true,
6710
+ token: mockToken,
6711
+ payerEmail: "mock@example.com",
6712
+ complete: (status) => console.log(`[MockApplePay:Airwallex] complete: ${status}`)
6713
+ };
6714
+ }
6715
+ if (this.mockScenario === "cancelled" /* Cancelled */) {
6716
+ console.log("[MockApplePay:Airwallex] showPaymentSheet: returning mock cancelled");
6717
+ return { success: false, cancelled: true };
6718
+ }
6719
+ if (!this.config) {
6720
+ return { success: false, error: "Apple Pay not initialized" };
6721
+ }
6722
+ if (!window.ApplePaySession) {
6723
+ return { success: false, error: "ApplePaySession not available" };
6724
+ }
6725
+ const config = this.config;
6726
+ const amount = this.formatAmount(config.amount, config.currency);
6727
+ const paymentRequest = {
6728
+ countryCode: config.country.toUpperCase(),
6729
+ currencyCode: config.currency.toUpperCase(),
6730
+ supportedNetworks: ["visa", "masterCard", "amex", "discover"],
6731
+ merchantCapabilities: ["supports3DS"],
6732
+ total: {
6733
+ label: config.merchantName || "Total",
6734
+ amount,
6735
+ type: "final"
6736
+ },
6737
+ // Surface the payer's email so the backend can fill missing customer email.
6738
+ requiredBillingContactFields: ["email"]
6739
+ };
6740
+ return new Promise((resolve) => {
6741
+ try {
6742
+ const session = new window.ApplePaySession(3, paymentRequest);
6743
+ const STATUS_SUCCESS = window.ApplePaySession.STATUS_SUCCESS;
6744
+ const STATUS_FAILURE = window.ApplePaySession.STATUS_FAILURE;
6745
+ session.onvalidatemerchant = async (event) => {
6746
+ console.log("[ApplePay:Airwallex] onvalidatemerchant called", event.validationURL);
6747
+ try {
6748
+ const validationResult = await onMerchantValidation(event.validationURL);
6749
+ if (validationResult.error || !validationResult.merchantSession) {
6750
+ console.error("[ApplePay:Airwallex] Merchant validation failed:", validationResult.error);
6751
+ session.abort();
6752
+ resolve({
6753
+ success: false,
6754
+ error: validationResult.error || "Merchant validation failed"
6755
+ });
6756
+ return;
6757
+ }
6758
+ session.completeMerchantValidation(validationResult.merchantSession);
6759
+ console.log("[ApplePay:Airwallex] Merchant validation completed");
6760
+ } catch (error) {
6761
+ console.error("[ApplePay:Airwallex] Merchant validation error:", error);
6762
+ session.abort();
6763
+ resolve({
6764
+ success: false,
6765
+ error: `Merchant validation error: ${error}`
6766
+ });
6767
+ }
6768
+ };
6769
+ session.onpaymentauthorized = (event) => {
6770
+ console.log("[ApplePay:Airwallex] onpaymentauthorized called");
6771
+ const payment = event.payment;
6772
+ const token = {
6773
+ paymentData: payment.token.paymentData,
6774
+ paymentMethod: {
6775
+ displayName: payment.token.paymentMethod.displayName,
6776
+ network: payment.token.paymentMethod.network,
6777
+ type: payment.token.paymentMethod.type
6778
+ },
6779
+ transactionIdentifier: payment.token.transactionIdentifier
6780
+ };
6781
+ const payerEmail = payment.billingContact?.emailAddress ?? payment.shippingContact?.emailAddress ?? void 0;
6782
+ const complete = (status) => {
6783
+ console.log("[ApplePay:Airwallex] completing session with status:", status);
6784
+ const appleStatus = status === "success" ? STATUS_SUCCESS : STATUS_FAILURE;
6785
+ session.completePayment({ status: appleStatus });
6786
+ };
6787
+ resolve({
6788
+ success: true,
6789
+ token,
6790
+ payerEmail,
6791
+ complete
6792
+ });
6793
+ };
6794
+ session.oncancel = () => {
6795
+ console.log("[ApplePay:Airwallex] oncancel - user cancelled");
6796
+ resolve({ success: false, cancelled: true });
6797
+ };
6798
+ console.log("[ApplePay:Airwallex] Starting Apple Pay session");
6799
+ session.begin();
6800
+ } catch (error) {
6801
+ console.error("[ApplePay:Airwallex] Session creation error:", error);
6802
+ resolve({
6803
+ success: false,
6804
+ error: `Failed to create Apple Pay session: ${error}`
6805
+ });
6806
+ }
6807
+ });
6808
+ }
6603
6809
  };
6604
6810
 
6605
6811
  // src/utils/3ds-iframe-modal.ts
@@ -6812,6 +7018,778 @@ var PaymentKit = (() => {
6812
7018
  }
6813
7019
  };
6814
7020
 
7021
+ // src/payment-methods/stripe-apple-pay-adapter.ts
7022
+ var StripeApplePayAdapter = class {
7023
+ constructor(mockScenario) {
7024
+ __publicField(this, "stripe", null);
7025
+ __publicField(this, "mockScenario");
7026
+ __publicField(this, "preparedPaymentRequest", null);
7027
+ this.mockScenario = mockScenario ?? "none" /* None */;
7028
+ }
7029
+ initialize(publishableKey) {
7030
+ switch (this.mockScenario) {
7031
+ case "none" /* None */: {
7032
+ console.log("[ApplePay] initialize called");
7033
+ if (!window.Stripe) {
7034
+ console.log("[ApplePay] Stripe.js not loaded");
7035
+ return false;
7036
+ }
7037
+ this.stripe = window.Stripe(publishableKey);
7038
+ const success = this.stripe !== null;
7039
+ console.log("[ApplePay] initialize result:", success);
7040
+ return success;
7041
+ }
7042
+ case "success" /* Success */:
7043
+ case "cancelled" /* Cancelled */: {
7044
+ console.log("[MockApplePay] initialize called");
7045
+ console.log("[MockApplePay] initialize result:", true);
7046
+ return true;
7047
+ }
7048
+ }
7049
+ }
7050
+ /**
7051
+ * Check if Apple Pay is available on this device/browser.
7052
+ * Uses Stripe's PaymentRequest.canMakePayment() which is more reliable
7053
+ * than checking ApplePaySession directly.
7054
+ */
7055
+ static isAvailable() {
7056
+ if (typeof window === "undefined" || !window.ApplePaySession) {
7057
+ console.log("[ApplePay] ApplePaySession not available");
7058
+ return false;
7059
+ }
7060
+ const canMakePayments = window.ApplePaySession.canMakePayments();
7061
+ console.log("[ApplePay] canMakePayments:", canMakePayments);
7062
+ return canMakePayments;
7063
+ }
7064
+ /**
7065
+ * Check availability using Stripe's PaymentRequest API.
7066
+ * This is more accurate as it checks Stripe's configuration too.
7067
+ */
7068
+ async canMakePayment() {
7069
+ if (!this.stripe) {
7070
+ console.log("[ApplePay] Stripe not initialized");
7071
+ return null;
7072
+ }
7073
+ const pr2 = this.stripe.paymentRequest({
7074
+ country: "US",
7075
+ currency: "usd",
7076
+ total: { label: "Check", amount: 100 }
7077
+ });
7078
+ const result = await pr2.canMakePayment();
7079
+ console.log("[ApplePay] canMakePayment result:", result);
7080
+ if (!result) {
7081
+ return null;
7082
+ }
7083
+ return {
7084
+ applePay: result.applePay ?? false,
7085
+ googlePay: result.googlePay ?? false
7086
+ };
7087
+ }
7088
+ /**
7089
+ * Prepare a PaymentRequest for later use. Call this BEFORE the user clicks.
7090
+ * This creates the PaymentRequest and calls canMakePayment() to validate.
7091
+ *
7092
+ * @returns Promise with success status and whether Apple Pay is available
7093
+ */
7094
+ async preparePaymentRequest(config) {
7095
+ if (this.mockScenario !== "none" /* None */) {
7096
+ console.log("[MockApplePay] preparePaymentRequest called");
7097
+ this.preparedConfig = config;
7098
+ return { success: true, applePay: true, googlePay: false };
7099
+ }
7100
+ console.log("[ApplePay] preparePaymentRequest called", config);
7101
+ if (!this.stripe) {
7102
+ return { success: false, error: "Stripe not initialized" };
7103
+ }
7104
+ const paymentRequest = this.stripe.paymentRequest({
7105
+ country: config.country,
7106
+ currency: config.currency.toLowerCase(),
7107
+ total: {
7108
+ label: config.total.label,
7109
+ amount: config.total.amount
7110
+ },
7111
+ requestPayerName: true,
7112
+ requestPayerEmail: true
7113
+ });
7114
+ const canMakePaymentResult = await paymentRequest.canMakePayment();
7115
+ console.log("[ApplePay] preparePaymentRequest canMakePayment:", canMakePaymentResult);
7116
+ if (!canMakePaymentResult) {
7117
+ return {
7118
+ success: false,
7119
+ error: "Payment methods not available on this device/browser",
7120
+ applePay: false,
7121
+ googlePay: false
7122
+ };
7123
+ }
7124
+ this.preparedPaymentRequest = paymentRequest;
7125
+ this.preparedConfig = config;
7126
+ return {
7127
+ success: true,
7128
+ applePay: canMakePaymentResult.applePay ?? false,
7129
+ googlePay: canMakePaymentResult.googlePay ?? false
7130
+ };
7131
+ }
7132
+ /**
7133
+ * Check if a PaymentRequest has been prepared and is ready to show.
7134
+ */
7135
+ isPrepared() {
7136
+ return this.preparedPaymentRequest !== null || this.mockScenario !== "none" /* None */;
7137
+ }
7138
+ /**
7139
+ * Clear the prepared PaymentRequest.
7140
+ */
7141
+ clearPrepared() {
7142
+ this.preparedPaymentRequest = null;
7143
+ this.preparedConfig = null;
7144
+ }
7145
+ /**
7146
+ * Show the prepared Apple Pay payment sheet.
7147
+ * MUST be called synchronously from a user click handler.
7148
+ * Call preparePaymentRequest() before the click to set up the PaymentRequest.
7149
+ */
7150
+ showPreparedPaymentSheet() {
7151
+ switch (this.mockScenario) {
7152
+ case "none" /* None */: {
7153
+ console.log("[ApplePay] showPreparedPaymentSheet called");
7154
+ if (!this.preparedPaymentRequest) {
7155
+ console.error("[ApplePay] No prepared PaymentRequest! Call preparePaymentRequest() first.");
7156
+ return Promise.resolve({
7157
+ success: false,
7158
+ error: "PaymentRequest not prepared. Call preparePaymentRequest() before showing the sheet."
7159
+ });
7160
+ }
7161
+ const paymentRequest = this.preparedPaymentRequest;
7162
+ return new Promise((resolve) => {
7163
+ paymentRequest.on("paymentmethod", (evt) => {
7164
+ console.log("[ApplePay] paymentmethod event received", {
7165
+ paymentMethodId: evt.paymentMethod.id,
7166
+ payerEmail: evt.payerEmail,
7167
+ payerName: evt.payerName
7168
+ });
7169
+ this.preparedPaymentRequest = null;
7170
+ resolve({
7171
+ success: true,
7172
+ paymentMethodId: evt.paymentMethod.id,
7173
+ paymentMethodEvent: evt,
7174
+ billingDetails: {
7175
+ email: evt.payerEmail ?? void 0,
7176
+ name: evt.payerName ?? void 0,
7177
+ address: evt.paymentMethod.billing_details?.address ?? void 0
7178
+ }
7179
+ });
7180
+ });
7181
+ paymentRequest.on("cancel", () => {
7182
+ console.log("[ApplePay] cancel event - user cancelled");
7183
+ this.preparedPaymentRequest = null;
7184
+ resolve({ success: false, cancelled: true });
7185
+ });
7186
+ console.log("[ApplePay] showing payment sheet");
7187
+ paymentRequest.show();
7188
+ });
7189
+ }
7190
+ case "success" /* Success */: {
7191
+ console.log("[MockApplePay] showPreparedPaymentSheet: success");
7192
+ return new Promise((resolve) => {
7193
+ setTimeout(() => {
7194
+ resolve({
7195
+ success: true,
7196
+ paymentMethodId: "pm_mock_apple_pay_test",
7197
+ paymentMethodEvent: {
7198
+ complete: (status) => console.log(`[MockApplePay] complete: ${status}`),
7199
+ paymentMethod: {
7200
+ id: "pm_mock_apple_pay_test",
7201
+ object: "payment_method",
7202
+ type: "card",
7203
+ card: {
7204
+ brand: "visa",
7205
+ last4: "4242",
7206
+ exp_month: 12,
7207
+ exp_year: 2030
7208
+ },
7209
+ billing_details: {
7210
+ email: "test@example.com",
7211
+ name: "Test User"
7212
+ }
7213
+ },
7214
+ payerEmail: "test@example.com",
7215
+ payerName: "Test User"
7216
+ },
7217
+ billingDetails: {
7218
+ email: "test@example.com",
7219
+ name: "Test User"
7220
+ }
7221
+ });
7222
+ }, 500);
7223
+ });
7224
+ }
7225
+ case "cancelled" /* Cancelled */: {
7226
+ console.log("[MockApplePay] showPreparedPaymentSheet: cancelled");
7227
+ return new Promise((resolve) => {
7228
+ setTimeout(() => {
7229
+ resolve({ success: false, cancelled: true });
7230
+ }, 500);
7231
+ });
7232
+ }
7233
+ }
7234
+ }
7235
+ /**
7236
+ * @deprecated Use preparePaymentRequest() + showPreparedPaymentSheet() instead.
7237
+ * This method creates a new PaymentRequest and shows it, which doesn't work
7238
+ * with browser security requirements (show() must be called synchronously).
7239
+ */
7240
+ async showPaymentSheet(config) {
7241
+ console.warn(
7242
+ "[ApplePay] showPaymentSheet is deprecated. Use preparePaymentRequest() + showPreparedPaymentSheet() instead."
7243
+ );
7244
+ const prepareResult = await this.preparePaymentRequest(config);
7245
+ if (!prepareResult.success) {
7246
+ return { success: false, error: prepareResult.error ?? "Failed to prepare payment request" };
7247
+ }
7248
+ return this.showPreparedPaymentSheet();
7249
+ }
7250
+ /**
7251
+ * Complete the payment flow in the Apple Pay sheet.
7252
+ * Call this after confirming the payment on the server.
7253
+ *
7254
+ * @param evt - The PaymentRequestPaymentMethodEvent from showPaymentSheet
7255
+ * @param status - 'success' or 'fail'
7256
+ */
7257
+ completePayment(evt, status) {
7258
+ console.log("[ApplePay] completePayment:", status);
7259
+ evt.complete(status);
7260
+ }
7261
+ /**
7262
+ * Confirm PaymentIntent with the PaymentMethod.
7263
+ * This is called after showPaymentSheet to finalize the payment.
7264
+ *
7265
+ * @deprecated - Server-side confirmation is preferred. The backend should
7266
+ * call stripe.PaymentIntent.confirm() with the payment_method_id.
7267
+ */
7268
+ async confirmPaymentIntent(clientSecret, paymentMethodId) {
7269
+ switch (this.mockScenario) {
7270
+ case "none" /* None */: {
7271
+ console.log("[ApplePay] confirmPaymentIntent called", {
7272
+ clientSecret: `${clientSecret.slice(0, 20)}...`,
7273
+ paymentMethodId
7274
+ });
7275
+ if (!this.stripe) {
7276
+ console.log("[ApplePay] confirmPaymentIntent: Stripe not initialized");
7277
+ return { success: false, error: "Stripe not initialized" };
7278
+ }
7279
+ const { error } = await this.stripe.confirmCardPayment(clientSecret, {
7280
+ payment_method: paymentMethodId
7281
+ });
7282
+ if (error) {
7283
+ console.log("[ApplePay] confirmPaymentIntent error:", error);
7284
+ return { success: false, error: error.message ?? "Payment failed" };
7285
+ }
7286
+ console.log("[ApplePay] confirmPaymentIntent success");
7287
+ return { success: true };
7288
+ }
7289
+ case "success" /* Success */: {
7290
+ console.log("[MockApplePay] confirmPaymentIntent called", { clientSecret, paymentMethodId });
7291
+ return { success: true };
7292
+ }
7293
+ case "cancelled" /* Cancelled */: {
7294
+ throw new Error("confirmPaymentIntent should not be called when scenario is Cancelled");
7295
+ }
7296
+ }
7297
+ }
7298
+ };
7299
+
7300
+ // src/payment-methods/apple-pay.ts
7301
+ var preparedStripeState = null;
7302
+ async function apiCall(url, options, checkoutRequestId) {
7303
+ const headers = new Headers(options.headers);
7304
+ if (checkoutRequestId) {
7305
+ headers.set("x-request-id", checkoutRequestId);
7306
+ }
7307
+ const response = await fetch(url, { ...options, headers });
7308
+ if (!response.ok) {
7309
+ let errorMessage = `Request failed (${response.status})`;
7310
+ try {
7311
+ const errorData = await response.json();
7312
+ errorMessage = errorData.detail || errorMessage;
7313
+ } catch {
7314
+ errorMessage = response.statusText || errorMessage;
7315
+ }
7316
+ return { error: errorMessage };
7317
+ }
7318
+ return { data: await response.json() };
7319
+ }
7320
+ function validateOptions(options) {
7321
+ if (!options?.processorId) {
7322
+ return { processor_id: "Processor ID is required" };
7323
+ }
7324
+ return null;
7325
+ }
7326
+ function getMockScenarioStr(mockScenario) {
7327
+ return mockScenario && mockScenario !== "none" /* None */ ? mockScenario : void 0;
7328
+ }
7329
+ async function callStripeStartEndpoint(apiBaseUrl, secureToken, options, mockScenarioStr, checkoutRequestId) {
7330
+ return apiCall(
7331
+ `${apiBaseUrl}/api/checkout/${secureToken}/apple-pay/start`,
7332
+ {
7333
+ method: "POST",
7334
+ headers: { "Content-Type": "application/json" },
7335
+ body: JSON.stringify({
7336
+ processor_id: options.processorId,
7337
+ customer_info: options.customerInfo,
7338
+ fraud_metadata: collectFraudMetadata(),
7339
+ mock_scenario: mockScenarioStr
7340
+ })
7341
+ },
7342
+ checkoutRequestId
7343
+ );
7344
+ }
7345
+ function initializeStripeAdapter(stripePk, mockScenario) {
7346
+ const adapter = new StripeApplePayAdapter(mockScenario);
7347
+ if (!adapter.initialize(stripePk)) {
7348
+ return { error: 'Stripe.js not loaded. Add <script src="https://js.stripe.com/v3/"><\/script> to your page.' };
7349
+ }
7350
+ return { adapter };
7351
+ }
7352
+ async function callStripeConfirmEndpoint(apiBaseUrl, secureToken, paymentMethodId, mockScenarioStr, checkoutRequestId, payerEmail) {
7353
+ const result = await apiCall(
7354
+ `${apiBaseUrl}/api/checkout/${secureToken}/apple-pay/confirm`,
7355
+ {
7356
+ method: "POST",
7357
+ headers: { "Content-Type": "application/json" },
7358
+ body: JSON.stringify({
7359
+ payment_method_id: paymentMethodId,
7360
+ payer_email: payerEmail,
7361
+ mock_scenario: mockScenarioStr
7362
+ })
7363
+ },
7364
+ checkoutRequestId
7365
+ );
7366
+ if (result.error || !result.data) {
7367
+ return { errors: { apple_pay: result.error || "Failed to confirm payment" } };
7368
+ }
7369
+ const confirmData = result.data;
7370
+ if (confirmData.charge_status === "success") {
7371
+ return {
7372
+ data: {
7373
+ id: confirmData.transaction_id,
7374
+ checkoutAttemptId: confirmData.checkout_attempt_id,
7375
+ checkoutSessionId: confirmData.checkout_session_id ?? secureToken,
7376
+ state: "checkout_succeeded",
7377
+ paymentIntentId: confirmData.payment_intent_id,
7378
+ customerId: confirmData.customer_id,
7379
+ paymentMethodId: confirmData.payment_method_id,
7380
+ processorUsed: confirmData.processor_used,
7381
+ subscriptionId: confirmData.subscription_id,
7382
+ invoiceId: confirmData.invoice_id,
7383
+ invoiceNumber: confirmData.invoice_number,
7384
+ cardBrand: confirmData.card_brand,
7385
+ cardLast4: confirmData.card_last4,
7386
+ cardExpMonth: confirmData.card_exp_month,
7387
+ cardExpYear: confirmData.card_exp_year,
7388
+ errorCode: confirmData.error_code,
7389
+ errorMessageForCustomer: confirmData.error_message_for_customer,
7390
+ errorMessageForDebug: confirmData.error_message_for_debug,
7391
+ nextAction: confirmData.next_action
7392
+ }
7393
+ };
7394
+ }
7395
+ return {
7396
+ errors: {
7397
+ apple_pay: confirmData.error_message_for_customer || confirmData.error_message_for_debug || "Payment failed"
7398
+ }
7399
+ };
7400
+ }
7401
+ async function prepareApplePay(apiBaseUrl, secureToken, options, environment) {
7402
+ console.log("[ApplePay] prepareApplePay called");
7403
+ preparedStripeState = null;
7404
+ const mockScenarioStr = getMockScenarioStr(options.mockScenario);
7405
+ const checkoutRequestId = getOrCreateCheckoutRequestId(environment);
7406
+ console.log(`[ApplePay] Using checkout_request_id: ${checkoutRequestId}`);
7407
+ if (options.processorType === "airwallex") {
7408
+ console.log("[ApplePay] Airwallex processor - will use native ApplePaySession on submit");
7409
+ return { success: true, applePay: true };
7410
+ }
7411
+ const startResult = await callStripeStartEndpoint(
7412
+ apiBaseUrl,
7413
+ secureToken,
7414
+ options,
7415
+ mockScenarioStr,
7416
+ checkoutRequestId
7417
+ );
7418
+ if (startResult.error || !startResult.data) {
7419
+ return { success: false, error: startResult.error || "Failed to start Apple Pay" };
7420
+ }
7421
+ const startData = startResult.data;
7422
+ if (!startData.stripe_pk) {
7423
+ return { success: false, error: "Stripe publishable key not provided" };
7424
+ }
7425
+ const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, options.mockScenario);
7426
+ if (!adapter) {
7427
+ return { success: false, error: adapterError };
7428
+ }
7429
+ const prepareResult = await adapter.preparePaymentRequest({
7430
+ country: startData.country,
7431
+ currency: startData.currency.toLowerCase(),
7432
+ total: {
7433
+ label: "Total",
7434
+ amount: startData.amount
7435
+ }
7436
+ });
7437
+ if (!prepareResult.success) {
7438
+ return {
7439
+ success: false,
7440
+ error: prepareResult.error || "Failed to prepare payment request",
7441
+ applePay: prepareResult.applePay
7442
+ };
7443
+ }
7444
+ if (!prepareResult.applePay) {
7445
+ return {
7446
+ success: false,
7447
+ error: "Apple Pay is not available on this device or Stripe account",
7448
+ applePay: false
7449
+ };
7450
+ }
7451
+ preparedStripeState = {
7452
+ processor: "stripe",
7453
+ adapter,
7454
+ startData,
7455
+ mockScenarioStr,
7456
+ checkoutRequestId
7457
+ };
7458
+ console.log("[ApplePay] prepareApplePay success (Stripe), ready for click");
7459
+ return { success: true, applePay: true };
7460
+ }
7461
+ function clearPreparedApplePay() {
7462
+ if (preparedStripeState) {
7463
+ preparedStripeState.adapter.clearPrepared();
7464
+ }
7465
+ preparedStripeState = null;
7466
+ }
7467
+ async function callAirwallexStartEndpoint(apiBaseUrl, secureToken, options, validationUrl, initiativeContext, mockScenarioStr, checkoutRequestId) {
7468
+ return apiCall(
7469
+ `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/start`,
7470
+ {
7471
+ method: "POST",
7472
+ headers: { "Content-Type": "application/json" },
7473
+ body: JSON.stringify({
7474
+ processor_id: options.processorId,
7475
+ customer_info: options.customerInfo,
7476
+ fraud_metadata: collectFraudMetadata(),
7477
+ validation_url: validationUrl,
7478
+ initiative_context: initiativeContext,
7479
+ mock_scenario: mockScenarioStr
7480
+ })
7481
+ },
7482
+ checkoutRequestId
7483
+ );
7484
+ }
7485
+ async function callAirwallexConfirmEndpoint(apiBaseUrl, secureToken, applePayToken, mockScenarioStr, checkoutRequestId, payerEmail) {
7486
+ const result = await apiCall(
7487
+ `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/confirm`,
7488
+ {
7489
+ method: "POST",
7490
+ headers: { "Content-Type": "application/json" },
7491
+ body: JSON.stringify({
7492
+ apple_pay_token: applePayToken,
7493
+ payer_email: payerEmail,
7494
+ mock_scenario: mockScenarioStr
7495
+ })
7496
+ },
7497
+ checkoutRequestId
7498
+ );
7499
+ if (result.error || !result.data) {
7500
+ return {
7501
+ charge_status: "fail",
7502
+ error_message_for_debug: result.error || "Failed to confirm payment",
7503
+ checkout_attempt_id: ""
7504
+ };
7505
+ }
7506
+ return result.data;
7507
+ }
7508
+ async function callAirwallexVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId) {
7509
+ const result = await apiCall(
7510
+ `${apiBaseUrl}/api/checkout/${secureToken}/airwallex/apple-pay/verify`,
7511
+ {
7512
+ method: "POST",
7513
+ headers: { "Content-Type": "application/json" }
7514
+ },
7515
+ checkoutRequestId
7516
+ );
7517
+ if (result.error || !result.data) {
7518
+ return {
7519
+ charge_status: "fail",
7520
+ error_message_for_debug: result.error || "Failed to verify payment",
7521
+ checkout_attempt_id: ""
7522
+ };
7523
+ }
7524
+ return result.data;
7525
+ }
7526
+ function toApplePayResult(response, secureToken) {
7527
+ if (response.charge_status === "success") {
7528
+ return {
7529
+ data: {
7530
+ id: response.transaction_id,
7531
+ checkoutAttemptId: response.checkout_attempt_id,
7532
+ checkoutSessionId: response.checkout_session_id ?? secureToken,
7533
+ state: "checkout_succeeded",
7534
+ paymentIntentId: response.payment_intent_id,
7535
+ customerId: response.customer_id,
7536
+ paymentMethodId: response.payment_method_id,
7537
+ processorUsed: response.processor_used,
7538
+ subscriptionId: response.subscription_id,
7539
+ invoiceId: response.invoice_id,
7540
+ invoiceNumber: response.invoice_number,
7541
+ cardBrand: response.card_brand,
7542
+ cardLast4: response.card_last4,
7543
+ cardExpMonth: response.card_exp_month,
7544
+ cardExpYear: response.card_exp_year,
7545
+ errorCode: response.error_code,
7546
+ errorMessageForCustomer: response.error_message_for_customer,
7547
+ errorMessageForDebug: response.error_message_for_debug,
7548
+ nextAction: response.next_action
7549
+ }
7550
+ };
7551
+ }
7552
+ return {
7553
+ errors: {
7554
+ apple_pay: response.error_message_for_customer || response.error_message_for_debug || "Payment failed"
7555
+ }
7556
+ };
7557
+ }
7558
+ var MAX_USER_ACTIONS = 5;
7559
+ async function runAirwallexFlow(apiBaseUrl, secureToken, options, mockScenarioStr, checkoutRequestId) {
7560
+ let airwallexMockScenario = "none" /* None */;
7561
+ if (options.mockScenario === "success" /* Success */) {
7562
+ airwallexMockScenario = "success" /* Success */;
7563
+ } else if (options.mockScenario === "cancelled" /* Cancelled */) {
7564
+ airwallexMockScenario = "cancelled" /* Cancelled */;
7565
+ }
7566
+ const adapter = new AirwallexApplePayAdapter(airwallexMockScenario);
7567
+ const config = {
7568
+ amount: options.amount || 0,
7569
+ currency: (options.currency || "USD").toUpperCase(),
7570
+ country: options.country.toUpperCase(),
7571
+ merchantName: options.merchantName || "Total"
7572
+ };
7573
+ if (!adapter.initialize(config)) {
7574
+ return { errors: { apple_pay: "Apple Pay not available on this device (requires Safari)" } };
7575
+ }
7576
+ const canPay = await adapter.canMakePayment();
7577
+ if (!canPay) {
7578
+ return { errors: { apple_pay: "Apple Pay not available on this device" } };
7579
+ }
7580
+ const initiativeContext = typeof window !== "undefined" ? window.location.hostname : "";
7581
+ if (airwallexMockScenario !== "none" /* None */) {
7582
+ const startResult = await callAirwallexStartEndpoint(
7583
+ apiBaseUrl,
7584
+ secureToken,
7585
+ options,
7586
+ "https://mock-apple-pay-gateway.example.com/paymentservices/startSession",
7587
+ initiativeContext,
7588
+ mockScenarioStr,
7589
+ checkoutRequestId
7590
+ );
7591
+ if (startResult.error || !startResult.data) {
7592
+ return { errors: { apple_pay: startResult.error || "Failed to start mock checkout" } };
7593
+ }
7594
+ }
7595
+ const paymentResult = await adapter.showPaymentSheet(async (validationUrl) => {
7596
+ const startResult = await callAirwallexStartEndpoint(
7597
+ apiBaseUrl,
7598
+ secureToken,
7599
+ options,
7600
+ validationUrl,
7601
+ initiativeContext,
7602
+ mockScenarioStr,
7603
+ checkoutRequestId
7604
+ );
7605
+ if (startResult.error || !startResult.data) {
7606
+ return { error: startResult.error || "Merchant validation failed" };
7607
+ }
7608
+ if (!startResult.data.merchant_session) {
7609
+ return { error: "No merchant session returned from server" };
7610
+ }
7611
+ return { merchantSession: startResult.data.merchant_session };
7612
+ });
7613
+ if (!paymentResult.success) {
7614
+ if ("cancelled" in paymentResult && paymentResult.cancelled) {
7615
+ return { errors: { apple_pay: "Apple Pay cancelled by user" } };
7616
+ }
7617
+ return { errors: { apple_pay: paymentResult.error || "Apple Pay failed" } };
7618
+ }
7619
+ const { token, complete, payerEmail } = paymentResult;
7620
+ let response = await callAirwallexConfirmEndpoint(
7621
+ apiBaseUrl,
7622
+ secureToken,
7623
+ token,
7624
+ mockScenarioStr,
7625
+ checkoutRequestId,
7626
+ payerEmail
7627
+ );
7628
+ let userActionCount = 0;
7629
+ while (response.charge_status === "pending" && response.next_action && userActionCount < MAX_USER_ACTIONS) {
7630
+ userActionCount++;
7631
+ const nextAction = response.next_action;
7632
+ const actionResult = await handleNextAction({ type: nextAction.type, url: nextAction.url });
7633
+ const verifyResponse = await callAirwallexVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);
7634
+ if (verifyResponse.charge_status === "pending" && verifyResponse.next_action) {
7635
+ if (!actionResult.success) {
7636
+ console.log("[ApplePay:Airwallex] 3DS failed but retry available, continuing loop...");
7637
+ }
7638
+ response = verifyResponse;
7639
+ continue;
7640
+ }
7641
+ if (!actionResult.success) {
7642
+ complete("fail");
7643
+ return {
7644
+ errors: {
7645
+ apple_pay: verifyResponse.error_message_for_customer || verifyResponse.error_message_for_debug || actionResult.error || "3DS authentication failed"
7646
+ }
7647
+ };
7648
+ }
7649
+ complete(verifyResponse.charge_status === "success" ? "success" : "fail");
7650
+ return toApplePayResult(verifyResponse, secureToken);
7651
+ }
7652
+ if (userActionCount >= MAX_USER_ACTIONS) {
7653
+ complete("fail");
7654
+ return { errors: { apple_pay: "Too many authentication attempts. Please try again." } };
7655
+ }
7656
+ complete(response.charge_status === "success" ? "success" : "fail");
7657
+ return toApplePayResult(response, secureToken);
7658
+ }
7659
+ var defSubmitPayment = (states) => {
7660
+ const submitPayment = async (_fields, options) => {
7661
+ const { apiBaseUrl, secureToken, environment } = states;
7662
+ const applePayOptions = options;
7663
+ const validationError = validateOptions(applePayOptions);
7664
+ if (validationError) {
7665
+ return { errors: validationError };
7666
+ }
7667
+ try {
7668
+ const mockScenarioStr = getMockScenarioStr(applePayOptions.mockScenario);
7669
+ const checkoutRequestId = getOrCreateCheckoutRequestId(environment);
7670
+ console.log(`[ApplePay] Using checkout_request_id: ${checkoutRequestId}`);
7671
+ if (preparedStripeState?.adapter.isPrepared()) {
7672
+ console.log("[ApplePay] Using prepared Stripe state for immediate sheet display");
7673
+ const paymentResultPromise = preparedStripeState.adapter.showPreparedPaymentSheet();
7674
+ const paymentResult2 = await paymentResultPromise;
7675
+ if (!paymentResult2.success) {
7676
+ clearPreparedApplePay();
7677
+ if ("cancelled" in paymentResult2 && paymentResult2.cancelled) {
7678
+ return { errors: { apple_pay: "Apple Pay cancelled by user" } };
7679
+ }
7680
+ const errorMessage = "error" in paymentResult2 ? paymentResult2.error : "Unknown error";
7681
+ return { errors: { apple_pay: errorMessage } };
7682
+ }
7683
+ const { paymentMethodId: paymentMethodId2, paymentMethodEvent: paymentMethodEvent2, billingDetails: billingDetails2 } = paymentResult2;
7684
+ const confirmResult2 = await callStripeConfirmEndpoint(
7685
+ apiBaseUrl,
7686
+ secureToken,
7687
+ paymentMethodId2,
7688
+ mockScenarioStr,
7689
+ preparedStripeState.checkoutRequestId,
7690
+ billingDetails2?.email
7691
+ );
7692
+ if (confirmResult2.data) {
7693
+ paymentMethodEvent2.complete("success");
7694
+ clearPreparedApplePay();
7695
+ return confirmResult2;
7696
+ } else {
7697
+ paymentMethodEvent2.complete("fail");
7698
+ clearPreparedApplePay();
7699
+ return confirmResult2;
7700
+ }
7701
+ }
7702
+ if (applePayOptions.processorType === "airwallex") {
7703
+ console.log("[ApplePay] Running Airwallex flow (processorType=airwallex)");
7704
+ return await runAirwallexFlow(apiBaseUrl, secureToken, applePayOptions, mockScenarioStr, checkoutRequestId);
7705
+ }
7706
+ const startResult = await callStripeStartEndpoint(
7707
+ apiBaseUrl,
7708
+ secureToken,
7709
+ applePayOptions,
7710
+ mockScenarioStr,
7711
+ checkoutRequestId
7712
+ );
7713
+ if (startResult.error || !startResult.data) {
7714
+ return { errors: { apple_pay: startResult.error || "Failed to start Apple Pay" } };
7715
+ }
7716
+ const startData = startResult.data;
7717
+ console.warn("[ApplePay] Stripe flow without prepared state - may fail due to user gesture requirements");
7718
+ if (!startData.stripe_pk) {
7719
+ return { errors: { apple_pay: "Stripe publishable key not provided" } };
7720
+ }
7721
+ const { adapter, error: adapterError } = initializeStripeAdapter(
7722
+ startData.stripe_pk,
7723
+ applePayOptions.mockScenario
7724
+ );
7725
+ if (!adapter) {
7726
+ return { errors: { apple_pay: adapterError || "Failed to initialize Stripe adapter" } };
7727
+ }
7728
+ const prepareResult = await adapter.preparePaymentRequest({
7729
+ country: startData.country,
7730
+ currency: startData.currency.toLowerCase(),
7731
+ total: { label: "Total", amount: startData.amount }
7732
+ });
7733
+ if (!prepareResult.success || !prepareResult.applePay) {
7734
+ return { errors: { apple_pay: prepareResult.error || "Apple Pay not available" } };
7735
+ }
7736
+ const paymentResult = await adapter.showPreparedPaymentSheet();
7737
+ if (!paymentResult.success) {
7738
+ if ("cancelled" in paymentResult && paymentResult.cancelled) {
7739
+ return { errors: { apple_pay: "Apple Pay cancelled by user" } };
7740
+ }
7741
+ const errorMessage = "error" in paymentResult ? paymentResult.error : "Unknown error";
7742
+ return { errors: { apple_pay: errorMessage } };
7743
+ }
7744
+ const { paymentMethodId, paymentMethodEvent, billingDetails } = paymentResult;
7745
+ const confirmResult = await callStripeConfirmEndpoint(
7746
+ apiBaseUrl,
7747
+ secureToken,
7748
+ paymentMethodId,
7749
+ mockScenarioStr,
7750
+ checkoutRequestId,
7751
+ billingDetails?.email
7752
+ );
7753
+ if (confirmResult.data) {
7754
+ paymentMethodEvent.complete("success");
7755
+ return confirmResult;
7756
+ } else {
7757
+ paymentMethodEvent.complete("fail");
7758
+ return confirmResult;
7759
+ }
7760
+ } catch (error) {
7761
+ clearPreparedApplePay();
7762
+ return { errors: { apple_pay: `Apple Pay error: ${error}` } };
7763
+ }
7764
+ };
7765
+ return submitPayment;
7766
+ };
7767
+ var ApplePayPaymentMethod = definePaymentMethod((paymentKitStates) => {
7768
+ return {
7769
+ name: "apple_pay",
7770
+ externalFuncs: {
7771
+ prepareApplePay: (options) => prepareApplePay(
7772
+ paymentKitStates.apiBaseUrl,
7773
+ paymentKitStates.secureToken,
7774
+ options,
7775
+ paymentKitStates.environment
7776
+ )
7777
+ },
7778
+ internalFuncs: {
7779
+ submitPayment: defSubmitPayment(paymentKitStates),
7780
+ cleanup: () => {
7781
+ clearPreparedApplePay();
7782
+ }
7783
+ }
7784
+ };
7785
+ });
7786
+ var apple_pay_default = ApplePayPaymentMethod;
7787
+
7788
+ // src/penpal/connect-card.ts
7789
+ var connectToCardIframe = (iframe, methods) => {
7790
+ return connectToWindow({ window: iframe.contentWindow, methods });
7791
+ };
7792
+
6815
7793
  // src/payment-methods/vgs-collect-loader.ts
6816
7794
  var VGS_COLLECT_CDN = "https://js.verygoodvault.com/vgs-collect/3.2.1/vgs-collect.js";
6817
7795
  var loadPromise = null;
@@ -7082,9 +8060,15 @@ var PaymentKit = (() => {
7082
8060
  }
7083
8061
  cleanupVgs = () => {
7084
8062
  if (type === "card_pan" && states.vgsForm) {
7085
- states.vgsFieldsCleanup?.();
8063
+ try {
8064
+ states.vgsFieldsCleanup?.();
8065
+ } catch {
8066
+ }
7086
8067
  states.vgsFieldsCleanup = void 0;
7087
- states.vgsForm.unmount();
8068
+ try {
8069
+ states.vgsForm.unmount();
8070
+ } catch {
8071
+ }
7088
8072
  states.vgsForm = void 0;
7089
8073
  }
7090
8074
  };
@@ -7118,7 +8102,10 @@ var PaymentKit = (() => {
7118
8102
  cleanupDirect = () => {
7119
8103
  const connection = cardInputConnections[type];
7120
8104
  connection?.destroy();
7121
- parent.removeChild(iframe);
8105
+ try {
8106
+ parent.removeChild(iframe);
8107
+ } catch {
8108
+ }
7122
8109
  states.cardInputConnections[type] = void 0;
7123
8110
  };
7124
8111
  parent.appendChild(iframe);
@@ -7151,7 +8138,7 @@ var PaymentKit = (() => {
7151
8138
  return { mount: mountIFrame };
7152
8139
  };
7153
8140
  };
7154
- var defSubmitPayment = (states) => {
8141
+ var defSubmitPayment2 = (states) => {
7155
8142
  const submitPayment = async (fields, options) => {
7156
8143
  if (states._sessionConfigReady) await states._sessionConfigReady;
7157
8144
  const isVgsMode = states.cardTokenizationMode === "vgs";
@@ -7181,7 +8168,8 @@ var PaymentKit = (() => {
7181
8168
  console.log("[PaymentKit] Submitting card via VGS CMP...");
7182
8169
  const vgsSubmitResult = await submitVgsCardFields(states, tunnelX);
7183
8170
  if (!vgsSubmitResult.isSuccess) {
7184
- timingTracker.trackFail(null, "card_submit_error", "VGS card submission failed");
8171
+ const errorDetail = Object.entries(vgsSubmitResult.errors).map(([k2, v2]) => `${k2}: ${v2}`).join(", ");
8172
+ timingTracker.trackFail(null, "card_submit_error", errorDetail || "VGS card submission failed");
7185
8173
  return { errors: vgsSubmitResult.errors };
7186
8174
  }
7187
8175
  } else {
@@ -7217,11 +8205,11 @@ var PaymentKit = (() => {
7217
8205
  requestOptions
7218
8206
  );
7219
8207
  console.log("Card checkout result:", currentResult);
7220
- const MAX_USER_ACTIONS2 = 5;
8208
+ const MAX_USER_ACTIONS3 = 5;
7221
8209
  let userActionCount = 0;
7222
- while (currentResult.nextAction && userActionCount < MAX_USER_ACTIONS2) {
8210
+ while (currentResult.nextAction && userActionCount < MAX_USER_ACTIONS3) {
7223
8211
  userActionCount++;
7224
- console.log(`Handling user action ${userActionCount}/${MAX_USER_ACTIONS2}...`);
8212
+ console.log(`Handling user action ${userActionCount}/${MAX_USER_ACTIONS3}...`);
7225
8213
  const actionResult = await handleNextAction(currentResult.nextAction);
7226
8214
  console.log("User action completed, verifying checkout...");
7227
8215
  const verifyResult = await tunnelX.publicEndpoints.cardCheckoutVerify(
@@ -7257,7 +8245,7 @@ var PaymentKit = (() => {
7257
8245
  timingTracker.trackSuccess(verifyResult.checkoutAttemptId || "unknown");
7258
8246
  return { data: verifyResult };
7259
8247
  }
7260
- if (userActionCount >= MAX_USER_ACTIONS2) {
8248
+ if (userActionCount >= MAX_USER_ACTIONS3) {
7261
8249
  console.error("Max user actions exceeded");
7262
8250
  timingTracker.trackFail(null, "max_actions_exceeded", "Too many authentication attempts");
7263
8251
  return { errors: { root: "Too many authentication attempts. Please try again." } };
@@ -7293,8 +8281,27 @@ var PaymentKit = (() => {
7293
8281
  const data = await resp.json();
7294
8282
  return data.access_token;
7295
8283
  };
8284
+ var VGS_FIELD_MAP = {
8285
+ // Actual VGS CMP error keys (verified empirically)
8286
+ pan: "card_pan",
8287
+ cvc: "card_cvc",
8288
+ "exp-date": "card_exp",
8289
+ // Alternative key formats (VGS documentation references)
8290
+ "card-number": "card_pan",
8291
+ "card-security-code": "card_cvc",
8292
+ "card-expiration-date": "card_exp"
8293
+ };
8294
+ var stringifyError = (err) => {
8295
+ if (err instanceof Error) return err.message;
8296
+ try {
8297
+ return JSON.stringify(err);
8298
+ } catch {
8299
+ return String(err);
8300
+ }
8301
+ };
7296
8302
  var submitVgsCardFields = async (states, tunnelX) => {
7297
- const { vgsForm, cardSetupIntentId, secureToken, apiBaseUrl } = states;
8303
+ const { vgsForm, cardSetupIntentId, secureToken, apiBaseUrl, checkoutRequestId } = states;
8304
+ const logPrefix = `[PaymentKit] [${checkoutRequestId}]`;
7298
8305
  const errors = {};
7299
8306
  if (!vgsForm) {
7300
8307
  errors.card_pan = "required";
@@ -7304,11 +8311,19 @@ var PaymentKit = (() => {
7304
8311
  errors.root = "Card setup intent not created";
7305
8312
  return { errors, isSuccess: false };
7306
8313
  }
8314
+ let accessToken;
8315
+ try {
8316
+ accessToken = await fetchCollectToken(apiBaseUrl, secureToken);
8317
+ } catch (err) {
8318
+ console.error(`${logPrefix} VGS auth token fetch failed:`, stringifyError(err));
8319
+ errors.root = "Card authentication failed \u2014 please try again";
8320
+ return { errors, isSuccess: false };
8321
+ }
8322
+ let cardResult;
8323
+ const VGS_CREATE_CARD_TIMEOUT_MS = 3e4;
7307
8324
  try {
7308
- const accessToken = await fetchCollectToken(apiBaseUrl, secureToken);
7309
- const VGS_CREATE_CARD_TIMEOUT_MS = 3e4;
7310
8325
  let createCardTimeoutId;
7311
- const cardResult = await Promise.race([
8326
+ cardResult = await Promise.race([
7312
8327
  new Promise((resolve, reject) => {
7313
8328
  vgsForm.createCard(
7314
8329
  {
@@ -7320,34 +8335,76 @@ var PaymentKit = (() => {
7320
8335
  );
7321
8336
  }),
7322
8337
  new Promise((_2, reject) => {
7323
- createCardTimeoutId = setTimeout(
7324
- () => reject(new Error("VGS createCard timed out")),
7325
- VGS_CREATE_CARD_TIMEOUT_MS
7326
- );
8338
+ createCardTimeoutId = setTimeout(() => reject(new Error("VGS_TIMEOUT")), VGS_CREATE_CARD_TIMEOUT_MS);
7327
8339
  })
7328
8340
  ]).finally(() => clearTimeout(createCardTimeoutId));
7329
- if (!cardResult?.data?.attributes) {
7330
- throw new Error("VGS createCard returned an invalid response");
8341
+ } catch (err) {
8342
+ const errStr = stringifyError(err);
8343
+ console.error(`${logPrefix} VGS createCard failed:`, errStr);
8344
+ if (err instanceof Error && err.message === "VGS_TIMEOUT") {
8345
+ errors.root = "Card processing timed out \u2014 please try again";
8346
+ return { errors, isSuccess: false };
8347
+ }
8348
+ if (err && typeof err === "object" && !(err instanceof Error)) {
8349
+ const vgsErrors = err;
8350
+ for (const [vgsKey, fieldKey] of Object.entries(VGS_FIELD_MAP)) {
8351
+ if (vgsKey in vgsErrors) {
8352
+ const fieldErr = vgsErrors[vgsKey];
8353
+ const messages = fieldErr?.errorMessages;
8354
+ errors[fieldKey] = Array.isArray(messages) ? messages[0] : "invalid";
8355
+ }
8356
+ }
8357
+ if (Object.keys(errors).length > 0) {
8358
+ return { errors, isSuccess: false };
8359
+ }
7331
8360
  }
7332
- const { pan_alias, cvc_alias, exp_month, exp_year } = cardResult.data.attributes;
7333
- const fullYear = exp_year < 100 ? 2e3 + exp_year : exp_year;
7334
- const formattedExp = `${String(exp_month).padStart(2, "0")}/${fullYear}`;
7335
- await tunnelX.publicEndpoints.updateCardSetupIntent({
8361
+ errors.root = "Card validation failed \u2014 please check your card details and try again";
8362
+ return { errors, isSuccess: false };
8363
+ }
8364
+ if (!cardResult?.data?.attributes) {
8365
+ console.error(`${logPrefix} VGS createCard returned invalid response:`, stringifyError(cardResult));
8366
+ errors.root = "Card processing returned an invalid response \u2014 please try again";
8367
+ return { errors, isSuccess: false };
8368
+ }
8369
+ const { pan_alias, cvc_alias, exp_month, exp_year } = cardResult.data.attributes;
8370
+ const fullYear = exp_year < 100 ? 2e3 + exp_year : exp_year;
8371
+ const formattedExp = `${String(exp_month).padStart(2, "0")}/${fullYear}`;
8372
+ const cmpCardId = cardResult.data.id;
8373
+ try {
8374
+ const updateIntentCall = tunnelX.publicEndpoints.updateCardSetupIntent({
7336
8375
  checkoutToken: secureToken,
7337
8376
  cardSetupIntentId,
7338
8377
  updateCardSetupIntentReq: {
7339
8378
  cardPan: pan_alias,
7340
8379
  cardExp: formattedExp,
7341
8380
  cardCvc: cvc_alias,
8381
+ cmpCardId,
7342
8382
  fraudMetadata: collectFraudMetadata()
7343
8383
  }
7344
8384
  });
7345
- return { errors: {}, isSuccess: true };
8385
+ const proxyCvcCall = new Promise((resolve, reject) => {
8386
+ if (!vgsForm.submit) {
8387
+ reject(new Error("VGS form.submit not available"));
8388
+ return;
8389
+ }
8390
+ vgsForm.submit(
8391
+ `/api/card-setup-intents/${secureToken}/${cardSetupIntentId}`,
8392
+ {
8393
+ method: "post",
8394
+ headers: { "Content-Type": "application/json" },
8395
+ data: (fields) => ({ card_cvc: fields.cvc })
8396
+ },
8397
+ (_status) => resolve(),
8398
+ (err) => reject(err)
8399
+ );
8400
+ });
8401
+ await Promise.all([updateIntentCall, proxyCvcCall]);
7346
8402
  } catch (err) {
7347
- console.error("[PaymentKit] VGS CMP createCard failed:", err);
7348
- errors.root = "Card submission failed";
8403
+ console.error(`${logPrefix} updateCardSetupIntent failed:`, stringifyError(err));
8404
+ errors.root = "Failed to save card details \u2014 please try again";
7349
8405
  return { errors, isSuccess: false };
7350
8406
  }
8407
+ return { errors: {}, isSuccess: true };
7351
8408
  };
7352
8409
  var submitCardFields = async (states) => {
7353
8410
  const errors = {};
@@ -7396,7 +8453,7 @@ var PaymentKit = (() => {
7396
8453
  createElement: defCreateElement(localStates)
7397
8454
  },
7398
8455
  internalFuncs: {
7399
- submitPayment: defSubmitPayment(localStates),
8456
+ submitPayment: defSubmitPayment2(localStates),
7400
8457
  cleanup: () => {
7401
8458
  if (localStates.vgsForm) {
7402
8459
  localStates.vgsFieldsCleanup?.();
@@ -7632,11 +8689,13 @@ var PaymentKit = (() => {
7632
8689
  return new Promise((resolve) => {
7633
8690
  this.paymentRequest.on("paymentmethod", (event) => {
7634
8691
  console.log("[GooglePay] showPaymentSheet: paymentmethod event", {
7635
- paymentMethodId: event.paymentMethod.id
8692
+ paymentMethodId: event.paymentMethod.id,
8693
+ payerEmail: event.payerEmail
7636
8694
  });
7637
8695
  resolve({
7638
8696
  success: true,
7639
8697
  paymentMethodId: event.paymentMethod.id,
8698
+ payerEmail: event.payerEmail ?? void 0,
7640
8699
  complete: (status) => {
7641
8700
  console.log("[GooglePay] complete called:", status);
7642
8701
  event.complete(status);
@@ -7657,6 +8716,7 @@ var PaymentKit = (() => {
7657
8716
  return {
7658
8717
  success: true,
7659
8718
  paymentMethodId: "pm_mock_123456789",
8719
+ payerEmail: "mock@example.com",
7660
8720
  complete: (status) => console.log(`[MockGooglePay] complete: ${status}`)
7661
8721
  };
7662
8722
  }
@@ -7700,7 +8760,7 @@ var PaymentKit = (() => {
7700
8760
  };
7701
8761
 
7702
8762
  // src/payment-methods/google-pay.ts
7703
- async function apiCall(url, options, checkoutRequestId) {
8763
+ async function apiCall2(url, options, checkoutRequestId) {
7704
8764
  const headers = new Headers(options.headers);
7705
8765
  if (checkoutRequestId) {
7706
8766
  headers.set("x-request-id", checkoutRequestId);
@@ -7718,17 +8778,17 @@ var PaymentKit = (() => {
7718
8778
  }
7719
8779
  return { data: await response.json() };
7720
8780
  }
7721
- function validateOptions(options) {
8781
+ function validateOptions2(options) {
7722
8782
  if (!options?.processorId) {
7723
8783
  return { processor_id: "Processor ID is required" };
7724
8784
  }
7725
8785
  return null;
7726
8786
  }
7727
- function getMockScenarioStr(mockScenario) {
8787
+ function getMockScenarioStr2(mockScenario) {
7728
8788
  return mockScenario && mockScenario !== "none" /* None */ ? mockScenario : void 0;
7729
8789
  }
7730
8790
  async function callStartEndpoint(apiBaseUrl, secureToken, options, mockScenarioStr, checkoutRequestId) {
7731
- return apiCall(
8791
+ return apiCall2(
7732
8792
  `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/start`,
7733
8793
  {
7734
8794
  method: "POST",
@@ -7743,7 +8803,7 @@ var PaymentKit = (() => {
7743
8803
  checkoutRequestId
7744
8804
  );
7745
8805
  }
7746
- function initializeStripeAdapter(stripePk, startData, mockScenario) {
8806
+ function initializeStripeAdapter2(stripePk, startData, mockScenario) {
7747
8807
  const adapter = new StripeGooglePayAdapter(mockScenario);
7748
8808
  if (!adapter.initialize(stripePk)) {
7749
8809
  return { error: 'Stripe.js not loaded. Add <script src="https://js.stripe.com/v3/"><\/script> to your page.' };
@@ -7762,7 +8822,7 @@ var PaymentKit = (() => {
7762
8822
  if (!startData.stripe_pk || !startData.client_secret) {
7763
8823
  return { success: false, error: "Stripe credentials not provided" };
7764
8824
  }
7765
- const { adapter, error: adapterError } = initializeStripeAdapter(startData.stripe_pk, startData, mockScenario);
8825
+ const { adapter, error: adapterError } = initializeStripeAdapter2(startData.stripe_pk, startData, mockScenario);
7766
8826
  if (!adapter) {
7767
8827
  return { success: false, error: adapterError };
7768
8828
  }
@@ -7784,7 +8844,7 @@ var PaymentKit = (() => {
7784
8844
  return { success: false, error: "error" in confirmResult ? confirmResult.error : "Card setup failed" };
7785
8845
  }
7786
8846
  paymentResult.complete("success");
7787
- return { success: true };
8847
+ return { success: true, payerEmail: paymentResult.payerEmail };
7788
8848
  }
7789
8849
  function initializeAirwallexAdapter(startData, mockScenario) {
7790
8850
  if (!startData.merchant_name || !startData.airwallex_account_id) {
@@ -7813,7 +8873,7 @@ var PaymentKit = (() => {
7813
8873
  }
7814
8874
  return { adapter };
7815
8875
  }
7816
- async function runAirwallexFlow(startData, mockScenario) {
8876
+ async function runAirwallexFlow2(startData, mockScenario) {
7817
8877
  const { adapter, error: adapterError } = initializeAirwallexAdapter(startData, mockScenario);
7818
8878
  if (!adapter) {
7819
8879
  return { success: false, error: adapterError };
@@ -7832,14 +8892,17 @@ var PaymentKit = (() => {
7832
8892
  }
7833
8893
  return { success: true, token: paymentResult.token };
7834
8894
  }
7835
- async function callConfirmEndpoint(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId) {
8895
+ async function callConfirmEndpoint(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId, payerEmail) {
7836
8896
  const requestBody = {
7837
8897
  mock_scenario: mockScenarioStr
7838
8898
  };
7839
8899
  if (googlePayToken) {
7840
8900
  requestBody.google_pay_token = googlePayToken;
7841
8901
  }
7842
- const result = await apiCall(
8902
+ if (payerEmail) {
8903
+ requestBody.payer_email = payerEmail;
8904
+ }
8905
+ const result = await apiCall2(
7843
8906
  `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/confirm`,
7844
8907
  {
7845
8908
  method: "POST",
@@ -7858,7 +8921,7 @@ var PaymentKit = (() => {
7858
8921
  return result.data;
7859
8922
  }
7860
8923
  async function callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId) {
7861
- const result = await apiCall(
8924
+ const result = await apiCall2(
7862
8925
  `${apiBaseUrl}/api/checkout/${secureToken}/google-pay/verify`,
7863
8926
  {
7864
8927
  method: "POST",
@@ -7881,22 +8944,48 @@ var PaymentKit = (() => {
7881
8944
  data: {
7882
8945
  id: response.transaction_id,
7883
8946
  checkoutAttemptId: response.checkout_attempt_id,
7884
- checkoutSessionId: secureToken,
7885
- state: "checkout_succeeded"
8947
+ checkoutSessionId: response.checkout_session_id ?? secureToken,
8948
+ state: "checkout_succeeded",
8949
+ paymentIntentId: response.payment_intent_id,
8950
+ customerId: response.customer_id,
8951
+ paymentMethodId: response.payment_method_id,
8952
+ processorUsed: response.processor_used,
8953
+ subscriptionId: response.subscription_id,
8954
+ invoiceId: response.invoice_id,
8955
+ invoiceNumber: response.invoice_number,
8956
+ cardBrand: response.card_brand,
8957
+ cardLast4: response.card_last4,
8958
+ cardExpMonth: response.card_exp_month,
8959
+ cardExpYear: response.card_exp_year,
8960
+ errorCode: response.error_code,
8961
+ errorMessageForCustomer: response.error_message_for_customer,
8962
+ errorMessageForDebug: response.error_message_for_debug,
8963
+ nextAction: response.next_action
7886
8964
  }
7887
8965
  };
7888
8966
  }
7889
- return { errors: { google_pay: response.error_message || "Payment failed" } };
8967
+ return {
8968
+ errors: {
8969
+ google_pay: response.error_message_for_customer || response.error_message_for_debug || response.error_message || "Payment failed"
8970
+ }
8971
+ };
7890
8972
  }
7891
- async function confirmStripeGooglePay(apiBaseUrl, secureToken, mockScenarioStr, checkoutRequestId) {
7892
- const response = await callConfirmEndpoint(apiBaseUrl, secureToken, void 0, mockScenarioStr, checkoutRequestId);
8973
+ async function confirmStripeGooglePay(apiBaseUrl, secureToken, mockScenarioStr, checkoutRequestId, payerEmail) {
8974
+ const response = await callConfirmEndpoint(
8975
+ apiBaseUrl,
8976
+ secureToken,
8977
+ void 0,
8978
+ mockScenarioStr,
8979
+ checkoutRequestId,
8980
+ payerEmail
8981
+ );
7893
8982
  return toGooglePayResult(response, secureToken);
7894
8983
  }
7895
- var MAX_USER_ACTIONS = 5;
8984
+ var MAX_USER_ACTIONS2 = 5;
7896
8985
  async function confirmAirwallexGooglePay(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId) {
7897
8986
  let userActionCount = 0;
7898
8987
  let response = await callConfirmEndpoint(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId);
7899
- while (response.charge_status === "pending" && response.next_action && userActionCount < MAX_USER_ACTIONS) {
8988
+ while (response.charge_status === "pending" && response.next_action && userActionCount < MAX_USER_ACTIONS2) {
7900
8989
  userActionCount++;
7901
8990
  const actionResult = await handleNextAction(response.next_action);
7902
8991
  const verifyResponse = await callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);
@@ -7916,21 +9005,21 @@ var PaymentKit = (() => {
7916
9005
  }
7917
9006
  return toGooglePayResult(verifyResponse, secureToken);
7918
9007
  }
7919
- if (userActionCount >= MAX_USER_ACTIONS) {
9008
+ if (userActionCount >= MAX_USER_ACTIONS2) {
7920
9009
  return { errors: { google_pay: "Too many authentication attempts. Please try again." } };
7921
9010
  }
7922
9011
  return toGooglePayResult(response, secureToken);
7923
9012
  }
7924
- var defSubmitPayment2 = (states) => {
9013
+ var defSubmitPayment3 = (states) => {
7925
9014
  const submitPayment = async (_fields, options) => {
7926
9015
  const { apiBaseUrl, secureToken, environment } = states;
7927
9016
  const gpayOptions = options;
7928
- const validationError = validateOptions(gpayOptions);
9017
+ const validationError = validateOptions2(gpayOptions);
7929
9018
  if (validationError) {
7930
9019
  return { errors: validationError };
7931
9020
  }
7932
9021
  try {
7933
- const mockScenarioStr = getMockScenarioStr(gpayOptions.mockScenario);
9022
+ const mockScenarioStr = getMockScenarioStr2(gpayOptions.mockScenario);
7934
9023
  const checkoutRequestId = getOrCreateCheckoutRequestId(environment);
7935
9024
  console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);
7936
9025
  const startResult = await callStartEndpoint(
@@ -7949,10 +9038,16 @@ var PaymentKit = (() => {
7949
9038
  if (!stripeResult.success) {
7950
9039
  return { errors: { google_pay: stripeResult.error } };
7951
9040
  }
7952
- return await confirmStripeGooglePay(apiBaseUrl, secureToken, mockScenarioStr, checkoutRequestId);
9041
+ return await confirmStripeGooglePay(
9042
+ apiBaseUrl,
9043
+ secureToken,
9044
+ mockScenarioStr,
9045
+ checkoutRequestId,
9046
+ stripeResult.payerEmail
9047
+ );
7953
9048
  }
7954
9049
  if (startData.processor === "airwallex") {
7955
- const airwallexResult = await runAirwallexFlow(startData, gpayOptions.mockScenario);
9050
+ const airwallexResult = await runAirwallexFlow2(startData, gpayOptions.mockScenario);
7956
9051
  if (!airwallexResult.success) {
7957
9052
  return { errors: { google_pay: airwallexResult.error } };
7958
9053
  }
@@ -7979,7 +9074,7 @@ var PaymentKit = (() => {
7979
9074
  name: "google_pay",
7980
9075
  externalFuncs: {},
7981
9076
  internalFuncs: {
7982
- submitPayment: defSubmitPayment2(paymentKitStates),
9077
+ submitPayment: defSubmitPayment3(paymentKitStates),
7983
9078
  cleanup: () => {
7984
9079
  }
7985
9080
  }
@@ -7988,7 +9083,7 @@ var PaymentKit = (() => {
7988
9083
  var google_pay_default = GooglePayPaymentMethod;
7989
9084
 
7990
9085
  // src/payment-methods/paypal.ts
7991
- var defSubmitPayment3 = (states) => {
9086
+ var defSubmitPayment4 = (states) => {
7992
9087
  const submitPayment = async (_fields, options) => {
7993
9088
  const { apiBaseUrl, secureToken, environment } = states;
7994
9089
  const paypalOptions = options;
@@ -8117,7 +9212,7 @@ var PaymentKit = (() => {
8117
9212
  // PayPal doesn't need createElement like card iframes
8118
9213
  },
8119
9214
  internalFuncs: {
8120
- submitPayment: defSubmitPayment3(localStates),
9215
+ submitPayment: defSubmitPayment4(localStates),
8121
9216
  cleanup: () => {
8122
9217
  if (localStates.pollInterval) {
8123
9218
  clearInterval(localStates.pollInterval);
@@ -8134,6 +9229,7 @@ var PaymentKit = (() => {
8134
9229
  // src/cdn.ts
8135
9230
  var cdn_default = index_default;
8136
9231
  var PaymentMethods = {
9232
+ applePay: apple_pay_default,
8137
9233
  card: card_default,
8138
9234
  googlePay: google_pay_default,
8139
9235
  paypal: paypal_default