@economist/web-apple-pay 0.1.3-beta.28 → 0.1.3-beta.29
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 +43 -74
- package/dist/src/apple-pay-button.js +43 -74
- package/dist/src/apple-pay-button.stories.js +43 -74
- package/dist/src/apple-pay-modal.js +16 -14
- package/dist/src/apple-pay-modal.stories.js +43 -74
- package/dist/src/clients/payment-checkout/apple-session.js +3 -20
- package/dist/src/clients/payment-checkout/index.js +0 -1
- package/dist/src/clients/payment-checkout/messages.d.ts +14 -11
- package/dist/src/clients/payment-checkout/messages.js +4 -0
- package/dist/src/clients/payment-checkout/payment-handler.js +25 -57
- package/dist/src/clients/payment-checkout/types.d.ts +2 -6
- package/dist/src/index.js +43 -74
- package/dist/src/utils/expressCheckoutRedirect.d.ts +6 -40
- package/dist/src/utils/expressCheckoutRedirect.js +3 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -684,6 +684,8 @@ function renewalPeriodText(unit, duration) {
|
|
|
684
684
|
return "";
|
|
685
685
|
}
|
|
686
686
|
}
|
|
687
|
+
var LI_SEPARATOR = "LI_SEPARATOR";
|
|
688
|
+
var P_SEPARATOR = "P_SEPARATOR";
|
|
687
689
|
function buildTermsContext(offer, country) {
|
|
688
690
|
const isUS = country === "US";
|
|
689
691
|
const isCA = country === "CA";
|
|
@@ -720,19 +722,19 @@ function freeTrialTerms(offer, ctx) {
|
|
|
720
722
|
const trialDuration = offer.subscription_options?.trial_period?.duration ?? 1;
|
|
721
723
|
const trialDateStr = `on ${getRenewalDateText(trialUnit, trialDuration)}${ctx.verificationText}`;
|
|
722
724
|
if (ctx.isUS) {
|
|
723
|
-
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled{
|
|
725
|
+
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
724
726
|
}
|
|
725
|
-
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled{
|
|
727
|
+
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
726
728
|
}
|
|
727
729
|
function nytTerms(ctx) {
|
|
728
730
|
const nytAccessText = "Your complimentary access to The New York Times is for one year only and does not auto-renew. We will send your instructions on how to redeem access to The New York Times by email.";
|
|
729
731
|
if (ctx.isUS) {
|
|
730
|
-
return `Your subscription to <em>The Economist</em> auto-renews ${ctx.periodText} until cancelled{
|
|
732
|
+
return `Your subscription to <em>The Economist</em> auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.renewalDateStr}${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}${P_SEPARATOR}${nytAccessText}`;
|
|
731
733
|
}
|
|
732
734
|
if (ctx.isCA) {
|
|
733
|
-
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled
|
|
735
|
+
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled.${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}${P_SEPARATOR}${nytAccessText}`;
|
|
734
736
|
}
|
|
735
|
-
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled{
|
|
737
|
+
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime} ${nytAccessText}`;
|
|
736
738
|
}
|
|
737
739
|
function minTermContractTerms(offer, ctx) {
|
|
738
740
|
const duePrice = formatPrice(offer.price.purchase, offer.price.currency_code);
|
|
@@ -742,28 +744,28 @@ function minTermContractTerms(offer, ctx) {
|
|
|
742
744
|
const contractLength = mtDuration && mtUnit ? `${mtDuration} ${mtUnit}` : "";
|
|
743
745
|
const initialContractText = contractLength ? `your initial ${contractLength} contract` : "your initial contract";
|
|
744
746
|
const mtRenewalDateText = mtUnit && mtDuration ? getRenewalDateText(mtUnit, Number(mtDuration)) : ctx.renewalDateText;
|
|
745
|
-
return `You\u2019ll be charged ${duePrice} a month for the duration of ${initialContractText}{
|
|
747
|
+
return `You\u2019ll be charged ${duePrice} a month for the duration of ${initialContractText}${LI_SEPARATOR}Your subscription auto-renews annually at ${ctx.renewalPriceText} a month on ${mtRenewalDateText} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}`;
|
|
746
748
|
}
|
|
747
749
|
function paidTrialTerms(offer, ctx) {
|
|
748
750
|
const trialUnit = offer.subscription_options?.trial_period?.unit ?? ctx.unit;
|
|
749
751
|
const trialDuration = offer.subscription_options?.trial_period?.duration ?? ctx.duration;
|
|
750
752
|
const trialDateText = getRenewalDateText(trialUnit, trialDuration);
|
|
751
753
|
if (ctx.isUS) {
|
|
752
|
-
return `Your subscription auto-renews ${ctx.periodText} until cancelled{
|
|
754
|
+
return `Your subscription auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} on ${trialDateText} when your paid trial ends${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
753
755
|
}
|
|
754
|
-
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} on ${trialDateText} when your paid trial ends, until cancelled{
|
|
756
|
+
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} on ${trialDateText} when your paid trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
755
757
|
}
|
|
756
758
|
function autoRenewalTerms(ctx) {
|
|
757
759
|
if (ctx.isUS) {
|
|
758
|
-
return `Your subscription auto-renews ${ctx.periodText} until cancelled{
|
|
760
|
+
return `Your subscription auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.renewalDateStr}${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
759
761
|
}
|
|
760
|
-
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled{
|
|
762
|
+
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
761
763
|
}
|
|
762
764
|
function noAutoRenewalTerms(ctx) {
|
|
763
765
|
if (ctx.isUS || ctx.isCA) {
|
|
764
|
-
return `Your subscription does not renew automatically${ctx.taxFootnote}{
|
|
766
|
+
return `Your subscription does not renew automatically${ctx.taxFootnote}${LI_SEPARATOR}`;
|
|
765
767
|
}
|
|
766
|
-
return `Your subscription does not renew automatically{
|
|
768
|
+
return `Your subscription does not renew automatically${LI_SEPARATOR}`;
|
|
767
769
|
}
|
|
768
770
|
function generateApplePayModalTerms(offer, country) {
|
|
769
771
|
const ctx = buildTermsContext(offer, country);
|
|
@@ -786,9 +788,9 @@ function generateApplePayModalTerms(offer, country) {
|
|
|
786
788
|
return noAutoRenewalTerms(ctx);
|
|
787
789
|
}
|
|
788
790
|
function renderTermsHtml(termsText) {
|
|
789
|
-
const renewalTextLists = termsText.split(
|
|
791
|
+
const renewalTextLists = termsText.split(LI_SEPARATOR);
|
|
790
792
|
const lastPart = renewalTextLists.pop() || "";
|
|
791
|
-
const renewalTextParagraphs = lastPart.split(
|
|
793
|
+
const renewalTextParagraphs = lastPart.split(P_SEPARATOR);
|
|
792
794
|
const ulHtml = `<ul class="apm__terms-bullets">${renewalTextLists.map((value) => `<li>${value}</li>`).join("")}</ul>`;
|
|
793
795
|
const paragraphHtml = renewalTextParagraphs.filter(Boolean).map((value) => `<p class="apm__terms-legal">${value}</p>`).join("");
|
|
794
796
|
return ulHtml + paragraphHtml;
|
|
@@ -1207,7 +1209,6 @@ var validateAppleMerchant = (data) => {
|
|
|
1207
1209
|
});
|
|
1208
1210
|
};
|
|
1209
1211
|
var performPurchase = (data) => {
|
|
1210
|
-
console.log("[web-apple-pay] /v1/wallet/purchase payload", JSON.stringify(data, null, 2));
|
|
1211
1212
|
return apiFetch("/v1/wallet/purchase", {
|
|
1212
1213
|
method: "POST",
|
|
1213
1214
|
body: JSON.stringify(data),
|
|
@@ -1224,22 +1225,6 @@ var getExpressCheckoutSession = () => {
|
|
|
1224
1225
|
};
|
|
1225
1226
|
|
|
1226
1227
|
// src/utils/expressCheckoutRedirect.ts
|
|
1227
|
-
var CHECKOUT_REDIRECT_KEY = "checkout-redirect";
|
|
1228
|
-
var ALLOWED_REDIRECT_HOSTNAME = "economist.com";
|
|
1229
|
-
var writeCheckoutRedirect = (originUrl) => {
|
|
1230
|
-
if (originUrl.startsWith("/")) {
|
|
1231
|
-
localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
|
|
1232
|
-
return;
|
|
1233
|
-
}
|
|
1234
|
-
try {
|
|
1235
|
-
const { hostname } = new URL(originUrl);
|
|
1236
|
-
const isAllowed = hostname === ALLOWED_REDIRECT_HOSTNAME || hostname.endsWith(`.${ALLOWED_REDIRECT_HOSTNAME}`);
|
|
1237
|
-
if (isAllowed) {
|
|
1238
|
-
localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
|
|
1239
|
-
}
|
|
1240
|
-
} catch {
|
|
1241
|
-
}
|
|
1242
|
-
};
|
|
1243
1228
|
var captureOriginUrl = () => window.location.href;
|
|
1244
1229
|
var buildQueryString = () => {
|
|
1245
1230
|
const countryCode = new URLSearchParams(window.location.search).get(
|
|
@@ -1264,8 +1249,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1264
1249
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1265
1250
|
url.searchParams.set("status", params.status);
|
|
1266
1251
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1267
|
-
|
|
1268
|
-
if (params.country) url.searchParams.set("country", params.country);
|
|
1252
|
+
url.searchParams.set("returnUrl", params.returnUrl);
|
|
1269
1253
|
return url.pathname + url.search;
|
|
1270
1254
|
};
|
|
1271
1255
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1276,7 +1260,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1276
1260
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1277
1261
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1278
1262
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1279
|
-
|
|
1263
|
+
url.searchParams.set("returnUrl", params.returnUrl);
|
|
1280
1264
|
return url.pathname + url.search;
|
|
1281
1265
|
};
|
|
1282
1266
|
|
|
@@ -1360,16 +1344,17 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1360
1344
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1361
1345
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1362
1346
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1347
|
+
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1348
|
+
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1363
1349
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1364
1350
|
|
|
1365
1351
|
// src/clients/payment-checkout/apple-session.ts
|
|
1366
1352
|
function redirectToFallbackCheckout(config) {
|
|
1367
|
-
writeCheckoutRedirect(config.returnUrl);
|
|
1368
1353
|
trackFallbackCheckout(config.skuId);
|
|
1369
1354
|
window.location.href = redirectToCheckoutFallback({
|
|
1370
1355
|
skuId: config.skuId,
|
|
1371
|
-
|
|
1372
|
-
|
|
1356
|
+
returnUrl: config.returnUrl,
|
|
1357
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1373
1358
|
});
|
|
1374
1359
|
}
|
|
1375
1360
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1548,6 +1533,8 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1548
1533
|
};
|
|
1549
1534
|
|
|
1550
1535
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1536
|
+
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1537
|
+
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1551
1538
|
var failApplePaySession = (session, errors = []) => {
|
|
1552
1539
|
session.completePayment({
|
|
1553
1540
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1556,15 +1543,9 @@ var failApplePaySession = (session, errors = []) => {
|
|
|
1556
1543
|
};
|
|
1557
1544
|
function parseWalletApiError(err) {
|
|
1558
1545
|
const body = err instanceof ApiError ? err.body : err;
|
|
1559
|
-
console.warn("[web-apple-pay] parseWalletApiError: raw error", {
|
|
1560
|
-
isApiError: err instanceof ApiError,
|
|
1561
|
-
body
|
|
1562
|
-
});
|
|
1563
1546
|
if (body && typeof body === "object" && "errorType" in body && "message" in body) {
|
|
1564
|
-
console.warn("[web-apple-pay] parseWalletApiError: structured BFF error", body);
|
|
1565
1547
|
return body;
|
|
1566
1548
|
}
|
|
1567
|
-
console.warn("[web-apple-pay] parseWalletApiError: unstructured error \u2014 no errorType found");
|
|
1568
1549
|
return null;
|
|
1569
1550
|
}
|
|
1570
1551
|
function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
@@ -1577,42 +1558,37 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1577
1558
|
}
|
|
1578
1559
|
return void 0;
|
|
1579
1560
|
}
|
|
1580
|
-
function redirectFallback(skuId, returnUrl,
|
|
1581
|
-
writeCheckoutRedirect(returnUrl);
|
|
1561
|
+
function redirectFallback(skuId, returnUrl, options) {
|
|
1582
1562
|
trackFallbackCheckout(skuId);
|
|
1583
1563
|
window.location.href = redirectToCheckoutFallback({
|
|
1584
1564
|
skuId,
|
|
1585
|
-
|
|
1565
|
+
returnUrl,
|
|
1586
1566
|
...options
|
|
1587
1567
|
});
|
|
1588
1568
|
}
|
|
1589
1569
|
var ERROR_HANDLERS = {
|
|
1590
|
-
|
|
1591
|
-
|
|
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,
|
|
1570
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1571
|
+
emailError: MSG_EMAIL_COLLISION,
|
|
1601
1572
|
email: validatedEmail
|
|
1602
1573
|
}),
|
|
1603
|
-
|
|
1604
|
-
|
|
1574
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1575
|
+
// Matches sma-checkout catch-all: always redirect with generic inlineError.
|
|
1576
|
+
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR })
|
|
1577
|
+
),
|
|
1578
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_ELIGIBILITY }),
|
|
1579
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1580
|
+
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_RECAPTCHA_VALIDATION_FAILED })
|
|
1605
1581
|
};
|
|
1606
1582
|
function handleStructuredError(ctx) {
|
|
1607
1583
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1608
1584
|
if (handler) {
|
|
1609
1585
|
handler(ctx);
|
|
1610
1586
|
} else {
|
|
1611
|
-
redirectFallback(ctx.skuId, ctx.returnUrl,
|
|
1587
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1612
1588
|
}
|
|
1613
1589
|
}
|
|
1614
1590
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1615
|
-
const { skuId, returnUrl, queryString
|
|
1591
|
+
const { skuId, returnUrl, queryString } = config;
|
|
1616
1592
|
let validatedEmail;
|
|
1617
1593
|
try {
|
|
1618
1594
|
validatedEmail = validateContacts(
|
|
@@ -1620,32 +1596,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1620
1596
|
sessionData,
|
|
1621
1597
|
config.supportedBillingCountries
|
|
1622
1598
|
);
|
|
1623
|
-
const resolvedShippingContact = sessionData.loggedIn ? {
|
|
1624
|
-
...event.payment.shippingContact ?? {},
|
|
1625
|
-
emailAddress: sessionData.emailAddress
|
|
1626
|
-
} : event.payment.shippingContact;
|
|
1627
1599
|
const result = await performPurchase({
|
|
1628
1600
|
applePayToken: event.payment.token,
|
|
1629
1601
|
skuId: config.skuId,
|
|
1630
1602
|
currency: config.currency,
|
|
1631
1603
|
billingContact: event.payment.billingContact,
|
|
1632
|
-
...
|
|
1633
|
-
shippingContact:
|
|
1604
|
+
...event.payment.shippingContact && {
|
|
1605
|
+
shippingContact: event.payment.shippingContact
|
|
1634
1606
|
},
|
|
1635
1607
|
recaptchaTokens: config.recaptchaTokens
|
|
1636
1608
|
});
|
|
1637
1609
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1638
1610
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1639
|
-
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1640
1611
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1641
|
-
writeCheckoutRedirect(returnUrl);
|
|
1642
1612
|
window.location.href = redirectToCheckoutComplete({
|
|
1643
1613
|
basketId: result.basketId,
|
|
1644
1614
|
status: userStatus,
|
|
1645
1615
|
skuId: decodeSku(skuId),
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
country
|
|
1616
|
+
returnUrl,
|
|
1617
|
+
queryString
|
|
1649
1618
|
});
|
|
1650
1619
|
} catch (err) {
|
|
1651
1620
|
if (err instanceof ContactValidationError) {
|
|
@@ -1657,10 +1626,10 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1657
1626
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1658
1627
|
failApplePaySession(session);
|
|
1659
1628
|
if (!walletError) {
|
|
1660
|
-
redirectFallback(skuId, returnUrl,
|
|
1629
|
+
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1661
1630
|
return;
|
|
1662
1631
|
}
|
|
1663
|
-
handleStructuredError({ skuId, returnUrl,
|
|
1632
|
+
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1664
1633
|
}
|
|
1665
1634
|
}
|
|
1666
1635
|
|
|
@@ -679,6 +679,8 @@ function renewalPeriodText(unit, duration) {
|
|
|
679
679
|
return "";
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
|
+
var LI_SEPARATOR = "LI_SEPARATOR";
|
|
683
|
+
var P_SEPARATOR = "P_SEPARATOR";
|
|
682
684
|
function buildTermsContext(offer, country) {
|
|
683
685
|
const isUS = country === "US";
|
|
684
686
|
const isCA = country === "CA";
|
|
@@ -715,19 +717,19 @@ function freeTrialTerms(offer, ctx) {
|
|
|
715
717
|
const trialDuration = offer.subscription_options?.trial_period?.duration ?? 1;
|
|
716
718
|
const trialDateStr = `on ${getRenewalDateText(trialUnit, trialDuration)}${ctx.verificationText}`;
|
|
717
719
|
if (ctx.isUS) {
|
|
718
|
-
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled{
|
|
720
|
+
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
719
721
|
}
|
|
720
|
-
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled{
|
|
722
|
+
return `Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${trialDateStr} when your free trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
721
723
|
}
|
|
722
724
|
function nytTerms(ctx) {
|
|
723
725
|
const nytAccessText = "Your complimentary access to The New York Times is for one year only and does not auto-renew. We will send your instructions on how to redeem access to The New York Times by email.";
|
|
724
726
|
if (ctx.isUS) {
|
|
725
|
-
return `Your subscription to <em>The Economist</em> auto-renews ${ctx.periodText} until cancelled{
|
|
727
|
+
return `Your subscription to <em>The Economist</em> auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.renewalDateStr}${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}${P_SEPARATOR}${nytAccessText}`;
|
|
726
728
|
}
|
|
727
729
|
if (ctx.isCA) {
|
|
728
|
-
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled
|
|
730
|
+
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled.${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}${P_SEPARATOR}${nytAccessText}`;
|
|
729
731
|
}
|
|
730
|
-
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled{
|
|
732
|
+
return `Your subscription to <em>The Economist</em> auto-renews at ${ctx.renewalPriceText} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime} ${nytAccessText}`;
|
|
731
733
|
}
|
|
732
734
|
function minTermContractTerms(offer, ctx) {
|
|
733
735
|
const duePrice = formatPrice(offer.price.purchase, offer.price.currency_code);
|
|
@@ -737,28 +739,28 @@ function minTermContractTerms(offer, ctx) {
|
|
|
737
739
|
const contractLength = mtDuration && mtUnit ? `${mtDuration} ${mtUnit}` : "";
|
|
738
740
|
const initialContractText = contractLength ? `your initial ${contractLength} contract` : "your initial contract";
|
|
739
741
|
const mtRenewalDateText = mtUnit && mtDuration ? getRenewalDateText(mtUnit, Number(mtDuration)) : ctx.renewalDateText;
|
|
740
|
-
return `You\u2019ll be charged ${duePrice} a month for the duration of ${initialContractText}{
|
|
742
|
+
return `You\u2019ll be charged ${duePrice} a month for the duration of ${initialContractText}${LI_SEPARATOR}Your subscription auto-renews annually at ${ctx.renewalPriceText} a month on ${mtRenewalDateText} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}`;
|
|
741
743
|
}
|
|
742
744
|
function paidTrialTerms(offer, ctx) {
|
|
743
745
|
const trialUnit = offer.subscription_options?.trial_period?.unit ?? ctx.unit;
|
|
744
746
|
const trialDuration = offer.subscription_options?.trial_period?.duration ?? ctx.duration;
|
|
745
747
|
const trialDateText = getRenewalDateText(trialUnit, trialDuration);
|
|
746
748
|
if (ctx.isUS) {
|
|
747
|
-
return `Your subscription auto-renews ${ctx.periodText} until cancelled{
|
|
749
|
+
return `Your subscription auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} on ${trialDateText} when your paid trial ends${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
748
750
|
}
|
|
749
|
-
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} on ${trialDateText} when your paid trial ends, until cancelled{
|
|
751
|
+
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} on ${trialDateText} when your paid trial ends, until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
750
752
|
}
|
|
751
753
|
function autoRenewalTerms(ctx) {
|
|
752
754
|
if (ctx.isUS) {
|
|
753
|
-
return `Your subscription auto-renews ${ctx.periodText} until cancelled{
|
|
755
|
+
return `Your subscription auto-renews ${ctx.periodText} until cancelled${LI_SEPARATOR}Your subscription renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.renewalDateStr}${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal until cancelled. ${ctx.usCancelNote}${ctx.taxFootnote}`;
|
|
754
756
|
}
|
|
755
|
-
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled{
|
|
757
|
+
return `Your subscription auto-renews at ${ctx.renewalPriceText}${ctx.taxSuffix} ${ctx.periodText} ${ctx.renewalDateStr} until cancelled${LI_SEPARATOR}You\u2019ll be charged the rate in effect at each renewal. ${ctx.cancelAnytime}${ctx.taxFootnote}`;
|
|
756
758
|
}
|
|
757
759
|
function noAutoRenewalTerms(ctx) {
|
|
758
760
|
if (ctx.isUS || ctx.isCA) {
|
|
759
|
-
return `Your subscription does not renew automatically${ctx.taxFootnote}{
|
|
761
|
+
return `Your subscription does not renew automatically${ctx.taxFootnote}${LI_SEPARATOR}`;
|
|
760
762
|
}
|
|
761
|
-
return `Your subscription does not renew automatically{
|
|
763
|
+
return `Your subscription does not renew automatically${LI_SEPARATOR}`;
|
|
762
764
|
}
|
|
763
765
|
function generateApplePayModalTerms(offer, country) {
|
|
764
766
|
const ctx = buildTermsContext(offer, country);
|
|
@@ -781,9 +783,9 @@ function generateApplePayModalTerms(offer, country) {
|
|
|
781
783
|
return noAutoRenewalTerms(ctx);
|
|
782
784
|
}
|
|
783
785
|
function renderTermsHtml(termsText) {
|
|
784
|
-
const renewalTextLists = termsText.split(
|
|
786
|
+
const renewalTextLists = termsText.split(LI_SEPARATOR);
|
|
785
787
|
const lastPart = renewalTextLists.pop() || "";
|
|
786
|
-
const renewalTextParagraphs = lastPart.split(
|
|
788
|
+
const renewalTextParagraphs = lastPart.split(P_SEPARATOR);
|
|
787
789
|
const ulHtml = `<ul class="apm__terms-bullets">${renewalTextLists.map((value) => `<li>${value}</li>`).join("")}</ul>`;
|
|
788
790
|
const paragraphHtml = renewalTextParagraphs.filter(Boolean).map((value) => `<p class="apm__terms-legal">${value}</p>`).join("");
|
|
789
791
|
return ulHtml + paragraphHtml;
|
|
@@ -1202,7 +1204,6 @@ var validateAppleMerchant = (data) => {
|
|
|
1202
1204
|
});
|
|
1203
1205
|
};
|
|
1204
1206
|
var performPurchase = (data) => {
|
|
1205
|
-
console.log("[web-apple-pay] /v1/wallet/purchase payload", JSON.stringify(data, null, 2));
|
|
1206
1207
|
return apiFetch("/v1/wallet/purchase", {
|
|
1207
1208
|
method: "POST",
|
|
1208
1209
|
body: JSON.stringify(data),
|
|
@@ -1219,22 +1220,6 @@ var getExpressCheckoutSession = () => {
|
|
|
1219
1220
|
};
|
|
1220
1221
|
|
|
1221
1222
|
// src/utils/expressCheckoutRedirect.ts
|
|
1222
|
-
var CHECKOUT_REDIRECT_KEY = "checkout-redirect";
|
|
1223
|
-
var ALLOWED_REDIRECT_HOSTNAME = "economist.com";
|
|
1224
|
-
var writeCheckoutRedirect = (originUrl) => {
|
|
1225
|
-
if (originUrl.startsWith("/")) {
|
|
1226
|
-
localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
|
|
1227
|
-
return;
|
|
1228
|
-
}
|
|
1229
|
-
try {
|
|
1230
|
-
const { hostname } = new URL(originUrl);
|
|
1231
|
-
const isAllowed = hostname === ALLOWED_REDIRECT_HOSTNAME || hostname.endsWith(`.${ALLOWED_REDIRECT_HOSTNAME}`);
|
|
1232
|
-
if (isAllowed) {
|
|
1233
|
-
localStorage.setItem(CHECKOUT_REDIRECT_KEY, originUrl);
|
|
1234
|
-
}
|
|
1235
|
-
} catch {
|
|
1236
|
-
}
|
|
1237
|
-
};
|
|
1238
1223
|
var captureOriginUrl = () => window.location.href;
|
|
1239
1224
|
var buildQueryString = () => {
|
|
1240
1225
|
const countryCode = new URLSearchParams(window.location.search).get(
|
|
@@ -1259,8 +1244,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1259
1244
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1260
1245
|
url.searchParams.set("status", params.status);
|
|
1261
1246
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1262
|
-
|
|
1263
|
-
if (params.country) url.searchParams.set("country", params.country);
|
|
1247
|
+
url.searchParams.set("returnUrl", params.returnUrl);
|
|
1264
1248
|
return url.pathname + url.search;
|
|
1265
1249
|
};
|
|
1266
1250
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1271,7 +1255,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1271
1255
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1272
1256
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1273
1257
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1274
|
-
|
|
1258
|
+
url.searchParams.set("returnUrl", params.returnUrl);
|
|
1275
1259
|
return url.pathname + url.search;
|
|
1276
1260
|
};
|
|
1277
1261
|
|
|
@@ -1355,16 +1339,17 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1355
1339
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1356
1340
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1357
1341
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1342
|
+
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1343
|
+
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1358
1344
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1359
1345
|
|
|
1360
1346
|
// src/clients/payment-checkout/apple-session.ts
|
|
1361
1347
|
function redirectToFallbackCheckout(config) {
|
|
1362
|
-
writeCheckoutRedirect(config.returnUrl);
|
|
1363
1348
|
trackFallbackCheckout(config.skuId);
|
|
1364
1349
|
window.location.href = redirectToCheckoutFallback({
|
|
1365
1350
|
skuId: config.skuId,
|
|
1366
|
-
|
|
1367
|
-
|
|
1351
|
+
returnUrl: config.returnUrl,
|
|
1352
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1368
1353
|
});
|
|
1369
1354
|
}
|
|
1370
1355
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1543,6 +1528,8 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1543
1528
|
};
|
|
1544
1529
|
|
|
1545
1530
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1531
|
+
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1532
|
+
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1546
1533
|
var failApplePaySession = (session, errors = []) => {
|
|
1547
1534
|
session.completePayment({
|
|
1548
1535
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1551,15 +1538,9 @@ var failApplePaySession = (session, errors = []) => {
|
|
|
1551
1538
|
};
|
|
1552
1539
|
function parseWalletApiError(err) {
|
|
1553
1540
|
const body = err instanceof ApiError ? err.body : err;
|
|
1554
|
-
console.warn("[web-apple-pay] parseWalletApiError: raw error", {
|
|
1555
|
-
isApiError: err instanceof ApiError,
|
|
1556
|
-
body
|
|
1557
|
-
});
|
|
1558
1541
|
if (body && typeof body === "object" && "errorType" in body && "message" in body) {
|
|
1559
|
-
console.warn("[web-apple-pay] parseWalletApiError: structured BFF error", body);
|
|
1560
1542
|
return body;
|
|
1561
1543
|
}
|
|
1562
|
-
console.warn("[web-apple-pay] parseWalletApiError: unstructured error \u2014 no errorType found");
|
|
1563
1544
|
return null;
|
|
1564
1545
|
}
|
|
1565
1546
|
function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
@@ -1572,42 +1553,37 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1572
1553
|
}
|
|
1573
1554
|
return void 0;
|
|
1574
1555
|
}
|
|
1575
|
-
function redirectFallback(skuId, returnUrl,
|
|
1576
|
-
writeCheckoutRedirect(returnUrl);
|
|
1556
|
+
function redirectFallback(skuId, returnUrl, options) {
|
|
1577
1557
|
trackFallbackCheckout(skuId);
|
|
1578
1558
|
window.location.href = redirectToCheckoutFallback({
|
|
1579
1559
|
skuId,
|
|
1580
|
-
|
|
1560
|
+
returnUrl,
|
|
1581
1561
|
...options
|
|
1582
1562
|
});
|
|
1583
1563
|
}
|
|
1584
1564
|
var ERROR_HANDLERS = {
|
|
1585
|
-
|
|
1586
|
-
|
|
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,
|
|
1565
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1566
|
+
emailError: MSG_EMAIL_COLLISION,
|
|
1596
1567
|
email: validatedEmail
|
|
1597
1568
|
}),
|
|
1598
|
-
|
|
1599
|
-
|
|
1569
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1570
|
+
// Matches sma-checkout catch-all: always redirect with generic inlineError.
|
|
1571
|
+
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR })
|
|
1572
|
+
),
|
|
1573
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_ELIGIBILITY }),
|
|
1574
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1575
|
+
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_RECAPTCHA_VALIDATION_FAILED })
|
|
1600
1576
|
};
|
|
1601
1577
|
function handleStructuredError(ctx) {
|
|
1602
1578
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1603
1579
|
if (handler) {
|
|
1604
1580
|
handler(ctx);
|
|
1605
1581
|
} else {
|
|
1606
|
-
redirectFallback(ctx.skuId, ctx.returnUrl,
|
|
1582
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1607
1583
|
}
|
|
1608
1584
|
}
|
|
1609
1585
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1610
|
-
const { skuId, returnUrl, queryString
|
|
1586
|
+
const { skuId, returnUrl, queryString } = config;
|
|
1611
1587
|
let validatedEmail;
|
|
1612
1588
|
try {
|
|
1613
1589
|
validatedEmail = validateContacts(
|
|
@@ -1615,32 +1591,25 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1615
1591
|
sessionData,
|
|
1616
1592
|
config.supportedBillingCountries
|
|
1617
1593
|
);
|
|
1618
|
-
const resolvedShippingContact = sessionData.loggedIn ? {
|
|
1619
|
-
...event.payment.shippingContact ?? {},
|
|
1620
|
-
emailAddress: sessionData.emailAddress
|
|
1621
|
-
} : event.payment.shippingContact;
|
|
1622
1594
|
const result = await performPurchase({
|
|
1623
1595
|
applePayToken: event.payment.token,
|
|
1624
1596
|
skuId: config.skuId,
|
|
1625
1597
|
currency: config.currency,
|
|
1626
1598
|
billingContact: event.payment.billingContact,
|
|
1627
|
-
...
|
|
1628
|
-
shippingContact:
|
|
1599
|
+
...event.payment.shippingContact && {
|
|
1600
|
+
shippingContact: event.payment.shippingContact
|
|
1629
1601
|
},
|
|
1630
1602
|
recaptchaTokens: config.recaptchaTokens
|
|
1631
1603
|
});
|
|
1632
1604
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1633
1605
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1634
|
-
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1635
1606
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1636
|
-
writeCheckoutRedirect(returnUrl);
|
|
1637
1607
|
window.location.href = redirectToCheckoutComplete({
|
|
1638
1608
|
basketId: result.basketId,
|
|
1639
1609
|
status: userStatus,
|
|
1640
1610
|
skuId: decodeSku(skuId),
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
country
|
|
1611
|
+
returnUrl,
|
|
1612
|
+
queryString
|
|
1644
1613
|
});
|
|
1645
1614
|
} catch (err) {
|
|
1646
1615
|
if (err instanceof ContactValidationError) {
|
|
@@ -1652,10 +1621,10 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1652
1621
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1653
1622
|
failApplePaySession(session);
|
|
1654
1623
|
if (!walletError) {
|
|
1655
|
-
redirectFallback(skuId, returnUrl,
|
|
1624
|
+
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1656
1625
|
return;
|
|
1657
1626
|
}
|
|
1658
|
-
handleStructuredError({ skuId, returnUrl,
|
|
1627
|
+
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1659
1628
|
}
|
|
1660
1629
|
}
|
|
1661
1630
|
|