@lightspeed/online-payments-sdk 1.8.0 → 1.9.1

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 (39) hide show
  1. package/README.md +37 -0
  2. package/dist/cjs/index.js +4 -1
  3. package/dist/cjs/v1/EventBroadcaster.js +1 -0
  4. package/dist/cjs/v1/adyen/widget.js +4 -13
  5. package/dist/cjs/v1/stripe/localizedText.js +32 -0
  6. package/dist/cjs/v1/stripe/session.js +9 -0
  7. package/dist/cjs/v1/stripe/shared.js +55 -14
  8. package/dist/cjs/v1/stripe/terms.js +1 -1
  9. package/dist/cjs/v1/stripe/themes.js +2 -2
  10. package/dist/cjs/v1/stripe/widget.js +64 -25
  11. package/dist/cjs/v1/stripe/widgets/deferredMoto.js +203 -0
  12. package/dist/cjs/v1/widget.js +32 -4
  13. package/dist/cjs/version.js +1 -1
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +3 -0
  16. package/dist/v1/EventBroadcaster.d.ts +18 -1
  17. package/dist/v1/EventBroadcaster.js +1 -0
  18. package/dist/v1/adyen/widget.js +4 -13
  19. package/dist/v1/common.d.ts +8 -2
  20. package/dist/v1/index.d.ts +2 -2
  21. package/dist/v1/stripe/localizedText.d.ts +3 -0
  22. package/dist/v1/stripe/localizedText.js +28 -0
  23. package/dist/v1/stripe/session.d.ts +29 -6
  24. package/dist/v1/stripe/session.js +7 -1
  25. package/dist/v1/stripe/shared.d.ts +8 -5
  26. package/dist/v1/stripe/shared.js +55 -15
  27. package/dist/v1/stripe/terms.d.ts +1 -1
  28. package/dist/v1/stripe/terms.js +1 -1
  29. package/dist/v1/stripe/themes.js +2 -2
  30. package/dist/v1/stripe/widget.js +62 -23
  31. package/dist/v1/stripe/widgets/deferredMoto.d.ts +5 -0
  32. package/dist/v1/stripe/widgets/deferredMoto.js +200 -0
  33. package/dist/v1/stripe/widgets/moto.d.ts +2 -2
  34. package/dist/v1/stripe/widgets/payment.d.ts +2 -2
  35. package/dist/v1/widget.js +32 -4
  36. package/dist/version.d.ts +1 -1
  37. package/dist/version.js +1 -1
  38. package/package.json +8 -3
  39. package/styles/lightspeed-global-styles.css +81 -1
package/README.md CHANGED
@@ -31,6 +31,7 @@ Mount the widget with the payment session from your integration:
31
31
 
32
32
  ```ts
33
33
  import {LightspeedPayments} from '@lightspeed/online-payments-sdk';
34
+ import '@lightspeed/online-payments-sdk/styles/lightspeed-global-styles.css';
34
35
 
35
36
  const mountPoint = document.getElementById('payment-widget');
36
37
 
@@ -109,6 +110,23 @@ submitButton.addEventListener('click', async () => {
109
110
  controller.unmount();
110
111
  ```
111
112
 
113
+ `submit()` returns `Promise<WidgetSubmitResult>`. Existing intent-bound Stripe
114
+ and Adyen sessions retain their runtime behavior, but TypeScript integrations
115
+ that explicitly treat the submit result as `Event` must first handle or exclude
116
+ the new `RequiresFinalization` status. Listener callbacks are unchanged and
117
+ continue to receive only `Event`.
118
+
119
+ ### Deferred MOTO payments
120
+
121
+ Deferred Stripe `moto` and `moto-with-save` sessions return a
122
+ `RequiresFinalization` result for backend finalization instead of reporting
123
+ payment success. Integrations opting into this mode must forward the returned
124
+ artifact unchanged and handle definitive declines through
125
+ `reportFinalizationDecline`.
126
+
127
+ The complete [deferred Stripe MOTO integration guide](https://github.com/lightspeed-payments/lsp-online-payments-sdk/blob/main/packages/lsp-online-payments-sdk/docs/deferred-stripe-moto.md)
128
+ is maintained in the GitHub repository and is not included in the npm package.
129
+
112
130
  ## Theming
113
131
 
114
132
  Use `theme` to select a widget appearance:
@@ -133,3 +151,22 @@ import {THEME_COLORS} from '@lightspeed/online-payments-sdk';
133
151
  wrapper.style.backgroundColor = THEME_COLORS.DARK.BACKGROUND;
134
152
  wrapper.style.color = THEME_COLORS.DARK.TEXT;
135
153
  ```
154
+
155
+ ## Checking the SDK version
156
+
157
+ The running SDK version is available at runtime, matching the version published to npm:
158
+
159
+ ```ts
160
+ import {LightspeedPayments, SDK_VERSION} from '@lightspeed/online-payments-sdk';
161
+
162
+ console.log(LightspeedPayments.version); // e.g. "1.8.0"
163
+ console.log(SDK_VERSION); // e.g. "1.8.0"
164
+ ```
165
+
166
+ While a widget is mounted, its mount element also carries a `data-lightspeed-payments-sdk-version` attribute, so the running version can be inspected directly in browser devtools without any application code:
167
+
168
+ ```html
169
+ <div id="payment-widget" data-lightspeed-payments-sdk-version="1.8.0"></div>
170
+ ```
171
+
172
+ The attribute is removed when `controller.unmount()` is called.
package/dist/cjs/index.js CHANGED
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LightspeedPayments = exports.THEME_COLORS = void 0;
3
+ exports.LightspeedPayments = exports.SDK_VERSION = exports.THEME_COLORS = void 0;
4
4
  var v1_1 = require("./v1");
5
+ var version_1 = require("./version");
6
+ Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return version_1.SDK_VERSION; } });
5
7
  var v1_2 = require("./v1");
6
8
  Object.defineProperty(exports, "THEME_COLORS", { enumerable: true, get: function () { return v1_2.THEME_COLORS; } });
7
9
  exports.LightspeedPayments = {
8
10
  v1: v1_1.v1,
11
+ version: version_1.SDK_VERSION,
9
12
  };
@@ -66,6 +66,7 @@ var EventBroadcaster = /** @class */ (function () {
66
66
  var processedEvent = this.applyMiddlewares(event);
67
67
  var eventListener = this.listenersRegistry[event.status];
68
68
  eventListener(processedEvent);
69
+ return processedEvent;
69
70
  };
70
71
  return EventBroadcaster;
71
72
  }());
@@ -86,7 +86,7 @@ function mountSessionsFlow(mountElement, context, eventBroadcaster) {
86
86
  }
87
87
  // Multi-step Advanced flow: submit() surfaces the encrypted payment data for
88
88
  // the host to POST; handleNextAction() feeds the server response back to drive
89
- // native 3DS2. See MultiStepController in common.ts.
89
+ // 3DS actions. See MultiStepController in common.ts.
90
90
  function mountAdvancedFlow(mountElement, context, eventBroadcaster, onRequiresFinalization) {
91
91
  return __awaiter(this, void 0, void 0, function () {
92
92
  var stashedActions, pendingResolve, isValid, checkoutConfig, checkout, dropinConfiguration, dropIn;
@@ -167,7 +167,7 @@ function mountAdvancedFlow(mountElement, context, eventBroadcaster, onRequiresFi
167
167
  case 1:
168
168
  checkout = _b.sent();
169
169
  dropinConfiguration = {
170
- paymentMethodComponents: [adyen_web_1.Card, adyen_web_1.ApplePay, adyen_web_1.GooglePay, adyen_web_1.Bancontact],
170
+ paymentMethodComponents: [adyen_web_1.Card, adyen_web_1.ApplePay, adyen_web_1.GooglePay, adyen_web_1.Bancontact, adyen_web_1.Redirect],
171
171
  showStoredPaymentMethods: false,
172
172
  paymentMethodsConfiguration: {
173
173
  card: {
@@ -209,17 +209,8 @@ function mountAdvancedFlow(mountElement, context, eventBroadcaster, onRequiresFi
209
209
  var _a;
210
210
  var response = (serverResponse !== null && serverResponse !== void 0 ? serverResponse : {});
211
211
  if (response.action) {
212
- // 3DS1 (redirect) is out of scope: surface as an error so the host can
213
- // ask the shopper for a different card.
214
- if (response.action.type === 'redirect') {
215
- resolve({
216
- status: 'Error',
217
- error: { code: 'RedirectNotSupported', resultCode: response.resultCode },
218
- });
219
- return;
220
- }
221
- // Native 3DS2 step: let the component perform it, then resolve once
222
- // onAdditionalDetails hands us the next payload for the host to POST.
212
+ // Let Adyen Web perform the action. Native challenges call
213
+ // onAdditionalDetails; redirect actions navigate away to the issuer.
223
214
  pendingResolve = resolve;
224
215
  stashedActions === null || stashedActions === void 0 ? void 0 : stashedActions.resolve(response);
225
216
  return;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /** Locale-selected UI text rendered alongside Stripe Elements. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.getSavePaymentMethodText = getSavePaymentMethodText;
5
+ exports.getCardDeclinedText = getCardDeclinedText;
6
+ var SAVE_PAYMENT_METHOD_TEXT = {
7
+ de: 'Zahlungsinformationen für zukünftige Einkäufe speichern',
8
+ en: 'Save payment details for future purchases',
9
+ fr: 'Enregistrer les informations de paiement pour vos prochains achats',
10
+ nl: 'Betaalgegevens opslaan voor toekomstige aankopen',
11
+ };
12
+ var CARD_DECLINED_TEXT = {
13
+ de: 'Ihre Karte wurde abgelehnt.',
14
+ en: 'Your card was declined.',
15
+ fr: 'Votre carte a été refusée.',
16
+ nl: 'Uw kaart is geweigerd.',
17
+ };
18
+ function getLanguage(locale) {
19
+ var _a;
20
+ var resolvedLocale = !locale || locale === 'auto'
21
+ ? ((_a = globalThis.navigator) === null || _a === void 0 ? void 0 : _a.language) || 'en'
22
+ : locale;
23
+ return resolvedLocale.toLowerCase().split('-')[0];
24
+ }
25
+ function getSavePaymentMethodText(locale) {
26
+ var language = getLanguage(locale);
27
+ return SAVE_PAYMENT_METHOD_TEXT[language] || SAVE_PAYMENT_METHOD_TEXT.en;
28
+ }
29
+ function getCardDeclinedText(locale) {
30
+ var language = getLanguage(locale);
31
+ return CARD_DECLINED_TEXT[language] || CARD_DECLINED_TEXT.en;
32
+ }
@@ -1,2 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDeferredStripeSession = isDeferredStripeSession;
4
+ exports.isIntentBoundStripeSession = isIntentBoundStripeSession;
5
+ function isDeferredStripeSession(session) {
6
+ return session.context.intentMode === 'deferred';
7
+ }
8
+ function isIntentBoundStripeSession(session) {
9
+ return (session.context.intentMode === undefined ||
10
+ session.context.intentMode === 'intent-bound');
11
+ }
@@ -52,6 +52,7 @@ exports.createPaymentElementOptions = createPaymentElementOptions;
52
52
  exports.createAddressElementOptions = createAddressElementOptions;
53
53
  exports.buildCardConsentText = buildCardConsentText;
54
54
  exports.createCardConsentElement = createCardConsentElement;
55
+ exports.createSavePaymentMethodElement = createSavePaymentMethodElement;
55
56
  exports.createPaymentElement = createPaymentElement;
56
57
  exports.setupChangeEventHandler = setupChangeEventHandler;
57
58
  exports.createAddressElement = createAddressElement;
@@ -64,16 +65,17 @@ var ResultBuilder_1 = require("./ResultBuilder");
64
65
  var error_1 = require("../error");
65
66
  var themes_1 = require("./themes");
66
67
  var terms_1 = require("./terms");
68
+ var localizedText_1 = require("./localizedText");
67
69
  /**
68
70
  * Initialize Stripe with the given context
69
71
  */
70
72
  function initStripe(context, theme) {
71
73
  return __awaiter(this, void 0, void 0, function () {
72
- var publishableKey, clientSecret, customerSessionClientSecret, loadedStripe, stripe, themeConfig, elementsOptions, elements;
74
+ var publishableKey, loadedStripe, stripe, themeConfig, sharedElementsOptions, elements, elementsOptions, elementsOptions;
73
75
  return __generator(this, function (_a) {
74
76
  switch (_a.label) {
75
77
  case 0:
76
- publishableKey = context.publishableKey, clientSecret = context.clientSecret, customerSessionClientSecret = context.customerSessionClientSecret;
78
+ publishableKey = context.publishableKey;
77
79
  return [4 /*yield*/, (0, stripe_js_1.loadStripe)(publishableKey)];
78
80
  case 1:
79
81
  loadedStripe = _a.sent();
@@ -82,8 +84,15 @@ function initStripe(context, theme) {
82
84
  }
83
85
  stripe = loadedStripe;
84
86
  themeConfig = (0, themes_1.getThemeConfig)(theme);
85
- elementsOptions = __assign(__assign(__assign({ clientSecret: clientSecret, customerSessionClientSecret: customerSessionClientSecret }, (context.locale && { locale: context.locale })), (themeConfig && { appearance: themeConfig.appearance })), (themeConfig && { fonts: themeConfig.fonts }));
86
- elements = stripe.elements(elementsOptions);
87
+ sharedElementsOptions = __assign(__assign(__assign({}, (context.locale && { locale: context.locale })), (themeConfig && { appearance: themeConfig.appearance })), (themeConfig && { fonts: themeConfig.fonts }));
88
+ if (context.intentMode === 'deferred') {
89
+ elementsOptions = __assign(__assign(__assign({}, sharedElementsOptions), { mode: 'payment', amount: context.amount, currency: context.currency.toLowerCase(), paymentMethodTypes: context.paymentMethodTypes, paymentMethodCreation: 'manual' }), (context.onBehalfOf && { onBehalfOf: context.onBehalfOf }));
90
+ elements = stripe.elements(elementsOptions);
91
+ }
92
+ else {
93
+ elementsOptions = __assign(__assign({}, sharedElementsOptions), { clientSecret: context.clientSecret, customerSessionClientSecret: context.customerSessionClientSecret });
94
+ elements = stripe.elements(elementsOptions);
95
+ }
87
96
  return [2 /*return*/, { stripe: stripe, elements: elements }];
88
97
  }
89
98
  });
@@ -220,6 +229,24 @@ function createCardConsentElement(consentText) {
220
229
  container.appendChild(text);
221
230
  return container;
222
231
  }
232
+ function createSavePaymentMethodElement(mountElement, onChange, locale) {
233
+ var label = document.createElement('label');
234
+ label.className = 'stripe-save-payment-method-container';
235
+ var checkbox = document.createElement('input');
236
+ checkbox.type = 'checkbox';
237
+ checkbox.className = 'stripe-save-payment-method-checkbox';
238
+ checkbox.dataset.testid = 'save-payment-method-checkbox';
239
+ var text = document.createElement('span');
240
+ text.className = 'stripe-save-payment-method-text';
241
+ text.textContent = (0, localizedText_1.getSavePaymentMethodText)(locale);
242
+ label.appendChild(checkbox);
243
+ label.appendChild(text);
244
+ mountElement.appendChild(label);
245
+ // The label must remain clickable, but its consent text is not selectable.
246
+ label.addEventListener('selectstart', function (event) { return event.preventDefault(); });
247
+ checkbox.addEventListener('change', function () { return onChange(checkbox.checked); });
248
+ return label;
249
+ }
223
250
  /**
224
251
  * Create and mount payment element
225
252
  */
@@ -259,12 +286,12 @@ function createPaymentElement(elements, options, mountElement, eventBroadcaster)
259
286
  * Also includes the current save-payment-method checkbox state (when present) on every Change event,
260
287
  * and emits a Change event when that checkbox state changes.
261
288
  */
262
- function setupChangeEventHandler(paymentElement, eventBroadcaster, addressElement) {
289
+ function setupChangeEventHandler(paymentElement, eventBroadcaster, addressElement, onPaymentValueChange, initialSaveCheckboxState) {
263
290
  var paymentComplete = false;
264
291
  var addressComplete = !addressElement; // If no address element, consider it complete
265
292
  var previousComplete = null;
266
293
  var previousMethodType;
267
- var previousSaveCheckboxState; // Track save checkbox state
294
+ var previousSaveCheckboxState = initialSaveCheckboxState;
268
295
  var emitChangeEvent = function () {
269
296
  var complete = paymentComplete && addressComplete;
270
297
  previousComplete = complete;
@@ -275,23 +302,30 @@ function setupChangeEventHandler(paymentElement, eventBroadcaster, addressElemen
275
302
  })));
276
303
  };
277
304
  paymentElement.on('change', function (event) {
278
- var _a, _b;
305
+ var _a, _b, _c;
279
306
  paymentComplete = event.complete;
307
+ onPaymentValueChange === null || onPaymentValueChange === void 0 ? void 0 : onPaymentValueChange({
308
+ savePaymentMethod: (_a = event.value) === null || _a === void 0 ? void 0 : _a.savePaymentMethod,
309
+ });
280
310
  var completenessChanged = (paymentComplete && addressComplete) !== previousComplete;
281
- var methodType = (_a = event.value) === null || _a === void 0 ? void 0 : _a.type;
311
+ var methodType = (_b = event.value) === null || _b === void 0 ? void 0 : _b.type;
282
312
  var methodTypeChanged = methodType !== undefined && methodType !== previousMethodType;
283
313
  if (methodType !== undefined) {
284
314
  previousMethodType = methodType;
285
315
  }
286
316
  // `savePaymentMethod` reflects the "save for future use" checkbox; it is only
287
317
  // present on the change event when the element renders that checkbox.
288
- var saveCheckboxChanged = false;
289
- var saveCheckboxState = (_b = event.value) === null || _b === void 0 ? void 0 : _b.savePaymentMethod;
290
- if (saveCheckboxState !== undefined) {
291
- saveCheckboxChanged = previousSaveCheckboxState !== saveCheckboxState;
292
- previousSaveCheckboxState = saveCheckboxState;
318
+ var stripeSaveCheckboxChanged = false;
319
+ var stripeSaveCheckboxState = (_c = event.value) === null || _c === void 0 ? void 0 : _c.savePaymentMethod;
320
+ if (initialSaveCheckboxState === undefined &&
321
+ stripeSaveCheckboxState !== undefined) {
322
+ stripeSaveCheckboxChanged =
323
+ previousSaveCheckboxState !== stripeSaveCheckboxState;
324
+ previousSaveCheckboxState = stripeSaveCheckboxState;
293
325
  }
294
- if (completenessChanged || methodTypeChanged || saveCheckboxChanged) {
326
+ if (completenessChanged ||
327
+ methodTypeChanged ||
328
+ stripeSaveCheckboxChanged) {
295
329
  emitChangeEvent();
296
330
  }
297
331
  });
@@ -304,6 +338,13 @@ function setupChangeEventHandler(paymentElement, eventBroadcaster, addressElemen
304
338
  }
305
339
  });
306
340
  }
341
+ return function (saveCheckboxChecked) {
342
+ if (previousSaveCheckboxState === saveCheckboxChecked) {
343
+ return;
344
+ }
345
+ previousSaveCheckboxState = saveCheckboxChecked;
346
+ emitChangeEvent();
347
+ };
307
348
  }
308
349
  /**
309
350
  * Create and mount address element
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * Translatable strings for Stripe payment elements.
3
+ * Terms and consent text for Stripe payment elements.
4
4
  * These strings are prepared for Transifex extraction.
5
5
  *
6
6
  * Usage with Transifex:
@@ -53,7 +53,7 @@ function ensureThemeStylesheet() {
53
53
  }
54
54
  var styleElement = document.createElement('style');
55
55
  styleElement.id = THEME_STYLESHEET_ID;
56
- styleElement.textContent = "\n /* Dark theme styles for the mount element */\n .lsp-theme-dark {\n background-color: ".concat(exports.THEME_COLORS.DARK.BACKGROUND, " !important;\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n /* Dark theme styles for Stripe custom terms elements */\n .lsp-theme-dark .stripe-terms-chevron-icon {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-custom-terms-text {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-expandable-terms-content p {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n ");
56
+ styleElement.textContent = "\n /* Dark theme styles for the mount element */\n .lsp-theme-dark {\n background-color: ".concat(exports.THEME_COLORS.DARK.BACKGROUND, " !important;\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n /* Dark theme styles for Stripe custom terms elements */\n .lsp-theme-dark .stripe-terms-chevron-icon {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-custom-terms-text {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-expandable-terms-content p {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-save-payment-method-container {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-finalization-error {\n color: #ff8a8a !important;\n }\n .lsp-theme-dark .stripe-save-payment-method-checkbox {\n border-color: #697386;\n background-color: #30313d;\n }\n .lsp-theme-dark .stripe-save-payment-method-checkbox:checked {\n border-color: #007ea3;\n background-color: #007ea3;\n }\n .lsp-theme-dark .stripe-save-payment-method-checkbox:focus-visible {\n border-color: #00d4ff;\n box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.25);\n }\n ");
57
57
  document.head.appendChild(styleElement);
58
58
  }
59
59
  /**
@@ -77,7 +77,7 @@ function ensureInvoicingDarkStylesheet() {
77
77
  }
78
78
  var styleElement = document.createElement('style');
79
79
  styleElement.id = INVOICING_DARK_STYLESHEET_ID;
80
- styleElement.textContent = "\n /*\n * Mirror the non-colour .lsp-theme-invoicing rules from\n * lightspeed-global-styles.css. Class selectors match whole tokens, so an\n * element carrying the class lsp-theme-invoicing-dark is never matched by\n * the selector .lsp-theme-invoicing; without these the terms text would\n * fall back to the system font while the Elements iframe renders Inter.\n */\n .lsp-theme-invoicing-dark {\n color: #e3e4e9;\n padding-bottom: 0 !important;\n }\n .lsp-theme-invoicing-dark .stripe-custom-terms-text,\n .lsp-theme-invoicing-dark .stripe-expandable-terms-content p {\n color: #e3e4e9;\n font-family: 'Inter', system-ui, sans-serif;\n }\n /*\n * Links and the expand toggle. lightspeed-global-styles.css colours these\n * #635bff, which is close to unreadable on a dark surface, so they take the\n * consumer dark interactive colour instead. The chevron inherits from its\n * toggle so the two can never drift apart.\n */\n .lsp-theme-invoicing-dark .stripe-custom-terms-text a,\n .lsp-theme-invoicing-dark .stripe-expandable-terms-content a,\n .lsp-theme-invoicing-dark .stripe-expandable-terms-toggle {\n color: #6cb5fb;\n }\n .lsp-theme-invoicing-dark .stripe-terms-chevron-icon {\n color: inherit;\n }\n ";
80
+ styleElement.textContent = "\n /*\n * Mirror the non-colour .lsp-theme-invoicing rules from\n * lightspeed-global-styles.css. Class selectors match whole tokens, so an\n * element carrying the class lsp-theme-invoicing-dark is never matched by\n * the selector .lsp-theme-invoicing; without these the terms text would\n * fall back to the system font while the Elements iframe renders Inter.\n */\n .lsp-theme-invoicing-dark {\n color: #e3e4e9;\n padding-bottom: 0 !important;\n }\n .lsp-theme-invoicing-dark .stripe-custom-terms-text,\n .lsp-theme-invoicing-dark .stripe-expandable-terms-content p,\n .lsp-theme-invoicing-dark .stripe-save-payment-method-container,\n .lsp-theme-invoicing-dark .stripe-finalization-error {\n color: #e3e4e9;\n font-family: 'Inter', system-ui, sans-serif;\n }\n .lsp-theme-invoicing-dark .stripe-finalization-error {\n color: #ffa597;\n }\n .lsp-theme-invoicing-dark .stripe-save-payment-method-checkbox {\n border-color: #525256;\n background-color: #242427;\n }\n .lsp-theme-invoicing-dark .stripe-save-payment-method-checkbox:checked {\n border-color: #286ea8;\n background-color: #286ea8;\n }\n .lsp-theme-invoicing-dark .stripe-save-payment-method-checkbox:focus-visible {\n border-color: #6cb5fb;\n box-shadow: 0 0 0 3px rgba(108, 181, 251, 0.25);\n }\n /*\n * Links and the expand toggle. lightspeed-global-styles.css colours these\n * #635bff, which is close to unreadable on a dark surface, so they take the\n * consumer dark interactive colour instead. The chevron inherits from its\n * toggle so the two can never drift apart.\n */\n .lsp-theme-invoicing-dark .stripe-custom-terms-text a,\n .lsp-theme-invoicing-dark .stripe-expandable-terms-content a,\n .lsp-theme-invoicing-dark .stripe-expandable-terms-toggle {\n color: #6cb5fb;\n }\n .lsp-theme-invoicing-dark .stripe-terms-chevron-icon {\n color: inherit;\n }\n ";
81
81
  document.head.appendChild(styleElement);
82
82
  }
83
83
  /**
@@ -38,15 +38,18 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.StripeWidget = void 0;
40
40
  exports.mount = mount;
41
+ var session_1 = require("./session");
42
+ var error_1 = require("../error");
41
43
  var payment_1 = require("./widgets/payment");
42
44
  var moto_1 = require("./widgets/moto");
45
+ var deferredMoto_1 = require("./widgets/deferredMoto");
43
46
  var themes_1 = require("./themes");
44
47
  /**
45
48
  * Main mount function that delegates to appropriate widget based on session type
46
49
  */
47
50
  function mount(mountElement, session, eventBroadcaster, defaultValues, theme) {
48
51
  return __awaiter(this, void 0, void 0, function () {
49
- var sessionType, widgetController, _a, originalUnmount_1, error_1;
52
+ var sessionType, widgetController_1, widgetController, _a, error_2;
50
53
  return __generator(this, function (_b) {
51
54
  switch (_b.label) {
52
55
  case 0:
@@ -57,43 +60,79 @@ function mount(mountElement, session, eventBroadcaster, defaultValues, theme) {
57
60
  sessionType = session.metadata.sessionType;
58
61
  _b.label = 1;
59
62
  case 1:
60
- _b.trys.push([1, 8, , 9]);
63
+ _b.trys.push([1, 10, , 11]);
64
+ if (!(0, session_1.isDeferredStripeSession)(session)) return [3 /*break*/, 3];
65
+ validateDeferredSession(session, sessionType);
66
+ return [4 /*yield*/, (0, deferredMoto_1.mountDeferredMotoWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
67
+ case 2:
68
+ widgetController_1 = _b.sent();
69
+ return [2 /*return*/, withThemeCleanup(widgetController_1, mountElement, theme)];
70
+ case 3:
71
+ if (!(0, session_1.isIntentBoundStripeSession)(session)) {
72
+ throw new error_1.InvalidSessionPayloadError('Invalid Stripe session context');
73
+ }
61
74
  widgetController = void 0;
62
75
  _a = sessionType;
63
76
  switch (_a) {
64
- case 'payment': return [3 /*break*/, 2];
65
- case 'payment-with-save': return [3 /*break*/, 2];
66
- case 'moto': return [3 /*break*/, 4];
67
- case 'moto-with-save': return [3 /*break*/, 4];
68
- case 'save': return [3 /*break*/, 4];
77
+ case 'payment': return [3 /*break*/, 4];
78
+ case 'payment-with-save': return [3 /*break*/, 4];
79
+ case 'moto': return [3 /*break*/, 6];
80
+ case 'moto-with-save': return [3 /*break*/, 6];
81
+ case 'save': return [3 /*break*/, 6];
69
82
  }
70
- return [3 /*break*/, 6];
71
- case 2: return [4 /*yield*/, (0, payment_1.mountPaymentWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
72
- case 3:
73
- widgetController = _b.sent();
74
- return [3 /*break*/, 7];
75
- case 4: return [4 /*yield*/, (0, moto_1.mountMotoWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
83
+ return [3 /*break*/, 8];
84
+ case 4: return [4 /*yield*/, (0, payment_1.mountPaymentWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
76
85
  case 5:
77
86
  widgetController = _b.sent();
78
- return [3 /*break*/, 7];
79
- case 6: throw new Error("Unsupported session type: ".concat(sessionType));
87
+ return [3 /*break*/, 9];
88
+ case 6: return [4 /*yield*/, (0, moto_1.mountMotoWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
80
89
  case 7:
81
- originalUnmount_1 = widgetController.unmount;
82
- widgetController.unmount = function () {
83
- (0, themes_1.removeThemeClass)(mountElement, theme);
84
- originalUnmount_1();
85
- };
86
- return [2 /*return*/, widgetController];
87
- case 8:
88
- error_1 = _b.sent();
90
+ widgetController = _b.sent();
91
+ return [3 /*break*/, 9];
92
+ case 8: throw new Error("Unsupported session type: ".concat(sessionType));
93
+ case 9:
94
+ // Wrap unmount to include theme cleanup
95
+ return [2 /*return*/, withThemeCleanup(widgetController, mountElement, theme)];
96
+ case 10:
97
+ error_2 = _b.sent();
89
98
  // Clean up theme class if mounting fails
90
99
  (0, themes_1.removeThemeClass)(mountElement, theme);
91
- throw error_1;
92
- case 9: return [2 /*return*/];
100
+ throw error_2;
101
+ case 11: return [2 /*return*/];
93
102
  }
94
103
  });
95
104
  });
96
105
  }
106
+ function validateDeferredSession(session, sessionType) {
107
+ var context = session.context;
108
+ if (!['moto', 'moto-with-save'].includes(sessionType || '') ||
109
+ context.intentMode !== 'deferred' ||
110
+ context.intent !== 'payment' ||
111
+ !Number.isSafeInteger(context.amount) ||
112
+ context.amount <= 0 ||
113
+ typeof context.currency !== 'string' ||
114
+ !/^[a-z]{3}$/i.test(context.currency) ||
115
+ typeof context.publishableKey !== 'string' ||
116
+ context.publishableKey.length === 0 ||
117
+ typeof context.onBehalfOf !== 'string' ||
118
+ context.onBehalfOf.length === 0 ||
119
+ context.onBehalfOf.trim() !== context.onBehalfOf ||
120
+ !Array.isArray(context.paymentMethodTypes) ||
121
+ context.paymentMethodTypes.length !== 1 ||
122
+ context.paymentMethodTypes[0] !== 'card' ||
123
+ 'clientSecret' in context ||
124
+ 'customerSessionClientSecret' in context) {
125
+ throw new error_1.InvalidSessionPayloadError('Invalid deferred Stripe MOTO session context');
126
+ }
127
+ }
128
+ function withThemeCleanup(controller, mountElement, theme) {
129
+ var originalUnmount = controller.unmount;
130
+ controller.unmount = function () {
131
+ (0, themes_1.removeThemeClass)(mountElement, theme);
132
+ originalUnmount();
133
+ };
134
+ return controller;
135
+ }
97
136
  exports.StripeWidget = {
98
137
  mount: mount,
99
138
  };