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

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
@@ -575,10 +575,11 @@ var loadRecaptchaScript = (siteKey) => {
575
575
  );
576
576
  if (existingScript) {
577
577
  existingScript.addEventListener("load", () => resolve());
578
- existingScript.addEventListener(
579
- "error",
580
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
581
- );
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);
582
+ });
582
583
  return;
583
584
  }
584
585
  const script = document.createElement("script");
@@ -586,7 +587,11 @@ var loadRecaptchaScript = (siteKey) => {
586
587
  script.async = true;
587
588
  script.defer = true;
588
589
  script.onload = () => resolve();
589
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
590
+ 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);
594
+ };
590
595
  document.head.appendChild(script);
591
596
  });
592
597
  };
@@ -605,12 +610,19 @@ var getRecaptchaToken = async (action) => {
605
610
  });
606
611
  };
607
612
  var getPurchaseRecaptchaTokens = async () => {
608
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
609
- getRecaptchaToken("checkEligibility"),
610
- getRecaptchaToken("newBasket"),
611
- getRecaptchaToken("registerUser")
612
- ]);
613
- return { checkEligibility, newBasket, registerUser };
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
+ }
614
626
  };
615
627
 
616
628
  // src/apple-pay-modal.ts
@@ -947,11 +959,18 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
947
959
  errorElement?.classList.remove("apm__error--visible");
948
960
  cta.disabled = true;
949
961
  cta.setAttribute("aria-busy", "true");
962
+ console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
950
963
  getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
951
- if (this.#isClosed) return;
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");
952
970
  this.onConfirm?.(recaptchaTokens);
953
971
  this.close();
954
- }).catch(() => {
972
+ }).catch((error) => {
973
+ console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
955
974
  cta.disabled = false;
956
975
  cta.removeAttribute("aria-busy");
957
976
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -1362,22 +1381,28 @@ async function handleMerchantValidation(event, session, config) {
1362
1381
  try {
1363
1382
  const validationHost = new URL(event.validationURL).host;
1364
1383
  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 });
1365
1385
  session.abort();
1366
1386
  redirectToFallbackCheckout(config);
1367
1387
  return;
1368
1388
  }
1389
+ console.info("[web-apple-pay] Merchant validation started", { validationHost });
1369
1390
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1391
+ console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1370
1392
  const response = await validateAppleMerchant({
1371
1393
  validationURL: event.validationURL,
1372
1394
  recaptchaToken
1373
1395
  });
1374
1396
  if (!response?.merchantSession) {
1397
+ console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1375
1398
  session.abort();
1376
1399
  redirectToFallbackCheckout(config);
1377
1400
  return;
1378
1401
  }
1402
+ console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1379
1403
  session.completeMerchantValidation(response.merchantSession);
1380
- } catch {
1404
+ } catch (error) {
1405
+ console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1381
1406
  session.abort();
1382
1407
  redirectToFallbackCheckout(config);
1383
1408
  }
@@ -1398,6 +1423,7 @@ function startApplePaySession(config) {
1398
1423
  };
1399
1424
  try {
1400
1425
  const session = new ApplePaySession(3, paymentRequest);
1426
+ console.info("[web-apple-pay] ApplePaySession created successfully");
1401
1427
  session.onvalidatemerchant = async (event) => {
1402
1428
  await handleMerchantValidation(event, session, config);
1403
1429
  };
@@ -1410,7 +1436,9 @@ function startApplePaySession(config) {
1410
1436
  };
1411
1437
  trackWalletPaymentSheetOpen(config.skuId);
1412
1438
  session.begin();
1413
- } catch {
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);
1414
1442
  redirectToFallbackCheckout(config);
1415
1443
  }
1416
1444
  }
@@ -1592,12 +1620,24 @@ function handleStructuredError(ctx) {
1592
1620
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1593
1621
  const { skuId, returnUrl, country } = config;
1594
1622
  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
+ });
1595
1634
  try {
1596
1635
  validatedEmail = validateContacts(
1597
1636
  event,
1598
1637
  sessionData,
1599
1638
  config.supportedBillingCountries
1600
1639
  );
1640
+ console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1601
1641
  const result = await performPurchase({
1602
1642
  applePayToken: event.payment.token,
1603
1643
  skuId: config.skuId,
@@ -1608,6 +1648,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1608
1648
  },
1609
1649
  recaptchaTokens: config.recaptchaTokens
1610
1650
  });
1651
+ console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1611
1652
  trackWalletPaymentSuccess(skuId, result.basketId);
1612
1653
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1613
1654
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1622,10 +1663,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1622
1663
  });
1623
1664
  } catch (err) {
1624
1665
  if (err instanceof ContactValidationError) {
1666
+ console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1625
1667
  failApplePaySession(session, err.errors);
1626
1668
  return;
1627
1669
  }
1628
1670
  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
+ });
1629
1677
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1630
1678
  failApplePaySession(session);
1631
1679
  if (!walletError) {
@@ -2157,8 +2205,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2157
2205
  const skuId = this.#offer.sku_id;
2158
2206
  const country = this.#country;
2159
2207
  modal.onConfirm = (recaptchaTokens) => {
2208
+ console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2160
2209
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2161
2210
  };
2211
+ console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2162
2212
  modal.open();
2163
2213
  }
2164
2214
  async #fetchSession() {
@@ -2206,6 +2256,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2206
2256
  try {
2207
2257
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2208
2258
  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
+ });
2209
2271
  startApplePaySession(
2210
2272
  this.#buildSessionParams(
2211
2273
  skuId,
@@ -2215,7 +2277,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2215
2277
  recaptchaTokens
2216
2278
  )
2217
2279
  );
2218
- } catch {
2280
+ } catch (error) {
2281
+ console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2219
2282
  }
2220
2283
  }
2221
2284
  };
@@ -570,10 +570,11 @@ var loadRecaptchaScript = (siteKey) => {
570
570
  );
571
571
  if (existingScript) {
572
572
  existingScript.addEventListener("load", () => resolve());
573
- existingScript.addEventListener(
574
- "error",
575
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
576
- );
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);
577
+ });
577
578
  return;
578
579
  }
579
580
  const script = document.createElement("script");
@@ -581,7 +582,11 @@ var loadRecaptchaScript = (siteKey) => {
581
582
  script.async = true;
582
583
  script.defer = true;
583
584
  script.onload = () => resolve();
584
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
585
+ 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);
589
+ };
585
590
  document.head.appendChild(script);
586
591
  });
587
592
  };
@@ -600,12 +605,19 @@ var getRecaptchaToken = async (action) => {
600
605
  });
601
606
  };
602
607
  var getPurchaseRecaptchaTokens = async () => {
603
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
604
- getRecaptchaToken("checkEligibility"),
605
- getRecaptchaToken("newBasket"),
606
- getRecaptchaToken("registerUser")
607
- ]);
608
- return { checkEligibility, newBasket, registerUser };
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
+ }
609
621
  };
610
622
 
611
623
  // src/apple-pay-modal.ts
@@ -942,11 +954,18 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
942
954
  errorElement?.classList.remove("apm__error--visible");
943
955
  cta.disabled = true;
944
956
  cta.setAttribute("aria-busy", "true");
957
+ console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
945
958
  getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
946
- if (this.#isClosed) return;
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");
947
965
  this.onConfirm?.(recaptchaTokens);
948
966
  this.close();
949
- }).catch(() => {
967
+ }).catch((error) => {
968
+ console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
950
969
  cta.disabled = false;
951
970
  cta.removeAttribute("aria-busy");
952
971
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -1357,22 +1376,28 @@ async function handleMerchantValidation(event, session, config) {
1357
1376
  try {
1358
1377
  const validationHost = new URL(event.validationURL).host;
1359
1378
  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 });
1360
1380
  session.abort();
1361
1381
  redirectToFallbackCheckout(config);
1362
1382
  return;
1363
1383
  }
1384
+ console.info("[web-apple-pay] Merchant validation started", { validationHost });
1364
1385
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1386
+ console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1365
1387
  const response = await validateAppleMerchant({
1366
1388
  validationURL: event.validationURL,
1367
1389
  recaptchaToken
1368
1390
  });
1369
1391
  if (!response?.merchantSession) {
1392
+ console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1370
1393
  session.abort();
1371
1394
  redirectToFallbackCheckout(config);
1372
1395
  return;
1373
1396
  }
1397
+ console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1374
1398
  session.completeMerchantValidation(response.merchantSession);
1375
- } catch {
1399
+ } catch (error) {
1400
+ console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1376
1401
  session.abort();
1377
1402
  redirectToFallbackCheckout(config);
1378
1403
  }
@@ -1393,6 +1418,7 @@ function startApplePaySession(config) {
1393
1418
  };
1394
1419
  try {
1395
1420
  const session = new ApplePaySession(3, paymentRequest);
1421
+ console.info("[web-apple-pay] ApplePaySession created successfully");
1396
1422
  session.onvalidatemerchant = async (event) => {
1397
1423
  await handleMerchantValidation(event, session, config);
1398
1424
  };
@@ -1405,7 +1431,9 @@ function startApplePaySession(config) {
1405
1431
  };
1406
1432
  trackWalletPaymentSheetOpen(config.skuId);
1407
1433
  session.begin();
1408
- } catch {
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);
1409
1437
  redirectToFallbackCheckout(config);
1410
1438
  }
1411
1439
  }
@@ -1587,12 +1615,24 @@ function handleStructuredError(ctx) {
1587
1615
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1588
1616
  const { skuId, returnUrl, country } = config;
1589
1617
  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
+ });
1590
1629
  try {
1591
1630
  validatedEmail = validateContacts(
1592
1631
  event,
1593
1632
  sessionData,
1594
1633
  config.supportedBillingCountries
1595
1634
  );
1635
+ console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1596
1636
  const result = await performPurchase({
1597
1637
  applePayToken: event.payment.token,
1598
1638
  skuId: config.skuId,
@@ -1603,6 +1643,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1603
1643
  },
1604
1644
  recaptchaTokens: config.recaptchaTokens
1605
1645
  });
1646
+ console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1606
1647
  trackWalletPaymentSuccess(skuId, result.basketId);
1607
1648
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1608
1649
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1617,10 +1658,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1617
1658
  });
1618
1659
  } catch (err) {
1619
1660
  if (err instanceof ContactValidationError) {
1661
+ console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1620
1662
  failApplePaySession(session, err.errors);
1621
1663
  return;
1622
1664
  }
1623
1665
  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
+ });
1624
1672
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1625
1673
  failApplePaySession(session);
1626
1674
  if (!walletError) {
@@ -2152,8 +2200,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2152
2200
  const skuId = this.#offer.sku_id;
2153
2201
  const country = this.#country;
2154
2202
  modal.onConfirm = (recaptchaTokens) => {
2203
+ console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2155
2204
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2156
2205
  };
2206
+ console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2157
2207
  modal.open();
2158
2208
  }
2159
2209
  async #fetchSession() {
@@ -2201,6 +2251,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2201
2251
  try {
2202
2252
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2203
2253
  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
+ });
2204
2266
  startApplePaySession(
2205
2267
  this.#buildSessionParams(
2206
2268
  skuId,
@@ -2210,7 +2272,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2210
2272
  recaptchaTokens
2211
2273
  )
2212
2274
  );
2213
- } catch {
2275
+ } catch (error) {
2276
+ console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2214
2277
  }
2215
2278
  }
2216
2279
  };
@@ -578,10 +578,11 @@ var loadRecaptchaScript = (siteKey) => {
578
578
  );
579
579
  if (existingScript) {
580
580
  existingScript.addEventListener("load", () => resolve());
581
- existingScript.addEventListener(
582
- "error",
583
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
584
- );
581
+ existingScript.addEventListener("error", () => {
582
+ const error = new Error("Failed to load existing reCAPTCHA script");
583
+ console.error("[web-apple-pay] reCAPTCHA script load failed (existing script)", error);
584
+ reject(error);
585
+ });
585
586
  return;
586
587
  }
587
588
  const script = document.createElement("script");
@@ -589,7 +590,11 @@ var loadRecaptchaScript = (siteKey) => {
589
590
  script.async = true;
590
591
  script.defer = true;
591
592
  script.onload = () => resolve();
592
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
593
+ script.onerror = () => {
594
+ const error = new Error("Failed to load reCAPTCHA script");
595
+ console.error("[web-apple-pay] reCAPTCHA script load failed (new script)", error);
596
+ reject(error);
597
+ };
593
598
  document.head.appendChild(script);
594
599
  });
595
600
  };
@@ -608,12 +613,19 @@ var getRecaptchaToken = async (action) => {
608
613
  });
609
614
  };
610
615
  var getPurchaseRecaptchaTokens = async () => {
611
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
612
- getRecaptchaToken("checkEligibility"),
613
- getRecaptchaToken("newBasket"),
614
- getRecaptchaToken("registerUser")
615
- ]);
616
- return { checkEligibility, newBasket, registerUser };
616
+ console.info("[web-apple-pay] Requesting reCAPTCHA tokens (checkEligibility, newBasket, registerUser)");
617
+ try {
618
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
619
+ getRecaptchaToken("checkEligibility"),
620
+ getRecaptchaToken("newBasket"),
621
+ getRecaptchaToken("registerUser")
622
+ ]);
623
+ console.info("[web-apple-pay] All reCAPTCHA tokens acquired successfully");
624
+ return { checkEligibility, newBasket, registerUser };
625
+ } catch (error) {
626
+ console.error("[web-apple-pay] Failed to acquire one or more reCAPTCHA tokens", error);
627
+ throw error;
628
+ }
617
629
  };
618
630
 
619
631
  // src/apple-pay-modal.ts
@@ -950,11 +962,18 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
950
962
  errorElement?.classList.remove("apm__error--visible");
951
963
  cta.disabled = true;
952
964
  cta.setAttribute("aria-busy", "true");
965
+ console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
953
966
  getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
954
- if (this.#isClosed) return;
967
+ console.info("[web-apple-pay] reCAPTCHA tokens resolved successfully");
968
+ if (this.#isClosed) {
969
+ console.warn("[web-apple-pay] Modal was closed before reCAPTCHA resolved \u2014 aborting Apple Pay initiation");
970
+ return;
971
+ }
972
+ console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
955
973
  this.onConfirm?.(recaptchaTokens);
956
974
  this.close();
957
- }).catch(() => {
975
+ }).catch((error) => {
976
+ console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
958
977
  cta.disabled = false;
959
978
  cta.removeAttribute("aria-busy");
960
979
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -1365,22 +1384,28 @@ async function handleMerchantValidation(event, session, config) {
1365
1384
  try {
1366
1385
  const validationHost = new URL(event.validationURL).host;
1367
1386
  if (!validationHost.endsWith("apple.com")) {
1387
+ console.error("[web-apple-pay] Merchant validation URL is not from apple.com \u2014 aborting session", { validationURL: event.validationURL });
1368
1388
  session.abort();
1369
1389
  redirectToFallbackCheckout(config);
1370
1390
  return;
1371
1391
  }
1392
+ console.info("[web-apple-pay] Merchant validation started", { validationHost });
1372
1393
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1394
+ console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1373
1395
  const response = await validateAppleMerchant({
1374
1396
  validationURL: event.validationURL,
1375
1397
  recaptchaToken
1376
1398
  });
1377
1399
  if (!response?.merchantSession) {
1400
+ console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1378
1401
  session.abort();
1379
1402
  redirectToFallbackCheckout(config);
1380
1403
  return;
1381
1404
  }
1405
+ console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1382
1406
  session.completeMerchantValidation(response.merchantSession);
1383
- } catch {
1407
+ } catch (error) {
1408
+ console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1384
1409
  session.abort();
1385
1410
  redirectToFallbackCheckout(config);
1386
1411
  }
@@ -1401,6 +1426,7 @@ function startApplePaySession(config) {
1401
1426
  };
1402
1427
  try {
1403
1428
  const session = new ApplePaySession(3, paymentRequest);
1429
+ console.info("[web-apple-pay] ApplePaySession created successfully");
1404
1430
  session.onvalidatemerchant = async (event) => {
1405
1431
  await handleMerchantValidation(event, session, config);
1406
1432
  };
@@ -1413,7 +1439,9 @@ function startApplePaySession(config) {
1413
1439
  };
1414
1440
  trackWalletPaymentSheetOpen(config.skuId);
1415
1441
  session.begin();
1416
- } catch {
1442
+ console.info("[web-apple-pay] ApplePaySession.begin() called \u2014 payment sheet should appear");
1443
+ } catch (error) {
1444
+ console.error("[web-apple-pay] ApplePaySession creation or begin() threw \u2014 redirecting to fallback checkout", error);
1417
1445
  redirectToFallbackCheckout(config);
1418
1446
  }
1419
1447
  }
@@ -1595,12 +1623,24 @@ function handleStructuredError(ctx) {
1595
1623
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1596
1624
  const { skuId, returnUrl, country } = config;
1597
1625
  let validatedEmail;
1626
+ console.info("[web-apple-pay] Payment authorised \u2014 starting purchase flow", {
1627
+ skuId,
1628
+ country,
1629
+ loggedIn: sessionData.loggedIn,
1630
+ userType: sessionData.userType,
1631
+ recaptchaTokensPresent: {
1632
+ checkEligibility: !!config.recaptchaTokens.checkEligibility,
1633
+ newBasket: !!config.recaptchaTokens.newBasket,
1634
+ registerUser: !!config.recaptchaTokens.registerUser
1635
+ }
1636
+ });
1598
1637
  try {
1599
1638
  validatedEmail = validateContacts(
1600
1639
  event,
1601
1640
  sessionData,
1602
1641
  config.supportedBillingCountries
1603
1642
  );
1643
+ console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1604
1644
  const result = await performPurchase({
1605
1645
  applePayToken: event.payment.token,
1606
1646
  skuId: config.skuId,
@@ -1611,6 +1651,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1611
1651
  },
1612
1652
  recaptchaTokens: config.recaptchaTokens
1613
1653
  });
1654
+ console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1614
1655
  trackWalletPaymentSuccess(skuId, result.basketId);
1615
1656
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1616
1657
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1625,10 +1666,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1625
1666
  });
1626
1667
  } catch (err) {
1627
1668
  if (err instanceof ContactValidationError) {
1669
+ console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1628
1670
  failApplePaySession(session, err.errors);
1629
1671
  return;
1630
1672
  }
1631
1673
  const walletError = parseWalletApiError(err);
1674
+ console.error("[web-apple-pay] Purchase API failed", {
1675
+ skuId,
1676
+ errorType: walletError?.errorType ?? "UNKNOWN",
1677
+ message: walletError?.message,
1678
+ err
1679
+ });
1632
1680
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1633
1681
  failApplePaySession(session);
1634
1682
  if (!walletError) {
@@ -2160,8 +2208,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2160
2208
  const skuId = this.#offer.sku_id;
2161
2209
  const country = this.#country;
2162
2210
  modal.onConfirm = (recaptchaTokens) => {
2211
+ console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2163
2212
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2164
2213
  };
2214
+ console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2165
2215
  modal.open();
2166
2216
  }
2167
2217
  async #fetchSession() {
@@ -2209,6 +2259,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2209
2259
  try {
2210
2260
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2211
2261
  const paymentOptions = this.#paymentOptions;
2262
+ console.info("[web-apple-pay] Starting Apple Pay session", {
2263
+ skuId,
2264
+ country,
2265
+ loggedIn: sessionData.loggedIn,
2266
+ userType: sessionData.userType,
2267
+ hasPaymentOptions: !!paymentOptions,
2268
+ recaptchaTokensPresent: {
2269
+ checkEligibility: !!recaptchaTokens.checkEligibility,
2270
+ newBasket: !!recaptchaTokens.newBasket,
2271
+ registerUser: !!recaptchaTokens.registerUser
2272
+ }
2273
+ });
2212
2274
  startApplePaySession(
2213
2275
  this.#buildSessionParams(
2214
2276
  skuId,
@@ -2218,7 +2280,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2218
2280
  recaptchaTokens
2219
2281
  )
2220
2282
  );
2221
- } catch {
2283
+ } catch (error) {
2284
+ console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2222
2285
  }
2223
2286
  }
2224
2287
  };
@@ -570,10 +570,11 @@ var loadRecaptchaScript = (siteKey) => {
570
570
  );
571
571
  if (existingScript) {
572
572
  existingScript.addEventListener("load", () => resolve());
573
- existingScript.addEventListener(
574
- "error",
575
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
576
- );
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);
577
+ });
577
578
  return;
578
579
  }
579
580
  const script = document.createElement("script");
@@ -581,7 +582,11 @@ var loadRecaptchaScript = (siteKey) => {
581
582
  script.async = true;
582
583
  script.defer = true;
583
584
  script.onload = () => resolve();
584
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
585
+ 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);
589
+ };
585
590
  document.head.appendChild(script);
586
591
  });
587
592
  };
@@ -600,12 +605,19 @@ var getRecaptchaToken = async (action) => {
600
605
  });
601
606
  };
602
607
  var getPurchaseRecaptchaTokens = async () => {
603
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
604
- getRecaptchaToken("checkEligibility"),
605
- getRecaptchaToken("newBasket"),
606
- getRecaptchaToken("registerUser")
607
- ]);
608
- return { checkEligibility, newBasket, registerUser };
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
+ }
609
621
  };
610
622
 
611
623
  // src/apple-pay-modal.ts
@@ -942,11 +954,18 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
942
954
  errorElement?.classList.remove("apm__error--visible");
943
955
  cta.disabled = true;
944
956
  cta.setAttribute("aria-busy", "true");
957
+ console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
945
958
  getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
946
- if (this.#isClosed) return;
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");
947
965
  this.onConfirm?.(recaptchaTokens);
948
966
  this.close();
949
- }).catch(() => {
967
+ }).catch((error) => {
968
+ console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
950
969
  cta.disabled = false;
951
970
  cta.removeAttribute("aria-busy");
952
971
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -570,10 +570,11 @@ var loadRecaptchaScript = (siteKey) => {
570
570
  );
571
571
  if (existingScript) {
572
572
  existingScript.addEventListener("load", () => resolve());
573
- existingScript.addEventListener(
574
- "error",
575
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
576
- );
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);
577
+ });
577
578
  return;
578
579
  }
579
580
  const script = document.createElement("script");
@@ -581,7 +582,11 @@ var loadRecaptchaScript = (siteKey) => {
581
582
  script.async = true;
582
583
  script.defer = true;
583
584
  script.onload = () => resolve();
584
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
585
+ 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);
589
+ };
585
590
  document.head.appendChild(script);
586
591
  });
587
592
  };
@@ -600,12 +605,19 @@ var getRecaptchaToken = async (action) => {
600
605
  });
601
606
  };
602
607
  var getPurchaseRecaptchaTokens = async () => {
603
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
604
- getRecaptchaToken("checkEligibility"),
605
- getRecaptchaToken("newBasket"),
606
- getRecaptchaToken("registerUser")
607
- ]);
608
- return { checkEligibility, newBasket, registerUser };
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
+ }
609
621
  };
610
622
 
611
623
  // src/apple-pay-modal.ts
@@ -942,11 +954,18 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
942
954
  errorElement?.classList.remove("apm__error--visible");
943
955
  cta.disabled = true;
944
956
  cta.setAttribute("aria-busy", "true");
957
+ console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
945
958
  getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
946
- if (this.#isClosed) return;
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");
947
965
  this.onConfirm?.(recaptchaTokens);
948
966
  this.close();
949
- }).catch(() => {
967
+ }).catch((error) => {
968
+ console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
950
969
  cta.disabled = false;
951
970
  cta.removeAttribute("aria-busy");
952
971
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -1357,22 +1376,28 @@ async function handleMerchantValidation(event, session, config) {
1357
1376
  try {
1358
1377
  const validationHost = new URL(event.validationURL).host;
1359
1378
  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 });
1360
1380
  session.abort();
1361
1381
  redirectToFallbackCheckout(config);
1362
1382
  return;
1363
1383
  }
1384
+ console.info("[web-apple-pay] Merchant validation started", { validationHost });
1364
1385
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1386
+ console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1365
1387
  const response = await validateAppleMerchant({
1366
1388
  validationURL: event.validationURL,
1367
1389
  recaptchaToken
1368
1390
  });
1369
1391
  if (!response?.merchantSession) {
1392
+ console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1370
1393
  session.abort();
1371
1394
  redirectToFallbackCheckout(config);
1372
1395
  return;
1373
1396
  }
1397
+ console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1374
1398
  session.completeMerchantValidation(response.merchantSession);
1375
- } catch {
1399
+ } catch (error) {
1400
+ console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1376
1401
  session.abort();
1377
1402
  redirectToFallbackCheckout(config);
1378
1403
  }
@@ -1393,6 +1418,7 @@ function startApplePaySession(config) {
1393
1418
  };
1394
1419
  try {
1395
1420
  const session = new ApplePaySession(3, paymentRequest);
1421
+ console.info("[web-apple-pay] ApplePaySession created successfully");
1396
1422
  session.onvalidatemerchant = async (event) => {
1397
1423
  await handleMerchantValidation(event, session, config);
1398
1424
  };
@@ -1405,7 +1431,9 @@ function startApplePaySession(config) {
1405
1431
  };
1406
1432
  trackWalletPaymentSheetOpen(config.skuId);
1407
1433
  session.begin();
1408
- } catch {
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);
1409
1437
  redirectToFallbackCheckout(config);
1410
1438
  }
1411
1439
  }
@@ -1587,12 +1615,24 @@ function handleStructuredError(ctx) {
1587
1615
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1588
1616
  const { skuId, returnUrl, country } = config;
1589
1617
  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
+ });
1590
1629
  try {
1591
1630
  validatedEmail = validateContacts(
1592
1631
  event,
1593
1632
  sessionData,
1594
1633
  config.supportedBillingCountries
1595
1634
  );
1635
+ console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1596
1636
  const result = await performPurchase({
1597
1637
  applePayToken: event.payment.token,
1598
1638
  skuId: config.skuId,
@@ -1603,6 +1643,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1603
1643
  },
1604
1644
  recaptchaTokens: config.recaptchaTokens
1605
1645
  });
1646
+ console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1606
1647
  trackWalletPaymentSuccess(skuId, result.basketId);
1607
1648
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1608
1649
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1617,10 +1658,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1617
1658
  });
1618
1659
  } catch (err) {
1619
1660
  if (err instanceof ContactValidationError) {
1661
+ console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1620
1662
  failApplePaySession(session, err.errors);
1621
1663
  return;
1622
1664
  }
1623
1665
  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
+ });
1624
1672
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1625
1673
  failApplePaySession(session);
1626
1674
  if (!walletError) {
@@ -2152,8 +2200,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2152
2200
  const skuId = this.#offer.sku_id;
2153
2201
  const country = this.#country;
2154
2202
  modal.onConfirm = (recaptchaTokens) => {
2203
+ console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2155
2204
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2156
2205
  };
2206
+ console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2157
2207
  modal.open();
2158
2208
  }
2159
2209
  async #fetchSession() {
@@ -2201,6 +2251,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2201
2251
  try {
2202
2252
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2203
2253
  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
+ });
2204
2266
  startApplePaySession(
2205
2267
  this.#buildSessionParams(
2206
2268
  skuId,
@@ -2210,7 +2272,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2210
2272
  recaptchaTokens
2211
2273
  )
2212
2274
  );
2213
- } catch {
2275
+ } catch (error) {
2276
+ console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2214
2277
  }
2215
2278
  }
2216
2279
  };
@@ -108,10 +108,11 @@ var loadRecaptchaScript = (siteKey) => {
108
108
  );
109
109
  if (existingScript) {
110
110
  existingScript.addEventListener("load", () => resolve());
111
- existingScript.addEventListener(
112
- "error",
113
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
114
- );
111
+ existingScript.addEventListener("error", () => {
112
+ const error = new Error("Failed to load existing reCAPTCHA script");
113
+ console.error("[web-apple-pay] reCAPTCHA script load failed (existing script)", error);
114
+ reject(error);
115
+ });
115
116
  return;
116
117
  }
117
118
  const script = document.createElement("script");
@@ -119,7 +120,11 @@ var loadRecaptchaScript = (siteKey) => {
119
120
  script.async = true;
120
121
  script.defer = true;
121
122
  script.onload = () => resolve();
122
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
123
+ script.onerror = () => {
124
+ const error = new Error("Failed to load reCAPTCHA script");
125
+ console.error("[web-apple-pay] reCAPTCHA script load failed (new script)", error);
126
+ reject(error);
127
+ };
123
128
  document.head.appendChild(script);
124
129
  });
125
130
  };
@@ -196,22 +201,28 @@ async function handleMerchantValidation(event, session, config) {
196
201
  try {
197
202
  const validationHost = new URL(event.validationURL).host;
198
203
  if (!validationHost.endsWith("apple.com")) {
204
+ console.error("[web-apple-pay] Merchant validation URL is not from apple.com \u2014 aborting session", { validationURL: event.validationURL });
199
205
  session.abort();
200
206
  redirectToFallbackCheckout(config);
201
207
  return;
202
208
  }
209
+ console.info("[web-apple-pay] Merchant validation started", { validationHost });
203
210
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
211
+ console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
204
212
  const response = await validateAppleMerchant({
205
213
  validationURL: event.validationURL,
206
214
  recaptchaToken
207
215
  });
208
216
  if (!response?.merchantSession) {
217
+ console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
209
218
  session.abort();
210
219
  redirectToFallbackCheckout(config);
211
220
  return;
212
221
  }
222
+ console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
213
223
  session.completeMerchantValidation(response.merchantSession);
214
- } catch {
224
+ } catch (error) {
225
+ console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
215
226
  session.abort();
216
227
  redirectToFallbackCheckout(config);
217
228
  }
@@ -232,6 +243,7 @@ function startApplePaySession(config) {
232
243
  };
233
244
  try {
234
245
  const session = new ApplePaySession(3, paymentRequest);
246
+ console.info("[web-apple-pay] ApplePaySession created successfully");
235
247
  session.onvalidatemerchant = async (event) => {
236
248
  await handleMerchantValidation(event, session, config);
237
249
  };
@@ -244,7 +256,9 @@ function startApplePaySession(config) {
244
256
  };
245
257
  trackWalletPaymentSheetOpen(config.skuId);
246
258
  session.begin();
247
- } catch {
259
+ console.info("[web-apple-pay] ApplePaySession.begin() called \u2014 payment sheet should appear");
260
+ } catch (error) {
261
+ console.error("[web-apple-pay] ApplePaySession creation or begin() threw \u2014 redirecting to fallback checkout", error);
248
262
  redirectToFallbackCheckout(config);
249
263
  }
250
264
  }
@@ -345,12 +345,24 @@ function handleStructuredError(ctx) {
345
345
  async function handlePaymentAuthorized(event, session, sessionData, config) {
346
346
  const { skuId, returnUrl, country } = config;
347
347
  let validatedEmail;
348
+ console.info("[web-apple-pay] Payment authorised \u2014 starting purchase flow", {
349
+ skuId,
350
+ country,
351
+ loggedIn: sessionData.loggedIn,
352
+ userType: sessionData.userType,
353
+ recaptchaTokensPresent: {
354
+ checkEligibility: !!config.recaptchaTokens.checkEligibility,
355
+ newBasket: !!config.recaptchaTokens.newBasket,
356
+ registerUser: !!config.recaptchaTokens.registerUser
357
+ }
358
+ });
348
359
  try {
349
360
  validatedEmail = validateContacts(
350
361
  event,
351
362
  sessionData,
352
363
  config.supportedBillingCountries
353
364
  );
365
+ console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
354
366
  const result = await performPurchase({
355
367
  applePayToken: event.payment.token,
356
368
  skuId: config.skuId,
@@ -361,6 +373,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
361
373
  },
362
374
  recaptchaTokens: config.recaptchaTokens
363
375
  });
376
+ console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
364
377
  trackWalletPaymentSuccess(skuId, result.basketId);
365
378
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
366
379
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -375,10 +388,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
375
388
  });
376
389
  } catch (err) {
377
390
  if (err instanceof ContactValidationError) {
391
+ console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
378
392
  failApplePaySession(session, err.errors);
379
393
  return;
380
394
  }
381
395
  const walletError = parseWalletApiError(err);
396
+ console.error("[web-apple-pay] Purchase API failed", {
397
+ skuId,
398
+ errorType: walletError?.errorType ?? "UNKNOWN",
399
+ message: walletError?.message,
400
+ err
401
+ });
382
402
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
383
403
  failApplePaySession(session);
384
404
  if (!walletError) {
package/dist/src/index.js CHANGED
@@ -575,10 +575,11 @@ var loadRecaptchaScript = (siteKey) => {
575
575
  );
576
576
  if (existingScript) {
577
577
  existingScript.addEventListener("load", () => resolve());
578
- existingScript.addEventListener(
579
- "error",
580
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
581
- );
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);
582
+ });
582
583
  return;
583
584
  }
584
585
  const script = document.createElement("script");
@@ -586,7 +587,11 @@ var loadRecaptchaScript = (siteKey) => {
586
587
  script.async = true;
587
588
  script.defer = true;
588
589
  script.onload = () => resolve();
589
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
590
+ 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);
594
+ };
590
595
  document.head.appendChild(script);
591
596
  });
592
597
  };
@@ -605,12 +610,19 @@ var getRecaptchaToken = async (action) => {
605
610
  });
606
611
  };
607
612
  var getPurchaseRecaptchaTokens = async () => {
608
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
609
- getRecaptchaToken("checkEligibility"),
610
- getRecaptchaToken("newBasket"),
611
- getRecaptchaToken("registerUser")
612
- ]);
613
- return { checkEligibility, newBasket, registerUser };
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
+ }
614
626
  };
615
627
 
616
628
  // src/apple-pay-modal.ts
@@ -947,11 +959,18 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
947
959
  errorElement?.classList.remove("apm__error--visible");
948
960
  cta.disabled = true;
949
961
  cta.setAttribute("aria-busy", "true");
962
+ console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
950
963
  getPurchaseRecaptchaTokens().then((recaptchaTokens) => {
951
- if (this.#isClosed) return;
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");
952
970
  this.onConfirm?.(recaptchaTokens);
953
971
  this.close();
954
- }).catch(() => {
972
+ }).catch((error) => {
973
+ console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
955
974
  cta.disabled = false;
956
975
  cta.removeAttribute("aria-busy");
957
976
  const existingError = this.querySelector("#apple-pay-modal-error");
@@ -1362,22 +1381,28 @@ async function handleMerchantValidation(event, session, config) {
1362
1381
  try {
1363
1382
  const validationHost = new URL(event.validationURL).host;
1364
1383
  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 });
1365
1385
  session.abort();
1366
1386
  redirectToFallbackCheckout(config);
1367
1387
  return;
1368
1388
  }
1389
+ console.info("[web-apple-pay] Merchant validation started", { validationHost });
1369
1390
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
1391
+ console.info("[web-apple-pay] verifyMerchant reCAPTCHA token acquired \u2014 calling validateAppleMerchant");
1370
1392
  const response = await validateAppleMerchant({
1371
1393
  validationURL: event.validationURL,
1372
1394
  recaptchaToken
1373
1395
  });
1374
1396
  if (!response?.merchantSession) {
1397
+ console.error("[web-apple-pay] Merchant validation response missing merchantSession \u2014 aborting session", { response });
1375
1398
  session.abort();
1376
1399
  redirectToFallbackCheckout(config);
1377
1400
  return;
1378
1401
  }
1402
+ console.info("[web-apple-pay] Merchant validation succeeded \u2014 completing merchant validation");
1379
1403
  session.completeMerchantValidation(response.merchantSession);
1380
- } catch {
1404
+ } catch (error) {
1405
+ console.error("[web-apple-pay] Merchant validation threw an error \u2014 aborting session", error);
1381
1406
  session.abort();
1382
1407
  redirectToFallbackCheckout(config);
1383
1408
  }
@@ -1398,6 +1423,7 @@ function startApplePaySession(config) {
1398
1423
  };
1399
1424
  try {
1400
1425
  const session = new ApplePaySession(3, paymentRequest);
1426
+ console.info("[web-apple-pay] ApplePaySession created successfully");
1401
1427
  session.onvalidatemerchant = async (event) => {
1402
1428
  await handleMerchantValidation(event, session, config);
1403
1429
  };
@@ -1410,7 +1436,9 @@ function startApplePaySession(config) {
1410
1436
  };
1411
1437
  trackWalletPaymentSheetOpen(config.skuId);
1412
1438
  session.begin();
1413
- } catch {
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);
1414
1442
  redirectToFallbackCheckout(config);
1415
1443
  }
1416
1444
  }
@@ -1592,12 +1620,24 @@ function handleStructuredError(ctx) {
1592
1620
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1593
1621
  const { skuId, returnUrl, country } = config;
1594
1622
  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
+ });
1595
1634
  try {
1596
1635
  validatedEmail = validateContacts(
1597
1636
  event,
1598
1637
  sessionData,
1599
1638
  config.supportedBillingCountries
1600
1639
  );
1640
+ console.info("[web-apple-pay] Contact validation passed \u2014 calling purchase API");
1601
1641
  const result = await performPurchase({
1602
1642
  applePayToken: event.payment.token,
1603
1643
  skuId: config.skuId,
@@ -1608,6 +1648,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1608
1648
  },
1609
1649
  recaptchaTokens: config.recaptchaTokens
1610
1650
  });
1651
+ console.info("[web-apple-pay] Purchase API succeeded", { skuId, basketId: result.basketId });
1611
1652
  trackWalletPaymentSuccess(skuId, result.basketId);
1612
1653
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1613
1654
  const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
@@ -1622,10 +1663,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1622
1663
  });
1623
1664
  } catch (err) {
1624
1665
  if (err instanceof ContactValidationError) {
1666
+ console.warn("[web-apple-pay] Contact validation failed \u2014 keeping Apple Pay sheet open", err);
1625
1667
  failApplePaySession(session, err.errors);
1626
1668
  return;
1627
1669
  }
1628
1670
  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
+ });
1629
1677
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1630
1678
  failApplePaySession(session);
1631
1679
  if (!walletError) {
@@ -2157,8 +2205,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2157
2205
  const skuId = this.#offer.sku_id;
2158
2206
  const country = this.#country;
2159
2207
  modal.onConfirm = (recaptchaTokens) => {
2208
+ console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
2160
2209
  this.#initiateApplePay(skuId, country, recaptchaTokens);
2161
2210
  };
2211
+ console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
2162
2212
  modal.open();
2163
2213
  }
2164
2214
  async #fetchSession() {
@@ -2206,6 +2256,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2206
2256
  try {
2207
2257
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
2208
2258
  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
+ });
2209
2271
  startApplePaySession(
2210
2272
  this.#buildSessionParams(
2211
2273
  skuId,
@@ -2215,7 +2277,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2215
2277
  recaptchaTokens
2216
2278
  )
2217
2279
  );
2218
- } catch {
2280
+ } catch (error) {
2281
+ console.error("[web-apple-pay] Failed to start Apple Pay session", error);
2219
2282
  }
2220
2283
  }
2221
2284
  };
@@ -11,10 +11,11 @@ var loadRecaptchaScript = (siteKey) => {
11
11
  );
12
12
  if (existingScript) {
13
13
  existingScript.addEventListener("load", () => resolve());
14
- existingScript.addEventListener(
15
- "error",
16
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
17
- );
14
+ existingScript.addEventListener("error", () => {
15
+ const error = new Error("Failed to load existing reCAPTCHA script");
16
+ console.error("[web-apple-pay] reCAPTCHA script load failed (existing script)", error);
17
+ reject(error);
18
+ });
18
19
  return;
19
20
  }
20
21
  const script = document.createElement("script");
@@ -22,7 +23,11 @@ var loadRecaptchaScript = (siteKey) => {
22
23
  script.async = true;
23
24
  script.defer = true;
24
25
  script.onload = () => resolve();
25
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
26
+ script.onerror = () => {
27
+ const error = new Error("Failed to load reCAPTCHA script");
28
+ console.error("[web-apple-pay] reCAPTCHA script load failed (new script)", error);
29
+ reject(error);
30
+ };
26
31
  document.head.appendChild(script);
27
32
  });
28
33
  };
@@ -41,12 +46,19 @@ var getRecaptchaToken = async (action) => {
41
46
  });
42
47
  };
43
48
  var getPurchaseRecaptchaTokens = async () => {
44
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
45
- getRecaptchaToken("checkEligibility"),
46
- getRecaptchaToken("newBasket"),
47
- getRecaptchaToken("registerUser")
48
- ]);
49
- return { checkEligibility, newBasket, registerUser };
49
+ console.info("[web-apple-pay] Requesting reCAPTCHA tokens (checkEligibility, newBasket, registerUser)");
50
+ try {
51
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
52
+ getRecaptchaToken("checkEligibility"),
53
+ getRecaptchaToken("newBasket"),
54
+ getRecaptchaToken("registerUser")
55
+ ]);
56
+ console.info("[web-apple-pay] All reCAPTCHA tokens acquired successfully");
57
+ return { checkEligibility, newBasket, registerUser };
58
+ } catch (error) {
59
+ console.error("[web-apple-pay] Failed to acquire one or more reCAPTCHA tokens", error);
60
+ throw error;
61
+ }
50
62
  };
51
63
  export {
52
64
  getPurchaseRecaptchaTokens,
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": "0.1.3-beta.43",
4
+ "version": "0.1.3-beta.45",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",