@economist/web-apple-pay 0.1.3-beta.0 → 0.1.3-beta.2

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();
@@ -319,11 +317,9 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
319
317
  const offer = this.#offer;
320
318
  const country = this.#country;
321
319
  if (!offer) {
322
- console.error("ApplePayModal: Missing or invalid offer data");
323
320
  this.remove();
324
321
  return;
325
322
  }
326
- console.log("[web-apple-pay] ApplePayModal: rendering for offer", { skuId: offer.sku_id, country });
327
323
  const offerNameElement = this.querySelector(
328
324
  "#apple-pay-modal-offer-name"
329
325
  );
@@ -396,14 +392,11 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
396
392
  });
397
393
  }
398
394
  cta?.addEventListener("click", () => {
399
- console.log("[web-apple-pay] ApplePayModal: CTA clicked", { skuId: offer.sku_id, country, isUS });
400
395
  if (isUS && checkbox && !checkbox.checked) {
401
- console.log("[web-apple-pay] ApplePayModal: T&C checkbox not accepted, showing error");
402
396
  errorElement?.classList.add("apm__error--visible");
403
397
  checkboxLabel?.classList.add("apm__checkbox-label--error");
404
398
  return;
405
399
  }
406
- console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed", { skuId: offer.sku_id, country });
407
400
  this.dispatchEvent(
408
401
  new CustomEvent("apple-pay-confirmed", {
409
402
  bubbles: true,
@@ -411,7 +404,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
411
404
  detail: { skuId: offer.sku_id, country }
412
405
  })
413
406
  );
414
- console.log("[web-apple-pay] ApplePayModal: dispatching apple-pay-confirmed-final", { skuId: offer.sku_id, country });
407
+ this.close();
415
408
  });
416
409
  this.querySelector("#apple-pay-modal-close")?.addEventListener(
417
410
  "click",
@@ -419,7 +412,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
419
412
  );
420
413
  }
421
414
  open() {
422
- console.log("[web-apple-pay] ApplePayModal: open()");
423
415
  this.#triggerElement = document.activeElement;
424
416
  document.body.appendChild(this);
425
417
  this.#keyHandler = (event) => {
@@ -434,7 +426,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
434
426
  this.querySelector("#apple-pay-modal")?.focus();
435
427
  }
436
428
  close() {
437
- console.log("[web-apple-pay] ApplePayModal: close()");
438
429
  if (this.#keyHandler) {
439
430
  document.removeEventListener("keydown", this.#keyHandler, {
440
431
  capture: true
@@ -447,7 +438,91 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
447
438
  };
448
439
 
449
440
  // 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';
441
+ var apple_pay_button_template_default = `<style>
442
+ /* Use CSS variables for layout so parent walls can easily override placement and sizing */
443
+ teg-apple-pay-button {
444
+ display: block;
445
+ margin: var(--apple-pay-margin, 0);
446
+ width: 100%;
447
+ height: 100%;
448
+ }
449
+
450
+ teg-apple-pay-button .apple-pay-container {
451
+ display: flex;
452
+ flex-direction: column;
453
+ align-items: stretch;
454
+ width: 100%;
455
+ height: 100%;
456
+ }
457
+
458
+ teg-apple-pay-button .apple-pay-btn {
459
+ display: flex;
460
+ align-items: center;
461
+ justify-content: center;
462
+ gap: 0.375rem;
463
+ width: 100%;
464
+ min-width: 0;
465
+ height: 100%;
466
+ min-height: var(--apple-pay-height, 2.75rem);
467
+ background-color: #000;
468
+ color: #fff;
469
+ border: none;
470
+ border-radius: var(--apple-pay-border-radius, 1.375rem);
471
+ cursor: pointer;
472
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
473
+ font-size: 1.0625rem;
474
+ font-weight: 500;
475
+ }
476
+
477
+ teg-apple-pay-button .apple-pay-btn svg {
478
+ flex-shrink: 0;
479
+ display: block;
480
+ }
481
+
482
+ teg-apple-pay-button .apple-pay-btn.wap-loading {
483
+ position: relative;
484
+ cursor: default;
485
+ }
486
+
487
+ teg-apple-pay-button .apple-pay-btn.wap-loading svg {
488
+ visibility: hidden;
489
+ }
490
+
491
+ teg-apple-pay-button .apple-pay-btn.wap-loading::after {
492
+ content: '';
493
+ position: absolute;
494
+ left: 50%;
495
+ top: 50%;
496
+ margin-left: -0.625rem;
497
+ margin-top: -0.625rem;
498
+ width: 1.25rem;
499
+ height: 1.25rem;
500
+ border: 2px solid rgba(255, 255, 255, 0.2);
501
+ border-top-color: #fff;
502
+ border-radius: 50%;
503
+ animation: wap-button-spinner 0.8s linear infinite;
504
+ }
505
+
506
+ @keyframes wap-button-spinner {
507
+ to {
508
+ transform: rotate(360deg);
509
+ }
510
+ }
511
+ </style>
512
+
513
+ <div class="apple-pay-container" aria-label="Express checkout with Apple Pay">
514
+ <button
515
+ class="apple-pay-btn"
516
+ type="button"
517
+ aria-label="Pay with Apple Pay"
518
+ data-analytics="paywall:apple-pay-checkout"
519
+ >
520
+ <svg width="51" height="22" aria-label="Apple Pay" role="img">
521
+ <use href="#apple-pay-logo" />
522
+ </svg>
523
+ </button>
524
+ </div>
525
+ `;
451
526
 
452
527
  // src/clients/payment-checkout/config.ts
453
528
  var runtimeConfig = null;
@@ -766,6 +841,65 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
766
841
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
767
842
 
768
843
  // src/clients/payment-checkout/apple-session.ts
844
+ function redirectToFallbackCheckout(config) {
845
+ console.warn("[web-apple-pay] redirectToFallbackCheckout", {
846
+ skuId: config.skuId,
847
+ returnUrl: config.returnUrl,
848
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
849
+ });
850
+ trackFallbackCheckout(config.skuId);
851
+ window.location.href = redirectToCheckoutFallback({
852
+ skuId: config.skuId,
853
+ returnUrl: config.returnUrl,
854
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
855
+ });
856
+ }
857
+ async function handleMerchantValidation(event, session, config) {
858
+ console.log("[web-apple-pay] handleMerchantValidation: start", {
859
+ skuId: config.skuId,
860
+ validationURL: event.validationURL
861
+ });
862
+ try {
863
+ const validationHost = new URL(event.validationURL).host;
864
+ console.log("[web-apple-pay] handleMerchantValidation: host parsed", {
865
+ validationHost
866
+ });
867
+ if (!validationHost.endsWith("apple.com")) {
868
+ console.warn(
869
+ "[web-apple-pay] handleMerchantValidation: invalid validation host",
870
+ { validationHost }
871
+ );
872
+ session.abort();
873
+ redirectToFallbackCheckout(config);
874
+ return;
875
+ }
876
+ console.log("[web-apple-pay] handleMerchantValidation: requesting recaptcha token");
877
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
878
+ console.log("[web-apple-pay] handleMerchantValidation: recaptcha token received");
879
+ const response = await validateAppleMerchant({
880
+ validationURL: event.validationURL,
881
+ recaptchaToken
882
+ });
883
+ if (!response?.merchantSession) {
884
+ console.warn(
885
+ "[web-apple-pay] handleMerchantValidation: missing merchantSession in response"
886
+ );
887
+ session.abort();
888
+ redirectToFallbackCheckout(config);
889
+ return;
890
+ }
891
+ console.log("[web-apple-pay] handleMerchantValidation: completing merchant validation");
892
+ session.completeMerchantValidation(response.merchantSession);
893
+ console.log("[web-apple-pay] handleMerchantValidation: success");
894
+ } catch (err) {
895
+ console.error("[web-apple-pay] handleMerchantValidation: failed", {
896
+ skuId: config.skuId,
897
+ err
898
+ });
899
+ session.abort();
900
+ redirectToFallbackCheckout(config);
901
+ }
902
+ }
769
903
  function startApplePaySession(config) {
770
904
  console.log("[web-apple-pay] startApplePaySession", {
771
905
  skuId: config.skuId,
@@ -787,74 +921,44 @@ function startApplePaySession(config) {
787
921
  // Only request email from Apple Pay sheet if user is NOT logged in
788
922
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
789
923
  };
924
+ console.log("[web-apple-pay] startApplePaySession: payment request created", {
925
+ skuId: config.skuId,
926
+ requiredShippingContactFields: paymentRequest.requiredShippingContactFields
927
+ });
790
928
  try {
791
929
  const session = new ApplePaySession(3, paymentRequest);
792
930
  console.log("[web-apple-pay] startApplePaySession: ApplePaySession created");
793
931
  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
813
- });
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);
829
- trackFallbackCheckout(config.skuId);
830
- session.abort();
831
- window.location.href = redirectToCheckoutFallback({
832
- skuId: config.skuId,
833
- returnUrl: config.returnUrl,
834
- inlineError: MSG_PAYMENT_GENERIC_ERROR
835
- });
836
- }
932
+ console.log("[web-apple-pay] onvalidatemerchant: invoked", {
933
+ skuId: config.skuId
934
+ });
935
+ await handleMerchantValidation(event, session, config);
837
936
  };
838
937
  session.onpaymentauthorized = (event) => {
839
- console.log("[web-apple-pay] onpaymentauthorized: payment authorized by user", { skuId: config.skuId });
938
+ console.log("[web-apple-pay] onpaymentauthorized: invoked", {
939
+ skuId: config.skuId
940
+ });
840
941
  trackWalletPaymentAuthorised(config.skuId);
841
942
  config.onPaymentAuthorized(event, session);
842
943
  };
843
944
  session.oncancel = () => {
844
- console.log("[web-apple-pay] oncancel: payment sheet cancelled by user", { skuId: config.skuId });
945
+ console.log("[web-apple-pay] oncancel: invoked", {
946
+ skuId: config.skuId
947
+ });
845
948
  config.onCancel?.();
846
949
  };
847
- console.log("[web-apple-pay] startApplePaySession: beginning session");
950
+ console.log("[web-apple-pay] startApplePaySession: opening payment sheet", {
951
+ skuId: config.skuId
952
+ });
848
953
  trackWalletPaymentSheetOpen(config.skuId);
849
954
  session.begin();
955
+ console.log("[web-apple-pay] startApplePaySession: session begin called");
850
956
  } 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({
957
+ console.error("[web-apple-pay] startApplePaySession: failed to start session", {
854
958
  skuId: config.skuId,
855
- returnUrl: config.returnUrl,
856
- inlineError: MSG_PAYMENT_GENERIC_ERROR
959
+ err
857
960
  });
961
+ redirectToFallbackCheckout(config);
858
962
  }
859
963
  }
860
964
 
@@ -944,13 +1048,25 @@ var billingContactDetails = (contact, supportedBillingCountries) => {
944
1048
  // src/clients/payment-checkout/shipping-contact-details.ts
945
1049
  var EMAIL_FORMAT_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
946
1050
  var shippingContactDetails = (shippingContact) => {
1051
+ console.log("[web-apple-pay] shippingContactDetails: start", {
1052
+ hasShippingContact: Boolean(shippingContact),
1053
+ hasEmailAddress: shippingContact?.emailAddress !== void 0
1054
+ });
947
1055
  const errors = [];
948
1056
  let emailAddress = "";
949
1057
  if (shippingContact?.emailAddress === void 0 || shippingContact?.emailAddress === "") {
1058
+ console.log(
1059
+ "[web-apple-pay] shippingContactDetails: email missing or empty"
1060
+ );
950
1061
  pushRequiredFieldError(errors, "shipping", "emailAddress");
951
1062
  } else {
1063
+ console.log("[web-apple-pay] shippingContactDetails: email provided");
952
1064
  emailAddress = shippingContact.emailAddress.trim();
1065
+ console.log("[web-apple-pay] shippingContactDetails: email trimmed", {
1066
+ emailLength: emailAddress.length
1067
+ });
953
1068
  if (emailAddress.length > 80) {
1069
+ console.log("[web-apple-pay] shippingContactDetails: email too long");
954
1070
  pushFieldError(
955
1071
  errors,
956
1072
  "shipping",
@@ -959,6 +1075,9 @@ var shippingContactDetails = (shippingContact) => {
959
1075
  MSG_EMAIL_TOO_LONG
960
1076
  );
961
1077
  } else if (!EMAIL_FORMAT_REGEX.test(emailAddress)) {
1078
+ console.log(
1079
+ "[web-apple-pay] shippingContactDetails: email format invalid"
1080
+ );
962
1081
  pushFieldError(
963
1082
  errors,
964
1083
  "shipping",
@@ -966,11 +1085,17 @@ var shippingContactDetails = (shippingContact) => {
966
1085
  "format",
967
1086
  MSG_EMAIL_WRONG_FORMAT
968
1087
  );
1088
+ } else {
1089
+ console.log("[web-apple-pay] shippingContactDetails: email valid");
969
1090
  }
970
1091
  }
971
1092
  if (errors.length > 0) {
1093
+ console.log("[web-apple-pay] shippingContactDetails: throwing validation error", {
1094
+ errorCount: errors.length
1095
+ });
972
1096
  throw new ContactValidationError(errors);
973
1097
  }
1098
+ console.log("[web-apple-pay] shippingContactDetails: success");
974
1099
  return { emailAddress };
975
1100
  };
976
1101
 
@@ -1371,18 +1496,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1371
1496
  */
1372
1497
  static createIfEnabled(offer, country, entryPoint) {
1373
1498
  if (!offer) {
1374
- console.log("[web-apple-pay] createIfEnabled: no offer provided \u2192 null");
1375
1499
  return null;
1376
1500
  }
1377
1501
  if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1378
- console.log("[web-apple-pay] createIfEnabled: excluded variant \u2192 null", { variant: offer.product?.variant });
1379
1502
  return null;
1380
1503
  }
1381
1504
  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
1505
  return null;
1384
1506
  }
1385
- console.log("[web-apple-pay] createIfEnabled: creating button", { skuId: offer.sku_id, country, entryPoint });
1386
1507
  _ApplePayButton.define();
1387
1508
  const button = document.createElement(_ApplePayButton.tag);
1388
1509
  button.offer = offer;
@@ -1451,9 +1572,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1451
1572
  }
1452
1573
  // ─── Lifecycle ──────────────────────────────────────────────────────────────
1453
1574
  async connectedCallback() {
1454
- console.log("[web-apple-pay] connectedCallback: element connected");
1455
1575
  if (this.#rendering || this.querySelector(SEL_CONTAINER)) {
1456
- console.log("[web-apple-pay] connectedCallback: already rendering or rendered, skipping");
1457
1576
  return;
1458
1577
  }
1459
1578
  this.#rendering = true;
@@ -1470,7 +1589,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1470
1589
  * and eliminating the implicit reliance on the DOM as a render-state flag.
1471
1590
  */
1472
1591
  disconnectedCallback() {
1473
- console.log("[web-apple-pay] disconnectedCallback: element removed from DOM, resetting state");
1474
1592
  this.#rendering = false;
1475
1593
  this.#readyPromise = null;
1476
1594
  this.#sessionData = null;
@@ -1481,17 +1599,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1481
1599
  }
1482
1600
  // ─── Render pipeline ────────────────────────────────────────────────────────
1483
1601
  async #run() {
1484
- console.log("[web-apple-pay] #run: starting render pipeline");
1485
1602
  try {
1486
1603
  if (await this.#checkAvailability()) return;
1487
- if (await this.#checkSession()) return;
1488
1604
  if (this.#checkOffer()) return;
1605
+ this.#renderTemplate();
1606
+ if (await this.#checkSession()) return;
1489
1607
  this.#captureReturnUrl();
1490
1608
  this.#computeBillingCountries();
1491
1609
  if (await this.#fetchAndCacheOptions()) return;
1492
- this.#renderTemplate();
1610
+ this.#finishLoading();
1493
1611
  } catch {
1494
1612
  this.style.display = "none";
1613
+ this.querySelector(SEL_CONTAINER)?.remove();
1495
1614
  } finally {
1496
1615
  this.#rendering = false;
1497
1616
  }
@@ -1500,11 +1619,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1500
1619
  async #checkAvailability() {
1501
1620
  const available = await isApplePayAvailable();
1502
1621
  if (!available) {
1503
- console.log("[web-apple-pay] #checkAvailability: Apple Pay unavailable \u2192 hiding");
1504
1622
  this.style.display = "none";
1505
1623
  return true;
1506
1624
  }
1507
- console.log("[web-apple-pay] #checkAvailability: Apple Pay available");
1508
1625
  return false;
1509
1626
  }
1510
1627
  /**
@@ -1513,10 +1630,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1513
1630
  */
1514
1631
  async #checkSession() {
1515
1632
  this.#sessionData = await this.#fetchSession();
1516
- console.log("[web-apple-pay] #checkSession: session fetched", { loggedIn: this.#sessionData?.loggedIn, userType: this.#sessionData?.userType });
1517
1633
  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
1634
  this.style.display = "none";
1635
+ this.querySelector(SEL_CONTAINER)?.remove();
1520
1636
  return true;
1521
1637
  }
1522
1638
  return false;
@@ -1524,17 +1640,14 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1524
1640
  /** Returns `true` (hide) when no offer has been set before mount. */
1525
1641
  #checkOffer() {
1526
1642
  if (!this.#offer) {
1527
- console.log("[web-apple-pay] #checkOffer: no offer set \u2192 hiding");
1528
1643
  this.style.display = "none";
1529
1644
  return true;
1530
1645
  }
1531
- console.log("[web-apple-pay] #checkOffer: offer present", { skuId: this.#offer.sku_id });
1532
1646
  return false;
1533
1647
  }
1534
1648
  /** Captures the current page URL once at mount for reuse across the session lifetime. */
1535
1649
  #captureReturnUrl() {
1536
1650
  this.#returnUrl = captureOriginUrl();
1537
- console.log("[web-apple-pay] #captureReturnUrl:", this.#returnUrl);
1538
1651
  }
1539
1652
  /**
1540
1653
  * Computes supported billing countries once at mount.
@@ -1546,7 +1659,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1546
1659
  this.#country,
1547
1660
  this.#offer.product?.variant ?? ""
1548
1661
  );
1549
- console.log("[web-apple-pay] #computeBillingCountries:", this.#supportedBillingCountries);
1550
1662
  }
1551
1663
  /**
1552
1664
  * Returns `true` (hide) when the wallet BFF reports Apple Pay is unavailable
@@ -1554,37 +1666,45 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1554
1666
  */
1555
1667
  async #fetchAndCacheOptions() {
1556
1668
  this.#paymentOptions = await this.#fetchPaymentOptions();
1557
- console.log("[web-apple-pay] #fetchAndCacheOptions: fetched payment options", { paymentOptions: this.#paymentOptions });
1558
1669
  if (!this.#paymentOptions?.options?.apple_pay) {
1559
- console.log("[web-apple-pay] #fetchAndCacheOptions: apple_pay not in options \u2192 hiding");
1560
1670
  this.style.display = "none";
1671
+ this.querySelector(SEL_CONTAINER)?.remove();
1561
1672
  return true;
1562
1673
  }
1563
1674
  return false;
1564
1675
  }
1565
1676
  /** Injects the button template and wires click and confirm event listeners. */
1566
1677
  #renderTemplate() {
1567
- console.log("[web-apple-pay] #renderTemplate: rendering Apple Pay button", { skuId: this.#offer?.sku_id, country: this.#country });
1568
1678
  this.style.removeProperty("display");
1569
1679
  ensureApplePayLogoSymbol();
1570
1680
  const template = document.createElement("template");
1571
1681
  template.innerHTML = apple_pay_button_template_default;
1572
1682
  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
1683
  const button = this.querySelector(SEL_BUTTON);
1684
+ button.classList.add("wap-loading");
1685
+ button.setAttribute("disabled", "");
1686
+ button.setAttribute("aria-disabled", "true");
1687
+ button.setAttribute("aria-busy", "true");
1579
1688
  button.addEventListener("click", () => {
1689
+ if (button.classList.contains("wap-loading")) return;
1580
1690
  this.#openModal();
1581
1691
  });
1582
1692
  document.addEventListener("apple-pay-confirmed", (event) => {
1583
1693
  const { skuId, country } = event.detail;
1584
- console.log("[web-apple-pay] apple-pay-confirmed received on document", { skuId, country });
1585
1694
  this.#initiateApplePay(skuId, country);
1586
1695
  }, { once: true });
1587
1696
  }
1697
+ #finishLoading() {
1698
+ const button = this.querySelector(SEL_BUTTON);
1699
+ if (button) {
1700
+ button.classList.remove("wap-loading");
1701
+ this.#updateDisabledState();
1702
+ trackExpressWalletImpression(this.#offer.sku_id, {
1703
+ entryPoint: this.#entryPoint,
1704
+ country: this.#country
1705
+ });
1706
+ }
1707
+ }
1588
1708
  // ─── Private helpers ────────────────────────────────────────────────────────
1589
1709
  #updateDisabledState() {
1590
1710
  const button = this.querySelector(SEL_BUTTON);
@@ -1592,27 +1712,23 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1592
1712
  if (this.#offer) {
1593
1713
  button.removeAttribute("disabled");
1594
1714
  button.removeAttribute("aria-disabled");
1715
+ button.removeAttribute("aria-busy");
1595
1716
  return;
1596
1717
  }
1597
1718
  button.setAttribute("disabled", "");
1598
1719
  button.setAttribute("aria-disabled", "true");
1599
1720
  }
1600
1721
  #openModal() {
1601
- console.log("[web-apple-pay] #openModal: button clicked", { skuId: this.#offer?.sku_id });
1602
1722
  if (!this.#offer) {
1603
- console.warn("[web-apple-pay] #openModal: no offer set, ignoring click");
1604
1723
  return;
1605
1724
  }
1606
1725
  if (document.querySelector(ApplePayModal.tag)) {
1607
- console.warn("[web-apple-pay] #openModal: modal already open, ignoring click");
1608
1726
  return;
1609
1727
  }
1610
1728
  trackExpressWalletClick(this.#offer.sku_id);
1611
1729
  getPurchaseRecaptchaTokens().then((tokens) => {
1612
- console.log("[web-apple-pay] #openModal: reCAPTCHA tokens pre-fetched");
1613
1730
  this.#recaptchaTokens = tokens;
1614
- }).catch((err) => {
1615
- console.warn("[web-apple-pay] #openModal: reCAPTCHA pre-fetch failed", err);
1731
+ }).catch(() => {
1616
1732
  });
1617
1733
  ApplePayModal.define();
1618
1734
  const modal = document.createElement(ApplePayModal.tag);
@@ -1625,31 +1741,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1625
1741
  }
1626
1742
  async #fetchSession() {
1627
1743
  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);
1744
+ return await getExpressCheckoutSession();
1745
+ } catch {
1633
1746
  return null;
1634
1747
  }
1635
1748
  }
1636
1749
  async #fetchPaymentOptions() {
1637
1750
  try {
1638
- const options = await getPaymentOptions({
1751
+ return await getPaymentOptions({
1639
1752
  sku: this.#offer.sku_id,
1640
1753
  countryCode: this.#country,
1641
1754
  currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
1642
1755
  checkoutUrl: this.#returnUrl
1643
1756
  });
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);
1757
+ } catch {
1648
1758
  return null;
1649
1759
  }
1650
1760
  }
1651
1761
  #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
1652
- console.log("[web-apple-pay] #buildSessionParams", { skuId, country, userLoggedIn: sessionData.loggedIn });
1653
1762
  const offer = this.#offer;
1654
1763
  const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
1655
1764
  return {
@@ -1672,12 +1781,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1672
1781
  };
1673
1782
  }
1674
1783
  async #initiateApplePay(skuId, country) {
1675
- console.log("[web-apple-pay] #initiateApplePay: starting", { skuId, country });
1676
1784
  try {
1677
1785
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1678
1786
  const paymentOptions = this.#paymentOptions;
1679
1787
  const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1680
- console.log("[web-apple-pay] #initiateApplePay: tokens ready, starting session", { prefetched: !!this.#recaptchaTokens });
1681
1788
  startApplePaySession(
1682
1789
  this.#buildSessionParams(
1683
1790
  skuId,