@economist/web-apple-pay 0.1.3-beta.45 → 0.1.3-beta.46
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 +40 -33
- package/dist/src/apple-pay-button.js +40 -33
- package/dist/src/apple-pay-button.stories.js +40 -33
- package/dist/src/apple-pay-modal.d.ts +7 -5
- package/dist/src/apple-pay-modal.js +14 -13
- package/dist/src/apple-pay-modal.stories.js +40 -33
- package/dist/src/clients/payment-checkout/apple-session.js +5 -1
- package/dist/src/index.js +40 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -849,10 +849,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
849
849
|
#keyHandler = null;
|
|
850
850
|
#isClosed = false;
|
|
851
851
|
/**
|
|
852
|
-
* Callback invoked from the CTA click handler
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* new ApplePaySession()
|
|
852
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
853
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
854
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
855
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
856
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
857
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
856
858
|
*/
|
|
857
859
|
onConfirm = null;
|
|
858
860
|
set offer(value) {
|
|
@@ -957,20 +959,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
957
959
|
return;
|
|
958
960
|
}
|
|
959
961
|
errorElement?.classList.remove("apm__error--visible");
|
|
962
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
960
963
|
cta.disabled = true;
|
|
961
964
|
cta.setAttribute("aria-busy", "true");
|
|
962
965
|
console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
|
|
963
|
-
getPurchaseRecaptchaTokens()
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
return;
|
|
968
|
-
}
|
|
969
|
-
console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
|
|
970
|
-
this.onConfirm?.(recaptchaTokens);
|
|
966
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
967
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
968
|
+
console.info("[web-apple-pay] Calling onConfirm synchronously to initiate Apple Pay session");
|
|
969
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
971
970
|
this.close();
|
|
972
|
-
}
|
|
971
|
+
}
|
|
972
|
+
recaptchaTokensPromise.catch((error) => {
|
|
973
973
|
console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
|
|
974
|
+
if (this.#isClosed) return;
|
|
974
975
|
cta.disabled = false;
|
|
975
976
|
cta.removeAttribute("aria-busy");
|
|
976
977
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
@@ -1429,7 +1430,11 @@ function startApplePaySession(config) {
|
|
|
1429
1430
|
};
|
|
1430
1431
|
session.onpaymentauthorized = (event) => {
|
|
1431
1432
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1432
|
-
config.onPaymentAuthorized(event, session)
|
|
1433
|
+
config.onPaymentAuthorized(event, session).catch((err) => {
|
|
1434
|
+
console.error("[web-apple-pay] onPaymentAuthorized threw an unhandled error \u2014 aborting session", err);
|
|
1435
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1436
|
+
redirectToFallbackCheckout(config);
|
|
1437
|
+
});
|
|
1433
1438
|
};
|
|
1434
1439
|
session.oncancel = () => {
|
|
1435
1440
|
config.onCancel?.();
|
|
@@ -2204,9 +2209,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2204
2209
|
}
|
|
2205
2210
|
const skuId = this.#offer.sku_id;
|
|
2206
2211
|
const country = this.#country;
|
|
2207
|
-
modal.onConfirm = (
|
|
2212
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2208
2213
|
console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
|
|
2209
|
-
this.#initiateApplePay(skuId, country,
|
|
2214
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2210
2215
|
};
|
|
2211
2216
|
console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
|
|
2212
2217
|
modal.open();
|
|
@@ -2230,7 +2235,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2230
2235
|
return null;
|
|
2231
2236
|
}
|
|
2232
2237
|
}
|
|
2233
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2238
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2234
2239
|
const offer = this.#offer;
|
|
2235
2240
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2236
2241
|
return {
|
|
@@ -2242,31 +2247,33 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2242
2247
|
skuId,
|
|
2243
2248
|
returnUrl: this.#returnUrl,
|
|
2244
2249
|
userLoggedIn: sessionData.loggedIn,
|
|
2245
|
-
onPaymentAuthorized: (event, session) =>
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2250
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2251
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2252
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2253
|
+
skuId,
|
|
2254
|
+
country,
|
|
2255
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2256
|
+
returnUrl: this.#returnUrl,
|
|
2257
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2258
|
+
recaptchaTokens
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2253
2261
|
};
|
|
2254
2262
|
}
|
|
2255
|
-
#initiateApplePay(skuId, country,
|
|
2263
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2256
2264
|
try {
|
|
2257
2265
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2258
2266
|
const paymentOptions = this.#paymentOptions;
|
|
2267
|
+
if (!paymentOptions) {
|
|
2268
|
+
console.error("[web-apple-pay] #initiateApplePay called before payment options were fetched");
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2259
2271
|
console.info("[web-apple-pay] Starting Apple Pay session", {
|
|
2260
2272
|
skuId,
|
|
2261
2273
|
country,
|
|
2262
2274
|
loggedIn: sessionData.loggedIn,
|
|
2263
2275
|
userType: sessionData.userType,
|
|
2264
|
-
hasPaymentOptions:
|
|
2265
|
-
recaptchaTokensPresent: {
|
|
2266
|
-
checkEligibility: !!recaptchaTokens.checkEligibility,
|
|
2267
|
-
newBasket: !!recaptchaTokens.newBasket,
|
|
2268
|
-
registerUser: !!recaptchaTokens.registerUser
|
|
2269
|
-
}
|
|
2276
|
+
hasPaymentOptions: true
|
|
2270
2277
|
});
|
|
2271
2278
|
startApplePaySession(
|
|
2272
2279
|
this.#buildSessionParams(
|
|
@@ -2274,7 +2281,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2274
2281
|
country,
|
|
2275
2282
|
sessionData,
|
|
2276
2283
|
paymentOptions,
|
|
2277
|
-
|
|
2284
|
+
recaptchaTokensPromise
|
|
2278
2285
|
)
|
|
2279
2286
|
);
|
|
2280
2287
|
} catch (error) {
|
|
@@ -844,10 +844,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
844
844
|
#keyHandler = null;
|
|
845
845
|
#isClosed = false;
|
|
846
846
|
/**
|
|
847
|
-
* Callback invoked from the CTA click handler
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
* new ApplePaySession()
|
|
847
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
848
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
849
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
850
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
851
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
852
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
851
853
|
*/
|
|
852
854
|
onConfirm = null;
|
|
853
855
|
set offer(value) {
|
|
@@ -952,20 +954,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
952
954
|
return;
|
|
953
955
|
}
|
|
954
956
|
errorElement?.classList.remove("apm__error--visible");
|
|
957
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
955
958
|
cta.disabled = true;
|
|
956
959
|
cta.setAttribute("aria-busy", "true");
|
|
957
960
|
console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
|
|
958
|
-
getPurchaseRecaptchaTokens()
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
|
|
965
|
-
this.onConfirm?.(recaptchaTokens);
|
|
961
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
962
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
963
|
+
console.info("[web-apple-pay] Calling onConfirm synchronously to initiate Apple Pay session");
|
|
964
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
966
965
|
this.close();
|
|
967
|
-
}
|
|
966
|
+
}
|
|
967
|
+
recaptchaTokensPromise.catch((error) => {
|
|
968
968
|
console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
|
|
969
|
+
if (this.#isClosed) return;
|
|
969
970
|
cta.disabled = false;
|
|
970
971
|
cta.removeAttribute("aria-busy");
|
|
971
972
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
@@ -1424,7 +1425,11 @@ function startApplePaySession(config) {
|
|
|
1424
1425
|
};
|
|
1425
1426
|
session.onpaymentauthorized = (event) => {
|
|
1426
1427
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1427
|
-
config.onPaymentAuthorized(event, session)
|
|
1428
|
+
config.onPaymentAuthorized(event, session).catch((err) => {
|
|
1429
|
+
console.error("[web-apple-pay] onPaymentAuthorized threw an unhandled error \u2014 aborting session", err);
|
|
1430
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1431
|
+
redirectToFallbackCheckout(config);
|
|
1432
|
+
});
|
|
1428
1433
|
};
|
|
1429
1434
|
session.oncancel = () => {
|
|
1430
1435
|
config.onCancel?.();
|
|
@@ -2199,9 +2204,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2199
2204
|
}
|
|
2200
2205
|
const skuId = this.#offer.sku_id;
|
|
2201
2206
|
const country = this.#country;
|
|
2202
|
-
modal.onConfirm = (
|
|
2207
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2203
2208
|
console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
|
|
2204
|
-
this.#initiateApplePay(skuId, country,
|
|
2209
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2205
2210
|
};
|
|
2206
2211
|
console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
|
|
2207
2212
|
modal.open();
|
|
@@ -2225,7 +2230,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2225
2230
|
return null;
|
|
2226
2231
|
}
|
|
2227
2232
|
}
|
|
2228
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2233
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2229
2234
|
const offer = this.#offer;
|
|
2230
2235
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2231
2236
|
return {
|
|
@@ -2237,31 +2242,33 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2237
2242
|
skuId,
|
|
2238
2243
|
returnUrl: this.#returnUrl,
|
|
2239
2244
|
userLoggedIn: sessionData.loggedIn,
|
|
2240
|
-
onPaymentAuthorized: (event, session) =>
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2245
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2246
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2247
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2248
|
+
skuId,
|
|
2249
|
+
country,
|
|
2250
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2251
|
+
returnUrl: this.#returnUrl,
|
|
2252
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2253
|
+
recaptchaTokens
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2248
2256
|
};
|
|
2249
2257
|
}
|
|
2250
|
-
#initiateApplePay(skuId, country,
|
|
2258
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2251
2259
|
try {
|
|
2252
2260
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2253
2261
|
const paymentOptions = this.#paymentOptions;
|
|
2262
|
+
if (!paymentOptions) {
|
|
2263
|
+
console.error("[web-apple-pay] #initiateApplePay called before payment options were fetched");
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2254
2266
|
console.info("[web-apple-pay] Starting Apple Pay session", {
|
|
2255
2267
|
skuId,
|
|
2256
2268
|
country,
|
|
2257
2269
|
loggedIn: sessionData.loggedIn,
|
|
2258
2270
|
userType: sessionData.userType,
|
|
2259
|
-
hasPaymentOptions:
|
|
2260
|
-
recaptchaTokensPresent: {
|
|
2261
|
-
checkEligibility: !!recaptchaTokens.checkEligibility,
|
|
2262
|
-
newBasket: !!recaptchaTokens.newBasket,
|
|
2263
|
-
registerUser: !!recaptchaTokens.registerUser
|
|
2264
|
-
}
|
|
2271
|
+
hasPaymentOptions: true
|
|
2265
2272
|
});
|
|
2266
2273
|
startApplePaySession(
|
|
2267
2274
|
this.#buildSessionParams(
|
|
@@ -2269,7 +2276,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2269
2276
|
country,
|
|
2270
2277
|
sessionData,
|
|
2271
2278
|
paymentOptions,
|
|
2272
|
-
|
|
2279
|
+
recaptchaTokensPromise
|
|
2273
2280
|
)
|
|
2274
2281
|
);
|
|
2275
2282
|
} catch (error) {
|
|
@@ -852,10 +852,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
852
852
|
#keyHandler = null;
|
|
853
853
|
#isClosed = false;
|
|
854
854
|
/**
|
|
855
|
-
* Callback invoked from the CTA click handler
|
|
856
|
-
*
|
|
857
|
-
*
|
|
858
|
-
* new ApplePaySession()
|
|
855
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
856
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
857
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
858
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
859
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
860
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
859
861
|
*/
|
|
860
862
|
onConfirm = null;
|
|
861
863
|
set offer(value) {
|
|
@@ -960,20 +962,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
960
962
|
return;
|
|
961
963
|
}
|
|
962
964
|
errorElement?.classList.remove("apm__error--visible");
|
|
965
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
963
966
|
cta.disabled = true;
|
|
964
967
|
cta.setAttribute("aria-busy", "true");
|
|
965
968
|
console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
|
|
966
|
-
getPurchaseRecaptchaTokens()
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
|
|
973
|
-
this.onConfirm?.(recaptchaTokens);
|
|
969
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
970
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
971
|
+
console.info("[web-apple-pay] Calling onConfirm synchronously to initiate Apple Pay session");
|
|
972
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
974
973
|
this.close();
|
|
975
|
-
}
|
|
974
|
+
}
|
|
975
|
+
recaptchaTokensPromise.catch((error) => {
|
|
976
976
|
console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
|
|
977
|
+
if (this.#isClosed) return;
|
|
977
978
|
cta.disabled = false;
|
|
978
979
|
cta.removeAttribute("aria-busy");
|
|
979
980
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
@@ -1432,7 +1433,11 @@ function startApplePaySession(config) {
|
|
|
1432
1433
|
};
|
|
1433
1434
|
session.onpaymentauthorized = (event) => {
|
|
1434
1435
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1435
|
-
config.onPaymentAuthorized(event, session)
|
|
1436
|
+
config.onPaymentAuthorized(event, session).catch((err) => {
|
|
1437
|
+
console.error("[web-apple-pay] onPaymentAuthorized threw an unhandled error \u2014 aborting session", err);
|
|
1438
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1439
|
+
redirectToFallbackCheckout(config);
|
|
1440
|
+
});
|
|
1436
1441
|
};
|
|
1437
1442
|
session.oncancel = () => {
|
|
1438
1443
|
config.onCancel?.();
|
|
@@ -2207,9 +2212,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2207
2212
|
}
|
|
2208
2213
|
const skuId = this.#offer.sku_id;
|
|
2209
2214
|
const country = this.#country;
|
|
2210
|
-
modal.onConfirm = (
|
|
2215
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2211
2216
|
console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
|
|
2212
|
-
this.#initiateApplePay(skuId, country,
|
|
2217
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2213
2218
|
};
|
|
2214
2219
|
console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
|
|
2215
2220
|
modal.open();
|
|
@@ -2233,7 +2238,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2233
2238
|
return null;
|
|
2234
2239
|
}
|
|
2235
2240
|
}
|
|
2236
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2241
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2237
2242
|
const offer = this.#offer;
|
|
2238
2243
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2239
2244
|
return {
|
|
@@ -2245,31 +2250,33 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2245
2250
|
skuId,
|
|
2246
2251
|
returnUrl: this.#returnUrl,
|
|
2247
2252
|
userLoggedIn: sessionData.loggedIn,
|
|
2248
|
-
onPaymentAuthorized: (event, session) =>
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2253
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2254
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2255
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2256
|
+
skuId,
|
|
2257
|
+
country,
|
|
2258
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2259
|
+
returnUrl: this.#returnUrl,
|
|
2260
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2261
|
+
recaptchaTokens
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2256
2264
|
};
|
|
2257
2265
|
}
|
|
2258
|
-
#initiateApplePay(skuId, country,
|
|
2266
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2259
2267
|
try {
|
|
2260
2268
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2261
2269
|
const paymentOptions = this.#paymentOptions;
|
|
2270
|
+
if (!paymentOptions) {
|
|
2271
|
+
console.error("[web-apple-pay] #initiateApplePay called before payment options were fetched");
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2262
2274
|
console.info("[web-apple-pay] Starting Apple Pay session", {
|
|
2263
2275
|
skuId,
|
|
2264
2276
|
country,
|
|
2265
2277
|
loggedIn: sessionData.loggedIn,
|
|
2266
2278
|
userType: sessionData.userType,
|
|
2267
|
-
hasPaymentOptions:
|
|
2268
|
-
recaptchaTokensPresent: {
|
|
2269
|
-
checkEligibility: !!recaptchaTokens.checkEligibility,
|
|
2270
|
-
newBasket: !!recaptchaTokens.newBasket,
|
|
2271
|
-
registerUser: !!recaptchaTokens.registerUser
|
|
2272
|
-
}
|
|
2279
|
+
hasPaymentOptions: true
|
|
2273
2280
|
});
|
|
2274
2281
|
startApplePaySession(
|
|
2275
2282
|
this.#buildSessionParams(
|
|
@@ -2277,7 +2284,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2277
2284
|
country,
|
|
2278
2285
|
sessionData,
|
|
2279
2286
|
paymentOptions,
|
|
2280
|
-
|
|
2287
|
+
recaptchaTokensPromise
|
|
2281
2288
|
)
|
|
2282
2289
|
);
|
|
2283
2290
|
} catch (error) {
|
|
@@ -7,12 +7,14 @@ export declare class ApplePayModal extends HTMLElement {
|
|
|
7
7
|
static readonly tag = "teg-apple-pay-modal";
|
|
8
8
|
static define(): void;
|
|
9
9
|
/**
|
|
10
|
-
* Callback invoked from the CTA click handler
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* new ApplePaySession()
|
|
10
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
11
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
12
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
13
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
14
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
15
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
14
16
|
*/
|
|
15
|
-
onConfirm: ((
|
|
17
|
+
onConfirm: ((recaptchaTokensPromise: Promise<RecaptchaTokens>) => void) | null;
|
|
16
18
|
set offer(value: Offer | null);
|
|
17
19
|
get country(): string;
|
|
18
20
|
set country(value: string);
|
|
@@ -844,10 +844,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
844
844
|
#keyHandler = null;
|
|
845
845
|
#isClosed = false;
|
|
846
846
|
/**
|
|
847
|
-
* Callback invoked from the CTA click handler
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
* new ApplePaySession()
|
|
847
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
848
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
849
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
850
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
851
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
852
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
851
853
|
*/
|
|
852
854
|
onConfirm = null;
|
|
853
855
|
set offer(value) {
|
|
@@ -952,20 +954,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
952
954
|
return;
|
|
953
955
|
}
|
|
954
956
|
errorElement?.classList.remove("apm__error--visible");
|
|
957
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
955
958
|
cta.disabled = true;
|
|
956
959
|
cta.setAttribute("aria-busy", "true");
|
|
957
960
|
console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
|
|
958
|
-
getPurchaseRecaptchaTokens()
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
|
|
965
|
-
this.onConfirm?.(recaptchaTokens);
|
|
961
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
962
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
963
|
+
console.info("[web-apple-pay] Calling onConfirm synchronously to initiate Apple Pay session");
|
|
964
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
966
965
|
this.close();
|
|
967
|
-
}
|
|
966
|
+
}
|
|
967
|
+
recaptchaTokensPromise.catch((error) => {
|
|
968
968
|
console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
|
|
969
|
+
if (this.#isClosed) return;
|
|
969
970
|
cta.disabled = false;
|
|
970
971
|
cta.removeAttribute("aria-busy");
|
|
971
972
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
@@ -844,10 +844,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
844
844
|
#keyHandler = null;
|
|
845
845
|
#isClosed = false;
|
|
846
846
|
/**
|
|
847
|
-
* Callback invoked from the CTA click handler
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
* new ApplePaySession()
|
|
847
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
848
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
849
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
850
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
851
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
852
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
851
853
|
*/
|
|
852
854
|
onConfirm = null;
|
|
853
855
|
set offer(value) {
|
|
@@ -952,20 +954,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
952
954
|
return;
|
|
953
955
|
}
|
|
954
956
|
errorElement?.classList.remove("apm__error--visible");
|
|
957
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
955
958
|
cta.disabled = true;
|
|
956
959
|
cta.setAttribute("aria-busy", "true");
|
|
957
960
|
console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
|
|
958
|
-
getPurchaseRecaptchaTokens()
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
|
|
965
|
-
this.onConfirm?.(recaptchaTokens);
|
|
961
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
962
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
963
|
+
console.info("[web-apple-pay] Calling onConfirm synchronously to initiate Apple Pay session");
|
|
964
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
966
965
|
this.close();
|
|
967
|
-
}
|
|
966
|
+
}
|
|
967
|
+
recaptchaTokensPromise.catch((error) => {
|
|
968
968
|
console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
|
|
969
|
+
if (this.#isClosed) return;
|
|
969
970
|
cta.disabled = false;
|
|
970
971
|
cta.removeAttribute("aria-busy");
|
|
971
972
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
@@ -1424,7 +1425,11 @@ function startApplePaySession(config) {
|
|
|
1424
1425
|
};
|
|
1425
1426
|
session.onpaymentauthorized = (event) => {
|
|
1426
1427
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1427
|
-
config.onPaymentAuthorized(event, session)
|
|
1428
|
+
config.onPaymentAuthorized(event, session).catch((err) => {
|
|
1429
|
+
console.error("[web-apple-pay] onPaymentAuthorized threw an unhandled error \u2014 aborting session", err);
|
|
1430
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1431
|
+
redirectToFallbackCheckout(config);
|
|
1432
|
+
});
|
|
1428
1433
|
};
|
|
1429
1434
|
session.oncancel = () => {
|
|
1430
1435
|
config.onCancel?.();
|
|
@@ -2199,9 +2204,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2199
2204
|
}
|
|
2200
2205
|
const skuId = this.#offer.sku_id;
|
|
2201
2206
|
const country = this.#country;
|
|
2202
|
-
modal.onConfirm = (
|
|
2207
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2203
2208
|
console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
|
|
2204
|
-
this.#initiateApplePay(skuId, country,
|
|
2209
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2205
2210
|
};
|
|
2206
2211
|
console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
|
|
2207
2212
|
modal.open();
|
|
@@ -2225,7 +2230,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2225
2230
|
return null;
|
|
2226
2231
|
}
|
|
2227
2232
|
}
|
|
2228
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2233
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2229
2234
|
const offer = this.#offer;
|
|
2230
2235
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2231
2236
|
return {
|
|
@@ -2237,31 +2242,33 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2237
2242
|
skuId,
|
|
2238
2243
|
returnUrl: this.#returnUrl,
|
|
2239
2244
|
userLoggedIn: sessionData.loggedIn,
|
|
2240
|
-
onPaymentAuthorized: (event, session) =>
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2245
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2246
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2247
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2248
|
+
skuId,
|
|
2249
|
+
country,
|
|
2250
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2251
|
+
returnUrl: this.#returnUrl,
|
|
2252
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2253
|
+
recaptchaTokens
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2248
2256
|
};
|
|
2249
2257
|
}
|
|
2250
|
-
#initiateApplePay(skuId, country,
|
|
2258
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2251
2259
|
try {
|
|
2252
2260
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2253
2261
|
const paymentOptions = this.#paymentOptions;
|
|
2262
|
+
if (!paymentOptions) {
|
|
2263
|
+
console.error("[web-apple-pay] #initiateApplePay called before payment options were fetched");
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2254
2266
|
console.info("[web-apple-pay] Starting Apple Pay session", {
|
|
2255
2267
|
skuId,
|
|
2256
2268
|
country,
|
|
2257
2269
|
loggedIn: sessionData.loggedIn,
|
|
2258
2270
|
userType: sessionData.userType,
|
|
2259
|
-
hasPaymentOptions:
|
|
2260
|
-
recaptchaTokensPresent: {
|
|
2261
|
-
checkEligibility: !!recaptchaTokens.checkEligibility,
|
|
2262
|
-
newBasket: !!recaptchaTokens.newBasket,
|
|
2263
|
-
registerUser: !!recaptchaTokens.registerUser
|
|
2264
|
-
}
|
|
2271
|
+
hasPaymentOptions: true
|
|
2265
2272
|
});
|
|
2266
2273
|
startApplePaySession(
|
|
2267
2274
|
this.#buildSessionParams(
|
|
@@ -2269,7 +2276,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2269
2276
|
country,
|
|
2270
2277
|
sessionData,
|
|
2271
2278
|
paymentOptions,
|
|
2272
|
-
|
|
2279
|
+
recaptchaTokensPromise
|
|
2273
2280
|
)
|
|
2274
2281
|
);
|
|
2275
2282
|
} catch (error) {
|
|
@@ -249,7 +249,11 @@ function startApplePaySession(config) {
|
|
|
249
249
|
};
|
|
250
250
|
session.onpaymentauthorized = (event) => {
|
|
251
251
|
trackWalletPaymentAuthorised(config.skuId);
|
|
252
|
-
config.onPaymentAuthorized(event, session)
|
|
252
|
+
config.onPaymentAuthorized(event, session).catch((err) => {
|
|
253
|
+
console.error("[web-apple-pay] onPaymentAuthorized threw an unhandled error \u2014 aborting session", err);
|
|
254
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
255
|
+
redirectToFallbackCheckout(config);
|
|
256
|
+
});
|
|
253
257
|
};
|
|
254
258
|
session.oncancel = () => {
|
|
255
259
|
config.onCancel?.();
|
package/dist/src/index.js
CHANGED
|
@@ -849,10 +849,12 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
849
849
|
#keyHandler = null;
|
|
850
850
|
#isClosed = false;
|
|
851
851
|
/**
|
|
852
|
-
* Callback invoked from the CTA click handler
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* new ApplePaySession()
|
|
852
|
+
* Callback invoked synchronously from the CTA click handler.
|
|
853
|
+
* Receives a Promise of reCAPTCHA tokens — the promise is already in-flight
|
|
854
|
+
* by the time this is called. The caller (ApplePayButton) must call
|
|
855
|
+
* new ApplePaySession() synchronously inside this callback to stay within
|
|
856
|
+
* Safari's user-gesture window. The token promise resolves before
|
|
857
|
+
* onPaymentAuthorized fires (user still needs to authenticate on the sheet).
|
|
856
858
|
*/
|
|
857
859
|
onConfirm = null;
|
|
858
860
|
set offer(value) {
|
|
@@ -957,20 +959,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
|
|
|
957
959
|
return;
|
|
958
960
|
}
|
|
959
961
|
errorElement?.classList.remove("apm__error--visible");
|
|
962
|
+
this.querySelector('[role="alert"]:not(#apple-pay-modal-error)')?.remove();
|
|
960
963
|
cta.disabled = true;
|
|
961
964
|
cta.setAttribute("aria-busy", "true");
|
|
962
965
|
console.info("[web-apple-pay] CTA clicked \u2014 fetching reCAPTCHA tokens");
|
|
963
|
-
getPurchaseRecaptchaTokens()
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
return;
|
|
968
|
-
}
|
|
969
|
-
console.info("[web-apple-pay] Calling onConfirm to initiate Apple Pay session");
|
|
970
|
-
this.onConfirm?.(recaptchaTokens);
|
|
966
|
+
const recaptchaTokensPromise = getPurchaseRecaptchaTokens();
|
|
967
|
+
if (!this.#isClosed && this.onConfirm) {
|
|
968
|
+
console.info("[web-apple-pay] Calling onConfirm synchronously to initiate Apple Pay session");
|
|
969
|
+
this.onConfirm(recaptchaTokensPromise);
|
|
971
970
|
this.close();
|
|
972
|
-
}
|
|
971
|
+
}
|
|
972
|
+
recaptchaTokensPromise.catch((error) => {
|
|
973
973
|
console.error("[web-apple-pay] reCAPTCHA token fetch failed", error);
|
|
974
|
+
if (this.#isClosed) return;
|
|
974
975
|
cta.disabled = false;
|
|
975
976
|
cta.removeAttribute("aria-busy");
|
|
976
977
|
const existingError = this.querySelector("#apple-pay-modal-error");
|
|
@@ -1429,7 +1430,11 @@ function startApplePaySession(config) {
|
|
|
1429
1430
|
};
|
|
1430
1431
|
session.onpaymentauthorized = (event) => {
|
|
1431
1432
|
trackWalletPaymentAuthorised(config.skuId);
|
|
1432
|
-
config.onPaymentAuthorized(event, session)
|
|
1433
|
+
config.onPaymentAuthorized(event, session).catch((err) => {
|
|
1434
|
+
console.error("[web-apple-pay] onPaymentAuthorized threw an unhandled error \u2014 aborting session", err);
|
|
1435
|
+
session.completePayment({ status: ApplePaySession.STATUS_FAILURE });
|
|
1436
|
+
redirectToFallbackCheckout(config);
|
|
1437
|
+
});
|
|
1433
1438
|
};
|
|
1434
1439
|
session.oncancel = () => {
|
|
1435
1440
|
config.onCancel?.();
|
|
@@ -2204,9 +2209,9 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2204
2209
|
}
|
|
2205
2210
|
const skuId = this.#offer.sku_id;
|
|
2206
2211
|
const country = this.#country;
|
|
2207
|
-
modal.onConfirm = (
|
|
2212
|
+
modal.onConfirm = (recaptchaTokensPromise) => {
|
|
2208
2213
|
console.info("[web-apple-pay] onConfirm received from modal \u2014 initiating Apple Pay session", { skuId, country });
|
|
2209
|
-
this.#initiateApplePay(skuId, country,
|
|
2214
|
+
this.#initiateApplePay(skuId, country, recaptchaTokensPromise);
|
|
2210
2215
|
};
|
|
2211
2216
|
console.info("[web-apple-pay] Opening Apple Pay modal", { skuId, country });
|
|
2212
2217
|
modal.open();
|
|
@@ -2230,7 +2235,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2230
2235
|
return null;
|
|
2231
2236
|
}
|
|
2232
2237
|
}
|
|
2233
|
-
#buildSessionParams(skuId, country, sessionData, paymentOptions,
|
|
2238
|
+
#buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokensPromise) {
|
|
2234
2239
|
const offer = this.#offer;
|
|
2235
2240
|
const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
|
|
2236
2241
|
return {
|
|
@@ -2242,31 +2247,33 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2242
2247
|
skuId,
|
|
2243
2248
|
returnUrl: this.#returnUrl,
|
|
2244
2249
|
userLoggedIn: sessionData.loggedIn,
|
|
2245
|
-
onPaymentAuthorized: (event, session) =>
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2250
|
+
onPaymentAuthorized: async (event, session) => {
|
|
2251
|
+
const recaptchaTokens = await recaptchaTokensPromise;
|
|
2252
|
+
return handlePaymentAuthorized(event, session, sessionData, {
|
|
2253
|
+
skuId,
|
|
2254
|
+
country,
|
|
2255
|
+
currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
|
|
2256
|
+
returnUrl: this.#returnUrl,
|
|
2257
|
+
supportedBillingCountries: this.#supportedBillingCountries,
|
|
2258
|
+
recaptchaTokens
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2253
2261
|
};
|
|
2254
2262
|
}
|
|
2255
|
-
#initiateApplePay(skuId, country,
|
|
2263
|
+
#initiateApplePay(skuId, country, recaptchaTokensPromise) {
|
|
2256
2264
|
try {
|
|
2257
2265
|
const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
|
|
2258
2266
|
const paymentOptions = this.#paymentOptions;
|
|
2267
|
+
if (!paymentOptions) {
|
|
2268
|
+
console.error("[web-apple-pay] #initiateApplePay called before payment options were fetched");
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2259
2271
|
console.info("[web-apple-pay] Starting Apple Pay session", {
|
|
2260
2272
|
skuId,
|
|
2261
2273
|
country,
|
|
2262
2274
|
loggedIn: sessionData.loggedIn,
|
|
2263
2275
|
userType: sessionData.userType,
|
|
2264
|
-
hasPaymentOptions:
|
|
2265
|
-
recaptchaTokensPresent: {
|
|
2266
|
-
checkEligibility: !!recaptchaTokens.checkEligibility,
|
|
2267
|
-
newBasket: !!recaptchaTokens.newBasket,
|
|
2268
|
-
registerUser: !!recaptchaTokens.registerUser
|
|
2269
|
-
}
|
|
2276
|
+
hasPaymentOptions: true
|
|
2270
2277
|
});
|
|
2271
2278
|
startApplePaySession(
|
|
2272
2279
|
this.#buildSessionParams(
|
|
@@ -2274,7 +2281,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2274
2281
|
country,
|
|
2275
2282
|
sessionData,
|
|
2276
2283
|
paymentOptions,
|
|
2277
|
-
|
|
2284
|
+
recaptchaTokensPromise
|
|
2278
2285
|
)
|
|
2279
2286
|
);
|
|
2280
2287
|
} catch (error) {
|
package/package.json
CHANGED