@economist/web-apple-pay 1.5.0 → 1.6.0

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.
Files changed (33) hide show
  1. package/dist/index.js +963 -367
  2. package/dist/src/apple-pay-button.d.ts +13 -1
  3. package/dist/src/apple-pay-button.js +963 -367
  4. package/dist/src/apple-pay-button.stories.js +970 -383
  5. package/dist/src/apple-pay-modal.js +18 -316
  6. package/dist/src/apple-pay-modal.stories.js +963 -367
  7. package/dist/src/clients/payment-checkout/apple-session.d.ts +18 -0
  8. package/dist/src/clients/payment-checkout/apple-session.js +227 -0
  9. package/dist/src/clients/payment-checkout/billing-contact-details.d.ts +21 -0
  10. package/dist/src/clients/payment-checkout/billing-contact-details.js +109 -0
  11. package/dist/src/clients/payment-checkout/config.d.ts +1 -0
  12. package/dist/src/clients/payment-checkout/contact-validation.d.ts +21 -0
  13. package/dist/src/clients/payment-checkout/contact-validation.js +50 -0
  14. package/dist/src/clients/payment-checkout/index.d.ts +4 -0
  15. package/dist/src/clients/payment-checkout/index.js +25 -1
  16. package/dist/src/clients/payment-checkout/messages.d.ts +33 -0
  17. package/dist/src/clients/payment-checkout/messages.js +19 -0
  18. package/dist/src/clients/payment-checkout/payment-handler.d.ts +36 -0
  19. package/dist/src/clients/payment-checkout/payment-handler.js +375 -0
  20. package/dist/src/clients/payment-checkout/shipping-contact-details.d.ts +10 -0
  21. package/dist/src/clients/payment-checkout/shipping-contact-details.js +83 -0
  22. package/dist/src/clients/payment-checkout/types.d.ts +128 -0
  23. package/dist/src/index.d.ts +1 -1
  24. package/dist/src/index.js +963 -367
  25. package/dist/src/utils/billing-countries.d.ts +19 -0
  26. package/dist/src/utils/billing-countries.js +263 -0
  27. package/dist/src/utils/expressCheckoutRedirect.d.ts +55 -0
  28. package/dist/src/utils/expressCheckoutRedirect.js +46 -0
  29. package/dist/src/utils/expressCheckoutTracking.d.ts +64 -0
  30. package/dist/src/utils/expressCheckoutTracking.js +84 -0
  31. package/dist/src/utils/recaptcha.d.ts +22 -0
  32. package/dist/src/utils/recaptcha.js +54 -0
  33. package/package.json +2 -1
@@ -76,322 +76,7 @@ function ensureApplePayLogoSymbol() {
76
76
  }
77
77
 
78
78
  // src/templates/apple-pay-modal.template.html
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);
92
- box-sizing: border-box;
93
- }
94
-
95
- .apm {
96
- position: relative;
97
- background: #fff;
98
- border-radius: 8px 8px 0 0;
99
- border: 1px solid #d9d9d9;
100
- padding: 24px;
101
- width: 400px;
102
- max-width: 400px;
103
- box-sizing: border-box;
104
- font-family: var(--wall-type-system-sans);
105
- box-shadow: 0 4px 16px 0 rgba(13, 13, 13, 0.15);
106
- }
107
-
108
- .apm__close {
109
- position: absolute;
110
- top: 24px;
111
- right: 21px;
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 2px var(--focus-border-color, #121212);
123
- border-radius: 0.25rem;
124
- }
125
-
126
- .apm__offer-name {
127
- font-family: var(--wall-type-system-sans);
128
- font-size: 1.4375rem;
129
- font-weight: 500;
130
- color: #0d0d0d;
131
- line-height: 28px;
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(--wall-type-system-sans);
139
- font-size: 15px;
140
- font-style: normal;
141
- font-weight: 400;
142
- line-height: 20px;
143
- margin: 0 0 1rem 0;
144
- }
145
-
146
- .apm__rule {
147
- border: none;
148
- border-top: 1px solid #d9d9d9;
149
- margin: 0 0 1rem 0;
150
- }
151
-
152
- .apm__terms {
153
- color: #1a1a1a;
154
- font-family: var(--wall-type-system-sans);
155
- font-size: 15px;
156
- font-style: normal;
157
- font-weight: 400;
158
- line-height: 1.333;
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__checkbox-label {
177
- display: flex;
178
- align-items: flex-start;
179
- gap: 12px;
180
- font-family: var(--wall-type-system-sans);
181
- font-size: 0.9375rem;
182
- color: #0d0d0d;
183
- line-height: 1.4;
184
- cursor: pointer;
185
- margin: 0 0 8px 0;
186
- }
187
-
188
- .apm__checkbox-wrapper {
189
- position: relative;
190
- flex-shrink: 0;
191
- width: 20px;
192
- height: 20px;
193
- margin-top: 1px;
194
- }
195
-
196
- .apm__checkbox-input {
197
- position: absolute;
198
- opacity: 0;
199
- width: 100%;
200
- height: 100%;
201
- cursor: pointer;
202
- margin: 0;
203
- z-index: 1;
204
- }
205
-
206
- .apm__checkbox-custom {
207
- position: absolute;
208
- top: 0;
209
- left: 0;
210
- width: 20px;
211
- height: 20px;
212
- pointer-events: none;
213
- }
214
-
215
- .apm__checkbox-custom svg {
216
- display: none;
217
- width: 20px;
218
- height: 20px;
219
- }
220
-
221
- .apm__checkbox-input:not(:checked)~.apm__checkbox-custom .svg-unchecked {
222
- display: block;
223
- }
224
-
225
- .apm__checkbox-input:checked~.apm__checkbox-custom .svg-checked {
226
- display: block;
227
- }
228
-
229
- .apm__checkbox-label--error .apm__checkbox-input:not(:checked)~.apm__checkbox-custom .svg-unchecked {
230
- display: none;
231
- }
232
-
233
- .apm__checkbox-label--error .apm__checkbox-input:not(:checked)~.apm__checkbox-custom .svg-error {
234
- display: block;
235
- }
236
-
237
- .apm__checkbox-input:focus-visible~.apm__checkbox-custom {
238
- outline: solid 2px #c91d42;
239
- outline-offset: 2px;
240
- border-radius: 4px;
241
- }
242
-
243
- .apm__checkbox-label a {
244
- color: #1a1a1a;
245
- font-weight: 700;
246
- text-decoration: underline;
247
- }
248
-
249
- .apm__error {
250
- display: none;
251
- align-items: center;
252
- gap: 12px;
253
- color: #0d0d0d;
254
- font-family: var(--wall-type-system-sans);
255
- font-size: 17px;
256
- font-style: normal;
257
- font-weight: 500;
258
- line-height: 24px;
259
- margin-bottom: 16px;
260
- }
261
-
262
- .apm__error--visible {
263
- display: flex;
264
- }
265
-
266
- .apm__cta {
267
- display: flex;
268
- width: 100%;
269
- height: 44px;
270
- padding: 6px 16px;
271
- justify-content: center;
272
- align-items: center;
273
- gap: 6px;
274
- border-radius: 4px;
275
- background: #000;
276
- border: none;
277
- cursor: pointer;
278
- color: #fff;
279
- text-align: center;
280
- font-family: 'SF Pro', var(--wall-type-system-sans, system-ui, sans-serif);
281
- font-size: 20px;
282
- font-style: normal;
283
- font-weight: 500;
284
- line-height: normal;
285
- }
286
-
287
- .apm__cta svg {
288
- flex-shrink: 0;
289
- display: block;
290
- }
291
-
292
- @media (min-width: 360px) and (max-width: 600px) {
293
- .apm {
294
- width: 390px;
295
- max-width: 390px;
296
- }
297
- }
298
-
299
- @media (min-width: 601px) {
300
- .apm {
301
- border-radius: 8px;
302
- }
303
- }
304
-
305
- @media (max-width: 359px) {
306
- .apm {
307
- width: 320px;
308
- max-width: 320px;
309
- }
310
- }
311
-
312
- @media (max-width: 419px) {
313
- .apm__cta {
314
- font-size: 18px;
315
- }
316
- }
317
- </style>
318
-
319
- <div class="apm-overlay" id="apple-pay-modal-overlay">
320
- <div class="apm" role="dialog" aria-modal="true" aria-labelledby="apple-pay-modal-offer-name" id="apple-pay-modal"
321
- tabindex="-1">
322
- <button class="apm__close" id="apple-pay-modal-close" aria-label="Close">
323
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
324
- <g clip-path="url(#clip0_15712_93054)">
325
- <rect width="24" height="24" fill="white" fill-opacity="0.01" />
326
- <path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H24V24H0V0Z" fill="white" fill-opacity="0.01" />
327
- <path fill-rule="evenodd" clip-rule="evenodd"
328
- 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"
329
- fill="#333333" />
330
- </g>
331
- <defs>
332
- <clipPath id="clip0_15712_93054">
333
- <rect width="24" height="24" fill="white" />
334
- </clipPath>
335
- </defs>
336
- </svg>
337
- </button>
338
- <p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>
339
- <p class="apm__due-today" id="apple-pay-modal-due-today"></p>
340
- <hr class="apm__rule" />
341
- <div class="apm__terms" id="apple-pay-modal-terms"></div>
342
- <label class="apm__checkbox-label" id="apple-pay-modal-checkbox-label" for="apple-pay-modal-checkbox">
343
- <div class="apm__checkbox-wrapper">
344
- <input class="apm__checkbox-input" type="checkbox" id="apple-pay-modal-checkbox" />
345
- <span class="apm__checkbox-custom">
346
- <svg class="svg-unchecked" width="24" height="24" viewBox="0 0 24 24" fill="none"
347
- xmlns="http://www.w3.org/2000/svg">
348
- <path
349
- 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"
350
- fill="white" stroke="#595959" />
351
- </svg>
352
- <svg class="svg-checked" width="24" height="24" viewBox="0 0 24 24" fill="none"
353
- xmlns="http://www.w3.org/2000/svg">
354
- <g clip-path="url(#clip0_20014_9555)">
355
- <path
356
- 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"
357
- fill="#333333" />
358
- <path d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"
359
- fill="white" />
360
- </g>
361
- <defs>
362
- <clipPath id="clip0_20014_9555">
363
- <path
364
- 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"
365
- fill="white" />
366
- </clipPath>
367
- </defs>
368
- </svg>
369
- <svg class="svg-error" width="24" height="24" viewBox="0 0 24 24" fill="none"
370
- xmlns="http://www.w3.org/2000/svg">
371
- <path
372
- 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"
373
- fill="white" stroke="#C91D42" stroke-width="2" />
374
- </svg>
375
- </span>
376
- </div>
377
- <span id="apple-pay-modal-checkbox-text"></span>
378
- </label>
379
- <div class="apm__error" id="apple-pay-modal-error" role="alert">
380
- <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
381
- <path fill-rule="evenodd" clip-rule="evenodd"
382
- 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"
383
- fill="#C91D42" />
384
- </svg>
385
- Please accept the terms to continue
386
- </div>
387
- <button class="apm__cta" id="apple-pay-modal-cta">
388
- Continue with
389
- <svg width="51" height="22" aria-label="Apple Pay" role="img">
390
- <use href="#apple-pay-logo" />
391
- </svg>
392
- </button>
393
- </div>
394
- </div>`;
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';
395
80
 
396
81
  // src/apple-pay-modal.ts
397
82
  function getRenewalDateText(unit, duration) {
@@ -457,6 +142,12 @@ function getCheckboxTermsHtml(isNYT, isLoggedIn, autoRenewal) {
457
142
  }
458
143
  return `I accept the ${TERMS_LINK}${autoRenewalClause} and acknowledge the ${PRIVACY_LINK}, and understand that by continuing, an account will be created for me if I don\u2019t already have one.`;
459
144
  }
145
+ function getPassiveTermsHtml(isNYT, isLoggedIn, autoRenewal) {
146
+ const accountClause = isLoggedIn ? " " : "\u2019ll get an account and ";
147
+ const autoRenewalClause = autoRenewal ? "above auto-renewal terms, " : "";
148
+ const nytPrefix = isNYT ? " your subscription to The Economist," : "";
149
+ return `By purchasing${nytPrefix} you${accountClause}agree to the ${autoRenewalClause}${TERMS_LINK} and acknowledge the ${PRIVACY_LINK}.`;
150
+ }
460
151
  function renewalPeriodText(unit, duration) {
461
152
  switch (unit) {
462
153
  case "week":
@@ -679,10 +370,21 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
679
370
  const errorElement = this.querySelector(
680
371
  "#apple-pay-modal-error"
681
372
  );
373
+ const passiveTermsElement = this.querySelector(
374
+ "#apple-pay-modal-passive-terms"
375
+ );
682
376
  if (!isUS) {
683
377
  checkboxLabel?.remove();
684
378
  errorElement?.remove();
379
+ if (passiveTermsElement) {
380
+ passiveTermsElement.innerHTML = getPassiveTermsHtml(
381
+ isOfferNYT,
382
+ isLoggedIn,
383
+ isAutoRenewal
384
+ );
385
+ }
685
386
  } else {
387
+ passiveTermsElement?.remove();
686
388
  checkbox?.addEventListener("change", () => {
687
389
  if (checkbox.checked) {
688
390
  errorElement?.classList.remove("apm__error--visible");
@@ -737,7 +439,7 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
737
439
  };
738
440
 
739
441
  // src/templates/apple-pay-button.template.html
740
- var apple_pay_button_template_default = '<style>\n /* Use CSS variables for layout so parent walls can easily override placement and sizing */\n teg-apple-pay-button {\n display: block;\n margin: var(--apple-pay-margin, 0);\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-container {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: var(--apple-pay-height, 2.75rem);\n background-color: #000;\n color: #fff;\n border: none;\n border-radius: var(--apple-pay-border-radius, 1.375rem);\n cursor: pointer;\n font-family: var(--wall-type-system-sans, system-ui, sans-serif);\n font-size: 17px;\n font-weight: 500;\n }\n\n teg-apple-pay-button .apple-pay-btn svg {\n flex-shrink: 0;\n display: block;\n }\n</style>\n\n<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">\n <button\n class="apple-pay-btn"\n type="button"\n aria-label="Pay with Apple Pay"\n data-analytics="paywall:apple-pay-checkout"\n >\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';
442
+ var apple_pay_button_template_default = '<style>\n /* Use CSS variables for layout so parent walls can easily override placement and sizing */\n teg-apple-pay-button {\n display: block;\n margin: var(--apple-pay-margin, 0);\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-container {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n teg-apple-pay-button .apple-pay-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n width: 100%;\n min-width: 0;\n height: 100%;\n min-height: var(--apple-pay-height, 2.75rem);\n background-color: #000;\n color: #fff;\n border: none;\n border-radius: var(--apple-pay-border-radius, 1.375rem);\n cursor: pointer;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-weight: 500;\n }\n\n teg-apple-pay-button .apple-pay-btn svg {\n flex-shrink: 0;\n display: block;\n }\n</style>\n\n<div class="apple-pay-container" aria-label="Express checkout with Apple Pay">\n <button\n class="apple-pay-btn"\n type="button"\n aria-label="Pay with Apple Pay"\n data-analytics="paywall:apple-pay-checkout"\n >\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';
741
443
 
742
444
  // src/clients/payment-checkout/config.ts
743
445
  var runtimeConfig = null;
@@ -842,6 +544,27 @@ var apiFetch = async (path, options = {}) => {
842
544
  }
843
545
  return response.json();
844
546
  };
547
+ var getPaymentOptions = (data) => {
548
+ const { sku, countryCode, currencyCode, checkoutUrl } = data;
549
+ const params = new URLSearchParams({ checkoutUrl });
550
+ return apiFetch(
551
+ `/ecomb2c/v1/payment-options/sku/${sku}/${countryCode}/${currencyCode}?${params}`,
552
+ { method: "GET" }
553
+ );
554
+ };
555
+ var validateAppleMerchant = (data) => {
556
+ return apiFetch("/v1/wallet/validate-merchant", {
557
+ method: "POST",
558
+ body: JSON.stringify(data)
559
+ });
560
+ };
561
+ var performPurchase = (data) => {
562
+ return apiFetch("/v1/wallet/purchase", {
563
+ method: "POST",
564
+ body: JSON.stringify(data),
565
+ credentials: "include"
566
+ });
567
+ };
845
568
 
846
569
  // src/clients/payment-checkout/session.ts
847
570
  var getExpressCheckoutSession = () => {
@@ -851,9 +574,732 @@ var getExpressCheckoutSession = () => {
851
574
  });
852
575
  };
853
576
 
577
+ // src/utils/expressCheckoutRedirect.ts
578
+ var captureOriginUrl = () => window.location.href;
579
+ var buildQueryString = () => {
580
+ const countryCode = new URLSearchParams(window.location.search).get(
581
+ "country"
582
+ );
583
+ return countryCode ? `&country=${encodeURIComponent(countryCode)}` : "";
584
+ };
585
+ var decodeSku = (sku) => {
586
+ try {
587
+ return atob(sku.substring(sku.indexOf("-") + 1));
588
+ } catch {
589
+ return sku;
590
+ }
591
+ };
592
+ var redirectToCheckoutComplete = (params) => {
593
+ const url = new URL("/checkout/complete", window.location.origin);
594
+ url.searchParams.set("basketId", params.basketId);
595
+ if (params.queryString) {
596
+ const qs = params.queryString.startsWith("?") ? params.queryString.slice(1) : params.queryString;
597
+ new URLSearchParams(qs).forEach((v, k) => url.searchParams.set(k, v));
598
+ }
599
+ url.searchParams.set("lmo_offer", params.skuId);
600
+ url.searchParams.set("status", params.status);
601
+ url.searchParams.set("redirectToCheckout", "true");
602
+ url.searchParams.set("returnUrl", params.returnUrl);
603
+ return url.pathname + url.search;
604
+ };
605
+ var redirectToCheckoutFallback = (params) => {
606
+ const url = new URL(window.location.href);
607
+ url.pathname = "/checkout";
608
+ url.searchParams.set("lmo_offer", params.skuId);
609
+ if (params.inlineError)
610
+ url.searchParams.set("inlineError", params.inlineError);
611
+ if (params.email) url.searchParams.set("email", params.email);
612
+ if (params.emailError) url.searchParams.set("emailError", params.emailError);
613
+ url.searchParams.set("returnUrl", params.returnUrl);
614
+ return url.pathname + url.search;
615
+ };
616
+
617
+ // src/utils/recaptcha.ts
618
+ var loadRecaptchaScript = (siteKey) => {
619
+ return new Promise((resolve, reject) => {
620
+ if (typeof grecaptcha !== "undefined") return resolve();
621
+ const existingScript = document.querySelector(
622
+ 'script[src*="recaptcha/api.js"]'
623
+ );
624
+ if (existingScript) {
625
+ existingScript.addEventListener("load", () => resolve());
626
+ existingScript.addEventListener(
627
+ "error",
628
+ () => reject(new Error("Failed to load existing reCAPTCHA script"))
629
+ );
630
+ return;
631
+ }
632
+ const script = document.createElement("script");
633
+ script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
634
+ script.async = true;
635
+ script.defer = true;
636
+ script.onload = () => resolve();
637
+ script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
638
+ document.head.appendChild(script);
639
+ });
640
+ };
641
+ var getRecaptchaToken = async (action) => {
642
+ const siteKey = getApplePayConfig()?.recaptchaSiteKey;
643
+ if (!siteKey) {
644
+ throw new Error(
645
+ "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
646
+ );
647
+ }
648
+ await loadRecaptchaScript(siteKey);
649
+ return new Promise((resolve, reject) => {
650
+ grecaptcha.ready(() => {
651
+ grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
652
+ });
653
+ });
654
+ };
655
+ var getPurchaseRecaptchaTokens = async () => {
656
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
657
+ getRecaptchaToken("checkEligibility"),
658
+ getRecaptchaToken("newBasket"),
659
+ getRecaptchaToken("registerUser")
660
+ ]);
661
+ return { checkEligibility, newBasket, registerUser };
662
+ };
663
+
664
+ // src/utils/expressCheckoutTracking.ts
665
+ var EXPRESS_CHECKOUT_EVENTS = {
666
+ /** Wallet button displayed */
667
+ IMPRESSION: "express_wallet_impression",
668
+ /** Wallet button clicked */
669
+ BUTTON_CLICK: "express_wallet_click",
670
+ /** Apple Pay sheet opened */
671
+ SHEET_OPEN: "wallet_payment_sheet_open",
672
+ /** Payment authorised by the user in the Apple Pay sheet */
673
+ AUTHORISED: "wallet_payment_authorised",
674
+ /** Purchase completed — BFF returned success */
675
+ SUCCESS: "wallet_payment_success",
676
+ /** Payment failed — BFF returned error */
677
+ FAILURE: "wallet_payment_failure",
678
+ /** Redirect to standard checkout (any fallback path) */
679
+ FALLBACK_CHECKOUT: "fallback_checkout"
680
+ };
681
+ var getDevice = () => {
682
+ const ua = navigator.userAgent;
683
+ if (/tablet|ipad/i.test(ua)) return "tablet";
684
+ if (/mobile|iphone|android/i.test(ua)) return "mobile";
685
+ return "desktop";
686
+ };
687
+ var emitTedlEvent = (event) => {
688
+ window.tedl = window.tedl ?? {};
689
+ window.tedl.events = window.tedl.events ?? [];
690
+ window.tedl.events.push(event);
691
+ };
692
+ var track = (action, extra) => {
693
+ emitTedlEvent({
694
+ name: "user.journey",
695
+ type: "checkout",
696
+ action,
697
+ info: "applepay",
698
+ ...extra
699
+ });
700
+ };
701
+ var trackExpressWalletImpression = (skuId, { entryPoint, country }) => {
702
+ track(EXPRESS_CHECKOUT_EVENTS.IMPRESSION, {
703
+ wallet_type: "apple_pay",
704
+ entry_point: entryPoint,
705
+ sku_id: skuId,
706
+ country,
707
+ device: getDevice()
708
+ });
709
+ };
710
+ var trackExpressWalletClick = (skuId) => {
711
+ track(EXPRESS_CHECKOUT_EVENTS.BUTTON_CLICK, { sku_id: skuId });
712
+ };
713
+ var trackWalletPaymentSheetOpen = (skuId) => {
714
+ track(EXPRESS_CHECKOUT_EVENTS.SHEET_OPEN, { sku_id: skuId });
715
+ };
716
+ var trackWalletPaymentAuthorised = (skuId) => {
717
+ track(EXPRESS_CHECKOUT_EVENTS.AUTHORISED, { sku_id: skuId });
718
+ };
719
+ var trackWalletPaymentSuccess = (skuId, basketId) => {
720
+ track(EXPRESS_CHECKOUT_EVENTS.SUCCESS, {
721
+ sku_id: skuId,
722
+ basket_id: basketId
723
+ });
724
+ };
725
+ var trackWalletPaymentFailure = (skuId, reason) => {
726
+ track(EXPRESS_CHECKOUT_EVENTS.FAILURE, {
727
+ sku_id: skuId,
728
+ failure_reason: reason
729
+ });
730
+ };
731
+ var trackFallbackCheckout = (skuId) => {
732
+ track(EXPRESS_CHECKOUT_EVENTS.FALLBACK_CHECKOUT, { sku_id: skuId });
733
+ };
734
+ var trackValidationFieldError = (field, errorType) => {
735
+ track(`validation_${field}_${errorType}`, {});
736
+ };
737
+
738
+ // src/clients/payment-checkout/messages.ts
739
+ var MSG_MISSING_REQUIRED_FIELD = "Missing required field";
740
+ var MSG_EMAIL_WRONG_FORMAT = "That email doesn\u2019t look right. Please enter a valid email address.";
741
+ var MSG_EMAIL_TOO_LONG = "This field must be 80 characters or less.";
742
+ var MSG_UNSUPPORTED_BILLING_COUNTRY = "Billing country does not match offer price zone";
743
+ var MSG_PAYMENT_GENERIC_ERROR = "Something went wrong. Please check your payment and billing details and try again or contact us.";
744
+ var MSG_RECAPTCHA_VALIDATION_FAILED = "Security check failed. Please try again.";
745
+ var MSG_EMAIL_COLLISION = "This email address is already linked to an account. Please log in, or try a different email address.";
746
+ var MSG_CONTACT_VALIDATION_INTERNAL = "Could not validate Apple Pay contact";
747
+
748
+ // src/clients/payment-checkout/apple-session.ts
749
+ function startApplePaySession(config) {
750
+ const paymentRequest = {
751
+ countryCode: config.countryCode,
752
+ currencyCode: config.currencyCode,
753
+ merchantCapabilities: ["supports3DS"],
754
+ supportedNetworks: config.supportedNetworks,
755
+ total: {
756
+ label: config.totalLabel,
757
+ amount: config.totalAmount
758
+ },
759
+ requiredBillingContactFields: ["postalAddress", "name"],
760
+ // Only request email from Apple Pay sheet if user is NOT logged in
761
+ ...!config.userLoggedIn && { requiredShippingContactFields: ["email"] }
762
+ };
763
+ const session = new ApplePaySession(3, paymentRequest);
764
+ session.onvalidatemerchant = async (event) => {
765
+ try {
766
+ const validationHost = new URL(event.validationURL).host;
767
+ if (!validationHost.endsWith("apple.com")) {
768
+ trackFallbackCheckout(config.skuId);
769
+ session.abort();
770
+ window.location.href = redirectToCheckoutFallback({
771
+ skuId: config.skuId,
772
+ returnUrl: config.returnUrl,
773
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
774
+ });
775
+ return;
776
+ }
777
+ const recaptchaToken = await getRecaptchaToken("verifyMerchant");
778
+ const response = await validateAppleMerchant({
779
+ validationURL: event.validationURL,
780
+ recaptchaToken
781
+ });
782
+ if (!response?.merchantSession) {
783
+ trackFallbackCheckout(config.skuId);
784
+ session.abort();
785
+ window.location.href = redirectToCheckoutFallback({
786
+ skuId: config.skuId,
787
+ returnUrl: config.returnUrl,
788
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
789
+ });
790
+ return;
791
+ }
792
+ session.completeMerchantValidation(response.merchantSession);
793
+ } catch {
794
+ trackFallbackCheckout(config.skuId);
795
+ session.abort();
796
+ window.location.href = redirectToCheckoutFallback({
797
+ skuId: config.skuId,
798
+ returnUrl: config.returnUrl,
799
+ inlineError: MSG_PAYMENT_GENERIC_ERROR
800
+ });
801
+ }
802
+ };
803
+ session.onpaymentauthorized = (event) => {
804
+ trackWalletPaymentAuthorised(config.skuId);
805
+ config.onPaymentAuthorized(event, session);
806
+ };
807
+ session.oncancel = () => {
808
+ config.onCancel?.();
809
+ };
810
+ trackWalletPaymentSheetOpen(config.skuId);
811
+ session.begin();
812
+ }
813
+
814
+ // src/clients/payment-checkout/contact-validation.ts
815
+ var pushFieldError = (errors, billingOrShippingContact = "billing", field, errorType, errorText) => {
816
+ const errorCode = billingOrShippingContact === "billing" ? "billingContactInvalid" : "shippingContactInvalid";
817
+ errors.push(new ApplePayError(errorCode, field, errorText));
818
+ trackValidationFieldError(field, errorType);
819
+ return "";
820
+ };
821
+ var pushRequiredFieldError = (errors, billingOrShippingContact = "billing", field) => {
822
+ return pushFieldError(
823
+ errors,
824
+ billingOrShippingContact,
825
+ field,
826
+ "required",
827
+ MSG_MISSING_REQUIRED_FIELD
828
+ );
829
+ };
830
+ var ContactValidationError = class extends Error {
831
+ constructor(errors) {
832
+ super(MSG_CONTACT_VALIDATION_INTERNAL);
833
+ this.errors = errors;
834
+ }
835
+ };
836
+
837
+ // src/clients/payment-checkout/billing-contact-details.ts
838
+ var countriesWithoutCityField = ["KY", "CK", "NR", "TC"];
839
+ var countriesRequiringAllFields = ["US", "CA", "GB"];
840
+ var resolveCountryConfig = (country) => {
841
+ const hasCityField = !countriesWithoutCityField.includes(country);
842
+ const requiresStateAndPostcode = countriesRequiringAllFields.includes(country);
843
+ return {
844
+ hasCityField,
845
+ requiresStateAndPostcode,
846
+ // if there is no city field, we require state and use it in place of city
847
+ requiresStateField: !hasCityField || requiresStateAndPostcode
848
+ };
849
+ };
850
+ var validateAddressFields = (errors, contact, { hasCityField, requiresStateAndPostcode, requiresStateField }) => {
851
+ const locality = !hasCityField ? contact.administrativeArea : contact.locality;
852
+ if (!contact.addressLines?.at(0)?.trim()) {
853
+ pushRequiredFieldError(errors, "billing", "addressLines");
854
+ }
855
+ if (!locality?.trim() && hasCityField) {
856
+ pushRequiredFieldError(errors, "billing", "locality");
857
+ }
858
+ if (!contact.administrativeArea?.trim() && requiresStateField) {
859
+ pushRequiredFieldError(errors, "billing", "administrativeArea");
860
+ }
861
+ if (!contact.postalCode?.trim() && requiresStateAndPostcode) {
862
+ pushRequiredFieldError(errors, "billing", "postalCode");
863
+ }
864
+ };
865
+ var validateNameFields = (errors, contact) => {
866
+ const firstName = contact.givenName?.trim() || "";
867
+ const lastName = contact.familyName?.trim() || "";
868
+ if (!firstName || !lastName) {
869
+ pushRequiredFieldError(errors, "billing", "name");
870
+ }
871
+ return { firstName, lastName };
872
+ };
873
+ var validateCountrySupport = (errors, country, supportedBillingCountries) => {
874
+ if (!supportedBillingCountries.includes(country)) {
875
+ pushFieldError(
876
+ errors,
877
+ "billing",
878
+ "countryCode",
879
+ "not-supported",
880
+ MSG_UNSUPPORTED_BILLING_COUNTRY
881
+ );
882
+ }
883
+ };
884
+ var billingContactDetails = (contact, supportedBillingCountries) => {
885
+ const errors = [];
886
+ const country = contact.countryCode?.toUpperCase() || pushRequiredFieldError(errors, "billing", "country");
887
+ const config = resolveCountryConfig(country);
888
+ validateAddressFields(errors, contact, config);
889
+ const { firstName, lastName } = validateNameFields(errors, contact);
890
+ validateCountrySupport(errors, country, supportedBillingCountries);
891
+ if (errors.length > 0) {
892
+ throw new ContactValidationError(errors);
893
+ }
894
+ return { firstName, lastName };
895
+ };
896
+
897
+ // src/clients/payment-checkout/shipping-contact-details.ts
898
+ var EMAIL_FORMAT_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
899
+ var shippingContactDetails = (shippingContact) => {
900
+ const errors = [];
901
+ let emailAddress = "";
902
+ if (shippingContact?.emailAddress === void 0 || shippingContact?.emailAddress === "") {
903
+ pushRequiredFieldError(errors, "shipping", "emailAddress");
904
+ } else {
905
+ emailAddress = shippingContact.emailAddress.trim();
906
+ if (emailAddress.length > 80) {
907
+ pushFieldError(
908
+ errors,
909
+ "shipping",
910
+ "emailAddress",
911
+ "format",
912
+ MSG_EMAIL_TOO_LONG
913
+ );
914
+ } else if (!EMAIL_FORMAT_REGEX.test(emailAddress)) {
915
+ pushFieldError(
916
+ errors,
917
+ "shipping",
918
+ "emailAddress",
919
+ "format",
920
+ MSG_EMAIL_WRONG_FORMAT
921
+ );
922
+ }
923
+ }
924
+ if (errors.length > 0) {
925
+ throw new ContactValidationError(errors);
926
+ }
927
+ return { emailAddress };
928
+ };
929
+
930
+ // src/clients/payment-checkout/payment-handler.ts
931
+ var MSG_ELIGIBILITY = "Something went wrong, please try again";
932
+ var MSG_REGISTRATION = "We couldn't create your account. Please enter your email or try a different login method.";
933
+ var failApplePaySession = (session, errors = []) => {
934
+ session.completePayment({
935
+ status: ApplePaySession.STATUS_FAILURE,
936
+ errors
937
+ });
938
+ };
939
+ function parseWalletApiError(err) {
940
+ const body = err instanceof ApiError ? err.body : err;
941
+ if (body && typeof body === "object" && "errorType" in body && "message" in body) {
942
+ return body;
943
+ }
944
+ return null;
945
+ }
946
+ function validateContacts(event, sessionData, supportedBillingCountries) {
947
+ billingContactDetails(
948
+ event.payment.billingContact,
949
+ supportedBillingCountries
950
+ );
951
+ if (!sessionData.loggedIn) {
952
+ return shippingContactDetails(event.payment.shippingContact).emailAddress;
953
+ }
954
+ return void 0;
955
+ }
956
+ function redirectFallback(skuId, returnUrl, options) {
957
+ trackFallbackCheckout(skuId);
958
+ window.location.href = redirectToCheckoutFallback({
959
+ skuId,
960
+ returnUrl,
961
+ ...options
962
+ });
963
+ }
964
+ var ERROR_HANDLERS = {
965
+ EMAIL_COLLISION: ({ skuId, returnUrl, validatedEmail }) => redirectFallback(skuId, returnUrl, {
966
+ emailError: MSG_EMAIL_COLLISION,
967
+ email: validatedEmail
968
+ }),
969
+ PAYMENT_DECLINED: ({ skuId, returnUrl }) => (
970
+ // Matches sma-checkout catch-all: always redirect with generic inlineError.
971
+ redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR })
972
+ ),
973
+ ELIGIBILITY_REJECTED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_ELIGIBILITY }),
974
+ REGISTRATION_FAILED: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_REGISTRATION }),
975
+ VALIDATION_ERROR: ({ skuId, returnUrl }) => redirectFallback(skuId, returnUrl, { inlineError: MSG_RECAPTCHA_VALIDATION_FAILED })
976
+ };
977
+ function handleStructuredError(ctx) {
978
+ const handler = ERROR_HANDLERS[ctx.walletError.errorType];
979
+ if (handler) {
980
+ handler(ctx);
981
+ } else {
982
+ redirectFallback(ctx.skuId, ctx.returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
983
+ }
984
+ }
985
+ async function handlePaymentAuthorized(event, session, sessionData, config) {
986
+ const { skuId, returnUrl, queryString } = config;
987
+ let validatedEmail;
988
+ try {
989
+ validatedEmail = validateContacts(
990
+ event,
991
+ sessionData,
992
+ config.supportedBillingCountries
993
+ );
994
+ const result = await performPurchase({
995
+ applePayToken: event.payment.token,
996
+ skuId: config.skuId,
997
+ billingContact: event.payment.billingContact,
998
+ ...event.payment.shippingContact && {
999
+ shippingContact: event.payment.shippingContact
1000
+ },
1001
+ recaptchaTokens: config.recaptchaTokens
1002
+ });
1003
+ trackWalletPaymentSuccess(skuId, result.basketId);
1004
+ session.completePayment({ status: ApplePaySession.STATUS_SUCCESS });
1005
+ const userStatus = sessionData.loggedIn ? "lex" : "nex";
1006
+ window.location.href = redirectToCheckoutComplete({
1007
+ basketId: result.basketId,
1008
+ status: userStatus,
1009
+ skuId: decodeSku(skuId),
1010
+ returnUrl,
1011
+ queryString
1012
+ });
1013
+ } catch (err) {
1014
+ if (err instanceof ContactValidationError) {
1015
+ failApplePaySession(session, err.errors);
1016
+ return;
1017
+ }
1018
+ console.error("[web-apple-pay] onpaymentauthorized error", { skuId, err });
1019
+ const walletError = parseWalletApiError(err);
1020
+ trackWalletPaymentFailure(skuId, walletError?.errorType ?? "UNKNOWN");
1021
+ failApplePaySession(session);
1022
+ if (!walletError) {
1023
+ redirectFallback(skuId, returnUrl, { inlineError: MSG_PAYMENT_GENERIC_ERROR });
1024
+ return;
1025
+ }
1026
+ handleStructuredError({ skuId, returnUrl, validatedEmail, walletError });
1027
+ }
1028
+ }
1029
+
1030
+ // src/data/price-zones.json
1031
+ var price_zones_default = {
1032
+ "AS-AS": [
1033
+ "BD",
1034
+ "BT",
1035
+ "CK",
1036
+ "FJ",
1037
+ "ID",
1038
+ "KH",
1039
+ "KI",
1040
+ "LA",
1041
+ "LK",
1042
+ "MH",
1043
+ "MM",
1044
+ "MN",
1045
+ "MV",
1046
+ "NC",
1047
+ "NF",
1048
+ "NP",
1049
+ "NR",
1050
+ "PF",
1051
+ "PG",
1052
+ "PK",
1053
+ "PW",
1054
+ "SB",
1055
+ "TH",
1056
+ "TL",
1057
+ "TO",
1058
+ "TV",
1059
+ "VN",
1060
+ "VU",
1061
+ "WS"
1062
+ ],
1063
+ "AS-AU": ["AU"],
1064
+ "AS-CN": ["CN"],
1065
+ "AS-HK": ["HK", "MO"],
1066
+ "AS-IN": ["IN"],
1067
+ "AS-JP": ["JP"],
1068
+ "AS-KR": ["KR"],
1069
+ "AS-MY": ["MY"],
1070
+ "AS-NZ": ["NZ"],
1071
+ "AS-PH": ["PH"],
1072
+ "AS-SG": ["BN", "SG"],
1073
+ "AS-TW": ["TW"],
1074
+ "CE-AF": [
1075
+ "DZ",
1076
+ "AO",
1077
+ "BJ",
1078
+ "BW",
1079
+ "BF",
1080
+ "BI",
1081
+ "CM",
1082
+ "CV",
1083
+ "CF",
1084
+ "TD",
1085
+ "CG",
1086
+ "CD",
1087
+ "CI",
1088
+ "DJ",
1089
+ "EG",
1090
+ "GQ",
1091
+ "ER",
1092
+ "ET",
1093
+ "GA",
1094
+ "GM",
1095
+ "GH",
1096
+ "GN",
1097
+ "GW",
1098
+ "IL",
1099
+ "JO",
1100
+ "KE",
1101
+ "LB",
1102
+ "LS",
1103
+ "LR",
1104
+ "LY",
1105
+ "MG",
1106
+ "MW",
1107
+ "ML",
1108
+ "MR",
1109
+ "MU",
1110
+ "MA",
1111
+ "MZ",
1112
+ "NA",
1113
+ "NE",
1114
+ "NG",
1115
+ "PS",
1116
+ "RE",
1117
+ "RW",
1118
+ "ST",
1119
+ "SN",
1120
+ "SC",
1121
+ "SL",
1122
+ "ZA",
1123
+ "SZ",
1124
+ "TZ",
1125
+ "TG",
1126
+ "TN",
1127
+ "UG",
1128
+ "ZM",
1129
+ "ZW"
1130
+ ],
1131
+ "CE-CH": ["LI", "CH"],
1132
+ "CE-DK": ["FO", "GL", "DK"],
1133
+ "CE-EU": [
1134
+ "AL",
1135
+ "AD",
1136
+ "AM",
1137
+ "AT",
1138
+ "AZ",
1139
+ "BY",
1140
+ "BE",
1141
+ "BA",
1142
+ "BG",
1143
+ "HR",
1144
+ "CY",
1145
+ "CZ",
1146
+ "EE",
1147
+ "FI",
1148
+ "FR",
1149
+ "GE",
1150
+ "DE",
1151
+ "GI",
1152
+ "GR",
1153
+ "HU",
1154
+ "IS",
1155
+ "IE",
1156
+ "IT",
1157
+ "KZ",
1158
+ "XK",
1159
+ "KG",
1160
+ "LV",
1161
+ "LT",
1162
+ "LU",
1163
+ "MT",
1164
+ "MD",
1165
+ "MC",
1166
+ "ME",
1167
+ "NL",
1168
+ "PL",
1169
+ "PT",
1170
+ "MK",
1171
+ "RO",
1172
+ "RS",
1173
+ "SK",
1174
+ "SI",
1175
+ "ES",
1176
+ "TJ",
1177
+ "TR",
1178
+ "TM",
1179
+ "UA",
1180
+ "UZ"
1181
+ ],
1182
+ "CE-ME": ["AE", "BH", "KW", "OM", "QA", "SA"],
1183
+ "CE-NO": ["NO"],
1184
+ "CE-SE": ["SE"],
1185
+ "LA-LA": [
1186
+ "AI",
1187
+ "AG",
1188
+ "AR",
1189
+ "AW",
1190
+ "BS",
1191
+ "BB",
1192
+ "BZ",
1193
+ "BM",
1194
+ "BO",
1195
+ "BR",
1196
+ "KY",
1197
+ "CL",
1198
+ "CO",
1199
+ "CR",
1200
+ "DM",
1201
+ "DO",
1202
+ "EC",
1203
+ "SV",
1204
+ "FK",
1205
+ "GF",
1206
+ "GD",
1207
+ "GT",
1208
+ "GY",
1209
+ "HT",
1210
+ "HN",
1211
+ "JM",
1212
+ "MQ",
1213
+ "MX",
1214
+ "MS",
1215
+ "NI",
1216
+ "MP",
1217
+ "PA",
1218
+ "PY",
1219
+ "PE",
1220
+ "KN",
1221
+ "LC",
1222
+ "VC",
1223
+ "SR",
1224
+ "TT",
1225
+ "TC",
1226
+ "UY",
1227
+ "VG",
1228
+ "VI"
1229
+ ],
1230
+ "NA-CA": ["CA"],
1231
+ "NA-US": ["AS", "GU", "FM", "PR", "US"],
1232
+ "UK-UK": ["GB"]
1233
+ };
1234
+
1235
+ // src/data/eea-countries.json
1236
+ var eea_countries_default = [
1237
+ "AT",
1238
+ "BE",
1239
+ "BG",
1240
+ "HR",
1241
+ "CY",
1242
+ "CZ",
1243
+ "DK",
1244
+ "EE",
1245
+ "FO",
1246
+ "FI",
1247
+ "FR",
1248
+ "DE",
1249
+ "GR",
1250
+ "GL",
1251
+ "HU",
1252
+ "IS",
1253
+ "IE",
1254
+ "IT",
1255
+ "LV",
1256
+ "LI",
1257
+ "LT",
1258
+ "LU",
1259
+ "MT",
1260
+ "NL",
1261
+ "NO",
1262
+ "PL",
1263
+ "PT",
1264
+ "RO",
1265
+ "SK",
1266
+ "SI",
1267
+ "ES",
1268
+ "SE"
1269
+ ];
1270
+
1271
+ // src/utils/billing-countries.ts
1272
+ var priceZones = price_zones_default;
1273
+ var eeaCountries = eea_countries_default;
1274
+ var ALL_COUNTRY_CODES = Object.values(priceZones).flat();
1275
+ var getZoneByCountry = (country) => Object.keys(priceZones).find((key) => priceZones[key].includes(country)) ?? null;
1276
+ var getSupportedBillingCountries = (offerCountry, offerVariant) => {
1277
+ if (offerVariant === "bundle" || offerVariant === "insider_print") {
1278
+ return [...ALL_COUNTRY_CODES];
1279
+ }
1280
+ const zone = getZoneByCountry(offerCountry);
1281
+ if (!zone) {
1282
+ return [...ALL_COUNTRY_CODES];
1283
+ }
1284
+ const zoneCountries = priceZones[zone];
1285
+ if (eeaCountries.includes(offerCountry)) {
1286
+ return Array.from(/* @__PURE__ */ new Set([...zoneCountries, ...eeaCountries]));
1287
+ }
1288
+ return [...zoneCountries];
1289
+ };
1290
+
854
1291
  // src/apple-pay-button.ts
855
1292
  var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
856
- var APPLE_PAY_EXCLUDED_VARIANTS = ["bundle", "insider_print"];
1293
+ var TOTAL_LABEL = "The Economist";
1294
+ var DEFAULT_CURRENCY = "USD";
1295
+ var DEFAULT_TOTAL = "0.00";
1296
+ var ERROR_INITIATE = "Failed to initiate Apple Pay session:";
1297
+ var SEL_CONTAINER = ".apple-pay-container";
1298
+ var SEL_BUTTON = ".apple-pay-btn";
1299
+ var APPLE_PAY_EXCLUDED_VARIANTS = [
1300
+ "bundle",
1301
+ "insider_print"
1302
+ ];
857
1303
  var ApplePayButton = class _ApplePayButton extends HTMLElement {
858
1304
  static tag = "teg-apple-pay-button";
859
1305
  static define() {
@@ -862,29 +1308,39 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
862
1308
  /**
863
1309
  * Creates and configures an ApplePayButton if the feature flag is present.
864
1310
  */
865
- static createIfEnabled(offer, country) {
866
- if (!offer) {
867
- return null;
868
- }
869
- const isExcludedVariant = APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant);
870
- if (isExcludedVariant) {
1311
+ static createIfEnabled(offer, country, entryPoint) {
1312
+ if (!offer) return null;
1313
+ if (APPLE_PAY_EXCLUDED_VARIANTS.includes(offer.product?.variant))
871
1314
  return null;
872
- }
873
- if (!new URLSearchParams(window.location.search).has(
874
- FEATURE_APPLE_PAY_EXPRESS_CHECKOUT
875
- )) {
1315
+ if (!new URLSearchParams(window.location.search).has(FEATURE_APPLE_PAY_EXPRESS_CHECKOUT))
876
1316
  return null;
877
- }
878
1317
  _ApplePayButton.define();
879
1318
  const button = document.createElement(_ApplePayButton.tag);
880
1319
  button.offer = offer;
881
1320
  button.country = country;
1321
+ button.entryPoint = entryPoint;
882
1322
  return button;
883
1323
  }
1324
+ /**
1325
+ * Fallback session used when the BFF is unreachable at page load.
1326
+ * Treats the user as anonymous (not logged in, new-eligible).
1327
+ * Matches the behaviour of sma-checkout when session fetch fails.
1328
+ */
1329
+ static #ANONYMOUS_SESSION = {
1330
+ loggedIn: false,
1331
+ userType: "new-eligible-user"
1332
+ };
1333
+ // ─── Private state ──────────────────────────────────────────────────────────
884
1334
  #offer = null;
885
1335
  #country = "";
886
1336
  #rendering = false;
887
1337
  #readyPromise = null;
1338
+ #sessionData = null;
1339
+ #paymentOptions = null;
1340
+ #returnUrl = "";
1341
+ #supportedBillingCountries = [];
1342
+ #entryPoint = "";
1343
+ // ─── Public API ─────────────────────────────────────────────────────────────
888
1344
  get offer() {
889
1345
  return this.#offer;
890
1346
  }
@@ -898,6 +1354,12 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
898
1354
  set country(value) {
899
1355
  this.#country = value;
900
1356
  }
1357
+ get entryPoint() {
1358
+ return this.#entryPoint;
1359
+ }
1360
+ set entryPoint(value) {
1361
+ this.#entryPoint = value;
1362
+ }
901
1363
  /**
902
1364
  * Awaitable contract for the component's current render lifecycle.
903
1365
  *
@@ -917,60 +1379,130 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
917
1379
  whenReady() {
918
1380
  return this.#readyPromise ?? Promise.resolve();
919
1381
  }
1382
+ // ─── Lifecycle ──────────────────────────────────────────────────────────────
920
1383
  async connectedCallback() {
921
- if (this.#rendering || this.querySelector(".apple-pay-container")) {
1384
+ if (this.#rendering || this.querySelector(SEL_CONTAINER)) {
922
1385
  return;
923
1386
  }
924
1387
  this.#rendering = true;
925
1388
  this.#readyPromise = this.#run();
926
1389
  await this.#readyPromise;
927
1390
  }
1391
+ /**
1392
+ * Resets all render state when the element is removed from the DOM.
1393
+ *
1394
+ * A shared library component cannot assume it won't be moved in the DOM
1395
+ * (e.g. lazy panels, SPA route changes). Resetting on disconnect means
1396
+ * reattach always triggers a fresh `#run()` — new session check, new payment
1397
+ * options fetch, fresh event listeners — preventing stale data from persisting
1398
+ * and eliminating the implicit reliance on the DOM as a render-state flag.
1399
+ */
1400
+ disconnectedCallback() {
1401
+ this.#rendering = false;
1402
+ this.#readyPromise = null;
1403
+ this.#sessionData = null;
1404
+ this.#paymentOptions = null;
1405
+ this.#returnUrl = "";
1406
+ this.#supportedBillingCountries = [];
1407
+ this.querySelector(SEL_CONTAINER)?.remove();
1408
+ }
1409
+ // ─── Render pipeline ────────────────────────────────────────────────────────
928
1410
  async #run() {
929
1411
  try {
930
- const available = await isApplePayAvailable();
931
- if (!available) {
932
- this.style.display = "none";
933
- return;
934
- }
935
- const sessionData = await this.#fetchSession();
936
- if (sessionData?.loggedIn && (sessionData.userType === "active-subscription" || sessionData.userType === "b2b-user")) {
937
- this.style.display = "none";
938
- return;
939
- }
940
- this.style.removeProperty("display");
941
- ensureApplePayLogoSymbol();
942
- const template = document.createElement("template");
943
- template.innerHTML = apple_pay_button_template_default;
944
- this.appendChild(template.content.cloneNode(true));
945
- this.#updateDisabledState();
946
- const button = this.querySelector(".apple-pay-btn");
947
- button.addEventListener("click", () => {
948
- if (!this.#offer) {
949
- return;
950
- }
951
- if (document.querySelector(ApplePayModal.tag)) {
952
- return;
953
- }
954
- ApplePayModal.define();
955
- const modal = document.createElement(ApplePayModal.tag);
956
- modal.offer = this.#offer;
957
- modal.country = this.#country;
958
- if (this.dataset.loggedIn !== void 0) {
959
- modal.dataset.loggedIn = this.dataset.loggedIn;
960
- }
961
- modal.open();
962
- });
1412
+ if (await this.#checkAvailability()) return;
1413
+ if (await this.#checkSession()) return;
1414
+ if (this.#checkOffer()) return;
1415
+ this.#captureReturnUrl();
1416
+ this.#computeBillingCountries();
1417
+ if (await this.#fetchAndCacheOptions()) return;
1418
+ this.#renderTemplate();
963
1419
  } catch {
964
1420
  this.style.display = "none";
965
1421
  } finally {
966
1422
  this.#rendering = false;
967
1423
  }
968
1424
  }
969
- #updateDisabledState() {
970
- const button = this.querySelector(".apple-pay-btn");
971
- if (!button) {
972
- return;
1425
+ /** Returns `true` (hide) when Apple Pay is unavailable on this device/browser. */
1426
+ async #checkAvailability() {
1427
+ const available = await isApplePayAvailable();
1428
+ if (!available) {
1429
+ this.style.display = "none";
1430
+ return true;
1431
+ }
1432
+ return false;
1433
+ }
1434
+ /**
1435
+ * Returns `true` (hide) when the user already has an active subscription or is B2B.
1436
+ * Session fetch errors are swallowed — the component continues as an anonymous user.
1437
+ */
1438
+ async #checkSession() {
1439
+ this.#sessionData = await this.#fetchSession();
1440
+ if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
1441
+ this.style.display = "none";
1442
+ return true;
1443
+ }
1444
+ return false;
1445
+ }
1446
+ /** Returns `true` (hide) when no offer has been set before mount. */
1447
+ #checkOffer() {
1448
+ if (!this.#offer) {
1449
+ this.style.display = "none";
1450
+ return true;
973
1451
  }
1452
+ return false;
1453
+ }
1454
+ /** Captures the current page URL once at mount for reuse across the session lifetime. */
1455
+ #captureReturnUrl() {
1456
+ this.#returnUrl = captureOriginUrl();
1457
+ }
1458
+ /**
1459
+ * Computes supported billing countries once at mount.
1460
+ * Mirrors sma-checkout `billingCountryOptions()` — stable for the element's
1461
+ * connected lifetime; recalculated on reattach via `disconnectedCallback` reset.
1462
+ */
1463
+ #computeBillingCountries() {
1464
+ this.#supportedBillingCountries = getSupportedBillingCountries(
1465
+ this.#country,
1466
+ this.#offer.product?.variant ?? ""
1467
+ );
1468
+ }
1469
+ /**
1470
+ * Returns `true` (hide) when ecom services reports Apple Pay is unavailable
1471
+ * for this offer. The response is cached and reused in `#initiateApplePay`.
1472
+ */
1473
+ async #fetchAndCacheOptions() {
1474
+ this.#paymentOptions = await this.#fetchPaymentOptions();
1475
+ if (!this.#paymentOptions?.options.applePay) {
1476
+ this.style.display = "none";
1477
+ return true;
1478
+ }
1479
+ return false;
1480
+ }
1481
+ /** Injects the button template and wires click and confirm event listeners. */
1482
+ #renderTemplate() {
1483
+ this.style.removeProperty("display");
1484
+ ensureApplePayLogoSymbol();
1485
+ const template = document.createElement("template");
1486
+ template.innerHTML = apple_pay_button_template_default;
1487
+ this.appendChild(template.content.cloneNode(true));
1488
+ this.#updateDisabledState();
1489
+ trackExpressWalletImpression(this.#offer.sku_id, {
1490
+ entryPoint: this.#entryPoint,
1491
+ country: this.#country
1492
+ });
1493
+ const button = this.querySelector(SEL_BUTTON);
1494
+ button.addEventListener("click", () => {
1495
+ this.#openModal();
1496
+ });
1497
+ this.addEventListener("apple-pay-confirmed", (event) => {
1498
+ const { skuId, country } = event.detail;
1499
+ this.#initiateApplePay(skuId, country);
1500
+ });
1501
+ }
1502
+ // ─── Private helpers ────────────────────────────────────────────────────────
1503
+ #updateDisabledState() {
1504
+ const button = this.querySelector(SEL_BUTTON);
1505
+ if (!button) return;
974
1506
  if (this.#offer) {
975
1507
  button.removeAttribute("disabled");
976
1508
  button.removeAttribute("aria-disabled");
@@ -979,6 +1511,18 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
979
1511
  button.setAttribute("disabled", "");
980
1512
  button.setAttribute("aria-disabled", "true");
981
1513
  }
1514
+ #openModal() {
1515
+ if (!this.#offer || document.querySelector(ApplePayModal.tag)) return;
1516
+ trackExpressWalletClick(this.#offer.sku_id);
1517
+ ApplePayModal.define();
1518
+ const modal = document.createElement(ApplePayModal.tag);
1519
+ modal.offer = this.#offer;
1520
+ modal.country = this.#country;
1521
+ if (this.#sessionData?.loggedIn) {
1522
+ modal.dataset.loggedIn = "true";
1523
+ }
1524
+ modal.open();
1525
+ }
982
1526
  async #fetchSession() {
983
1527
  try {
984
1528
  return await getExpressCheckoutSession();
@@ -986,6 +1530,58 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
986
1530
  return null;
987
1531
  }
988
1532
  }
1533
+ async #fetchPaymentOptions() {
1534
+ try {
1535
+ return await getPaymentOptions({
1536
+ sku: this.#offer.sku_id,
1537
+ countryCode: this.#country,
1538
+ currencyCode: this.#offer.price?.currency_code ?? DEFAULT_CURRENCY,
1539
+ checkoutUrl: this.#returnUrl
1540
+ });
1541
+ } catch {
1542
+ return null;
1543
+ }
1544
+ }
1545
+ #buildSessionParams(skuId, country, sessionData, paymentOptions, recaptchaTokens) {
1546
+ const offer = this.#offer;
1547
+ const totalAmount = offer.price?.purchase ? `${offer.price.purchase}` : DEFAULT_TOTAL;
1548
+ return {
1549
+ countryCode: country,
1550
+ currencyCode: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1551
+ supportedNetworks: paymentOptions.options.applePay.settings.supportedNetworks,
1552
+ totalAmount,
1553
+ totalLabel: TOTAL_LABEL,
1554
+ skuId,
1555
+ returnUrl: this.#returnUrl,
1556
+ userLoggedIn: sessionData.loggedIn,
1557
+ onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
1558
+ skuId,
1559
+ country,
1560
+ returnUrl: this.#returnUrl,
1561
+ queryString: buildQueryString(),
1562
+ supportedBillingCountries: this.#supportedBillingCountries,
1563
+ recaptchaTokens
1564
+ })
1565
+ };
1566
+ }
1567
+ async #initiateApplePay(skuId, country) {
1568
+ try {
1569
+ const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1570
+ const paymentOptions = this.#paymentOptions;
1571
+ const recaptchaTokens = await getPurchaseRecaptchaTokens();
1572
+ startApplePaySession(
1573
+ this.#buildSessionParams(
1574
+ skuId,
1575
+ country,
1576
+ sessionData,
1577
+ paymentOptions,
1578
+ recaptchaTokens
1579
+ )
1580
+ );
1581
+ } catch (error) {
1582
+ console.error(ERROR_INITIATE, error);
1583
+ }
1584
+ }
989
1585
  };
990
1586
 
991
1587
  // src/index.ts
@@ -1132,7 +1728,7 @@ var withApplePayStoryEnvironment = (options, renderFn) => (args) => {
1132
1728
 
1133
1729
  // src/apple-pay-button.stories.ts
1134
1730
  var APPLE_PAY_BUTTON_TAG = "teg-apple-pay-button";
1135
- var renderButton = ({ country, loggedIn }) => {
1731
+ var renderButton = ({ country }) => {
1136
1732
  defineApplePayElements();
1137
1733
  const container = document.createElement("div");
1138
1734
  container.style.padding = "24px";
@@ -1141,7 +1737,6 @@ var renderButton = ({ country, loggedIn }) => {
1141
1737
  );
1142
1738
  button.offer = STORYBOOK_SAMPLE_OFFER;
1143
1739
  button.country = country;
1144
- button.dataset.loggedIn = String(loggedIn);
1145
1740
  container.appendChild(button);
1146
1741
  return container;
1147
1742
  };
@@ -1154,12 +1749,10 @@ var meta = {
1154
1749
  }
1155
1750
  },
1156
1751
  args: {
1157
- country: "US",
1158
- loggedIn: false
1752
+ country: "US"
1159
1753
  },
1160
1754
  argTypes: {
1161
- country: { control: "text" },
1162
- loggedIn: { control: "boolean" }
1755
+ country: { control: "text" }
1163
1756
  },
1164
1757
  render: renderButton
1165
1758
  };
@@ -1180,7 +1773,10 @@ var NotSupported = {
1180
1773
  disable: true
1181
1774
  }
1182
1775
  },
1183
- render: withApplePayStoryEnvironment({ applePaySupported: false }, renderButton)
1776
+ render: withApplePayStoryEnvironment(
1777
+ { applePaySupported: false },
1778
+ renderButton
1779
+ )
1184
1780
  };
1185
1781
  var SessionInitErrorFallback = {
1186
1782
  parameters: {
@@ -1204,9 +1800,6 @@ var LoggedInModalPropagation = {
1204
1800
  disable: true
1205
1801
  }
1206
1802
  },
1207
- args: {
1208
- loggedIn: true
1209
- },
1210
1803
  render: withApplePayStoryEnvironment(
1211
1804
  {
1212
1805
  applePaySupported: true,
@@ -1246,9 +1839,6 @@ var ActiveSubscriberHidden = {
1246
1839
  disable: true
1247
1840
  }
1248
1841
  },
1249
- args: {
1250
- loggedIn: true
1251
- },
1252
1842
  render: withApplePayStoryEnvironment(
1253
1843
  {
1254
1844
  applePaySupported: true,
@@ -1270,9 +1860,6 @@ var B2BUserHidden = {
1270
1860
  disable: true
1271
1861
  }
1272
1862
  },
1273
- args: {
1274
- loggedIn: true
1275
- },
1276
1863
  render: withApplePayStoryEnvironment(
1277
1864
  {
1278
1865
  applePaySupported: true,