@economist/web-apple-pay 1.6.2-beta.1 → 1.7.0

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.
@@ -439,24 +439,101 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
439
439
  };
440
440
 
441
441
  // src/templates/apple-pay-button.template.html
442
- var apple_pay_button_template_default = '<style>\n /* Use CSS variables for layout so parent walls can easily override placement and sizing */\n teg-apple-pay-button {\n display: block;\n margin: var(--apple-pay-margin, 0);\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-container {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: var(--apple-pay-height, 2.75rem);\n background-color: #000;\n color: #fff;\n border: none;\n border-radius: var(--apple-pay-border-radius, 1.375rem);\n cursor: pointer;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-weight: 500;\n }\n\n teg-apple-pay-button .apple-pay-btn svg {\n flex-shrink: 0;\n display: block;\n }\n</style>\n\n<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">\n <button\n class="apple-pay-btn"\n type="button"\n aria-label="Pay with Apple Pay"\n data-analytics="paywall:apple-pay-checkout"\n >\n <svg width="51" height="22" aria-label="Apple Pay" role="img">\n <use href="#apple-pay-logo" />\n </svg>\n </button>\n</div>\n';
442
+ var apple_pay_button_template_default = `<style>
443
+ /* Use CSS variables for layout so parent walls can easily override placement and sizing */
444
+ teg-apple-pay-button {
445
+ display: block;
446
+ margin: var(--apple-pay-margin, 0);
447
+ width: 100%;
448
+ height: 100%;
449
+ }
450
+
451
+ teg-apple-pay-button .apple-pay-container {
452
+ display: flex;
453
+ flex-direction: column;
454
+ align-items: stretch;
455
+ width: 100%;
456
+ height: 100%;
457
+ }
458
+
459
+ teg-apple-pay-button .apple-pay-btn {
460
+ display: flex;
461
+ align-items: center;
462
+ justify-content: center;
463
+ gap: 0.375rem;
464
+ width: 100%;
465
+ min-width: 0;
466
+ height: 100%;
467
+ min-height: var(--apple-pay-height, 2.75rem);
468
+ background-color: #000;
469
+ color: #fff;
470
+ border: none;
471
+ border-radius: var(--apple-pay-border-radius, 1.375rem);
472
+ cursor: pointer;
473
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
474
+ font-size: 1.0625rem;
475
+ font-weight: 500;
476
+ }
477
+
478
+ teg-apple-pay-button .apple-pay-btn svg {
479
+ flex-shrink: 0;
480
+ display: block;
481
+ }
482
+
483
+ teg-apple-pay-button .apple-pay-btn.wap-loading {
484
+ position: relative;
485
+ cursor: default;
486
+ }
487
+
488
+ teg-apple-pay-button .apple-pay-btn.wap-loading svg {
489
+ visibility: hidden;
490
+ }
491
+
492
+ teg-apple-pay-button .apple-pay-btn.wap-loading::after {
493
+ content: '';
494
+ position: absolute;
495
+ left: 50%;
496
+ top: 50%;
497
+ margin-left: -0.625rem;
498
+ margin-top: -0.625rem;
499
+ width: 1.25rem;
500
+ height: 1.25rem;
501
+ border: 2px solid rgba(255, 255, 255, 0.2);
502
+ border-top-color: #fff;
503
+ border-radius: 50%;
504
+ animation: wap-button-spinner 0.8s linear infinite;
505
+ }
506
+
507
+ @keyframes wap-button-spinner {
508
+ to {
509
+ transform: rotate(360deg);
510
+ }
511
+ }
512
+ </style>
513
+
514
+ <div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
515
+ <button
516
+ class="apple-pay-btn"
517
+ type="button"
518
+ aria-label="Pay with Apple Pay"
519
+ data-analytics="paywall:apple-pay-checkout"
520
+ >
521
+ <svg width="51" height="22" aria-label="Apple Pay" role="img">
522
+ <use href="#apple-pay-logo" />
523
+ </svg>
524
+ </button>
525
+ </div>
526
+ `;
443
527
 
444
528
  // src/clients/payment-checkout/config.ts
445
529
  var runtimeConfig = null;
446
530
  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
- });
453
531
  runtimeConfig = {
454
532
  ...config
455
533
  };
456
534
  };
457
535
  var getApplePayConfig = () => runtimeConfig;
458
536
  var resetApplePayConfig = () => {
459
- console.log("[web-apple-pay] resetApplePayConfig called");
460
537
  runtimeConfig = null;
461
538
  };
462
539
 
@@ -468,27 +545,21 @@ var isAppleDeviceOrSafari = () => {
468
545
  };
469
546
  var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
470
547
  var isApplePayAvailable = async () => {
471
- console.log("[web-apple-pay] isApplePayAvailable: checking availability");
472
548
  if (bypassApplePayChecks()) {
473
- console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
474
549
  return true;
475
550
  }
476
551
  if (!isAppleDeviceOrSafari()) {
477
- console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
478
552
  return false;
479
553
  }
480
554
  const applePaySession = window.ApplePaySession;
481
555
  if (!applePaySession) {
482
- console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
483
556
  return false;
484
557
  }
485
558
  try {
486
559
  if (typeof applePaySession.canMakePayments !== "function") {
487
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
488
560
  return false;
489
561
  }
490
562
  if (!applePaySession.canMakePayments()) {
491
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
492
563
  return false;
493
564
  }
494
565
  const merchantId = getApplePayConfig()?.merchantId;
@@ -498,10 +569,7 @@ var isApplePayAvailable = async () => {
498
569
  );
499
570
  return false;
500
571
  }
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;
572
+ return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
505
573
  } catch (error) {
506
574
  console.error("Error checking Apple Pay active card status:", error);
507
575
  return false;
@@ -763,13 +831,6 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
763
831
 
764
832
  // src/clients/payment-checkout/apple-session.ts
765
833
  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
- });
773
834
  const paymentRequest = {
774
835
  countryCode: config.countryCode,
775
836
  currencyCode: config.currencyCode,
@@ -785,11 +846,9 @@ function startApplePaySession(config) {
785
846
  };
786
847
  const session = new ApplePaySession(3, paymentRequest);
787
848
  session.onvalidatemerchant = async (event) => {
788
- console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
789
849
  try {
790
850
  const validationHost = new URL(event.validationURL).host;
791
851
  if (!validationHost.endsWith("apple.com")) {
792
- console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
793
852
  trackFallbackCheckout(config.skuId);
794
853
  session.abort();
795
854
  window.location.href = redirectToCheckoutFallback({
@@ -800,13 +859,11 @@ function startApplePaySession(config) {
800
859
  return;
801
860
  }
802
861
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
803
- console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
804
862
  const response = await validateAppleMerchant({
805
863
  validationURL: event.validationURL,
806
864
  recaptchaToken
807
865
  });
808
866
  if (!response?.merchantSession) {
809
- console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
810
867
  trackFallbackCheckout(config.skuId);
811
868
  session.abort();
812
869
  window.location.href = redirectToCheckoutFallback({
@@ -816,10 +873,8 @@ function startApplePaySession(config) {
816
873
  });
817
874
  return;
818
875
  }
819
- console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
820
876
  session.completeMerchantValidation(response.merchantSession);
821
- } catch (err) {
822
- console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
877
+ } catch {
823
878
  trackFallbackCheckout(config.skuId);
824
879
  session.abort();
825
880
  window.location.href = redirectToCheckoutFallback({
@@ -830,15 +885,12 @@ function startApplePaySession(config) {
830
885
  }
831
886
  };
832
887
  session.onpaymentauthorized = (event) => {
833
- console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
834
888
  trackWalletPaymentAuthorised(config.skuId);
835
889
  config.onPaymentAuthorized(event, session);
836
890
  };
837
891
  session.oncancel = () => {
838
- console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
839
892
  config.onCancel?.();
840
893
  };
841
- console.log("[web-apple-pay] startApplePaySession: beginning session");
842
894
  trackWalletPaymentSheetOpen(config.skuId);
843
895
  session.begin();
844
896
  }
@@ -1017,16 +1069,12 @@ function handleStructuredError(ctx) {
1017
1069
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1018
1070
  const { skuId, returnUrl, queryString } = config;
1019
1071
  let validatedEmail;
1020
- console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
1021
1072
  try {
1022
- console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
1023
1073
  validatedEmail = validateContacts(
1024
1074
  event,
1025
1075
  sessionData,
1026
1076
  config.supportedBillingCountries
1027
1077
  );
1028
- console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
1029
- console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
1030
1078
  const result = await performPurchase({
1031
1079
  applePayToken: event.payment.token,
1032
1080
  skuId: config.skuId,
@@ -1036,8 +1084,6 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1036
1084
  },
1037
1085
  recaptchaTokens: config.recaptchaTokens
1038
1086
  });
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");
1041
1087
  trackWalletPaymentSuccess(skuId, result.basketId);
1042
1088
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1043
1089
  const userStatus = sessionData.loggedIn ? "lex" : "nex";
@@ -1050,25 +1096,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1050
1096
  });
1051
1097
  } catch (err) {
1052
1098
  if (err instanceof ContactValidationError) {
1053
- console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
1054
1099
  failApplePaySession(session, err.errors);
1055
1100
  return;
1056
1101
  }
1057
1102
  console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1058
1103
  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
- });
1064
1104
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1065
1105
  failApplePaySession(session);
1066
1106
  if (!walletError) {
1067
- console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
1068
1107
  redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1069
1108
  return;
1070
1109
  }
1071
- console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
1072
1110
  handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1073
1111
  }
1074
1112
  }
@@ -1456,14 +1494,16 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1456
1494
  async #run() {
1457
1495
  try {
1458
1496
  if (await this.#checkAvailability()) return;
1459
- if (await this.#checkSession()) return;
1460
1497
  if (this.#checkOffer()) return;
1498
+ this.#renderTemplate();
1499
+ if (await this.#checkSession()) return;
1461
1500
  this.#captureReturnUrl();
1462
1501
  this.#computeBillingCountries();
1463
1502
  if (await this.#fetchAndCacheOptions()) return;
1464
- this.#renderTemplate();
1503
+ this.#finishLoading();
1465
1504
  } catch {
1466
1505
  this.style.display = "none";
1506
+ this.querySelector(SEL_CONTAINER)?.remove();
1467
1507
  } finally {
1468
1508
  this.#rendering = false;
1469
1509
  }
@@ -1485,6 +1525,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1485
1525
  this.#sessionData = await this.#fetchSession();
1486
1526
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
1487
1527
  this.style.display = "none";
1528
+ this.querySelector(SEL_CONTAINER)?.remove();
1488
1529
  return true;
1489
1530
  }
1490
1531
  return false;
@@ -1520,6 +1561,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1520
1561
  this.#paymentOptions = await this.#fetchPaymentOptions();
1521
1562
  if (!this.#paymentOptions?.apple_pay) {
1522
1563
  this.style.display = "none";
1564
+ this.querySelector(SEL_CONTAINER)?.remove();
1523
1565
  return true;
1524
1566
  }
1525
1567
  return false;
@@ -1531,13 +1573,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1531
1573
  const template = document.createElement("template");
1532
1574
  template.innerHTML = apple_pay_button_template_default;
1533
1575
  this.appendChild(template.content.cloneNode(true));
1534
- this.#updateDisabledState();
1535
- trackExpressWalletImpression(this.#offer.sku_id, {
1536
- entryPoint: this.#entryPoint,
1537
- country: this.#country
1538
- });
1539
1576
  const button = this.querySelector(SEL_BUTTON);
1577
+ button.classList.add("wap-loading");
1578
+ button.setAttribute("disabled", "");
1579
+ button.setAttribute("aria-disabled", "true");
1580
+ button.setAttribute("aria-busy", "true");
1540
1581
  button.addEventListener("click", () => {
1582
+ if (button.classList.contains("wap-loading")) return;
1541
1583
  this.#openModal();
1542
1584
  });
1543
1585
  this.addEventListener("apple-pay-confirmed", (event) => {
@@ -1545,6 +1587,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1545
1587
  this.#initiateApplePay(skuId, country);
1546
1588
  });
1547
1589
  }
1590
+ #finishLoading() {
1591
+ const button = this.querySelector(SEL_BUTTON);
1592
+ if (button) {
1593
+ button.classList.remove("wap-loading");
1594
+ this.#updateDisabledState();
1595
+ trackExpressWalletImpression(this.#offer.sku_id, {
1596
+ entryPoint: this.#entryPoint,
1597
+ country: this.#country
1598
+ });
1599
+ }
1600
+ }
1548
1601
  // ─── Private helpers ────────────────────────────────────────────────────────
1549
1602
  #updateDisabledState() {
1550
1603
  const button = this.querySelector(SEL_BUTTON);
@@ -1552,6 +1605,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1552
1605
  if (this.#offer) {
1553
1606
  button.removeAttribute("disabled");
1554
1607
  button.removeAttribute("aria-disabled");
1608
+ button.removeAttribute("aria-busy");
1555
1609
  return;
1556
1610
  }
1557
1611
  button.setAttribute("disabled", "");
@@ -439,7 +439,91 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
439
439
  };
440
440
 
441
441
  // src/templates/apple-pay-button.template.html
442
- var apple_pay_button_template_default = '<style>\n /* Use CSS variables for layout so parent walls can easily override placement and sizing */\n teg-apple-pay-button {\n display: block;\n margin: var(--apple-pay-margin, 0);\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-container {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: var(--apple-pay-height, 2.75rem);\n background-color: #000;\n color: #fff;\n border: none;\n border-radius: var(--apple-pay-border-radius, 1.375rem);\n cursor: pointer;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-weight: 500;\n }\n\n teg-apple-pay-button .apple-pay-btn svg {\n flex-shrink: 0;\n display: block;\n }\n</style>\n\n<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">\n <button\n class="apple-pay-btn"\n type="button"\n aria-label="Pay with Apple Pay"\n data-analytics="paywall:apple-pay-checkout"\n >\n <svg width="51" height="22" aria-label="Apple Pay" role="img">\n <use href="#apple-pay-logo" />\n </svg>\n </button>\n</div>\n';
442
+ var apple_pay_button_template_default = `<style>
443
+ /* Use CSS variables for layout so parent walls can easily override placement and sizing */
444
+ teg-apple-pay-button {
445
+ display: block;
446
+ margin: var(--apple-pay-margin, 0);
447
+ width: 100%;
448
+ height: 100%;
449
+ }
450
+
451
+ teg-apple-pay-button .apple-pay-container {
452
+ display: flex;
453
+ flex-direction: column;
454
+ align-items: stretch;
455
+ width: 100%;
456
+ height: 100%;
457
+ }
458
+
459
+ teg-apple-pay-button .apple-pay-btn {
460
+ display: flex;
461
+ align-items: center;
462
+ justify-content: center;
463
+ gap: 0.375rem;
464
+ width: 100%;
465
+ min-width: 0;
466
+ height: 100%;
467
+ min-height: var(--apple-pay-height, 2.75rem);
468
+ background-color: #000;
469
+ color: #fff;
470
+ border: none;
471
+ border-radius: var(--apple-pay-border-radius, 1.375rem);
472
+ cursor: pointer;
473
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
474
+ font-size: 1.0625rem;
475
+ font-weight: 500;
476
+ }
477
+
478
+ teg-apple-pay-button .apple-pay-btn svg {
479
+ flex-shrink: 0;
480
+ display: block;
481
+ }
482
+
483
+ teg-apple-pay-button .apple-pay-btn.wap-loading {
484
+ position: relative;
485
+ cursor: default;
486
+ }
487
+
488
+ teg-apple-pay-button .apple-pay-btn.wap-loading svg {
489
+ visibility: hidden;
490
+ }
491
+
492
+ teg-apple-pay-button .apple-pay-btn.wap-loading::after {
493
+ content: '';
494
+ position: absolute;
495
+ left: 50%;
496
+ top: 50%;
497
+ margin-left: -0.625rem;
498
+ margin-top: -0.625rem;
499
+ width: 1.25rem;
500
+ height: 1.25rem;
501
+ border: 2px solid rgba(255, 255, 255, 0.2);
502
+ border-top-color: #fff;
503
+ border-radius: 50%;
504
+ animation: wap-button-spinner 0.8s linear infinite;
505
+ }
506
+
507
+ @keyframes wap-button-spinner {
508
+ to {
509
+ transform: rotate(360deg);
510
+ }
511
+ }
512
+ </style>
513
+
514
+ <div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
515
+ <button
516
+ class="apple-pay-btn"
517
+ type="button"
518
+ aria-label="Pay with Apple Pay"
519
+ data-analytics="paywall:apple-pay-checkout"
520
+ >
521
+ <svg width="51" height="22" aria-label="Apple Pay" role="img">
522
+ <use href="#apple-pay-logo" />
523
+ </svg>
524
+ </button>
525
+ </div>
526
+ `;
443
527
 
444
528
  // src/clients/payment-checkout/config.ts
445
529
  var runtimeConfig = null;
@@ -453,27 +537,21 @@ var isAppleDeviceOrSafari = () => {
453
537
  };
454
538
  var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
455
539
  var isApplePayAvailable = async () => {
456
- console.log("[web-apple-pay] isApplePayAvailable: checking availability");
457
540
  if (bypassApplePayChecks()) {
458
- console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
459
541
  return true;
460
542
  }
461
543
  if (!isAppleDeviceOrSafari()) {
462
- console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
463
544
  return false;
464
545
  }
465
546
  const applePaySession = window.ApplePaySession;
466
547
  if (!applePaySession) {
467
- console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
468
548
  return false;
469
549
  }
470
550
  try {
471
551
  if (typeof applePaySession.canMakePayments !== "function") {
472
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
473
552
  return false;
474
553
  }
475
554
  if (!applePaySession.canMakePayments()) {
476
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
477
555
  return false;
478
556
  }
479
557
  const merchantId = getApplePayConfig()?.merchantId;
@@ -483,10 +561,7 @@ var isApplePayAvailable = async () => {
483
561
  );
484
562
  return false;
485
563
  }
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;
564
+ return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
490
565
  } catch (error) {
491
566
  console.error("Error checking Apple Pay active card status:", error);
492
567
  return false;
@@ -748,13 +823,6 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
748
823
 
749
824
  // src/clients/payment-checkout/apple-session.ts
750
825
  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
- });
758
826
  const paymentRequest = {
759
827
  countryCode: config.countryCode,
760
828
  currencyCode: config.currencyCode,
@@ -770,11 +838,9 @@ function startApplePaySession(config) {
770
838
  };
771
839
  const session = new ApplePaySession(3, paymentRequest);
772
840
  session.onvalidatemerchant = async (event) => {
773
- console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
774
841
  try {
775
842
  const validationHost = new URL(event.validationURL).host;
776
843
  if (!validationHost.endsWith("apple.com")) {
777
- console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
778
844
  trackFallbackCheckout(config.skuId);
779
845
  session.abort();
780
846
  window.location.href = redirectToCheckoutFallback({
@@ -785,13 +851,11 @@ function startApplePaySession(config) {
785
851
  return;
786
852
  }
787
853
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
788
- console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
789
854
  const response = await validateAppleMerchant({
790
855
  validationURL: event.validationURL,
791
856
  recaptchaToken
792
857
  });
793
858
  if (!response?.merchantSession) {
794
- console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
795
859
  trackFallbackCheckout(config.skuId);
796
860
  session.abort();
797
861
  window.location.href = redirectToCheckoutFallback({
@@ -801,10 +865,8 @@ function startApplePaySession(config) {
801
865
  });
802
866
  return;
803
867
  }
804
- console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
805
868
  session.completeMerchantValidation(response.merchantSession);
806
- } catch (err) {
807
- console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
869
+ } catch {
808
870
  trackFallbackCheckout(config.skuId);
809
871
  session.abort();
810
872
  window.location.href = redirectToCheckoutFallback({
@@ -815,15 +877,12 @@ function startApplePaySession(config) {
815
877
  }
816
878
  };
817
879
  session.onpaymentauthorized = (event) => {
818
- console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
819
880
  trackWalletPaymentAuthorised(config.skuId);
820
881
  config.onPaymentAuthorized(event, session);
821
882
  };
822
883
  session.oncancel = () => {
823
- console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
824
884
  config.onCancel?.();
825
885
  };
826
- console.log("[web-apple-pay] startApplePaySession: beginning session");
827
886
  trackWalletPaymentSheetOpen(config.skuId);
828
887
  session.begin();
829
888
  }
@@ -1002,16 +1061,12 @@ function handleStructuredError(ctx) {
1002
1061
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1003
1062
  const { skuId, returnUrl, queryString } = config;
1004
1063
  let validatedEmail;
1005
- console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
1006
1064
  try {
1007
- console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
1008
1065
  validatedEmail = validateContacts(
1009
1066
  event,
1010
1067
  sessionData,
1011
1068
  config.supportedBillingCountries
1012
1069
  );
1013
- console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
1014
- console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
1015
1070
  const result = await performPurchase({
1016
1071
  applePayToken: event.payment.token,
1017
1072
  skuId: config.skuId,
@@ -1021,8 +1076,6 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1021
1076
  },
1022
1077
  recaptchaTokens: config.recaptchaTokens
1023
1078
  });
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");
1026
1079
  trackWalletPaymentSuccess(skuId, result.basketId);
1027
1080
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1028
1081
  const userStatus = sessionData.loggedIn ? "lex" : "nex";
@@ -1035,25 +1088,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1035
1088
  });
1036
1089
  } catch (err) {
1037
1090
  if (err instanceof ContactValidationError) {
1038
- console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
1039
1091
  failApplePaySession(session, err.errors);
1040
1092
  return;
1041
1093
  }
1042
1094
  console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1043
1095
  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
- });
1049
1096
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1050
1097
  failApplePaySession(session);
1051
1098
  if (!walletError) {
1052
- console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
1053
1099
  redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1054
1100
  return;
1055
1101
  }
1056
- console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
1057
1102
  handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1058
1103
  }
1059
1104
  }
@@ -1441,14 +1486,16 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1441
1486
  async #run() {
1442
1487
  try {
1443
1488
  if (await this.#checkAvailability()) return;
1444
- if (await this.#checkSession()) return;
1445
1489
  if (this.#checkOffer()) return;
1490
+ this.#renderTemplate();
1491
+ if (await this.#checkSession()) return;
1446
1492
  this.#captureReturnUrl();
1447
1493
  this.#computeBillingCountries();
1448
1494
  if (await this.#fetchAndCacheOptions()) return;
1449
- this.#renderTemplate();
1495
+ this.#finishLoading();
1450
1496
  } catch {
1451
1497
  this.style.display = "none";
1498
+ this.querySelector(SEL_CONTAINER)?.remove();
1452
1499
  } finally {
1453
1500
  this.#rendering = false;
1454
1501
  }
@@ -1470,6 +1517,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1470
1517
  this.#sessionData = await this.#fetchSession();
1471
1518
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
1472
1519
  this.style.display = "none";
1520
+ this.querySelector(SEL_CONTAINER)?.remove();
1473
1521
  return true;
1474
1522
  }
1475
1523
  return false;
@@ -1505,6 +1553,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1505
1553
  this.#paymentOptions = await this.#fetchPaymentOptions();
1506
1554
  if (!this.#paymentOptions?.apple_pay) {
1507
1555
  this.style.display = "none";
1556
+ this.querySelector(SEL_CONTAINER)?.remove();
1508
1557
  return true;
1509
1558
  }
1510
1559
  return false;
@@ -1516,13 +1565,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1516
1565
  const template = document.createElement("template");
1517
1566
  template.innerHTML = apple_pay_button_template_default;
1518
1567
  this.appendChild(template.content.cloneNode(true));
1519
- this.#updateDisabledState();
1520
- trackExpressWalletImpression(this.#offer.sku_id, {
1521
- entryPoint: this.#entryPoint,
1522
- country: this.#country
1523
- });
1524
1568
  const button = this.querySelector(SEL_BUTTON);
1569
+ button.classList.add("wap-loading");
1570
+ button.setAttribute("disabled", "");
1571
+ button.setAttribute("aria-disabled", "true");
1572
+ button.setAttribute("aria-busy", "true");
1525
1573
  button.addEventListener("click", () => {
1574
+ if (button.classList.contains("wap-loading")) return;
1526
1575
  this.#openModal();
1527
1576
  });
1528
1577
  this.addEventListener("apple-pay-confirmed", (event) => {
@@ -1530,6 +1579,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1530
1579
  this.#initiateApplePay(skuId, country);
1531
1580
  });
1532
1581
  }
1582
+ #finishLoading() {
1583
+ const button = this.querySelector(SEL_BUTTON);
1584
+ if (button) {
1585
+ button.classList.remove("wap-loading");
1586
+ this.#updateDisabledState();
1587
+ trackExpressWalletImpression(this.#offer.sku_id, {
1588
+ entryPoint: this.#entryPoint,
1589
+ country: this.#country
1590
+ });
1591
+ }
1592
+ }
1533
1593
  // ─── Private helpers ────────────────────────────────────────────────────────
1534
1594
  #updateDisabledState() {
1535
1595
  const button = this.querySelector(SEL_BUTTON);
@@ -1537,6 +1597,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1537
1597
  if (this.#offer) {
1538
1598
  button.removeAttribute("disabled");
1539
1599
  button.removeAttribute("aria-disabled");
1600
+ button.removeAttribute("aria-busy");
1540
1601
  return;
1541
1602
  }
1542
1603
  button.setAttribute("disabled", "");