@idonatedev/idonate-sdk 1.2.0-dev14 → 1.2.0-dev16

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 (34) hide show
  1. package/dist/constants.js +1 -1
  2. package/dist/esm/constants.js +1 -1
  3. package/dist/esm/tokenize/CardConnectTokenizer.d.ts +6 -1
  4. package/dist/esm/tokenize/CardConnectTokenizer.js +184 -53
  5. package/dist/esm/tokenize/PayPalTokenizer.d.ts +1 -0
  6. package/dist/esm/tokenize/PayPalTokenizer.js +52 -16
  7. package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +6 -0
  8. package/dist/esm/tokenize/SpreedlyTokenizer.js +113 -63
  9. package/dist/esm/tokenize/Tokenizer.d.ts +6 -2
  10. package/dist/esm/tokenize/Tokenizer.js +13 -3
  11. package/dist/esm/tokenize/gateway-utils.js +3 -2
  12. package/dist/esm/tokenize/index.d.ts +1 -1
  13. package/dist/esm/tokenize/spreedly-secure.js +6 -2
  14. package/dist/esm/tokenize/tokenizer-utils.d.ts +1 -1
  15. package/dist/esm/tokenize/tokenizer-utils.js +25 -4
  16. package/dist/esm/tokenize/types.d.ts +3 -2
  17. package/dist/esm/typeAdapters.js +6 -4
  18. package/dist/tokenize/CardConnectTokenizer.d.ts +6 -1
  19. package/dist/tokenize/CardConnectTokenizer.js +184 -56
  20. package/dist/tokenize/PayPalTokenizer.d.ts +1 -0
  21. package/dist/tokenize/PayPalTokenizer.js +52 -16
  22. package/dist/tokenize/SpreedlyTokenizer.d.ts +6 -0
  23. package/dist/tokenize/SpreedlyTokenizer.js +113 -63
  24. package/dist/tokenize/Tokenizer.d.ts +6 -2
  25. package/dist/tokenize/Tokenizer.js +13 -3
  26. package/dist/tokenize/gateway-utils.js +3 -2
  27. package/dist/tokenize/index.d.ts +1 -1
  28. package/dist/tokenize/spreedly-secure.js +6 -2
  29. package/dist/tokenize/tokenizer-utils.d.ts +1 -1
  30. package/dist/tokenize/tokenizer-utils.js +25 -4
  31. package/dist/tokenize/types.d.ts +3 -2
  32. package/dist/typeAdapters.js +6 -4
  33. package/package.json +1 -1
  34. package/umd/idonate-sdk.js +1 -1
package/dist/constants.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CLIENT_HEADERS = exports.CARD_CONNECT_DEFAULT_STYLE = exports.DEFAULT_APP_NAME = exports.DEFAULT_CF_TURNSTILE_CDN_EXPLICIT_URL = exports.FALLBACK_CF_TURNSTILE_SITE_KEY = exports.FALLBACK_PC_SCRIPT_ID = exports.FALLBACK_PC_SCRIPT_URL = exports.SANDBOX_APPLE_PAY_URL = exports.APPLE_PAY_URL = exports.SPREEDLY_TOKENIZER_URL = exports.SANDBOX_CARD_CONNECT_BASE_URL = exports.PRODUCTION_CARD_CONNECT_BASE_URL = exports.SANDBOX_BASE_URL = exports.PRODUCTION_BASE_URL = exports.SDK_VERSION = void 0;
4
- exports.SDK_VERSION = '1.2.0-dev14';
4
+ exports.SDK_VERSION = '1.2.0-dev16';
5
5
  exports.PRODUCTION_BASE_URL = 'https://secure-api.idonate.com';
6
6
  exports.SANDBOX_BASE_URL = 'https://api.qa-idonate.com';
7
7
  exports.PRODUCTION_CARD_CONNECT_BASE_URL = 'https://boltgw.cardconnect.com:8443';
@@ -1,4 +1,4 @@
1
- export const SDK_VERSION = '1.2.0-dev14';
1
+ export const SDK_VERSION = '1.2.0-dev16';
2
2
  export const PRODUCTION_BASE_URL = 'https://secure-api.idonate.com';
3
3
  export const SANDBOX_BASE_URL = 'https://api.qa-idonate.com';
4
4
  export const PRODUCTION_CARD_CONNECT_BASE_URL = 'https://boltgw.cardconnect.com:8443';
@@ -16,10 +16,13 @@ export declare class CardConnectTokenizer extends Tokenizer {
16
16
  private accountTypeEl?;
17
17
  private enableTestMode;
18
18
  private cachedTokenResult?;
19
+ private acceptAutoToken;
19
20
  private tokenizationPromise?;
20
21
  private tokenizationResolve?;
21
22
  private tokenizationReject?;
22
23
  private currentCardType?;
24
+ private tokenizationTimeout?;
25
+ private mergedStyles?;
23
26
  private constructor();
24
27
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
25
28
  organizationId: string;
@@ -29,6 +32,8 @@ export declare class CardConnectTokenizer extends Tokenizer {
29
32
  private createInternalElements;
30
33
  private createCreditCardFields;
31
34
  private createBankAccountFields;
35
+ private addBankAccountValidationListeners;
36
+ private updateBankAccountValidation;
32
37
  private init;
33
38
  tokenize(paymentData: PaymentData): Promise<PaymentToken>;
34
39
  private tokenizeCardInternal;
@@ -47,5 +52,5 @@ export declare class CardConnectTokenizer extends Tokenizer {
47
52
  private static generateIframeUrl;
48
53
  private static createIframe;
49
54
  private static generateCardConnectCss;
50
- static tokenizeBankAccount(routingNumber: string, accountNumber: string, config: ConfigHandler): Promise<TokenizeCardConnectBankAccountResult>;
55
+ static tokenizeBankAccount(routingNumber: string, accountNumber: string, configOrBaseUrl: ConfigHandler | string): Promise<TokenizeCardConnectBankAccountResult>;
51
56
  }
@@ -9,7 +9,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Tokenizer } from './Tokenizer';
11
11
  import { TokenizationError, } from './types';
12
- import ConfigHandler from '../config-handler';
13
12
  import { DEFAULT_UNIFIED_STYLES, mergeStyles, getContainerStylesForLayout, } from './styles';
14
13
  import { INIT_TIMEOUT, TOKENIZE_TIMEOUT, BANK_FIELD_FLEX, RESPONSIVE_BREAKPOINT, } from './tokenizer-constants';
15
14
  import { createInputElement, validateRoutingNumber, validateAccountNumber, createAccountTypeSelect, } from './tokenizer-utils';
@@ -20,6 +19,7 @@ export class CardConnectTokenizer extends Tokenizer {
20
19
  this.containerId = containerId;
21
20
  this.layout = layout;
22
21
  this.enableTestMode = false;
22
+ this.acceptAutoToken = true;
23
23
  this.mode = mode;
24
24
  this.enableTestMode = enableTestMode;
25
25
  this.iframe = iframe;
@@ -34,7 +34,7 @@ export class CardConnectTokenizer extends Tokenizer {
34
34
  }
35
35
  static create(gateway, container, config) {
36
36
  return __awaiter(this, void 0, void 0, function* () {
37
- var _a;
37
+ var _a, _b;
38
38
  if (container.mode === 'bank_account' && container.bankCountry === 'CA') {
39
39
  throw new Error('CardConnect does not support Canadian bank accounts');
40
40
  }
@@ -42,7 +42,7 @@ export class CardConnectTokenizer extends Tokenizer {
42
42
  if (container.layout === 'responsive') {
43
43
  const containerEl = document.getElementById(container.containerId);
44
44
  const containerWidth = (containerEl === null || containerEl === void 0 ? void 0 : containerEl.offsetWidth) || 0;
45
- const breakpoint = container.responsiveBreakpoint || RESPONSIVE_BREAKPOINT;
45
+ const breakpoint = (_a = container.responsiveBreakpoint) !== null && _a !== void 0 ? _a : RESPONSIVE_BREAKPOINT;
46
46
  effectiveLayout =
47
47
  containerWidth < breakpoint ? 'two-line' : 'single-line';
48
48
  }
@@ -50,8 +50,7 @@ export class CardConnectTokenizer extends Tokenizer {
50
50
  effectiveLayout = 'two-line';
51
51
  }
52
52
  const resolvedContainer = Object.assign(Object.assign({}, container), { layout: effectiveLayout });
53
- let baseUrl = ((_a = gateway.config) === null || _a === void 0 ? void 0 : _a.baseUrl) || config.clientConfig.cardConnectBaseUrl;
54
- config.cardConnectBaseUrl = baseUrl;
53
+ const baseUrl = ((_b = gateway.config) === null || _b === void 0 ? void 0 : _b.baseUrl) || config.clientConfig.cardConnectBaseUrl;
55
54
  const mergedStyles = mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling);
56
55
  const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, resolvedContainer);
57
56
  const iframe = CardConnectTokenizer.createIframe(iframeUrl, mergedStyles);
@@ -139,6 +138,66 @@ export class CardConnectTokenizer extends Tokenizer {
139
138
  this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
140
139
  containerEl.appendChild(this.accountTypeEl);
141
140
  }
141
+ this.mergedStyles = mergedStyles;
142
+ this.currentValidationState = {
143
+ isValid: false,
144
+ routingNumber: { isValid: false, isEmpty: true },
145
+ accountNumber: { isValid: false, isEmpty: true },
146
+ };
147
+ this.addBankAccountValidationListeners(mergedStyles);
148
+ }
149
+ addBankAccountValidationListeners(styles) {
150
+ if (this.routingNumberEl) {
151
+ this.routingNumberEl.addEventListener('blur', () => {
152
+ this.updateBankAccountValidation(styles);
153
+ });
154
+ this.routingNumberEl.addEventListener('input', () => {
155
+ this.updateBankAccountValidation(styles);
156
+ });
157
+ }
158
+ if (this.accountNumberEl) {
159
+ this.accountNumberEl.addEventListener('blur', () => {
160
+ this.updateBankAccountValidation(styles);
161
+ });
162
+ this.accountNumberEl.addEventListener('input', () => {
163
+ this.updateBankAccountValidation(styles);
164
+ });
165
+ }
166
+ }
167
+ updateBankAccountValidation(styles) {
168
+ var _a, _b;
169
+ const routingValue = ((_a = this.routingNumberEl) === null || _a === void 0 ? void 0 : _a.value) || '';
170
+ const accountValue = ((_b = this.accountNumberEl) === null || _b === void 0 ? void 0 : _b.value) || '';
171
+ const routingValid = routingValue.length > 0 && validateRoutingNumber(routingValue);
172
+ const accountValid = accountValue.length > 0 && validateAccountNumber(accountValue);
173
+ if (this.routingNumberEl) {
174
+ if (routingValue.length > 0 && !routingValid) {
175
+ this.routingNumberEl.style.borderColor = styles.error.borderColor;
176
+ }
177
+ else {
178
+ this.routingNumberEl.style.borderColor = '';
179
+ }
180
+ }
181
+ if (this.accountNumberEl) {
182
+ if (accountValue.length > 0 && !accountValid) {
183
+ this.accountNumberEl.style.borderColor = styles.error.borderColor;
184
+ }
185
+ else {
186
+ this.accountNumberEl.style.borderColor = '';
187
+ }
188
+ }
189
+ this.currentValidationState = {
190
+ isValid: routingValid && accountValid,
191
+ routingNumber: {
192
+ isValid: routingValid,
193
+ isEmpty: routingValue.length === 0,
194
+ },
195
+ accountNumber: {
196
+ isValid: accountValid,
197
+ isEmpty: accountValue.length === 0,
198
+ },
199
+ };
200
+ this.emit('validation', this.currentValidationState);
142
201
  }
143
202
  init() {
144
203
  return __awaiter(this, void 0, void 0, function* () {
@@ -208,31 +267,39 @@ export class CardConnectTokenizer extends Tokenizer {
208
267
  }
209
268
  tokenizeCardInternal(cardData) {
210
269
  return __awaiter(this, void 0, void 0, function* () {
270
+ var _a, _b, _c;
211
271
  if (this.cachedTokenResult && this.cachedTokenResult.errorCode === '0') {
272
+ const cardType = this.cachedTokenResult.cardType
273
+ ? this.normalizeCardType(this.cachedTokenResult.cardType)
274
+ : this.normalizeCardType('unknown');
212
275
  return {
213
276
  token: this.cachedTokenResult.token,
214
- lastFour: this.cachedTokenResult.token.slice(-4),
215
- cardType: this.normalizeCardType('unknown'),
277
+ lastFour: this.cachedTokenResult.last4 ||
278
+ this.cachedTokenResult.token.slice(-4),
279
+ cardType,
280
+ paymentMethodType: 'credit_card',
216
281
  provider: 'cardconnect',
217
282
  };
218
283
  }
219
284
  if (this.tokenizationPromise) {
220
285
  return this.tokenizationPromise;
221
286
  }
287
+ if (!this.currentValidationState.isValid &&
288
+ (((_a = this.currentValidationState.cardNumber) === null || _a === void 0 ? void 0 : _a.isEmpty) ||
289
+ ((_b = this.currentValidationState.cvv) === null || _b === void 0 ? void 0 : _b.isEmpty) ||
290
+ ((_c = this.currentValidationState.expiry) === null || _c === void 0 ? void 0 : _c.isEmpty))) {
291
+ throw new TokenizationError('Card fields are incomplete', 'VALIDATION_ERROR');
292
+ }
222
293
  this.tokenizationPromise = new Promise((resolve, reject) => {
223
294
  this.tokenizationResolve = resolve;
224
295
  this.tokenizationReject = reject;
225
- const timeout = setTimeout(() => {
296
+ this.tokenizationTimeout = setTimeout(() => {
297
+ this.tokenizationTimeout = undefined;
226
298
  this.tokenizationPromise = undefined;
227
299
  this.tokenizationResolve = undefined;
228
300
  this.tokenizationReject = undefined;
229
301
  reject(new TokenizationError('Tokenization timeout - ensure all card fields are filled in iframe', 'TIMEOUT'));
230
302
  }, TOKENIZE_TIMEOUT);
231
- const tokenizationHandler = (data) => {
232
- clearTimeout(timeout);
233
- this.off('tokenization', tokenizationHandler);
234
- };
235
- this.on('tokenization', tokenizationHandler);
236
303
  });
237
304
  return this.tokenizationPromise;
238
305
  });
@@ -254,16 +321,16 @@ export class CardConnectTokenizer extends Tokenizer {
254
321
  throw new TokenizationError('Invalid account number', 'VALIDATION_ERROR');
255
322
  }
256
323
  const baseUrl = new URL(this.iframeUrl).origin;
257
- const config = new ConfigHandler({});
258
- config.cardConnectBaseUrl = baseUrl;
259
- const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, config);
260
- return {
324
+ const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, baseUrl);
325
+ const paymentToken = {
261
326
  token: result.token,
262
327
  lastFour: accountNumber.slice(-4),
263
328
  accountType: accountType,
264
329
  paymentMethodType: 'bank_account',
265
330
  provider: 'cardconnect',
266
331
  };
332
+ this.emit('tokenReady', paymentToken);
333
+ return paymentToken;
267
334
  });
268
335
  }
269
336
  validate() {
@@ -400,12 +467,39 @@ export class CardConnectTokenizer extends Tokenizer {
400
467
  action: 'clear',
401
468
  }, this.expectedOrigin);
402
469
  }
403
- this.currentValidationState = {
404
- isValid: false,
405
- cardNumber: { isValid: false, isEmpty: true },
406
- cvv: { isValid: false, isEmpty: true },
407
- expiry: { isValid: false, isEmpty: true },
408
- };
470
+ this.cachedTokenResult = undefined;
471
+ this.acceptAutoToken = false;
472
+ if (this.tokenizationTimeout) {
473
+ clearTimeout(this.tokenizationTimeout);
474
+ this.tokenizationTimeout = undefined;
475
+ }
476
+ if (this.tokenizationReject) {
477
+ const reject = this.tokenizationReject;
478
+ this.tokenizationPromise = undefined;
479
+ this.tokenizationResolve = undefined;
480
+ this.tokenizationReject = undefined;
481
+ reject(new TokenizationError('Tokenizer cleared', 'CLEARED'));
482
+ }
483
+ else {
484
+ this.tokenizationPromise = undefined;
485
+ this.tokenizationResolve = undefined;
486
+ this.tokenizationReject = undefined;
487
+ }
488
+ if (this.mode === 'bank_account') {
489
+ this.currentValidationState = {
490
+ isValid: false,
491
+ routingNumber: { isValid: false, isEmpty: true },
492
+ accountNumber: { isValid: false, isEmpty: true },
493
+ };
494
+ }
495
+ else {
496
+ this.currentValidationState = {
497
+ isValid: false,
498
+ cardNumber: { isValid: false, isEmpty: true },
499
+ cvv: { isValid: false, isEmpty: true },
500
+ expiry: { isValid: false, isEmpty: true },
501
+ };
502
+ }
409
503
  this.emit('validation', this.currentValidationState);
410
504
  }
411
505
  focus(field) {
@@ -434,8 +528,22 @@ export class CardConnectTokenizer extends Tokenizer {
434
528
  }
435
529
  }
436
530
  destroy() {
531
+ this.markDestroyed();
532
+ if (this.tokenizationTimeout) {
533
+ clearTimeout(this.tokenizationTimeout);
534
+ this.tokenizationTimeout = undefined;
535
+ }
536
+ if (this.tokenizationReject) {
537
+ const reject = this.tokenizationReject;
538
+ this.tokenizationPromise = undefined;
539
+ this.tokenizationResolve = undefined;
540
+ this.tokenizationReject = undefined;
541
+ reject(new TokenizationError('Tokenizer destroyed', 'DESTROYED'));
542
+ }
543
+ this.cachedTokenResult = undefined;
437
544
  if (this.messageHandler) {
438
545
  window.removeEventListener('message', this.messageHandler);
546
+ this.messageHandler = undefined;
439
547
  }
440
548
  if (this.containerEl) {
441
549
  this.containerEl.innerHTML = '';
@@ -462,6 +570,7 @@ export class CardConnectTokenizer extends Tokenizer {
462
570
  lastFour: this.cachedTokenResult.last4 ||
463
571
  this.cachedTokenResult.token.slice(-4),
464
572
  cardType,
573
+ paymentMethodType: 'credit_card',
465
574
  provider: 'cardconnect',
466
575
  };
467
576
  }
@@ -474,8 +583,14 @@ export class CardConnectTokenizer extends Tokenizer {
474
583
  try {
475
584
  const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
476
585
  if (data.token && data.errorCode !== undefined) {
586
+ if (!this.acceptAutoToken && !this.tokenizationResolve) {
587
+ return;
588
+ }
477
589
  this.cachedTokenResult = data;
478
- this.emit('tokenization', data);
590
+ if (this.tokenizationTimeout) {
591
+ clearTimeout(this.tokenizationTimeout);
592
+ this.tokenizationTimeout = undefined;
593
+ }
479
594
  if (data.errorCode === '0') {
480
595
  const cardType = data.cardType
481
596
  ? this.normalizeCardType(data.cardType)
@@ -488,6 +603,7 @@ export class CardConnectTokenizer extends Tokenizer {
488
603
  token: data.token,
489
604
  lastFour: data.last4 || data.token.slice(-4),
490
605
  cardType,
606
+ paymentMethodType: 'credit_card',
491
607
  provider: 'cardconnect',
492
608
  };
493
609
  if (this.tokenizationResolve) {
@@ -502,12 +618,14 @@ export class CardConnectTokenizer extends Tokenizer {
502
618
  cvv: { isValid: true, isEmpty: false },
503
619
  expiry: { isValid: true, isEmpty: false },
504
620
  };
505
- this.emit('validation', { isValid: true });
621
+ this.emit('validation', this.currentValidationState);
506
622
  this.emit('tokenReady', token);
507
623
  }
508
624
  else {
625
+ const error = new TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN');
626
+ this.emit('error', error);
509
627
  if (this.tokenizationReject) {
510
- this.tokenizationReject(new TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
628
+ this.tokenizationReject(error);
511
629
  this.tokenizationPromise = undefined;
512
630
  this.tokenizationResolve = undefined;
513
631
  this.tokenizationReject = undefined;
@@ -515,19 +633,16 @@ export class CardConnectTokenizer extends Tokenizer {
515
633
  }
516
634
  }
517
635
  if (data.event === 'validation' || data.validationError !== undefined) {
636
+ this.acceptAutoToken = true;
518
637
  this.handleValidationMessage(data);
519
638
  }
520
- if (data.event === 'focus' || data.event === 'blur') {
521
- this.emit(data.event, { field: data.data });
522
- }
523
- if (data.event === 'input' || data.event === 'change') {
524
- this.emit('change', { field: data.data });
525
- if (data.cardType) {
526
- const cardType = this.normalizeCardType(data.cardType);
527
- if (cardType !== this.currentCardType) {
528
- this.currentCardType = cardType;
529
- this.emit('cardTypeChange', { cardType });
530
- }
639
+ if ((data.event === 'input' || data.event === 'change') &&
640
+ data.cardType) {
641
+ this.acceptAutoToken = true;
642
+ const cardType = this.normalizeCardType(data.cardType);
643
+ if (cardType !== this.currentCardType) {
644
+ this.currentCardType = cardType;
645
+ this.emit('cardTypeChange', { cardType });
531
646
  }
532
647
  }
533
648
  }
@@ -535,7 +650,6 @@ export class CardConnectTokenizer extends Tokenizer {
535
650
  }
536
651
  }
537
652
  handleValidationMessage(data) {
538
- var _a, _b, _c, _d, _e, _f;
539
653
  if (data.validationError) {
540
654
  const errorLower = data.validationError.toLowerCase();
541
655
  if (errorLower.includes('card') || errorLower.includes('number')) {
@@ -557,10 +671,14 @@ export class CardConnectTokenizer extends Tokenizer {
557
671
  this.emit('validation', this.currentValidationState);
558
672
  }
559
673
  else {
560
- this.currentValidationState.isValid =
561
- ((_b = (_a = this.currentValidationState.cardNumber) === null || _a === void 0 ? void 0 : _a.isValid) !== null && _b !== void 0 ? _b : false) &&
562
- ((_d = (_c = this.currentValidationState.cvv) === null || _c === void 0 ? void 0 : _c.isValid) !== null && _d !== void 0 ? _d : false) &&
563
- ((_f = (_e = this.currentValidationState.expiry) === null || _e === void 0 ? void 0 : _e.isValid) !== null && _f !== void 0 ? _f : false);
674
+ this.currentValidationState.cardNumber = {
675
+ isValid: true,
676
+ isEmpty: false,
677
+ };
678
+ this.currentValidationState.cvv = { isValid: true, isEmpty: false };
679
+ this.currentValidationState.expiry = { isValid: true, isEmpty: false };
680
+ this.currentValidationState.isValid = true;
681
+ this.emit('validation', this.currentValidationState);
564
682
  }
565
683
  }
566
684
  static generateIframeUrl(baseUrl, container) {
@@ -740,16 +858,29 @@ export class CardConnectTokenizer extends Tokenizer {
740
858
  }
741
859
  return encodeURIComponent(css.join(''));
742
860
  }
743
- static tokenizeBankAccount(routingNumber, accountNumber, config) {
744
- return fetch(`${config.cardConnectBaseUrl}/cardsecure/api/v1/ccn/tokenize`, {
745
- method: 'POST',
746
- headers: {
747
- 'Content-Type': 'application/json',
748
- },
749
- body: JSON.stringify({
750
- account: `${routingNumber}/${accountNumber}`,
751
- unique: true,
752
- }),
753
- }).then((response) => response.json());
861
+ static tokenizeBankAccount(routingNumber, accountNumber, configOrBaseUrl) {
862
+ return __awaiter(this, void 0, void 0, function* () {
863
+ const baseUrl = typeof configOrBaseUrl === 'string'
864
+ ? configOrBaseUrl
865
+ : configOrBaseUrl.cardConnectBaseUrl;
866
+ const response = yield fetch(`${baseUrl}/cardsecure/api/v1/ccn/tokenize`, {
867
+ method: 'POST',
868
+ headers: {
869
+ 'Content-Type': 'application/json',
870
+ },
871
+ body: JSON.stringify({
872
+ account: `${routingNumber}/${accountNumber}`,
873
+ unique: true,
874
+ }),
875
+ });
876
+ if (!response.ok) {
877
+ throw new TokenizationError(`Bank account tokenization failed: HTTP ${response.status}`, 'API_ERROR');
878
+ }
879
+ const result = yield response.json();
880
+ if (!result.token) {
881
+ throw new TokenizationError(result.message || 'Bank account tokenization failed: no token returned', 'API_ERROR');
882
+ }
883
+ return result;
884
+ });
754
885
  }
755
886
  }
@@ -41,6 +41,7 @@ export declare class PayPalTokenizer extends Tokenizer {
41
41
  private configContext;
42
42
  private containerEl?;
43
43
  private paypalButtonContainer?;
44
+ private buttonsInstance?;
44
45
  private cachedToken?;
45
46
  private currency;
46
47
  private amount?;
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Tokenizer } from './Tokenizer';
11
11
  import { TokenizationError, } from './types';
12
+ import { CLIENT_HEADERS } from '../constants';
12
13
  const PAYPAL_SDK_URL = 'https://www.paypal.com/sdk/js';
13
14
  const PAYPAL_SCRIPT_ID = 'paypal-sdk-script';
14
15
  const INIT_TIMEOUT = 10000;
@@ -19,7 +20,7 @@ export class PayPalTokenizer extends Tokenizer {
19
20
  this.gateway = gateway;
20
21
  this.containerId = containerId;
21
22
  this.configContext = configContext;
22
- this.mode = 'credit_card';
23
+ this.mode = 'paypal';
23
24
  const gatewayConfig = gateway.config;
24
25
  if (!(gatewayConfig === null || gatewayConfig === void 0 ? void 0 : gatewayConfig.client_id)) {
25
26
  throw new Error('PayPal gateway configuration missing client_id');
@@ -66,7 +67,7 @@ export class PayPalTokenizer extends Tokenizer {
66
67
  })
67
68
  .then(() => {
68
69
  this.emit('ready');
69
- this.emit('validation', { isValid: true });
70
+ this.emit('validation', { isValid: true, hasToken: false });
70
71
  resolve();
71
72
  })
72
73
  .catch((error) => {
@@ -79,11 +80,20 @@ export class PayPalTokenizer extends Tokenizer {
79
80
  }
80
81
  loadPayPalSDK() {
81
82
  return __awaiter(this, void 0, void 0, function* () {
82
- if (window.paypal) {
83
- return Promise.resolve();
84
- }
85
- if (document.getElementById(PAYPAL_SCRIPT_ID)) {
86
- return this.waitForPayPalGlobal();
83
+ const configKey = `${this.clientId}|${this.currency}`;
84
+ const existingScript = document.getElementById(PAYPAL_SCRIPT_ID);
85
+ if (existingScript) {
86
+ const loadedConfig = existingScript.getAttribute('data-config-key');
87
+ if (loadedConfig && loadedConfig !== configKey) {
88
+ existingScript.remove();
89
+ delete window.paypal;
90
+ }
91
+ else if (window.paypal) {
92
+ return Promise.resolve();
93
+ }
94
+ else {
95
+ return this.waitForPayPalGlobal();
96
+ }
87
97
  }
88
98
  const params = new URLSearchParams({
89
99
  'client-id': this.clientId,
@@ -102,6 +112,7 @@ export class PayPalTokenizer extends Tokenizer {
102
112
  script.id = PAYPAL_SCRIPT_ID;
103
113
  script.src = `${PAYPAL_SDK_URL}?${params.toString()}`;
104
114
  script.async = true;
115
+ script.setAttribute('data-config-key', configKey);
105
116
  return new Promise((resolve, reject) => {
106
117
  script.onload = () => {
107
118
  this.waitForPayPalGlobal().then(resolve).catch(reject);
@@ -145,7 +156,7 @@ export class PayPalTokenizer extends Tokenizer {
145
156
  if (!window.paypal || !this.paypalButtonContainer) {
146
157
  return;
147
158
  }
148
- const button = window.paypal.Buttons({
159
+ this.buttonsInstance = window.paypal.Buttons({
149
160
  createOrder: () => this.createOrder(),
150
161
  onApprove: (data) => this.handleApprove(data),
151
162
  onCancel: (data) => this.handleCancel(data),
@@ -156,36 +167,48 @@ export class PayPalTokenizer extends Tokenizer {
156
167
  height: 40,
157
168
  },
158
169
  });
159
- yield button.render(this.paypalButtonContainer);
170
+ yield this.buttonsInstance.render(this.paypalButtonContainer);
160
171
  });
161
172
  }
162
173
  createOrder() {
163
174
  const endpoint = `${this.clientConfig.embedApiBaseUrl}/payment/paypal/create-order`;
175
+ this.paymentTransactionId = undefined;
176
+ this.paymentMethodId = undefined;
164
177
  let orderAmount;
165
178
  let orderCurrency = this.currency;
166
179
  if (this.onCreateOrder) {
167
- const orderData = this.onCreateOrder();
168
- orderAmount = orderData.amount;
169
- orderCurrency = orderData.currency || this.currency;
180
+ try {
181
+ const orderData = this.onCreateOrder();
182
+ orderAmount = orderData.amount;
183
+ orderCurrency = orderData.currency || this.currency;
184
+ }
185
+ catch (err) {
186
+ const error = err instanceof Error
187
+ ? err
188
+ : new Error('onCreateOrder callback failed');
189
+ this.handleError(error, 'Order creation failed');
190
+ return Promise.reject(error);
191
+ }
170
192
  }
171
193
  else {
172
194
  orderAmount = this.amount;
173
195
  }
174
- if (orderAmount === undefined || orderAmount <= 0) {
196
+ if (orderAmount === undefined || isNaN(orderAmount) || orderAmount <= 0) {
175
197
  const error = new Error('Amount is required to create PayPal order');
176
198
  this.handleError(error, 'Order creation failed');
177
199
  return Promise.reject(error);
178
200
  }
179
201
  const requestBody = {
180
202
  payment_gateway_id: this.gateway.id,
203
+ organization_id: this.organizationId,
204
+ embed_id: this.embedId,
181
205
  currency: orderCurrency,
182
206
  amount: orderAmount,
183
207
  };
184
208
  return fetch(endpoint, {
185
209
  method: 'POST',
186
- headers: {
187
- 'Content-Type': 'application/json',
188
- },
210
+ headers: CLIENT_HEADERS,
211
+ credentials: 'include',
189
212
  body: JSON.stringify(requestBody),
190
213
  })
191
214
  .then((response) => {
@@ -212,6 +235,7 @@ export class PayPalTokenizer extends Tokenizer {
212
235
  const token = {
213
236
  token: data.orderID,
214
237
  lastFour: data.orderID.slice(-4),
238
+ paymentMethodType: 'paypal',
215
239
  provider: 'paypal_checkout',
216
240
  paymentMethodId: this.paymentMethodId,
217
241
  paymentTransactionId: this.paymentTransactionId,
@@ -241,6 +265,9 @@ export class PayPalTokenizer extends Tokenizer {
241
265
  }
242
266
  validate() {
243
267
  return __awaiter(this, void 0, void 0, function* () {
268
+ if (!this.isReady) {
269
+ throw new Error('Tokenizer not initialized');
270
+ }
244
271
  return {
245
272
  isValid: true,
246
273
  errors: [],
@@ -254,6 +281,15 @@ export class PayPalTokenizer extends Tokenizer {
254
281
  focus(field) {
255
282
  }
256
283
  destroy() {
284
+ this.markDestroyed();
285
+ if (this.buttonsInstance) {
286
+ try {
287
+ this.buttonsInstance.close();
288
+ }
289
+ catch (_a) {
290
+ }
291
+ this.buttonsInstance = undefined;
292
+ }
257
293
  if (this.containerEl) {
258
294
  this.containerEl.innerHTML = '';
259
295
  }
@@ -29,6 +29,10 @@ export declare class SpreedlyTokenizer extends Tokenizer {
29
29
  private cardNumberDiv?;
30
30
  private cvvDiv?;
31
31
  private responsiveBreakpoint;
32
+ private tokenizationPromise?;
33
+ private tokenizationResolve?;
34
+ private tokenizationReject?;
35
+ private tokenizationTimeout?;
32
36
  private constructor();
33
37
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
34
38
  organizationId: string;
@@ -38,6 +42,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
38
42
  private init;
39
43
  tokenize(paymentData: PaymentData): Promise<PaymentToken>;
40
44
  private tokenizeCardInternal;
45
+ private executeCardTokenization;
41
46
  private createCanadianBankAccountFields;
42
47
  private tokenizeBankAccountInternal;
43
48
  validate(): Promise<ValidationResult>;
@@ -50,6 +55,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
50
55
  private determineLayout;
51
56
  private setupResizeObserver;
52
57
  private applyLayoutStyles;
58
+ private clearTokenizationState;
53
59
  destroy(): void;
54
60
  hasToken(): boolean;
55
61
  getToken(): PaymentToken | null;