@economist/web-apple-pay 0.1.3-beta.45 → 0.1.3-beta.47

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
@@ -576,9 +576,7 @@ var loadRecaptchaScript = (siteKey) => {
576
576
  if (existingScript) {
577
577
  existingScript.addEventListener("load", () => resolve());
578
578
  existingScript.addEventListener("error", () => {
579
- const error = new Error("Failed to load existing reCAPTCHA script");
580
- console.error("[web-apple-pay] reCAPTCHA script load failed (existing script)", error);
581
- reject(error);
579
+ reject(new Error("Failed to load existing reCAPTCHA script"));
582
580
  });
583
581
  return;
584
582
  }
@@ -588,9 +586,7 @@ var loadRecaptchaScript = (siteKey) => {
588
586
  script.defer = true;
589
587
  script.onload = () => resolve();
590
588
  script.onerror = () => {
591
- const error = new Error("Failed to load reCAPTCHA script");
592
- console.error("[web-apple-pay] reCAPTCHA script load failed (new script)", error);
593
- reject(error);
589
+ reject(new Error("Failed to load reCAPTCHA script"));
594
590
  };
595
591
  document.head.appendChild(script);
596
592
  });
@@ -609,20 +605,8 @@ var getRecaptchaToken = async (action) => {
609
605
  });
610
606
  });
611
607
  };
612
- var getPurchaseRecaptchaTokens = async () => {
613
- console.info("[web-apple-pay] Requesting reCAPTCHA tokens (checkEligibility, newBasket, registerUser)");
614
- try {
615
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
616
- getRecaptchaToken("checkEligibility"),
617
- getRecaptchaToken("newBasket"),
618
- getRecaptchaToken("registerUser")
619
- ]);
620
- console.info("[web-apple-pay] All reCAPTCHA tokens acquired successfully");
621
- return { checkEligibility, newBasket, registerUser };
622
- } catch (error) {
623
- console.error("[web-apple-pay] Failed to acquire one or more reCAPTCHA tokens", error);
624
- throw error;
625
- }
608
+ var getPurchaseRecaptchaTokens = () => {
609
+ return getRecaptchaToken("walletPurchase");
626
610
  };
627
611
 
628
612
  // src/apple-pay-modal.ts
@@ -849,10 +833,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
849
833
  #keyHandler = null;
850
834
  #isClosed = false;
851
835
  /**
852
- * Callback invoked from the CTA click handler once the user confirms.
853
- * The caller (ApplePayButton) must call startApplePaySession inside this
854
- * callback to preserve the browser's user-gesture chain — Safari requires
855
- * new ApplePaySession() to execute within the original click stack.
836
+ * Callback invoked synchronously from the CTA click handler.
837
+ * Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
838
+ * by the time this is called. The caller (ApplePayButton) must call
839
+ * new ApplePaySession() synchronously inside this callback to stay within
840
+ * Safari's user-gesture window. The token promise resolves before
841
+ * onPaymentAuthorized fires (user still needs to authenticate on the sheet).
856
842
  */
857
843
  onConfirm = null;
858
844
  set offer(value) {
@@ -957,20 +943,16 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
957
943
  return;
958
944
  }
959
945
  errorElement?.classList.remove("apm__error--visible");
946
+ this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
960
947
  cta.disabled = true;
961
948
  cta.setAttribute("aria-busy", "true");
962
- console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
963
- getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
964
- console.info("[web-apple-pay] reCAPTCHA tokens resolved successfully");
965
- if (this.#isClosed) {
966
- console.warn("[web-apple-pay] Modal was closed before reCAPTCHA resolved \u2014 aborting Apple Pay initiation");
967
- return;
968
- }
969
- console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
970
- this.onConfirm?.(recaptchaTokens);
949
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
950
+ if (!this.#isClosed && this.onConfirm) {
951
+ this.onConfirm(recaptchaTokensPromise);
971
952
  this.close();
972
- }).catch((error) => {
973
- console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
953
+ }
954
+ recaptchaTokensPromise.catch(() => {
955
+ if (this.#isClosed) return;
974
956
  cta.disabled = false;
975
957
  cta.removeAttribute("aria-busy");
976
958
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -995,6 +977,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
995
977
  );
996
978
  }
997
979
  open() {
980
+ this.#isClosed = false;
998
981
  this.#triggerElement = document.activeElement;
999
982
  document.body.appendChild(this);
1000
983
  this.#keyHandler = (event) => {
@@ -1381,28 +1364,22 @@ async function handleMerchantValidation(event, session, config) {
1381
1364
  try {
1382
1365
  const validationHost = new URL(event.validationURL).host;
1383
1366
  if (!validationHost.endsWith("apple.com")) {
1384
- console.error("[web-apple-pay] Merchant validation URL is not from apple.com \u2014 aborting session", { validationURL: event.validationURL });
1385
1367
  session.abort();
1386
1368
  redirectToFallbackCheckout(config);
1387
1369
  return;
1388
1370
  }
1389
- console.info("[web-apple-pay] Merchant validation started", { validationHost });
1390
1371
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1391
- console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1392
1372
  const response = await validateAppleMerchant({
1393
1373
  validationURL: event.validationURL,
1394
1374
  recaptchaToken
1395
1375
  });
1396
1376
  if (!response?.merchantSession) {
1397
- console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1398
1377
  session.abort();
1399
1378
  redirectToFallbackCheckout(config);
1400
1379
  return;
1401
1380
  }
1402
- console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1403
1381
  session.completeMerchantValidation(response.merchantSession);
1404
- } catch (error) {
1405
- console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1382
+ } catch {
1406
1383
  session.abort();
1407
1384
  redirectToFallbackCheckout(config);
1408
1385
  }
@@ -1423,22 +1400,22 @@ function startApplePaySession(config) {
1423
1400
  };
1424
1401
  try {
1425
1402
  const session = new ApplePaySession(3, paymentRequest);
1426
- console.info("[web-apple-pay] ApplePaySession created successfully");
1427
1403
  session.onvalidatemerchant = async (event) => {
1428
1404
  await handleMerchantValidation(event, session, config);
1429
1405
  };
1430
1406
  session.onpaymentauthorized = (event) => {
1431
1407
  trackWalletPaymentAuthorised(config.skuId);
1432
- config.onPaymentAuthorized(event, session);
1408
+ config.onPaymentAuthorized(event, session).catch(() => {
1409
+ session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
1410
+ redirectToFallbackCheckout(config);
1411
+ });
1433
1412
  };
1434
1413
  session.oncancel = () => {
1435
1414
  config.onCancel?.();
1436
1415
  };
1437
1416
  trackWalletPaymentSheetOpen(config.skuId);
1438
1417
  session.begin();
1439
- console.info("[web-apple-pay] ApplePaySession.begin() called \u2014 payment sheet should appear");
1440
- } catch (error) {
1441
- console.error("[web-apple-pay] ApplePaySession creation or begin() threw \u2014 redirecting to fallback checkout", error);
1418
+ } catch {
1442
1419
  redirectToFallbackCheckout(config);
1443
1420
  }
1444
1421
  }
@@ -1620,24 +1597,12 @@ function handleStructuredError(ctx) {
1620
1597
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1621
1598
  const { skuId, returnUrl, country } = config;
1622
1599
  let validatedEmail;
1623
- console.info("[web-apple-pay] Payment authorised \u2014 starting purchase flow", {
1624
- skuId,
1625
- country,
1626
- loggedIn: sessionData.loggedIn,
1627
- userType: sessionData.userType,
1628
- recaptchaTokensPresent: {
1629
- checkEligibility: !!config.recaptchaTokens.checkEligibility,
1630
- newBasket: !!config.recaptchaTokens.newBasket,
1631
- registerUser: !!config.recaptchaTokens.registerUser
1632
- }
1633
- });
1634
1600
  try {
1635
1601
  validatedEmail = validateContacts(
1636
1602
  event,
1637
1603
  sessionData,
1638
1604
  config.supportedBillingCountries
1639
1605
  );
1640
- console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1641
1606
  const result = await performPurchase({
1642
1607
  applePayToken: event.payment.token,
1643
1608
  skuId: config.skuId,
@@ -1646,9 +1611,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1646
1611
  ...event.payment.shippingContact && {
1647
1612
  shippingContact: event.payment.shippingContact
1648
1613
  },
1649
- recaptchaTokens: config.recaptchaTokens
1614
+ recaptchaToken: config.recaptchaToken
1650
1615
  });
1651
- console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1652
1616
  trackWalletPaymentSuccess(skuId, result.basketId);
1653
1617
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1654
1618
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1663,17 +1627,10 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1663
1627
  });
1664
1628
  } catch (err) {
1665
1629
  if (err instanceof ContactValidationError) {
1666
- console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1667
1630
  failApplePaySession(session, err.errors);
1668
1631
  return;
1669
1632
  }
1670
1633
  const walletError = parseWalletApiError(err);
1671
- console.error("[web-apple-pay] Purchase API failed", {
1672
- skuId,
1673
- errorType: walletError?.errorType ?? "UNKNOWN",
1674
- message: walletError?.message,
1675
- err
1676
- });
1677
1634
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1678
1635
  failApplePaySession(session);
1679
1636
  if (!walletError) {
@@ -2204,11 +2161,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2204
2161
  }
2205
2162
  const skuId = this.#offer.sku_id;
2206
2163
  const country = this.#country;
2207
- modal.onConfirm = (recaptchaTokens) => {
2208
- console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2209
- this.#initiateApplePay(skuId, country, recaptchaTokens);
2164
+ modal.onConfirm = (recaptchaTokensPromise) => {
2165
+ this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
2210
2166
  };
2211
- console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2212
2167
  modal.open();
2213
2168
  }
2214
2169
  async #fetchSession() {
@@ -2230,7 +2185,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2230
2185
  return null;
2231
2186
  }
2232
2187
  }
2233
- #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
2188
+ #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
2234
2189
  const offer = this.#offer;
2235
2190
  const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
2236
2191
  return {
@@ -2242,43 +2197,41 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2242
2197
  skuId,
2243
2198
  returnUrl: this.#returnUrl,
2244
2199
  userLoggedIn: sessionData.loggedIn,
2245
- onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
2246
- skuId,
2247
- country,
2248
- currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
2249
- returnUrl: this.#returnUrl,
2250
- supportedBillingCountries: this.#supportedBillingCountries,
2251
- recaptchaTokens
2252
- })
2200
+ onPaymentAuthorized: async (event, session) => {
2201
+ const recaptchaToken = await recaptchaTokensPromise;
2202
+ return handlePaymentAuthorized(event, session, sessionData, {
2203
+ skuId,
2204
+ country,
2205
+ currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
2206
+ returnUrl: this.#returnUrl,
2207
+ supportedBillingCountries: this.#supportedBillingCountries,
2208
+ recaptchaToken
2209
+ });
2210
+ }
2253
2211
  };
2254
2212
  }
2255
- #initiateApplePay(skuId, country, recaptchaTokens) {
2213
+ #initiateApplePay(skuId, country, recaptchaTokensPromise) {
2256
2214
  try {
2257
2215
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2258
2216
  const paymentOptions = this.#paymentOptions;
2259
- console.info("[web-apple-pay] Starting Apple Pay session", {
2260
- skuId,
2261
- country,
2262
- loggedIn: sessionData.loggedIn,
2263
- userType: sessionData.userType,
2264
- hasPaymentOptions: !!paymentOptions,
2265
- recaptchaTokensPresent: {
2266
- checkEligibility: !!recaptchaTokens.checkEligibility,
2267
- newBasket: !!recaptchaTokens.newBasket,
2268
- registerUser: !!recaptchaTokens.registerUser
2269
- }
2270
- });
2217
+ if (!paymentOptions) {
2218
+ return;
2219
+ }
2271
2220
  startApplePaySession(
2272
2221
  this.#buildSessionParams(
2273
2222
  skuId,
2274
2223
  country,
2275
2224
  sessionData,
2276
2225
  paymentOptions,
2277
- recaptchaTokens
2226
+ recaptchaTokensPromise
2278
2227
  )
2279
2228
  );
2280
- } catch (error) {
2281
- console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2229
+ } catch {
2230
+ redirectToFallbackCheckout({
2231
+ returnUrl: this.#returnUrl,
2232
+ skuId,
2233
+ countryCode: country
2234
+ });
2282
2235
  }
2283
2236
  }
2284
2237
  };
@@ -571,9 +571,7 @@ var loadRecaptchaScript = (siteKey) => {
571
571
  if (existingScript) {
572
572
  existingScript.addEventListener("load", () => resolve());
573
573
  existingScript.addEventListener("error", () => {
574
- const error = new Error("Failed to load existing reCAPTCHA script");
575
- console.error("[web-apple-pay] reCAPTCHA script load failed (existing script)", error);
576
- reject(error);
574
+ reject(new Error("Failed to load existing reCAPTCHA script"));
577
575
  });
578
576
  return;
579
577
  }
@@ -583,9 +581,7 @@ var loadRecaptchaScript = (siteKey) => {
583
581
  script.defer = true;
584
582
  script.onload = () => resolve();
585
583
  script.onerror = () => {
586
- const error = new Error("Failed to load reCAPTCHA script");
587
- console.error("[web-apple-pay] reCAPTCHA script load failed (new script)", error);
588
- reject(error);
584
+ reject(new Error("Failed to load reCAPTCHA script"));
589
585
  };
590
586
  document.head.appendChild(script);
591
587
  });
@@ -604,20 +600,8 @@ var getRecaptchaToken = async (action) => {
604
600
  });
605
601
  });
606
602
  };
607
- var getPurchaseRecaptchaTokens = async () => {
608
- console.info("[web-apple-pay] Requesting reCAPTCHA tokens (checkEligibility, newBasket, registerUser)");
609
- try {
610
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
611
- getRecaptchaToken("checkEligibility"),
612
- getRecaptchaToken("newBasket"),
613
- getRecaptchaToken("registerUser")
614
- ]);
615
- console.info("[web-apple-pay] All reCAPTCHA tokens acquired successfully");
616
- return { checkEligibility, newBasket, registerUser };
617
- } catch (error) {
618
- console.error("[web-apple-pay] Failed to acquire one or more reCAPTCHA tokens", error);
619
- throw error;
620
- }
603
+ var getPurchaseRecaptchaTokens = () => {
604
+ return getRecaptchaToken("walletPurchase");
621
605
  };
622
606
 
623
607
  // src/apple-pay-modal.ts
@@ -844,10 +828,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
844
828
  #keyHandler = null;
845
829
  #isClosed = false;
846
830
  /**
847
- * Callback invoked from the CTA click handler once the user confirms.
848
- * The caller (ApplePayButton) must call startApplePaySession inside this
849
- * callback to preserve the browser's user-gesture chain — Safari requires
850
- * new ApplePaySession() to execute within the original click stack.
831
+ * Callback invoked synchronously from the CTA click handler.
832
+ * Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
833
+ * by the time this is called. The caller (ApplePayButton) must call
834
+ * new ApplePaySession() synchronously inside this callback to stay within
835
+ * Safari's user-gesture window. The token promise resolves before
836
+ * onPaymentAuthorized fires (user still needs to authenticate on the sheet).
851
837
  */
852
838
  onConfirm = null;
853
839
  set offer(value) {
@@ -952,20 +938,16 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
952
938
  return;
953
939
  }
954
940
  errorElement?.classList.remove("apm__error--visible");
941
+ this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
955
942
  cta.disabled = true;
956
943
  cta.setAttribute("aria-busy", "true");
957
- console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
958
- getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
959
- console.info("[web-apple-pay] reCAPTCHA tokens resolved successfully");
960
- if (this.#isClosed) {
961
- console.warn("[web-apple-pay] Modal was closed before reCAPTCHA resolved \u2014 aborting Apple Pay initiation");
962
- return;
963
- }
964
- console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
965
- this.onConfirm?.(recaptchaTokens);
944
+ const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
945
+ if (!this.#isClosed && this.onConfirm) {
946
+ this.onConfirm(recaptchaTokensPromise);
966
947
  this.close();
967
- }).catch((error) => {
968
- console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
948
+ }
949
+ recaptchaTokensPromise.catch(() => {
950
+ if (this.#isClosed) return;
969
951
  cta.disabled = false;
970
952
  cta.removeAttribute("aria-busy");
971
953
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -990,6 +972,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
990
972
  );
991
973
  }
992
974
  open() {
975
+ this.#isClosed = false;
993
976
  this.#triggerElement = document.activeElement;
994
977
  document.body.appendChild(this);
995
978
  this.#keyHandler = (event) => {
@@ -1376,28 +1359,22 @@ async function handleMerchantValidation(event, session, config) {
1376
1359
  try {
1377
1360
  const validationHost = new URL(event.validationURL).host;
1378
1361
  if (!validationHost.endsWith("apple.com")) {
1379
- console.error("[web-apple-pay] Merchant validation URL is not from apple.com \u2014 aborting session", { validationURL: event.validationURL });
1380
1362
  session.abort();
1381
1363
  redirectToFallbackCheckout(config);
1382
1364
  return;
1383
1365
  }
1384
- console.info("[web-apple-pay] Merchant validation started", { validationHost });
1385
1366
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1386
- console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1387
1367
  const response = await validateAppleMerchant({
1388
1368
  validationURL: event.validationURL,
1389
1369
  recaptchaToken
1390
1370
  });
1391
1371
  if (!response?.merchantSession) {
1392
- console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1393
1372
  session.abort();
1394
1373
  redirectToFallbackCheckout(config);
1395
1374
  return;
1396
1375
  }
1397
- console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1398
1376
  session.completeMerchantValidation(response.merchantSession);
1399
- } catch (error) {
1400
- console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1377
+ } catch {
1401
1378
  session.abort();
1402
1379
  redirectToFallbackCheckout(config);
1403
1380
  }
@@ -1418,22 +1395,22 @@ function startApplePaySession(config) {
1418
1395
  };
1419
1396
  try {
1420
1397
  const session = new ApplePaySession(3, paymentRequest);
1421
- console.info("[web-apple-pay] ApplePaySession created successfully");
1422
1398
  session.onvalidatemerchant = async (event) => {
1423
1399
  await handleMerchantValidation(event, session, config);
1424
1400
  };
1425
1401
  session.onpaymentauthorized = (event) => {
1426
1402
  trackWalletPaymentAuthorised(config.skuId);
1427
- config.onPaymentAuthorized(event, session);
1403
+ config.onPaymentAuthorized(event, session).catch(() => {
1404
+ session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
1405
+ redirectToFallbackCheckout(config);
1406
+ });
1428
1407
  };
1429
1408
  session.oncancel = () => {
1430
1409
  config.onCancel?.();
1431
1410
  };
1432
1411
  trackWalletPaymentSheetOpen(config.skuId);
1433
1412
  session.begin();
1434
- console.info("[web-apple-pay] ApplePaySession.begin() called \u2014 payment sheet should appear");
1435
- } catch (error) {
1436
- console.error("[web-apple-pay] ApplePaySession creation or begin() threw \u2014 redirecting to fallback checkout", error);
1413
+ } catch {
1437
1414
  redirectToFallbackCheckout(config);
1438
1415
  }
1439
1416
  }
@@ -1615,24 +1592,12 @@ function handleStructuredError(ctx) {
1615
1592
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1616
1593
  const { skuId, returnUrl, country } = config;
1617
1594
  let validatedEmail;
1618
- console.info("[web-apple-pay] Payment authorised \u2014 starting purchase flow", {
1619
- skuId,
1620
- country,
1621
- loggedIn: sessionData.loggedIn,
1622
- userType: sessionData.userType,
1623
- recaptchaTokensPresent: {
1624
- checkEligibility: !!config.recaptchaTokens.checkEligibility,
1625
- newBasket: !!config.recaptchaTokens.newBasket,
1626
- registerUser: !!config.recaptchaTokens.registerUser
1627
- }
1628
- });
1629
1595
  try {
1630
1596
  validatedEmail = validateContacts(
1631
1597
  event,
1632
1598
  sessionData,
1633
1599
  config.supportedBillingCountries
1634
1600
  );
1635
- console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1636
1601
  const result = await performPurchase({
1637
1602
  applePayToken: event.payment.token,
1638
1603
  skuId: config.skuId,
@@ -1641,9 +1606,8 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1641
1606
  ...event.payment.shippingContact && {
1642
1607
  shippingContact: event.payment.shippingContact
1643
1608
  },
1644
- recaptchaTokens: config.recaptchaTokens
1609
+ recaptchaToken: config.recaptchaToken
1645
1610
  });
1646
- console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1647
1611
  trackWalletPaymentSuccess(skuId, result.basketId);
1648
1612
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1649
1613
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1658,17 +1622,10 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1658
1622
  });
1659
1623
  } catch (err) {
1660
1624
  if (err instanceof ContactValidationError) {
1661
- console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1662
1625
  failApplePaySession(session, err.errors);
1663
1626
  return;
1664
1627
  }
1665
1628
  const walletError = parseWalletApiError(err);
1666
- console.error("[web-apple-pay] Purchase API failed", {
1667
- skuId,
1668
- errorType: walletError?.errorType ?? "UNKNOWN",
1669
- message: walletError?.message,
1670
- err
1671
- });
1672
1629
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1673
1630
  failApplePaySession(session);
1674
1631
  if (!walletError) {
@@ -2199,11 +2156,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2199
2156
  }
2200
2157
  const skuId = this.#offer.sku_id;
2201
2158
  const country = this.#country;
2202
- modal.onConfirm = (recaptchaTokens) => {
2203
- console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2204
- this.#initiateApplePay(skuId, country, recaptchaTokens);
2159
+ modal.onConfirm = (recaptchaTokensPromise) => {
2160
+ this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
2205
2161
  };
2206
- console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2207
2162
  modal.open();
2208
2163
  }
2209
2164
  async #fetchSession() {
@@ -2225,7 +2180,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2225
2180
  return null;
2226
2181
  }
2227
2182
  }
2228
- #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
2183
+ #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
2229
2184
  const offer = this.#offer;
2230
2185
  const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
2231
2186
  return {
@@ -2237,43 +2192,41 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2237
2192
  skuId,
2238
2193
  returnUrl: this.#returnUrl,
2239
2194
  userLoggedIn: sessionData.loggedIn,
2240
- onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
2241
- skuId,
2242
- country,
2243
- currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
2244
- returnUrl: this.#returnUrl,
2245
- supportedBillingCountries: this.#supportedBillingCountries,
2246
- recaptchaTokens
2247
- })
2195
+ onPaymentAuthorized: async (event, session) => {
2196
+ const recaptchaToken = await recaptchaTokensPromise;
2197
+ return handlePaymentAuthorized(event, session, sessionData, {
2198
+ skuId,
2199
+ country,
2200
+ currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
2201
+ returnUrl: this.#returnUrl,
2202
+ supportedBillingCountries: this.#supportedBillingCountries,
2203
+ recaptchaToken
2204
+ });
2205
+ }
2248
2206
  };
2249
2207
  }
2250
- #initiateApplePay(skuId, country, recaptchaTokens) {
2208
+ #initiateApplePay(skuId, country, recaptchaTokensPromise) {
2251
2209
  try {
2252
2210
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2253
2211
  const paymentOptions = this.#paymentOptions;
2254
- console.info("[web-apple-pay] Starting Apple Pay session", {
2255
- skuId,
2256
- country,
2257
- loggedIn: sessionData.loggedIn,
2258
- userType: sessionData.userType,
2259
- hasPaymentOptions: !!paymentOptions,
2260
- recaptchaTokensPresent: {
2261
- checkEligibility: !!recaptchaTokens.checkEligibility,
2262
- newBasket: !!recaptchaTokens.newBasket,
2263
- registerUser: !!recaptchaTokens.registerUser
2264
- }
2265
- });
2212
+ if (!paymentOptions) {
2213
+ return;
2214
+ }
2266
2215
  startApplePaySession(
2267
2216
  this.#buildSessionParams(
2268
2217
  skuId,
2269
2218
  country,
2270
2219
  sessionData,
2271
2220
  paymentOptions,
2272
- recaptchaTokens
2221
+ recaptchaTokensPromise
2273
2222
  )
2274
2223
  );
2275
- } catch (error) {
2276
- console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2224
+ } catch {
2225
+ redirectToFallbackCheckout({
2226
+ returnUrl: this.#returnUrl,
2227
+ skuId,
2228
+ countryCode: country
2229
+ });
2277
2230
  }
2278
2231
  }
2279
2232
  };