@payment-kit-js/vanilla 0.5.8 → 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.
- package/dist/{airwallex-apple-pay-adapter-I_pnNYdy.d.mts → airwallex-apple-pay-adapter-BCYt7Jzc.d.mts} +2 -1
- package/dist/airwallex-apple-pay-adapter-BCYt7Jzc.d.mts.map +1 -0
- package/dist/{airwallex-apple-pay-adapter-BE15xREr.mjs → airwallex-apple-pay-adapter-BFsoDoSf.mjs} +6 -2
- package/dist/airwallex-apple-pay-adapter-BFsoDoSf.mjs.map +1 -0
- package/dist/cdn/paymentkit.js +1250 -129
- package/dist/cdn/paymentkit.js.map +4 -4
- package/dist/cdn/paymentkit.min.js +10 -10
- package/dist/cdn/paymentkit.min.js.map +4 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +7 -1
- package/dist/index.mjs.map +1 -1
- package/dist/payment-methods/airwallex-apple-pay-adapter.d.mts +1 -1
- package/dist/payment-methods/airwallex-apple-pay-adapter.mjs +1 -1
- package/dist/payment-methods/apple-pay.d.mts +15 -1
- package/dist/payment-methods/apple-pay.d.mts.map +1 -1
- package/dist/payment-methods/apple-pay.mjs +45 -13
- package/dist/payment-methods/apple-pay.mjs.map +1 -1
- package/dist/payment-methods/card.d.mts.map +1 -1
- package/dist/payment-methods/card.mjs +120 -21
- package/dist/payment-methods/card.mjs.map +1 -1
- package/dist/payment-methods/google-pay.d.mts +18 -1
- package/dist/payment-methods/google-pay.d.mts.map +1 -1
- package/dist/payment-methods/google-pay.mjs +28 -9
- package/dist/payment-methods/google-pay.mjs.map +1 -1
- package/dist/payment-methods/stripe-google-pay-adapter.d.mts +1 -1
- package/dist/payment-methods/stripe-google-pay-adapter.mjs +1 -1
- package/dist/payment-methods/vgs-collect-loader.d.mts +1 -1
- package/dist/payment-methods/vgs-collect-loader.mjs +1 -1
- package/dist/{stripe-google-pay-adapter-CqcUEoM3.mjs → stripe-google-pay-adapter-3cx0KNjK.mjs} +7 -2
- package/dist/stripe-google-pay-adapter-3cx0KNjK.mjs.map +1 -0
- package/dist/{stripe-google-pay-adapter-C3NCBSO3.d.mts → stripe-google-pay-adapter-Bdox4xBq.d.mts} +2 -1
- package/dist/stripe-google-pay-adapter-Bdox4xBq.d.mts.map +1 -0
- package/dist/{vgs-collect-loader-3Z4IWCA6.mjs → vgs-collect-loader-BZj36d8r.mjs} +28 -9
- package/dist/vgs-collect-loader-BZj36d8r.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/airwallex-apple-pay-adapter-BE15xREr.mjs.map +0 -1
- package/dist/airwallex-apple-pay-adapter-I_pnNYdy.d.mts.map +0 -1
- package/dist/stripe-google-pay-adapter-C3NCBSO3.d.mts.map +0 -1
- package/dist/stripe-google-pay-adapter-CqcUEoM3.mjs.map +0 -1
- package/dist/vgs-collect-loader-3Z4IWCA6.mjs.map +0 -1
package/dist/cdn/paymentkit.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PaymentKit.js v0.5.
|
|
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.
|
|
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/
|
|
6601
|
-
var
|
|
6602
|
-
|
|
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
|
|
@@ -6739,77 +6945,849 @@ var PaymentKit = (() => {
|
|
|
6739
6945
|
}
|
|
6740
6946
|
}
|
|
6741
6947
|
};
|
|
6742
|
-
window.addEventListener("keydown", handleKeydown);
|
|
6743
|
-
closeButton.focus();
|
|
6744
|
-
const handleMessage = (event) => {
|
|
6745
|
-
const messageResult = onMessage(event);
|
|
6746
|
-
if (messageResult.handled) {
|
|
6747
|
-
cleanupWithAnimation();
|
|
6748
|
-
resolve(messageResult.result);
|
|
6749
|
-
}
|
|
6948
|
+
window.addEventListener("keydown", handleKeydown);
|
|
6949
|
+
closeButton.focus();
|
|
6950
|
+
const handleMessage = (event) => {
|
|
6951
|
+
const messageResult = onMessage(event);
|
|
6952
|
+
if (messageResult.handled) {
|
|
6953
|
+
cleanupWithAnimation();
|
|
6954
|
+
resolve(messageResult.result);
|
|
6955
|
+
}
|
|
6956
|
+
};
|
|
6957
|
+
window.addEventListener("message", handleMessage);
|
|
6958
|
+
});
|
|
6959
|
+
}
|
|
6960
|
+
|
|
6961
|
+
// src/payment-methods/next-action-handlers.ts
|
|
6962
|
+
var sleep = (ms2) => new Promise((resolve) => setTimeout(resolve, ms2));
|
|
6963
|
+
var isStripeJsPresent = () => "Stripe" in window;
|
|
6964
|
+
var getLoadedStripe = async (publishableKey) => {
|
|
6965
|
+
for (let i2 = 0; i2 < 10; i2++) {
|
|
6966
|
+
if (isStripeJsPresent()) {
|
|
6967
|
+
break;
|
|
6968
|
+
}
|
|
6969
|
+
await sleep(500);
|
|
6970
|
+
}
|
|
6971
|
+
if (!isStripeJsPresent()) {
|
|
6972
|
+
throw new Error(
|
|
6973
|
+
'Stripe.js not loaded. Add this script tag to your HTML <head>:\n<script src="https://js.stripe.com/v3/"><\/script>'
|
|
6974
|
+
);
|
|
6975
|
+
}
|
|
6976
|
+
const stripe = new window.Stripe(publishableKey);
|
|
6977
|
+
return stripe;
|
|
6978
|
+
};
|
|
6979
|
+
var handleStripe3ds = async (nextAction) => {
|
|
6980
|
+
const { clientSecret, stripePk } = nextAction;
|
|
6981
|
+
const stripe = await getLoadedStripe(stripePk);
|
|
6982
|
+
const { error: stripeError } = await stripe.confirmCardPayment(clientSecret);
|
|
6983
|
+
if (stripeError) {
|
|
6984
|
+
console.error("[3DS:Stripe] Authentication failed:", stripeError.message);
|
|
6985
|
+
return { success: false, error: stripeError.message || "3DS authentication failed" };
|
|
6986
|
+
}
|
|
6987
|
+
return { success: true };
|
|
6988
|
+
};
|
|
6989
|
+
var handleAirwallex3ds = async (nextAction) => {
|
|
6990
|
+
return show3DSIframeModal({
|
|
6991
|
+
url: nextAction.url,
|
|
6992
|
+
size: { width: 605, height: 550 },
|
|
6993
|
+
onMessage: (event) => {
|
|
6994
|
+
if (event.data.type !== "3ds_complete") {
|
|
6995
|
+
return { handled: false };
|
|
6996
|
+
}
|
|
6997
|
+
const { isSuccess, error } = event.data;
|
|
6998
|
+
if (isSuccess) {
|
|
6999
|
+
return { handled: true, result: { success: true, data: {} } };
|
|
7000
|
+
} else {
|
|
7001
|
+
console.error("[3DS:Airwallex] Authentication failed:", error);
|
|
7002
|
+
return {
|
|
7003
|
+
handled: true,
|
|
7004
|
+
result: { success: false, error: error || "3DS authentication failed" }
|
|
7005
|
+
};
|
|
7006
|
+
}
|
|
7007
|
+
}
|
|
7008
|
+
});
|
|
7009
|
+
};
|
|
7010
|
+
var handleNextAction = async (nextAction) => {
|
|
7011
|
+
switch (nextAction.type) {
|
|
7012
|
+
case "stripe_3ds":
|
|
7013
|
+
return handleStripe3ds(nextAction);
|
|
7014
|
+
case "airwallex_3ds":
|
|
7015
|
+
return handleAirwallex3ds(nextAction);
|
|
7016
|
+
default:
|
|
7017
|
+
return { success: false, error: `Unknown next action type: ${nextAction.type}` };
|
|
7018
|
+
}
|
|
7019
|
+
};
|
|
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: ""
|
|
6750
7522
|
};
|
|
6751
|
-
|
|
6752
|
-
|
|
7523
|
+
}
|
|
7524
|
+
return result.data;
|
|
6753
7525
|
}
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
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"
|
|
6762
7555
|
}
|
|
6763
|
-
|
|
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 */;
|
|
6764
7565
|
}
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
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
|
|
6768
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" } };
|
|
6769
7618
|
}
|
|
6770
|
-
const
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
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);
|
|
6780
7651
|
}
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
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
|
+
}
|
|
6790
7701
|
}
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
return
|
|
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;
|
|
6794
7756
|
} else {
|
|
6795
|
-
|
|
6796
|
-
return
|
|
6797
|
-
handled: true,
|
|
6798
|
-
result: { success: false, error: error || "3DS authentication failed" }
|
|
6799
|
-
};
|
|
7757
|
+
paymentMethodEvent.complete("fail");
|
|
7758
|
+
return confirmResult;
|
|
6800
7759
|
}
|
|
7760
|
+
} catch (error) {
|
|
7761
|
+
clearPreparedApplePay();
|
|
7762
|
+
return { errors: { apple_pay: `Apple Pay error: ${error}` } };
|
|
6801
7763
|
}
|
|
6802
|
-
}
|
|
7764
|
+
};
|
|
7765
|
+
return submitPayment;
|
|
6803
7766
|
};
|
|
6804
|
-
var
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
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 });
|
|
6813
7791
|
};
|
|
6814
7792
|
|
|
6815
7793
|
// src/payment-methods/vgs-collect-loader.ts
|
|
@@ -6864,6 +7842,14 @@ var PaymentKit = (() => {
|
|
|
6864
7842
|
"box-sizing": "border-box",
|
|
6865
7843
|
...containerPadding && containerPadding !== "0px" ? { padding: containerPadding } : {}
|
|
6866
7844
|
};
|
|
7845
|
+
for (const selector of [mountPoints.pan, mountPoints.exp, mountPoints.cvc]) {
|
|
7846
|
+
const container = document.querySelector(selector);
|
|
7847
|
+
if (!container) continue;
|
|
7848
|
+
const staleIframes = container.querySelectorAll("iframe");
|
|
7849
|
+
for (const iframe of staleIframes) {
|
|
7850
|
+
iframe.remove();
|
|
7851
|
+
}
|
|
7852
|
+
}
|
|
6867
7853
|
const panField = form.cardNumberField(mountPoints.pan, {
|
|
6868
7854
|
placeholder: placeholders?.card_pan ?? "Card number",
|
|
6869
7855
|
validations: ["required", "validCardNumber"],
|
|
@@ -6883,9 +7869,12 @@ var PaymentKit = (() => {
|
|
|
6883
7869
|
validations: ["required", "validCardSecurityCode"],
|
|
6884
7870
|
css: fieldCss
|
|
6885
7871
|
});
|
|
7872
|
+
const observers = [];
|
|
7873
|
+
const containers = [];
|
|
6886
7874
|
for (const selector of [mountPoints.pan, mountPoints.exp, mountPoints.cvc]) {
|
|
6887
7875
|
const container = document.querySelector(selector);
|
|
6888
7876
|
if (!container) continue;
|
|
7877
|
+
containers.push(container);
|
|
6889
7878
|
const styleIframe = (iframe) => {
|
|
6890
7879
|
const containerEl = container;
|
|
6891
7880
|
if (getComputedStyle(containerEl).position === "static") {
|
|
@@ -6897,18 +7886,17 @@ var PaymentKit = (() => {
|
|
|
6897
7886
|
iframe.style.height = "100%";
|
|
6898
7887
|
iframe.style.border = "none";
|
|
6899
7888
|
};
|
|
7889
|
+
const observer = new MutationObserver(() => {
|
|
7890
|
+
const iframe = container.querySelector("iframe");
|
|
7891
|
+
if (iframe && iframe.style.position !== "absolute") {
|
|
7892
|
+
styleIframe(iframe);
|
|
7893
|
+
}
|
|
7894
|
+
});
|
|
7895
|
+
observer.observe(container, { childList: true, subtree: true });
|
|
7896
|
+
observers.push(observer);
|
|
6900
7897
|
const existing = container.querySelector("iframe");
|
|
6901
|
-
if (existing) {
|
|
7898
|
+
if (existing && existing.style.position !== "absolute") {
|
|
6902
7899
|
styleIframe(existing);
|
|
6903
|
-
} else {
|
|
6904
|
-
const observer = new MutationObserver((_2, obs) => {
|
|
6905
|
-
const iframe = container.querySelector("iframe");
|
|
6906
|
-
if (iframe) {
|
|
6907
|
-
styleIframe(iframe);
|
|
6908
|
-
obs.disconnect();
|
|
6909
|
-
}
|
|
6910
|
-
});
|
|
6911
|
-
observer.observe(container, { childList: true, subtree: true });
|
|
6912
7900
|
}
|
|
6913
7901
|
}
|
|
6914
7902
|
if (onFocusChangeCallbacks) {
|
|
@@ -6925,6 +7913,17 @@ var PaymentKit = (() => {
|
|
|
6925
7913
|
}
|
|
6926
7914
|
}
|
|
6927
7915
|
}
|
|
7916
|
+
return () => {
|
|
7917
|
+
for (const observer of observers) {
|
|
7918
|
+
observer.disconnect();
|
|
7919
|
+
}
|
|
7920
|
+
for (const container of containers) {
|
|
7921
|
+
const iframes = container.querySelectorAll("iframe");
|
|
7922
|
+
for (const iframe of iframes) {
|
|
7923
|
+
iframe.remove();
|
|
7924
|
+
}
|
|
7925
|
+
}
|
|
7926
|
+
};
|
|
6928
7927
|
}
|
|
6929
7928
|
|
|
6930
7929
|
// src/payment-methods/card.ts
|
|
@@ -7037,7 +8036,7 @@ var PaymentKit = (() => {
|
|
|
7037
8036
|
console.log(
|
|
7038
8037
|
`[PaymentKit] Creating VGS card fields \u2014 pan: ${parentSelector}, exp: ${expSelector}, cvc: ${cvcSelector}`
|
|
7039
8038
|
);
|
|
7040
|
-
createVgsCardFields(
|
|
8039
|
+
states.vgsFieldsCleanup = createVgsCardFields(
|
|
7041
8040
|
form,
|
|
7042
8041
|
{
|
|
7043
8042
|
pan: parentSelector,
|
|
@@ -7061,7 +8060,15 @@ var PaymentKit = (() => {
|
|
|
7061
8060
|
}
|
|
7062
8061
|
cleanupVgs = () => {
|
|
7063
8062
|
if (type === "card_pan" && states.vgsForm) {
|
|
7064
|
-
|
|
8063
|
+
try {
|
|
8064
|
+
states.vgsFieldsCleanup?.();
|
|
8065
|
+
} catch {
|
|
8066
|
+
}
|
|
8067
|
+
states.vgsFieldsCleanup = void 0;
|
|
8068
|
+
try {
|
|
8069
|
+
states.vgsForm.unmount();
|
|
8070
|
+
} catch {
|
|
8071
|
+
}
|
|
7065
8072
|
states.vgsForm = void 0;
|
|
7066
8073
|
}
|
|
7067
8074
|
};
|
|
@@ -7095,7 +8102,10 @@ var PaymentKit = (() => {
|
|
|
7095
8102
|
cleanupDirect = () => {
|
|
7096
8103
|
const connection = cardInputConnections[type];
|
|
7097
8104
|
connection?.destroy();
|
|
7098
|
-
|
|
8105
|
+
try {
|
|
8106
|
+
parent.removeChild(iframe);
|
|
8107
|
+
} catch {
|
|
8108
|
+
}
|
|
7099
8109
|
states.cardInputConnections[type] = void 0;
|
|
7100
8110
|
};
|
|
7101
8111
|
parent.appendChild(iframe);
|
|
@@ -7128,7 +8138,7 @@ var PaymentKit = (() => {
|
|
|
7128
8138
|
return { mount: mountIFrame };
|
|
7129
8139
|
};
|
|
7130
8140
|
};
|
|
7131
|
-
var
|
|
8141
|
+
var defSubmitPayment2 = (states) => {
|
|
7132
8142
|
const submitPayment = async (fields, options) => {
|
|
7133
8143
|
if (states._sessionConfigReady) await states._sessionConfigReady;
|
|
7134
8144
|
const isVgsMode = states.cardTokenizationMode === "vgs";
|
|
@@ -7158,7 +8168,8 @@ var PaymentKit = (() => {
|
|
|
7158
8168
|
console.log("[PaymentKit] Submitting card via VGS CMP...");
|
|
7159
8169
|
const vgsSubmitResult = await submitVgsCardFields(states, tunnelX);
|
|
7160
8170
|
if (!vgsSubmitResult.isSuccess) {
|
|
7161
|
-
|
|
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");
|
|
7162
8173
|
return { errors: vgsSubmitResult.errors };
|
|
7163
8174
|
}
|
|
7164
8175
|
} else {
|
|
@@ -7194,11 +8205,11 @@ var PaymentKit = (() => {
|
|
|
7194
8205
|
requestOptions
|
|
7195
8206
|
);
|
|
7196
8207
|
console.log("Card checkout result:", currentResult);
|
|
7197
|
-
const
|
|
8208
|
+
const MAX_USER_ACTIONS3 = 5;
|
|
7198
8209
|
let userActionCount = 0;
|
|
7199
|
-
while (currentResult.nextAction && userActionCount <
|
|
8210
|
+
while (currentResult.nextAction && userActionCount < MAX_USER_ACTIONS3) {
|
|
7200
8211
|
userActionCount++;
|
|
7201
|
-
console.log(`Handling user action ${userActionCount}/${
|
|
8212
|
+
console.log(`Handling user action ${userActionCount}/${MAX_USER_ACTIONS3}...`);
|
|
7202
8213
|
const actionResult = await handleNextAction(currentResult.nextAction);
|
|
7203
8214
|
console.log("User action completed, verifying checkout...");
|
|
7204
8215
|
const verifyResult = await tunnelX.publicEndpoints.cardCheckoutVerify(
|
|
@@ -7234,7 +8245,7 @@ var PaymentKit = (() => {
|
|
|
7234
8245
|
timingTracker.trackSuccess(verifyResult.checkoutAttemptId || "unknown");
|
|
7235
8246
|
return { data: verifyResult };
|
|
7236
8247
|
}
|
|
7237
|
-
if (userActionCount >=
|
|
8248
|
+
if (userActionCount >= MAX_USER_ACTIONS3) {
|
|
7238
8249
|
console.error("Max user actions exceeded");
|
|
7239
8250
|
timingTracker.trackFail(null, "max_actions_exceeded", "Too many authentication attempts");
|
|
7240
8251
|
return { errors: { root: "Too many authentication attempts. Please try again." } };
|
|
@@ -7270,8 +8281,27 @@ var PaymentKit = (() => {
|
|
|
7270
8281
|
const data = await resp.json();
|
|
7271
8282
|
return data.access_token;
|
|
7272
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
|
+
};
|
|
7273
8302
|
var submitVgsCardFields = async (states, tunnelX) => {
|
|
7274
|
-
const { vgsForm, cardSetupIntentId, secureToken, apiBaseUrl } = states;
|
|
8303
|
+
const { vgsForm, cardSetupIntentId, secureToken, apiBaseUrl, checkoutRequestId } = states;
|
|
8304
|
+
const logPrefix = `[PaymentKit] [${checkoutRequestId}]`;
|
|
7275
8305
|
const errors = {};
|
|
7276
8306
|
if (!vgsForm) {
|
|
7277
8307
|
errors.card_pan = "required";
|
|
@@ -7281,11 +8311,19 @@ var PaymentKit = (() => {
|
|
|
7281
8311
|
errors.root = "Card setup intent not created";
|
|
7282
8312
|
return { errors, isSuccess: false };
|
|
7283
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;
|
|
7284
8324
|
try {
|
|
7285
|
-
const accessToken = await fetchCollectToken(apiBaseUrl, secureToken);
|
|
7286
|
-
const VGS_CREATE_CARD_TIMEOUT_MS = 3e4;
|
|
7287
8325
|
let createCardTimeoutId;
|
|
7288
|
-
|
|
8326
|
+
cardResult = await Promise.race([
|
|
7289
8327
|
new Promise((resolve, reject) => {
|
|
7290
8328
|
vgsForm.createCard(
|
|
7291
8329
|
{
|
|
@@ -7297,34 +8335,76 @@ var PaymentKit = (() => {
|
|
|
7297
8335
|
);
|
|
7298
8336
|
}),
|
|
7299
8337
|
new Promise((_2, reject) => {
|
|
7300
|
-
createCardTimeoutId = setTimeout(
|
|
7301
|
-
() => reject(new Error("VGS createCard timed out")),
|
|
7302
|
-
VGS_CREATE_CARD_TIMEOUT_MS
|
|
7303
|
-
);
|
|
8338
|
+
createCardTimeoutId = setTimeout(() => reject(new Error("VGS_TIMEOUT")), VGS_CREATE_CARD_TIMEOUT_MS);
|
|
7304
8339
|
})
|
|
7305
8340
|
]).finally(() => clearTimeout(createCardTimeoutId));
|
|
7306
|
-
|
|
7307
|
-
|
|
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
|
+
}
|
|
7308
8360
|
}
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
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({
|
|
7313
8375
|
checkoutToken: secureToken,
|
|
7314
8376
|
cardSetupIntentId,
|
|
7315
8377
|
updateCardSetupIntentReq: {
|
|
7316
8378
|
cardPan: pan_alias,
|
|
7317
8379
|
cardExp: formattedExp,
|
|
7318
8380
|
cardCvc: cvc_alias,
|
|
8381
|
+
cmpCardId,
|
|
7319
8382
|
fraudMetadata: collectFraudMetadata()
|
|
7320
8383
|
}
|
|
7321
8384
|
});
|
|
7322
|
-
|
|
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]);
|
|
7323
8402
|
} catch (err) {
|
|
7324
|
-
console.error(
|
|
7325
|
-
errors.root = "
|
|
8403
|
+
console.error(`${logPrefix} updateCardSetupIntent failed:`, stringifyError(err));
|
|
8404
|
+
errors.root = "Failed to save card details \u2014 please try again";
|
|
7326
8405
|
return { errors, isSuccess: false };
|
|
7327
8406
|
}
|
|
8407
|
+
return { errors: {}, isSuccess: true };
|
|
7328
8408
|
};
|
|
7329
8409
|
var submitCardFields = async (states) => {
|
|
7330
8410
|
const errors = {};
|
|
@@ -7373,9 +8453,11 @@ var PaymentKit = (() => {
|
|
|
7373
8453
|
createElement: defCreateElement(localStates)
|
|
7374
8454
|
},
|
|
7375
8455
|
internalFuncs: {
|
|
7376
|
-
submitPayment:
|
|
8456
|
+
submitPayment: defSubmitPayment2(localStates),
|
|
7377
8457
|
cleanup: () => {
|
|
7378
8458
|
if (localStates.vgsForm) {
|
|
8459
|
+
localStates.vgsFieldsCleanup?.();
|
|
8460
|
+
localStates.vgsFieldsCleanup = void 0;
|
|
7379
8461
|
localStates.vgsForm.unmount();
|
|
7380
8462
|
localStates.vgsForm = void 0;
|
|
7381
8463
|
}
|
|
@@ -7607,11 +8689,13 @@ var PaymentKit = (() => {
|
|
|
7607
8689
|
return new Promise((resolve) => {
|
|
7608
8690
|
this.paymentRequest.on("paymentmethod", (event) => {
|
|
7609
8691
|
console.log("[GooglePay] showPaymentSheet: paymentmethod event", {
|
|
7610
|
-
paymentMethodId: event.paymentMethod.id
|
|
8692
|
+
paymentMethodId: event.paymentMethod.id,
|
|
8693
|
+
payerEmail: event.payerEmail
|
|
7611
8694
|
});
|
|
7612
8695
|
resolve({
|
|
7613
8696
|
success: true,
|
|
7614
8697
|
paymentMethodId: event.paymentMethod.id,
|
|
8698
|
+
payerEmail: event.payerEmail ?? void 0,
|
|
7615
8699
|
complete: (status) => {
|
|
7616
8700
|
console.log("[GooglePay] complete called:", status);
|
|
7617
8701
|
event.complete(status);
|
|
@@ -7632,6 +8716,7 @@ var PaymentKit = (() => {
|
|
|
7632
8716
|
return {
|
|
7633
8717
|
success: true,
|
|
7634
8718
|
paymentMethodId: "pm_mock_123456789",
|
|
8719
|
+
payerEmail: "mock@example.com",
|
|
7635
8720
|
complete: (status) => console.log(`[MockGooglePay] complete: ${status}`)
|
|
7636
8721
|
};
|
|
7637
8722
|
}
|
|
@@ -7675,7 +8760,7 @@ var PaymentKit = (() => {
|
|
|
7675
8760
|
};
|
|
7676
8761
|
|
|
7677
8762
|
// src/payment-methods/google-pay.ts
|
|
7678
|
-
async function
|
|
8763
|
+
async function apiCall2(url, options, checkoutRequestId) {
|
|
7679
8764
|
const headers = new Headers(options.headers);
|
|
7680
8765
|
if (checkoutRequestId) {
|
|
7681
8766
|
headers.set("x-request-id", checkoutRequestId);
|
|
@@ -7693,17 +8778,17 @@ var PaymentKit = (() => {
|
|
|
7693
8778
|
}
|
|
7694
8779
|
return { data: await response.json() };
|
|
7695
8780
|
}
|
|
7696
|
-
function
|
|
8781
|
+
function validateOptions2(options) {
|
|
7697
8782
|
if (!options?.processorId) {
|
|
7698
8783
|
return { processor_id: "Processor ID is required" };
|
|
7699
8784
|
}
|
|
7700
8785
|
return null;
|
|
7701
8786
|
}
|
|
7702
|
-
function
|
|
8787
|
+
function getMockScenarioStr2(mockScenario) {
|
|
7703
8788
|
return mockScenario && mockScenario !== "none" /* None */ ? mockScenario : void 0;
|
|
7704
8789
|
}
|
|
7705
8790
|
async function callStartEndpoint(apiBaseUrl, secureToken, options, mockScenarioStr, checkoutRequestId) {
|
|
7706
|
-
return
|
|
8791
|
+
return apiCall2(
|
|
7707
8792
|
`${apiBaseUrl}/api/checkout/${secureToken}/google-pay/start`,
|
|
7708
8793
|
{
|
|
7709
8794
|
method: "POST",
|
|
@@ -7718,7 +8803,7 @@ var PaymentKit = (() => {
|
|
|
7718
8803
|
checkoutRequestId
|
|
7719
8804
|
);
|
|
7720
8805
|
}
|
|
7721
|
-
function
|
|
8806
|
+
function initializeStripeAdapter2(stripePk, startData, mockScenario) {
|
|
7722
8807
|
const adapter = new StripeGooglePayAdapter(mockScenario);
|
|
7723
8808
|
if (!adapter.initialize(stripePk)) {
|
|
7724
8809
|
return { error: 'Stripe.js not loaded. Add <script src="https://js.stripe.com/v3/"><\/script> to your page.' };
|
|
@@ -7737,7 +8822,7 @@ var PaymentKit = (() => {
|
|
|
7737
8822
|
if (!startData.stripe_pk || !startData.client_secret) {
|
|
7738
8823
|
return { success: false, error: "Stripe credentials not provided" };
|
|
7739
8824
|
}
|
|
7740
|
-
const { adapter, error: adapterError } =
|
|
8825
|
+
const { adapter, error: adapterError } = initializeStripeAdapter2(startData.stripe_pk, startData, mockScenario);
|
|
7741
8826
|
if (!adapter) {
|
|
7742
8827
|
return { success: false, error: adapterError };
|
|
7743
8828
|
}
|
|
@@ -7759,7 +8844,7 @@ var PaymentKit = (() => {
|
|
|
7759
8844
|
return { success: false, error: "error" in confirmResult ? confirmResult.error : "Card setup failed" };
|
|
7760
8845
|
}
|
|
7761
8846
|
paymentResult.complete("success");
|
|
7762
|
-
return { success: true };
|
|
8847
|
+
return { success: true, payerEmail: paymentResult.payerEmail };
|
|
7763
8848
|
}
|
|
7764
8849
|
function initializeAirwallexAdapter(startData, mockScenario) {
|
|
7765
8850
|
if (!startData.merchant_name || !startData.airwallex_account_id) {
|
|
@@ -7788,7 +8873,7 @@ var PaymentKit = (() => {
|
|
|
7788
8873
|
}
|
|
7789
8874
|
return { adapter };
|
|
7790
8875
|
}
|
|
7791
|
-
async function
|
|
8876
|
+
async function runAirwallexFlow2(startData, mockScenario) {
|
|
7792
8877
|
const { adapter, error: adapterError } = initializeAirwallexAdapter(startData, mockScenario);
|
|
7793
8878
|
if (!adapter) {
|
|
7794
8879
|
return { success: false, error: adapterError };
|
|
@@ -7807,14 +8892,17 @@ var PaymentKit = (() => {
|
|
|
7807
8892
|
}
|
|
7808
8893
|
return { success: true, token: paymentResult.token };
|
|
7809
8894
|
}
|
|
7810
|
-
async function callConfirmEndpoint(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId) {
|
|
8895
|
+
async function callConfirmEndpoint(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId, payerEmail) {
|
|
7811
8896
|
const requestBody = {
|
|
7812
8897
|
mock_scenario: mockScenarioStr
|
|
7813
8898
|
};
|
|
7814
8899
|
if (googlePayToken) {
|
|
7815
8900
|
requestBody.google_pay_token = googlePayToken;
|
|
7816
8901
|
}
|
|
7817
|
-
|
|
8902
|
+
if (payerEmail) {
|
|
8903
|
+
requestBody.payer_email = payerEmail;
|
|
8904
|
+
}
|
|
8905
|
+
const result = await apiCall2(
|
|
7818
8906
|
`${apiBaseUrl}/api/checkout/${secureToken}/google-pay/confirm`,
|
|
7819
8907
|
{
|
|
7820
8908
|
method: "POST",
|
|
@@ -7833,7 +8921,7 @@ var PaymentKit = (() => {
|
|
|
7833
8921
|
return result.data;
|
|
7834
8922
|
}
|
|
7835
8923
|
async function callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId) {
|
|
7836
|
-
const result = await
|
|
8924
|
+
const result = await apiCall2(
|
|
7837
8925
|
`${apiBaseUrl}/api/checkout/${secureToken}/google-pay/verify`,
|
|
7838
8926
|
{
|
|
7839
8927
|
method: "POST",
|
|
@@ -7856,22 +8944,48 @@ var PaymentKit = (() => {
|
|
|
7856
8944
|
data: {
|
|
7857
8945
|
id: response.transaction_id,
|
|
7858
8946
|
checkoutAttemptId: response.checkout_attempt_id,
|
|
7859
|
-
checkoutSessionId: secureToken,
|
|
7860
|
-
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
|
|
7861
8964
|
}
|
|
7862
8965
|
};
|
|
7863
8966
|
}
|
|
7864
|
-
return {
|
|
8967
|
+
return {
|
|
8968
|
+
errors: {
|
|
8969
|
+
google_pay: response.error_message_for_customer || response.error_message_for_debug || response.error_message || "Payment failed"
|
|
8970
|
+
}
|
|
8971
|
+
};
|
|
7865
8972
|
}
|
|
7866
|
-
async function confirmStripeGooglePay(apiBaseUrl, secureToken, mockScenarioStr, checkoutRequestId) {
|
|
7867
|
-
const response = await callConfirmEndpoint(
|
|
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
|
+
);
|
|
7868
8982
|
return toGooglePayResult(response, secureToken);
|
|
7869
8983
|
}
|
|
7870
|
-
var
|
|
8984
|
+
var MAX_USER_ACTIONS2 = 5;
|
|
7871
8985
|
async function confirmAirwallexGooglePay(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId) {
|
|
7872
8986
|
let userActionCount = 0;
|
|
7873
8987
|
let response = await callConfirmEndpoint(apiBaseUrl, secureToken, googlePayToken, mockScenarioStr, checkoutRequestId);
|
|
7874
|
-
while (response.charge_status === "pending" && response.next_action && userActionCount <
|
|
8988
|
+
while (response.charge_status === "pending" && response.next_action && userActionCount < MAX_USER_ACTIONS2) {
|
|
7875
8989
|
userActionCount++;
|
|
7876
8990
|
const actionResult = await handleNextAction(response.next_action);
|
|
7877
8991
|
const verifyResponse = await callVerifyEndpoint(apiBaseUrl, secureToken, checkoutRequestId);
|
|
@@ -7891,21 +9005,21 @@ var PaymentKit = (() => {
|
|
|
7891
9005
|
}
|
|
7892
9006
|
return toGooglePayResult(verifyResponse, secureToken);
|
|
7893
9007
|
}
|
|
7894
|
-
if (userActionCount >=
|
|
9008
|
+
if (userActionCount >= MAX_USER_ACTIONS2) {
|
|
7895
9009
|
return { errors: { google_pay: "Too many authentication attempts. Please try again." } };
|
|
7896
9010
|
}
|
|
7897
9011
|
return toGooglePayResult(response, secureToken);
|
|
7898
9012
|
}
|
|
7899
|
-
var
|
|
9013
|
+
var defSubmitPayment3 = (states) => {
|
|
7900
9014
|
const submitPayment = async (_fields, options) => {
|
|
7901
9015
|
const { apiBaseUrl, secureToken, environment } = states;
|
|
7902
9016
|
const gpayOptions = options;
|
|
7903
|
-
const validationError =
|
|
9017
|
+
const validationError = validateOptions2(gpayOptions);
|
|
7904
9018
|
if (validationError) {
|
|
7905
9019
|
return { errors: validationError };
|
|
7906
9020
|
}
|
|
7907
9021
|
try {
|
|
7908
|
-
const mockScenarioStr =
|
|
9022
|
+
const mockScenarioStr = getMockScenarioStr2(gpayOptions.mockScenario);
|
|
7909
9023
|
const checkoutRequestId = getOrCreateCheckoutRequestId(environment);
|
|
7910
9024
|
console.log(`[GooglePay] Using checkout_request_id: ${checkoutRequestId}`);
|
|
7911
9025
|
const startResult = await callStartEndpoint(
|
|
@@ -7924,10 +9038,16 @@ var PaymentKit = (() => {
|
|
|
7924
9038
|
if (!stripeResult.success) {
|
|
7925
9039
|
return { errors: { google_pay: stripeResult.error } };
|
|
7926
9040
|
}
|
|
7927
|
-
return await confirmStripeGooglePay(
|
|
9041
|
+
return await confirmStripeGooglePay(
|
|
9042
|
+
apiBaseUrl,
|
|
9043
|
+
secureToken,
|
|
9044
|
+
mockScenarioStr,
|
|
9045
|
+
checkoutRequestId,
|
|
9046
|
+
stripeResult.payerEmail
|
|
9047
|
+
);
|
|
7928
9048
|
}
|
|
7929
9049
|
if (startData.processor === "airwallex") {
|
|
7930
|
-
const airwallexResult = await
|
|
9050
|
+
const airwallexResult = await runAirwallexFlow2(startData, gpayOptions.mockScenario);
|
|
7931
9051
|
if (!airwallexResult.success) {
|
|
7932
9052
|
return { errors: { google_pay: airwallexResult.error } };
|
|
7933
9053
|
}
|
|
@@ -7954,7 +9074,7 @@ var PaymentKit = (() => {
|
|
|
7954
9074
|
name: "google_pay",
|
|
7955
9075
|
externalFuncs: {},
|
|
7956
9076
|
internalFuncs: {
|
|
7957
|
-
submitPayment:
|
|
9077
|
+
submitPayment: defSubmitPayment3(paymentKitStates),
|
|
7958
9078
|
cleanup: () => {
|
|
7959
9079
|
}
|
|
7960
9080
|
}
|
|
@@ -7963,7 +9083,7 @@ var PaymentKit = (() => {
|
|
|
7963
9083
|
var google_pay_default = GooglePayPaymentMethod;
|
|
7964
9084
|
|
|
7965
9085
|
// src/payment-methods/paypal.ts
|
|
7966
|
-
var
|
|
9086
|
+
var defSubmitPayment4 = (states) => {
|
|
7967
9087
|
const submitPayment = async (_fields, options) => {
|
|
7968
9088
|
const { apiBaseUrl, secureToken, environment } = states;
|
|
7969
9089
|
const paypalOptions = options;
|
|
@@ -8092,7 +9212,7 @@ var PaymentKit = (() => {
|
|
|
8092
9212
|
// PayPal doesn't need createElement like card iframes
|
|
8093
9213
|
},
|
|
8094
9214
|
internalFuncs: {
|
|
8095
|
-
submitPayment:
|
|
9215
|
+
submitPayment: defSubmitPayment4(localStates),
|
|
8096
9216
|
cleanup: () => {
|
|
8097
9217
|
if (localStates.pollInterval) {
|
|
8098
9218
|
clearInterval(localStates.pollInterval);
|
|
@@ -8109,6 +9229,7 @@ var PaymentKit = (() => {
|
|
|
8109
9229
|
// src/cdn.ts
|
|
8110
9230
|
var cdn_default = index_default;
|
|
8111
9231
|
var PaymentMethods = {
|
|
9232
|
+
applePay: apple_pay_default,
|
|
8112
9233
|
card: card_default,
|
|
8113
9234
|
googlePay: google_pay_default,
|
|
8114
9235
|
paypal: paypal_default
|