@economist/web-apple-pay 1.7.0 → 1.7.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
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
317
317
  const offer = this.#offer;
318
318
  const country = this.#country;
319
319
  if (!offer) {
320
- console.error("ApplePayModal: Missing or invalid offer data");
321
320
  this.remove();
322
321
  return;
323
322
  }
@@ -827,6 +826,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
827
826
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
828
827
 
829
828
  // src/clients/payment-checkout/apple-session.ts
829
+ function redirectToFallbackCheckout(config) {
830
+ trackFallbackCheckout(config.skuId);
831
+ window.location.href = redirectToCheckoutFallback({
832
+ skuId: config.skuId,
833
+ returnUrl: config.returnUrl,
834
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
835
+ });
836
+ }
837
+ async function handleMerchantValidation(event, session, config) {
838
+ try {
839
+ const validationHost = new URL(event.validationURL).host;
840
+ if (!validationHost.endsWith("apple.com")) {
841
+ session.abort();
842
+ redirectToFallbackCheckout(config);
843
+ return;
844
+ }
845
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
846
+ const response = await validateAppleMerchant({
847
+ validationURL: event.validationURL,
848
+ recaptchaToken
849
+ });
850
+ if (!response?.merchantSession) {
851
+ session.abort();
852
+ redirectToFallbackCheckout(config);
853
+ return;
854
+ }
855
+ session.completeMerchantValidation(response.merchantSession);
856
+ } catch {
857
+ session.abort();
858
+ redirectToFallbackCheckout(config);
859
+ }
860
+ }
830
861
  function startApplePaySession(config) {
831
862
  const paymentRequest = {
832
863
  countryCode: config.countryCode,
@@ -841,55 +872,23 @@ function startApplePaySession(config) {
841
872
  // Only request email from Apple Pay sheet if user is NOT logged in
842
873
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
843
874
  };
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
855
- });
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) {
864
- trackFallbackCheckout(config.skuId);
865
- session.abort();
866
- window.location.href = redirectToCheckoutFallback({
867
- skuId: config.skuId,
868
- returnUrl: config.returnUrl,
869
- inlineError: MSG_PAYMENT_GENERIC_ERROR
870
- });
871
- return;
872
- }
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();
875
+ try {
876
+ const session = new ApplePaySession(3, paymentRequest);
877
+ session.onvalidatemerchant = async (event) => {
878
+ await handleMerchantValidation(event, session, config);
879
+ };
880
+ session.onpaymentauthorized = (event) => {
881
+ trackWalletPaymentAuthorised(config.skuId);
882
+ config.onPaymentAuthorized(event, session);
883
+ };
884
+ session.oncancel = () => {
885
+ config.onCancel?.();
886
+ };
887
+ trackWalletPaymentSheetOpen(config.skuId);
888
+ session.begin();
889
+ } catch {
890
+ redirectToFallbackCheckout(config);
891
+ }
893
892
  }
894
893
 
895
894
  // src/clients/payment-checkout/contact-validation.ts
@@ -1390,11 +1389,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1390
1389
  * Creates and configures an ApplePayButton if the feature flag is present.
1391
1390
  */
1392
1391
  static createIfEnabled(offer, country, entryPoint) {
1393
- if (!offer) return null;
1394
- if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
1392
+ if (!offer) {
1395
1393
  return null;
1396
- if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
1394
+ }
1395
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1396
+ return null;
1397
+ }
1398
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1397
1399
  return null;
1400
+ }
1398
1401
  _ApplePayButton.define();
1399
1402
  const button = document.createElement(_ApplePayButton.tag);
1400
1403
  button.offer = offer;
@@ -1421,6 +1424,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1421
1424
  #returnUrl = "";
1422
1425
  #supportedBillingCountries = [];
1423
1426
  #entryPoint = "";
1427
+ #recaptchaTokens = null;
1424
1428
  // ─── Public API ─────────────────────────────────────────────────────────────
1425
1429
  get offer() {
1426
1430
  return this.#offer;
@@ -1556,7 +1560,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1556
1560
  */
1557
1561
  async #fetchAndCacheOptions() {
1558
1562
  this.#paymentOptions = await this.#fetchPaymentOptions();
1559
- if (!this.#paymentOptions?.apple_pay) {
1563
+ if (!this.#paymentOptions?.options?.apple_pay) {
1560
1564
  this.style.display = "none";
1561
1565
  this.querySelector(SEL_CONTAINER)?.remove();
1562
1566
  return true;
@@ -1579,10 +1583,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1579
1583
  if (button.classList.contains("wap-loading")) return;
1580
1584
  this.#openModal();
1581
1585
  });
1582
- this.addEventListener("apple-pay-confirmed", (event) => {
1586
+ document.addEventListener("apple-pay-confirmed", (event) => {
1583
1587
  const { skuId, country } = event.detail;
1584
1588
  this.#initiateApplePay(skuId, country);
1585
- });
1589
+ }, { once: true });
1586
1590
  }
1587
1591
  #finishLoading() {
1588
1592
  const button = this.querySelector(SEL_BUTTON);
@@ -1609,8 +1613,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1609
1613
  button.setAttribute("aria-disabled", "true");
1610
1614
  }
1611
1615
  #openModal() {
1612
- if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1616
+ if (!this.#offer) {
1617
+ return;
1618
+ }
1619
+ if (document.querySelector(ApplePayModal.tag)) {
1620
+ return;
1621
+ }
1613
1622
  trackExpressWalletClick(this.#offer.sku_id);
1623
+ getPurchaseRecaptchaTokens().then((tokens) => {
1624
+ this.#recaptchaTokens = tokens;
1625
+ }).catch(() => {
1626
+ });
1614
1627
  ApplePayModal.define();
1615
1628
  const modal = document.createElement(ApplePayModal.tag);
1616
1629
  modal.offer = this.#offer;
@@ -1645,7 +1658,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1645
1658
  return {
1646
1659
  countryCode: country,
1647
1660
  currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1648
- supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
1661
+ supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
1649
1662
  totalAmount,
1650
1663
  totalLabel: TOTAL_LABEL,
1651
1664
  skuId,
@@ -1665,7 +1678,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1665
1678
  try {
1666
1679
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1667
1680
  const paymentOptions = this.#paymentOptions;
1668
- const recaptchaTokens = await getPurchaseRecaptchaTokens();
1681
+ const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1669
1682
  startApplePaySession(
1670
1683
  this.#buildSessionParams(
1671
1684
  skuId,
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
317
317
  const offer = this.#offer;
318
318
  const country = this.#country;
319
319
  if (!offer) {
320
- console.error("ApplePayModal: Missing or invalid offer data");
321
320
  this.remove();
322
321
  return;
323
322
  }
@@ -822,6 +821,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
822
821
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
823
822
 
824
823
  // src/clients/payment-checkout/apple-session.ts
824
+ function redirectToFallbackCheckout(config) {
825
+ trackFallbackCheckout(config.skuId);
826
+ window.location.href = redirectToCheckoutFallback({
827
+ skuId: config.skuId,
828
+ returnUrl: config.returnUrl,
829
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
830
+ });
831
+ }
832
+ async function handleMerchantValidation(event, session, config) {
833
+ try {
834
+ const validationHost = new URL(event.validationURL).host;
835
+ if (!validationHost.endsWith("apple.com")) {
836
+ session.abort();
837
+ redirectToFallbackCheckout(config);
838
+ return;
839
+ }
840
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
841
+ const response = await validateAppleMerchant({
842
+ validationURL: event.validationURL,
843
+ recaptchaToken
844
+ });
845
+ if (!response?.merchantSession) {
846
+ session.abort();
847
+ redirectToFallbackCheckout(config);
848
+ return;
849
+ }
850
+ session.completeMerchantValidation(response.merchantSession);
851
+ } catch {
852
+ session.abort();
853
+ redirectToFallbackCheckout(config);
854
+ }
855
+ }
825
856
  function startApplePaySession(config) {
826
857
  const paymentRequest = {
827
858
  countryCode: config.countryCode,
@@ -836,55 +867,23 @@ function startApplePaySession(config) {
836
867
  // Only request email from Apple Pay sheet if user is NOT logged in
837
868
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
838
869
  };
839
- const session = new ApplePaySession(3, paymentRequest);
840
- session.onvalidatemerchant = async (event) => {
841
- try {
842
- const validationHost = new URL(event.validationURL).host;
843
- if (!validationHost.endsWith("apple.com")) {
844
- trackFallbackCheckout(config.skuId);
845
- session.abort();
846
- window.location.href = redirectToCheckoutFallback({
847
- skuId: config.skuId,
848
- returnUrl: config.returnUrl,
849
- inlineError: MSG_PAYMENT_GENERIC_ERROR
850
- });
851
- return;
852
- }
853
- const recaptchaToken = await getRecaptchaToken("verifyMerchant");
854
- const response = await validateAppleMerchant({
855
- validationURL: event.validationURL,
856
- recaptchaToken
857
- });
858
- if (!response?.merchantSession) {
859
- trackFallbackCheckout(config.skuId);
860
- session.abort();
861
- window.location.href = redirectToCheckoutFallback({
862
- skuId: config.skuId,
863
- returnUrl: config.returnUrl,
864
- inlineError: MSG_PAYMENT_GENERIC_ERROR
865
- });
866
- return;
867
- }
868
- session.completeMerchantValidation(response.merchantSession);
869
- } catch {
870
- trackFallbackCheckout(config.skuId);
871
- session.abort();
872
- window.location.href = redirectToCheckoutFallback({
873
- skuId: config.skuId,
874
- returnUrl: config.returnUrl,
875
- inlineError: MSG_PAYMENT_GENERIC_ERROR
876
- });
877
- }
878
- };
879
- session.onpaymentauthorized = (event) => {
880
- trackWalletPaymentAuthorised(config.skuId);
881
- config.onPaymentAuthorized(event, session);
882
- };
883
- session.oncancel = () => {
884
- config.onCancel?.();
885
- };
886
- trackWalletPaymentSheetOpen(config.skuId);
887
- session.begin();
870
+ try {
871
+ const session = new ApplePaySession(3, paymentRequest);
872
+ session.onvalidatemerchant = async (event) => {
873
+ await handleMerchantValidation(event, session, config);
874
+ };
875
+ session.onpaymentauthorized = (event) => {
876
+ trackWalletPaymentAuthorised(config.skuId);
877
+ config.onPaymentAuthorized(event, session);
878
+ };
879
+ session.oncancel = () => {
880
+ config.onCancel?.();
881
+ };
882
+ trackWalletPaymentSheetOpen(config.skuId);
883
+ session.begin();
884
+ } catch {
885
+ redirectToFallbackCheckout(config);
886
+ }
888
887
  }
889
888
 
890
889
  // src/clients/payment-checkout/contact-validation.ts
@@ -1385,11 +1384,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1385
1384
  * Creates and configures an ApplePayButton if the feature flag is present.
1386
1385
  */
1387
1386
  static createIfEnabled(offer, country, entryPoint) {
1388
- if (!offer) return null;
1389
- if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
1387
+ if (!offer) {
1390
1388
  return null;
1391
- if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
1389
+ }
1390
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1391
+ return null;
1392
+ }
1393
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1392
1394
  return null;
1395
+ }
1393
1396
  _ApplePayButton.define();
1394
1397
  const button = document.createElement(_ApplePayButton.tag);
1395
1398
  button.offer = offer;
@@ -1416,6 +1419,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1416
1419
  #returnUrl = "";
1417
1420
  #supportedBillingCountries = [];
1418
1421
  #entryPoint = "";
1422
+ #recaptchaTokens = null;
1419
1423
  // ─── Public API ─────────────────────────────────────────────────────────────
1420
1424
  get offer() {
1421
1425
  return this.#offer;
@@ -1551,7 +1555,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1551
1555
  */
1552
1556
  async #fetchAndCacheOptions() {
1553
1557
  this.#paymentOptions = await this.#fetchPaymentOptions();
1554
- if (!this.#paymentOptions?.apple_pay) {
1558
+ if (!this.#paymentOptions?.options?.apple_pay) {
1555
1559
  this.style.display = "none";
1556
1560
  this.querySelector(SEL_CONTAINER)?.remove();
1557
1561
  return true;
@@ -1574,10 +1578,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1574
1578
  if (button.classList.contains("wap-loading")) return;
1575
1579
  this.#openModal();
1576
1580
  });
1577
- this.addEventListener("apple-pay-confirmed", (event) => {
1581
+ document.addEventListener("apple-pay-confirmed", (event) => {
1578
1582
  const { skuId, country } = event.detail;
1579
1583
  this.#initiateApplePay(skuId, country);
1580
- });
1584
+ }, { once: true });
1581
1585
  }
1582
1586
  #finishLoading() {
1583
1587
  const button = this.querySelector(SEL_BUTTON);
@@ -1604,8 +1608,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1604
1608
  button.setAttribute("aria-disabled", "true");
1605
1609
  }
1606
1610
  #openModal() {
1607
- if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1611
+ if (!this.#offer) {
1612
+ return;
1613
+ }
1614
+ if (document.querySelector(ApplePayModal.tag)) {
1615
+ return;
1616
+ }
1608
1617
  trackExpressWalletClick(this.#offer.sku_id);
1618
+ getPurchaseRecaptchaTokens().then((tokens) => {
1619
+ this.#recaptchaTokens = tokens;
1620
+ }).catch(() => {
1621
+ });
1609
1622
  ApplePayModal.define();
1610
1623
  const modal = document.createElement(ApplePayModal.tag);
1611
1624
  modal.offer = this.#offer;
@@ -1640,7 +1653,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1640
1653
  return {
1641
1654
  countryCode: country,
1642
1655
  currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1643
- supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
1656
+ supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
1644
1657
  totalAmount,
1645
1658
  totalLabel: TOTAL_LABEL,
1646
1659
  skuId,
@@ -1660,7 +1673,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1660
1673
  try {
1661
1674
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1662
1675
  const paymentOptions = this.#paymentOptions;
1663
- const recaptchaTokens = await getPurchaseRecaptchaTokens();
1676
+ const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1664
1677
  startApplePaySession(
1665
1678
  this.#buildSessionParams(
1666
1679
  skuId,
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
317
317
  const offer = this.#offer;
318
318
  const country = this.#country;
319
319
  if (!offer) {
320
- console.error("ApplePayModal: Missing or invalid offer data");
321
320
  this.remove();
322
321
  return;
323
322
  }
@@ -830,6 +829,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
830
829
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
831
830
 
832
831
  // src/clients/payment-checkout/apple-session.ts
832
+ function redirectToFallbackCheckout(config) {
833
+ trackFallbackCheckout(config.skuId);
834
+ window.location.href = redirectToCheckoutFallback({
835
+ skuId: config.skuId,
836
+ returnUrl: config.returnUrl,
837
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
838
+ });
839
+ }
840
+ async function handleMerchantValidation(event, session, config) {
841
+ try {
842
+ const validationHost = new URL(event.validationURL).host;
843
+ if (!validationHost.endsWith("apple.com")) {
844
+ session.abort();
845
+ redirectToFallbackCheckout(config);
846
+ return;
847
+ }
848
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
849
+ const response = await validateAppleMerchant({
850
+ validationURL: event.validationURL,
851
+ recaptchaToken
852
+ });
853
+ if (!response?.merchantSession) {
854
+ session.abort();
855
+ redirectToFallbackCheckout(config);
856
+ return;
857
+ }
858
+ session.completeMerchantValidation(response.merchantSession);
859
+ } catch {
860
+ session.abort();
861
+ redirectToFallbackCheckout(config);
862
+ }
863
+ }
833
864
  function startApplePaySession(config) {
834
865
  const paymentRequest = {
835
866
  countryCode: config.countryCode,
@@ -844,55 +875,23 @@ function startApplePaySession(config) {
844
875
  // Only request email from Apple Pay sheet if user is NOT logged in
845
876
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
846
877
  };
847
- const session = new ApplePaySession(3, paymentRequest);
848
- session.onvalidatemerchant = async (event) => {
849
- try {
850
- const validationHost = new URL(event.validationURL).host;
851
- if (!validationHost.endsWith("apple.com")) {
852
- trackFallbackCheckout(config.skuId);
853
- session.abort();
854
- window.location.href = redirectToCheckoutFallback({
855
- skuId: config.skuId,
856
- returnUrl: config.returnUrl,
857
- inlineError: MSG_PAYMENT_GENERIC_ERROR
858
- });
859
- return;
860
- }
861
- const recaptchaToken = await getRecaptchaToken("verifyMerchant");
862
- const response = await validateAppleMerchant({
863
- validationURL: event.validationURL,
864
- recaptchaToken
865
- });
866
- if (!response?.merchantSession) {
867
- trackFallbackCheckout(config.skuId);
868
- session.abort();
869
- window.location.href = redirectToCheckoutFallback({
870
- skuId: config.skuId,
871
- returnUrl: config.returnUrl,
872
- inlineError: MSG_PAYMENT_GENERIC_ERROR
873
- });
874
- return;
875
- }
876
- session.completeMerchantValidation(response.merchantSession);
877
- } catch {
878
- trackFallbackCheckout(config.skuId);
879
- session.abort();
880
- window.location.href = redirectToCheckoutFallback({
881
- skuId: config.skuId,
882
- returnUrl: config.returnUrl,
883
- inlineError: MSG_PAYMENT_GENERIC_ERROR
884
- });
885
- }
886
- };
887
- session.onpaymentauthorized = (event) => {
888
- trackWalletPaymentAuthorised(config.skuId);
889
- config.onPaymentAuthorized(event, session);
890
- };
891
- session.oncancel = () => {
892
- config.onCancel?.();
893
- };
894
- trackWalletPaymentSheetOpen(config.skuId);
895
- session.begin();
878
+ try {
879
+ const session = new ApplePaySession(3, paymentRequest);
880
+ session.onvalidatemerchant = async (event) => {
881
+ await handleMerchantValidation(event, session, config);
882
+ };
883
+ session.onpaymentauthorized = (event) => {
884
+ trackWalletPaymentAuthorised(config.skuId);
885
+ config.onPaymentAuthorized(event, session);
886
+ };
887
+ session.oncancel = () => {
888
+ config.onCancel?.();
889
+ };
890
+ trackWalletPaymentSheetOpen(config.skuId);
891
+ session.begin();
892
+ } catch {
893
+ redirectToFallbackCheckout(config);
894
+ }
896
895
  }
897
896
 
898
897
  // src/clients/payment-checkout/contact-validation.ts
@@ -1393,11 +1392,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1393
1392
  * Creates and configures an ApplePayButton if the feature flag is present.
1394
1393
  */
1395
1394
  static createIfEnabled(offer, country, entryPoint) {
1396
- if (!offer) return null;
1397
- if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
1395
+ if (!offer) {
1398
1396
  return null;
1399
- if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
1397
+ }
1398
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1399
+ return null;
1400
+ }
1401
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1400
1402
  return null;
1403
+ }
1401
1404
  _ApplePayButton.define();
1402
1405
  const button = document.createElement(_ApplePayButton.tag);
1403
1406
  button.offer = offer;
@@ -1424,6 +1427,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1424
1427
  #returnUrl = "";
1425
1428
  #supportedBillingCountries = [];
1426
1429
  #entryPoint = "";
1430
+ #recaptchaTokens = null;
1427
1431
  // ─── Public API ─────────────────────────────────────────────────────────────
1428
1432
  get offer() {
1429
1433
  return this.#offer;
@@ -1559,7 +1563,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1559
1563
  */
1560
1564
  async #fetchAndCacheOptions() {
1561
1565
  this.#paymentOptions = await this.#fetchPaymentOptions();
1562
- if (!this.#paymentOptions?.apple_pay) {
1566
+ if (!this.#paymentOptions?.options?.apple_pay) {
1563
1567
  this.style.display = "none";
1564
1568
  this.querySelector(SEL_CONTAINER)?.remove();
1565
1569
  return true;
@@ -1582,10 +1586,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1582
1586
  if (button.classList.contains("wap-loading")) return;
1583
1587
  this.#openModal();
1584
1588
  });
1585
- this.addEventListener("apple-pay-confirmed", (event) => {
1589
+ document.addEventListener("apple-pay-confirmed", (event) => {
1586
1590
  const { skuId, country } = event.detail;
1587
1591
  this.#initiateApplePay(skuId, country);
1588
- });
1592
+ }, { once: true });
1589
1593
  }
1590
1594
  #finishLoading() {
1591
1595
  const button = this.querySelector(SEL_BUTTON);
@@ -1612,8 +1616,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1612
1616
  button.setAttribute("aria-disabled", "true");
1613
1617
  }
1614
1618
  #openModal() {
1615
- if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1619
+ if (!this.#offer) {
1620
+ return;
1621
+ }
1622
+ if (document.querySelector(ApplePayModal.tag)) {
1623
+ return;
1624
+ }
1616
1625
  trackExpressWalletClick(this.#offer.sku_id);
1626
+ getPurchaseRecaptchaTokens().then((tokens) => {
1627
+ this.#recaptchaTokens = tokens;
1628
+ }).catch(() => {
1629
+ });
1617
1630
  ApplePayModal.define();
1618
1631
  const modal = document.createElement(ApplePayModal.tag);
1619
1632
  modal.offer = this.#offer;
@@ -1648,7 +1661,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1648
1661
  return {
1649
1662
  countryCode: country,
1650
1663
  currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1651
- supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
1664
+ supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
1652
1665
  totalAmount,
1653
1666
  totalLabel: TOTAL_LABEL,
1654
1667
  skuId,
@@ -1668,7 +1681,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1668
1681
  try {
1669
1682
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1670
1683
  const paymentOptions = this.#paymentOptions;
1671
- const recaptchaTokens = await getPurchaseRecaptchaTokens();
1684
+ const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1672
1685
  startApplePaySession(
1673
1686
  this.#buildSessionParams(
1674
1687
  skuId,
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
317
317
  const offer = this.#offer;
318
318
  const country = this.#country;
319
319
  if (!offer) {
320
- console.error("ApplePayModal: Missing or invalid offer data");
321
320
  this.remove();
322
321
  return;
323
322
  }
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
317
317
  const offer = this.#offer;
318
318
  const country = this.#country;
319
319
  if (!offer) {
320
- console.error("ApplePayModal: Missing or invalid offer data");
321
320
  this.remove();
322
321
  return;
323
322
  }
@@ -822,6 +821,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
822
821
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
823
822
 
824
823
  // src/clients/payment-checkout/apple-session.ts
824
+ function redirectToFallbackCheckout(config) {
825
+ trackFallbackCheckout(config.skuId);
826
+ window.location.href = redirectToCheckoutFallback({
827
+ skuId: config.skuId,
828
+ returnUrl: config.returnUrl,
829
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
830
+ });
831
+ }
832
+ async function handleMerchantValidation(event, session, config) {
833
+ try {
834
+ const validationHost = new URL(event.validationURL).host;
835
+ if (!validationHost.endsWith("apple.com")) {
836
+ session.abort();
837
+ redirectToFallbackCheckout(config);
838
+ return;
839
+ }
840
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
841
+ const response = await validateAppleMerchant({
842
+ validationURL: event.validationURL,
843
+ recaptchaToken
844
+ });
845
+ if (!response?.merchantSession) {
846
+ session.abort();
847
+ redirectToFallbackCheckout(config);
848
+ return;
849
+ }
850
+ session.completeMerchantValidation(response.merchantSession);
851
+ } catch {
852
+ session.abort();
853
+ redirectToFallbackCheckout(config);
854
+ }
855
+ }
825
856
  function startApplePaySession(config) {
826
857
  const paymentRequest = {
827
858
  countryCode: config.countryCode,
@@ -836,55 +867,23 @@ function startApplePaySession(config) {
836
867
  // Only request email from Apple Pay sheet if user is NOT logged in
837
868
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
838
869
  };
839
- const session = new ApplePaySession(3, paymentRequest);
840
- session.onvalidatemerchant = async (event) => {
841
- try {
842
- const validationHost = new URL(event.validationURL).host;
843
- if (!validationHost.endsWith("apple.com")) {
844
- trackFallbackCheckout(config.skuId);
845
- session.abort();
846
- window.location.href = redirectToCheckoutFallback({
847
- skuId: config.skuId,
848
- returnUrl: config.returnUrl,
849
- inlineError: MSG_PAYMENT_GENERIC_ERROR
850
- });
851
- return;
852
- }
853
- const recaptchaToken = await getRecaptchaToken("verifyMerchant");
854
- const response = await validateAppleMerchant({
855
- validationURL: event.validationURL,
856
- recaptchaToken
857
- });
858
- if (!response?.merchantSession) {
859
- trackFallbackCheckout(config.skuId);
860
- session.abort();
861
- window.location.href = redirectToCheckoutFallback({
862
- skuId: config.skuId,
863
- returnUrl: config.returnUrl,
864
- inlineError: MSG_PAYMENT_GENERIC_ERROR
865
- });
866
- return;
867
- }
868
- session.completeMerchantValidation(response.merchantSession);
869
- } catch {
870
- trackFallbackCheckout(config.skuId);
871
- session.abort();
872
- window.location.href = redirectToCheckoutFallback({
873
- skuId: config.skuId,
874
- returnUrl: config.returnUrl,
875
- inlineError: MSG_PAYMENT_GENERIC_ERROR
876
- });
877
- }
878
- };
879
- session.onpaymentauthorized = (event) => {
880
- trackWalletPaymentAuthorised(config.skuId);
881
- config.onPaymentAuthorized(event, session);
882
- };
883
- session.oncancel = () => {
884
- config.onCancel?.();
885
- };
886
- trackWalletPaymentSheetOpen(config.skuId);
887
- session.begin();
870
+ try {
871
+ const session = new ApplePaySession(3, paymentRequest);
872
+ session.onvalidatemerchant = async (event) => {
873
+ await handleMerchantValidation(event, session, config);
874
+ };
875
+ session.onpaymentauthorized = (event) => {
876
+ trackWalletPaymentAuthorised(config.skuId);
877
+ config.onPaymentAuthorized(event, session);
878
+ };
879
+ session.oncancel = () => {
880
+ config.onCancel?.();
881
+ };
882
+ trackWalletPaymentSheetOpen(config.skuId);
883
+ session.begin();
884
+ } catch {
885
+ redirectToFallbackCheckout(config);
886
+ }
888
887
  }
889
888
 
890
889
  // src/clients/payment-checkout/contact-validation.ts
@@ -1385,11 +1384,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1385
1384
  * Creates and configures an ApplePayButton if the feature flag is present.
1386
1385
  */
1387
1386
  static createIfEnabled(offer, country, entryPoint) {
1388
- if (!offer) return null;
1389
- if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
1387
+ if (!offer) {
1390
1388
  return null;
1391
- if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
1389
+ }
1390
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1391
+ return null;
1392
+ }
1393
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1392
1394
  return null;
1395
+ }
1393
1396
  _ApplePayButton.define();
1394
1397
  const button = document.createElement(_ApplePayButton.tag);
1395
1398
  button.offer = offer;
@@ -1416,6 +1419,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1416
1419
  #returnUrl = "";
1417
1420
  #supportedBillingCountries = [];
1418
1421
  #entryPoint = "";
1422
+ #recaptchaTokens = null;
1419
1423
  // ─── Public API ─────────────────────────────────────────────────────────────
1420
1424
  get offer() {
1421
1425
  return this.#offer;
@@ -1551,7 +1555,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1551
1555
  */
1552
1556
  async #fetchAndCacheOptions() {
1553
1557
  this.#paymentOptions = await this.#fetchPaymentOptions();
1554
- if (!this.#paymentOptions?.apple_pay) {
1558
+ if (!this.#paymentOptions?.options?.apple_pay) {
1555
1559
  this.style.display = "none";
1556
1560
  this.querySelector(SEL_CONTAINER)?.remove();
1557
1561
  return true;
@@ -1574,10 +1578,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1574
1578
  if (button.classList.contains("wap-loading")) return;
1575
1579
  this.#openModal();
1576
1580
  });
1577
- this.addEventListener("apple-pay-confirmed", (event) => {
1581
+ document.addEventListener("apple-pay-confirmed", (event) => {
1578
1582
  const { skuId, country } = event.detail;
1579
1583
  this.#initiateApplePay(skuId, country);
1580
- });
1584
+ }, { once: true });
1581
1585
  }
1582
1586
  #finishLoading() {
1583
1587
  const button = this.querySelector(SEL_BUTTON);
@@ -1604,8 +1608,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1604
1608
  button.setAttribute("aria-disabled", "true");
1605
1609
  }
1606
1610
  #openModal() {
1607
- if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1611
+ if (!this.#offer) {
1612
+ return;
1613
+ }
1614
+ if (document.querySelector(ApplePayModal.tag)) {
1615
+ return;
1616
+ }
1608
1617
  trackExpressWalletClick(this.#offer.sku_id);
1618
+ getPurchaseRecaptchaTokens().then((tokens) => {
1619
+ this.#recaptchaTokens = tokens;
1620
+ }).catch(() => {
1621
+ });
1609
1622
  ApplePayModal.define();
1610
1623
  const modal = document.createElement(ApplePayModal.tag);
1611
1624
  modal.offer = this.#offer;
@@ -1640,7 +1653,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1640
1653
  return {
1641
1654
  countryCode: country,
1642
1655
  currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1643
- supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
1656
+ supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
1644
1657
  totalAmount,
1645
1658
  totalLabel: TOTAL_LABEL,
1646
1659
  skuId,
@@ -1660,7 +1673,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1660
1673
  try {
1661
1674
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1662
1675
  const paymentOptions = this.#paymentOptions;
1663
- const recaptchaTokens = await getPurchaseRecaptchaTokens();
1676
+ const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1664
1677
  startApplePaySession(
1665
1678
  this.#buildSessionParams(
1666
1679
  skuId,
@@ -158,6 +158,38 @@ var trackFallbackCheckout = (skuId) => {
158
158
  var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
159
159
 
160
160
  // src/clients/payment-checkout/apple-session.ts
161
+ function redirectToFallbackCheckout(config) {
162
+ trackFallbackCheckout(config.skuId);
163
+ window.location.href = redirectToCheckoutFallback({
164
+ skuId: config.skuId,
165
+ returnUrl: config.returnUrl,
166
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
167
+ });
168
+ }
169
+ async function handleMerchantValidation(event, session, config) {
170
+ try {
171
+ const validationHost = new URL(event.validationURL).host;
172
+ if (!validationHost.endsWith("apple.com")) {
173
+ session.abort();
174
+ redirectToFallbackCheckout(config);
175
+ return;
176
+ }
177
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
178
+ const response = await validateAppleMerchant({
179
+ validationURL: event.validationURL,
180
+ recaptchaToken
181
+ });
182
+ if (!response?.merchantSession) {
183
+ session.abort();
184
+ redirectToFallbackCheckout(config);
185
+ return;
186
+ }
187
+ session.completeMerchantValidation(response.merchantSession);
188
+ } catch {
189
+ session.abort();
190
+ redirectToFallbackCheckout(config);
191
+ }
192
+ }
161
193
  function startApplePaySession(config) {
162
194
  const paymentRequest = {
163
195
  countryCode: config.countryCode,
@@ -172,55 +204,23 @@ function startApplePaySession(config) {
172
204
  // Only request email from Apple Pay sheet if user is NOT logged in
173
205
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
174
206
  };
175
- const session = new ApplePaySession(3, paymentRequest);
176
- session.onvalidatemerchant = async (event) => {
177
- try {
178
- const validationHost = new URL(event.validationURL).host;
179
- if (!validationHost.endsWith("apple.com")) {
180
- trackFallbackCheckout(config.skuId);
181
- session.abort();
182
- window.location.href = redirectToCheckoutFallback({
183
- skuId: config.skuId,
184
- returnUrl: config.returnUrl,
185
- inlineError: MSG_PAYMENT_GENERIC_ERROR
186
- });
187
- return;
188
- }
189
- const recaptchaToken = await getRecaptchaToken("verifyMerchant");
190
- const response = await validateAppleMerchant({
191
- validationURL: event.validationURL,
192
- recaptchaToken
193
- });
194
- if (!response?.merchantSession) {
195
- trackFallbackCheckout(config.skuId);
196
- session.abort();
197
- window.location.href = redirectToCheckoutFallback({
198
- skuId: config.skuId,
199
- returnUrl: config.returnUrl,
200
- inlineError: MSG_PAYMENT_GENERIC_ERROR
201
- });
202
- return;
203
- }
204
- session.completeMerchantValidation(response.merchantSession);
205
- } catch {
206
- trackFallbackCheckout(config.skuId);
207
- session.abort();
208
- window.location.href = redirectToCheckoutFallback({
209
- skuId: config.skuId,
210
- returnUrl: config.returnUrl,
211
- inlineError: MSG_PAYMENT_GENERIC_ERROR
212
- });
213
- }
214
- };
215
- session.onpaymentauthorized = (event) => {
216
- trackWalletPaymentAuthorised(config.skuId);
217
- config.onPaymentAuthorized(event, session);
218
- };
219
- session.oncancel = () => {
220
- config.onCancel?.();
221
- };
222
- trackWalletPaymentSheetOpen(config.skuId);
223
- session.begin();
207
+ try {
208
+ const session = new ApplePaySession(3, paymentRequest);
209
+ session.onvalidatemerchant = async (event) => {
210
+ await handleMerchantValidation(event, session, config);
211
+ };
212
+ session.onpaymentauthorized = (event) => {
213
+ trackWalletPaymentAuthorised(config.skuId);
214
+ config.onPaymentAuthorized(event, session);
215
+ };
216
+ session.oncancel = () => {
217
+ config.onCancel?.();
218
+ };
219
+ trackWalletPaymentSheetOpen(config.skuId);
220
+ session.begin();
221
+ } catch {
222
+ redirectToFallbackCheckout(config);
223
+ }
224
224
  }
225
225
  export {
226
226
  startApplePaySession
@@ -14,10 +14,12 @@ export type PaymentOptionsRequest = {
14
14
  * Only the apple_pay field is consumed by this package.
15
15
  */
16
16
  export type PaymentOptionsResponse = {
17
- apple_pay?: {
18
- provider: string;
19
- settings: {
20
- supported_networks: string[];
17
+ options: {
18
+ apple_pay?: {
19
+ provider: string;
20
+ settings: {
21
+ supported_networks: string[];
22
+ };
21
23
  };
22
24
  };
23
25
  };
package/dist/src/index.js CHANGED
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
317
317
  const offer = this.#offer;
318
318
  const country = this.#country;
319
319
  if (!offer) {
320
- console.error("ApplePayModal: Missing or invalid offer data");
321
320
  this.remove();
322
321
  return;
323
322
  }
@@ -827,6 +826,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
827
826
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
828
827
 
829
828
  // src/clients/payment-checkout/apple-session.ts
829
+ function redirectToFallbackCheckout(config) {
830
+ trackFallbackCheckout(config.skuId);
831
+ window.location.href = redirectToCheckoutFallback({
832
+ skuId: config.skuId,
833
+ returnUrl: config.returnUrl,
834
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
835
+ });
836
+ }
837
+ async function handleMerchantValidation(event, session, config) {
838
+ try {
839
+ const validationHost = new URL(event.validationURL).host;
840
+ if (!validationHost.endsWith("apple.com")) {
841
+ session.abort();
842
+ redirectToFallbackCheckout(config);
843
+ return;
844
+ }
845
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
846
+ const response = await validateAppleMerchant({
847
+ validationURL: event.validationURL,
848
+ recaptchaToken
849
+ });
850
+ if (!response?.merchantSession) {
851
+ session.abort();
852
+ redirectToFallbackCheckout(config);
853
+ return;
854
+ }
855
+ session.completeMerchantValidation(response.merchantSession);
856
+ } catch {
857
+ session.abort();
858
+ redirectToFallbackCheckout(config);
859
+ }
860
+ }
830
861
  function startApplePaySession(config) {
831
862
  const paymentRequest = {
832
863
  countryCode: config.countryCode,
@@ -841,55 +872,23 @@ function startApplePaySession(config) {
841
872
  // Only request email from Apple Pay sheet if user is NOT logged in
842
873
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
843
874
  };
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
855
- });
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) {
864
- trackFallbackCheckout(config.skuId);
865
- session.abort();
866
- window.location.href = redirectToCheckoutFallback({
867
- skuId: config.skuId,
868
- returnUrl: config.returnUrl,
869
- inlineError: MSG_PAYMENT_GENERIC_ERROR
870
- });
871
- return;
872
- }
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();
875
+ try {
876
+ const session = new ApplePaySession(3, paymentRequest);
877
+ session.onvalidatemerchant = async (event) => {
878
+ await handleMerchantValidation(event, session, config);
879
+ };
880
+ session.onpaymentauthorized = (event) => {
881
+ trackWalletPaymentAuthorised(config.skuId);
882
+ config.onPaymentAuthorized(event, session);
883
+ };
884
+ session.oncancel = () => {
885
+ config.onCancel?.();
886
+ };
887
+ trackWalletPaymentSheetOpen(config.skuId);
888
+ session.begin();
889
+ } catch {
890
+ redirectToFallbackCheckout(config);
891
+ }
893
892
  }
894
893
 
895
894
  // src/clients/payment-checkout/contact-validation.ts
@@ -1390,11 +1389,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1390
1389
  * Creates and configures an ApplePayButton if the feature flag is present.
1391
1390
  */
1392
1391
  static createIfEnabled(offer, country, entryPoint) {
1393
- if (!offer) return null;
1394
- if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
1392
+ if (!offer) {
1395
1393
  return null;
1396
- if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
1394
+ }
1395
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
1396
+ return null;
1397
+ }
1398
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
1397
1399
  return null;
1400
+ }
1398
1401
  _ApplePayButton.define();
1399
1402
  const button = document.createElement(_ApplePayButton.tag);
1400
1403
  button.offer = offer;
@@ -1421,6 +1424,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1421
1424
  #returnUrl = "";
1422
1425
  #supportedBillingCountries = [];
1423
1426
  #entryPoint = "";
1427
+ #recaptchaTokens = null;
1424
1428
  // ─── Public API ─────────────────────────────────────────────────────────────
1425
1429
  get offer() {
1426
1430
  return this.#offer;
@@ -1556,7 +1560,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1556
1560
  */
1557
1561
  async #fetchAndCacheOptions() {
1558
1562
  this.#paymentOptions = await this.#fetchPaymentOptions();
1559
- if (!this.#paymentOptions?.apple_pay) {
1563
+ if (!this.#paymentOptions?.options?.apple_pay) {
1560
1564
  this.style.display = "none";
1561
1565
  this.querySelector(SEL_CONTAINER)?.remove();
1562
1566
  return true;
@@ -1579,10 +1583,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1579
1583
  if (button.classList.contains("wap-loading")) return;
1580
1584
  this.#openModal();
1581
1585
  });
1582
- this.addEventListener("apple-pay-confirmed", (event) => {
1586
+ document.addEventListener("apple-pay-confirmed", (event) => {
1583
1587
  const { skuId, country } = event.detail;
1584
1588
  this.#initiateApplePay(skuId, country);
1585
- });
1589
+ }, { once: true });
1586
1590
  }
1587
1591
  #finishLoading() {
1588
1592
  const button = this.querySelector(SEL_BUTTON);
@@ -1609,8 +1613,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1609
1613
  button.setAttribute("aria-disabled", "true");
1610
1614
  }
1611
1615
  #openModal() {
1612
- if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1616
+ if (!this.#offer) {
1617
+ return;
1618
+ }
1619
+ if (document.querySelector(ApplePayModal.tag)) {
1620
+ return;
1621
+ }
1613
1622
  trackExpressWalletClick(this.#offer.sku_id);
1623
+ getPurchaseRecaptchaTokens().then((tokens) => {
1624
+ this.#recaptchaTokens = tokens;
1625
+ }).catch(() => {
1626
+ });
1614
1627
  ApplePayModal.define();
1615
1628
  const modal = document.createElement(ApplePayModal.tag);
1616
1629
  modal.offer = this.#offer;
@@ -1645,7 +1658,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1645
1658
  return {
1646
1659
  countryCode: country,
1647
1660
  currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1648
- supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
1661
+ supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
1649
1662
  totalAmount,
1650
1663
  totalLabel: TOTAL_LABEL,
1651
1664
  skuId,
@@ -1665,7 +1678,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1665
1678
  try {
1666
1679
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1667
1680
  const paymentOptions = this.#paymentOptions;
1668
- const recaptchaTokens = await getPurchaseRecaptchaTokens();
1681
+ const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1669
1682
  startApplePaySession(
1670
1683
  this.#buildSessionParams(
1671
1684
  skuId,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@economist/web-apple-pay",
3
3
  "description": "Web component package for Apple Pay checkout UI",
4
- "version": "1.7.0",
4
+ "version": "1.7.1",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",