@economist/web-apple-pay 1.7.0 → 1.7.2
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 +73 -60
- package/dist/src/apple-pay-button.js +73 -60
- package/dist/src/apple-pay-button.stories.js +73 -60
- package/dist/src/apple-pay-modal.js +0 -1
- package/dist/src/apple-pay-modal.stories.js +73 -60
- package/dist/src/clients/payment-checkout/apple-session.js +57 -50
- package/dist/src/clients/payment-checkout/payment-handler.js +1 -1
- package/dist/src/clients/payment-checkout/types.d.ts +6 -4
- package/dist/src/index.js +73 -60
- package/dist/src/utils/expressCheckoutRedirect.d.ts +5 -1
- package/dist/src/utils/expressCheckoutRedirect.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
317
|
const offer = this.#offer;
|
|
318
318
|
const country = this.#country;
|
|
319
319
|
if (!offer) {
|
|
320
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
321
320
|
this.remove();
|
|
322
321
|
return;
|
|
323
322
|
}
|
|
@@ -686,7 +685,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
686
685
|
var redirectToCheckoutFallback = (params) => {
|
|
687
686
|
const url = new URL(window.location.href);
|
|
688
687
|
url.pathname = "/checkout";
|
|
689
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
688
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
690
689
|
if (params.inlineError)
|
|
691
690
|
url.searchParams.set("inlineError", params.inlineError);
|
|
692
691
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -827,6 +826,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
827
826
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
828
827
|
|
|
829
828
|
// src/clients/payment-checkout/apple-session.ts
|
|
829
|
+
function redirectToFallbackCheckout(config) {
|
|
830
|
+
trackFallbackCheckout(config.skuId);
|
|
831
|
+
window.location.href = redirectToCheckoutFallback({
|
|
832
|
+
skuId: config.skuId,
|
|
833
|
+
returnUrl: config.returnUrl,
|
|
834
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
async function handleMerchantValidation(event, session, config) {
|
|
838
|
+
try {
|
|
839
|
+
const validationHost = new URL(event.validationURL).host;
|
|
840
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
841
|
+
session.abort();
|
|
842
|
+
redirectToFallbackCheckout(config);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
846
|
+
const response = await validateAppleMerchant({
|
|
847
|
+
validationURL: event.validationURL,
|
|
848
|
+
recaptchaToken
|
|
849
|
+
});
|
|
850
|
+
if (!response?.merchantSession) {
|
|
851
|
+
session.abort();
|
|
852
|
+
redirectToFallbackCheckout(config);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
856
|
+
} catch {
|
|
857
|
+
session.abort();
|
|
858
|
+
redirectToFallbackCheckout(config);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
830
861
|
function startApplePaySession(config) {
|
|
831
862
|
const paymentRequest = {
|
|
832
863
|
countryCode: config.countryCode,
|
|
@@ -841,55 +872,23 @@ function startApplePaySession(config) {
|
|
|
841
872
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
842
873
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
843
874
|
};
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
recaptchaToken
|
|
862
|
-
});
|
|
863
|
-
if (!response?.merchantSession) {
|
|
864
|
-
trackFallbackCheckout(config.skuId);
|
|
865
|
-
session.abort();
|
|
866
|
-
window.location.href = redirectToCheckoutFallback({
|
|
867
|
-
skuId: config.skuId,
|
|
868
|
-
returnUrl: config.returnUrl,
|
|
869
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
870
|
-
});
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
874
|
-
} catch {
|
|
875
|
-
trackFallbackCheckout(config.skuId);
|
|
876
|
-
session.abort();
|
|
877
|
-
window.location.href = redirectToCheckoutFallback({
|
|
878
|
-
skuId: config.skuId,
|
|
879
|
-
returnUrl: config.returnUrl,
|
|
880
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
};
|
|
884
|
-
session.onpaymentauthorized = (event) => {
|
|
885
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
886
|
-
config.onPaymentAuthorized(event, session);
|
|
887
|
-
};
|
|
888
|
-
session.oncancel = () => {
|
|
889
|
-
config.onCancel?.();
|
|
890
|
-
};
|
|
891
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
892
|
-
session.begin();
|
|
875
|
+
try {
|
|
876
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
877
|
+
session.onvalidatemerchant = async (event) => {
|
|
878
|
+
await handleMerchantValidation(event, session, config);
|
|
879
|
+
};
|
|
880
|
+
session.onpaymentauthorized = (event) => {
|
|
881
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
882
|
+
config.onPaymentAuthorized(event, session);
|
|
883
|
+
};
|
|
884
|
+
session.oncancel = () => {
|
|
885
|
+
config.onCancel?.();
|
|
886
|
+
};
|
|
887
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
888
|
+
session.begin();
|
|
889
|
+
} catch {
|
|
890
|
+
redirectToFallbackCheckout(config);
|
|
891
|
+
}
|
|
893
892
|
}
|
|
894
893
|
|
|
895
894
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1390,11 +1389,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1390
1389
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1391
1390
|
*/
|
|
1392
1391
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1393
|
-
if (!offer)
|
|
1394
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1392
|
+
if (!offer) {
|
|
1395
1393
|
return null;
|
|
1396
|
-
|
|
1394
|
+
}
|
|
1395
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1397
1399
|
return null;
|
|
1400
|
+
}
|
|
1398
1401
|
_ApplePayButton.define();
|
|
1399
1402
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1400
1403
|
button.offer = offer;
|
|
@@ -1421,6 +1424,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1421
1424
|
#returnUrl = "";
|
|
1422
1425
|
#supportedBillingCountries = [];
|
|
1423
1426
|
#entryPoint = "";
|
|
1427
|
+
#recaptchaTokens = null;
|
|
1424
1428
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1425
1429
|
get offer() {
|
|
1426
1430
|
return this.#offer;
|
|
@@ -1556,7 +1560,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1556
1560
|
*/
|
|
1557
1561
|
async #fetchAndCacheOptions() {
|
|
1558
1562
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1559
|
-
if (!this.#paymentOptions?.apple_pay) {
|
|
1563
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1560
1564
|
this.style.display = "none";
|
|
1561
1565
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1562
1566
|
return true;
|
|
@@ -1579,10 +1583,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1579
1583
|
if (button.classList.contains("wap-loading")) return;
|
|
1580
1584
|
this.#openModal();
|
|
1581
1585
|
});
|
|
1582
|
-
|
|
1586
|
+
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1583
1587
|
const { skuId, country } = event.detail;
|
|
1584
1588
|
this.#initiateApplePay(skuId, country);
|
|
1585
|
-
});
|
|
1589
|
+
}, { once: true });
|
|
1586
1590
|
}
|
|
1587
1591
|
#finishLoading() {
|
|
1588
1592
|
const button = this.querySelector(SEL_BUTTON);
|
|
@@ -1609,8 +1613,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1609
1613
|
button.setAttribute("aria-disabled", "true");
|
|
1610
1614
|
}
|
|
1611
1615
|
#openModal() {
|
|
1612
|
-
if (!this.#offer
|
|
1616
|
+
if (!this.#offer) {
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
if (document.querySelector(ApplePayModal.tag)) {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1613
1622
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1623
|
+
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1624
|
+
this.#recaptchaTokens = tokens;
|
|
1625
|
+
}).catch(() => {
|
|
1626
|
+
});
|
|
1614
1627
|
ApplePayModal.define();
|
|
1615
1628
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1616
1629
|
modal.offer = this.#offer;
|
|
@@ -1645,7 +1658,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1645
1658
|
return {
|
|
1646
1659
|
countryCode: country,
|
|
1647
1660
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1648
|
-
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1661
|
+
supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
|
|
1649
1662
|
totalAmount,
|
|
1650
1663
|
totalLabel: TOTAL_LABEL,
|
|
1651
1664
|
skuId,
|
|
@@ -1665,7 +1678,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1665
1678
|
try {
|
|
1666
1679
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1667
1680
|
const paymentOptions = this.#paymentOptions;
|
|
1668
|
-
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1681
|
+
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1669
1682
|
startApplePaySession(
|
|
1670
1683
|
this.#buildSessionParams(
|
|
1671
1684
|
skuId,
|
|
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
317
|
const offer = this.#offer;
|
|
318
318
|
const country = this.#country;
|
|
319
319
|
if (!offer) {
|
|
320
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
321
320
|
this.remove();
|
|
322
321
|
return;
|
|
323
322
|
}
|
|
@@ -681,7 +680,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
681
680
|
var redirectToCheckoutFallback = (params) => {
|
|
682
681
|
const url = new URL(window.location.href);
|
|
683
682
|
url.pathname = "/checkout";
|
|
684
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
683
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
685
684
|
if (params.inlineError)
|
|
686
685
|
url.searchParams.set("inlineError", params.inlineError);
|
|
687
686
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -822,6 +821,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
822
821
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
823
822
|
|
|
824
823
|
// src/clients/payment-checkout/apple-session.ts
|
|
824
|
+
function redirectToFallbackCheckout(config) {
|
|
825
|
+
trackFallbackCheckout(config.skuId);
|
|
826
|
+
window.location.href = redirectToCheckoutFallback({
|
|
827
|
+
skuId: config.skuId,
|
|
828
|
+
returnUrl: config.returnUrl,
|
|
829
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
async function handleMerchantValidation(event, session, config) {
|
|
833
|
+
try {
|
|
834
|
+
const validationHost = new URL(event.validationURL).host;
|
|
835
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
836
|
+
session.abort();
|
|
837
|
+
redirectToFallbackCheckout(config);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
841
|
+
const response = await validateAppleMerchant({
|
|
842
|
+
validationURL: event.validationURL,
|
|
843
|
+
recaptchaToken
|
|
844
|
+
});
|
|
845
|
+
if (!response?.merchantSession) {
|
|
846
|
+
session.abort();
|
|
847
|
+
redirectToFallbackCheckout(config);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
851
|
+
} catch {
|
|
852
|
+
session.abort();
|
|
853
|
+
redirectToFallbackCheckout(config);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
825
856
|
function startApplePaySession(config) {
|
|
826
857
|
const paymentRequest = {
|
|
827
858
|
countryCode: config.countryCode,
|
|
@@ -836,55 +867,23 @@ function startApplePaySession(config) {
|
|
|
836
867
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
837
868
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
838
869
|
};
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
recaptchaToken
|
|
857
|
-
});
|
|
858
|
-
if (!response?.merchantSession) {
|
|
859
|
-
trackFallbackCheckout(config.skuId);
|
|
860
|
-
session.abort();
|
|
861
|
-
window.location.href = redirectToCheckoutFallback({
|
|
862
|
-
skuId: config.skuId,
|
|
863
|
-
returnUrl: config.returnUrl,
|
|
864
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
865
|
-
});
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
869
|
-
} catch {
|
|
870
|
-
trackFallbackCheckout(config.skuId);
|
|
871
|
-
session.abort();
|
|
872
|
-
window.location.href = redirectToCheckoutFallback({
|
|
873
|
-
skuId: config.skuId,
|
|
874
|
-
returnUrl: config.returnUrl,
|
|
875
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
session.onpaymentauthorized = (event) => {
|
|
880
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
881
|
-
config.onPaymentAuthorized(event, session);
|
|
882
|
-
};
|
|
883
|
-
session.oncancel = () => {
|
|
884
|
-
config.onCancel?.();
|
|
885
|
-
};
|
|
886
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
887
|
-
session.begin();
|
|
870
|
+
try {
|
|
871
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
872
|
+
session.onvalidatemerchant = async (event) => {
|
|
873
|
+
await handleMerchantValidation(event, session, config);
|
|
874
|
+
};
|
|
875
|
+
session.onpaymentauthorized = (event) => {
|
|
876
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
877
|
+
config.onPaymentAuthorized(event, session);
|
|
878
|
+
};
|
|
879
|
+
session.oncancel = () => {
|
|
880
|
+
config.onCancel?.();
|
|
881
|
+
};
|
|
882
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
883
|
+
session.begin();
|
|
884
|
+
} catch {
|
|
885
|
+
redirectToFallbackCheckout(config);
|
|
886
|
+
}
|
|
888
887
|
}
|
|
889
888
|
|
|
890
889
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1385,11 +1384,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1385
1384
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1386
1385
|
*/
|
|
1387
1386
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1388
|
-
if (!offer)
|
|
1389
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1387
|
+
if (!offer) {
|
|
1390
1388
|
return null;
|
|
1391
|
-
|
|
1389
|
+
}
|
|
1390
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1392
1394
|
return null;
|
|
1395
|
+
}
|
|
1393
1396
|
_ApplePayButton.define();
|
|
1394
1397
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1395
1398
|
button.offer = offer;
|
|
@@ -1416,6 +1419,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1416
1419
|
#returnUrl = "";
|
|
1417
1420
|
#supportedBillingCountries = [];
|
|
1418
1421
|
#entryPoint = "";
|
|
1422
|
+
#recaptchaTokens = null;
|
|
1419
1423
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1420
1424
|
get offer() {
|
|
1421
1425
|
return this.#offer;
|
|
@@ -1551,7 +1555,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1551
1555
|
*/
|
|
1552
1556
|
async #fetchAndCacheOptions() {
|
|
1553
1557
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1554
|
-
if (!this.#paymentOptions?.apple_pay) {
|
|
1558
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1555
1559
|
this.style.display = "none";
|
|
1556
1560
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1557
1561
|
return true;
|
|
@@ -1574,10 +1578,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1574
1578
|
if (button.classList.contains("wap-loading")) return;
|
|
1575
1579
|
this.#openModal();
|
|
1576
1580
|
});
|
|
1577
|
-
|
|
1581
|
+
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1578
1582
|
const { skuId, country } = event.detail;
|
|
1579
1583
|
this.#initiateApplePay(skuId, country);
|
|
1580
|
-
});
|
|
1584
|
+
}, { once: true });
|
|
1581
1585
|
}
|
|
1582
1586
|
#finishLoading() {
|
|
1583
1587
|
const button = this.querySelector(SEL_BUTTON);
|
|
@@ -1604,8 +1608,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1604
1608
|
button.setAttribute("aria-disabled", "true");
|
|
1605
1609
|
}
|
|
1606
1610
|
#openModal() {
|
|
1607
|
-
if (!this.#offer
|
|
1611
|
+
if (!this.#offer) {
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
if (document.querySelector(ApplePayModal.tag)) {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1608
1617
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1618
|
+
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1619
|
+
this.#recaptchaTokens = tokens;
|
|
1620
|
+
}).catch(() => {
|
|
1621
|
+
});
|
|
1609
1622
|
ApplePayModal.define();
|
|
1610
1623
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1611
1624
|
modal.offer = this.#offer;
|
|
@@ -1640,7 +1653,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1640
1653
|
return {
|
|
1641
1654
|
countryCode: country,
|
|
1642
1655
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1643
|
-
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1656
|
+
supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
|
|
1644
1657
|
totalAmount,
|
|
1645
1658
|
totalLabel: TOTAL_LABEL,
|
|
1646
1659
|
skuId,
|
|
@@ -1660,7 +1673,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1660
1673
|
try {
|
|
1661
1674
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1662
1675
|
const paymentOptions = this.#paymentOptions;
|
|
1663
|
-
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1676
|
+
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1664
1677
|
startApplePaySession(
|
|
1665
1678
|
this.#buildSessionParams(
|
|
1666
1679
|
skuId,
|
|
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
317
|
const offer = this.#offer;
|
|
318
318
|
const country = this.#country;
|
|
319
319
|
if (!offer) {
|
|
320
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
321
320
|
this.remove();
|
|
322
321
|
return;
|
|
323
322
|
}
|
|
@@ -689,7 +688,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
689
688
|
var redirectToCheckoutFallback = (params) => {
|
|
690
689
|
const url = new URL(window.location.href);
|
|
691
690
|
url.pathname = "/checkout";
|
|
692
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
691
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
693
692
|
if (params.inlineError)
|
|
694
693
|
url.searchParams.set("inlineError", params.inlineError);
|
|
695
694
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -830,6 +829,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
830
829
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
831
830
|
|
|
832
831
|
// src/clients/payment-checkout/apple-session.ts
|
|
832
|
+
function redirectToFallbackCheckout(config) {
|
|
833
|
+
trackFallbackCheckout(config.skuId);
|
|
834
|
+
window.location.href = redirectToCheckoutFallback({
|
|
835
|
+
skuId: config.skuId,
|
|
836
|
+
returnUrl: config.returnUrl,
|
|
837
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
async function handleMerchantValidation(event, session, config) {
|
|
841
|
+
try {
|
|
842
|
+
const validationHost = new URL(event.validationURL).host;
|
|
843
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
844
|
+
session.abort();
|
|
845
|
+
redirectToFallbackCheckout(config);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
849
|
+
const response = await validateAppleMerchant({
|
|
850
|
+
validationURL: event.validationURL,
|
|
851
|
+
recaptchaToken
|
|
852
|
+
});
|
|
853
|
+
if (!response?.merchantSession) {
|
|
854
|
+
session.abort();
|
|
855
|
+
redirectToFallbackCheckout(config);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
859
|
+
} catch {
|
|
860
|
+
session.abort();
|
|
861
|
+
redirectToFallbackCheckout(config);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
833
864
|
function startApplePaySession(config) {
|
|
834
865
|
const paymentRequest = {
|
|
835
866
|
countryCode: config.countryCode,
|
|
@@ -844,55 +875,23 @@ function startApplePaySession(config) {
|
|
|
844
875
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
845
876
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
846
877
|
};
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
recaptchaToken
|
|
865
|
-
});
|
|
866
|
-
if (!response?.merchantSession) {
|
|
867
|
-
trackFallbackCheckout(config.skuId);
|
|
868
|
-
session.abort();
|
|
869
|
-
window.location.href = redirectToCheckoutFallback({
|
|
870
|
-
skuId: config.skuId,
|
|
871
|
-
returnUrl: config.returnUrl,
|
|
872
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
873
|
-
});
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
877
|
-
} catch {
|
|
878
|
-
trackFallbackCheckout(config.skuId);
|
|
879
|
-
session.abort();
|
|
880
|
-
window.location.href = redirectToCheckoutFallback({
|
|
881
|
-
skuId: config.skuId,
|
|
882
|
-
returnUrl: config.returnUrl,
|
|
883
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
884
|
-
});
|
|
885
|
-
}
|
|
886
|
-
};
|
|
887
|
-
session.onpaymentauthorized = (event) => {
|
|
888
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
889
|
-
config.onPaymentAuthorized(event, session);
|
|
890
|
-
};
|
|
891
|
-
session.oncancel = () => {
|
|
892
|
-
config.onCancel?.();
|
|
893
|
-
};
|
|
894
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
895
|
-
session.begin();
|
|
878
|
+
try {
|
|
879
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
880
|
+
session.onvalidatemerchant = async (event) => {
|
|
881
|
+
await handleMerchantValidation(event, session, config);
|
|
882
|
+
};
|
|
883
|
+
session.onpaymentauthorized = (event) => {
|
|
884
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
885
|
+
config.onPaymentAuthorized(event, session);
|
|
886
|
+
};
|
|
887
|
+
session.oncancel = () => {
|
|
888
|
+
config.onCancel?.();
|
|
889
|
+
};
|
|
890
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
891
|
+
session.begin();
|
|
892
|
+
} catch {
|
|
893
|
+
redirectToFallbackCheckout(config);
|
|
894
|
+
}
|
|
896
895
|
}
|
|
897
896
|
|
|
898
897
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1393,11 +1392,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1393
1392
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1394
1393
|
*/
|
|
1395
1394
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1396
|
-
if (!offer)
|
|
1397
|
-
|
|
1395
|
+
if (!offer) {
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1398
1399
|
return null;
|
|
1399
|
-
|
|
1400
|
+
}
|
|
1401
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1400
1402
|
return null;
|
|
1403
|
+
}
|
|
1401
1404
|
_ApplePayButton.define();
|
|
1402
1405
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1403
1406
|
button.offer = offer;
|
|
@@ -1424,6 +1427,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1424
1427
|
#returnUrl = "";
|
|
1425
1428
|
#supportedBillingCountries = [];
|
|
1426
1429
|
#entryPoint = "";
|
|
1430
|
+
#recaptchaTokens = null;
|
|
1427
1431
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1428
1432
|
get offer() {
|
|
1429
1433
|
return this.#offer;
|
|
@@ -1559,7 +1563,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1559
1563
|
*/
|
|
1560
1564
|
async #fetchAndCacheOptions() {
|
|
1561
1565
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1562
|
-
if (!this.#paymentOptions?.apple_pay) {
|
|
1566
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1563
1567
|
this.style.display = "none";
|
|
1564
1568
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1565
1569
|
return true;
|
|
@@ -1582,10 +1586,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1582
1586
|
if (button.classList.contains("wap-loading")) return;
|
|
1583
1587
|
this.#openModal();
|
|
1584
1588
|
});
|
|
1585
|
-
|
|
1589
|
+
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1586
1590
|
const { skuId, country } = event.detail;
|
|
1587
1591
|
this.#initiateApplePay(skuId, country);
|
|
1588
|
-
});
|
|
1592
|
+
}, { once: true });
|
|
1589
1593
|
}
|
|
1590
1594
|
#finishLoading() {
|
|
1591
1595
|
const button = this.querySelector(SEL_BUTTON);
|
|
@@ -1612,8 +1616,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1612
1616
|
button.setAttribute("aria-disabled", "true");
|
|
1613
1617
|
}
|
|
1614
1618
|
#openModal() {
|
|
1615
|
-
if (!this.#offer
|
|
1619
|
+
if (!this.#offer) {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
if (document.querySelector(ApplePayModal.tag)) {
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1616
1625
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1626
|
+
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1627
|
+
this.#recaptchaTokens = tokens;
|
|
1628
|
+
}).catch(() => {
|
|
1629
|
+
});
|
|
1617
1630
|
ApplePayModal.define();
|
|
1618
1631
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1619
1632
|
modal.offer = this.#offer;
|
|
@@ -1648,7 +1661,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1648
1661
|
return {
|
|
1649
1662
|
countryCode: country,
|
|
1650
1663
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1651
|
-
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1664
|
+
supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
|
|
1652
1665
|
totalAmount,
|
|
1653
1666
|
totalLabel: TOTAL_LABEL,
|
|
1654
1667
|
skuId,
|
|
@@ -1668,7 +1681,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1668
1681
|
try {
|
|
1669
1682
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1670
1683
|
const paymentOptions = this.#paymentOptions;
|
|
1671
|
-
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1684
|
+
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1672
1685
|
startApplePaySession(
|
|
1673
1686
|
this.#buildSessionParams(
|
|
1674
1687
|
skuId,
|
|
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
317
|
const offer = this.#offer;
|
|
318
318
|
const country = this.#country;
|
|
319
319
|
if (!offer) {
|
|
320
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
321
320
|
this.remove();
|
|
322
321
|
return;
|
|
323
322
|
}
|
|
@@ -681,7 +680,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
681
680
|
var redirectToCheckoutFallback = (params) => {
|
|
682
681
|
const url = new URL(window.location.href);
|
|
683
682
|
url.pathname = "/checkout";
|
|
684
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
683
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
685
684
|
if (params.inlineError)
|
|
686
685
|
url.searchParams.set("inlineError", params.inlineError);
|
|
687
686
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -822,6 +821,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
822
821
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
823
822
|
|
|
824
823
|
// src/clients/payment-checkout/apple-session.ts
|
|
824
|
+
function redirectToFallbackCheckout(config) {
|
|
825
|
+
trackFallbackCheckout(config.skuId);
|
|
826
|
+
window.location.href = redirectToCheckoutFallback({
|
|
827
|
+
skuId: config.skuId,
|
|
828
|
+
returnUrl: config.returnUrl,
|
|
829
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
async function handleMerchantValidation(event, session, config) {
|
|
833
|
+
try {
|
|
834
|
+
const validationHost = new URL(event.validationURL).host;
|
|
835
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
836
|
+
session.abort();
|
|
837
|
+
redirectToFallbackCheckout(config);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
841
|
+
const response = await validateAppleMerchant({
|
|
842
|
+
validationURL: event.validationURL,
|
|
843
|
+
recaptchaToken
|
|
844
|
+
});
|
|
845
|
+
if (!response?.merchantSession) {
|
|
846
|
+
session.abort();
|
|
847
|
+
redirectToFallbackCheckout(config);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
851
|
+
} catch {
|
|
852
|
+
session.abort();
|
|
853
|
+
redirectToFallbackCheckout(config);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
825
856
|
function startApplePaySession(config) {
|
|
826
857
|
const paymentRequest = {
|
|
827
858
|
countryCode: config.countryCode,
|
|
@@ -836,55 +867,23 @@ function startApplePaySession(config) {
|
|
|
836
867
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
837
868
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
838
869
|
};
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
recaptchaToken
|
|
857
|
-
});
|
|
858
|
-
if (!response?.merchantSession) {
|
|
859
|
-
trackFallbackCheckout(config.skuId);
|
|
860
|
-
session.abort();
|
|
861
|
-
window.location.href = redirectToCheckoutFallback({
|
|
862
|
-
skuId: config.skuId,
|
|
863
|
-
returnUrl: config.returnUrl,
|
|
864
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
865
|
-
});
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
869
|
-
} catch {
|
|
870
|
-
trackFallbackCheckout(config.skuId);
|
|
871
|
-
session.abort();
|
|
872
|
-
window.location.href = redirectToCheckoutFallback({
|
|
873
|
-
skuId: config.skuId,
|
|
874
|
-
returnUrl: config.returnUrl,
|
|
875
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
session.onpaymentauthorized = (event) => {
|
|
880
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
881
|
-
config.onPaymentAuthorized(event, session);
|
|
882
|
-
};
|
|
883
|
-
session.oncancel = () => {
|
|
884
|
-
config.onCancel?.();
|
|
885
|
-
};
|
|
886
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
887
|
-
session.begin();
|
|
870
|
+
try {
|
|
871
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
872
|
+
session.onvalidatemerchant = async (event) => {
|
|
873
|
+
await handleMerchantValidation(event, session, config);
|
|
874
|
+
};
|
|
875
|
+
session.onpaymentauthorized = (event) => {
|
|
876
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
877
|
+
config.onPaymentAuthorized(event, session);
|
|
878
|
+
};
|
|
879
|
+
session.oncancel = () => {
|
|
880
|
+
config.onCancel?.();
|
|
881
|
+
};
|
|
882
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
883
|
+
session.begin();
|
|
884
|
+
} catch {
|
|
885
|
+
redirectToFallbackCheckout(config);
|
|
886
|
+
}
|
|
888
887
|
}
|
|
889
888
|
|
|
890
889
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1385,11 +1384,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1385
1384
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1386
1385
|
*/
|
|
1387
1386
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1388
|
-
if (!offer)
|
|
1389
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1387
|
+
if (!offer) {
|
|
1390
1388
|
return null;
|
|
1391
|
-
|
|
1389
|
+
}
|
|
1390
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1392
1394
|
return null;
|
|
1395
|
+
}
|
|
1393
1396
|
_ApplePayButton.define();
|
|
1394
1397
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1395
1398
|
button.offer = offer;
|
|
@@ -1416,6 +1419,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1416
1419
|
#returnUrl = "";
|
|
1417
1420
|
#supportedBillingCountries = [];
|
|
1418
1421
|
#entryPoint = "";
|
|
1422
|
+
#recaptchaTokens = null;
|
|
1419
1423
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1420
1424
|
get offer() {
|
|
1421
1425
|
return this.#offer;
|
|
@@ -1551,7 +1555,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1551
1555
|
*/
|
|
1552
1556
|
async #fetchAndCacheOptions() {
|
|
1553
1557
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1554
|
-
if (!this.#paymentOptions?.apple_pay) {
|
|
1558
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1555
1559
|
this.style.display = "none";
|
|
1556
1560
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1557
1561
|
return true;
|
|
@@ -1574,10 +1578,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1574
1578
|
if (button.classList.contains("wap-loading")) return;
|
|
1575
1579
|
this.#openModal();
|
|
1576
1580
|
});
|
|
1577
|
-
|
|
1581
|
+
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1578
1582
|
const { skuId, country } = event.detail;
|
|
1579
1583
|
this.#initiateApplePay(skuId, country);
|
|
1580
|
-
});
|
|
1584
|
+
}, { once: true });
|
|
1581
1585
|
}
|
|
1582
1586
|
#finishLoading() {
|
|
1583
1587
|
const button = this.querySelector(SEL_BUTTON);
|
|
@@ -1604,8 +1608,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1604
1608
|
button.setAttribute("aria-disabled", "true");
|
|
1605
1609
|
}
|
|
1606
1610
|
#openModal() {
|
|
1607
|
-
if (!this.#offer
|
|
1611
|
+
if (!this.#offer) {
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
if (document.querySelector(ApplePayModal.tag)) {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1608
1617
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1618
|
+
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1619
|
+
this.#recaptchaTokens = tokens;
|
|
1620
|
+
}).catch(() => {
|
|
1621
|
+
});
|
|
1609
1622
|
ApplePayModal.define();
|
|
1610
1623
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1611
1624
|
modal.offer = this.#offer;
|
|
@@ -1640,7 +1653,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1640
1653
|
return {
|
|
1641
1654
|
countryCode: country,
|
|
1642
1655
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1643
|
-
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1656
|
+
supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
|
|
1644
1657
|
totalAmount,
|
|
1645
1658
|
totalLabel: TOTAL_LABEL,
|
|
1646
1659
|
skuId,
|
|
@@ -1660,7 +1673,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1660
1673
|
try {
|
|
1661
1674
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1662
1675
|
const paymentOptions = this.#paymentOptions;
|
|
1663
|
-
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1676
|
+
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1664
1677
|
startApplePaySession(
|
|
1665
1678
|
this.#buildSessionParams(
|
|
1666
1679
|
skuId,
|
|
@@ -62,10 +62,17 @@ var validateAppleMerchant = (data) => {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
// src/utils/expressCheckoutRedirect.ts
|
|
65
|
+
var decodeSku = (sku) => {
|
|
66
|
+
try {
|
|
67
|
+
return atob(sku.substring(sku.indexOf("-") + 1));
|
|
68
|
+
} catch {
|
|
69
|
+
return sku;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
65
72
|
var redirectToCheckoutFallback = (params) => {
|
|
66
73
|
const url = new URL(window.location.href);
|
|
67
74
|
url.pathname = "/checkout";
|
|
68
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
75
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
69
76
|
if (params.inlineError)
|
|
70
77
|
url.searchParams.set("inlineError", params.inlineError);
|
|
71
78
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -158,6 +165,38 @@ var trackFallbackCheckout = (skuId) => {
|
|
|
158
165
|
var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
|
|
159
166
|
|
|
160
167
|
// src/clients/payment-checkout/apple-session.ts
|
|
168
|
+
function redirectToFallbackCheckout(config) {
|
|
169
|
+
trackFallbackCheckout(config.skuId);
|
|
170
|
+
window.location.href = redirectToCheckoutFallback({
|
|
171
|
+
skuId: config.skuId,
|
|
172
|
+
returnUrl: config.returnUrl,
|
|
173
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
async function handleMerchantValidation(event, session, config) {
|
|
177
|
+
try {
|
|
178
|
+
const validationHost = new URL(event.validationURL).host;
|
|
179
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
180
|
+
session.abort();
|
|
181
|
+
redirectToFallbackCheckout(config);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
185
|
+
const response = await validateAppleMerchant({
|
|
186
|
+
validationURL: event.validationURL,
|
|
187
|
+
recaptchaToken
|
|
188
|
+
});
|
|
189
|
+
if (!response?.merchantSession) {
|
|
190
|
+
session.abort();
|
|
191
|
+
redirectToFallbackCheckout(config);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
195
|
+
} catch {
|
|
196
|
+
session.abort();
|
|
197
|
+
redirectToFallbackCheckout(config);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
161
200
|
function startApplePaySession(config) {
|
|
162
201
|
const paymentRequest = {
|
|
163
202
|
countryCode: config.countryCode,
|
|
@@ -172,55 +211,23 @@ function startApplePaySession(config) {
|
|
|
172
211
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
173
212
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
174
213
|
};
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
recaptchaToken
|
|
193
|
-
});
|
|
194
|
-
if (!response?.merchantSession) {
|
|
195
|
-
trackFallbackCheckout(config.skuId);
|
|
196
|
-
session.abort();
|
|
197
|
-
window.location.href = redirectToCheckoutFallback({
|
|
198
|
-
skuId: config.skuId,
|
|
199
|
-
returnUrl: config.returnUrl,
|
|
200
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
201
|
-
});
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
205
|
-
} catch {
|
|
206
|
-
trackFallbackCheckout(config.skuId);
|
|
207
|
-
session.abort();
|
|
208
|
-
window.location.href = redirectToCheckoutFallback({
|
|
209
|
-
skuId: config.skuId,
|
|
210
|
-
returnUrl: config.returnUrl,
|
|
211
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
session.onpaymentauthorized = (event) => {
|
|
216
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
217
|
-
config.onPaymentAuthorized(event, session);
|
|
218
|
-
};
|
|
219
|
-
session.oncancel = () => {
|
|
220
|
-
config.onCancel?.();
|
|
221
|
-
};
|
|
222
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
223
|
-
session.begin();
|
|
214
|
+
try {
|
|
215
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
216
|
+
session.onvalidatemerchant = async (event) => {
|
|
217
|
+
await handleMerchantValidation(event, session, config);
|
|
218
|
+
};
|
|
219
|
+
session.onpaymentauthorized = (event) => {
|
|
220
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
221
|
+
config.onPaymentAuthorized(event, session);
|
|
222
|
+
};
|
|
223
|
+
session.oncancel = () => {
|
|
224
|
+
config.onCancel?.();
|
|
225
|
+
};
|
|
226
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
227
|
+
session.begin();
|
|
228
|
+
} catch {
|
|
229
|
+
redirectToFallbackCheckout(config);
|
|
230
|
+
}
|
|
224
231
|
}
|
|
225
232
|
export {
|
|
226
233
|
startApplePaySession
|
|
@@ -262,7 +262,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
262
262
|
var redirectToCheckoutFallback = (params) => {
|
|
263
263
|
const url = new URL(window.location.href);
|
|
264
264
|
url.pathname = "/checkout";
|
|
265
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
265
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
266
266
|
if (params.inlineError)
|
|
267
267
|
url.searchParams.set("inlineError", params.inlineError);
|
|
268
268
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -14,10 +14,12 @@ export type PaymentOptionsRequest = {
|
|
|
14
14
|
* Only the apple_pay field is consumed by this package.
|
|
15
15
|
*/
|
|
16
16
|
export type PaymentOptionsResponse = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
options: {
|
|
18
|
+
apple_pay?: {
|
|
19
|
+
provider: string;
|
|
20
|
+
settings: {
|
|
21
|
+
supported_networks: string[];
|
|
22
|
+
};
|
|
21
23
|
};
|
|
22
24
|
};
|
|
23
25
|
};
|
package/dist/src/index.js
CHANGED
|
@@ -317,7 +317,6 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
317
317
|
const offer = this.#offer;
|
|
318
318
|
const country = this.#country;
|
|
319
319
|
if (!offer) {
|
|
320
|
-
console.error("ApplePayModal: Missing or invalid offer data");
|
|
321
320
|
this.remove();
|
|
322
321
|
return;
|
|
323
322
|
}
|
|
@@ -686,7 +685,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
686
685
|
var redirectToCheckoutFallback = (params) => {
|
|
687
686
|
const url = new URL(window.location.href);
|
|
688
687
|
url.pathname = "/checkout";
|
|
689
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
688
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
690
689
|
if (params.inlineError)
|
|
691
690
|
url.searchParams.set("inlineError", params.inlineError);
|
|
692
691
|
if (params.email) url.searchParams.set("email", params.email);
|
|
@@ -827,6 +826,38 @@ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. P
|
|
|
827
826
|
var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
|
|
828
827
|
|
|
829
828
|
// src/clients/payment-checkout/apple-session.ts
|
|
829
|
+
function redirectToFallbackCheckout(config) {
|
|
830
|
+
trackFallbackCheckout(config.skuId);
|
|
831
|
+
window.location.href = redirectToCheckoutFallback({
|
|
832
|
+
skuId: config.skuId,
|
|
833
|
+
returnUrl: config.returnUrl,
|
|
834
|
+
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
async function handleMerchantValidation(event, session, config) {
|
|
838
|
+
try {
|
|
839
|
+
const validationHost = new URL(event.validationURL).host;
|
|
840
|
+
if (!validationHost.endsWith("apple.com")) {
|
|
841
|
+
session.abort();
|
|
842
|
+
redirectToFallbackCheckout(config);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
const recaptchaToken = await getRecaptchaToken("verifyMerchant");
|
|
846
|
+
const response = await validateAppleMerchant({
|
|
847
|
+
validationURL: event.validationURL,
|
|
848
|
+
recaptchaToken
|
|
849
|
+
});
|
|
850
|
+
if (!response?.merchantSession) {
|
|
851
|
+
session.abort();
|
|
852
|
+
redirectToFallbackCheckout(config);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
session.completeMerchantValidation(response.merchantSession);
|
|
856
|
+
} catch {
|
|
857
|
+
session.abort();
|
|
858
|
+
redirectToFallbackCheckout(config);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
830
861
|
function startApplePaySession(config) {
|
|
831
862
|
const paymentRequest = {
|
|
832
863
|
countryCode: config.countryCode,
|
|
@@ -841,55 +872,23 @@ function startApplePaySession(config) {
|
|
|
841
872
|
// Only request email from Apple Pay sheet if user is NOT logged in
|
|
842
873
|
...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
|
|
843
874
|
};
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
recaptchaToken
|
|
862
|
-
});
|
|
863
|
-
if (!response?.merchantSession) {
|
|
864
|
-
trackFallbackCheckout(config.skuId);
|
|
865
|
-
session.abort();
|
|
866
|
-
window.location.href = redirectToCheckoutFallback({
|
|
867
|
-
skuId: config.skuId,
|
|
868
|
-
returnUrl: config.returnUrl,
|
|
869
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
870
|
-
});
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
session.completeMerchantValidation(response.merchantSession);
|
|
874
|
-
} catch {
|
|
875
|
-
trackFallbackCheckout(config.skuId);
|
|
876
|
-
session.abort();
|
|
877
|
-
window.location.href = redirectToCheckoutFallback({
|
|
878
|
-
skuId: config.skuId,
|
|
879
|
-
returnUrl: config.returnUrl,
|
|
880
|
-
inlineError: MSG_PAYMENT_GENERIC_ERROR
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
};
|
|
884
|
-
session.onpaymentauthorized = (event) => {
|
|
885
|
-
trackWalletPaymentAuthorised(config.skuId);
|
|
886
|
-
config.onPaymentAuthorized(event, session);
|
|
887
|
-
};
|
|
888
|
-
session.oncancel = () => {
|
|
889
|
-
config.onCancel?.();
|
|
890
|
-
};
|
|
891
|
-
trackWalletPaymentSheetOpen(config.skuId);
|
|
892
|
-
session.begin();
|
|
875
|
+
try {
|
|
876
|
+
const session = new ApplePaySession(3, paymentRequest);
|
|
877
|
+
session.onvalidatemerchant = async (event) => {
|
|
878
|
+
await handleMerchantValidation(event, session, config);
|
|
879
|
+
};
|
|
880
|
+
session.onpaymentauthorized = (event) => {
|
|
881
|
+
trackWalletPaymentAuthorised(config.skuId);
|
|
882
|
+
config.onPaymentAuthorized(event, session);
|
|
883
|
+
};
|
|
884
|
+
session.oncancel = () => {
|
|
885
|
+
config.onCancel?.();
|
|
886
|
+
};
|
|
887
|
+
trackWalletPaymentSheetOpen(config.skuId);
|
|
888
|
+
session.begin();
|
|
889
|
+
} catch {
|
|
890
|
+
redirectToFallbackCheckout(config);
|
|
891
|
+
}
|
|
893
892
|
}
|
|
894
893
|
|
|
895
894
|
// src/clients/payment-checkout/contact-validation.ts
|
|
@@ -1390,11 +1389,15 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1390
1389
|
* Creates and configures an ApplePayButton if the feature flag is present.
|
|
1391
1390
|
*/
|
|
1392
1391
|
static createIfEnabled(offer, country, entryPoint) {
|
|
1393
|
-
if (!offer)
|
|
1394
|
-
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
|
|
1392
|
+
if (!offer) {
|
|
1395
1393
|
return null;
|
|
1396
|
-
|
|
1394
|
+
}
|
|
1395
|
+
if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant)) {
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT)) {
|
|
1397
1399
|
return null;
|
|
1400
|
+
}
|
|
1398
1401
|
_ApplePayButton.define();
|
|
1399
1402
|
const button = document.createElement(_ApplePayButton.tag);
|
|
1400
1403
|
button.offer = offer;
|
|
@@ -1421,6 +1424,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1421
1424
|
#returnUrl = "";
|
|
1422
1425
|
#supportedBillingCountries = [];
|
|
1423
1426
|
#entryPoint = "";
|
|
1427
|
+
#recaptchaTokens = null;
|
|
1424
1428
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1425
1429
|
get offer() {
|
|
1426
1430
|
return this.#offer;
|
|
@@ -1556,7 +1560,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1556
1560
|
*/
|
|
1557
1561
|
async #fetchAndCacheOptions() {
|
|
1558
1562
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
1559
|
-
if (!this.#paymentOptions?.apple_pay) {
|
|
1563
|
+
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
1560
1564
|
this.style.display = "none";
|
|
1561
1565
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
1562
1566
|
return true;
|
|
@@ -1579,10 +1583,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1579
1583
|
if (button.classList.contains("wap-loading")) return;
|
|
1580
1584
|
this.#openModal();
|
|
1581
1585
|
});
|
|
1582
|
-
|
|
1586
|
+
document.addEventListener("apple-pay-confirmed", (event) => {
|
|
1583
1587
|
const { skuId, country } = event.detail;
|
|
1584
1588
|
this.#initiateApplePay(skuId, country);
|
|
1585
|
-
});
|
|
1589
|
+
}, { once: true });
|
|
1586
1590
|
}
|
|
1587
1591
|
#finishLoading() {
|
|
1588
1592
|
const button = this.querySelector(SEL_BUTTON);
|
|
@@ -1609,8 +1613,17 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1609
1613
|
button.setAttribute("aria-disabled", "true");
|
|
1610
1614
|
}
|
|
1611
1615
|
#openModal() {
|
|
1612
|
-
if (!this.#offer
|
|
1616
|
+
if (!this.#offer) {
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
if (document.querySelector(ApplePayModal.tag)) {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1613
1622
|
trackExpressWalletClick(this.#offer.sku_id);
|
|
1623
|
+
getPurchaseRecaptchaTokens().then((tokens) => {
|
|
1624
|
+
this.#recaptchaTokens = tokens;
|
|
1625
|
+
}).catch(() => {
|
|
1626
|
+
});
|
|
1614
1627
|
ApplePayModal.define();
|
|
1615
1628
|
const modal = document.createElement(ApplePayModal.tag);
|
|
1616
1629
|
modal.offer = this.#offer;
|
|
@@ -1645,7 +1658,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1645
1658
|
return {
|
|
1646
1659
|
countryCode: country,
|
|
1647
1660
|
currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
1648
|
-
supportedNetworks: paymentOptions.apple_pay.settings.supported_networks,
|
|
1661
|
+
supportedNetworks: paymentOptions.options.apple_pay.settings.supported_networks,
|
|
1649
1662
|
totalAmount,
|
|
1650
1663
|
totalLabel: TOTAL_LABEL,
|
|
1651
1664
|
skuId,
|
|
@@ -1665,7 +1678,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1665
1678
|
try {
|
|
1666
1679
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
1667
1680
|
const paymentOptions = this.#paymentOptions;
|
|
1668
|
-
const recaptchaTokens = await getPurchaseRecaptchaTokens();
|
|
1681
|
+
const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
|
|
1669
1682
|
startApplePaySession(
|
|
1670
1683
|
this.#buildSessionParams(
|
|
1671
1684
|
skuId,
|
|
@@ -40,7 +40,11 @@ export declare const redirectToCheckoutComplete: (params: {
|
|
|
40
40
|
}) => string;
|
|
41
41
|
/**
|
|
42
42
|
* Builds the fallback redirect URL for error scenarios.
|
|
43
|
-
* /checkout?lmo_offer={
|
|
43
|
+
* /checkout?lmo_offer={offerPath}&inlineError=...&returnUrl=...
|
|
44
|
+
*
|
|
45
|
+
* The skuId is decoded via decodeSku() before being set as lmo_offer, producing
|
|
46
|
+
* a Limio offer path (e.g. /offers2/UK-UK.DIGITAL.1YAR.X.DISC.30.NYT) as
|
|
47
|
+
* checkout expects. If decoding fails (malformed SKU), the raw skuId is used.
|
|
44
48
|
*
|
|
45
49
|
* Builds on top of the current page URL (window.location.href) so that any
|
|
46
50
|
* existing query params (UTM tags, campaign flags) are preserved — matching
|
|
@@ -29,7 +29,7 @@ var redirectToCheckoutComplete = (params) => {
|
|
|
29
29
|
var redirectToCheckoutFallback = (params) => {
|
|
30
30
|
const url = new URL(window.location.href);
|
|
31
31
|
url.pathname = "/checkout";
|
|
32
|
-
url.searchParams.set("lmo_offer", params.skuId);
|
|
32
|
+
url.searchParams.set("lmo_offer", decodeSku(params.skuId));
|
|
33
33
|
if (params.inlineError)
|
|
34
34
|
url.searchParams.set("inlineError", params.inlineError);
|
|
35
35
|
if (params.email) url.searchParams.set("email", params.email);
|