@economist/web-apple-pay 0.1.3-beta.2 → 0.1.3-beta.20

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 CHANGED
@@ -76,7 +76,512 @@ function ensureApplePayLogoSymbol() {
76
76
  }
77
77
 
78
78
  // src/templates/apple-pay-modal.template.html
79
- var apple_pay_modal_template_default = '<style>\n .apm-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 97;\n background: rgba(13, 13, 13, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wall-gutter, 2rem);\n box-sizing: border-box;\n }\n\n .apm {\n position: relative;\n background: #fff;\n border-radius: 0.5rem 0.5rem 0 0;\n border: 0.0625rem solid #d9d9d9;\n padding: var(--mb-spacing-lg, 1.5rem);\n width: 25rem;\n max-width: 25rem;\n box-sizing: border-box;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n box-shadow: 0 0.25rem 1rem 0 rgba(13, 13, 13, 0.15);\n }\n\n .apm__close {\n position: absolute;\n top: 1.5rem;\n right: 1.3125rem;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .apm__close:focus {\n outline: solid 0.125rem var(--focus-border-color, #121212);\n border-radius: 0.25rem;\n }\n\n .apm__offer-name {\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-title-3-size, 1.25rem);\n font-weight: 500;\n color: var(--mb-colour-greyscale-london-5, #0d0d0d);\n line-height: var(--mb-typestyle-title-3-leading, 1.75rem);\n font-style: normal;\n margin: 0 1.5rem 0.5rem 0;\n }\n\n .apm__due-today {\n color: #1a1a1a;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n font-style: normal;\n font-weight: 400;\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n margin: 0 0 0.75rem 0;\n }\n\n .apm__rule {\n border: none;\n border-top: 0.0625rem solid #d9d9d9;\n margin: 0 0 1rem 0;\n }\n\n .apm__terms {\n color: #1a1a1a;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n font-style: normal;\n font-weight: 400;\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n margin: 0 0 1rem 0;\n }\n\n .apm__terms-bullets {\n list-style: disc outside;\n padding-left: 1.25rem;\n margin: 0 0 0.75rem 0;\n }\n\n .apm__terms-bullets li {\n margin-bottom: 0.375rem;\n }\n\n .apm__terms-legal {\n margin: 0;\n }\n\n .apm__passive-terms {\n font-family: var(--wall-type-system-sans);\n font-size: 0.9375rem;\n color: #0d0d0d;\n line-height: 1.4;\n margin: 0 0 8px 0;\n }\n\n .apm__passive-terms a {\n color: #1a1a1a;\n font-weight: 700;\n text-decoration: underline;\n }\n\n .apm__checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: var(--mb-spacing-sm, 0.5rem);\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n color: var(--mb-colour-greyscale-london-20, #1a1a1a);\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n cursor: pointer;\n margin: 0 0 1.5rem 0;\n }\n\n .apm__checkbox-label--error {\n margin-bottom: 0.25rem;\n }\n\n .apm__checkbox-wrapper {\n position: relative;\n flex-shrink: 0;\n width: 1.25rem;\n height: 1.25rem;\n margin-top: 0.0625rem;\n }\n\n .apm__checkbox-input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n margin: 0;\n z-index: 1;\n }\n\n .apm__checkbox-custom {\n position: absolute;\n top: 0;\n left: 0;\n width: 1.25rem;\n height: 1.25rem;\n pointer-events: none;\n }\n\n .apm__checkbox-custom svg {\n display: none;\n width: 1.25rem;\n height: 1.25rem;\n }\n\n .apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {\n display: block;\n }\n\n .apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {\n display: block;\n }\n\n .apm__checkbox-label--error\n .apm__checkbox-input:not(:checked)\n ~ .apm__checkbox-custom\n .svg-unchecked {\n display: none;\n }\n\n .apm__checkbox-label--error\n .apm__checkbox-input:not(:checked)\n ~ .apm__checkbox-custom\n .svg-error {\n display: block;\n }\n\n .apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {\n outline: solid 0.125rem #c91d42;\n outline-offset: 0.125rem;\n border-radius: 0.25rem;\n }\n\n .apm__checkbox-label a {\n color: #1a1a1a;\n font-weight: 700;\n text-decoration: underline;\n }\n\n .apm__error {\n display: none;\n align-items: center;\n gap: 0.75rem;\n color: var(--mb-colour-greyscale-london-5, #0d0d0d);\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-style: normal;\n font-weight: 500;\n line-height: 1.5rem;\n margin-bottom: 1rem;\n }\n\n .apm__error--visible {\n display: flex;\n }\n\n .apm__cta {\n display: flex;\n width: 100%;\n height: 2.75rem;\n padding: 0.375rem 1rem;\n justify-content: center;\n align-items: center;\n gap: 0.375rem;\n border-radius: 0.25rem;\n background: #000;\n border: none;\n cursor: pointer;\n color: #fff;\n text-align: center;\n font-family: var(\n --mb-typeface-sans,\n var(--wall-type-system-sans, system-ui, sans-serif)\n );\n font-size: 1.25rem;\n font-style: normal;\n font-weight: 500;\n line-height: normal;\n }\n\n .apm__cta svg {\n flex-shrink: 0;\n display: block;\n }\n\n @media (min-width: 22.5rem) and (max-width: 37.5rem) {\n .apm {\n width: 24.375rem;\n max-width: 24.375rem;\n }\n }\n\n @media (min-width: 37.5625rem) {\n .apm {\n border-radius: 0.5rem;\n }\n }\n\n @media (max-width: 22.4375rem) {\n .apm {\n width: 20rem;\n max-width: 20rem;\n }\n }\n\n @media (max-width: 26.1875rem) {\n .apm__cta {\n font-size: 1.125rem;\n }\n }\n</style>\n\n<div class="apm-overlay" id="apple-pay-modal-overlay">\n <div\n class="apm"\n role="dialog"\n aria-modal="true"\n aria-labelledby="apple-pay-modal-offer-name"\n id="apple-pay-modal"\n tabindex="-1"\n >\n <button class="apm__close" id="apple-pay-modal-close" aria-label="Close">\n <svg\n aria-hidden="true"\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n >\n <g clip-path="url(#clip0_15712_93054)">\n <rect width="24" height="24" fill="white" fill-opacity="0.01" />\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M0 0H24V24H0V0Z"\n fill="white"\n fill-opacity="0.01"\n />\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M18.75 6.60964L17.3904 5.25L12 10.6404L6.60964 5.25L5.25 6.60964L10.6404 12L5.25 17.3904L6.60964 18.75L12 13.3596L17.3904 18.75L18.75 17.3904L13.3596 12L18.75 6.60964Z"\n fill="#333333"\n />\n </g>\n <defs>\n <clipPath id="clip0_15712_93054">\n <rect width="24" height="24" fill="white" />\n </clipPath>\n </defs>\n </svg>\n </button>\n <p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>\n <p class="apm__due-today" id="apple-pay-modal-due-today"></p>\n <hr class="apm__rule" />\n <div class="apm__terms" id="apple-pay-modal-terms"></div>\n <p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>\n <label\n class="apm__checkbox-label"\n id="apple-pay-modal-checkbox-label"\n for="apple-pay-modal-checkbox"\n >\n <div class="apm__checkbox-wrapper">\n <input\n class="apm__checkbox-input"\n type="checkbox"\n id="apple-pay-modal-checkbox"\n />\n <span class="apm__checkbox-custom">\n <svg\n aria-hidden="true"\n class="svg-unchecked"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"\n fill="white"\n stroke="#595959"\n />\n </svg>\n <svg\n aria-hidden="true"\n class="svg-checked"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <g clip-path="url(#clip0_20014_9555)">\n <path\n d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"\n fill="#333333"\n />\n <path\n d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"\n fill="white"\n />\n </g>\n <defs>\n <clipPath id="clip0_20014_9555">\n <path\n d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"\n fill="white"\n />\n </clipPath>\n </defs>\n </svg>\n <svg\n aria-hidden="true"\n class="svg-error"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"\n fill="white"\n stroke="#C91D42"\n stroke-width="2"\n />\n </svg>\n </span>\n </div>\n <span id="apple-pay-modal-checkbox-text"></span>\n </label>\n <div class="apm__error" id="apple-pay-modal-error" role="alert">\n <svg\n aria-hidden="true"\n width="20"\n height="20"\n viewBox="0 0 20 20"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10ZM11 13C11 13.5523 10.5523 14 10 14C9.44772 14 9 13.5523 9 13C9 12.4477 9.44772 12 10 12C10.5523 12 11 12.4477 11 13ZM10 6C10.5523 6 11 6.44772 11 7V10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10V7C9 6.44772 9.44772 6 10 6Z"\n fill="#C91D42"\n />\n </svg>\n Please accept the terms to continue\n </div>\n <button class="apm__cta" id="apple-pay-modal-cta">\n Continue with\n <svg width="51" height="22" aria-label="Apple Pay" role="img">\n <use href="#apple-pay-logo" />\n </svg>\n </button>\n </div>\n</div>\n\n';
79
+ var apple_pay_modal_template_default = `<style>
80
+ .apm-overlay {
81
+ position: fixed;
82
+ top: 0;
83
+ left: 0;
84
+ width: 100%;
85
+ height: 100%;
86
+ z-index: 97;
87
+ background: rgba(13, 13, 13, 0.7);
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ padding: var(--wall-gutter, 2rem);
92
+ box-sizing: border-box;
93
+ }
94
+
95
+ .apm {
96
+ position: relative;
97
+ background: #fff;
98
+ border-radius: 0.5rem 0.5rem 0 0;
99
+ border: 0.0625rem solid #d9d9d9;
100
+ padding: var(--mb-spacing-lg, 1.5rem);
101
+ width: 25rem;
102
+ max-width: 25rem;
103
+ box-sizing: border-box;
104
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
105
+ box-shadow: 0 0.25rem 1rem 0 rgba(13, 13, 13, 0.15);
106
+ }
107
+
108
+ .apm__close {
109
+ position: absolute;
110
+ top: 1.5rem;
111
+ right: 1.3125rem;
112
+ background: none;
113
+ border: none;
114
+ cursor: pointer;
115
+ padding: 0;
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ }
120
+
121
+ .apm__close:focus {
122
+ outline: solid 0.125rem var(--focus-border-color, #121212);
123
+ border-radius: 0.25rem;
124
+ }
125
+
126
+ .apm__offer-name {
127
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
128
+ font-size: var(--mb-typestyle-title-3-size, 1.25rem);
129
+ font-weight: 500;
130
+ color: var(--mb-colour-greyscale-london-5, #0d0d0d);
131
+ line-height: var(--mb-typestyle-title-3-leading, 1.75rem);
132
+ font-style: normal;
133
+ margin: 0 1.5rem 0.5rem 0;
134
+ }
135
+
136
+ .apm__due-today {
137
+ color: #1a1a1a;
138
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
139
+ font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
140
+ font-style: normal;
141
+ font-weight: 400;
142
+ line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
143
+ margin: 0 0 0.75rem 0;
144
+ }
145
+
146
+ .apm__rule {
147
+ border: none;
148
+ border-top: 0.0625rem solid #d9d9d9;
149
+ margin: 0 0 1rem 0;
150
+ }
151
+
152
+ .apm__terms {
153
+ color: #1a1a1a;
154
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
155
+ font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
156
+ font-style: normal;
157
+ font-weight: 400;
158
+ line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
159
+ margin: 0 0 1rem 0;
160
+ }
161
+
162
+ .apm__terms-bullets {
163
+ list-style: disc outside;
164
+ padding-left: 1.25rem;
165
+ margin: 0 0 0.75rem 0;
166
+ }
167
+
168
+ .apm__terms-bullets li {
169
+ margin-bottom: 0.375rem;
170
+ }
171
+
172
+ .apm__terms-legal {
173
+ margin: 0;
174
+ }
175
+
176
+ .apm__passive-terms {
177
+ font-family: var(--wall-type-system-sans);
178
+ font-size: 0.9375rem;
179
+ color: #0d0d0d;
180
+ line-height: 1.4;
181
+ margin: 0 0 8px 0;
182
+ }
183
+
184
+ .apm__passive-terms a {
185
+ color: #1a1a1a;
186
+ font-weight: 700;
187
+ text-decoration: underline;
188
+ }
189
+
190
+ .apm__checkbox-label {
191
+ display: flex;
192
+ align-items: flex-start;
193
+ gap: var(--mb-spacing-sm, 0.5rem);
194
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
195
+ font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
196
+ color: var(--mb-colour-greyscale-london-20, #1a1a1a);
197
+ line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
198
+ cursor: pointer;
199
+ margin: 0 0 1.5rem 0;
200
+ }
201
+
202
+ .apm__checkbox-label--error {
203
+ margin-bottom: 0.25rem;
204
+ }
205
+
206
+ .apm__checkbox-wrapper {
207
+ position: relative;
208
+ flex-shrink: 0;
209
+ width: 1.25rem;
210
+ height: 1.25rem;
211
+ margin-top: 0.0625rem;
212
+ }
213
+
214
+ .apm__checkbox-input {
215
+ position: absolute;
216
+ opacity: 0;
217
+ width: 100%;
218
+ height: 100%;
219
+ cursor: pointer;
220
+ margin: 0;
221
+ z-index: 1;
222
+ }
223
+
224
+ .apm__checkbox-custom {
225
+ position: absolute;
226
+ top: 0;
227
+ left: 0;
228
+ width: 1.25rem;
229
+ height: 1.25rem;
230
+ pointer-events: none;
231
+ }
232
+
233
+ .apm__checkbox-custom svg {
234
+ display: none;
235
+ width: 1.25rem;
236
+ height: 1.25rem;
237
+ }
238
+
239
+ .apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {
240
+ display: block;
241
+ }
242
+
243
+ .apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {
244
+ display: block;
245
+ }
246
+
247
+ .apm__checkbox-label--error
248
+ .apm__checkbox-input:not(:checked)
249
+ ~ .apm__checkbox-custom
250
+ .svg-unchecked {
251
+ display: none;
252
+ }
253
+
254
+ .apm__checkbox-label--error
255
+ .apm__checkbox-input:not(:checked)
256
+ ~ .apm__checkbox-custom
257
+ .svg-error {
258
+ display: block;
259
+ }
260
+
261
+ .apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {
262
+ outline: solid 0.125rem #c91d42;
263
+ outline-offset: 0.125rem;
264
+ border-radius: 0.25rem;
265
+ }
266
+
267
+ .apm__checkbox-label a {
268
+ color: #1a1a1a;
269
+ font-weight: 700;
270
+ text-decoration: underline;
271
+ }
272
+
273
+ .apm__error {
274
+ display: none;
275
+ align-items: center;
276
+ gap: 0.75rem;
277
+ color: var(--mb-colour-greyscale-london-5, #0d0d0d);
278
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
279
+ font-size: 1.0625rem;
280
+ font-style: normal;
281
+ font-weight: 500;
282
+ line-height: 1.5rem;
283
+ margin-bottom: 1rem;
284
+ }
285
+
286
+ .apm__error--visible {
287
+ display: flex;
288
+ }
289
+
290
+ .apm__cta {
291
+ display: flex;
292
+ width: 100%;
293
+ height: 2.75rem;
294
+ padding: 0.375rem 1rem;
295
+ justify-content: center;
296
+ align-items: center;
297
+ gap: 0.375rem;
298
+ border-radius: 0.25rem;
299
+ background: #000;
300
+ border: none;
301
+ cursor: pointer;
302
+ color: #fff;
303
+ text-align: center;
304
+ font-family: var(
305
+ --mb-typeface-sans,
306
+ var(--wall-type-system-sans, system-ui, sans-serif)
307
+ );
308
+ font-size: 1.25rem;
309
+ font-style: normal;
310
+ font-weight: 500;
311
+ line-height: normal;
312
+ }
313
+
314
+ .apm__cta:disabled {
315
+ cursor: not-allowed;
316
+ }
317
+
318
+ .apm__cta[aria-busy="true"] {
319
+ position: relative;
320
+ cursor: not-allowed;
321
+ }
322
+
323
+ .apm__cta[aria-busy="true"] > * {
324
+ visibility: hidden;
325
+ }
326
+
327
+ .apm__cta[aria-busy="true"]::after {
328
+ content: '';
329
+ position: absolute;
330
+ left: 50%;
331
+ top: 50%;
332
+ margin-left: -0.625rem;
333
+ margin-top: -0.625rem;
334
+ width: 1.25rem;
335
+ height: 1.25rem;
336
+ border: 2px solid rgba(255, 255, 255, 0.2);
337
+ border-top-color: #fff;
338
+ border-radius: 50%;
339
+ animation: apm-cta-spinner 0.8s linear infinite;
340
+ }
341
+
342
+ @keyframes apm-cta-spinner {
343
+ to {
344
+ transform: rotate(360deg);
345
+ }
346
+ }
347
+
348
+ .apm__cta svg {
349
+ flex-shrink: 0;
350
+ display: block;
351
+ }
352
+
353
+ @media (min-width: 22.5rem) and (max-width: 37.5rem) {
354
+ .apm {
355
+ width: 24.375rem;
356
+ max-width: 24.375rem;
357
+ }
358
+ }
359
+
360
+ @media (min-width: 37.5625rem) {
361
+ .apm {
362
+ border-radius: 0.5rem;
363
+ }
364
+ }
365
+
366
+ @media (max-width: 22.4375rem) {
367
+ .apm {
368
+ width: 20rem;
369
+ max-width: 20rem;
370
+ }
371
+ }
372
+
373
+ @media (max-width: 26.1875rem) {
374
+ .apm__cta {
375
+ font-size: 1.125rem;
376
+ }
377
+ }
378
+ </style>
379
+
380
+ <div class="apm-overlay" id="apple-pay-modal-overlay">
381
+ <div
382
+ class="apm"
383
+ role="dialog"
384
+ aria-modal="true"
385
+ aria-labelledby="apple-pay-modal-offer-name"
386
+ id="apple-pay-modal"
387
+ tabindex="-1"
388
+ >
389
+ <button class="apm__close" id="apple-pay-modal-close" aria-label="Close">
390
+ <svg
391
+ aria-hidden="true"
392
+ xmlns="http://www.w3.org/2000/svg"
393
+ width="24"
394
+ height="24"
395
+ viewBox="0 0 24 24"
396
+ fill="none"
397
+ >
398
+ <g clip-path="url(#clip0_15712_93054)">
399
+ <rect width="24" height="24" fill="white" fill-opacity="0.01" />
400
+ <path
401
+ fill-rule="evenodd"
402
+ clip-rule="evenodd"
403
+ d="M0 0H24V24H0V0Z"
404
+ fill="white"
405
+ fill-opacity="0.01"
406
+ />
407
+ <path
408
+ fill-rule="evenodd"
409
+ clip-rule="evenodd"
410
+ d="M18.75 6.60964L17.3904 5.25L12 10.6404L6.60964 5.25L5.25 6.60964L10.6404 12L5.25 17.3904L6.60964 18.75L12 13.3596L17.3904 18.75L18.75 17.3904L13.3596 12L18.75 6.60964Z"
411
+ fill="#333333"
412
+ />
413
+ </g>
414
+ <defs>
415
+ <clipPath id="clip0_15712_93054">
416
+ <rect width="24" height="24" fill="white" />
417
+ </clipPath>
418
+ </defs>
419
+ </svg>
420
+ </button>
421
+ <p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>
422
+ <p class="apm__due-today" id="apple-pay-modal-due-today"></p>
423
+ <hr class="apm__rule" />
424
+ <div class="apm__terms" id="apple-pay-modal-terms"></div>
425
+ <p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>
426
+ <label
427
+ class="apm__checkbox-label"
428
+ id="apple-pay-modal-checkbox-label"
429
+ for="apple-pay-modal-checkbox"
430
+ >
431
+ <div class="apm__checkbox-wrapper">
432
+ <input
433
+ class="apm__checkbox-input"
434
+ type="checkbox"
435
+ id="apple-pay-modal-checkbox"
436
+ />
437
+ <span class="apm__checkbox-custom">
438
+ <svg
439
+ aria-hidden="true"
440
+ class="svg-unchecked"
441
+ width="24"
442
+ height="24"
443
+ viewBox="0 0 24 24"
444
+ fill="none"
445
+ xmlns="http://www.w3.org/2000/svg"
446
+ >
447
+ <path
448
+ d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"
449
+ fill="white"
450
+ stroke="#595959"
451
+ />
452
+ </svg>
453
+ <svg
454
+ aria-hidden="true"
455
+ class="svg-checked"
456
+ width="24"
457
+ height="24"
458
+ viewBox="0 0 24 24"
459
+ fill="none"
460
+ xmlns="http://www.w3.org/2000/svg"
461
+ >
462
+ <g clip-path="url(#clip0_20014_9555)">
463
+ <path
464
+ d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"
465
+ fill="#333333"
466
+ />
467
+ <path
468
+ d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"
469
+ fill="white"
470
+ />
471
+ </g>
472
+ <defs>
473
+ <clipPath id="clip0_20014_9555">
474
+ <path
475
+ d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"
476
+ fill="white"
477
+ />
478
+ </clipPath>
479
+ </defs>
480
+ </svg>
481
+ <svg
482
+ aria-hidden="true"
483
+ class="svg-error"
484
+ width="24"
485
+ height="24"
486
+ viewBox="0 0 24 24"
487
+ fill="none"
488
+ xmlns="http://www.w3.org/2000/svg"
489
+ >
490
+ <path
491
+ d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"
492
+ fill="white"
493
+ stroke="#C91D42"
494
+ stroke-width="2"
495
+ />
496
+ </svg>
497
+ </span>
498
+ </div>
499
+ <span id="apple-pay-modal-checkbox-text"></span>
500
+ </label>
501
+ <div class="apm__error" id="apple-pay-modal-error" role="alert">
502
+ <svg
503
+ aria-hidden="true"
504
+ width="20"
505
+ height="20"
506
+ viewBox="0 0 20 20"
507
+ fill="none"
508
+ xmlns="http://www.w3.org/2000/svg"
509
+ >
510
+ <path
511
+ fill-rule="evenodd"
512
+ clip-rule="evenodd"
513
+ d="M10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10ZM11 13C11 13.5523 10.5523 14 10 14C9.44772 14 9 13.5523 9 13C9 12.4477 9.44772 12 10 12C10.5523 12 11 12.4477 11 13ZM10 6C10.5523 6 11 6.44772 11 7V10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10V7C9 6.44772 9.44772 6 10 6Z"
514
+ fill="#C91D42"
515
+ />
516
+ </svg>
517
+ Please accept the terms to continue
518
+ </div>
519
+ <button class="apm__cta" id="apple-pay-modal-cta">
520
+ Continue with
521
+ <svg width="51" height="22" aria-label="Apple Pay" role="img">
522
+ <use href="#apple-pay-logo" />
523
+ </svg>
524
+ </button>
525
+ </div>
526
+ </div>
527
+
528
+ `;
529
+
530
+ // src/clients/payment-checkout/config.ts
531
+ var runtimeConfig = null;
532
+ var configureApplePay = (config) => {
533
+ runtimeConfig = {
534
+ ...config
535
+ };
536
+ };
537
+ var getApplePayConfig = () => runtimeConfig;
538
+
539
+ // src/utils/recaptcha.ts
540
+ var loadRecaptchaScript = (siteKey) => {
541
+ return new Promise((resolve, reject) => {
542
+ if (typeof grecaptcha !== "undefined") return resolve();
543
+ const existingScript = document.querySelector(
544
+ 'script[src*="recaptcha/api.js"]'
545
+ );
546
+ if (existingScript) {
547
+ existingScript.addEventListener("load", () => resolve());
548
+ existingScript.addEventListener(
549
+ "error",
550
+ () => reject(new Error("Failed to load existing reCAPTCHA script"))
551
+ );
552
+ return;
553
+ }
554
+ const script = document.createElement("script");
555
+ script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
556
+ script.async = true;
557
+ script.defer = true;
558
+ script.onload = () => resolve();
559
+ script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
560
+ document.head.appendChild(script);
561
+ });
562
+ };
563
+ var getRecaptchaToken = async (action) => {
564
+ const siteKey = getApplePayConfig()?.recaptchaSiteKey;
565
+ if (!siteKey) {
566
+ throw new Error(
567
+ "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
568
+ );
569
+ }
570
+ await loadRecaptchaScript(siteKey);
571
+ return new Promise((resolve, reject) => {
572
+ grecaptcha.ready(() => {
573
+ grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
574
+ });
575
+ });
576
+ };
577
+ var getPurchaseRecaptchaTokens = async () => {
578
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
579
+ getRecaptchaToken("checkEligibility"),
580
+ getRecaptchaToken("newBasket"),
581
+ getRecaptchaToken("registerUser")
582
+ ]);
583
+ return { checkEligibility, newBasket, registerUser };
584
+ };
80
585
 
81
586
  // src/apple-pay-modal.ts
82
587
  function getRenewalDateText(unit, duration) {
@@ -297,6 +802,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
297
802
  #country = "";
298
803
  #triggerElement = null;
299
804
  #keyHandler = null;
805
+ #recaptchaTokens = null;
806
+ #recaptchaTokensPromise = null;
807
+ /**
808
+ * Synchronous callback invoked directly from the CTA click handler once the
809
+ * user confirms. The caller (ApplePayButton) must call startApplePaySession
810
+ * inside this callback to preserve the browser's user-gesture chain — Safari
811
+ * requires new ApplePaySession() to execute within the original click stack.
812
+ *
813
+ * reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
814
+ * until the token pre-fetch resolves, so this callback is never reached
815
+ * without valid tokens.
816
+ */
817
+ onConfirm = null;
300
818
  set offer(value) {
301
819
  this.#offer = value;
302
820
  }
@@ -391,19 +909,32 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
391
909
  }
392
910
  });
393
911
  }
912
+ if (this.#recaptchaTokensPromise) {
913
+ if (cta) {
914
+ cta.setAttribute("disabled", "");
915
+ cta.setAttribute("aria-disabled", "true");
916
+ cta.setAttribute("aria-busy", "true");
917
+ }
918
+ this.#recaptchaTokensPromise.then((tokens) => {
919
+ this.#recaptchaTokens = tokens;
920
+ if (cta) {
921
+ cta.removeAttribute("disabled");
922
+ cta.removeAttribute("aria-disabled");
923
+ cta.removeAttribute("aria-busy");
924
+ }
925
+ }).catch(() => {
926
+ console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
927
+ });
928
+ }
394
929
  cta?.addEventListener("click", () => {
395
930
  if (isUS && checkbox && !checkbox.checked) {
396
931
  errorElement?.classList.add("apm__error--visible");
397
932
  checkboxLabel?.classList.add("apm__checkbox-label--error");
398
933
  return;
399
934
  }
400
- this.dispatchEvent(
401
- new CustomEvent("apple-pay-confirmed", {
402
- bubbles: true,
403
- composed: true,
404
- detail: { skuId: offer.sku_id, country }
405
- })
406
- );
935
+ if (this.#recaptchaTokens) {
936
+ this.onConfirm?.(this.#recaptchaTokens);
937
+ }
407
938
  this.close();
408
939
  });
409
940
  this.querySelector("#apple-pay-modal-close")?.addEventListener(
@@ -411,7 +942,8 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
411
942
  () => this.close()
412
943
  );
413
944
  }
414
- open() {
945
+ open(recaptchaTokensPromise) {
946
+ this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
415
947
  this.#triggerElement = document.activeElement;
416
948
  document.body.appendChild(this);
417
949
  this.#keyHandler = (event) => {
@@ -524,21 +1056,6 @@ var apple_pay_button_template_default = `<style>
524
1056
  </div>
525
1057
  `;
526
1058
 
527
- // src/clients/payment-checkout/config.ts
528
- var runtimeConfig = null;
529
- var configureApplePay = (config) => {
530
- console.log("[web-apple-pay] configureApplePay called", {
531
- merchantId: config.merchantId,
532
- walletApiBaseUrl: config.walletApiBaseUrl,
533
- debugBypassEnabled: config.debugBypassEnabled,
534
- recaptchaSiteKey: config.recaptchaSiteKey ? "***" : void 0
535
- });
536
- runtimeConfig = {
537
- ...config
538
- };
539
- };
540
- var getApplePayConfig = () => runtimeConfig;
541
-
542
1059
  // src/clients/payment-checkout/detects.ts
543
1060
  var isAppleDeviceOrSafari = () => {
544
1061
  const isIOSOrMacTouchDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent);
@@ -547,27 +1064,21 @@ var isAppleDeviceOrSafari = () => {
547
1064
  };
548
1065
  var bypassApplePayChecks = () => new URLSearchParams(window.location.search).get("BYPASS_APPLE_PAY_CHECKS") !== null && getApplePayConfig()?.debugBypassEnabled === true;
549
1066
  var isApplePayAvailable = async () => {
550
- console.log("[web-apple-pay] isApplePayAvailable: checking availability");
551
1067
  if (bypassApplePayChecks()) {
552
- console.log("[web-apple-pay] isApplePayAvailable: bypass active \u2192 true");
553
1068
  return true;
554
1069
  }
555
1070
  if (!isAppleDeviceOrSafari()) {
556
- console.log("[web-apple-pay] isApplePayAvailable: not Apple device or Safari \u2192 false");
557
1071
  return false;
558
1072
  }
559
1073
  const applePaySession = window.ApplePaySession;
560
1074
  if (!applePaySession) {
561
- console.log("[web-apple-pay] isApplePayAvailable: ApplePaySession not found on window \u2192 false");
562
1075
  return false;
563
1076
  }
564
1077
  try {
565
1078
  if (typeof applePaySession.canMakePayments !== "function") {
566
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments is not a function \u2192 false");
567
1079
  return false;
568
1080
  }
569
1081
  if (!applePaySession.canMakePayments()) {
570
- console.log("[web-apple-pay] isApplePayAvailable: canMakePayments() returned false \u2192 false");
571
1082
  return false;
572
1083
  }
573
1084
  const merchantId = getApplePayConfig()?.merchantId;
@@ -577,10 +1088,8 @@ var isApplePayAvailable = async () => {
577
1088
  );
578
1089
  return false;
579
1090
  }
580
- console.log("[web-apple-pay] isApplePayAvailable : calling canMakePaymentsWithActiveCard", { merchantId });
581
- const result = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
582
- console.log("[web-apple-pay] isApplePayAvailable: canMakePaymentsWithActiveCard \u2192", result);
583
- return result;
1091
+ const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1092
+ return hasActiveCard;
584
1093
  } catch (error) {
585
1094
  console.error("Error checking Apple Pay active card status:", error);
586
1095
  return false;
@@ -679,8 +1188,11 @@ var buildQueryString = () => {
679
1188
  };
680
1189
  var decodeSku = (sku) => {
681
1190
  try {
682
- return atob(sku.substring(sku.indexOf("-") + 1));
683
- } catch {
1191
+ const decoded = atob(sku.substring(sku.indexOf("-") + 1));
1192
+ console.log("[web-apple-pay] decodeSku", { input: sku, decoded });
1193
+ return decoded;
1194
+ } catch (err) {
1195
+ console.warn("[web-apple-pay] decodeSku: failed to decode, returning raw", { input: sku, err });
684
1196
  return sku;
685
1197
  }
686
1198
  };
@@ -698,64 +1210,23 @@ var redirectToCheckoutComplete = (params) => {
698
1210
  return url.pathname + url.search;
699
1211
  };
700
1212
  var redirectToCheckoutFallback = (params) => {
1213
+ const decodedOffer = decodeSku(params.skuId);
1214
+ console.log("[web-apple-pay] redirectToCheckoutFallback", {
1215
+ rawSkuId: params.skuId,
1216
+ decodedOffer
1217
+ });
701
1218
  const url = new URL(window.location.href);
702
1219
  url.pathname = "/checkout";
703
- url.searchParams.set("lmo_offer", params.skuId);
1220
+ url.searchParams.set("lmo_offer", decodedOffer);
704
1221
  if (params.inlineError)
705
1222
  url.searchParams.set("inlineError", params.inlineError);
706
1223
  if (params.email) url.searchParams.set("email", params.email);
707
1224
  if (params.emailError) url.searchParams.set("emailError", params.emailError);
708
1225
  url.searchParams.set("returnUrl", params.returnUrl);
1226
+ console.log("[web-apple-pay] fallback redirect URL", url.pathname + url.search);
709
1227
  return url.pathname + url.search;
710
1228
  };
711
1229
 
712
- // src/utils/recaptcha.ts
713
- var loadRecaptchaScript = (siteKey) => {
714
- return new Promise((resolve, reject) => {
715
- if (typeof grecaptcha !== "undefined") return resolve();
716
- const existingScript = document.querySelector(
717
- 'script[src*="recaptcha/api.js"]'
718
- );
719
- if (existingScript) {
720
- existingScript.addEventListener("load", () => resolve());
721
- existingScript.addEventListener(
722
- "error",
723
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
724
- );
725
- return;
726
- }
727
- const script = document.createElement("script");
728
- script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
729
- script.async = true;
730
- script.defer = true;
731
- script.onload = () => resolve();
732
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
733
- document.head.appendChild(script);
734
- });
735
- };
736
- var getRecaptchaToken = async (action) => {
737
- const siteKey = getApplePayConfig()?.recaptchaSiteKey;
738
- if (!siteKey) {
739
- throw new Error(
740
- "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
741
- );
742
- }
743
- await loadRecaptchaScript(siteKey);
744
- return new Promise((resolve, reject) => {
745
- grecaptcha.ready(() => {
746
- grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
747
- });
748
- });
749
- };
750
- var getPurchaseRecaptchaTokens = async () => {
751
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
752
- getRecaptchaToken("checkEligibility"),
753
- getRecaptchaToken("newBasket"),
754
- getRecaptchaToken("registerUser")
755
- ]);
756
- return { checkEligibility, newBasket, registerUser };
757
- };
758
-
759
1230
  // src/utils/expressCheckoutTracking.ts
760
1231
  var EXPRESS_CHECKOUT_EVENTS = {
761
1232
  /** Wallet button displayed */
@@ -842,11 +1313,6 @@ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
842
1313
 
843
1314
  // src/clients/payment-checkout/apple-session.ts
844
1315
  function redirectToFallbackCheckout(config) {
845
- console.warn("[web-apple-pay] redirectToFallbackCheckout", {
846
- skuId: config.skuId,
847
- returnUrl: config.returnUrl,
848
- inlineError: MSG_PAYMENT_GENERIC_ERROR
849
- });
850
1316
  trackFallbackCheckout(config.skuId);
851
1317
  window.location.href = redirectToCheckoutFallback({
852
1318
  skuId: config.skuId,
@@ -855,59 +1321,31 @@ function redirectToFallbackCheckout(config) {
855
1321
  });
856
1322
  }
857
1323
  async function handleMerchantValidation(event, session, config) {
858
- console.log("[web-apple-pay] handleMerchantValidation: start", {
859
- skuId: config.skuId,
860
- validationURL: event.validationURL
861
- });
862
1324
  try {
863
1325
  const validationHost = new URL(event.validationURL).host;
864
- console.log("[web-apple-pay] handleMerchantValidation: host parsed", {
865
- validationHost
866
- });
867
1326
  if (!validationHost.endsWith("apple.com")) {
868
- console.warn(
869
- "[web-apple-pay] handleMerchantValidation: invalid validation host",
870
- { validationHost }
871
- );
872
1327
  session.abort();
873
1328
  redirectToFallbackCheckout(config);
874
1329
  return;
875
1330
  }
876
- console.log("[web-apple-pay] handleMerchantValidation: requesting recaptcha token");
877
1331
  const recaptchaToken = await getRecaptchaToken("verifyMerchant");
878
- console.log("[web-apple-pay] handleMerchantValidation: recaptcha token received");
879
1332
  const response = await validateAppleMerchant({
880
1333
  validationURL: event.validationURL,
881
1334
  recaptchaToken
882
1335
  });
883
1336
  if (!response?.merchantSession) {
884
- console.warn(
885
- "[web-apple-pay] handleMerchantValidation: missing merchantSession in response"
886
- );
887
1337
  session.abort();
888
1338
  redirectToFallbackCheckout(config);
889
1339
  return;
890
1340
  }
891
- console.log("[web-apple-pay] handleMerchantValidation: completing merchant validation");
892
1341
  session.completeMerchantValidation(response.merchantSession);
893
- console.log("[web-apple-pay] handleMerchantValidation: success");
894
1342
  } catch (err) {
895
- console.error("[web-apple-pay] handleMerchantValidation: failed", {
896
- skuId: config.skuId,
897
- err
898
- });
1343
+ console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
899
1344
  session.abort();
900
1345
  redirectToFallbackCheckout(config);
901
1346
  }
902
1347
  }
903
1348
  function startApplePaySession(config) {
904
- console.log("[web-apple-pay] startApplePaySession", {
905
- skuId: config.skuId,
906
- countryCode: config.countryCode,
907
- currencyCode: config.currencyCode,
908
- totalAmount: config.totalAmount,
909
- userLoggedIn: config.userLoggedIn
910
- });
911
1349
  const paymentRequest = {
912
1350
  countryCode: config.countryCode,
913
1351
  currencyCode: config.currencyCode,
@@ -921,43 +1359,22 @@ function startApplePaySession(config) {
921
1359
  // Only request email from Apple Pay sheet if user is NOT logged in
922
1360
  ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
923
1361
  };
924
- console.log("[web-apple-pay] startApplePaySession: payment request created", {
925
- skuId: config.skuId,
926
- requiredShippingContactFields: paymentRequest.requiredShippingContactFields
927
- });
928
1362
  try {
929
1363
  const session = new ApplePaySession(3, paymentRequest);
930
- console.log("[web-apple-pay] startApplePaySession: ApplePaySession created");
931
1364
  session.onvalidatemerchant = async (event) => {
932
- console.log("[web-apple-pay] onvalidatemerchant: invoked", {
933
- skuId: config.skuId
934
- });
935
1365
  await handleMerchantValidation(event, session, config);
936
1366
  };
937
1367
  session.onpaymentauthorized = (event) => {
938
- console.log("[web-apple-pay] onpaymentauthorized: invoked", {
939
- skuId: config.skuId
940
- });
941
1368
  trackWalletPaymentAuthorised(config.skuId);
942
1369
  config.onPaymentAuthorized(event, session);
943
1370
  };
944
1371
  session.oncancel = () => {
945
- console.log("[web-apple-pay] oncancel: invoked", {
946
- skuId: config.skuId
947
- });
948
1372
  config.onCancel?.();
949
1373
  };
950
- console.log("[web-apple-pay] startApplePaySession: opening payment sheet", {
951
- skuId: config.skuId
952
- });
953
1374
  trackWalletPaymentSheetOpen(config.skuId);
954
1375
  session.begin();
955
- console.log("[web-apple-pay] startApplePaySession: session begin called");
956
1376
  } catch (err) {
957
- console.error("[web-apple-pay] startApplePaySession: failed to start session", {
958
- skuId: config.skuId,
959
- err
960
- });
1377
+ console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
961
1378
  redirectToFallbackCheckout(config);
962
1379
  }
963
1380
  }
@@ -1048,25 +1465,13 @@ var billingContactDetails = (contact, supportedBillingCountries) => {
1048
1465
  // src/clients/payment-checkout/shipping-contact-details.ts
1049
1466
  var EMAIL_FORMAT_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1050
1467
  var shippingContactDetails = (shippingContact) => {
1051
- console.log("[web-apple-pay] shippingContactDetails: start", {
1052
- hasShippingContact: Boolean(shippingContact),
1053
- hasEmailAddress: shippingContact?.emailAddress !== void 0
1054
- });
1055
1468
  const errors = [];
1056
1469
  let emailAddress = "";
1057
1470
  if (shippingContact?.emailAddress === void 0 || shippingContact?.emailAddress === "") {
1058
- console.log(
1059
- "[web-apple-pay] shippingContactDetails: email missing or empty"
1060
- );
1061
1471
  pushRequiredFieldError(errors, "shipping", "emailAddress");
1062
1472
  } else {
1063
- console.log("[web-apple-pay] shippingContactDetails: email provided");
1064
1473
  emailAddress = shippingContact.emailAddress.trim();
1065
- console.log("[web-apple-pay] shippingContactDetails: email trimmed", {
1066
- emailLength: emailAddress.length
1067
- });
1068
1474
  if (emailAddress.length > 80) {
1069
- console.log("[web-apple-pay] shippingContactDetails: email too long");
1070
1475
  pushFieldError(
1071
1476
  errors,
1072
1477
  "shipping",
@@ -1075,9 +1480,6 @@ var shippingContactDetails = (shippingContact) => {
1075
1480
  MSG_EMAIL_TOO_LONG
1076
1481
  );
1077
1482
  } else if (!EMAIL_FORMAT_REGEX.test(emailAddress)) {
1078
- console.log(
1079
- "[web-apple-pay] shippingContactDetails: email format invalid"
1080
- );
1081
1483
  pushFieldError(
1082
1484
  errors,
1083
1485
  "shipping",
@@ -1085,17 +1487,11 @@ var shippingContactDetails = (shippingContact) => {
1085
1487
  "format",
1086
1488
  MSG_EMAIL_WRONG_FORMAT
1087
1489
  );
1088
- } else {
1089
- console.log("[web-apple-pay] shippingContactDetails: email valid");
1090
1490
  }
1091
1491
  }
1092
1492
  if (errors.length > 0) {
1093
- console.log("[web-apple-pay] shippingContactDetails: throwing validation error", {
1094
- errorCount: errors.length
1095
- });
1096
1493
  throw new ContactValidationError(errors);
1097
1494
  }
1098
- console.log("[web-apple-pay] shippingContactDetails: success");
1099
1495
  return { emailAddress };
1100
1496
  };
1101
1497
 
@@ -1126,6 +1522,7 @@ function validateContacts(event, sessionData, supportedBillingCountries) {
1126
1522
  return void 0;
1127
1523
  }
1128
1524
  function redirectFallback(skuId, returnUrl, options) {
1525
+ console.log("[web-apple-pay] redirectFallback called", { skuId, returnUrl, options });
1129
1526
  trackFallbackCheckout(skuId);
1130
1527
  window.location.href = redirectToCheckoutFallback({
1131
1528
  skuId,
@@ -1157,27 +1554,22 @@ function handleStructuredError(ctx) {
1157
1554
  async function handlePaymentAuthorized(event, session, sessionData, config) {
1158
1555
  const { skuId, returnUrl, queryString } = config;
1159
1556
  let validatedEmail;
1160
- console.log("[web-apple-pay] handlePaymentAuthorized: starting", { skuId, userLoggedIn: sessionData.loggedIn });
1161
1557
  try {
1162
- console.log("[web-apple-pay] handlePaymentAuthorized: step 1 \u2014 validating contacts");
1163
1558
  validatedEmail = validateContacts(
1164
1559
  event,
1165
1560
  sessionData,
1166
1561
  config.supportedBillingCountries
1167
1562
  );
1168
- console.log("[web-apple-pay] handlePaymentAuthorized: contacts valid", { validatedEmail });
1169
- console.log("[web-apple-pay] handlePaymentAuthorized: step 2 \u2014 calling performPurchase", { skuId });
1170
1563
  const result = await performPurchase({
1171
1564
  applePayToken: event.payment.token,
1172
1565
  skuId: config.skuId,
1566
+ currency: config.currency,
1173
1567
  billingContact: event.payment.billingContact,
1174
1568
  ...event.payment.shippingContact && {
1175
1569
  shippingContact: event.payment.shippingContact
1176
1570
  },
1177
1571
  recaptchaTokens: config.recaptchaTokens
1178
1572
  });
1179
- console.log("[web-apple-pay] handlePaymentAuthorized: performPurchase succeeded", { basketId: result.basketId });
1180
- console.log("[web-apple-pay] handlePaymentAuthorized: step 3 \u2014 completing payment and redirecting");
1181
1573
  trackWalletPaymentSuccess(skuId, result.basketId);
1182
1574
  session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1183
1575
  const userStatus = sessionData.loggedIn ? "lex" : "nex";
@@ -1190,25 +1582,17 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1190
1582
  });
1191
1583
  } catch (err) {
1192
1584
  if (err instanceof ContactValidationError) {
1193
- console.warn("[web-apple-pay] handlePaymentAuthorized: contact validation failed", err.errors);
1194
1585
  failApplePaySession(session, err.errors);
1195
1586
  return;
1196
1587
  }
1197
1588
  console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1198
1589
  const walletError = parseWalletApiError(err);
1199
- console.error("[web-apple-pay] handlePaymentAuthorized: BFF/network error", {
1200
- skuId,
1201
- errorType: walletError?.errorType ?? "UNKNOWN",
1202
- message: walletError?.message
1203
- });
1204
1590
  trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1205
1591
  failApplePaySession(session);
1206
1592
  if (!walletError) {
1207
- console.warn("[web-apple-pay] handlePaymentAuthorized: unstructured error, using generic fallback");
1208
1593
  redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1209
1594
  return;
1210
1595
  }
1211
- console.log("[web-apple-pay] handlePaymentAuthorized: dispatching structured error handler", { errorType: walletError.errorType });
1212
1596
  handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1213
1597
  }
1214
1598
  }
@@ -1530,7 +1914,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1530
1914
  #returnUrl = "";
1531
1915
  #supportedBillingCountries = [];
1532
1916
  #entryPoint = "";
1533
- #recaptchaTokens = null;
1917
+ #recaptchaTokensPromise = null;
1534
1918
  // ─── Public API ─────────────────────────────────────────────────────────────
1535
1919
  get offer() {
1536
1920
  return this.#offer;
@@ -1595,6 +1979,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1595
1979
  this.#paymentOptions = null;
1596
1980
  this.#returnUrl = "";
1597
1981
  this.#supportedBillingCountries = [];
1982
+ this.#recaptchaTokensPromise = null;
1598
1983
  this.querySelector(SEL_CONTAINER)?.remove();
1599
1984
  }
1600
1985
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -1608,7 +1993,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1608
1993
  this.#computeBillingCountries();
1609
1994
  if (await this.#fetchAndCacheOptions()) return;
1610
1995
  this.#finishLoading();
1611
- } catch {
1996
+ } catch (err) {
1997
+ console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
1612
1998
  this.style.display = "none";
1613
1999
  this.querySelector(SEL_CONTAINER)?.remove();
1614
2000
  } finally {
@@ -1689,16 +2075,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1689
2075
  if (button.classList.contains("wap-loading")) return;
1690
2076
  this.#openModal();
1691
2077
  });
1692
- document.addEventListener("apple-pay-confirmed", (event) => {
1693
- const { skuId, country } = event.detail;
1694
- this.#initiateApplePay(skuId, country);
1695
- }, { once: true });
1696
2078
  }
1697
2079
  #finishLoading() {
1698
2080
  const button = this.querySelector(SEL_BUTTON);
1699
2081
  if (button) {
1700
2082
  button.classList.remove("wap-loading");
1701
2083
  this.#updateDisabledState();
2084
+ this.#recaptchaTokensPromise = getPurchaseRecaptchaTokens();
1702
2085
  trackExpressWalletImpression(this.#offer.sku_id, {
1703
2086
  entryPoint: this.#entryPoint,
1704
2087
  country: this.#country
@@ -1726,10 +2109,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1726
2109
  return;
1727
2110
  }
1728
2111
  trackExpressWalletClick(this.#offer.sku_id);
1729
- getPurchaseRecaptchaTokens().then((tokens) => {
1730
- this.#recaptchaTokens = tokens;
1731
- }).catch(() => {
1732
- });
1733
2112
  ApplePayModal.define();
1734
2113
  const modal = document.createElement(ApplePayModal.tag);
1735
2114
  modal.offer = this.#offer;
@@ -1737,7 +2116,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1737
2116
  if (this.#sessionData?.loggedIn) {
1738
2117
  modal.dataset.loggedIn = "true";
1739
2118
  }
1740
- modal.open();
2119
+ const skuId = this.#offer.sku_id;
2120
+ const country = this.#country;
2121
+ modal.onConfirm = (recaptchaTokens) => {
2122
+ this.#initiateApplePay(skuId, country, recaptchaTokens);
2123
+ this.#recaptchaTokensPromise = getPurchaseRecaptchaTokens();
2124
+ };
2125
+ modal.open(this.#recaptchaTokensPromise);
1741
2126
  }
1742
2127
  async #fetchSession() {
1743
2128
  try {
@@ -1773,6 +2158,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1773
2158
  onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
1774
2159
  skuId,
1775
2160
  country,
2161
+ currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1776
2162
  returnUrl: this.#returnUrl,
1777
2163
  queryString: buildQueryString(),
1778
2164
  supportedBillingCountries: this.#supportedBillingCountries,
@@ -1780,11 +2166,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1780
2166
  })
1781
2167
  };
1782
2168
  }
1783
- async #initiateApplePay(skuId, country) {
2169
+ #initiateApplePay(skuId, country, recaptchaTokens) {
1784
2170
  try {
1785
2171
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1786
2172
  const paymentOptions = this.#paymentOptions;
1787
- const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1788
2173
  startApplePaySession(
1789
2174
  this.#buildSessionParams(
1790
2175
  skuId,