@economist/web-apple-pay 1.6.0 → 1.6.2-beta.1
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/index.js +51 -6
- package/dist/src/apple-pay-button.js +45 -6
- package/dist/src/apple-pay-button.stories.js +52 -6
- package/dist/src/apple-pay-modal.stories.js +45 -6
- package/dist/src/clients/payment-checkout/apple-session.js +17 -1
- package/dist/src/clients/payment-checkout/config.js +7 -0
- package/dist/src/clients/payment-checkout/detects.js +10 -1
- package/dist/src/clients/payment-checkout/index.js +1 -1
- package/dist/src/clients/payment-checkout/payment-handler.js +14 -0
- package/dist/src/clients/payment-checkout/types.d.ts +6 -32
- package/dist/src/index.js +51 -6
- package/dist/src/stories/utils/story-env.js +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -444,6 +444,12 @@ var apple_pay_button_template_default = '<style>\n /* Use CSS variables for lay
|
|
|
444
444
|
// src/clients/payment-checkout/config.ts
|
|
445
445
|
var runtimeConfig = null;
|
|
446
446
|
var configureApplePay = (config) => {
|
|
447
|
+
console.log("[web-apple-pay] configureApplePay called", {
|
|
448
|
+
merchantId: config.merchantId,
|
|
449
|
+
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
450
|
+
debugBypassEnabled: config.debugBypassEnabled,
|
|
451
|
+
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
452
|
+
});
|
|
447
453
|
runtimeConfig = {
|
|
448
454
|
...config
|
|
449
455
|
};
|
|
@@ -458,21 +464,27 @@ var isAppleDeviceOrSafari = () => {
|
|
|
458
464
|
};
|
|
459
465
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
460
466
|
var isApplePayAvailable = async () => {
|
|
467
|
+
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
461
468
|
if (bypassApplePayChecks()) {
|
|
469
|
+
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
462
470
|
return true;
|
|
463
471
|
}
|
|
464
472
|
if (!isAppleDeviceOrSafari()) {
|
|
473
|
+
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
465
474
|
return false;
|
|
466
475
|
}
|
|
467
476
|
const applePaySession = window.ApplePaySession;
|
|
468
477
|
if (!applePaySession) {
|
|
478
|
+
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
469
479
|
return false;
|
|
470
480
|
}
|
|
471
481
|
try {
|
|
472
482
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
483
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
473
484
|
return false;
|
|
474
485
|
}
|
|
475
486
|
if (!applePaySession.canMakePayments()) {
|
|
487
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
476
488
|
return false;
|
|
477
489
|
}
|
|
478
490
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -482,7 +494,10 @@ var isApplePayAvailable = async () => {
|
|
|
482
494
|
);
|
|
483
495
|
return false;
|
|
484
496
|
}
|
|
485
|
-
|
|
497
|
+
console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
|
|
498
|
+
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
499
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
500
|
+
return result;
|
|
486
501
|
} catch (error) {
|
|
487
502
|
console.error("Error checking Apple Pay active card status:", error);
|
|
488
503
|
return false;
|
|
@@ -545,7 +560,7 @@ var getPaymentOptions = (data) => {
|
|
|
545
560
|
const { sku, countryCode, currencyCode, checkoutUrl } = data;
|
|
546
561
|
const params = new URLSearchParams({ checkoutUrl });
|
|
547
562
|
return apiFetch(
|
|
548
|
-
`/
|
|
563
|
+
`/v1/wallet/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
|
|
549
564
|
{ method: "GET" }
|
|
550
565
|
);
|
|
551
566
|
};
|
|
@@ -744,6 +759,13 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
|
744
759
|
|
|
745
760
|
// src/clients/payment-checkout/apple-session.ts
|
|
746
761
|
function startApplePaySession(config) {
|
|
762
|
+
console.log("[web-apple-pay] startApplePaySession", {
|
|
763
|
+
skuId: config.skuId,
|
|
764
|
+
countryCode: config.countryCode,
|
|
765
|
+
currencyCode: config.currencyCode,
|
|
766
|
+
totalAmount: config.totalAmount,
|
|
767
|
+
userLoggedIn: config.userLoggedIn
|
|
768
|
+
});
|
|
747
769
|
const paymentRequest = {
|
|
748
770
|
countryCode: config.countryCode,
|
|
749
771
|
currencyCode: config.currencyCode,
|
|
@@ -759,9 +781,11 @@ function startApplePaySession(config) {
|
|
|
759
781
|
};
|
|
760
782
|
const session = new ApplePaySession(3, paymentRequest);
|
|
761
783
|
session.onvalidatemerchant = async (event) => {
|
|
784
|
+
console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
|
|
762
785
|
try {
|
|
763
786
|
const validationHost = new URL(event.validationURL).host;
|
|
764
787
|
if (!validationHost.endsWith("apple.com")) {
|
|
788
|
+
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
765
789
|
trackFallbackCheckout(config.skuId);
|
|
766
790
|
session.abort();
|
|
767
791
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -772,11 +796,13 @@ function startApplePaySession(config) {
|
|
|
772
796
|
return;
|
|
773
797
|
}
|
|
774
798
|
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
799
|
+
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
775
800
|
const response = await validateAppleMerchant({
|
|
776
801
|
validationURL: event.validationURL,
|
|
777
802
|
recaptchaToken
|
|
778
803
|
});
|
|
779
804
|
if (!response?.merchantSession) {
|
|
805
|
+
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
780
806
|
trackFallbackCheckout(config.skuId);
|
|
781
807
|
session.abort();
|
|
782
808
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -786,8 +812,10 @@ function startApplePaySession(config) {
|
|
|
786
812
|
});
|
|
787
813
|
return;
|
|
788
814
|
}
|
|
815
|
+
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
789
816
|
session.completeMerchantValidation(response.merchantSession);
|
|
790
|
-
} catch {
|
|
817
|
+
} catch (err) {
|
|
818
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
791
819
|
trackFallbackCheckout(config.skuId);
|
|
792
820
|
session.abort();
|
|
793
821
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -798,12 +826,15 @@ function startApplePaySession(config) {
|
|
|
798
826
|
}
|
|
799
827
|
};
|
|
800
828
|
session.onpaymentauthorized = (event) => {
|
|
829
|
+
console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
|
|
801
830
|
trackWalletPaymentAuthorised(config.skuId);
|
|
802
831
|
config.onPaymentAuthorized(event, session);
|
|
803
832
|
};
|
|
804
833
|
session.oncancel = () => {
|
|
834
|
+
console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
|
|
805
835
|
config.onCancel?.();
|
|
806
836
|
};
|
|
837
|
+
console.log("[web-apple-pay] startApplePaySession: beginning session");
|
|
807
838
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
808
839
|
session.begin();
|
|
809
840
|
}
|
|
@@ -982,12 +1013,16 @@ function handleStructuredError(ctx) {
|
|
|
982
1013
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
983
1014
|
const { skuId, returnUrl, queryString } = config;
|
|
984
1015
|
let validatedEmail;
|
|
1016
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
985
1017
|
try {
|
|
1018
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
986
1019
|
validatedEmail = validateContacts(
|
|
987
1020
|
event,
|
|
988
1021
|
sessionData,
|
|
989
1022
|
config.supportedBillingCountries
|
|
990
1023
|
);
|
|
1024
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
1025
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
991
1026
|
const result = await performPurchase({
|
|
992
1027
|
applePayToken: event.payment.token,
|
|
993
1028
|
skuId: config.skuId,
|
|
@@ -997,6 +1032,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
997
1032
|
},
|
|
998
1033
|
recaptchaTokens: config.recaptchaTokens
|
|
999
1034
|
});
|
|
1035
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1036
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
1000
1037
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1001
1038
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1002
1039
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1009,17 +1046,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1009
1046
|
});
|
|
1010
1047
|
} catch (err) {
|
|
1011
1048
|
if (err instanceof ContactValidationError) {
|
|
1049
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1012
1050
|
failApplePaySession(session, err.errors);
|
|
1013
1051
|
return;
|
|
1014
1052
|
}
|
|
1015
1053
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1016
1054
|
const walletError = parseWalletApiError(err);
|
|
1055
|
+
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1056
|
+
skuId,
|
|
1057
|
+
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1058
|
+
message: walletError?.message
|
|
1059
|
+
});
|
|
1017
1060
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1018
1061
|
failApplePaySession(session);
|
|
1019
1062
|
if (!walletError) {
|
|
1063
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1020
1064
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1021
1065
|
return;
|
|
1022
1066
|
}
|
|
1067
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1023
1068
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1024
1069
|
}
|
|
1025
1070
|
}
|
|
@@ -1464,12 +1509,12 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1464
1509
|
);
|
|
1465
1510
|
}
|
|
1466
1511
|
/**
|
|
1467
|
-
* Returns `true` (hide) when
|
|
1512
|
+
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
1468
1513
|
* for this offer. The response is cached and reused in `#initiateApplePay`.
|
|
1469
1514
|
*/
|
|
1470
1515
|
async #fetchAndCacheOptions() {
|
|
1471
1516
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1472
|
-
if (!this.#paymentOptions?.
|
|
1517
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1473
1518
|
this.style.display = "none";
|
|
1474
1519
|
return true;
|
|
1475
1520
|
}
|
|
@@ -1545,7 +1590,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1545
1590
|
return {
|
|
1546
1591
|
countryCode: country,
|
|
1547
1592
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1548
|
-
supportedNetworks: paymentOptions.
|
|
1593
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1549
1594
|
totalAmount,
|
|
1550
1595
|
totalLabel: TOTAL_LABEL,
|
|
1551
1596
|
skuId,
|
|
@@ -453,21 +453,27 @@ var isAppleDeviceOrSafari = () => {
|
|
|
453
453
|
};
|
|
454
454
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
455
455
|
var isApplePayAvailable = async () => {
|
|
456
|
+
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
456
457
|
if (bypassApplePayChecks()) {
|
|
458
|
+
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
457
459
|
return true;
|
|
458
460
|
}
|
|
459
461
|
if (!isAppleDeviceOrSafari()) {
|
|
462
|
+
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
460
463
|
return false;
|
|
461
464
|
}
|
|
462
465
|
const applePaySession = window.ApplePaySession;
|
|
463
466
|
if (!applePaySession) {
|
|
467
|
+
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
464
468
|
return false;
|
|
465
469
|
}
|
|
466
470
|
try {
|
|
467
471
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
472
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
468
473
|
return false;
|
|
469
474
|
}
|
|
470
475
|
if (!applePaySession.canMakePayments()) {
|
|
476
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
471
477
|
return false;
|
|
472
478
|
}
|
|
473
479
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -477,7 +483,10 @@ var isApplePayAvailable = async () => {
|
|
|
477
483
|
);
|
|
478
484
|
return false;
|
|
479
485
|
}
|
|
480
|
-
|
|
486
|
+
console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
|
|
487
|
+
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
488
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
489
|
+
return result;
|
|
481
490
|
} catch (error) {
|
|
482
491
|
console.error("Error checking Apple Pay active card status:", error);
|
|
483
492
|
return false;
|
|
@@ -540,7 +549,7 @@ var getPaymentOptions = (data) => {
|
|
|
540
549
|
const { sku, countryCode, currencyCode, checkoutUrl } = data;
|
|
541
550
|
const params = new URLSearchParams({ checkoutUrl });
|
|
542
551
|
return apiFetch(
|
|
543
|
-
`/
|
|
552
|
+
`/v1/wallet/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
|
|
544
553
|
{ method: "GET" }
|
|
545
554
|
);
|
|
546
555
|
};
|
|
@@ -739,6 +748,13 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
|
739
748
|
|
|
740
749
|
// src/clients/payment-checkout/apple-session.ts
|
|
741
750
|
function startApplePaySession(config) {
|
|
751
|
+
console.log("[web-apple-pay] startApplePaySession", {
|
|
752
|
+
skuId: config.skuId,
|
|
753
|
+
countryCode: config.countryCode,
|
|
754
|
+
currencyCode: config.currencyCode,
|
|
755
|
+
totalAmount: config.totalAmount,
|
|
756
|
+
userLoggedIn: config.userLoggedIn
|
|
757
|
+
});
|
|
742
758
|
const paymentRequest = {
|
|
743
759
|
countryCode: config.countryCode,
|
|
744
760
|
currencyCode: config.currencyCode,
|
|
@@ -754,9 +770,11 @@ function startApplePaySession(config) {
|
|
|
754
770
|
};
|
|
755
771
|
const session = new ApplePaySession(3, paymentRequest);
|
|
756
772
|
session.onvalidatemerchant = async (event) => {
|
|
773
|
+
console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
|
|
757
774
|
try {
|
|
758
775
|
const validationHost = new URL(event.validationURL).host;
|
|
759
776
|
if (!validationHost.endsWith("apple.com")) {
|
|
777
|
+
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
760
778
|
trackFallbackCheckout(config.skuId);
|
|
761
779
|
session.abort();
|
|
762
780
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -767,11 +785,13 @@ function startApplePaySession(config) {
|
|
|
767
785
|
return;
|
|
768
786
|
}
|
|
769
787
|
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
788
|
+
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
770
789
|
const response = await validateAppleMerchant({
|
|
771
790
|
validationURL: event.validationURL,
|
|
772
791
|
recaptchaToken
|
|
773
792
|
});
|
|
774
793
|
if (!response?.merchantSession) {
|
|
794
|
+
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
775
795
|
trackFallbackCheckout(config.skuId);
|
|
776
796
|
session.abort();
|
|
777
797
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -781,8 +801,10 @@ function startApplePaySession(config) {
|
|
|
781
801
|
});
|
|
782
802
|
return;
|
|
783
803
|
}
|
|
804
|
+
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
784
805
|
session.completeMerchantValidation(response.merchantSession);
|
|
785
|
-
} catch {
|
|
806
|
+
} catch (err) {
|
|
807
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
786
808
|
trackFallbackCheckout(config.skuId);
|
|
787
809
|
session.abort();
|
|
788
810
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -793,12 +815,15 @@ function startApplePaySession(config) {
|
|
|
793
815
|
}
|
|
794
816
|
};
|
|
795
817
|
session.onpaymentauthorized = (event) => {
|
|
818
|
+
console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
|
|
796
819
|
trackWalletPaymentAuthorised(config.skuId);
|
|
797
820
|
config.onPaymentAuthorized(event, session);
|
|
798
821
|
};
|
|
799
822
|
session.oncancel = () => {
|
|
823
|
+
console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
|
|
800
824
|
config.onCancel?.();
|
|
801
825
|
};
|
|
826
|
+
console.log("[web-apple-pay] startApplePaySession: beginning session");
|
|
802
827
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
803
828
|
session.begin();
|
|
804
829
|
}
|
|
@@ -977,12 +1002,16 @@ function handleStructuredError(ctx) {
|
|
|
977
1002
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
978
1003
|
const { skuId, returnUrl, queryString } = config;
|
|
979
1004
|
let validatedEmail;
|
|
1005
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
980
1006
|
try {
|
|
1007
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
981
1008
|
validatedEmail = validateContacts(
|
|
982
1009
|
event,
|
|
983
1010
|
sessionData,
|
|
984
1011
|
config.supportedBillingCountries
|
|
985
1012
|
);
|
|
1013
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
1014
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
986
1015
|
const result = await performPurchase({
|
|
987
1016
|
applePayToken: event.payment.token,
|
|
988
1017
|
skuId: config.skuId,
|
|
@@ -992,6 +1021,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
992
1021
|
},
|
|
993
1022
|
recaptchaTokens: config.recaptchaTokens
|
|
994
1023
|
});
|
|
1024
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1025
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
995
1026
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
996
1027
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
997
1028
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1004,17 +1035,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1004
1035
|
});
|
|
1005
1036
|
} catch (err) {
|
|
1006
1037
|
if (err instanceof ContactValidationError) {
|
|
1038
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1007
1039
|
failApplePaySession(session, err.errors);
|
|
1008
1040
|
return;
|
|
1009
1041
|
}
|
|
1010
1042
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1011
1043
|
const walletError = parseWalletApiError(err);
|
|
1044
|
+
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1045
|
+
skuId,
|
|
1046
|
+
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1047
|
+
message: walletError?.message
|
|
1048
|
+
});
|
|
1012
1049
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1013
1050
|
failApplePaySession(session);
|
|
1014
1051
|
if (!walletError) {
|
|
1052
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1015
1053
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1016
1054
|
return;
|
|
1017
1055
|
}
|
|
1056
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1018
1057
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1019
1058
|
}
|
|
1020
1059
|
}
|
|
@@ -1459,12 +1498,12 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1459
1498
|
);
|
|
1460
1499
|
}
|
|
1461
1500
|
/**
|
|
1462
|
-
* Returns `true` (hide) when
|
|
1501
|
+
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
1463
1502
|
* for this offer. The response is cached and reused in `#initiateApplePay`.
|
|
1464
1503
|
*/
|
|
1465
1504
|
async #fetchAndCacheOptions() {
|
|
1466
1505
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1467
|
-
if (!this.#paymentOptions?.
|
|
1506
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1468
1507
|
this.style.display = "none";
|
|
1469
1508
|
return true;
|
|
1470
1509
|
}
|
|
@@ -1540,7 +1579,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1540
1579
|
return {
|
|
1541
1580
|
countryCode: country,
|
|
1542
1581
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1543
|
-
supportedNetworks: paymentOptions.
|
|
1582
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1544
1583
|
totalAmount,
|
|
1545
1584
|
totalLabel: TOTAL_LABEL,
|
|
1546
1585
|
skuId,
|
|
@@ -444,12 +444,19 @@ var apple_pay_button_template_default = '<style>\n /* Use CSS variables for lay
|
|
|
444
444
|
// src/clients/payment-checkout/config.ts
|
|
445
445
|
var runtimeConfig = null;
|
|
446
446
|
var configureApplePay = (config) => {
|
|
447
|
+
console.log("[web-apple-pay] configureApplePay called", {
|
|
448
|
+
merchantId: config.merchantId,
|
|
449
|
+
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
450
|
+
debugBypassEnabled: config.debugBypassEnabled,
|
|
451
|
+
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
452
|
+
});
|
|
447
453
|
runtimeConfig = {
|
|
448
454
|
...config
|
|
449
455
|
};
|
|
450
456
|
};
|
|
451
457
|
var getApplePayConfig = () => runtimeConfig;
|
|
452
458
|
var resetApplePayConfig = () => {
|
|
459
|
+
console.log("[web-apple-pay] resetApplePayConfig called");
|
|
453
460
|
runtimeConfig = null;
|
|
454
461
|
};
|
|
455
462
|
|
|
@@ -461,21 +468,27 @@ var isAppleDeviceOrSafari = () => {
|
|
|
461
468
|
};
|
|
462
469
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
463
470
|
var isApplePayAvailable = async () => {
|
|
471
|
+
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
464
472
|
if (bypassApplePayChecks()) {
|
|
473
|
+
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
465
474
|
return true;
|
|
466
475
|
}
|
|
467
476
|
if (!isAppleDeviceOrSafari()) {
|
|
477
|
+
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
468
478
|
return false;
|
|
469
479
|
}
|
|
470
480
|
const applePaySession = window.ApplePaySession;
|
|
471
481
|
if (!applePaySession) {
|
|
482
|
+
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
472
483
|
return false;
|
|
473
484
|
}
|
|
474
485
|
try {
|
|
475
486
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
487
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
476
488
|
return false;
|
|
477
489
|
}
|
|
478
490
|
if (!applePaySession.canMakePayments()) {
|
|
491
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
479
492
|
return false;
|
|
480
493
|
}
|
|
481
494
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -485,7 +498,10 @@ var isApplePayAvailable = async () => {
|
|
|
485
498
|
);
|
|
486
499
|
return false;
|
|
487
500
|
}
|
|
488
|
-
|
|
501
|
+
console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
|
|
502
|
+
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
503
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
504
|
+
return result;
|
|
489
505
|
} catch (error) {
|
|
490
506
|
console.error("Error checking Apple Pay active card status:", error);
|
|
491
507
|
return false;
|
|
@@ -548,7 +564,7 @@ var getPaymentOptions = (data) => {
|
|
|
548
564
|
const { sku, countryCode, currencyCode, checkoutUrl } = data;
|
|
549
565
|
const params = new URLSearchParams({ checkoutUrl });
|
|
550
566
|
return apiFetch(
|
|
551
|
-
`/
|
|
567
|
+
`/v1/wallet/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
|
|
552
568
|
{ method: "GET" }
|
|
553
569
|
);
|
|
554
570
|
};
|
|
@@ -747,6 +763,13 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
|
747
763
|
|
|
748
764
|
// src/clients/payment-checkout/apple-session.ts
|
|
749
765
|
function startApplePaySession(config) {
|
|
766
|
+
console.log("[web-apple-pay] startApplePaySession", {
|
|
767
|
+
skuId: config.skuId,
|
|
768
|
+
countryCode: config.countryCode,
|
|
769
|
+
currencyCode: config.currencyCode,
|
|
770
|
+
totalAmount: config.totalAmount,
|
|
771
|
+
userLoggedIn: config.userLoggedIn
|
|
772
|
+
});
|
|
750
773
|
const paymentRequest = {
|
|
751
774
|
countryCode: config.countryCode,
|
|
752
775
|
currencyCode: config.currencyCode,
|
|
@@ -762,9 +785,11 @@ function startApplePaySession(config) {
|
|
|
762
785
|
};
|
|
763
786
|
const session = new ApplePaySession(3, paymentRequest);
|
|
764
787
|
session.onvalidatemerchant = async (event) => {
|
|
788
|
+
console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
|
|
765
789
|
try {
|
|
766
790
|
const validationHost = new URL(event.validationURL).host;
|
|
767
791
|
if (!validationHost.endsWith("apple.com")) {
|
|
792
|
+
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
768
793
|
trackFallbackCheckout(config.skuId);
|
|
769
794
|
session.abort();
|
|
770
795
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -775,11 +800,13 @@ function startApplePaySession(config) {
|
|
|
775
800
|
return;
|
|
776
801
|
}
|
|
777
802
|
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
803
|
+
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
778
804
|
const response = await validateAppleMerchant({
|
|
779
805
|
validationURL: event.validationURL,
|
|
780
806
|
recaptchaToken
|
|
781
807
|
});
|
|
782
808
|
if (!response?.merchantSession) {
|
|
809
|
+
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
783
810
|
trackFallbackCheckout(config.skuId);
|
|
784
811
|
session.abort();
|
|
785
812
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -789,8 +816,10 @@ function startApplePaySession(config) {
|
|
|
789
816
|
});
|
|
790
817
|
return;
|
|
791
818
|
}
|
|
819
|
+
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
792
820
|
session.completeMerchantValidation(response.merchantSession);
|
|
793
|
-
} catch {
|
|
821
|
+
} catch (err) {
|
|
822
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
794
823
|
trackFallbackCheckout(config.skuId);
|
|
795
824
|
session.abort();
|
|
796
825
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -801,12 +830,15 @@ function startApplePaySession(config) {
|
|
|
801
830
|
}
|
|
802
831
|
};
|
|
803
832
|
session.onpaymentauthorized = (event) => {
|
|
833
|
+
console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
|
|
804
834
|
trackWalletPaymentAuthorised(config.skuId);
|
|
805
835
|
config.onPaymentAuthorized(event, session);
|
|
806
836
|
};
|
|
807
837
|
session.oncancel = () => {
|
|
838
|
+
console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
|
|
808
839
|
config.onCancel?.();
|
|
809
840
|
};
|
|
841
|
+
console.log("[web-apple-pay] startApplePaySession: beginning session");
|
|
810
842
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
811
843
|
session.begin();
|
|
812
844
|
}
|
|
@@ -985,12 +1017,16 @@ function handleStructuredError(ctx) {
|
|
|
985
1017
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
986
1018
|
const { skuId, returnUrl, queryString } = config;
|
|
987
1019
|
let validatedEmail;
|
|
1020
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
988
1021
|
try {
|
|
1022
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
989
1023
|
validatedEmail = validateContacts(
|
|
990
1024
|
event,
|
|
991
1025
|
sessionData,
|
|
992
1026
|
config.supportedBillingCountries
|
|
993
1027
|
);
|
|
1028
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
1029
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
994
1030
|
const result = await performPurchase({
|
|
995
1031
|
applePayToken: event.payment.token,
|
|
996
1032
|
skuId: config.skuId,
|
|
@@ -1000,6 +1036,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1000
1036
|
},
|
|
1001
1037
|
recaptchaTokens: config.recaptchaTokens
|
|
1002
1038
|
});
|
|
1039
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1040
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
1003
1041
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1004
1042
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1005
1043
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1012,17 +1050,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1012
1050
|
});
|
|
1013
1051
|
} catch (err) {
|
|
1014
1052
|
if (err instanceof ContactValidationError) {
|
|
1053
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1015
1054
|
failApplePaySession(session, err.errors);
|
|
1016
1055
|
return;
|
|
1017
1056
|
}
|
|
1018
1057
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1019
1058
|
const walletError = parseWalletApiError(err);
|
|
1059
|
+
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1060
|
+
skuId,
|
|
1061
|
+
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1062
|
+
message: walletError?.message
|
|
1063
|
+
});
|
|
1020
1064
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1021
1065
|
failApplePaySession(session);
|
|
1022
1066
|
if (!walletError) {
|
|
1067
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1023
1068
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1024
1069
|
return;
|
|
1025
1070
|
}
|
|
1071
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1026
1072
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1027
1073
|
}
|
|
1028
1074
|
}
|
|
@@ -1467,12 +1513,12 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1467
1513
|
);
|
|
1468
1514
|
}
|
|
1469
1515
|
/**
|
|
1470
|
-
* Returns `true` (hide) when
|
|
1516
|
+
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
1471
1517
|
* for this offer. The response is cached and reused in `#initiateApplePay`.
|
|
1472
1518
|
*/
|
|
1473
1519
|
async #fetchAndCacheOptions() {
|
|
1474
1520
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1475
|
-
if (!this.#paymentOptions?.
|
|
1521
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1476
1522
|
this.style.display = "none";
|
|
1477
1523
|
return true;
|
|
1478
1524
|
}
|
|
@@ -1548,7 +1594,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1548
1594
|
return {
|
|
1549
1595
|
countryCode: country,
|
|
1550
1596
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1551
|
-
supportedNetworks: paymentOptions.
|
|
1597
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1552
1598
|
totalAmount,
|
|
1553
1599
|
totalLabel: TOTAL_LABEL,
|
|
1554
1600
|
skuId,
|
|
@@ -453,21 +453,27 @@ var isAppleDeviceOrSafari = () => {
|
|
|
453
453
|
};
|
|
454
454
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
455
455
|
var isApplePayAvailable = async () => {
|
|
456
|
+
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
456
457
|
if (bypassApplePayChecks()) {
|
|
458
|
+
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
457
459
|
return true;
|
|
458
460
|
}
|
|
459
461
|
if (!isAppleDeviceOrSafari()) {
|
|
462
|
+
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
460
463
|
return false;
|
|
461
464
|
}
|
|
462
465
|
const applePaySession = window.ApplePaySession;
|
|
463
466
|
if (!applePaySession) {
|
|
467
|
+
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
464
468
|
return false;
|
|
465
469
|
}
|
|
466
470
|
try {
|
|
467
471
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
472
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
468
473
|
return false;
|
|
469
474
|
}
|
|
470
475
|
if (!applePaySession.canMakePayments()) {
|
|
476
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
471
477
|
return false;
|
|
472
478
|
}
|
|
473
479
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -477,7 +483,10 @@ var isApplePayAvailable = async () => {
|
|
|
477
483
|
);
|
|
478
484
|
return false;
|
|
479
485
|
}
|
|
480
|
-
|
|
486
|
+
console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
|
|
487
|
+
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
488
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
489
|
+
return result;
|
|
481
490
|
} catch (error) {
|
|
482
491
|
console.error("Error checking Apple Pay active card status:", error);
|
|
483
492
|
return false;
|
|
@@ -540,7 +549,7 @@ var getPaymentOptions = (data) => {
|
|
|
540
549
|
const { sku, countryCode, currencyCode, checkoutUrl } = data;
|
|
541
550
|
const params = new URLSearchParams({ checkoutUrl });
|
|
542
551
|
return apiFetch(
|
|
543
|
-
`/
|
|
552
|
+
`/v1/wallet/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
|
|
544
553
|
{ method: "GET" }
|
|
545
554
|
);
|
|
546
555
|
};
|
|
@@ -739,6 +748,13 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
|
739
748
|
|
|
740
749
|
// src/clients/payment-checkout/apple-session.ts
|
|
741
750
|
function startApplePaySession(config) {
|
|
751
|
+
console.log("[web-apple-pay] startApplePaySession", {
|
|
752
|
+
skuId: config.skuId,
|
|
753
|
+
countryCode: config.countryCode,
|
|
754
|
+
currencyCode: config.currencyCode,
|
|
755
|
+
totalAmount: config.totalAmount,
|
|
756
|
+
userLoggedIn: config.userLoggedIn
|
|
757
|
+
});
|
|
742
758
|
const paymentRequest = {
|
|
743
759
|
countryCode: config.countryCode,
|
|
744
760
|
currencyCode: config.currencyCode,
|
|
@@ -754,9 +770,11 @@ function startApplePaySession(config) {
|
|
|
754
770
|
};
|
|
755
771
|
const session = new ApplePaySession(3, paymentRequest);
|
|
756
772
|
session.onvalidatemerchant = async (event) => {
|
|
773
|
+
console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
|
|
757
774
|
try {
|
|
758
775
|
const validationHost = new URL(event.validationURL).host;
|
|
759
776
|
if (!validationHost.endsWith("apple.com")) {
|
|
777
|
+
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
760
778
|
trackFallbackCheckout(config.skuId);
|
|
761
779
|
session.abort();
|
|
762
780
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -767,11 +785,13 @@ function startApplePaySession(config) {
|
|
|
767
785
|
return;
|
|
768
786
|
}
|
|
769
787
|
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
788
|
+
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
770
789
|
const response = await validateAppleMerchant({
|
|
771
790
|
validationURL: event.validationURL,
|
|
772
791
|
recaptchaToken
|
|
773
792
|
});
|
|
774
793
|
if (!response?.merchantSession) {
|
|
794
|
+
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
775
795
|
trackFallbackCheckout(config.skuId);
|
|
776
796
|
session.abort();
|
|
777
797
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -781,8 +801,10 @@ function startApplePaySession(config) {
|
|
|
781
801
|
});
|
|
782
802
|
return;
|
|
783
803
|
}
|
|
804
|
+
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
784
805
|
session.completeMerchantValidation(response.merchantSession);
|
|
785
|
-
} catch {
|
|
806
|
+
} catch (err) {
|
|
807
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
786
808
|
trackFallbackCheckout(config.skuId);
|
|
787
809
|
session.abort();
|
|
788
810
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -793,12 +815,15 @@ function startApplePaySession(config) {
|
|
|
793
815
|
}
|
|
794
816
|
};
|
|
795
817
|
session.onpaymentauthorized = (event) => {
|
|
818
|
+
console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
|
|
796
819
|
trackWalletPaymentAuthorised(config.skuId);
|
|
797
820
|
config.onPaymentAuthorized(event, session);
|
|
798
821
|
};
|
|
799
822
|
session.oncancel = () => {
|
|
823
|
+
console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
|
|
800
824
|
config.onCancel?.();
|
|
801
825
|
};
|
|
826
|
+
console.log("[web-apple-pay] startApplePaySession: beginning session");
|
|
802
827
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
803
828
|
session.begin();
|
|
804
829
|
}
|
|
@@ -977,12 +1002,16 @@ function handleStructuredError(ctx) {
|
|
|
977
1002
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
978
1003
|
const { skuId, returnUrl, queryString } = config;
|
|
979
1004
|
let validatedEmail;
|
|
1005
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
980
1006
|
try {
|
|
1007
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
981
1008
|
validatedEmail = validateContacts(
|
|
982
1009
|
event,
|
|
983
1010
|
sessionData,
|
|
984
1011
|
config.supportedBillingCountries
|
|
985
1012
|
);
|
|
1013
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
1014
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
986
1015
|
const result = await performPurchase({
|
|
987
1016
|
applePayToken: event.payment.token,
|
|
988
1017
|
skuId: config.skuId,
|
|
@@ -992,6 +1021,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
992
1021
|
},
|
|
993
1022
|
recaptchaTokens: config.recaptchaTokens
|
|
994
1023
|
});
|
|
1024
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1025
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
995
1026
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
996
1027
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
997
1028
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1004,17 +1035,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1004
1035
|
});
|
|
1005
1036
|
} catch (err) {
|
|
1006
1037
|
if (err instanceof ContactValidationError) {
|
|
1038
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1007
1039
|
failApplePaySession(session, err.errors);
|
|
1008
1040
|
return;
|
|
1009
1041
|
}
|
|
1010
1042
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1011
1043
|
const walletError = parseWalletApiError(err);
|
|
1044
|
+
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1045
|
+
skuId,
|
|
1046
|
+
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1047
|
+
message: walletError?.message
|
|
1048
|
+
});
|
|
1012
1049
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1013
1050
|
failApplePaySession(session);
|
|
1014
1051
|
if (!walletError) {
|
|
1052
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1015
1053
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1016
1054
|
return;
|
|
1017
1055
|
}
|
|
1056
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1018
1057
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1019
1058
|
}
|
|
1020
1059
|
}
|
|
@@ -1459,12 +1498,12 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1459
1498
|
);
|
|
1460
1499
|
}
|
|
1461
1500
|
/**
|
|
1462
|
-
* Returns `true` (hide) when
|
|
1501
|
+
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
1463
1502
|
* for this offer. The response is cached and reused in `#initiateApplePay`.
|
|
1464
1503
|
*/
|
|
1465
1504
|
async #fetchAndCacheOptions() {
|
|
1466
1505
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1467
|
-
if (!this.#paymentOptions?.
|
|
1506
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1468
1507
|
this.style.display = "none";
|
|
1469
1508
|
return true;
|
|
1470
1509
|
}
|
|
@@ -1540,7 +1579,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1540
1579
|
return {
|
|
1541
1580
|
countryCode: country,
|
|
1542
1581
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1543
|
-
supportedNetworks: paymentOptions.
|
|
1582
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1544
1583
|
totalAmount,
|
|
1545
1584
|
totalLabel: TOTAL_LABEL,
|
|
1546
1585
|
skuId,
|
|
@@ -159,6 +159,13 @@ var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment
|
|
|
159
159
|
|
|
160
160
|
// src/clients/payment-checkout/apple-session.ts
|
|
161
161
|
function startApplePaySession(config) {
|
|
162
|
+
console.log("[web-apple-pay] startApplePaySession", {
|
|
163
|
+
skuId: config.skuId,
|
|
164
|
+
countryCode: config.countryCode,
|
|
165
|
+
currencyCode: config.currencyCode,
|
|
166
|
+
totalAmount: config.totalAmount,
|
|
167
|
+
userLoggedIn: config.userLoggedIn
|
|
168
|
+
});
|
|
162
169
|
const paymentRequest = {
|
|
163
170
|
countryCode: config.countryCode,
|
|
164
171
|
currencyCode: config.currencyCode,
|
|
@@ -174,9 +181,11 @@ function startApplePaySession(config) {
|
|
|
174
181
|
};
|
|
175
182
|
const session = new ApplePaySession(3, paymentRequest);
|
|
176
183
|
session.onvalidatemerchant = async (event) => {
|
|
184
|
+
console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
|
|
177
185
|
try {
|
|
178
186
|
const validationHost = new URL(event.validationURL).host;
|
|
179
187
|
if (!validationHost.endsWith("apple.com")) {
|
|
188
|
+
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
180
189
|
trackFallbackCheckout(config.skuId);
|
|
181
190
|
session.abort();
|
|
182
191
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -187,11 +196,13 @@ function startApplePaySession(config) {
|
|
|
187
196
|
return;
|
|
188
197
|
}
|
|
189
198
|
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
199
|
+
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
190
200
|
const response = await validateAppleMerchant({
|
|
191
201
|
validationURL: event.validationURL,
|
|
192
202
|
recaptchaToken
|
|
193
203
|
});
|
|
194
204
|
if (!response?.merchantSession) {
|
|
205
|
+
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
195
206
|
trackFallbackCheckout(config.skuId);
|
|
196
207
|
session.abort();
|
|
197
208
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -201,8 +212,10 @@ function startApplePaySession(config) {
|
|
|
201
212
|
});
|
|
202
213
|
return;
|
|
203
214
|
}
|
|
215
|
+
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
204
216
|
session.completeMerchantValidation(response.merchantSession);
|
|
205
|
-
} catch {
|
|
217
|
+
} catch (err) {
|
|
218
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
206
219
|
trackFallbackCheckout(config.skuId);
|
|
207
220
|
session.abort();
|
|
208
221
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -213,12 +226,15 @@ function startApplePaySession(config) {
|
|
|
213
226
|
}
|
|
214
227
|
};
|
|
215
228
|
session.onpaymentauthorized = (event) => {
|
|
229
|
+
console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
|
|
216
230
|
trackWalletPaymentAuthorised(config.skuId);
|
|
217
231
|
config.onPaymentAuthorized(event, session);
|
|
218
232
|
};
|
|
219
233
|
session.oncancel = () => {
|
|
234
|
+
console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
|
|
220
235
|
config.onCancel?.();
|
|
221
236
|
};
|
|
237
|
+
console.log("[web-apple-pay] startApplePaySession: beginning session");
|
|
222
238
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
223
239
|
session.begin();
|
|
224
240
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
// src/clients/payment-checkout/config.ts
|
|
2
2
|
var runtimeConfig = null;
|
|
3
3
|
var configureApplePay = (config) => {
|
|
4
|
+
console.log("[web-apple-pay] configureApplePay called", {
|
|
5
|
+
merchantId: config.merchantId,
|
|
6
|
+
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
7
|
+
debugBypassEnabled: config.debugBypassEnabled,
|
|
8
|
+
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
9
|
+
});
|
|
4
10
|
runtimeConfig = {
|
|
5
11
|
...config
|
|
6
12
|
};
|
|
7
13
|
};
|
|
8
14
|
var getApplePayConfig = () => runtimeConfig;
|
|
9
15
|
var resetApplePayConfig = () => {
|
|
16
|
+
console.log("[web-apple-pay] resetApplePayConfig called");
|
|
10
17
|
runtimeConfig = null;
|
|
11
18
|
};
|
|
12
19
|
export {
|
|
@@ -10,21 +10,27 @@ var isAppleDeviceOrSafari = () => {
|
|
|
10
10
|
};
|
|
11
11
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
12
12
|
var isApplePayAvailable = async () => {
|
|
13
|
+
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
13
14
|
if (bypassApplePayChecks()) {
|
|
15
|
+
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
14
16
|
return true;
|
|
15
17
|
}
|
|
16
18
|
if (!isAppleDeviceOrSafari()) {
|
|
19
|
+
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
17
20
|
return false;
|
|
18
21
|
}
|
|
19
22
|
const applePaySession = window.ApplePaySession;
|
|
20
23
|
if (!applePaySession) {
|
|
24
|
+
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
21
25
|
return false;
|
|
22
26
|
}
|
|
23
27
|
try {
|
|
24
28
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
29
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
25
30
|
return false;
|
|
26
31
|
}
|
|
27
32
|
if (!applePaySession.canMakePayments()) {
|
|
33
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
28
34
|
return false;
|
|
29
35
|
}
|
|
30
36
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -34,7 +40,10 @@ var isApplePayAvailable = async () => {
|
|
|
34
40
|
);
|
|
35
41
|
return false;
|
|
36
42
|
}
|
|
37
|
-
|
|
43
|
+
console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
|
|
44
|
+
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
45
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
46
|
+
return result;
|
|
38
47
|
} catch (error) {
|
|
39
48
|
console.error("Error checking Apple Pay active card status:", error);
|
|
40
49
|
return false;
|
|
@@ -58,7 +58,7 @@ var getPaymentOptions = (data) => {
|
|
|
58
58
|
const { sku, countryCode, currencyCode, checkoutUrl } = data;
|
|
59
59
|
const params = new URLSearchParams({ checkoutUrl });
|
|
60
60
|
return apiFetch(
|
|
61
|
-
`/
|
|
61
|
+
`/v1/wallet/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
|
|
62
62
|
{ method: "GET" }
|
|
63
63
|
);
|
|
64
64
|
};
|
|
@@ -329,12 +329,16 @@ function handleStructuredError(ctx) {
|
|
|
329
329
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
330
330
|
const { skuId, returnUrl, queryString } = config;
|
|
331
331
|
let validatedEmail;
|
|
332
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
332
333
|
try {
|
|
334
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
333
335
|
validatedEmail = validateContacts(
|
|
334
336
|
event,
|
|
335
337
|
sessionData,
|
|
336
338
|
config.supportedBillingCountries
|
|
337
339
|
);
|
|
340
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
341
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
338
342
|
const result = await performPurchase({
|
|
339
343
|
applePayToken: event.payment.token,
|
|
340
344
|
skuId: config.skuId,
|
|
@@ -344,6 +348,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
344
348
|
},
|
|
345
349
|
recaptchaTokens: config.recaptchaTokens
|
|
346
350
|
});
|
|
351
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
352
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
347
353
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
348
354
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
349
355
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -356,17 +362,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
356
362
|
});
|
|
357
363
|
} catch (err) {
|
|
358
364
|
if (err instanceof ContactValidationError) {
|
|
365
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
359
366
|
failApplePaySession(session, err.errors);
|
|
360
367
|
return;
|
|
361
368
|
}
|
|
362
369
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
363
370
|
const walletError = parseWalletApiError(err);
|
|
371
|
+
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
372
|
+
skuId,
|
|
373
|
+
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
374
|
+
message: walletError?.message
|
|
375
|
+
});
|
|
364
376
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
365
377
|
failApplePaySession(session);
|
|
366
378
|
if (!walletError) {
|
|
379
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
367
380
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
368
381
|
return;
|
|
369
382
|
}
|
|
383
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
370
384
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
371
385
|
}
|
|
372
386
|
}
|
|
@@ -10,40 +10,14 @@ export type PaymentOptionsRequest = {
|
|
|
10
10
|
checkoutUrl: string;
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* Relevant subset of the wallet-payments-api BFF GET /v1/wallet/payment-options/sku/:sku/:countryCode/:currencyCode response.
|
|
14
|
+
* Only the apple_pay field is consumed by this package.
|
|
15
15
|
*/
|
|
16
16
|
export type PaymentOptionsResponse = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
supportedNetworks: string[];
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
payPal?: {
|
|
25
|
-
provider: string;
|
|
26
|
-
};
|
|
27
|
-
googlePay?: {
|
|
28
|
-
provider: string;
|
|
29
|
-
settings: {
|
|
30
|
-
supportedNetworks: string[];
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
creditDebit?: {
|
|
34
|
-
provider: string;
|
|
35
|
-
settings: {
|
|
36
|
-
tenantId: string;
|
|
37
|
-
id: string;
|
|
38
|
-
token: string;
|
|
39
|
-
signature: string;
|
|
40
|
-
key: string;
|
|
41
|
-
locale: string;
|
|
42
|
-
url: string;
|
|
43
|
-
paymentGateway: string;
|
|
44
|
-
height: number;
|
|
45
|
-
supportedNetworks: string[];
|
|
46
|
-
};
|
|
17
|
+
apple_pay?: {
|
|
18
|
+
provider: string;
|
|
19
|
+
settings: {
|
|
20
|
+
supported_networks: string[];
|
|
47
21
|
};
|
|
48
22
|
};
|
|
49
23
|
};
|
package/dist/src/index.js
CHANGED
|
@@ -444,6 +444,12 @@ var apple_pay_button_template_default = '<style>\n /* Use CSS variables for lay
|
|
|
444
444
|
// src/clients/payment-checkout/config.ts
|
|
445
445
|
var runtimeConfig = null;
|
|
446
446
|
var configureApplePay = (config) => {
|
|
447
|
+
console.log("[web-apple-pay] configureApplePay called", {
|
|
448
|
+
merchantId: config.merchantId,
|
|
449
|
+
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
450
|
+
debugBypassEnabled: config.debugBypassEnabled,
|
|
451
|
+
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
452
|
+
});
|
|
447
453
|
runtimeConfig = {
|
|
448
454
|
...config
|
|
449
455
|
};
|
|
@@ -458,21 +464,27 @@ var isAppleDeviceOrSafari = () => {
|
|
|
458
464
|
};
|
|
459
465
|
var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
|
|
460
466
|
var isApplePayAvailable = async () => {
|
|
467
|
+
console.log("[web-apple-pay] isApplePayAvailable: checking availability");
|
|
461
468
|
if (bypassApplePayChecks()) {
|
|
469
|
+
console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
|
|
462
470
|
return true;
|
|
463
471
|
}
|
|
464
472
|
if (!isAppleDeviceOrSafari()) {
|
|
473
|
+
console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
|
|
465
474
|
return false;
|
|
466
475
|
}
|
|
467
476
|
const applePaySession = window.ApplePaySession;
|
|
468
477
|
if (!applePaySession) {
|
|
478
|
+
console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
|
|
469
479
|
return false;
|
|
470
480
|
}
|
|
471
481
|
try {
|
|
472
482
|
if (typeof applePaySession.canMakePayments !== "function") {
|
|
483
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
|
|
473
484
|
return false;
|
|
474
485
|
}
|
|
475
486
|
if (!applePaySession.canMakePayments()) {
|
|
487
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
|
|
476
488
|
return false;
|
|
477
489
|
}
|
|
478
490
|
const merchantId = getApplePayConfig()?.merchantId;
|
|
@@ -482,7 +494,10 @@ var isApplePayAvailable = async () => {
|
|
|
482
494
|
);
|
|
483
495
|
return false;
|
|
484
496
|
}
|
|
485
|
-
|
|
497
|
+
console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
|
|
498
|
+
const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
|
|
499
|
+
console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
|
|
500
|
+
return result;
|
|
486
501
|
} catch (error) {
|
|
487
502
|
console.error("Error checking Apple Pay active card status:", error);
|
|
488
503
|
return false;
|
|
@@ -545,7 +560,7 @@ var getPaymentOptions = (data) => {
|
|
|
545
560
|
const { sku, countryCode, currencyCode, checkoutUrl } = data;
|
|
546
561
|
const params = new URLSearchParams({ checkoutUrl });
|
|
547
562
|
return apiFetch(
|
|
548
|
-
`/
|
|
563
|
+
`/v1/wallet/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
|
|
549
564
|
{ method: "GET" }
|
|
550
565
|
);
|
|
551
566
|
};
|
|
@@ -744,6 +759,13 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
|
744
759
|
|
|
745
760
|
// src/clients/payment-checkout/apple-session.ts
|
|
746
761
|
function startApplePaySession(config) {
|
|
762
|
+
console.log("[web-apple-pay] startApplePaySession", {
|
|
763
|
+
skuId: config.skuId,
|
|
764
|
+
countryCode: config.countryCode,
|
|
765
|
+
currencyCode: config.currencyCode,
|
|
766
|
+
totalAmount: config.totalAmount,
|
|
767
|
+
userLoggedIn: config.userLoggedIn
|
|
768
|
+
});
|
|
747
769
|
const paymentRequest = {
|
|
748
770
|
countryCode: config.countryCode,
|
|
749
771
|
currencyCode: config.currencyCode,
|
|
@@ -759,9 +781,11 @@ function startApplePaySession(config) {
|
|
|
759
781
|
};
|
|
760
782
|
const session = new ApplePaySession(3, paymentRequest);
|
|
761
783
|
session.onvalidatemerchant = async (event) => {
|
|
784
|
+
console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
|
|
762
785
|
try {
|
|
763
786
|
const validationHost = new URL(event.validationURL).host;
|
|
764
787
|
if (!validationHost.endsWith("apple.com")) {
|
|
788
|
+
console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
|
|
765
789
|
trackFallbackCheckout(config.skuId);
|
|
766
790
|
session.abort();
|
|
767
791
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -772,11 +796,13 @@ function startApplePaySession(config) {
|
|
|
772
796
|
return;
|
|
773
797
|
}
|
|
774
798
|
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
799
|
+
console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
|
|
775
800
|
const response = await validateAppleMerchant({
|
|
776
801
|
validationURL: event.validationURL,
|
|
777
802
|
recaptchaToken
|
|
778
803
|
});
|
|
779
804
|
if (!response?.merchantSession) {
|
|
805
|
+
console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
|
|
780
806
|
trackFallbackCheckout(config.skuId);
|
|
781
807
|
session.abort();
|
|
782
808
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -786,8 +812,10 @@ function startApplePaySession(config) {
|
|
|
786
812
|
});
|
|
787
813
|
return;
|
|
788
814
|
}
|
|
815
|
+
console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
|
|
789
816
|
session.completeMerchantValidation(response.merchantSession);
|
|
790
|
-
} catch {
|
|
817
|
+
} catch (err) {
|
|
818
|
+
console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
|
|
791
819
|
trackFallbackCheckout(config.skuId);
|
|
792
820
|
session.abort();
|
|
793
821
|
window.location.href = redirectToCheckoutFallback({
|
|
@@ -798,12 +826,15 @@ function startApplePaySession(config) {
|
|
|
798
826
|
}
|
|
799
827
|
};
|
|
800
828
|
session.onpaymentauthorized = (event) => {
|
|
829
|
+
console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
|
|
801
830
|
trackWalletPaymentAuthorised(config.skuId);
|
|
802
831
|
config.onPaymentAuthorized(event, session);
|
|
803
832
|
};
|
|
804
833
|
session.oncancel = () => {
|
|
834
|
+
console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
|
|
805
835
|
config.onCancel?.();
|
|
806
836
|
};
|
|
837
|
+
console.log("[web-apple-pay] startApplePaySession: beginning session");
|
|
807
838
|
trackWalletPaymentSheetOpen(config.skuId);
|
|
808
839
|
session.begin();
|
|
809
840
|
}
|
|
@@ -982,12 +1013,16 @@ function handleStructuredError(ctx) {
|
|
|
982
1013
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
983
1014
|
const { skuId, returnUrl, queryString } = config;
|
|
984
1015
|
let validatedEmail;
|
|
1016
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
|
|
985
1017
|
try {
|
|
1018
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
|
|
986
1019
|
validatedEmail = validateContacts(
|
|
987
1020
|
event,
|
|
988
1021
|
sessionData,
|
|
989
1022
|
config.supportedBillingCountries
|
|
990
1023
|
);
|
|
1024
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
|
|
1025
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
|
|
991
1026
|
const result = await performPurchase({
|
|
992
1027
|
applePayToken: event.payment.token,
|
|
993
1028
|
skuId: config.skuId,
|
|
@@ -997,6 +1032,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
997
1032
|
},
|
|
998
1033
|
recaptchaTokens: config.recaptchaTokens
|
|
999
1034
|
});
|
|
1035
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
|
|
1036
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
|
|
1000
1037
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1001
1038
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1002
1039
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
@@ -1009,17 +1046,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1009
1046
|
});
|
|
1010
1047
|
} catch (err) {
|
|
1011
1048
|
if (err instanceof ContactValidationError) {
|
|
1049
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
|
|
1012
1050
|
failApplePaySession(session, err.errors);
|
|
1013
1051
|
return;
|
|
1014
1052
|
}
|
|
1015
1053
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1016
1054
|
const walletError = parseWalletApiError(err);
|
|
1055
|
+
console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
|
|
1056
|
+
skuId,
|
|
1057
|
+
errorType: walletError?.errorType ?? "UNKNOWN",
|
|
1058
|
+
message: walletError?.message
|
|
1059
|
+
});
|
|
1017
1060
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1018
1061
|
failApplePaySession(session);
|
|
1019
1062
|
if (!walletError) {
|
|
1063
|
+
console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
|
|
1020
1064
|
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1021
1065
|
return;
|
|
1022
1066
|
}
|
|
1067
|
+
console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
|
|
1023
1068
|
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1024
1069
|
}
|
|
1025
1070
|
}
|
|
@@ -1464,12 +1509,12 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1464
1509
|
);
|
|
1465
1510
|
}
|
|
1466
1511
|
/**
|
|
1467
|
-
* Returns `true` (hide) when
|
|
1512
|
+
* Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
|
|
1468
1513
|
* for this offer. The response is cached and reused in `#initiateApplePay`.
|
|
1469
1514
|
*/
|
|
1470
1515
|
async #fetchAndCacheOptions() {
|
|
1471
1516
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1472
|
-
if (!this.#paymentOptions?.
|
|
1517
|
+
if (!this.#paymentOptions?.apple_pay) {
|
|
1473
1518
|
this.style.display = "none";
|
|
1474
1519
|
return true;
|
|
1475
1520
|
}
|
|
@@ -1545,7 +1590,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1545
1590
|
return {
|
|
1546
1591
|
countryCode: country,
|
|
1547
1592
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1548
|
-
supportedNetworks: paymentOptions.
|
|
1593
|
+
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1549
1594
|
totalAmount,
|
|
1550
1595
|
totalLabel: TOTAL_LABEL,
|
|
1551
1596
|
skuId,
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
// src/clients/payment-checkout/config.ts
|
|
2
2
|
var runtimeConfig = null;
|
|
3
3
|
var configureApplePay = (config) => {
|
|
4
|
+
console.log("[web-apple-pay] configureApplePay called", {
|
|
5
|
+
merchantId: config.merchantId,
|
|
6
|
+
walletApiBaseUrl: config.walletApiBaseUrl,
|
|
7
|
+
debugBypassEnabled: config.debugBypassEnabled,
|
|
8
|
+
recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
|
|
9
|
+
});
|
|
4
10
|
runtimeConfig = {
|
|
5
11
|
...config
|
|
6
12
|
};
|
|
7
13
|
};
|
|
8
14
|
var resetApplePayConfig = () => {
|
|
15
|
+
console.log("[web-apple-pay] resetApplePayConfig called");
|
|
9
16
|
runtimeConfig = null;
|
|
10
17
|
};
|
|
11
18
|
|