@economist/web-apple-pay 0.1.3-beta.0 → 0.1.3-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 CHANGED
@@ -307,9 +307,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
307
307
  this.#country = value;
308
308
  }
309
309
  connectedCallback() {
310
- console.log("[web-apple-pay] ApplePayModal connectedCallback");
311
310
  if (this.querySelector(".apm-overlay")) {
312
- console.log("[web-apple-pay] ApplePayModal connectedCallback: already rendered, skipping");
313
311
  return;
314
312
  }
315
313
  ensureApplePayLogoSymbol();
@@ -323,7 +321,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
323
321
  this.remove();
324
322
  return;
325
323
  }
326
- console.log("[web-apple-pay] ApplePayModal: rendering for offer", { skuId: offer.sku_id, country });
327
324
  const offerNameElement = this.querySelector(
328
325
  "#apple-pay-modal-offer-name"
329
326
  );
@@ -396,14 +393,11 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
396
393
  });
397
394
  }
398
395
  cta?.addEventListener("click", () => {
399
- console.log("[web-apple-pay] ApplePayModal: CTA clicked", { skuId: offer.sku_id, country, isUS });
400
396
  if (isUS && checkbox && !checkbox.checked) {
401
- console.log("[web-apple-pay] ApplePayModal: T&C checkbox not accepted, showing error");
402
397
  errorElement?.classList.add("apm__error--visible");
403
398
  checkboxLabel?.classList.add("apm__checkbox-label--error");
404
399
  return;
405
400
  }
406
- console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed", { skuId: offer.sku_id, country });
407
401
  this.dispatchEvent(
408
402
  new CustomEvent("apple-pay-confirmed", {
409
403
  bubbles: true,
@@ -411,7 +405,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
411
405
  detail: { skuId: offer.sku_id, country }
412
406
  })
413
407
  );
414
- console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed-final", { skuId: offer.sku_id, country });
408
+ this.close();
415
409
  });
416
410
  this.querySelector("#apple-pay-modal-close")?.addEventListener(
417
411
  "click",
@@ -419,7 +413,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
419
413
  );
420
414
  }
421
415
  open() {
422
- console.log("[web-apple-pay] ApplePayModal: open()");
423
416
  this.#triggerElement = document.activeElement;
424
417
  document.body.appendChild(this);
425
418
  this.#keyHandler = (event) => {
@@ -434,7 +427,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
434
427
  this.querySelector("#apple-pay-modal")?.focus();
435
428
  }
436
429
  close() {
437
- console.log("[web-apple-pay] ApplePayModal: close()");
438
430
  if (this.#keyHandler) {
439
431
  document.removeEventListener("keydown", this.#keyHandler, {
440
432
  capture: true
@@ -447,17 +439,95 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
447
439
  };
448
440
 
449
441
  // src/templates/apple-pay-button.template.html
450
- 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
+ `;
451
527
 
452
528
  // src/clients/payment-checkout/config.ts
453
529
  var runtimeConfig = null;
454
530
  var configureApplePay = (config) => {
455
- console.log("[web-apple-pay] configureApplePay called", {
456
- merchantId: config.merchantId,
457
- walletApiBaseUrl: config.walletApiBaseUrl,
458
- debugBypassEnabled: config.debugBypassEnabled,
459
- recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
460
- });
461
531
  runtimeConfig = {
462
532
  ...config
463
533
  };
@@ -472,27 +542,21 @@ var isAppleDeviceOrSafari = () => {
472
542
  };
473
543
  var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
474
544
  var isApplePayAvailable = async () => {
475
- console.log("[web-apple-pay] isApplePayAvailable: checking availability");
476
545
  if (bypassApplePayChecks()) {
477
- console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
478
546
  return true;
479
547
  }
480
548
  if (!isAppleDeviceOrSafari()) {
481
- console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
482
549
  return false;
483
550
  }
484
551
  const applePaySession = window.ApplePaySession;
485
552
  if (!applePaySession) {
486
- console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
487
553
  return false;
488
554
  }
489
555
  try {
490
556
  if (typeof applePaySession.canMakePayments !== "function") {
491
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
492
557
  return false;
493
558
  }
494
559
  if (!applePaySession.canMakePayments()) {
495
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
496
560
  return false;
497
561
  }
498
562
  const merchantId = getApplePayConfig()?.merchantId;
@@ -502,10 +566,7 @@ var isApplePayAvailable = async () => {
502
566
  );
503
567
  return false;
504
568
  }
505
- console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
506
- const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
507
- console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
508
- return result;
569
+ return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
509
570
  } catch (error) {
510
571
  console.error("Error checking Apple Pay active card status:", error);
511
572
  return false;
@@ -767,13 +828,6 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
767
828
 
768
829
  // src/clients/payment-checkout/apple-session.ts
769
830
  function startApplePaySession(config) {
770
- console.log("[web-apple-pay] startApplePaySession", {
771
- skuId: config.skuId,
772
- countryCode: config.countryCode,
773
- currencyCode: config.currencyCode,
774
- totalAmount: config.totalAmount,
775
- userLoggedIn: config.userLoggedIn
776
- });
777
831
  const paymentRequest = {
778
832
  countryCode: config.countryCode,
779
833
  currencyCode: config.currencyCode,
@@ -787,45 +841,26 @@ function startApplePaySession(config) {
787
841
  // Only request email from Apple Pay sheet if user is NOT logged in
788
842
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
789
843
  };
790
- try {
791
- const session = new ApplePaySession(3, paymentRequest);
792
- console.log("[web-apple-pay] startApplePaySession: ApplePaySession created");
793
- session.onvalidatemerchant = async (event) => {
794
- console.log("[web-apple-pay] onvalidatemerchant: received", { validationURL: event.validationURL });
795
- try {
796
- const validationHost = new URL(event.validationURL).host;
797
- if (!validationHost.endsWith("apple.com")) {
798
- console.warn("[web-apple-pay] onvalidatemerchant: invalid host, aborting", { validationHost });
799
- trackFallbackCheckout(config.skuId);
800
- session.abort();
801
- window.location.href = redirectToCheckoutFallback({
802
- skuId: config.skuId,
803
- returnUrl: config.returnUrl,
804
- inlineError: MSG_PAYMENT_GENERIC_ERROR
805
- });
806
- return;
807
- }
808
- const recaptchaToken = await getRecaptchaToken("verifyMerchant");
809
- console.log("[web-apple-pay] onvalidatemerchant: calling validateAppleMerchant");
810
- const response = await validateAppleMerchant({
811
- validationURL: event.validationURL,
812
- recaptchaToken
844
+ const session = new ApplePaySession(3, paymentRequest);
845
+ session.onvalidatemerchant = async (event) => {
846
+ try {
847
+ const validationHost = new URL(event.validationURL).host;
848
+ if (!validationHost.endsWith("apple.com")) {
849
+ trackFallbackCheckout(config.skuId);
850
+ session.abort();
851
+ window.location.href = redirectToCheckoutFallback({
852
+ skuId: config.skuId,
853
+ returnUrl: config.returnUrl,
854
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
813
855
  });
814
- if (!response?.merchantSession) {
815
- console.warn("[web-apple-pay] onvalidatemerchant: no merchantSession in response, aborting");
816
- trackFallbackCheckout(config.skuId);
817
- session.abort();
818
- window.location.href = redirectToCheckoutFallback({
819
- skuId: config.skuId,
820
- returnUrl: config.returnUrl,
821
- inlineError: MSG_PAYMENT_GENERIC_ERROR
822
- });
823
- return;
824
- }
825
- console.log("[web-apple-pay] onvalidatemerchant: merchant validated successfully");
826
- session.completeMerchantValidation(response.merchantSession);
827
- } catch (err) {
828
- console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
856
+ return;
857
+ }
858
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
859
+ const response = await validateAppleMerchant({
860
+ validationURL: event.validationURL,
861
+ recaptchaToken
862
+ });
863
+ if (!response?.merchantSession) {
829
864
  trackFallbackCheckout(config.skuId);
830
865
  session.abort();
831
866
  window.location.href = redirectToCheckoutFallback({
@@ -833,29 +868,28 @@ function startApplePaySession(config) {
833
868
  returnUrl: config.returnUrl,
834
869
  inlineError: MSG_PAYMENT_GENERIC_ERROR
835
870
  });
871
+ return;
836
872
  }
837
- };
838
- session.onpaymentauthorized = (event) => {
839
- console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
840
- trackWalletPaymentAuthorised(config.skuId);
841
- config.onPaymentAuthorized(event, session);
842
- };
843
- session.oncancel = () => {
844
- console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
845
- config.onCancel?.();
846
- };
847
- console.log("[web-apple-pay] startApplePaySession: beginning session");
848
- trackWalletPaymentSheetOpen(config.skuId);
849
- session.begin();
850
- } catch (err) {
851
- console.error("[web-apple-pay] startApplePaySession: failed to create or begin ApplePaySession", err);
852
- trackFallbackCheckout(config.skuId);
853
- window.location.href = redirectToCheckoutFallback({
854
- skuId: config.skuId,
855
- returnUrl: config.returnUrl,
856
- inlineError: MSG_PAYMENT_GENERIC_ERROR
857
- });
858
- }
873
+ session.completeMerchantValidation(response.merchantSession);
874
+ } catch {
875
+ trackFallbackCheckout(config.skuId);
876
+ session.abort();
877
+ window.location.href = redirectToCheckoutFallback({
878
+ skuId: config.skuId,
879
+ returnUrl: config.returnUrl,
880
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
881
+ });
882
+ }
883
+ };
884
+ session.onpaymentauthorized = (event) => {
885
+ trackWalletPaymentAuthorised(config.skuId);
886
+ config.onPaymentAuthorized(event, session);
887
+ };
888
+ session.oncancel = () => {
889
+ config.onCancel?.();
890
+ };
891
+ trackWalletPaymentSheetOpen(config.skuId);
892
+ session.begin();
859
893
  }
860
894
 
861
895
  // src/clients/payment-checkout/contact-validation.ts
@@ -1032,16 +1066,12 @@ function handleStructuredError(ctx) {
1032
1066
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1033
1067
  const { skuId, returnUrl, queryString } = config;
1034
1068
  let validatedEmail;
1035
- console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
1036
1069
  try {
1037
- console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
1038
1070
  validatedEmail = validateContacts(
1039
1071
  event,
1040
1072
  sessionData,
1041
1073
  config.supportedBillingCountries
1042
1074
  );
1043
- console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
1044
- console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
1045
1075
  const result = await performPurchase({
1046
1076
  applePayToken: event.payment.token,
1047
1077
  skuId: config.skuId,
@@ -1051,8 +1081,6 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1051
1081
  },
1052
1082
  recaptchaTokens: config.recaptchaTokens
1053
1083
  });
1054
- console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
1055
- console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
1056
1084
  trackWalletPaymentSuccess(skuId, result.basketId);
1057
1085
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1058
1086
  const userStatus = sessionData.loggedIn ? "lex" : "nex";
@@ -1065,25 +1093,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1065
1093
  });
1066
1094
  } catch (err) {
1067
1095
  if (err instanceof ContactValidationError) {
1068
- console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
1069
1096
  failApplePaySession(session, err.errors);
1070
1097
  return;
1071
1098
  }
1072
1099
  console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1073
1100
  const walletError = parseWalletApiError(err);
1074
- console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
1075
- skuId,
1076
- errorType: walletError?.errorType ?? "UNKNOWN",
1077
- message: walletError?.message
1078
- });
1079
1101
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1080
1102
  failApplePaySession(session);
1081
1103
  if (!walletError) {
1082
- console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
1083
1104
  redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1084
1105
  return;
1085
1106
  }
1086
- console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
1087
1107
  handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1088
1108
  }
1089
1109
  }
@@ -1370,19 +1390,11 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1370
1390
  * Creates and configures an ApplePayButton if the feature flag is present.
1371
1391
  */
1372
1392
  static createIfEnabled(offer, country, entryPoint) {
1373
- if (!offer) {
1374
- console.log("[web-apple-pay] createIfEnabled: no offer provided \u2192 null");
1393
+ if (!offer) return null;
1394
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
1375
1395
  return null;
1376
- }
1377
- if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1378
- console.log("[web-apple-pay] createIfEnabled: excluded variant \u2192 null", { variant: offer.product?.variant });
1396
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
1379
1397
  return null;
1380
- }
1381
- if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1382
- console.log("[web-apple-pay] createIfEnabled: feature flag absent \u2192 null");
1383
- return null;
1384
- }
1385
- console.log("[web-apple-pay] createIfEnabled: creating button", { skuId: offer.sku_id, country, entryPoint });
1386
1398
  _ApplePayButton.define();
1387
1399
  const button = document.createElement(_ApplePayButton.tag);
1388
1400
  button.offer = offer;
@@ -1409,7 +1421,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1409
1421
  #returnUrl = "";
1410
1422
  #supportedBillingCountries = [];
1411
1423
  #entryPoint = "";
1412
- #recaptchaTokens = null;
1413
1424
  // ─── Public API ─────────────────────────────────────────────────────────────
1414
1425
  get offer() {
1415
1426
  return this.#offer;
@@ -1451,9 +1462,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1451
1462
  }
1452
1463
  // ─── Lifecycle ──────────────────────────────────────────────────────────────
1453
1464
  async connectedCallback() {
1454
- console.log("[web-apple-pay] connectedCallback: element connected");
1455
1465
  if (this.#rendering || this.querySelector(SEL_CONTAINER)) {
1456
- console.log("[web-apple-pay] connectedCallback: already rendering or rendered, skipping");
1457
1466
  return;
1458
1467
  }
1459
1468
  this.#rendering = true;
@@ -1470,7 +1479,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1470
1479
  * and eliminating the implicit reliance on the DOM as a render-state flag.
1471
1480
  */
1472
1481
  disconnectedCallback() {
1473
- console.log("[web-apple-pay] disconnectedCallback: element removed from DOM, resetting state");
1474
1482
  this.#rendering = false;
1475
1483
  this.#readyPromise = null;
1476
1484
  this.#sessionData = null;
@@ -1481,17 +1489,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1481
1489
  }
1482
1490
  // ─── Render pipeline ────────────────────────────────────────────────────────
1483
1491
  async #run() {
1484
- console.log("[web-apple-pay] #run: starting render pipeline");
1485
1492
  try {
1486
1493
  if (await this.#checkAvailability()) return;
1487
- if (await this.#checkSession()) return;
1488
1494
  if (this.#checkOffer()) return;
1495
+ this.#renderTemplate();
1496
+ if (await this.#checkSession()) return;
1489
1497
  this.#captureReturnUrl();
1490
1498
  this.#computeBillingCountries();
1491
1499
  if (await this.#fetchAndCacheOptions()) return;
1492
- this.#renderTemplate();
1500
+ this.#finishLoading();
1493
1501
  } catch {
1494
1502
  this.style.display = "none";
1503
+ this.querySelector(SEL_CONTAINER)?.remove();
1495
1504
  } finally {
1496
1505
  this.#rendering = false;
1497
1506
  }
@@ -1500,11 +1509,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1500
1509
  async #checkAvailability() {
1501
1510
  const available = await isApplePayAvailable();
1502
1511
  if (!available) {
1503
- console.log("[web-apple-pay] #checkAvailability: Apple Pay unavailable \u2192 hiding");
1504
1512
  this.style.display = "none";
1505
1513
  return true;
1506
1514
  }
1507
- console.log("[web-apple-pay] #checkAvailability: Apple Pay available");
1508
1515
  return false;
1509
1516
  }
1510
1517
  /**
@@ -1513,10 +1520,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1513
1520
  */
1514
1521
  async #checkSession() {
1515
1522
  this.#sessionData = await this.#fetchSession();
1516
- console.log("[web-apple-pay] #checkSession: session fetched", { loggedIn: this.#sessionData?.loggedIn, userType: this.#sessionData?.userType });
1517
1523
  if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
1518
- console.log("[web-apple-pay] #checkSession: ineligible user \u2192 hiding", { userType: this.#sessionData.userType });
1519
1524
  this.style.display = "none";
1525
+ this.querySelector(SEL_CONTAINER)?.remove();
1520
1526
  return true;
1521
1527
  }
1522
1528
  return false;
@@ -1524,17 +1530,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1524
1530
  /** Returns `true` (hide) when no offer has been set before mount. */
1525
1531
  #checkOffer() {
1526
1532
  if (!this.#offer) {
1527
- console.log("[web-apple-pay] #checkOffer: no offer set \u2192 hiding");
1528
1533
  this.style.display = "none";
1529
1534
  return true;
1530
1535
  }
1531
- console.log("[web-apple-pay] #checkOffer: offer present", { skuId: this.#offer.sku_id });
1532
1536
  return false;
1533
1537
  }
1534
1538
  /** Captures the current page URL once at mount for reuse across the session lifetime. */
1535
1539
  #captureReturnUrl() {
1536
1540
  this.#returnUrl = captureOriginUrl();
1537
- console.log("[web-apple-pay] #captureReturnUrl:", this.#returnUrl);
1538
1541
  }
1539
1542
  /**
1540
1543
  * Computes supported billing countries once at mount.
@@ -1546,7 +1549,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1546
1549
  this.#country,
1547
1550
  this.#offer.product?.variant ?? ""
1548
1551
  );
1549
- console.log("[web-apple-pay] #computeBillingCountries:", this.#supportedBillingCountries);
1550
1552
  }
1551
1553
  /**
1552
1554
  * Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
@@ -1554,36 +1556,44 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1554
1556
  */
1555
1557
  async #fetchAndCacheOptions() {
1556
1558
  this.#paymentOptions = await this.#fetchPaymentOptions();
1557
- console.log("[web-apple-pay] #fetchAndCacheOptions: fetched payment options", { paymentOptions: this.#paymentOptions });
1558
- if (!this.#paymentOptions?.options?.apple_pay) {
1559
- console.log("[web-apple-pay] #fetchAndCacheOptions: apple_pay not in options \u2192 hiding");
1559
+ if (!this.#paymentOptions?.apple_pay) {
1560
1560
  this.style.display = "none";
1561
+ this.querySelector(SEL_CONTAINER)?.remove();
1561
1562
  return true;
1562
1563
  }
1563
1564
  return false;
1564
1565
  }
1565
1566
  /** Injects the button template and wires click and confirm event listeners. */
1566
1567
  #renderTemplate() {
1567
- console.log("[web-apple-pay] #renderTemplate: rendering Apple Pay button", { skuId: this.#offer?.sku_id, country: this.#country });
1568
1568
  this.style.removeProperty("display");
1569
1569
  ensureApplePayLogoSymbol();
1570
1570
  const template = document.createElement("template");
1571
1571
  template.innerHTML = apple_pay_button_template_default;
1572
1572
  this.appendChild(template.content.cloneNode(true));
1573
- this.#updateDisabledState();
1574
- trackExpressWalletImpression(this.#offer.sku_id, {
1575
- entryPoint: this.#entryPoint,
1576
- country: this.#country
1577
- });
1578
1573
  const button = this.querySelector(SEL_BUTTON);
1574
+ button.classList.add("wap-loading");
1575
+ button.setAttribute("disabled", "");
1576
+ button.setAttribute("aria-disabled", "true");
1577
+ button.setAttribute("aria-busy", "true");
1579
1578
  button.addEventListener("click", () => {
1579
+ if (button.classList.contains("wap-loading")) return;
1580
1580
  this.#openModal();
1581
1581
  });
1582
- document.addEventListener("apple-pay-confirmed", (event) => {
1582
+ this.addEventListener("apple-pay-confirmed", (event) => {
1583
1583
  const { skuId, country } = event.detail;
1584
- console.log("[web-apple-pay] apple-pay-confirmed received on document", { skuId, country });
1585
1584
  this.#initiateApplePay(skuId, country);
1586
- }, { once: true });
1585
+ });
1586
+ }
1587
+ #finishLoading() {
1588
+ const button = this.querySelector(SEL_BUTTON);
1589
+ if (button) {
1590
+ button.classList.remove("wap-loading");
1591
+ this.#updateDisabledState();
1592
+ trackExpressWalletImpression(this.#offer.sku_id, {
1593
+ entryPoint: this.#entryPoint,
1594
+ country: this.#country
1595
+ });
1596
+ }
1587
1597
  }
1588
1598
  // ─── Private helpers ────────────────────────────────────────────────────────
1589
1599
  #updateDisabledState() {
@@ -1592,28 +1602,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1592
1602
  if (this.#offer) {
1593
1603
  button.removeAttribute("disabled");
1594
1604
  button.removeAttribute("aria-disabled");
1605
+ button.removeAttribute("aria-busy");
1595
1606
  return;
1596
1607
  }
1597
1608
  button.setAttribute("disabled", "");
1598
1609
  button.setAttribute("aria-disabled", "true");
1599
1610
  }
1600
1611
  #openModal() {
1601
- console.log("[web-apple-pay] #openModal: button clicked", { skuId: this.#offer?.sku_id });
1602
- if (!this.#offer) {
1603
- console.warn("[web-apple-pay] #openModal: no offer set, ignoring click");
1604
- return;
1605
- }
1606
- if (document.querySelector(ApplePayModal.tag)) {
1607
- console.warn("[web-apple-pay] #openModal: modal already open, ignoring click");
1608
- return;
1609
- }
1612
+ if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1610
1613
  trackExpressWalletClick(this.#offer.sku_id);
1611
- getPurchaseRecaptchaTokens().then((tokens) => {
1612
- console.log("[web-apple-pay] #openModal: reCAPTCHA tokens pre-fetched");
1613
- this.#recaptchaTokens = tokens;
1614
- }).catch((err) => {
1615
- console.warn("[web-apple-pay] #openModal: reCAPTCHA pre-fetch failed", err);
1616
- });
1617
1614
  ApplePayModal.define();
1618
1615
  const modal = document.createElement(ApplePayModal.tag);
1619
1616
  modal.offer = this.#offer;
@@ -1625,37 +1622,30 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1625
1622
  }
1626
1623
  async #fetchSession() {
1627
1624
  try {
1628
- const session = await getExpressCheckoutSession();
1629
- console.log("[web-apple-pay] #fetchSession: success", { loggedIn: session.loggedIn, userType: session.userType });
1630
- return session;
1631
- } catch (err) {
1632
- console.warn("[web-apple-pay] #fetchSession: failed, falling back to anonymous session", err);
1625
+ return await getExpressCheckoutSession();
1626
+ } catch {
1633
1627
  return null;
1634
1628
  }
1635
1629
  }
1636
1630
  async #fetchPaymentOptions() {
1637
1631
  try {
1638
- const options = await getPaymentOptions({
1632
+ return await getPaymentOptions({
1639
1633
  sku: this.#offer.sku_id,
1640
1634
  countryCode: this.#country,
1641
1635
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
1642
1636
  checkoutUrl: this.#returnUrl
1643
1637
  });
1644
- console.log("[web-apple-pay] #fetchPaymentOptions: success", { hasApplePay: !!options?.options?.apple_pay });
1645
- return options;
1646
- } catch (err) {
1647
- console.warn("[web-apple-pay] #fetchPaymentOptions: failed", err);
1638
+ } catch {
1648
1639
  return null;
1649
1640
  }
1650
1641
  }
1651
1642
  #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
1652
- console.log("[web-apple-pay] #buildSessionParams", { skuId, country, userLoggedIn: sessionData.loggedIn });
1653
1643
  const offer = this.#offer;
1654
1644
  const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
1655
1645
  return {
1656
1646
  countryCode: country,
1657
1647
  currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1658
- supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
1648
+ supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
1659
1649
  totalAmount,
1660
1650
  totalLabel: TOTAL_LABEL,
1661
1651
  skuId,
@@ -1672,12 +1662,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1672
1662
  };
1673
1663
  }
1674
1664
  async #initiateApplePay(skuId, country) {
1675
- console.log("[web-apple-pay] #initiateApplePay: starting", { skuId, country });
1676
1665
  try {
1677
1666
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1678
1667
  const paymentOptions = this.#paymentOptions;
1679
- const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1680
- console.log("[web-apple-pay] #initiateApplePay: tokens ready, starting session", { prefetched: !!this.#recaptchaTokens });
1668
+ const recaptchaTokens = await getPurchaseRecaptchaTokens();
1681
1669
  startApplePaySession(
1682
1670
  this.#buildSessionParams(
1683
1671
  skuId,