@economist/web-apple-pay 0.1.3-beta.30 → 0.1.3-beta.31

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
@@ -956,6 +956,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
956
956
  cta.removeAttribute("aria-busy");
957
957
  }
958
958
  }).catch(() => {
959
+ console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
959
960
  if (cta) {
960
961
  cta.removeAttribute("aria-busy");
961
962
  }
@@ -1141,11 +1142,15 @@ var isApplePayAvailable = async () => {
1141
1142
  }
1142
1143
  const merchantId = getApplePayConfig()?.merchantId;
1143
1144
  if (!merchantId) {
1145
+ console.warn(
1146
+ "[web-apple-pay] Missing merchantId. Call configureApplePay({ merchantId, ... }) before rendering Apple Pay components."
1147
+ );
1144
1148
  return false;
1145
1149
  }
1146
1150
  const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1147
1151
  return hasActiveCard;
1148
1152
  } catch (error) {
1153
+ console.error("Error checking Apple Pay active card status:", error);
1149
1154
  return false;
1150
1155
  }
1151
1156
  };
@@ -1233,13 +1238,25 @@ var getExpressCheckoutSession = () => {
1233
1238
  };
1234
1239
 
1235
1240
  // src/utils/expressCheckoutRedirect.ts
1236
- var captureOriginUrl = () => window.location.href;
1237
- var buildQueryString = () => {
1238
- const countryCode = new URLSearchParams(window.location.search).get(
1239
- "country"
1240
- );
1241
- return countryCode ? `&country=${encodeURIComponent(countryCode)}` : "";
1241
+ var CHECKOUT_REDIRECT_KEY = "checkout-redirect";
1242
+ var ALLOWED_REDIRECT_HOSTNAME = "economist.com";
1243
+ function isAllowedRedirectUrl(url) {
1244
+ if (url.startsWith("/")) return !url.startsWith("//");
1245
+ try {
1246
+ const { hostname } = new URL(url);
1247
+ return hostname === ALLOWED_REDIRECT_HOSTNAME || hostname.endsWith(`.${ALLOWED_REDIRECT_HOSTNAME}`);
1248
+ } catch {
1249
+ return false;
1250
+ }
1251
+ }
1252
+ var writeCheckoutRedirect = (originUrl) => {
1253
+ if (!isAllowedRedirectUrl(originUrl)) return;
1254
+ try {
1255
+ localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
1256
+ } catch {
1257
+ }
1242
1258
  };
1259
+ var captureOriginUrl = () => window.location.href;
1243
1260
  var decodeSku = (sku) => {
1244
1261
  try {
1245
1262
  return atob(sku.substring(sku.indexOf("-") + 1));
@@ -1250,14 +1267,11 @@ var decodeSku = (sku) => {
1250
1267
  var redirectToCheckoutComplete = (params) => {
1251
1268
  const url = new URL("/checkout/complete", window.location.origin);
1252
1269
  url.searchParams.set("basketId", params.basketId);
1253
- if (params.queryString) {
1254
- const qs = params.queryString.startsWith("?") ? params.queryString.slice(1) : params.queryString;
1255
- new URLSearchParams(qs).forEach((v, k) => url.searchParams.set(k, v));
1256
- }
1257
1270
  url.searchParams.set("lmo_offer", params.skuId);
1258
1271
  url.searchParams.set("status", params.status);
1259
1272
  url.searchParams.set("redirectToCheckout", "true");
1260
- url.searchParams.set("returnUrl", params.returnUrl);
1273
+ if (params.email) url.searchParams.set("email", params.email);
1274
+ if (params.country) url.searchParams.set("country", params.country);
1261
1275
  return url.pathname + url.search;
1262
1276
  };
1263
1277
  var redirectToCheckoutFallback = (params) => {
@@ -1268,7 +1282,7 @@ var redirectToCheckoutFallback = (params) => {
1268
1282
  url.searchParams.set("inlineError", params.inlineError);
1269
1283
  if (params.email) url.searchParams.set("email", params.email);
1270
1284
  if (params.emailError) url.searchParams.set("emailError", params.emailError);
1271
- url.searchParams.set("returnUrl", params.returnUrl);
1285
+ if (params.country) url.searchParams.set("country", params.country);
1272
1286
  return url.pathname + url.search;
1273
1287
  };
1274
1288
 
@@ -1352,17 +1366,16 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
1352
1366
  var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
1353
1367
  var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
1354
1368
  var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
1355
- var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
1356
- var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
1357
1369
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
1358
1370
 
1359
1371
  // src/clients/payment-checkout/apple-session.ts
1360
1372
  function redirectToFallbackCheckout(config) {
1373
+ writeCheckoutRedirect(config.returnUrl);
1361
1374
  trackFallbackCheckout(config.skuId);
1362
1375
  window.location.href = redirectToCheckoutFallback({
1363
1376
  skuId: config.skuId,
1364
- returnUrl: config.returnUrl,
1365
- inlineError: MSG_PAYMENT_GENERIC_ERROR
1377
+ inlineError: MSG_PAYMENT_GENERIC_ERROR,
1378
+ country: config.countryCode
1366
1379
  });
1367
1380
  }
1368
1381
  async function handleMerchantValidation(event, session, config) {
@@ -1385,6 +1398,7 @@ async function handleMerchantValidation(event, session, config) {
1385
1398
  }
1386
1399
  session.completeMerchantValidation(response.merchantSession);
1387
1400
  } catch (err) {
1401
+ console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
1388
1402
  session.abort();
1389
1403
  redirectToFallbackCheckout(config);
1390
1404
  }
@@ -1418,6 +1432,7 @@ function startApplePaySession(config) {
1418
1432
  trackWalletPaymentSheetOpen(config.skuId);
1419
1433
  session.begin();
1420
1434
  } catch (err) {
1435
+ console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
1421
1436
  redirectToFallbackCheckout(config);
1422
1437
  }
1423
1438
  }
@@ -1539,8 +1554,6 @@ var shippingContactDetails = (shippingContact) => {
1539
1554
  };
1540
1555
 
1541
1556
  // src/clients/payment-checkout/payment-handler.ts
1542
- var MSG_ELIGIBILITY = "Something went wrong, please try again";
1543
- var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
1544
1557
  var failApplePaySession = (session, errors = []) => {
1545
1558
  session.completePayment({
1546
1559
  status: ApplePaySession.STATUS_FAILURE,
@@ -1564,37 +1577,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
1564
1577
  }
1565
1578
  return void 0;
1566
1579
  }
1567
- function redirectFallback(skuId, returnUrl, options) {
1580
+ function redirectFallback(skuId, returnUrl, country, options) {
1581
+ writeCheckoutRedirect(returnUrl);
1568
1582
  trackFallbackCheckout(skuId);
1569
1583
  window.location.href = redirectToCheckoutFallback({
1570
1584
  skuId,
1571
- returnUrl,
1585
+ country,
1572
1586
  ...options
1573
1587
  });
1574
1588
  }
1575
1589
  var ERROR_HANDLERS = {
1576
- EMAIL_COLLISION: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
1577
- emailError: MSG_EMAIL_COLLISION,
1590
+ // emailError flows as an inline field error on the email input.
1591
+ // email pre-populates the input so the user doesn't have to retype it.
1592
+ EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
1593
+ emailError: walletError.message,
1594
+ email: validatedEmail
1595
+ }),
1596
+ PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1597
+ ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1598
+ REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1599
+ ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
1600
+ emailError: walletError.message,
1578
1601
  email: validatedEmail
1579
1602
  }),
1580
- PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
1581
- // Matches sma-checkout catch-all: always redirect with generic inlineError.
1582
- redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR })
1583
- ),
1584
- ELIGIBILITY_REJECTED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_ELIGIBILITY }),
1585
- REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
1586
- VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_RECAPTCHA_VALIDATION_FAILED })
1603
+ VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1604
+ RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
1587
1605
  };
1588
1606
  function handleStructuredError(ctx) {
1589
1607
  const handler = ERROR_HANDLERS[ctx.walletError.errorType];
1590
1608
  if (handler) {
1591
1609
  handler(ctx);
1592
1610
  } else {
1593
- redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1611
+ redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1594
1612
  }
1595
1613
  }
1596
1614
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1597
- const { skuId, returnUrl, queryString } = config;
1615
+ const { skuId, returnUrl, country } = config;
1598
1616
  let validatedEmail;
1599
1617
  try {
1600
1618
  validatedEmail = validateContacts(
@@ -1614,27 +1632,30 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1614
1632
  });
1615
1633
  trackWalletPaymentSuccess(skuId, result.basketId);
1616
1634
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1635
+ const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
1617
1636
  const userStatus = sessionData.loggedIn ? "lex" : "nex";
1637
+ writeCheckoutRedirect(returnUrl);
1618
1638
  window.location.href = redirectToCheckoutComplete({
1619
1639
  basketId: result.basketId,
1620
1640
  status: userStatus,
1621
1641
  skuId: decodeSku(skuId),
1622
- returnUrl,
1623
- queryString
1642
+ email: successEmail,
1643
+ country
1624
1644
  });
1625
1645
  } catch (err) {
1626
1646
  if (err instanceof ContactValidationError) {
1627
1647
  failApplePaySession(session, err.errors);
1628
1648
  return;
1629
1649
  }
1650
+ console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1630
1651
  const walletError = parseWalletApiError(err);
1631
1652
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1632
1653
  failApplePaySession(session);
1633
1654
  if (!walletError) {
1634
- redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1655
+ redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1635
1656
  return;
1636
1657
  }
1637
- handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1658
+ handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
1638
1659
  }
1639
1660
  }
1640
1661
 
@@ -1904,6 +1925,7 @@ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1904
1925
  var TOTAL_LABEL = "The Economist";
1905
1926
  var DEFAULT_CURRENCY = "USD";
1906
1927
  var DEFAULT_TOTAL = "0.00";
1928
+ var ERROR_INITIATE = "Failed to initiate Apple Pay session:";
1907
1929
  var SEL_CONTAINER = ".apple-pay-container";
1908
1930
  var SEL_BUTTON = ".apple-pay-btn";
1909
1931
  var APPLE_PAY_EXCLUDED_VARIANTS = [
@@ -2027,15 +2049,16 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2027
2049
  // ─── Render pipeline ────────────────────────────────────────────────────────
2028
2050
  async #run() {
2029
2051
  try {
2052
+ this.#renderTemplate();
2030
2053
  if (await this.#checkAvailability()) return;
2031
2054
  if (this.#checkOffer()) return;
2032
- this.#renderTemplate();
2033
2055
  if (await this.#checkSession()) return;
2034
2056
  this.#captureReturnUrl();
2035
2057
  this.#computeBillingCountries();
2036
2058
  if (await this.#fetchAndCacheOptions()) return;
2037
2059
  this.#finishLoading();
2038
2060
  } catch (err) {
2061
+ console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
2039
2062
  this.style.display = "none";
2040
2063
  this.querySelector(SEL_CONTAINER)?.remove();
2041
2064
  } finally {
@@ -2047,6 +2070,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2047
2070
  const available = await isApplePayAvailable();
2048
2071
  if (!available) {
2049
2072
  this.style.display = "none";
2073
+ this.querySelector(SEL_CONTAINER)?.remove();
2050
2074
  return true;
2051
2075
  }
2052
2076
  return false;
@@ -2068,6 +2092,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2068
2092
  #checkOffer() {
2069
2093
  if (!this.#offer) {
2070
2094
  this.style.display = "none";
2095
+ this.querySelector(SEL_CONTAINER)?.remove();
2071
2096
  return true;
2072
2097
  }
2073
2098
  return false;
@@ -2175,6 +2200,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2175
2200
  #scheduleRecaptchaTokens() {
2176
2201
  const attempt = getPurchaseRecaptchaTokens();
2177
2202
  attempt.catch((err) => {
2203
+ console.error("[web-apple-pay] reCAPTCHA token pre-fetch failed; will retry on modal open", err);
2178
2204
  if (this.#recaptchaTokensPromise === attempt) {
2179
2205
  this.#recaptchaTokensPromise = null;
2180
2206
  }
@@ -2217,7 +2243,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2217
2243
  country,
2218
2244
  currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
2219
2245
  returnUrl: this.#returnUrl,
2220
- queryString: buildQueryString(),
2221
2246
  supportedBillingCountries: this.#supportedBillingCountries,
2222
2247
  recaptchaTokens
2223
2248
  })
@@ -2237,6 +2262,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2237
2262
  )
2238
2263
  );
2239
2264
  } catch (error) {
2265
+ console.error(ERROR_INITIATE, error);
2240
2266
  }
2241
2267
  }
2242
2268
  };
@@ -2245,7 +2271,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2245
2271
  var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint2) => {
2246
2272
  ApplePayEntryPoint2["PAYWALL"] = "article_paywall";
2247
2273
  ApplePayEntryPoint2["REGWALL"] = "article_regwall";
2248
- ApplePayEntryPoint2["DUAL_OFFER_BANNER"] = "dual_offer_banner";
2249
2274
  return ApplePayEntryPoint2;
2250
2275
  })(ApplePayEntryPoint || {});
2251
2276
 
@@ -951,6 +951,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
951
951
  cta.removeAttribute("aria-busy");
952
952
  }
953
953
  }).catch(() => {
954
+ console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
954
955
  if (cta) {
955
956
  cta.removeAttribute("aria-busy");
956
957
  }
@@ -1136,11 +1137,15 @@ var isApplePayAvailable = async () => {
1136
1137
  }
1137
1138
  const merchantId = getApplePayConfig()?.merchantId;
1138
1139
  if (!merchantId) {
1140
+ console.warn(
1141
+ "[web-apple-pay] Missing merchantId. Call configureApplePay({ merchantId, ... }) before rendering Apple Pay components."
1142
+ );
1139
1143
  return false;
1140
1144
  }
1141
1145
  const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1142
1146
  return hasActiveCard;
1143
1147
  } catch (error) {
1148
+ console.error("Error checking Apple Pay active card status:", error);
1144
1149
  return false;
1145
1150
  }
1146
1151
  };
@@ -1228,13 +1233,25 @@ var getExpressCheckoutSession = () => {
1228
1233
  };
1229
1234
 
1230
1235
  // src/utils/expressCheckoutRedirect.ts
1231
- var captureOriginUrl = () => window.location.href;
1232
- var buildQueryString = () => {
1233
- const countryCode = new URLSearchParams(window.location.search).get(
1234
- "country"
1235
- );
1236
- return countryCode ? `&country=${encodeURIComponent(countryCode)}` : "";
1236
+ var CHECKOUT_REDIRECT_KEY = "checkout-redirect";
1237
+ var ALLOWED_REDIRECT_HOSTNAME = "economist.com";
1238
+ function isAllowedRedirectUrl(url) {
1239
+ if (url.startsWith("/")) return !url.startsWith("//");
1240
+ try {
1241
+ const { hostname } = new URL(url);
1242
+ return hostname === ALLOWED_REDIRECT_HOSTNAME || hostname.endsWith(`.${ALLOWED_REDIRECT_HOSTNAME}`);
1243
+ } catch {
1244
+ return false;
1245
+ }
1246
+ }
1247
+ var writeCheckoutRedirect = (originUrl) => {
1248
+ if (!isAllowedRedirectUrl(originUrl)) return;
1249
+ try {
1250
+ localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
1251
+ } catch {
1252
+ }
1237
1253
  };
1254
+ var captureOriginUrl = () => window.location.href;
1238
1255
  var decodeSku = (sku) => {
1239
1256
  try {
1240
1257
  return atob(sku.substring(sku.indexOf("-") + 1));
@@ -1245,14 +1262,11 @@ var decodeSku = (sku) => {
1245
1262
  var redirectToCheckoutComplete = (params) => {
1246
1263
  const url = new URL("/checkout/complete", window.location.origin);
1247
1264
  url.searchParams.set("basketId", params.basketId);
1248
- if (params.queryString) {
1249
- const qs = params.queryString.startsWith("?") ? params.queryString.slice(1) : params.queryString;
1250
- new URLSearchParams(qs).forEach((v, k) => url.searchParams.set(k, v));
1251
- }
1252
1265
  url.searchParams.set("lmo_offer", params.skuId);
1253
1266
  url.searchParams.set("status", params.status);
1254
1267
  url.searchParams.set("redirectToCheckout", "true");
1255
- url.searchParams.set("returnUrl", params.returnUrl);
1268
+ if (params.email) url.searchParams.set("email", params.email);
1269
+ if (params.country) url.searchParams.set("country", params.country);
1256
1270
  return url.pathname + url.search;
1257
1271
  };
1258
1272
  var redirectToCheckoutFallback = (params) => {
@@ -1263,7 +1277,7 @@ var redirectToCheckoutFallback = (params) => {
1263
1277
  url.searchParams.set("inlineError", params.inlineError);
1264
1278
  if (params.email) url.searchParams.set("email", params.email);
1265
1279
  if (params.emailError) url.searchParams.set("emailError", params.emailError);
1266
- url.searchParams.set("returnUrl", params.returnUrl);
1280
+ if (params.country) url.searchParams.set("country", params.country);
1267
1281
  return url.pathname + url.search;
1268
1282
  };
1269
1283
 
@@ -1347,17 +1361,16 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
1347
1361
  var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
1348
1362
  var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
1349
1363
  var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
1350
- var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
1351
- var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
1352
1364
  var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
1353
1365
 
1354
1366
  // src/clients/payment-checkout/apple-session.ts
1355
1367
  function redirectToFallbackCheckout(config) {
1368
+ writeCheckoutRedirect(config.returnUrl);
1356
1369
  trackFallbackCheckout(config.skuId);
1357
1370
  window.location.href = redirectToCheckoutFallback({
1358
1371
  skuId: config.skuId,
1359
- returnUrl: config.returnUrl,
1360
- inlineError: MSG_PAYMENT_GENERIC_ERROR
1372
+ inlineError: MSG_PAYMENT_GENERIC_ERROR,
1373
+ country: config.countryCode
1361
1374
  });
1362
1375
  }
1363
1376
  async function handleMerchantValidation(event, session, config) {
@@ -1380,6 +1393,7 @@ async function handleMerchantValidation(event, session, config) {
1380
1393
  }
1381
1394
  session.completeMerchantValidation(response.merchantSession);
1382
1395
  } catch (err) {
1396
+ console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
1383
1397
  session.abort();
1384
1398
  redirectToFallbackCheckout(config);
1385
1399
  }
@@ -1413,6 +1427,7 @@ function startApplePaySession(config) {
1413
1427
  trackWalletPaymentSheetOpen(config.skuId);
1414
1428
  session.begin();
1415
1429
  } catch (err) {
1430
+ console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
1416
1431
  redirectToFallbackCheckout(config);
1417
1432
  }
1418
1433
  }
@@ -1534,8 +1549,6 @@ var shippingContactDetails = (shippingContact) => {
1534
1549
  };
1535
1550
 
1536
1551
  // src/clients/payment-checkout/payment-handler.ts
1537
- var MSG_ELIGIBILITY = "Something went wrong, please try again";
1538
- var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
1539
1552
  var failApplePaySession = (session, errors = []) => {
1540
1553
  session.completePayment({
1541
1554
  status: ApplePaySession.STATUS_FAILURE,
@@ -1559,37 +1572,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
1559
1572
  }
1560
1573
  return void 0;
1561
1574
  }
1562
- function redirectFallback(skuId, returnUrl, options) {
1575
+ function redirectFallback(skuId, returnUrl, country, options) {
1576
+ writeCheckoutRedirect(returnUrl);
1563
1577
  trackFallbackCheckout(skuId);
1564
1578
  window.location.href = redirectToCheckoutFallback({
1565
1579
  skuId,
1566
- returnUrl,
1580
+ country,
1567
1581
  ...options
1568
1582
  });
1569
1583
  }
1570
1584
  var ERROR_HANDLERS = {
1571
- EMAIL_COLLISION: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
1572
- emailError: MSG_EMAIL_COLLISION,
1585
+ // emailError flows as an inline field error on the email input.
1586
+ // email pre-populates the input so the user doesn't have to retype it.
1587
+ EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
1588
+ emailError: walletError.message,
1589
+ email: validatedEmail
1590
+ }),
1591
+ PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1592
+ ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1593
+ REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1594
+ ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
1595
+ emailError: walletError.message,
1573
1596
  email: validatedEmail
1574
1597
  }),
1575
- PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
1576
- // Matches sma-checkout catch-all: always redirect with generic inlineError.
1577
- redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR })
1578
- ),
1579
- ELIGIBILITY_REJECTED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_ELIGIBILITY }),
1580
- REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
1581
- VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_RECAPTCHA_VALIDATION_FAILED })
1598
+ VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
1599
+ RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
1582
1600
  };
1583
1601
  function handleStructuredError(ctx) {
1584
1602
  const handler = ERROR_HANDLERS[ctx.walletError.errorType];
1585
1603
  if (handler) {
1586
1604
  handler(ctx);
1587
1605
  } else {
1588
- redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1606
+ redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1589
1607
  }
1590
1608
  }
1591
1609
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1592
- const { skuId, returnUrl, queryString } = config;
1610
+ const { skuId, returnUrl, country } = config;
1593
1611
  let validatedEmail;
1594
1612
  try {
1595
1613
  validatedEmail = validateContacts(
@@ -1609,27 +1627,30 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1609
1627
  });
1610
1628
  trackWalletPaymentSuccess(skuId, result.basketId);
1611
1629
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1630
+ const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
1612
1631
  const userStatus = sessionData.loggedIn ? "lex" : "nex";
1632
+ writeCheckoutRedirect(returnUrl);
1613
1633
  window.location.href = redirectToCheckoutComplete({
1614
1634
  basketId: result.basketId,
1615
1635
  status: userStatus,
1616
1636
  skuId: decodeSku(skuId),
1617
- returnUrl,
1618
- queryString
1637
+ email: successEmail,
1638
+ country
1619
1639
  });
1620
1640
  } catch (err) {
1621
1641
  if (err instanceof ContactValidationError) {
1622
1642
  failApplePaySession(session, err.errors);
1623
1643
  return;
1624
1644
  }
1645
+ console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1625
1646
  const walletError = parseWalletApiError(err);
1626
1647
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1627
1648
  failApplePaySession(session);
1628
1649
  if (!walletError) {
1629
- redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1650
+ redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1630
1651
  return;
1631
1652
  }
1632
- handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1653
+ handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
1633
1654
  }
1634
1655
  }
1635
1656
 
@@ -1899,6 +1920,7 @@ var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
1899
1920
  var TOTAL_LABEL = "The Economist";
1900
1921
  var DEFAULT_CURRENCY = "USD";
1901
1922
  var DEFAULT_TOTAL = "0.00";
1923
+ var ERROR_INITIATE = "Failed to initiate Apple Pay session:";
1902
1924
  var SEL_CONTAINER = ".apple-pay-container";
1903
1925
  var SEL_BUTTON = ".apple-pay-btn";
1904
1926
  var APPLE_PAY_EXCLUDED_VARIANTS = [
@@ -2022,15 +2044,16 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2022
2044
  // ─── Render pipeline ────────────────────────────────────────────────────────
2023
2045
  async #run() {
2024
2046
  try {
2047
+ this.#renderTemplate();
2025
2048
  if (await this.#checkAvailability()) return;
2026
2049
  if (this.#checkOffer()) return;
2027
- this.#renderTemplate();
2028
2050
  if (await this.#checkSession()) return;
2029
2051
  this.#captureReturnUrl();
2030
2052
  this.#computeBillingCountries();
2031
2053
  if (await this.#fetchAndCacheOptions()) return;
2032
2054
  this.#finishLoading();
2033
2055
  } catch (err) {
2056
+ console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
2034
2057
  this.style.display = "none";
2035
2058
  this.querySelector(SEL_CONTAINER)?.remove();
2036
2059
  } finally {
@@ -2042,6 +2065,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2042
2065
  const available = await isApplePayAvailable();
2043
2066
  if (!available) {
2044
2067
  this.style.display = "none";
2068
+ this.querySelector(SEL_CONTAINER)?.remove();
2045
2069
  return true;
2046
2070
  }
2047
2071
  return false;
@@ -2063,6 +2087,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2063
2087
  #checkOffer() {
2064
2088
  if (!this.#offer) {
2065
2089
  this.style.display = "none";
2090
+ this.querySelector(SEL_CONTAINER)?.remove();
2066
2091
  return true;
2067
2092
  }
2068
2093
  return false;
@@ -2170,6 +2195,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2170
2195
  #scheduleRecaptchaTokens() {
2171
2196
  const attempt = getPurchaseRecaptchaTokens();
2172
2197
  attempt.catch((err) => {
2198
+ console.error("[web-apple-pay] reCAPTCHA token pre-fetch failed; will retry on modal open", err);
2173
2199
  if (this.#recaptchaTokensPromise === attempt) {
2174
2200
  this.#recaptchaTokensPromise = null;
2175
2201
  }
@@ -2212,7 +2238,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2212
2238
  country,
2213
2239
  currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
2214
2240
  returnUrl: this.#returnUrl,
2215
- queryString: buildQueryString(),
2216
2241
  supportedBillingCountries: this.#supportedBillingCountries,
2217
2242
  recaptchaTokens
2218
2243
  })
@@ -2232,6 +2257,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
2232
2257
  )
2233
2258
  );
2234
2259
  } catch (error) {
2260
+ console.error(ERROR_INITIATE, error);
2235
2261
  }
2236
2262
  }
2237
2263
  };