@idonatedev/idonate-sdk 1.2.0-dev2 → 1.2.0-dev21

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 (56) hide show
  1. package/dist/constants.js +11 -2
  2. package/dist/esm/constants.js +11 -2
  3. package/dist/esm/idonate-client.js +18 -8
  4. package/dist/esm/recaptcha.d.ts +1 -0
  5. package/dist/esm/recaptcha.js +26 -2
  6. package/dist/esm/shared.js +9 -1
  7. package/dist/esm/tokenize/CardConnectTokenizer.d.ts +8 -1
  8. package/dist/esm/tokenize/CardConnectTokenizer.js +353 -104
  9. package/dist/esm/tokenize/PayPalTokenizer.d.ts +6 -0
  10. package/dist/esm/tokenize/PayPalTokenizer.js +66 -16
  11. package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +23 -1
  12. package/dist/esm/tokenize/SpreedlyTokenizer.js +330 -151
  13. package/dist/esm/tokenize/Tokenizer.d.ts +6 -2
  14. package/dist/esm/tokenize/Tokenizer.js +24 -8
  15. package/dist/esm/tokenize/gateway-utils.d.ts +2 -0
  16. package/dist/esm/tokenize/gateway-utils.js +27 -0
  17. package/dist/esm/tokenize/index.d.ts +3 -2
  18. package/dist/esm/tokenize/index.js +1 -0
  19. package/dist/esm/tokenize/spreedly-secure.js +6 -2
  20. package/dist/esm/tokenize/styles.d.ts +1 -1
  21. package/dist/esm/tokenize/styles.js +20 -1
  22. package/dist/esm/tokenize/tokenizer-constants.d.ts +1 -0
  23. package/dist/esm/tokenize/tokenizer-constants.js +1 -0
  24. package/dist/esm/tokenize/tokenizer-utils.d.ts +4 -1
  25. package/dist/esm/tokenize/tokenizer-utils.js +77 -4
  26. package/dist/esm/tokenize/types.d.ts +33 -8
  27. package/dist/esm/typeAdapters.js +6 -4
  28. package/dist/esm/types.d.ts +4 -10
  29. package/dist/idonate-client.js +18 -8
  30. package/dist/recaptcha.d.ts +1 -0
  31. package/dist/recaptcha.js +27 -2
  32. package/dist/shared.js +9 -1
  33. package/dist/tokenize/CardConnectTokenizer.d.ts +8 -1
  34. package/dist/tokenize/CardConnectTokenizer.js +351 -105
  35. package/dist/tokenize/PayPalTokenizer.d.ts +6 -0
  36. package/dist/tokenize/PayPalTokenizer.js +66 -16
  37. package/dist/tokenize/SpreedlyTokenizer.d.ts +23 -1
  38. package/dist/tokenize/SpreedlyTokenizer.js +327 -148
  39. package/dist/tokenize/Tokenizer.d.ts +6 -2
  40. package/dist/tokenize/Tokenizer.js +24 -8
  41. package/dist/tokenize/gateway-utils.d.ts +2 -0
  42. package/dist/tokenize/gateway-utils.js +30 -0
  43. package/dist/tokenize/index.d.ts +3 -2
  44. package/dist/tokenize/index.js +3 -1
  45. package/dist/tokenize/spreedly-secure.js +6 -2
  46. package/dist/tokenize/styles.d.ts +1 -1
  47. package/dist/tokenize/styles.js +20 -1
  48. package/dist/tokenize/tokenizer-constants.d.ts +1 -0
  49. package/dist/tokenize/tokenizer-constants.js +2 -1
  50. package/dist/tokenize/tokenizer-utils.d.ts +4 -1
  51. package/dist/tokenize/tokenizer-utils.js +80 -4
  52. package/dist/tokenize/types.d.ts +33 -8
  53. package/dist/typeAdapters.js +6 -4
  54. package/dist/types.d.ts +4 -10
  55. package/package.json +33 -2
  56. package/umd/idonate-sdk.js +1 -1
@@ -21,16 +21,26 @@ const tokenizer_utils_1 = require("./tokenizer-utils");
21
21
  const SPREEDLY_SCRIPT_URL = 'https://core.spreedly.com/iframe/iframe-v1.min.js';
22
22
  const SPREEDLY_SCRIPT_ID = 'spreedly-iframe-script';
23
23
  class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
24
- constructor(environmentKey, containerId, styles, mode = 'credit_card', bankCountry = 'US', enableTestMode = false, layout = 'single-line') {
24
+ constructor(environmentKey, containerId, styles, mode = 'credit_card', bankCountry = 'US', enableTestMode = false, layout = 'single-line', responsiveBreakpoint = tokenizer_constants_1.RESPONSIVE_BREAKPOINT, customPlaceholders) {
25
25
  super();
26
26
  this.environmentKey = environmentKey;
27
27
  this.containerId = containerId;
28
28
  this.layout = layout;
29
+ this.customPlaceholders = customPlaceholders;
29
30
  this.bankCountry = 'US';
30
31
  this.enableTestMode = false;
32
+ this.numberBaseCss = '';
33
+ this.cvvBaseCss = '';
34
+ this.numberErrorCss = '';
35
+ this.cvvErrorCss = '';
36
+ this.numberHasError = false;
37
+ this.cvvHasError = false;
38
+ this.effectiveLayout = 'single-line';
39
+ this.responsiveBreakpoint = tokenizer_constants_1.RESPONSIVE_BREAKPOINT;
31
40
  this.mode = mode;
32
41
  this.bankCountry = bankCountry;
33
42
  this.enableTestMode = enableTestMode;
43
+ this.responsiveBreakpoint = responsiveBreakpoint;
34
44
  if (mode === 'credit_card') {
35
45
  const SpreedlyFrame = window.SpreedlyPaymentFrame;
36
46
  if (SpreedlyFrame) {
@@ -66,40 +76,33 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
66
76
  }
67
77
  static create(gateway, container, config) {
68
78
  return __awaiter(this, void 0, void 0, function* () {
69
- var _a;
79
+ var _a, _b;
70
80
  if (container.mode !== 'bank_account') {
71
81
  yield SpreedlyTokenizer.ensureSpreedlyLoaded();
72
82
  }
73
- let environmentKey = (_a = gateway.config) === null || _a === void 0 ? void 0 : _a.environment_key;
83
+ let environmentKey = (_a = gateway.config) === null || _a === void 0 ? void 0 : _a.environmentKey;
74
84
  if (!environmentKey && config.clientConfig.spreedlyEnvironmentKey) {
75
85
  environmentKey = config.clientConfig.spreedlyEnvironmentKey;
76
86
  }
77
87
  if (!environmentKey) {
78
- environmentKey = '';
88
+ throw new Error('Spreedly environment key is required. Provide it via gateway.config.environmentKey or client config.');
79
89
  }
80
- const tokenizer = new SpreedlyTokenizer(environmentKey, container.containerId, container.styling, container.mode || 'credit_card', container.bankCountry || 'US', container.enableTestMode || false, container.layout || 'single-line');
90
+ const tokenizer = new SpreedlyTokenizer(environmentKey, container.containerId, container.styling, container.mode || 'credit_card', container.bankCountry || 'US', container.enableTestMode || false, container.layout || 'single-line', (_b = container.responsiveBreakpoint) !== null && _b !== void 0 ? _b : tokenizer_constants_1.RESPONSIVE_BREAKPOINT, container.placeholders);
81
91
  tokenizer.organizationId = config.organizationId;
82
92
  tokenizer.embedId = config.embedId;
83
93
  tokenizer.clientConfig = config.clientConfig;
84
94
  tokenizer.createInternalElements();
85
- let securityArgs;
86
95
  if (container.mode === 'credit_card' &&
87
96
  config.clientConfig.enableSpreedlySecureTokenization) {
88
97
  if (!config.organizationId || !config.embedId) {
89
98
  throw new Error('Secure tokenization is enabled but organizationId and embedId are required');
90
99
  }
91
- try {
92
- securityArgs = yield (0, spreedly_secure_1.fetchSpreedlySecurityArgs)(config.clientConfig, config.organizationId, config.embedId);
93
- }
94
- catch (error) {
95
- throw new Error(`Secure tokenization is enabled but failed to initialize: ${error instanceof Error ? error.message : 'Unknown error'}`);
96
- }
97
100
  }
98
- yield tokenizer.init(securityArgs);
101
+ yield tokenizer.init();
99
102
  return tokenizer;
100
103
  });
101
104
  }
102
- init(securityArgs) {
105
+ init() {
103
106
  return __awaiter(this, void 0, void 0, function* () {
104
107
  this.containerEl = document.getElementById(this.containerId);
105
108
  if (this.mode === 'bank_account') {
@@ -143,11 +146,12 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
143
146
  reject(new Error('Spreedly initialization timeout'));
144
147
  }, tokenizer_constants_1.INIT_TIMEOUT);
145
148
  this.spreedly.on('ready', () => {
149
+ var _a, _b;
146
150
  clearTimeout(timeout);
147
- this.spreedly.setPlaceholder('number', tokenizer_constants_1.PLACEHOLDERS.cardNumber);
151
+ this.spreedly.setPlaceholder('number', ((_a = this.customPlaceholders) === null || _a === void 0 ? void 0 : _a.cardNumber) || tokenizer_constants_1.PLACEHOLDERS.cardNumber);
148
152
  this.spreedly.setFieldType('number', 'text');
149
153
  this.spreedly.setNumberFormat('prettyFormat');
150
- this.spreedly.setPlaceholder('cvv', tokenizer_constants_1.PLACEHOLDERS.cvv);
154
+ this.spreedly.setPlaceholder('cvv', ((_b = this.customPlaceholders) === null || _b === void 0 ? void 0 : _b.cvv) || tokenizer_constants_1.PLACEHOLDERS.cvv);
151
155
  this.spreedly.setFieldType('cvv', 'text');
152
156
  this.applyUnifiedStyles();
153
157
  if (this.enableTestMode &&
@@ -165,23 +169,37 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
165
169
  this.emit('ready');
166
170
  resolve();
167
171
  });
172
+ this.spreedly.on('paymentMethod', (token, pmData) => {
173
+ const paymentToken = {
174
+ token,
175
+ lastFour: pmData.last_four_digits,
176
+ cardType: this.normalizeCardType(pmData.card_type),
177
+ paymentMethodType: 'credit_card',
178
+ provider: 'spreedly',
179
+ };
180
+ if (this.tokenizationResolve) {
181
+ const resolveTokenization = this.tokenizationResolve;
182
+ this.clearTokenizationState();
183
+ this.emit('tokenReady', paymentToken);
184
+ resolveTokenization(paymentToken);
185
+ }
186
+ });
168
187
  this.spreedly.on('errors', (errors) => {
169
- this.emit('error', new types_1.TokenizationError(errors));
188
+ const error = new types_1.TokenizationError(errors);
189
+ this.emit('error', error);
190
+ if (this.tokenizationReject) {
191
+ const rejectTokenization = this.tokenizationReject;
192
+ this.clearTokenizationState();
193
+ rejectTokenization(error);
194
+ }
170
195
  });
171
196
  this.spreedly.on('fieldEvent', (fieldName, eventType, activeEl, inputProperties) => {
172
197
  this.handleFieldEvent(fieldName, eventType, inputProperties);
173
198
  });
174
- const initOptions = {
199
+ this.spreedly.init(this.environmentKey, {
175
200
  numberEl: this.numberEl,
176
201
  cvvEl: this.cvvEl,
177
- };
178
- if (securityArgs) {
179
- initOptions.certificateToken = securityArgs.certificate_token;
180
- initOptions.signature = securityArgs.signature;
181
- initOptions.timestamp = securityArgs.timestamp;
182
- initOptions.nonce = securityArgs.nonce;
183
- }
184
- this.spreedly.init(this.environmentKey, initOptions);
202
+ });
185
203
  });
186
204
  });
187
205
  }
@@ -199,58 +217,45 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
199
217
  });
200
218
  }
201
219
  tokenizeCardInternal(cardData) {
220
+ if (this.tokenizationPromise) {
221
+ return this.tokenizationPromise;
222
+ }
223
+ const expiry = this.parseExpiry(this.expiryEl);
224
+ if (!expiry) {
225
+ return Promise.reject(new types_1.TokenizationError('Expiration date is required', 'VALIDATION_ERROR'));
226
+ }
227
+ this.tokenizationPromise = this.executeCardTokenization(cardData, expiry).finally(() => {
228
+ this.tokenizationPromise = undefined;
229
+ });
230
+ return this.tokenizationPromise;
231
+ }
232
+ executeCardTokenization(cardData, expiry) {
202
233
  return __awaiter(this, void 0, void 0, function* () {
234
+ var _a;
235
+ let securityFields = {};
236
+ if ((_a = this.clientConfig) === null || _a === void 0 ? void 0 : _a.enableSpreedlySecureTokenization) {
237
+ try {
238
+ const args = yield (0, spreedly_secure_1.fetchSpreedlySecurityArgs)(this.clientConfig, this.organizationId, this.embedId);
239
+ securityFields = {
240
+ nonce: args.nonce,
241
+ timestamp: args.timestamp,
242
+ certificateToken: args.certificate_token,
243
+ signature: args.signature,
244
+ };
245
+ }
246
+ catch (error) {
247
+ throw new types_1.TokenizationError(`Secure tokenization failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'SECURE_TOKENIZATION_ERROR');
248
+ }
249
+ }
203
250
  return new Promise((resolve, reject) => {
204
251
  var _a, _b, _c, _d, _e, _f;
205
- const timeout = setTimeout(() => {
206
- if (this.spreedly && this.spreedly.removeHandlers) {
207
- this.spreedly.removeHandlers();
208
- }
252
+ this.tokenizationResolve = resolve;
253
+ this.tokenizationReject = reject;
254
+ this.tokenizationTimeout = setTimeout(() => {
255
+ this.clearTokenizationState();
209
256
  reject(new types_1.TokenizationError('Tokenization timeout', 'TIMEOUT'));
210
257
  }, tokenizer_constants_1.TOKENIZE_TIMEOUT);
211
- const cleanup = () => {
212
- clearTimeout(timeout);
213
- if (this.spreedly && this.spreedly.removeHandlers) {
214
- this.spreedly.removeHandlers();
215
- }
216
- };
217
- this.spreedly.on('paymentMethod', (token, pmData) => {
218
- cleanup();
219
- const paymentToken = {
220
- token,
221
- lastFour: pmData.last_four_digits,
222
- cardType: this.normalizeCardType(pmData.card_type),
223
- provider: 'spreedly',
224
- };
225
- this.emit('tokenReady', paymentToken);
226
- resolve(paymentToken);
227
- });
228
- this.spreedly.on('errors', (errors) => {
229
- cleanup();
230
- reject(new types_1.TokenizationError(errors));
231
- });
232
- const expiry = this.parseExpiry(this.expiryEl);
233
- if (!expiry) {
234
- cleanup();
235
- reject(new types_1.TokenizationError('Expiration date is required', 'VALIDATION_ERROR'));
236
- return;
237
- }
238
- const expiryMonth = expiry.month;
239
- const expiryYear = expiry.year;
240
- this.spreedly.tokenizeCreditCard({
241
- first_name: cardData.firstName,
242
- last_name: cardData.lastName,
243
- month: expiryMonth,
244
- year: expiryYear,
245
- email: cardData.email,
246
- phone_number: cardData.phone,
247
- address1: (_a = cardData.address) === null || _a === void 0 ? void 0 : _a.address1,
248
- address2: (_b = cardData.address) === null || _b === void 0 ? void 0 : _b.address2,
249
- city: (_c = cardData.address) === null || _c === void 0 ? void 0 : _c.city,
250
- state: (_d = cardData.address) === null || _d === void 0 ? void 0 : _d.state,
251
- zip: (_e = cardData.address) === null || _e === void 0 ? void 0 : _e.zip,
252
- country: (_f = cardData.address) === null || _f === void 0 ? void 0 : _f.country,
253
- });
258
+ this.spreedly.tokenizeCreditCard(Object.assign({ first_name: cardData.firstName, last_name: cardData.lastName, month: expiry.month, year: expiry.year, email: cardData.email, phone_number: cardData.phone, address1: (_a = cardData.address) === null || _a === void 0 ? void 0 : _a.address1, address2: (_b = cardData.address) === null || _b === void 0 ? void 0 : _b.address2, city: (_c = cardData.address) === null || _c === void 0 ? void 0 : _c.city, state: (_d = cardData.address) === null || _d === void 0 ? void 0 : _d.state, zip: (_e = cardData.address) === null || _e === void 0 ? void 0 : _e.zip, country: (_f = cardData.address) === null || _f === void 0 ? void 0 : _f.country }, securityFields));
254
259
  });
255
260
  });
256
261
  }
@@ -262,7 +267,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
262
267
  minWidth: tokenizer_constants_1.CANADIAN_BANK_FIELD_FLEX.accountType.minWidth,
263
268
  });
264
269
  this.applyInputStyles(this.accountTypeEl, this.mergedStyles, 'left');
265
- container.appendChild(this.accountTypeEl);
270
+ this.appendField(container, this.accountTypeEl, 'Account Type');
266
271
  this.institutionNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-institution`, 'text', 'Inst *', 3);
267
272
  Object.assign(this.institutionNumberEl.style, {
268
273
  flex: '1',
@@ -279,7 +284,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
279
284
  }
280
285
  this.updateBankAccountValidation();
281
286
  });
282
- container.appendChild(this.institutionNumberEl);
287
+ this.appendField(container, this.institutionNumberEl, 'Institution');
283
288
  this.transitNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-transit`, 'text', 'Transit *', 5);
284
289
  Object.assign(this.transitNumberEl.style, {
285
290
  flex: '2',
@@ -296,7 +301,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
296
301
  }
297
302
  this.updateBankAccountValidation();
298
303
  });
299
- container.appendChild(this.transitNumberEl);
304
+ this.appendField(container, this.transitNumberEl, 'Transit');
300
305
  this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *');
301
306
  Object.assign(this.accountNumberEl.style, {
302
307
  flex: '1',
@@ -314,7 +319,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
314
319
  }
315
320
  this.updateBankAccountValidation();
316
321
  });
317
- container.appendChild(this.accountNumberEl);
322
+ this.appendField(container, this.accountNumberEl, 'Account Number');
318
323
  }
319
324
  else {
320
325
  this.institutionNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-institution`, 'text', 'Inst *', 3);
@@ -333,7 +338,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
333
338
  }
334
339
  this.updateBankAccountValidation();
335
340
  });
336
- container.appendChild(this.institutionNumberEl);
341
+ this.appendField(container, this.institutionNumberEl, 'Institution');
337
342
  this.transitNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-transit`, 'text', 'Transit *', 5);
338
343
  Object.assign(this.transitNumberEl.style, {
339
344
  flex: tokenizer_constants_1.CANADIAN_BANK_FIELD_FLEX.transitNumber.flex,
@@ -350,7 +355,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
350
355
  }
351
356
  this.updateBankAccountValidation();
352
357
  });
353
- container.appendChild(this.transitNumberEl);
358
+ this.appendField(container, this.transitNumberEl, 'Transit');
354
359
  this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *');
355
360
  Object.assign(this.accountNumberEl.style, {
356
361
  flex: tokenizer_constants_1.CANADIAN_BANK_FIELD_FLEX.accountNumber.flex,
@@ -367,14 +372,14 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
367
372
  }
368
373
  this.updateBankAccountValidation();
369
374
  });
370
- container.appendChild(this.accountNumberEl);
375
+ this.appendField(container, this.accountNumberEl, 'Account Number');
371
376
  this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
372
377
  Object.assign(this.accountTypeEl.style, {
373
378
  flex: tokenizer_constants_1.CANADIAN_BANK_FIELD_FLEX.accountType.flex,
374
379
  minWidth: tokenizer_constants_1.CANADIAN_BANK_FIELD_FLEX.accountType.minWidth,
375
380
  });
376
381
  this.applyInputStyles(this.accountTypeEl, this.mergedStyles, 'right');
377
- container.appendChild(this.accountTypeEl);
382
+ this.appendField(container, this.accountTypeEl, 'Account Type');
378
383
  }
379
384
  }
380
385
  tokenizeBankAccountInternal(bankData) {
@@ -442,18 +447,23 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
442
447
  accountType: accountType,
443
448
  accountHolderType: accountHolderType,
444
449
  },
445
- }, this.clientConfig);
446
- return {
450
+ }, this.clientConfig, this.environmentKey);
451
+ const paymentToken = {
447
452
  token: result,
448
453
  lastFour: accountNumber.slice(-4),
449
454
  accountType: accountType,
450
455
  paymentMethodType: 'bank_account',
451
456
  provider: 'spreedly',
452
457
  };
458
+ this.emit('tokenReady', paymentToken);
459
+ return paymentToken;
453
460
  });
454
461
  }
455
462
  validate() {
456
463
  return __awaiter(this, void 0, void 0, function* () {
464
+ if (!this.isReady) {
465
+ throw new Error('Tokenizer not initialized');
466
+ }
457
467
  if (this.mode === 'bank_account') {
458
468
  return this.validateBankAccountInternal();
459
469
  }
@@ -588,19 +598,21 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
588
598
  const isConnected = ((_a = this.mergedStyles.container) === null || _a === void 0 ? void 0 : _a.gap) === '0';
589
599
  if (this.mergedStyles.input) {
590
600
  if (isConnected) {
591
- const numberStyles = Object.assign(Object.assign({}, this.mergedStyles.input), { borderRight: 'none', borderRadius: this.mergedStyles.input.borderRadius
601
+ const numberStyles = Object.assign(Object.assign({}, this.mergedStyles.input), { borderRight: '1px solid transparent', borderRadius: this.mergedStyles.input.borderRadius
592
602
  ? `${this.mergedStyles.input.borderRadius} 0 0 ${this.mergedStyles.input.borderRadius}`
593
603
  : '0' });
594
- const numberCss = this.stylesToCssString(numberStyles);
595
- this.spreedly.setStyle('number', numberCss);
604
+ this.numberBaseCss = this.stylesToCssString(numberStyles);
605
+ this.spreedly.setStyle('number', this.numberBaseCss);
596
606
  const cvvStyles = Object.assign(Object.assign({}, this.mergedStyles.input), { borderRadius: this.mergedStyles.input.borderRadius
597
607
  ? `0 ${this.mergedStyles.input.borderRadius} ${this.mergedStyles.input.borderRadius} 0`
598
608
  : '0' });
599
- const cvvCss = this.stylesToCssString(cvvStyles);
600
- this.spreedly.setStyle('cvv', cvvCss);
609
+ this.cvvBaseCss = this.stylesToCssString(cvvStyles);
610
+ this.spreedly.setStyle('cvv', this.cvvBaseCss);
601
611
  }
602
612
  else {
603
613
  const baseCss = this.stylesToCssString(this.mergedStyles.input);
614
+ this.numberBaseCss = baseCss;
615
+ this.cvvBaseCss = baseCss;
604
616
  this.spreedly.setStyle('number', baseCss);
605
617
  this.spreedly.setStyle('cvv', baseCss);
606
618
  }
@@ -611,9 +623,20 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
611
623
  this.spreedly.setStyle('cvv:focus', focusCss);
612
624
  }
613
625
  if (this.mergedStyles.error) {
614
- const errorCss = this.stylesToCssString(this.mergedStyles.error);
615
- this.spreedly.setStyle('number.invalid', errorCss);
616
- this.spreedly.setStyle('cvv.invalid', errorCss);
626
+ const errorOverrides = {};
627
+ if (this.mergedStyles.error.borderColor) {
628
+ errorOverrides.border = `1px solid ${this.mergedStyles.error.borderColor}`;
629
+ }
630
+ if (this.mergedStyles.error.backgroundColor) {
631
+ errorOverrides.backgroundColor =
632
+ this.mergedStyles.error.backgroundColor;
633
+ }
634
+ if (this.mergedStyles.error.color) {
635
+ errorOverrides.color = this.mergedStyles.error.color;
636
+ }
637
+ const errorCss = this.stylesToCssString(errorOverrides);
638
+ this.numberErrorCss = this.numberBaseCss + '; ' + errorCss;
639
+ this.cvvErrorCss = this.cvvBaseCss + '; ' + errorCss;
617
640
  }
618
641
  }
619
642
  stylesToCssString(styles) {
@@ -641,13 +664,41 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
641
664
  this.accountNumberEl.value = '';
642
665
  if (this.accountTypeEl)
643
666
  this.accountTypeEl.selectedIndex = 0;
667
+ this.currentValidationState = {
668
+ isValid: false,
669
+ routingNumber: { isValid: false, isEmpty: true },
670
+ accountNumber: { isValid: false, isEmpty: true },
671
+ };
644
672
  }
645
673
  else {
646
674
  this.spreedly.reload();
647
675
  if (this.expiryEl) {
648
676
  this.expiryEl.value = '';
649
677
  }
678
+ if (this.numberHasError && this.numberBaseCss) {
679
+ this.spreedly.setStyle('number', this.numberBaseCss);
680
+ this.numberHasError = false;
681
+ }
682
+ if (this.cvvHasError && this.cvvBaseCss) {
683
+ this.spreedly.setStyle('cvv', this.cvvBaseCss);
684
+ this.cvvHasError = false;
685
+ }
686
+ this.currentValidationState = {
687
+ isValid: false,
688
+ cardNumber: { isValid: false, isEmpty: true },
689
+ cvv: { isValid: false, isEmpty: true },
690
+ expiry: { isValid: false, isEmpty: true },
691
+ };
692
+ }
693
+ if (this.tokenizationReject) {
694
+ const reject = this.tokenizationReject;
695
+ this.clearTokenizationState();
696
+ reject(new types_1.TokenizationError('Tokenizer cleared', 'CLEARED'));
650
697
  }
698
+ else {
699
+ this.clearTokenizationState();
700
+ }
701
+ this.emit('validation', this.currentValidationState);
651
702
  }
652
703
  focus(field) {
653
704
  if (this.mode === 'bank_account') {
@@ -683,12 +734,84 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
683
734
  element === null || element === void 0 ? void 0 : element.focus();
684
735
  }
685
736
  }
737
+ determineLayout(width) {
738
+ return width < this.responsiveBreakpoint ? 'two-line' : 'single-line';
739
+ }
740
+ setupResizeObserver() {
741
+ if (this.layout !== 'responsive')
742
+ return;
743
+ const container = document.getElementById(this.containerId);
744
+ if (!container)
745
+ return;
746
+ let debounceTimer;
747
+ this.resizeObserver = new ResizeObserver((entries) => {
748
+ clearTimeout(debounceTimer);
749
+ debounceTimer = setTimeout(() => {
750
+ const newWidth = entries[0].contentRect.width;
751
+ const newLayout = this.determineLayout(newWidth);
752
+ if (newLayout !== this.effectiveLayout) {
753
+ this.applyLayoutStyles(newLayout);
754
+ }
755
+ }, 100);
756
+ });
757
+ this.resizeObserver.observe(container);
758
+ }
759
+ applyLayoutStyles(newLayout) {
760
+ this.effectiveLayout = newLayout;
761
+ const container = document.getElementById(this.containerId);
762
+ if (!container)
763
+ return;
764
+ if (newLayout === 'two-line') {
765
+ container.style.flexWrap = 'wrap';
766
+ if (this.cardNumberDiv) {
767
+ this.cardNumberDiv.style.flex = '1';
768
+ this.cardNumberDiv.style.flexBasis = '100%';
769
+ }
770
+ if (this.expiryEl) {
771
+ this.expiryEl.style.flex = '1';
772
+ this.expiryEl.style.flexBasis = 'auto';
773
+ }
774
+ if (this.cvvDiv) {
775
+ this.cvvDiv.style.flex = '1';
776
+ this.cvvDiv.style.flexBasis = 'auto';
777
+ }
778
+ }
779
+ else {
780
+ container.style.flexWrap = 'nowrap';
781
+ if (this.cardNumberDiv) {
782
+ this.cardNumberDiv.style.flex = tokenizer_constants_1.FIELD_FLEX.cardNumber.flex;
783
+ }
784
+ if (this.expiryEl) {
785
+ this.expiryEl.style.flex = tokenizer_constants_1.FIELD_FLEX.expiry.flex;
786
+ }
787
+ if (this.cvvDiv) {
788
+ this.cvvDiv.style.flex = tokenizer_constants_1.FIELD_FLEX.cvv.flex;
789
+ }
790
+ }
791
+ }
792
+ clearTokenizationState() {
793
+ if (this.tokenizationTimeout) {
794
+ clearTimeout(this.tokenizationTimeout);
795
+ this.tokenizationTimeout = undefined;
796
+ }
797
+ this.tokenizationResolve = undefined;
798
+ this.tokenizationReject = undefined;
799
+ }
686
800
  destroy() {
801
+ var _a;
802
+ this.markDestroyed();
803
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
804
+ if (this.tokenizationReject) {
805
+ const reject = this.tokenizationReject;
806
+ this.clearTokenizationState();
807
+ reject(new types_1.TokenizationError('Tokenizer destroyed', 'DESTROYED'));
808
+ }
687
809
  if (this.spreedly && this.spreedly.removeHandlers) {
688
810
  this.spreedly.removeHandlers();
689
811
  }
690
812
  this.eventHandlers.clear();
691
- if (this.expiryEl) {
813
+ if (this.containerEl) {
814
+ this.containerEl.innerHTML = '';
692
815
  }
693
816
  }
694
817
  hasToken() {
@@ -716,10 +839,9 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
716
839
  handleFieldEvent(fieldName, eventType, inputProperties) {
717
840
  if (eventType === 'input') {
718
841
  if (fieldName === 'number') {
719
- this.currentValidationState.cardNumber = {
720
- isValid: inputProperties.validNumber || false,
721
- isEmpty: inputProperties.numberLength === 0,
722
- };
842
+ const isEmpty = inputProperties.numberLength === 0;
843
+ const isValid = inputProperties.validNumber || false;
844
+ this.currentValidationState.cardNumber = { isValid, isEmpty };
723
845
  if (inputProperties.cardType &&
724
846
  inputProperties.cardType !== 'unknown') {
725
847
  this.emit('cardTypeChange', {
@@ -728,21 +850,37 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
728
850
  }
729
851
  }
730
852
  else if (fieldName === 'cvv') {
731
- this.currentValidationState.cvv = {
732
- isValid: inputProperties.validCvv || false,
733
- isEmpty: inputProperties.cvvLength === 0,
734
- };
853
+ const isEmpty = inputProperties.cvvLength === 0;
854
+ const isValid = inputProperties.validCvv || false;
855
+ this.currentValidationState.cvv = { isValid, isEmpty };
735
856
  }
736
857
  this.updateOverallValidation();
737
858
  }
738
- if (eventType === 'focus') {
739
- this.emit('focus', { field: fieldName });
740
- }
741
- else if (eventType === 'blur') {
742
- this.emit('blur', { field: fieldName });
743
- }
744
- else if (eventType === 'input') {
745
- this.emit('change', { field: fieldName });
859
+ if (eventType === 'blur') {
860
+ if (fieldName === 'number') {
861
+ const state = this.currentValidationState.cardNumber;
862
+ const shouldShowError = state
863
+ ? !state.isEmpty && !state.isValid
864
+ : false;
865
+ if (shouldShowError !== this.numberHasError) {
866
+ this.numberHasError = shouldShowError;
867
+ if (this.numberErrorCss) {
868
+ this.spreedly.setStyle('number', shouldShowError ? this.numberErrorCss : this.numberBaseCss);
869
+ }
870
+ }
871
+ }
872
+ else if (fieldName === 'cvv') {
873
+ const state = this.currentValidationState.cvv;
874
+ const shouldShowError = state
875
+ ? !state.isEmpty && !state.isValid
876
+ : false;
877
+ if (shouldShowError !== this.cvvHasError) {
878
+ this.cvvHasError = shouldShowError;
879
+ if (this.cvvErrorCss) {
880
+ this.spreedly.setStyle('cvv', shouldShowError ? this.cvvErrorCss : this.cvvBaseCss);
881
+ }
882
+ }
883
+ }
746
884
  }
747
885
  }
748
886
  createInternalElements() {
@@ -759,13 +897,25 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
759
897
  this.createCreditCardFields(container);
760
898
  }
761
899
  }
900
+ appendField(container, field, labelText) {
901
+ container.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(field, labelText, this.mergedStyles));
902
+ }
762
903
  createCreditCardFields(container) {
763
- if (this.layout === 'two-line') {
904
+ var _a, _b;
905
+ if (this.layout === 'responsive') {
906
+ this.effectiveLayout = this.determineLayout(container.offsetWidth);
907
+ }
908
+ else {
909
+ this.effectiveLayout =
910
+ this.layout === 'two-line' ? 'two-line' : 'single-line';
911
+ }
912
+ if (this.effectiveLayout === 'two-line' && this.layout !== 'responsive') {
764
913
  const cardNumberDiv = (0, tokenizer_utils_1.createFieldContainer)(this.numberEl, '1', tokenizer_constants_1.FIELD_FLEX.cardNumber.minWidth);
765
914
  cardNumberDiv.style.height = this.mergedStyles.input.height;
766
915
  cardNumberDiv.style.flexBasis = '100%';
767
- container.appendChild(cardNumberDiv);
768
- this.expiryEl = (0, tokenizer_utils_1.createInputElement)(this.expiryId, 'text', tokenizer_constants_1.PLACEHOLDERS.expiry, tokenizer_constants_1.FIELD_CONSTRAINTS.expiry.maxLength);
916
+ this.cardNumberDiv = cardNumberDiv;
917
+ this.appendField(container, cardNumberDiv, 'Card Number');
918
+ this.expiryEl = (0, tokenizer_utils_1.createInputElement)(this.expiryId, 'text', ((_a = this.customPlaceholders) === null || _a === void 0 ? void 0 : _a.expiry) || tokenizer_constants_1.PLACEHOLDERS.expiry, tokenizer_constants_1.FIELD_CONSTRAINTS.expiry.maxLength);
769
919
  Object.assign(this.expiryEl.style, {
770
920
  flex: '1',
771
921
  minWidth: tokenizer_constants_1.FIELD_FLEX.expiry.minWidth,
@@ -781,16 +931,22 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
781
931
  };
782
932
  this.updateOverallValidation();
783
933
  });
784
- container.appendChild(this.expiryEl);
934
+ this.expiryEl.addEventListener('blur', () => {
935
+ this.validateExpiry();
936
+ this.updateOverallValidation();
937
+ });
938
+ this.appendField(container, this.expiryEl, 'Expiration');
785
939
  const cvvDiv = (0, tokenizer_utils_1.createFieldContainer)(this.cvvEl, '1', tokenizer_constants_1.FIELD_FLEX.cvv.minWidth);
786
940
  cvvDiv.style.height = this.mergedStyles.input.height;
787
- container.appendChild(cvvDiv);
941
+ this.cvvDiv = cvvDiv;
942
+ this.appendField(container, cvvDiv, 'CVV');
788
943
  }
789
944
  else {
790
945
  const cardNumberDiv = (0, tokenizer_utils_1.createFieldContainer)(this.numberEl, tokenizer_constants_1.FIELD_FLEX.cardNumber.flex, tokenizer_constants_1.FIELD_FLEX.cardNumber.minWidth);
791
946
  cardNumberDiv.style.height = this.mergedStyles.input.height;
792
- container.appendChild(cardNumberDiv);
793
- this.expiryEl = (0, tokenizer_utils_1.createInputElement)(this.expiryId, 'text', tokenizer_constants_1.PLACEHOLDERS.expiry, tokenizer_constants_1.FIELD_CONSTRAINTS.expiry.maxLength);
947
+ this.cardNumberDiv = cardNumberDiv;
948
+ this.appendField(container, cardNumberDiv, 'Card Number');
949
+ this.expiryEl = (0, tokenizer_utils_1.createInputElement)(this.expiryId, 'text', ((_b = this.customPlaceholders) === null || _b === void 0 ? void 0 : _b.expiry) || tokenizer_constants_1.PLACEHOLDERS.expiry, tokenizer_constants_1.FIELD_CONSTRAINTS.expiry.maxLength);
794
950
  Object.assign(this.expiryEl.style, {
795
951
  flex: tokenizer_constants_1.FIELD_FLEX.expiry.flex,
796
952
  minWidth: tokenizer_constants_1.FIELD_FLEX.expiry.minWidth,
@@ -806,10 +962,19 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
806
962
  };
807
963
  this.updateOverallValidation();
808
964
  });
809
- container.appendChild(this.expiryEl);
965
+ this.expiryEl.addEventListener('blur', () => {
966
+ this.validateExpiry();
967
+ this.updateOverallValidation();
968
+ });
969
+ this.appendField(container, this.expiryEl, 'Expiration');
810
970
  const cvvDiv = (0, tokenizer_utils_1.createFieldContainer)(this.cvvEl, tokenizer_constants_1.FIELD_FLEX.cvv.flex, tokenizer_constants_1.FIELD_FLEX.cvv.minWidth);
811
971
  cvvDiv.style.height = this.mergedStyles.input.height;
812
- container.appendChild(cvvDiv);
972
+ this.cvvDiv = cvvDiv;
973
+ this.appendField(container, cvvDiv, 'CVV');
974
+ if (this.layout === 'responsive') {
975
+ this.applyLayoutStyles(this.effectiveLayout);
976
+ this.setupResizeObserver();
977
+ }
813
978
  }
814
979
  }
815
980
  createBankAccountFields(container) {
@@ -821,6 +986,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
821
986
  }
822
987
  }
823
988
  createUSBankAccountFields(container) {
989
+ var _a, _b, _c, _d;
824
990
  if (this.layout === 'two-line') {
825
991
  this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
826
992
  Object.assign(this.accountTypeEl.style, {
@@ -828,8 +994,8 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
828
994
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
829
995
  });
830
996
  this.applyInputStyles(this.accountTypeEl, this.mergedStyles, 'left');
831
- container.appendChild(this.accountTypeEl);
832
- this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
997
+ this.appendField(container, this.accountTypeEl, 'Account Type');
998
+ this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', ((_a = this.customPlaceholders) === null || _a === void 0 ? void 0 : _a.routingNumber) || 'Routing *', 9);
833
999
  Object.assign(this.routingNumberEl.style, {
834
1000
  flex: '1',
835
1001
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
@@ -845,8 +1011,8 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
845
1011
  }
846
1012
  this.updateBankAccountValidation();
847
1013
  });
848
- container.appendChild(this.routingNumberEl);
849
- this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
1014
+ this.appendField(container, this.routingNumberEl, 'Routing Number');
1015
+ this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', ((_b = this.customPlaceholders) === null || _b === void 0 ? void 0 : _b.accountNumber) || 'Account Number *', 17);
850
1016
  Object.assign(this.accountNumberEl.style, {
851
1017
  flex: '1',
852
1018
  flexBasis: '100%',
@@ -863,10 +1029,10 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
863
1029
  }
864
1030
  this.updateBankAccountValidation();
865
1031
  });
866
- container.appendChild(this.accountNumberEl);
1032
+ this.appendField(container, this.accountNumberEl, 'Account Number');
867
1033
  }
868
1034
  else {
869
- this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
1035
+ this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', ((_c = this.customPlaceholders) === null || _c === void 0 ? void 0 : _c.routingNumber) || 'Routing *', 9);
870
1036
  Object.assign(this.routingNumberEl.style, {
871
1037
  flex: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.flex,
872
1038
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
@@ -882,8 +1048,8 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
882
1048
  }
883
1049
  this.updateBankAccountValidation();
884
1050
  });
885
- container.appendChild(this.routingNumberEl);
886
- this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
1051
+ this.appendField(container, this.routingNumberEl, 'Routing Number');
1052
+ this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', ((_d = this.customPlaceholders) === null || _d === void 0 ? void 0 : _d.accountNumber) || 'Account Number *', 17);
887
1053
  Object.assign(this.accountNumberEl.style, {
888
1054
  flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.flex,
889
1055
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
@@ -899,14 +1065,14 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
899
1065
  }
900
1066
  this.updateBankAccountValidation();
901
1067
  });
902
- container.appendChild(this.accountNumberEl);
1068
+ this.appendField(container, this.accountNumberEl, 'Account Number');
903
1069
  this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
904
1070
  Object.assign(this.accountTypeEl.style, {
905
1071
  flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.flex,
906
1072
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
907
1073
  });
908
1074
  this.applyInputStyles(this.accountTypeEl, this.mergedStyles, 'right');
909
- container.appendChild(this.accountTypeEl);
1075
+ this.appendField(container, this.accountTypeEl, 'Account Type');
910
1076
  }
911
1077
  }
912
1078
  updateBankAccountValidation() {
@@ -963,30 +1129,42 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
963
1129
  if (!this.expiryEl)
964
1130
  return;
965
1131
  const expiry = this.parseExpiry(this.expiryEl);
1132
+ const isEmpty = !this.expiryEl.value;
1133
+ let isValid = false;
966
1134
  if (!expiry) {
967
- this.applyErrorStyles(this.expiryEl);
968
- return;
969
- }
970
- const month = parseInt(expiry.month, 10);
971
- const year = parseInt(expiry.year, 10);
972
- if (month < 1 || month > 12) {
973
- this.applyErrorStyles(this.expiryEl);
974
- return;
1135
+ if (!isEmpty)
1136
+ this.applyErrorStyles(this.expiryEl);
975
1137
  }
976
- const now = new Date();
977
- const expiryDate = new Date(year, month - 1);
978
- if (expiryDate < now) {
979
- this.applyErrorStyles(this.expiryEl);
980
- return;
1138
+ else {
1139
+ const month = parseInt(expiry.month, 10);
1140
+ const year = parseInt(expiry.year, 10);
1141
+ if (month < 1 || month > 12) {
1142
+ this.applyErrorStyles(this.expiryEl);
1143
+ }
1144
+ else {
1145
+ const now = new Date();
1146
+ const expiryEndDate = new Date(year, month);
1147
+ if (expiryEndDate <= now) {
1148
+ this.applyErrorStyles(this.expiryEl);
1149
+ }
1150
+ else {
1151
+ isValid = true;
1152
+ const expiryPosition = this.effectiveLayout === 'two-line' ? 'left' : 'middle';
1153
+ this.applyInputStyles(this.expiryEl, this.mergedStyles, expiryPosition);
1154
+ }
1155
+ }
981
1156
  }
982
- this.applyInputStyles(this.expiryEl, this.mergedStyles, 'middle');
1157
+ this.currentValidationState.expiry = { isValid, isEmpty };
983
1158
  }
984
1159
  applyErrorStyles(element) {
985
- if (this.mergedStyles.error) {
986
- Object.assign(element.style, this.mergedStyles.error);
1160
+ var _a, _b, _c;
1161
+ const errorColor = ((_a = this.mergedStyles.error) === null || _a === void 0 ? void 0 : _a.borderColor) || '#dc3545';
1162
+ element.style.border = `1px solid ${errorColor}`;
1163
+ if ((_b = this.mergedStyles.error) === null || _b === void 0 ? void 0 : _b.backgroundColor) {
1164
+ element.style.backgroundColor = this.mergedStyles.error.backgroundColor;
987
1165
  }
988
- else {
989
- element.style.borderColor = '#dc3545';
1166
+ if ((_c = this.mergedStyles.error) === null || _c === void 0 ? void 0 : _c.color) {
1167
+ element.style.color = this.mergedStyles.error.color;
990
1168
  }
991
1169
  }
992
1170
  static ensureSpreedlyLoaded() {
@@ -1033,13 +1211,14 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
1033
1211
  throw new Error(`Timeout waiting for global: ${globalName}`);
1034
1212
  });
1035
1213
  }
1036
- static tokenizeBankAccount(data, config) {
1037
- if (config.spreedlyEnvironmentKey === undefined) {
1214
+ static tokenizeBankAccount(data, config, environmentKeyOverride) {
1215
+ const environmentKey = environmentKeyOverride || config.spreedlyEnvironmentKey;
1216
+ if (!environmentKey) {
1038
1217
  return Promise.reject(new Error('Spreedly is not configured.'));
1039
1218
  }
1040
1219
  return fetch(constants_1.SPREEDLY_TOKENIZER_URL +
1041
1220
  '?' +
1042
- new URLSearchParams({ environment_key: config.spreedlyEnvironmentKey }), {
1221
+ new URLSearchParams({ environment_key: environmentKey }), {
1043
1222
  method: 'POST',
1044
1223
  headers: {
1045
1224
  'Content-Type': 'application/json',