@economist/web-apple-pay 1.7.9 → 1.7.10
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 +65 -79
- package/dist/src/apple-pay-button.js +65 -79
- package/dist/src/apple-pay-button.stories.js +65 -79
- package/dist/src/apple-pay-modal.d.ts +9 -14
- package/dist/src/apple-pay-modal.js +36 -44
- package/dist/src/apple-pay-modal.stories.js +65 -79
- package/dist/src/clients/payment-checkout/apple-session.d.ts +1 -0
- package/dist/src/clients/payment-checkout/apple-session.js +11 -6
- package/dist/src/index.js +65 -79
- package/dist/src/utils/recaptcha.d.ts +9 -3
- package/dist/src/utils/recaptcha.js +6 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -575,10 +575,9 @@ var loadRecaptchaScript = (siteKey) => {
|
|
|
575
575
|
);
|
|
576
576
|
if (existingScript) {
|
|
577
577
|
existingScript.addEventListener("load", () => resolve());
|
|
578
|
-
existingScript.addEventListener(
|
|
579
|
-
"
|
|
580
|
-
|
|
581
|
-
);
|
|
578
|
+
existingScript.addEventListener("error", () => {
|
|
579
|
+
reject(new Error("Failed to load existing reCAPTCHA script"));
|
|
580
|
+
});
|
|
582
581
|
return;
|
|
583
582
|
}
|
|
584
583
|
const script = document.createElement("script");
|
|
@@ -586,7 +585,9 @@ var loadRecaptchaScript = (siteKey) => {
|
|
|
586
585
|
script.async = true;
|
|
587
586
|
script.defer = true;
|
|
588
587
|
script.onload = () => resolve();
|
|
589
|
-
script.onerror = () =>
|
|
588
|
+
script.onerror = () => {
|
|
589
|
+
reject(new Error("Failed to load reCAPTCHA script"));
|
|
590
|
+
};
|
|
590
591
|
document.head.appendChild(script);
|
|
591
592
|
});
|
|
592
593
|
};
|
|
@@ -835,17 +836,14 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
835
836
|
#country = "";
|
|
836
837
|
#triggerElement = null;
|
|
837
838
|
#keyHandler = null;
|
|
838
|
-
#
|
|
839
|
-
#recaptchaTokensPromise = null;
|
|
839
|
+
#isClosed = false;
|
|
840
840
|
/**
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
* until the token pre-fetch resolves, so this callback is never reached
|
|
848
|
-
* without valid tokens.
|
|
841
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
842
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
843
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
844
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
845
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
846
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
849
847
|
*/
|
|
850
848
|
onConfirm = null;
|
|
851
849
|
set offer(value) {
|
|
@@ -942,28 +940,32 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
942
940
|
}
|
|
943
941
|
});
|
|
944
942
|
}
|
|
945
|
-
|
|
946
|
-
if (cta)
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
943
|
+
cta?.addEventListener("click", () => {
|
|
944
|
+
if (cta.disabled) return;
|
|
945
|
+
if (isUS && checkbox && !checkbox.checked) {
|
|
946
|
+
errorElement?.classList.add("apm__error--visible");
|
|
947
|
+
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
948
|
+
return;
|
|
950
949
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
950
|
+
errorElement?.classList.remove("apm__error--visible");
|
|
951
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
952
|
+
cta.disabled = true;
|
|
953
|
+
cta.setAttribute("aria-busy", "true");
|
|
954
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
955
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
956
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
957
|
+
this.close();
|
|
958
|
+
}
|
|
959
|
+
recaptchaTokensPromise.catch(() => {
|
|
960
|
+
if (this.#isClosed) return;
|
|
961
|
+
cta.disabled = false;
|
|
962
|
+
cta.removeAttribute("aria-busy");
|
|
962
963
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
963
964
|
if (existingError) {
|
|
964
965
|
const icon = existingError.querySelector("svg");
|
|
965
966
|
existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
966
967
|
if (icon) existingError.prepend(icon);
|
|
968
|
+
existingError.setAttribute("role", "alert");
|
|
967
969
|
existingError.classList.add("apm__error--visible");
|
|
968
970
|
} else {
|
|
969
971
|
const errorNotice = document.createElement("div");
|
|
@@ -973,25 +975,14 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
973
975
|
cta?.insertAdjacentElement("beforebegin", errorNotice);
|
|
974
976
|
}
|
|
975
977
|
});
|
|
976
|
-
}
|
|
977
|
-
cta?.addEventListener("click", () => {
|
|
978
|
-
if (isUS && checkbox && !checkbox.checked) {
|
|
979
|
-
errorElement?.classList.add("apm__error--visible");
|
|
980
|
-
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
|
-
if (this.#recaptchaTokens) {
|
|
984
|
-
this.onConfirm?.(this.#recaptchaTokens);
|
|
985
|
-
this.close();
|
|
986
|
-
}
|
|
987
978
|
});
|
|
988
979
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
989
980
|
"click",
|
|
990
981
|
() => this.close()
|
|
991
982
|
);
|
|
992
983
|
}
|
|
993
|
-
open(
|
|
994
|
-
this.#
|
|
984
|
+
open() {
|
|
985
|
+
this.#isClosed = false;
|
|
995
986
|
this.#triggerElement = document.activeElement;
|
|
996
987
|
document.body.appendChild(this);
|
|
997
988
|
this.#keyHandler = (event) => {
|
|
@@ -1006,6 +997,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
1006
997
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
1007
998
|
}
|
|
1008
999
|
close() {
|
|
1000
|
+
this.#isClosed = true;
|
|
1009
1001
|
if (this.#keyHandler) {
|
|
1010
1002
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
1011
1003
|
capture: true
|
|
@@ -1418,7 +1410,10 @@ function startApplePaySession(config) {
|
|
|
1418
1410
|
};
|
|
1419
1411
|
session.onpaymentauthorized = (event) => {
|
|
1420
1412
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1421
|
-
config.onPaymentAuthorized(event, session)
|
|
1413
|
+
config.onPaymentAuthorized(event, session).catch(() => {
|
|
1414
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1415
|
+
redirectToFallbackCheckout(config);
|
|
1416
|
+
});
|
|
1422
1417
|
};
|
|
1423
1418
|
session.oncancel = () => {
|
|
1424
1419
|
config.onCancel?.();
|
|
@@ -1969,7 +1964,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1969
1964
|
#returnUrl = "";
|
|
1970
1965
|
#supportedBillingCountries = [];
|
|
1971
1966
|
#entryPoint = "";
|
|
1972
|
-
#recaptchaTokensPromise = null;
|
|
1973
1967
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1974
1968
|
get offer() {
|
|
1975
1969
|
return this.#offer;
|
|
@@ -2034,7 +2028,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2034
2028
|
this.#paymentOptions = null;
|
|
2035
2029
|
this.#returnUrl = "";
|
|
2036
2030
|
this.#supportedBillingCountries = [];
|
|
2037
|
-
this.#recaptchaTokensPromise = null;
|
|
2038
2031
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2039
2032
|
}
|
|
2040
2033
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
@@ -2137,7 +2130,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2137
2130
|
if (button) {
|
|
2138
2131
|
button.classList.remove("wap-loading");
|
|
2139
2132
|
this.#updateDisabledState();
|
|
2140
|
-
this.#scheduleRecaptchaTokens();
|
|
2141
2133
|
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
2142
2134
|
entryPoint: this.#entryPoint,
|
|
2143
2135
|
country: this.#country
|
|
@@ -2174,27 +2166,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2174
2166
|
}
|
|
2175
2167
|
const skuId = this.#offer.sku_id;
|
|
2176
2168
|
const country = this.#country;
|
|
2177
|
-
modal.onConfirm = (
|
|
2178
|
-
this.#initiateApplePay(skuId, country,
|
|
2179
|
-
this.#scheduleRecaptchaTokens();
|
|
2169
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2170
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2180
2171
|
};
|
|
2181
|
-
modal.open(
|
|
2182
|
-
}
|
|
2183
|
-
/**
|
|
2184
|
-
* Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
|
|
2185
|
-
* If the fetch rejects, the field is cleared so the next `modal.open()` call
|
|
2186
|
-
* falls back to a new attempt via the modal's own null-fallback path — preventing
|
|
2187
|
-
* a single transient failure from permanently disabling the CTA on all retries.
|
|
2188
|
-
* The identity guard prevents a late rejection from clobbering a newer attempt.
|
|
2189
|
-
*/
|
|
2190
|
-
#scheduleRecaptchaTokens() {
|
|
2191
|
-
const attempt = getPurchaseRecaptchaTokens();
|
|
2192
|
-
attempt.catch(() => {
|
|
2193
|
-
if (this.#recaptchaTokensPromise === attempt) {
|
|
2194
|
-
this.#recaptchaTokensPromise = null;
|
|
2195
|
-
}
|
|
2196
|
-
});
|
|
2197
|
-
this.#recaptchaTokensPromise = attempt;
|
|
2172
|
+
modal.open();
|
|
2198
2173
|
}
|
|
2199
2174
|
async #fetchSession() {
|
|
2200
2175
|
try {
|
|
@@ -2215,7 +2190,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2215
2190
|
return null;
|
|
2216
2191
|
}
|
|
2217
2192
|
}
|
|
2218
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2193
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2219
2194
|
const offer = this.#offer;
|
|
2220
2195
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2221
2196
|
return {
|
|
@@ -2227,30 +2202,41 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2227
2202
|
skuId,
|
|
2228
2203
|
returnUrl: this.#returnUrl,
|
|
2229
2204
|
userLoggedIn: sessionData.loggedIn,
|
|
2230
|
-
onPaymentAuthorized: (event, session) =>
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2205
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2206
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2207
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2208
|
+
skuId,
|
|
2209
|
+
country,
|
|
2210
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2211
|
+
returnUrl: this.#returnUrl,
|
|
2212
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2213
|
+
recaptchaTokens
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2238
2216
|
};
|
|
2239
2217
|
}
|
|
2240
|
-
#initiateApplePay(skuId, country,
|
|
2218
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2241
2219
|
try {
|
|
2242
2220
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2243
2221
|
const paymentOptions = this.#paymentOptions;
|
|
2222
|
+
if (!paymentOptions) {
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2244
2225
|
startApplePaySession(
|
|
2245
2226
|
this.#buildSessionParams(
|
|
2246
2227
|
skuId,
|
|
2247
2228
|
country,
|
|
2248
2229
|
sessionData,
|
|
2249
2230
|
paymentOptions,
|
|
2250
|
-
|
|
2231
|
+
recaptchaTokensPromise
|
|
2251
2232
|
)
|
|
2252
2233
|
);
|
|
2253
2234
|
} catch {
|
|
2235
|
+
redirectToFallbackCheckout({
|
|
2236
|
+
returnUrl: this.#returnUrl,
|
|
2237
|
+
skuId,
|
|
2238
|
+
countryCode: country
|
|
2239
|
+
});
|
|
2254
2240
|
}
|
|
2255
2241
|
}
|
|
2256
2242
|
};
|
|
@@ -570,10 +570,9 @@ var loadRecaptchaScript = (siteKey) => {
|
|
|
570
570
|
);
|
|
571
571
|
if (existingScript) {
|
|
572
572
|
existingScript.addEventListener("load", () => resolve());
|
|
573
|
-
existingScript.addEventListener(
|
|
574
|
-
"
|
|
575
|
-
|
|
576
|
-
);
|
|
573
|
+
existingScript.addEventListener("error", () => {
|
|
574
|
+
reject(new Error("Failed to load existing reCAPTCHA script"));
|
|
575
|
+
});
|
|
577
576
|
return;
|
|
578
577
|
}
|
|
579
578
|
const script = document.createElement("script");
|
|
@@ -581,7 +580,9 @@ var loadRecaptchaScript = (siteKey) => {
|
|
|
581
580
|
script.async = true;
|
|
582
581
|
script.defer = true;
|
|
583
582
|
script.onload = () => resolve();
|
|
584
|
-
script.onerror = () =>
|
|
583
|
+
script.onerror = () => {
|
|
584
|
+
reject(new Error("Failed to load reCAPTCHA script"));
|
|
585
|
+
};
|
|
585
586
|
document.head.appendChild(script);
|
|
586
587
|
});
|
|
587
588
|
};
|
|
@@ -830,17 +831,14 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
830
831
|
#country = "";
|
|
831
832
|
#triggerElement = null;
|
|
832
833
|
#keyHandler = null;
|
|
833
|
-
#
|
|
834
|
-
#recaptchaTokensPromise = null;
|
|
834
|
+
#isClosed = false;
|
|
835
835
|
/**
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
* until the token pre-fetch resolves, so this callback is never reached
|
|
843
|
-
* without valid tokens.
|
|
836
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
837
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
838
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
839
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
840
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
841
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
844
842
|
*/
|
|
845
843
|
onConfirm = null;
|
|
846
844
|
set offer(value) {
|
|
@@ -937,28 +935,32 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
937
935
|
}
|
|
938
936
|
});
|
|
939
937
|
}
|
|
940
|
-
|
|
941
|
-
if (cta)
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
938
|
+
cta?.addEventListener("click", () => {
|
|
939
|
+
if (cta.disabled) return;
|
|
940
|
+
if (isUS && checkbox && !checkbox.checked) {
|
|
941
|
+
errorElement?.classList.add("apm__error--visible");
|
|
942
|
+
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
943
|
+
return;
|
|
945
944
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
945
|
+
errorElement?.classList.remove("apm__error--visible");
|
|
946
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
947
|
+
cta.disabled = true;
|
|
948
|
+
cta.setAttribute("aria-busy", "true");
|
|
949
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
950
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
951
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
952
|
+
this.close();
|
|
953
|
+
}
|
|
954
|
+
recaptchaTokensPromise.catch(() => {
|
|
955
|
+
if (this.#isClosed) return;
|
|
956
|
+
cta.disabled = false;
|
|
957
|
+
cta.removeAttribute("aria-busy");
|
|
957
958
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
958
959
|
if (existingError) {
|
|
959
960
|
const icon = existingError.querySelector("svg");
|
|
960
961
|
existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
|
|
961
962
|
if (icon) existingError.prepend(icon);
|
|
963
|
+
existingError.setAttribute("role", "alert");
|
|
962
964
|
existingError.classList.add("apm__error--visible");
|
|
963
965
|
} else {
|
|
964
966
|
const errorNotice = document.createElement("div");
|
|
@@ -968,25 +970,14 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
968
970
|
cta?.insertAdjacentElement("beforebegin", errorNotice);
|
|
969
971
|
}
|
|
970
972
|
});
|
|
971
|
-
}
|
|
972
|
-
cta?.addEventListener("click", () => {
|
|
973
|
-
if (isUS && checkbox && !checkbox.checked) {
|
|
974
|
-
errorElement?.classList.add("apm__error--visible");
|
|
975
|
-
checkboxLabel?.classList.add("apm__checkbox-label--error");
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
if (this.#recaptchaTokens) {
|
|
979
|
-
this.onConfirm?.(this.#recaptchaTokens);
|
|
980
|
-
this.close();
|
|
981
|
-
}
|
|
982
973
|
});
|
|
983
974
|
this.querySelector("#apple-pay-modal-close")?.addEventListener(
|
|
984
975
|
"click",
|
|
985
976
|
() => this.close()
|
|
986
977
|
);
|
|
987
978
|
}
|
|
988
|
-
open(
|
|
989
|
-
this.#
|
|
979
|
+
open() {
|
|
980
|
+
this.#isClosed = false;
|
|
990
981
|
this.#triggerElement = document.activeElement;
|
|
991
982
|
document.body.appendChild(this);
|
|
992
983
|
this.#keyHandler = (event) => {
|
|
@@ -1001,6 +992,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
1001
992
|
this.querySelector("#apple-pay-modal")?.focus();
|
|
1002
993
|
}
|
|
1003
994
|
close() {
|
|
995
|
+
this.#isClosed = true;
|
|
1004
996
|
if (this.#keyHandler) {
|
|
1005
997
|
document.removeEventListener("keydown", this.#keyHandler, {
|
|
1006
998
|
capture: true
|
|
@@ -1413,7 +1405,10 @@ function startApplePaySession(config) {
|
|
|
1413
1405
|
};
|
|
1414
1406
|
session.onpaymentauthorized = (event) => {
|
|
1415
1407
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1416
|
-
config.onPaymentAuthorized(event, session)
|
|
1408
|
+
config.onPaymentAuthorized(event, session).catch(() => {
|
|
1409
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1410
|
+
redirectToFallbackCheckout(config);
|
|
1411
|
+
});
|
|
1417
1412
|
};
|
|
1418
1413
|
session.oncancel = () => {
|
|
1419
1414
|
config.onCancel?.();
|
|
@@ -1964,7 +1959,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
1964
1959
|
#returnUrl = "";
|
|
1965
1960
|
#supportedBillingCountries = [];
|
|
1966
1961
|
#entryPoint = "";
|
|
1967
|
-
#recaptchaTokensPromise = null;
|
|
1968
1962
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
1969
1963
|
get offer() {
|
|
1970
1964
|
return this.#offer;
|
|
@@ -2029,7 +2023,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2029
2023
|
this.#paymentOptions = null;
|
|
2030
2024
|
this.#returnUrl = "";
|
|
2031
2025
|
this.#supportedBillingCountries = [];
|
|
2032
|
-
this.#recaptchaTokensPromise = null;
|
|
2033
2026
|
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2034
2027
|
}
|
|
2035
2028
|
// ─── Render pipeline ────────────────────────────────────────────────────────
|
|
@@ -2132,7 +2125,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2132
2125
|
if (button) {
|
|
2133
2126
|
button.classList.remove("wap-loading");
|
|
2134
2127
|
this.#updateDisabledState();
|
|
2135
|
-
this.#scheduleRecaptchaTokens();
|
|
2136
2128
|
trackExpressWalletImpression(this.#offer.sku_id, {
|
|
2137
2129
|
entryPoint: this.#entryPoint,
|
|
2138
2130
|
country: this.#country
|
|
@@ -2169,27 +2161,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2169
2161
|
}
|
|
2170
2162
|
const skuId = this.#offer.sku_id;
|
|
2171
2163
|
const country = this.#country;
|
|
2172
|
-
modal.onConfirm = (
|
|
2173
|
-
this.#initiateApplePay(skuId, country,
|
|
2174
|
-
this.#scheduleRecaptchaTokens();
|
|
2164
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2165
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2175
2166
|
};
|
|
2176
|
-
modal.open(
|
|
2177
|
-
}
|
|
2178
|
-
/**
|
|
2179
|
-
* Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
|
|
2180
|
-
* If the fetch rejects, the field is cleared so the next `modal.open()` call
|
|
2181
|
-
* falls back to a new attempt via the modal's own null-fallback path — preventing
|
|
2182
|
-
* a single transient failure from permanently disabling the CTA on all retries.
|
|
2183
|
-
* The identity guard prevents a late rejection from clobbering a newer attempt.
|
|
2184
|
-
*/
|
|
2185
|
-
#scheduleRecaptchaTokens() {
|
|
2186
|
-
const attempt = getPurchaseRecaptchaTokens();
|
|
2187
|
-
attempt.catch(() => {
|
|
2188
|
-
if (this.#recaptchaTokensPromise === attempt) {
|
|
2189
|
-
this.#recaptchaTokensPromise = null;
|
|
2190
|
-
}
|
|
2191
|
-
});
|
|
2192
|
-
this.#recaptchaTokensPromise = attempt;
|
|
2167
|
+
modal.open();
|
|
2193
2168
|
}
|
|
2194
2169
|
async #fetchSession() {
|
|
2195
2170
|
try {
|
|
@@ -2210,7 +2185,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2210
2185
|
return null;
|
|
2211
2186
|
}
|
|
2212
2187
|
}
|
|
2213
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2188
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2214
2189
|
const offer = this.#offer;
|
|
2215
2190
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2216
2191
|
return {
|
|
@@ -2222,30 +2197,41 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2222
2197
|
skuId,
|
|
2223
2198
|
returnUrl: this.#returnUrl,
|
|
2224
2199
|
userLoggedIn: sessionData.loggedIn,
|
|
2225
|
-
onPaymentAuthorized: (event, session) =>
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2200
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2201
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2202
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2203
|
+
skuId,
|
|
2204
|
+
country,
|
|
2205
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2206
|
+
returnUrl: this.#returnUrl,
|
|
2207
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2208
|
+
recaptchaTokens
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2233
2211
|
};
|
|
2234
2212
|
}
|
|
2235
|
-
#initiateApplePay(skuId, country,
|
|
2213
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2236
2214
|
try {
|
|
2237
2215
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2238
2216
|
const paymentOptions = this.#paymentOptions;
|
|
2217
|
+
if (!paymentOptions) {
|
|
2218
|
+
return;
|
|
2219
|
+
}
|
|
2239
2220
|
startApplePaySession(
|
|
2240
2221
|
this.#buildSessionParams(
|
|
2241
2222
|
skuId,
|
|
2242
2223
|
country,
|
|
2243
2224
|
sessionData,
|
|
2244
2225
|
paymentOptions,
|
|
2245
|
-
|
|
2226
|
+
recaptchaTokensPromise
|
|
2246
2227
|
)
|
|
2247
2228
|
);
|
|
2248
2229
|
} catch {
|
|
2230
|
+
redirectToFallbackCheckout({
|
|
2231
|
+
returnUrl: this.#returnUrl,
|
|
2232
|
+
skuId,
|
|
2233
|
+
countryCode: country
|
|
2234
|
+
});
|
|
2249
2235
|
}
|
|
2250
2236
|
}
|
|
2251
2237
|
};
|