@economist/web-apple-pay 0.1.3-beta.22 → 0.1.3-beta.24
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 +26 -34
- package/dist/src/apple-pay-button.js +26 -34
- package/dist/src/apple-pay-button.stories.js +26 -34
- package/dist/src/apple-pay-modal.stories.js +26 -34
- package/dist/src/clients/payment-checkout/apple-session.js +3 -8
- package/dist/src/clients/payment-checkout/index.js +0 -7
- package/dist/src/clients/payment-checkout/messages.d.ts +11 -14
- package/dist/src/clients/payment-checkout/messages.js +0 -4
- package/dist/src/clients/payment-checkout/payment-handler.js +24 -33
- package/dist/src/clients/payment-checkout/session.js +0 -7
- package/dist/src/index.js +26 -34
- package/dist/src/utils/expressCheckoutRedirect.d.ts +18 -1
- package/dist/src/utils/expressCheckoutRedirect.js +3 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1156,18 +1156,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
1156
1156
|
});
|
|
1157
1157
|
if (!response.ok) {
|
|
1158
1158
|
const contentType = response.headers.get("content-type") || "";
|
|
1159
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
1160
|
-
path,
|
|
1161
|
-
status: response.status,
|
|
1162
|
-
contentType
|
|
1163
|
-
});
|
|
1164
1159
|
if (contentType.includes("application/json")) {
|
|
1165
1160
|
const errorBody = await response.json();
|
|
1166
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
1167
1161
|
throw new ApiError(response.status, errorBody);
|
|
1168
1162
|
}
|
|
1169
1163
|
const errorText = await response.text();
|
|
1170
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
1171
1164
|
throw new Error(
|
|
1172
1165
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
1173
1166
|
);
|
|
@@ -1245,6 +1238,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1245
1238
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1246
1239
|
url.searchParams.set("status", params.status);
|
|
1247
1240
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1241
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
1242
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1248
1243
|
return url.pathname + url.search;
|
|
1249
1244
|
};
|
|
1250
1245
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1255,6 +1250,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1255
1250
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1256
1251
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1257
1252
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1253
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1258
1254
|
return url.pathname + url.search;
|
|
1259
1255
|
};
|
|
1260
1256
|
|
|
@@ -1338,8 +1334,6 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1338
1334
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1339
1335
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1340
1336
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1341
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1342
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1343
1337
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1344
1338
|
|
|
1345
1339
|
// src/clients/payment-checkout/apple-session.ts
|
|
@@ -1348,7 +1342,8 @@ function redirectToFallbackCheckout(config) {
|
|
|
1348
1342
|
trackFallbackCheckout(config.skuId);
|
|
1349
1343
|
window.location.href = redirectToCheckoutFallback({
|
|
1350
1344
|
skuId: config.skuId,
|
|
1351
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1345
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
1346
|
+
country: config.countryCode
|
|
1352
1347
|
});
|
|
1353
1348
|
}
|
|
1354
1349
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1527,8 +1522,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1527
1522
|
};
|
|
1528
1523
|
|
|
1529
1524
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1530
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1531
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1532
1525
|
var failApplePaySession = (session, errors = []) => {
|
|
1533
1526
|
session.completePayment({
|
|
1534
1527
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1558,42 +1551,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1558
1551
|
}
|
|
1559
1552
|
return void 0;
|
|
1560
1553
|
}
|
|
1561
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
1554
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
1562
1555
|
writeCheckoutRedirect(returnUrl);
|
|
1563
1556
|
trackFallbackCheckout(skuId);
|
|
1564
1557
|
window.location.href = redirectToCheckoutFallback({
|
|
1565
1558
|
skuId,
|
|
1559
|
+
country,
|
|
1566
1560
|
...options
|
|
1567
1561
|
});
|
|
1568
1562
|
}
|
|
1569
1563
|
var ERROR_HANDLERS = {
|
|
1570
|
-
|
|
1571
|
-
|
|
1564
|
+
// emailError flows as an inline field error on the email input.
|
|
1565
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
1566
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1567
|
+
emailError: walletError.message,
|
|
1572
1568
|
email: validatedEmail
|
|
1573
1569
|
}),
|
|
1574
|
-
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
),
|
|
1578
|
-
|
|
1579
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1580
|
-
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1581
|
-
emailError: MSG_REGISTRATION,
|
|
1570
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1571
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1572
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1573
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1574
|
+
emailError: walletError.message,
|
|
1582
1575
|
email: validatedEmail
|
|
1583
1576
|
}),
|
|
1584
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1585
|
-
RECAPTCHA_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1577
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1578
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
1586
1579
|
};
|
|
1587
1580
|
function handleStructuredError(ctx) {
|
|
1588
1581
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1589
1582
|
if (handler) {
|
|
1590
1583
|
handler(ctx);
|
|
1591
1584
|
} else {
|
|
1592
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1585
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1593
1586
|
}
|
|
1594
1587
|
}
|
|
1595
1588
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1596
|
-
const { skuId, returnUrl, queryString } = config;
|
|
1589
|
+
const { skuId, returnUrl, queryString, country } = config;
|
|
1597
1590
|
let validatedEmail;
|
|
1598
1591
|
try {
|
|
1599
1592
|
validatedEmail = validateContacts(
|
|
@@ -1613,13 +1606,16 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1613
1606
|
});
|
|
1614
1607
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1615
1608
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1609
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1616
1610
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1617
1611
|
writeCheckoutRedirect(returnUrl);
|
|
1618
1612
|
window.location.href = redirectToCheckoutComplete({
|
|
1619
1613
|
basketId: result.basketId,
|
|
1620
1614
|
status: userStatus,
|
|
1621
1615
|
skuId: decodeSku(skuId),
|
|
1622
|
-
queryString
|
|
1616
|
+
queryString,
|
|
1617
|
+
email: successEmail,
|
|
1618
|
+
country
|
|
1623
1619
|
});
|
|
1624
1620
|
} catch (err) {
|
|
1625
1621
|
if (err instanceof ContactValidationError) {
|
|
@@ -1628,17 +1624,13 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1628
1624
|
}
|
|
1629
1625
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1630
1626
|
const walletError = parseWalletApiError(err);
|
|
1631
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: walletError result", {
|
|
1632
|
-
walletError,
|
|
1633
|
-
validatedEmail
|
|
1634
|
-
});
|
|
1635
1627
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1636
1628
|
failApplePaySession(session);
|
|
1637
1629
|
if (!walletError) {
|
|
1638
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1630
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1639
1631
|
return;
|
|
1640
1632
|
}
|
|
1641
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1633
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
1642
1634
|
}
|
|
1643
1635
|
}
|
|
1644
1636
|
|
|
@@ -1151,18 +1151,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
1151
1151
|
});
|
|
1152
1152
|
if (!response.ok) {
|
|
1153
1153
|
const contentType = response.headers.get("content-type") || "";
|
|
1154
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
1155
|
-
path,
|
|
1156
|
-
status: response.status,
|
|
1157
|
-
contentType
|
|
1158
|
-
});
|
|
1159
1154
|
if (contentType.includes("application/json")) {
|
|
1160
1155
|
const errorBody = await response.json();
|
|
1161
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
1162
1156
|
throw new ApiError(response.status, errorBody);
|
|
1163
1157
|
}
|
|
1164
1158
|
const errorText = await response.text();
|
|
1165
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
1166
1159
|
throw new Error(
|
|
1167
1160
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
1168
1161
|
);
|
|
@@ -1240,6 +1233,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1240
1233
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1241
1234
|
url.searchParams.set("status", params.status);
|
|
1242
1235
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1236
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
1237
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1243
1238
|
return url.pathname + url.search;
|
|
1244
1239
|
};
|
|
1245
1240
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1250,6 +1245,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1250
1245
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1251
1246
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1252
1247
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1248
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1253
1249
|
return url.pathname + url.search;
|
|
1254
1250
|
};
|
|
1255
1251
|
|
|
@@ -1333,8 +1329,6 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1333
1329
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1334
1330
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1335
1331
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1336
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1337
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1338
1332
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1339
1333
|
|
|
1340
1334
|
// src/clients/payment-checkout/apple-session.ts
|
|
@@ -1343,7 +1337,8 @@ function redirectToFallbackCheckout(config) {
|
|
|
1343
1337
|
trackFallbackCheckout(config.skuId);
|
|
1344
1338
|
window.location.href = redirectToCheckoutFallback({
|
|
1345
1339
|
skuId: config.skuId,
|
|
1346
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1340
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
1341
|
+
country: config.countryCode
|
|
1347
1342
|
});
|
|
1348
1343
|
}
|
|
1349
1344
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1522,8 +1517,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1522
1517
|
};
|
|
1523
1518
|
|
|
1524
1519
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1525
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1526
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1527
1520
|
var failApplePaySession = (session, errors = []) => {
|
|
1528
1521
|
session.completePayment({
|
|
1529
1522
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1553,42 +1546,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1553
1546
|
}
|
|
1554
1547
|
return void 0;
|
|
1555
1548
|
}
|
|
1556
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
1549
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
1557
1550
|
writeCheckoutRedirect(returnUrl);
|
|
1558
1551
|
trackFallbackCheckout(skuId);
|
|
1559
1552
|
window.location.href = redirectToCheckoutFallback({
|
|
1560
1553
|
skuId,
|
|
1554
|
+
country,
|
|
1561
1555
|
...options
|
|
1562
1556
|
});
|
|
1563
1557
|
}
|
|
1564
1558
|
var ERROR_HANDLERS = {
|
|
1565
|
-
|
|
1566
|
-
|
|
1559
|
+
// emailError flows as an inline field error on the email input.
|
|
1560
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
1561
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1562
|
+
emailError: walletError.message,
|
|
1567
1563
|
email: validatedEmail
|
|
1568
1564
|
}),
|
|
1569
|
-
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
),
|
|
1573
|
-
|
|
1574
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1575
|
-
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1576
|
-
emailError: MSG_REGISTRATION,
|
|
1565
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1566
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1567
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1568
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1569
|
+
emailError: walletError.message,
|
|
1577
1570
|
email: validatedEmail
|
|
1578
1571
|
}),
|
|
1579
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1580
|
-
RECAPTCHA_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1572
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1573
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
1581
1574
|
};
|
|
1582
1575
|
function handleStructuredError(ctx) {
|
|
1583
1576
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1584
1577
|
if (handler) {
|
|
1585
1578
|
handler(ctx);
|
|
1586
1579
|
} else {
|
|
1587
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1580
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1588
1581
|
}
|
|
1589
1582
|
}
|
|
1590
1583
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1591
|
-
const { skuId, returnUrl, queryString } = config;
|
|
1584
|
+
const { skuId, returnUrl, queryString, country } = config;
|
|
1592
1585
|
let validatedEmail;
|
|
1593
1586
|
try {
|
|
1594
1587
|
validatedEmail = validateContacts(
|
|
@@ -1608,13 +1601,16 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1608
1601
|
});
|
|
1609
1602
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1610
1603
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1604
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1611
1605
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1612
1606
|
writeCheckoutRedirect(returnUrl);
|
|
1613
1607
|
window.location.href = redirectToCheckoutComplete({
|
|
1614
1608
|
basketId: result.basketId,
|
|
1615
1609
|
status: userStatus,
|
|
1616
1610
|
skuId: decodeSku(skuId),
|
|
1617
|
-
queryString
|
|
1611
|
+
queryString,
|
|
1612
|
+
email: successEmail,
|
|
1613
|
+
country
|
|
1618
1614
|
});
|
|
1619
1615
|
} catch (err) {
|
|
1620
1616
|
if (err instanceof ContactValidationError) {
|
|
@@ -1623,17 +1619,13 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1623
1619
|
}
|
|
1624
1620
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1625
1621
|
const walletError = parseWalletApiError(err);
|
|
1626
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: walletError result", {
|
|
1627
|
-
walletError,
|
|
1628
|
-
validatedEmail
|
|
1629
|
-
});
|
|
1630
1622
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1631
1623
|
failApplePaySession(session);
|
|
1632
1624
|
if (!walletError) {
|
|
1633
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1625
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1634
1626
|
return;
|
|
1635
1627
|
}
|
|
1636
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1628
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
1637
1629
|
}
|
|
1638
1630
|
}
|
|
1639
1631
|
|
|
@@ -1159,18 +1159,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
1159
1159
|
});
|
|
1160
1160
|
if (!response.ok) {
|
|
1161
1161
|
const contentType = response.headers.get("content-type") || "";
|
|
1162
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
1163
|
-
path,
|
|
1164
|
-
status: response.status,
|
|
1165
|
-
contentType
|
|
1166
|
-
});
|
|
1167
1162
|
if (contentType.includes("application/json")) {
|
|
1168
1163
|
const errorBody = await response.json();
|
|
1169
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
1170
1164
|
throw new ApiError(response.status, errorBody);
|
|
1171
1165
|
}
|
|
1172
1166
|
const errorText = await response.text();
|
|
1173
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
1174
1167
|
throw new Error(
|
|
1175
1168
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
1176
1169
|
);
|
|
@@ -1248,6 +1241,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1248
1241
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1249
1242
|
url.searchParams.set("status", params.status);
|
|
1250
1243
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1244
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
1245
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1251
1246
|
return url.pathname + url.search;
|
|
1252
1247
|
};
|
|
1253
1248
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1258,6 +1253,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1258
1253
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1259
1254
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1260
1255
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1256
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1261
1257
|
return url.pathname + url.search;
|
|
1262
1258
|
};
|
|
1263
1259
|
|
|
@@ -1341,8 +1337,6 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1341
1337
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1342
1338
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1343
1339
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1344
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1345
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1346
1340
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1347
1341
|
|
|
1348
1342
|
// src/clients/payment-checkout/apple-session.ts
|
|
@@ -1351,7 +1345,8 @@ function redirectToFallbackCheckout(config) {
|
|
|
1351
1345
|
trackFallbackCheckout(config.skuId);
|
|
1352
1346
|
window.location.href = redirectToCheckoutFallback({
|
|
1353
1347
|
skuId: config.skuId,
|
|
1354
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1348
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
1349
|
+
country: config.countryCode
|
|
1355
1350
|
});
|
|
1356
1351
|
}
|
|
1357
1352
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1530,8 +1525,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1530
1525
|
};
|
|
1531
1526
|
|
|
1532
1527
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1533
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1534
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1535
1528
|
var failApplePaySession = (session, errors = []) => {
|
|
1536
1529
|
session.completePayment({
|
|
1537
1530
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1561,42 +1554,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1561
1554
|
}
|
|
1562
1555
|
return void 0;
|
|
1563
1556
|
}
|
|
1564
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
1557
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
1565
1558
|
writeCheckoutRedirect(returnUrl);
|
|
1566
1559
|
trackFallbackCheckout(skuId);
|
|
1567
1560
|
window.location.href = redirectToCheckoutFallback({
|
|
1568
1561
|
skuId,
|
|
1562
|
+
country,
|
|
1569
1563
|
...options
|
|
1570
1564
|
});
|
|
1571
1565
|
}
|
|
1572
1566
|
var ERROR_HANDLERS = {
|
|
1573
|
-
|
|
1574
|
-
|
|
1567
|
+
// emailError flows as an inline field error on the email input.
|
|
1568
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
1569
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1570
|
+
emailError: walletError.message,
|
|
1575
1571
|
email: validatedEmail
|
|
1576
1572
|
}),
|
|
1577
|
-
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
),
|
|
1581
|
-
|
|
1582
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1583
|
-
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1584
|
-
emailError: MSG_REGISTRATION,
|
|
1573
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1574
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1575
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1576
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1577
|
+
emailError: walletError.message,
|
|
1585
1578
|
email: validatedEmail
|
|
1586
1579
|
}),
|
|
1587
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1588
|
-
RECAPTCHA_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1580
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1581
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
1589
1582
|
};
|
|
1590
1583
|
function handleStructuredError(ctx) {
|
|
1591
1584
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1592
1585
|
if (handler) {
|
|
1593
1586
|
handler(ctx);
|
|
1594
1587
|
} else {
|
|
1595
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1588
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1596
1589
|
}
|
|
1597
1590
|
}
|
|
1598
1591
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1599
|
-
const { skuId, returnUrl, queryString } = config;
|
|
1592
|
+
const { skuId, returnUrl, queryString, country } = config;
|
|
1600
1593
|
let validatedEmail;
|
|
1601
1594
|
try {
|
|
1602
1595
|
validatedEmail = validateContacts(
|
|
@@ -1616,13 +1609,16 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1616
1609
|
});
|
|
1617
1610
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1618
1611
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1612
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1619
1613
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1620
1614
|
writeCheckoutRedirect(returnUrl);
|
|
1621
1615
|
window.location.href = redirectToCheckoutComplete({
|
|
1622
1616
|
basketId: result.basketId,
|
|
1623
1617
|
status: userStatus,
|
|
1624
1618
|
skuId: decodeSku(skuId),
|
|
1625
|
-
queryString
|
|
1619
|
+
queryString,
|
|
1620
|
+
email: successEmail,
|
|
1621
|
+
country
|
|
1626
1622
|
});
|
|
1627
1623
|
} catch (err) {
|
|
1628
1624
|
if (err instanceof ContactValidationError) {
|
|
@@ -1631,17 +1627,13 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1631
1627
|
}
|
|
1632
1628
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1633
1629
|
const walletError = parseWalletApiError(err);
|
|
1634
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: walletError result", {
|
|
1635
|
-
walletError,
|
|
1636
|
-
validatedEmail
|
|
1637
|
-
});
|
|
1638
1630
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1639
1631
|
failApplePaySession(session);
|
|
1640
1632
|
if (!walletError) {
|
|
1641
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1633
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1642
1634
|
return;
|
|
1643
1635
|
}
|
|
1644
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1636
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
1645
1637
|
}
|
|
1646
1638
|
}
|
|
1647
1639
|
|
|
@@ -1151,18 +1151,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
1151
1151
|
});
|
|
1152
1152
|
if (!response.ok) {
|
|
1153
1153
|
const contentType = response.headers.get("content-type") || "";
|
|
1154
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
1155
|
-
path,
|
|
1156
|
-
status: response.status,
|
|
1157
|
-
contentType
|
|
1158
|
-
});
|
|
1159
1154
|
if (contentType.includes("application/json")) {
|
|
1160
1155
|
const errorBody = await response.json();
|
|
1161
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
1162
1156
|
throw new ApiError(response.status, errorBody);
|
|
1163
1157
|
}
|
|
1164
1158
|
const errorText = await response.text();
|
|
1165
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
1166
1159
|
throw new Error(
|
|
1167
1160
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
1168
1161
|
);
|
|
@@ -1240,6 +1233,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1240
1233
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1241
1234
|
url.searchParams.set("status", params.status);
|
|
1242
1235
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1236
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
1237
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1243
1238
|
return url.pathname + url.search;
|
|
1244
1239
|
};
|
|
1245
1240
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1250,6 +1245,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1250
1245
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1251
1246
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1252
1247
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1248
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1253
1249
|
return url.pathname + url.search;
|
|
1254
1250
|
};
|
|
1255
1251
|
|
|
@@ -1333,8 +1329,6 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1333
1329
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1334
1330
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1335
1331
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1336
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1337
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1338
1332
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1339
1333
|
|
|
1340
1334
|
// src/clients/payment-checkout/apple-session.ts
|
|
@@ -1343,7 +1337,8 @@ function redirectToFallbackCheckout(config) {
|
|
|
1343
1337
|
trackFallbackCheckout(config.skuId);
|
|
1344
1338
|
window.location.href = redirectToCheckoutFallback({
|
|
1345
1339
|
skuId: config.skuId,
|
|
1346
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1340
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
1341
|
+
country: config.countryCode
|
|
1347
1342
|
});
|
|
1348
1343
|
}
|
|
1349
1344
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1522,8 +1517,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1522
1517
|
};
|
|
1523
1518
|
|
|
1524
1519
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1525
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1526
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1527
1520
|
var failApplePaySession = (session, errors = []) => {
|
|
1528
1521
|
session.completePayment({
|
|
1529
1522
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1553,42 +1546,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1553
1546
|
}
|
|
1554
1547
|
return void 0;
|
|
1555
1548
|
}
|
|
1556
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
1549
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
1557
1550
|
writeCheckoutRedirect(returnUrl);
|
|
1558
1551
|
trackFallbackCheckout(skuId);
|
|
1559
1552
|
window.location.href = redirectToCheckoutFallback({
|
|
1560
1553
|
skuId,
|
|
1554
|
+
country,
|
|
1561
1555
|
...options
|
|
1562
1556
|
});
|
|
1563
1557
|
}
|
|
1564
1558
|
var ERROR_HANDLERS = {
|
|
1565
|
-
|
|
1566
|
-
|
|
1559
|
+
// emailError flows as an inline field error on the email input.
|
|
1560
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
1561
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1562
|
+
emailError: walletError.message,
|
|
1567
1563
|
email: validatedEmail
|
|
1568
1564
|
}),
|
|
1569
|
-
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
),
|
|
1573
|
-
|
|
1574
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1575
|
-
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1576
|
-
emailError: MSG_REGISTRATION,
|
|
1565
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1566
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1567
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1568
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1569
|
+
emailError: walletError.message,
|
|
1577
1570
|
email: validatedEmail
|
|
1578
1571
|
}),
|
|
1579
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1580
|
-
RECAPTCHA_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1572
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1573
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
1581
1574
|
};
|
|
1582
1575
|
function handleStructuredError(ctx) {
|
|
1583
1576
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1584
1577
|
if (handler) {
|
|
1585
1578
|
handler(ctx);
|
|
1586
1579
|
} else {
|
|
1587
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1580
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1588
1581
|
}
|
|
1589
1582
|
}
|
|
1590
1583
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1591
|
-
const { skuId, returnUrl, queryString } = config;
|
|
1584
|
+
const { skuId, returnUrl, queryString, country } = config;
|
|
1592
1585
|
let validatedEmail;
|
|
1593
1586
|
try {
|
|
1594
1587
|
validatedEmail = validateContacts(
|
|
@@ -1608,13 +1601,16 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1608
1601
|
});
|
|
1609
1602
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1610
1603
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1604
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1611
1605
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1612
1606
|
writeCheckoutRedirect(returnUrl);
|
|
1613
1607
|
window.location.href = redirectToCheckoutComplete({
|
|
1614
1608
|
basketId: result.basketId,
|
|
1615
1609
|
status: userStatus,
|
|
1616
1610
|
skuId: decodeSku(skuId),
|
|
1617
|
-
queryString
|
|
1611
|
+
queryString,
|
|
1612
|
+
email: successEmail,
|
|
1613
|
+
country
|
|
1618
1614
|
});
|
|
1619
1615
|
} catch (err) {
|
|
1620
1616
|
if (err instanceof ContactValidationError) {
|
|
@@ -1623,17 +1619,13 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1623
1619
|
}
|
|
1624
1620
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1625
1621
|
const walletError = parseWalletApiError(err);
|
|
1626
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: walletError result", {
|
|
1627
|
-
walletError,
|
|
1628
|
-
validatedEmail
|
|
1629
|
-
});
|
|
1630
1622
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1631
1623
|
failApplePaySession(session);
|
|
1632
1624
|
if (!walletError) {
|
|
1633
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1625
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1634
1626
|
return;
|
|
1635
1627
|
}
|
|
1636
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1628
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
1637
1629
|
}
|
|
1638
1630
|
}
|
|
1639
1631
|
|
|
@@ -43,18 +43,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
43
43
|
});
|
|
44
44
|
if (!response.ok) {
|
|
45
45
|
const contentType = response.headers.get("content-type") || "";
|
|
46
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
47
|
-
path,
|
|
48
|
-
status: response.status,
|
|
49
|
-
contentType
|
|
50
|
-
});
|
|
51
46
|
if (contentType.includes("application/json")) {
|
|
52
47
|
const errorBody = await response.json();
|
|
53
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
54
48
|
throw new ApiError(response.status, errorBody);
|
|
55
49
|
}
|
|
56
50
|
const errorText = await response.text();
|
|
57
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
58
51
|
throw new Error(
|
|
59
52
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
60
53
|
);
|
|
@@ -100,6 +93,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
100
93
|
url.searchParams.set("inlineError", params.inlineError);
|
|
101
94
|
if (params.email) url.searchParams.set("email", params.email);
|
|
102
95
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
96
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
103
97
|
return url.pathname + url.search;
|
|
104
98
|
};
|
|
105
99
|
|
|
@@ -192,7 +186,8 @@ function redirectToFallbackCheckout(config) {
|
|
|
192
186
|
trackFallbackCheckout(config.skuId);
|
|
193
187
|
window.location.href = redirectToCheckoutFallback({
|
|
194
188
|
skuId: config.skuId,
|
|
195
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
189
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
190
|
+
country: config.countryCode
|
|
196
191
|
});
|
|
197
192
|
}
|
|
198
193
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -43,18 +43,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
43
43
|
});
|
|
44
44
|
if (!response.ok) {
|
|
45
45
|
const contentType = response.headers.get("content-type") || "";
|
|
46
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
47
|
-
path,
|
|
48
|
-
status: response.status,
|
|
49
|
-
contentType
|
|
50
|
-
});
|
|
51
46
|
if (contentType.includes("application/json")) {
|
|
52
47
|
const errorBody = await response.json();
|
|
53
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
54
48
|
throw new ApiError(response.status, errorBody);
|
|
55
49
|
}
|
|
56
50
|
const errorText = await response.text();
|
|
57
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
58
51
|
throw new Error(
|
|
59
52
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
60
53
|
);
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical user-facing
|
|
2
|
+
* Canonical user-facing strings for the Apple Pay Express Checkout flow.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* These constants cover two categories:
|
|
5
|
+
* 1. Local contact/field validation — fired before any BFF call, no API
|
|
6
|
+
* message is available.
|
|
7
|
+
* 2. Pre-purchase fallbacks — merchant validation failures and unstructured
|
|
8
|
+
* network errors where no BFF WalletApiError is present.
|
|
9
|
+
*
|
|
10
|
+
* Structured BFF errors (EMAIL_COLLISION, PAYMENT_DECLINED, RECAPTCHA_FAILED,
|
|
11
|
+
* etc.) are NOT represented here — their user-facing copy comes directly from
|
|
12
|
+
* walletError.message in the API response, so copy changes on the BFF side
|
|
13
|
+
* take effect without a frontend deploy.
|
|
7
14
|
*/
|
|
8
15
|
/** Shown when a required Apple Pay contact field is absent. */
|
|
9
16
|
export declare const MSG_MISSING_REQUIRED_FIELD = "Missing required field";
|
|
@@ -19,15 +26,5 @@ export declare const MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not
|
|
|
19
26
|
* Matches sma-checkout GENERIC_ERROR_MSG pattern.
|
|
20
27
|
*/
|
|
21
28
|
export declare const MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
22
|
-
/**
|
|
23
|
-
* Shown when a reCAPTCHA security check fails.
|
|
24
|
-
* Matches sma-checkout reference: handlers/create-on-payment-authorized-handler/subscribe.
|
|
25
|
-
*/
|
|
26
|
-
export declare const MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
27
|
-
/**
|
|
28
|
-
* Shown when the BFF returns an EMAIL_COLLISION error (account already exists).
|
|
29
|
-
* Matches sma-checkout L103-104.
|
|
30
|
-
*/
|
|
31
|
-
export declare const MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
32
29
|
/** Internal ContactValidationError message — not shown to the user directly. */
|
|
33
30
|
export declare const MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
@@ -4,16 +4,12 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
4
4
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
5
5
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
6
6
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
7
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
8
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
9
7
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
10
8
|
export {
|
|
11
9
|
MSG_CONTACT_VALIDATION_INTERNAL,
|
|
12
|
-
MSG_EMAIL_COLLISION,
|
|
13
10
|
MSG_EMAIL_TOO_LONG,
|
|
14
11
|
MSG_EMAIL_WRONG_FORMAT,
|
|
15
12
|
MSG_MISSING_REQUIRED_FIELD,
|
|
16
13
|
MSG_PAYMENT_GENERIC_ERROR,
|
|
17
|
-
MSG_RECAPTCHA_VALIDATION_FAILED,
|
|
18
14
|
MSG_UNSUPPORTED_BILLING_COUNTRY
|
|
19
15
|
};
|
|
@@ -43,18 +43,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
43
43
|
});
|
|
44
44
|
if (!response.ok) {
|
|
45
45
|
const contentType = response.headers.get("content-type") || "";
|
|
46
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
47
|
-
path,
|
|
48
|
-
status: response.status,
|
|
49
|
-
contentType
|
|
50
|
-
});
|
|
51
46
|
if (contentType.includes("application/json")) {
|
|
52
47
|
const errorBody = await response.json();
|
|
53
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
54
48
|
throw new ApiError(response.status, errorBody);
|
|
55
49
|
}
|
|
56
50
|
const errorText = await response.text();
|
|
57
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
58
51
|
throw new Error(
|
|
59
52
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
60
53
|
);
|
|
@@ -125,8 +118,6 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
125
118
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
126
119
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
127
120
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
128
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
129
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
130
121
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
131
122
|
|
|
132
123
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -279,6 +270,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
279
270
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
280
271
|
url.searchParams.set("status", params.status);
|
|
281
272
|
url.searchParams.set("redirectToCheckout", "true");
|
|
273
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
274
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
282
275
|
return url.pathname + url.search;
|
|
283
276
|
};
|
|
284
277
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -289,12 +282,11 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
289
282
|
url.searchParams.set("inlineError", params.inlineError);
|
|
290
283
|
if (params.email) url.searchParams.set("email", params.email);
|
|
291
284
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
285
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
292
286
|
return url.pathname + url.search;
|
|
293
287
|
};
|
|
294
288
|
|
|
295
289
|
// src/clients/payment-checkout/payment-handler.ts
|
|
296
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
297
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
298
290
|
var failApplePaySession = (session, errors = []) => {
|
|
299
291
|
session.completePayment({
|
|
300
292
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -324,42 +316,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
324
316
|
}
|
|
325
317
|
return void 0;
|
|
326
318
|
}
|
|
327
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
319
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
328
320
|
writeCheckoutRedirect(returnUrl);
|
|
329
321
|
trackFallbackCheckout(skuId);
|
|
330
322
|
window.location.href = redirectToCheckoutFallback({
|
|
331
323
|
skuId,
|
|
324
|
+
country,
|
|
332
325
|
...options
|
|
333
326
|
});
|
|
334
327
|
}
|
|
335
328
|
var ERROR_HANDLERS = {
|
|
336
|
-
|
|
337
|
-
|
|
329
|
+
// emailError flows as an inline field error on the email input.
|
|
330
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
331
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
332
|
+
emailError: walletError.message,
|
|
338
333
|
email: validatedEmail
|
|
339
334
|
}),
|
|
340
|
-
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
),
|
|
344
|
-
|
|
345
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
346
|
-
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
347
|
-
emailError: MSG_REGISTRATION,
|
|
335
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
336
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
337
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
338
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
339
|
+
emailError: walletError.message,
|
|
348
340
|
email: validatedEmail
|
|
349
341
|
}),
|
|
350
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
351
|
-
RECAPTCHA_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
342
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
343
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
352
344
|
};
|
|
353
345
|
function handleStructuredError(ctx) {
|
|
354
346
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
355
347
|
if (handler) {
|
|
356
348
|
handler(ctx);
|
|
357
349
|
} else {
|
|
358
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
350
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
359
351
|
}
|
|
360
352
|
}
|
|
361
353
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
362
|
-
const { skuId, returnUrl, queryString } = config;
|
|
354
|
+
const { skuId, returnUrl, queryString, country } = config;
|
|
363
355
|
let validatedEmail;
|
|
364
356
|
try {
|
|
365
357
|
validatedEmail = validateContacts(
|
|
@@ -379,13 +371,16 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
379
371
|
});
|
|
380
372
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
381
373
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
374
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
382
375
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
383
376
|
writeCheckoutRedirect(returnUrl);
|
|
384
377
|
window.location.href = redirectToCheckoutComplete({
|
|
385
378
|
basketId: result.basketId,
|
|
386
379
|
status: userStatus,
|
|
387
380
|
skuId: decodeSku(skuId),
|
|
388
|
-
queryString
|
|
381
|
+
queryString,
|
|
382
|
+
email: successEmail,
|
|
383
|
+
country
|
|
389
384
|
});
|
|
390
385
|
} catch (err) {
|
|
391
386
|
if (err instanceof ContactValidationError) {
|
|
@@ -394,17 +389,13 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
394
389
|
}
|
|
395
390
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
396
391
|
const walletError = parseWalletApiError(err);
|
|
397
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: walletError result", {
|
|
398
|
-
walletError,
|
|
399
|
-
validatedEmail
|
|
400
|
-
});
|
|
401
392
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
402
393
|
failApplePaySession(session);
|
|
403
394
|
if (!walletError) {
|
|
404
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
395
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
405
396
|
return;
|
|
406
397
|
}
|
|
407
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
398
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
408
399
|
}
|
|
409
400
|
}
|
|
410
401
|
export {
|
|
@@ -43,18 +43,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
43
43
|
});
|
|
44
44
|
if (!response.ok) {
|
|
45
45
|
const contentType = response.headers.get("content-type") || "";
|
|
46
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
47
|
-
path,
|
|
48
|
-
status: response.status,
|
|
49
|
-
contentType
|
|
50
|
-
});
|
|
51
46
|
if (contentType.includes("application/json")) {
|
|
52
47
|
const errorBody = await response.json();
|
|
53
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
54
48
|
throw new ApiError(response.status, errorBody);
|
|
55
49
|
}
|
|
56
50
|
const errorText = await response.text();
|
|
57
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
58
51
|
throw new Error(
|
|
59
52
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
60
53
|
);
|
package/dist/src/index.js
CHANGED
|
@@ -1156,18 +1156,11 @@ var apiFetch = async (path, options = {}) => {
|
|
|
1156
1156
|
});
|
|
1157
1157
|
if (!response.ok) {
|
|
1158
1158
|
const contentType = response.headers.get("content-type") || "";
|
|
1159
|
-
console.warn("[web-apple-pay] apiFetch: non-2xx response", {
|
|
1160
|
-
path,
|
|
1161
|
-
status: response.status,
|
|
1162
|
-
contentType
|
|
1163
|
-
});
|
|
1164
1159
|
if (contentType.includes("application/json")) {
|
|
1165
1160
|
const errorBody = await response.json();
|
|
1166
|
-
console.warn("[web-apple-pay] apiFetch: parsed JSON error body", { errorBody });
|
|
1167
1161
|
throw new ApiError(response.status, errorBody);
|
|
1168
1162
|
}
|
|
1169
1163
|
const errorText = await response.text();
|
|
1170
|
-
console.warn("[web-apple-pay] apiFetch: non-JSON error body", { errorText });
|
|
1171
1164
|
throw new Error(
|
|
1172
1165
|
`API request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
1173
1166
|
);
|
|
@@ -1245,6 +1238,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
1245
1238
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
1246
1239
|
url.searchParams.set("status", params.status);
|
|
1247
1240
|
url.searchParams.set("redirectToCheckout", "true");
|
|
1241
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
1242
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1248
1243
|
return url.pathname + url.search;
|
|
1249
1244
|
};
|
|
1250
1245
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -1255,6 +1250,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
1255
1250
|
url.searchParams.set("inlineError", params.inlineError);
|
|
1256
1251
|
if (params.email) url.searchParams.set("email", params.email);
|
|
1257
1252
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
1253
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
1258
1254
|
return url.pathname + url.search;
|
|
1259
1255
|
};
|
|
1260
1256
|
|
|
@@ -1338,8 +1334,6 @@ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a
|
|
|
1338
1334
|
var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
|
|
1339
1335
|
var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
|
|
1340
1336
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
1341
|
-
var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
|
|
1342
|
-
var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
|
|
1343
1337
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
1344
1338
|
|
|
1345
1339
|
// src/clients/payment-checkout/apple-session.ts
|
|
@@ -1348,7 +1342,8 @@ function redirectToFallbackCheckout(config) {
|
|
|
1348
1342
|
trackFallbackCheckout(config.skuId);
|
|
1349
1343
|
window.location.href = redirectToCheckoutFallback({
|
|
1350
1344
|
skuId: config.skuId,
|
|
1351
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
1345
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR,
|
|
1346
|
+
country: config.countryCode
|
|
1352
1347
|
});
|
|
1353
1348
|
}
|
|
1354
1349
|
async function handleMerchantValidation(event, session, config) {
|
|
@@ -1527,8 +1522,6 @@ var shippingContactDetails = (shippingContact) => {
|
|
|
1527
1522
|
};
|
|
1528
1523
|
|
|
1529
1524
|
// src/clients/payment-checkout/payment-handler.ts
|
|
1530
|
-
var MSG_ELIGIBILITY = "Something went wrong, please try again";
|
|
1531
|
-
var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
|
|
1532
1525
|
var failApplePaySession = (session, errors = []) => {
|
|
1533
1526
|
session.completePayment({
|
|
1534
1527
|
status: ApplePaySession.STATUS_FAILURE,
|
|
@@ -1558,42 +1551,42 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
|
|
|
1558
1551
|
}
|
|
1559
1552
|
return void 0;
|
|
1560
1553
|
}
|
|
1561
|
-
function redirectFallback(skuId, returnUrl, options) {
|
|
1554
|
+
function redirectFallback(skuId, returnUrl, country, options) {
|
|
1562
1555
|
writeCheckoutRedirect(returnUrl);
|
|
1563
1556
|
trackFallbackCheckout(skuId);
|
|
1564
1557
|
window.location.href = redirectToCheckoutFallback({
|
|
1565
1558
|
skuId,
|
|
1559
|
+
country,
|
|
1566
1560
|
...options
|
|
1567
1561
|
});
|
|
1568
1562
|
}
|
|
1569
1563
|
var ERROR_HANDLERS = {
|
|
1570
|
-
|
|
1571
|
-
|
|
1564
|
+
// emailError flows as an inline field error on the email input.
|
|
1565
|
+
// email pre-populates the input so the user doesn't have to retype it.
|
|
1566
|
+
EMAIL_COLLISION: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1567
|
+
emailError: walletError.message,
|
|
1572
1568
|
email: validatedEmail
|
|
1573
1569
|
}),
|
|
1574
|
-
PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
),
|
|
1578
|
-
|
|
1579
|
-
REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
|
|
1580
|
-
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
|
|
1581
|
-
emailError: MSG_REGISTRATION,
|
|
1570
|
+
PAYMENT_DECLINED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1571
|
+
ELIGIBILITY_REJECTED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1572
|
+
REGISTRATION_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1573
|
+
ACCOUNT_CREATION_FAILED: ({ skuId, returnUrl, country, validatedEmail, walletError }) => redirectFallback(skuId, returnUrl, country, {
|
|
1574
|
+
emailError: walletError.message,
|
|
1582
1575
|
email: validatedEmail
|
|
1583
1576
|
}),
|
|
1584
|
-
VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1585
|
-
RECAPTCHA_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError:
|
|
1577
|
+
VALIDATION_ERROR: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message }),
|
|
1578
|
+
RECAPTCHA_FAILED: ({ skuId, returnUrl, country, walletError }) => redirectFallback(skuId, returnUrl, country, { inlineError: walletError.message })
|
|
1586
1579
|
};
|
|
1587
1580
|
function handleStructuredError(ctx) {
|
|
1588
1581
|
const handler = ERROR_HANDLERS[ctx.walletError.errorType];
|
|
1589
1582
|
if (handler) {
|
|
1590
1583
|
handler(ctx);
|
|
1591
1584
|
} else {
|
|
1592
|
-
redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1585
|
+
redirectFallback(ctx.skuId, ctx.returnUrl, ctx.country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1593
1586
|
}
|
|
1594
1587
|
}
|
|
1595
1588
|
async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
1596
|
-
const { skuId, returnUrl, queryString } = config;
|
|
1589
|
+
const { skuId, returnUrl, queryString, country } = config;
|
|
1597
1590
|
let validatedEmail;
|
|
1598
1591
|
try {
|
|
1599
1592
|
validatedEmail = validateContacts(
|
|
@@ -1613,13 +1606,16 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1613
1606
|
});
|
|
1614
1607
|
trackWalletPaymentSuccess(skuId, result.basketId);
|
|
1615
1608
|
session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
|
|
1609
|
+
const successEmail = sessionData.loggedIn ? sessionData.emailAddress : validatedEmail;
|
|
1616
1610
|
const userStatus = sessionData.loggedIn ? "lex" : "nex";
|
|
1617
1611
|
writeCheckoutRedirect(returnUrl);
|
|
1618
1612
|
window.location.href = redirectToCheckoutComplete({
|
|
1619
1613
|
basketId: result.basketId,
|
|
1620
1614
|
status: userStatus,
|
|
1621
1615
|
skuId: decodeSku(skuId),
|
|
1622
|
-
queryString
|
|
1616
|
+
queryString,
|
|
1617
|
+
email: successEmail,
|
|
1618
|
+
country
|
|
1623
1619
|
});
|
|
1624
1620
|
} catch (err) {
|
|
1625
1621
|
if (err instanceof ContactValidationError) {
|
|
@@ -1628,17 +1624,13 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
|
|
|
1628
1624
|
}
|
|
1629
1625
|
console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
|
|
1630
1626
|
const walletError = parseWalletApiError(err);
|
|
1631
|
-
console.warn("[web-apple-pay] handlePaymentAuthorized: walletError result", {
|
|
1632
|
-
walletError,
|
|
1633
|
-
validatedEmail
|
|
1634
|
-
});
|
|
1635
1627
|
trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
|
|
1636
1628
|
failApplePaySession(session);
|
|
1637
1629
|
if (!walletError) {
|
|
1638
|
-
redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1630
|
+
redirectFallback(skuId, returnUrl, country, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
|
|
1639
1631
|
return;
|
|
1640
1632
|
}
|
|
1641
|
-
handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
|
|
1633
|
+
handleStructuredError({ skuId, returnUrl, country, validatedEmail, walletError });
|
|
1642
1634
|
}
|
|
1643
1635
|
}
|
|
1644
1636
|
|
|
@@ -43,6 +43,14 @@ export declare const decodeSku: (sku: string) => string;
|
|
|
43
43
|
/**
|
|
44
44
|
* Builds the success redirect URL.
|
|
45
45
|
* /checkout/complete?basketId={id}&lmo_offer={sku}&status={userStatus}&redirectToCheckout=true
|
|
46
|
+
* &email={email}&country={country}
|
|
47
|
+
*
|
|
48
|
+
* `email` — the user's email address (from session for lex users, from Apple Pay
|
|
49
|
+
* shipping contact for nex users). Always appended when non-empty so checkout
|
|
50
|
+
* can pre-fill the account field.
|
|
51
|
+
*
|
|
52
|
+
* `country` — the offer country code forwarded from the payment handler config.
|
|
53
|
+
* Always appended when non-empty to preserve geo-context across the redirect.
|
|
46
54
|
*
|
|
47
55
|
* The origin article URL is written to localStorage by the caller via
|
|
48
56
|
* writeCheckoutRedirect() before this redirect fires.
|
|
@@ -52,15 +60,23 @@ export declare const redirectToCheckoutComplete: (params: {
|
|
|
52
60
|
status: "nex" | "lex";
|
|
53
61
|
skuId: string;
|
|
54
62
|
queryString?: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
country?: string;
|
|
55
65
|
}) => string;
|
|
56
66
|
/**
|
|
57
67
|
* Builds the fallback redirect URL for error scenarios.
|
|
58
|
-
* /checkout?lmo_offer={offerPath}&inlineError
|
|
68
|
+
* /checkout?lmo_offer={offerPath}&inlineError=...&email={email}&country={country}
|
|
59
69
|
*
|
|
60
70
|
* The skuId is decoded via decodeSku() before being set as lmo_offer, producing
|
|
61
71
|
* a Limio offer path (e.g. /offers2/UK-UK.DIGITAL.1YAR.X.DISC.30.NYT) as
|
|
62
72
|
* checkout expects. If decoding fails (malformed SKU), the raw skuId is used.
|
|
63
73
|
*
|
|
74
|
+
* `email` — always appended when non-empty so checkout can pre-fill the email
|
|
75
|
+
* field on the fallback page (e.g. for EMAIL_COLLISION flows).
|
|
76
|
+
*
|
|
77
|
+
* `country` — the offer country code, always appended when non-empty to preserve
|
|
78
|
+
* geo-context across the redirect.
|
|
79
|
+
*
|
|
64
80
|
* Builds on top of the current page URL (window.location.href) so that any
|
|
65
81
|
* existing query params (UTM tags, campaign flags) are preserved — matching
|
|
66
82
|
* sma-checkout: src/lib/navigate-to-checkout/index.tsx
|
|
@@ -73,4 +89,5 @@ export declare const redirectToCheckoutFallback: (params: {
|
|
|
73
89
|
inlineError?: string;
|
|
74
90
|
emailError?: string;
|
|
75
91
|
email?: string;
|
|
92
|
+
country?: string;
|
|
76
93
|
}) => string;
|
|
@@ -39,6 +39,8 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
39
39
|
url.searchParams.set("lmo_offer", params.skuId);
|
|
40
40
|
url.searchParams.set("status", params.status);
|
|
41
41
|
url.searchParams.set("redirectToCheckout", "true");
|
|
42
|
+
if (params.email) url.searchParams.set("email", params.email);
|
|
43
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
42
44
|
return url.pathname + url.search;
|
|
43
45
|
};
|
|
44
46
|
var redirectToCheckoutFallback = (params) => {
|
|
@@ -49,6 +51,7 @@ var redirectToCheckoutFallback = (params) => {
|
|
|
49
51
|
url.searchParams.set("inlineError", params.inlineError);
|
|
50
52
|
if (params.email) url.searchParams.set("email", params.email);
|
|
51
53
|
if (params.emailError) url.searchParams.set("emailError", params.emailError);
|
|
54
|
+
if (params.country) url.searchParams.set("country", params.country);
|
|
52
55
|
return url.pathname + url.search;
|
|
53
56
|
};
|
|
54
57
|
export {
|
package/package.json
CHANGED