@idonatedev/idonate-sdk 1.1.0-dev12 → 1.1.0-dev14

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 (54) hide show
  1. package/README.md +27 -0
  2. package/dist/esm/apple-pay.d.ts +12 -0
  3. package/dist/esm/apple-pay.js +74 -0
  4. package/dist/esm/cloudflare-challenge-handler.d.ts +5 -0
  5. package/dist/esm/cloudflare-challenge-handler.js +77 -0
  6. package/dist/esm/config-handler.d.ts +22 -0
  7. package/dist/esm/config-handler.js +47 -0
  8. package/dist/esm/constants.d.ts +18 -0
  9. package/dist/esm/constants.js +82 -0
  10. package/dist/esm/google-pay.d.ts +18 -0
  11. package/dist/esm/google-pay.js +140 -0
  12. package/dist/esm/idonate-client.d.ts +28 -0
  13. package/dist/esm/idonate-client.js +256 -0
  14. package/dist/esm/index.d.ts +11 -0
  15. package/dist/esm/index.js +11 -0
  16. package/dist/esm/recaptcha.d.ts +12 -0
  17. package/dist/esm/recaptcha.js +89 -0
  18. package/dist/esm/shared.d.ts +3 -0
  19. package/dist/esm/shared.js +13 -0
  20. package/dist/esm/test-utils.d.ts +81 -0
  21. package/dist/esm/test-utils.js +94 -0
  22. package/dist/esm/tokenize/CardConnectTokenizer.d.ts +51 -0
  23. package/dist/esm/tokenize/CardConnectTokenizer.js +706 -0
  24. package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +92 -0
  25. package/dist/esm/tokenize/SpreedlyTokenizer.js +1140 -0
  26. package/dist/esm/tokenize/Tokenizer.d.ts +37 -0
  27. package/dist/esm/tokenize/Tokenizer.js +146 -0
  28. package/dist/esm/tokenize/iats.d.ts +3 -0
  29. package/dist/esm/tokenize/iats.js +48 -0
  30. package/dist/esm/tokenize/index.d.ts +6 -0
  31. package/dist/esm/tokenize/index.js +6 -0
  32. package/dist/esm/tokenize/spreedly-secure.d.ts +8 -0
  33. package/dist/esm/tokenize/spreedly-secure.js +40 -0
  34. package/dist/esm/tokenize/styles.d.ts +4 -0
  35. package/dist/esm/tokenize/styles.js +46 -0
  36. package/dist/esm/tokenize/tokenizer-constants.d.ts +62 -0
  37. package/dist/esm/tokenize/tokenizer-constants.js +62 -0
  38. package/dist/esm/tokenize/tokenizer-utils.d.ts +19 -0
  39. package/dist/esm/tokenize/tokenizer-utils.js +139 -0
  40. package/dist/esm/tokenize/types.d.ts +144 -0
  41. package/dist/esm/tokenize/types.js +26 -0
  42. package/dist/esm/typeAdapters.d.ts +29 -0
  43. package/dist/esm/typeAdapters.js +188 -0
  44. package/dist/esm/types.d.ts +367 -0
  45. package/dist/esm/types.js +14 -0
  46. package/dist/esm/util.d.ts +17 -0
  47. package/dist/esm/util.js +113 -0
  48. package/dist/typeAdapters.js +0 -9
  49. package/package.json +52 -23
  50. package/umd/idonate-sdk.js +1 -1
  51. package/dist/tokenize/cardconnect.d.ts +0 -3
  52. package/dist/tokenize/cardconnect.js +0 -16
  53. package/dist/tokenize/spreedly.d.ts +0 -48
  54. package/dist/tokenize/spreedly.js +0 -208
@@ -0,0 +1,706 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Tokenizer } from './Tokenizer';
11
+ import { TokenizationError, } from './types';
12
+ import ConfigHandler from '../config-handler';
13
+ import { DEFAULT_UNIFIED_STYLES, mergeStyles, getContainerStylesForLayout, } from './styles';
14
+ import { INIT_TIMEOUT, TOKENIZE_TIMEOUT, BANK_FIELD_FLEX, } from './tokenizer-constants';
15
+ import { createInputElement, validateRoutingNumber, validateAccountNumber, createAccountTypeSelect, } from './tokenizer-utils';
16
+ export class CardConnectTokenizer extends Tokenizer {
17
+ constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false, layout = 'single-line') {
18
+ super();
19
+ this.iframeUrl = iframeUrl;
20
+ this.containerId = containerId;
21
+ this.layout = layout;
22
+ this.isReady = false;
23
+ this.enableTestMode = false;
24
+ this.mode = mode;
25
+ this.enableTestMode = enableTestMode;
26
+ this.iframe = iframe;
27
+ const url = new URL(iframeUrl);
28
+ this.expectedOrigin = `${url.protocol}//${url.host}`;
29
+ this.currentValidationState = {
30
+ isValid: false,
31
+ cardNumber: { isValid: false, isEmpty: true },
32
+ cvv: { isValid: false, isEmpty: true },
33
+ expiry: { isValid: false, isEmpty: true },
34
+ };
35
+ }
36
+ static create(gateway, container, config) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ var _a;
39
+ if (container.mode === 'bank_account' && container.bankCountry === 'CA') {
40
+ throw new Error('CardConnect does not support Canadian bank accounts');
41
+ }
42
+ let baseUrl = ((_a = gateway.config) === null || _a === void 0 ? void 0 : _a.base_url) || config.clientConfig.cardConnectBaseUrl;
43
+ config.cardConnectBaseUrl = baseUrl;
44
+ const mergedStyles = mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling);
45
+ const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, container);
46
+ const iframe = CardConnectTokenizer.createIframe(iframeUrl, mergedStyles);
47
+ const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false, container.layout || 'single-line');
48
+ tokenizer.createInternalElements(container);
49
+ yield tokenizer.init();
50
+ return tokenizer;
51
+ });
52
+ }
53
+ createInternalElements(container) {
54
+ const containerEl = document.getElementById(container.containerId);
55
+ if (!containerEl) {
56
+ throw new Error(`Container element not found: ${container.containerId}`);
57
+ }
58
+ this.containerEl = containerEl;
59
+ containerEl.innerHTML = '';
60
+ const mergedStyles = getContainerStylesForLayout(mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling), this.layout);
61
+ Object.assign(containerEl.style, mergedStyles.container);
62
+ if (this.mode === 'bank_account') {
63
+ this.createBankAccountFields(containerEl, mergedStyles);
64
+ }
65
+ else {
66
+ this.createCreditCardFields(containerEl, mergedStyles);
67
+ }
68
+ }
69
+ createCreditCardFields(containerEl, mergedStyles) {
70
+ this.iframe.style.width = '100%';
71
+ if (this.layout === 'two-line') {
72
+ const inputHeight = mergedStyles.input.height || '40px';
73
+ this.iframe.style.height = `calc((${inputHeight}) * 2 + 10px)`;
74
+ }
75
+ else {
76
+ this.iframe.style.height = mergedStyles.input.height || '40px';
77
+ }
78
+ this.iframe.style.border = 'none';
79
+ this.iframe.style.display = 'block';
80
+ containerEl.appendChild(this.iframe);
81
+ }
82
+ createBankAccountFields(containerEl, mergedStyles) {
83
+ this.iframe.style.display = 'none';
84
+ if (this.layout === 'two-line') {
85
+ this.accountTypeEl = createAccountTypeSelect(`${this.containerId}-account-type`);
86
+ Object.assign(this.accountTypeEl.style, {
87
+ flex: '1',
88
+ minWidth: BANK_FIELD_FLEX.accountType.minWidth,
89
+ });
90
+ this.applyInputStyles(this.accountTypeEl, mergedStyles, 'left');
91
+ containerEl.appendChild(this.accountTypeEl);
92
+ this.routingNumberEl = createInputElement(`${this.containerId}-routing`, 'text', 'Routing *', 9);
93
+ Object.assign(this.routingNumberEl.style, {
94
+ flex: '1',
95
+ minWidth: BANK_FIELD_FLEX.routingNumber.minWidth,
96
+ });
97
+ this.applyInputStyles(this.routingNumberEl, mergedStyles, 'right');
98
+ containerEl.appendChild(this.routingNumberEl);
99
+ this.accountNumberEl = createInputElement(`${this.containerId}-account`, 'text', 'Account Number *', 17);
100
+ Object.assign(this.accountNumberEl.style, {
101
+ flex: '1',
102
+ flexBasis: '100%',
103
+ minWidth: BANK_FIELD_FLEX.accountNumber.minWidth,
104
+ });
105
+ this.applyInputStyles(this.accountNumberEl, mergedStyles);
106
+ containerEl.appendChild(this.accountNumberEl);
107
+ }
108
+ else {
109
+ this.routingNumberEl = createInputElement(`${this.containerId}-routing`, 'text', 'Routing *', 9);
110
+ Object.assign(this.routingNumberEl.style, {
111
+ flex: BANK_FIELD_FLEX.routingNumber.flex,
112
+ minWidth: BANK_FIELD_FLEX.routingNumber.minWidth,
113
+ });
114
+ this.applyInputStyles(this.routingNumberEl, mergedStyles, 'left');
115
+ containerEl.appendChild(this.routingNumberEl);
116
+ this.accountNumberEl = createInputElement(`${this.containerId}-account`, 'text', 'Account Number *', 17);
117
+ Object.assign(this.accountNumberEl.style, {
118
+ flex: BANK_FIELD_FLEX.accountNumber.flex,
119
+ minWidth: BANK_FIELD_FLEX.accountNumber.minWidth,
120
+ });
121
+ this.applyInputStyles(this.accountNumberEl, mergedStyles, 'middle');
122
+ containerEl.appendChild(this.accountNumberEl);
123
+ this.accountTypeEl = createAccountTypeSelect(`${this.containerId}-account-type`);
124
+ Object.assign(this.accountTypeEl.style, {
125
+ flex: BANK_FIELD_FLEX.accountType.flex,
126
+ minWidth: BANK_FIELD_FLEX.accountType.minWidth,
127
+ });
128
+ this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
129
+ containerEl.appendChild(this.accountTypeEl);
130
+ }
131
+ }
132
+ init() {
133
+ return __awaiter(this, void 0, void 0, function* () {
134
+ if (this.mode === 'bank_account') {
135
+ this.isReady = true;
136
+ if (this.enableTestMode) {
137
+ setTimeout(() => {
138
+ if (this.routingNumberEl) {
139
+ this.routingNumberEl.value = '021000021';
140
+ this.routingNumberEl.dispatchEvent(new Event('input', { bubbles: true }));
141
+ }
142
+ if (this.accountNumberEl) {
143
+ this.accountNumberEl.value = '9876543210';
144
+ this.accountNumberEl.dispatchEvent(new Event('input', { bubbles: true }));
145
+ }
146
+ if (this.accountTypeEl) {
147
+ this.accountTypeEl.value = 'checking';
148
+ this.accountTypeEl.dispatchEvent(new Event('change', { bubbles: true }));
149
+ }
150
+ }, 100);
151
+ }
152
+ this.emit('ready');
153
+ return Promise.resolve();
154
+ }
155
+ return new Promise((resolve, reject) => {
156
+ const timeout = setTimeout(() => {
157
+ reject(new Error('CardConnect initialization timeout'));
158
+ }, INIT_TIMEOUT);
159
+ this.messageHandler = (event) => {
160
+ if (event.origin !== this.expectedOrigin) {
161
+ return;
162
+ }
163
+ this.handleMessage(event);
164
+ };
165
+ window.addEventListener('message', this.messageHandler);
166
+ this.iframe.onload = () => {
167
+ clearTimeout(timeout);
168
+ this.isReady = true;
169
+ if (this.enableTestMode && this.mode === 'credit_card') {
170
+ }
171
+ this.emit('ready');
172
+ resolve();
173
+ };
174
+ this.iframe.onerror = () => {
175
+ clearTimeout(timeout);
176
+ reject(new Error('Failed to load CardConnect iframe'));
177
+ };
178
+ });
179
+ });
180
+ }
181
+ tokenize(paymentData) {
182
+ return __awaiter(this, void 0, void 0, function* () {
183
+ if (!this.isReady) {
184
+ throw new Error('Tokenizer not initialized');
185
+ }
186
+ if (this.mode === 'credit_card' && this.hasToken()) {
187
+ const cachedToken = this.getToken();
188
+ if (cachedToken) {
189
+ return cachedToken;
190
+ }
191
+ }
192
+ if (this.mode === 'bank_account' || this.isBankAccountData(paymentData)) {
193
+ return this.tokenizeBankAccountInternal(paymentData);
194
+ }
195
+ else {
196
+ return this.tokenizeCardInternal(paymentData);
197
+ }
198
+ });
199
+ }
200
+ tokenizeCardInternal(cardData) {
201
+ return __awaiter(this, void 0, void 0, function* () {
202
+ if (this.cachedTokenResult && this.cachedTokenResult.errorCode === '0') {
203
+ return {
204
+ token: this.cachedTokenResult.token,
205
+ lastFour: this.cachedTokenResult.token.slice(-4),
206
+ cardType: this.normalizeCardType('unknown'),
207
+ provider: 'cardconnect',
208
+ };
209
+ }
210
+ if (this.tokenizationPromise) {
211
+ return this.tokenizationPromise;
212
+ }
213
+ this.tokenizationPromise = new Promise((resolve, reject) => {
214
+ this.tokenizationResolve = resolve;
215
+ this.tokenizationReject = reject;
216
+ const timeout = setTimeout(() => {
217
+ this.tokenizationPromise = undefined;
218
+ this.tokenizationResolve = undefined;
219
+ this.tokenizationReject = undefined;
220
+ reject(new TokenizationError('Tokenization timeout - ensure all card fields are filled in iframe', 'TIMEOUT'));
221
+ }, TOKENIZE_TIMEOUT);
222
+ const tokenizationHandler = (data) => {
223
+ clearTimeout(timeout);
224
+ this.off('tokenization', tokenizationHandler);
225
+ };
226
+ this.on('tokenization', tokenizationHandler);
227
+ });
228
+ return this.tokenizationPromise;
229
+ });
230
+ }
231
+ tokenizeBankAccountInternal(bankData) {
232
+ return __awaiter(this, void 0, void 0, function* () {
233
+ var _a, _b, _c;
234
+ const routingNumber = (_a = this.routingNumberEl) === null || _a === void 0 ? void 0 : _a.value;
235
+ const accountNumber = (_b = this.accountNumberEl) === null || _b === void 0 ? void 0 : _b.value;
236
+ const accountType = ((_c = this.accountTypeEl) === null || _c === void 0 ? void 0 : _c.value) || 'checking';
237
+ const accountHolderType = 'personal';
238
+ if (!routingNumber || !accountNumber) {
239
+ throw new TokenizationError('Routing number and account number are required', 'VALIDATION_ERROR');
240
+ }
241
+ if (!validateRoutingNumber(routingNumber)) {
242
+ throw new TokenizationError('Invalid routing number', 'VALIDATION_ERROR');
243
+ }
244
+ if (!validateAccountNumber(accountNumber)) {
245
+ throw new TokenizationError('Invalid account number', 'VALIDATION_ERROR');
246
+ }
247
+ const baseUrl = new URL(this.iframeUrl).origin;
248
+ const config = new ConfigHandler({});
249
+ config.cardConnectBaseUrl = baseUrl;
250
+ const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, config);
251
+ return {
252
+ token: result.token,
253
+ lastFour: accountNumber.slice(-4),
254
+ accountType: accountType,
255
+ paymentMethodType: 'bank_account',
256
+ provider: 'cardconnect',
257
+ };
258
+ });
259
+ }
260
+ validate() {
261
+ return __awaiter(this, void 0, void 0, function* () {
262
+ if (!this.isReady) {
263
+ throw new Error('Tokenizer not initialized');
264
+ }
265
+ if (this.mode === 'bank_account') {
266
+ return this.validateBankAccountInternal();
267
+ }
268
+ else {
269
+ return this.validateCardInternal();
270
+ }
271
+ });
272
+ }
273
+ validateCardInternal() {
274
+ return __awaiter(this, void 0, void 0, function* () {
275
+ const errors = [];
276
+ if (this.currentValidationState.cardNumber) {
277
+ if (this.currentValidationState.cardNumber.isEmpty) {
278
+ errors.push({
279
+ field: 'cardNumber',
280
+ message: 'Card number is required',
281
+ });
282
+ }
283
+ else if (!this.currentValidationState.cardNumber.isValid) {
284
+ errors.push({
285
+ field: 'cardNumber',
286
+ message: 'Invalid card number',
287
+ });
288
+ }
289
+ }
290
+ else {
291
+ errors.push({
292
+ field: 'cardNumber',
293
+ message: 'Card number is required',
294
+ });
295
+ }
296
+ if (this.currentValidationState.expiry) {
297
+ if (this.currentValidationState.expiry.isEmpty) {
298
+ errors.push({
299
+ field: 'expiry',
300
+ message: 'Expiry date is required',
301
+ });
302
+ }
303
+ else if (!this.currentValidationState.expiry.isValid) {
304
+ errors.push({
305
+ field: 'expiry',
306
+ message: 'Invalid expiry date',
307
+ });
308
+ }
309
+ }
310
+ else {
311
+ errors.push({
312
+ field: 'expiry',
313
+ message: 'Expiry date is required',
314
+ });
315
+ }
316
+ if (this.currentValidationState.cvv) {
317
+ if (this.currentValidationState.cvv.isEmpty) {
318
+ errors.push({
319
+ field: 'cvv',
320
+ message: 'CVV is required',
321
+ });
322
+ }
323
+ else if (!this.currentValidationState.cvv.isValid) {
324
+ errors.push({
325
+ field: 'cvv',
326
+ message: 'Invalid CVV',
327
+ });
328
+ }
329
+ }
330
+ else {
331
+ errors.push({
332
+ field: 'cvv',
333
+ message: 'CVV is required',
334
+ });
335
+ }
336
+ return {
337
+ isValid: this.currentValidationState.isValid,
338
+ errors,
339
+ };
340
+ });
341
+ }
342
+ validateBankAccountInternal() {
343
+ return __awaiter(this, void 0, void 0, function* () {
344
+ var _a, _b;
345
+ const errors = [];
346
+ if (!((_a = this.routingNumberEl) === null || _a === void 0 ? void 0 : _a.value)) {
347
+ errors.push({
348
+ field: 'routingNumber',
349
+ message: 'Routing number is required',
350
+ });
351
+ }
352
+ else if (!validateRoutingNumber(this.routingNumberEl.value)) {
353
+ errors.push({
354
+ field: 'routingNumber',
355
+ message: 'Invalid routing number',
356
+ });
357
+ }
358
+ if (!((_b = this.accountNumberEl) === null || _b === void 0 ? void 0 : _b.value)) {
359
+ errors.push({
360
+ field: 'accountNumber',
361
+ message: 'Account number is required',
362
+ });
363
+ }
364
+ else if (!validateAccountNumber(this.accountNumberEl.value)) {
365
+ errors.push({
366
+ field: 'accountNumber',
367
+ message: 'Invalid account number',
368
+ });
369
+ }
370
+ return {
371
+ isValid: errors.length === 0,
372
+ errors,
373
+ };
374
+ });
375
+ }
376
+ clear() {
377
+ var _a;
378
+ if (this.mode === 'bank_account') {
379
+ if (this.routingNumberEl) {
380
+ this.routingNumberEl.value = '';
381
+ }
382
+ if (this.accountNumberEl) {
383
+ this.accountNumberEl.value = '';
384
+ }
385
+ if (this.accountTypeEl) {
386
+ this.accountTypeEl.value = 'checking';
387
+ }
388
+ }
389
+ else {
390
+ (_a = this.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage({
391
+ action: 'clear',
392
+ }, this.expectedOrigin);
393
+ }
394
+ this.currentValidationState = {
395
+ isValid: false,
396
+ cardNumber: { isValid: false, isEmpty: true },
397
+ cvv: { isValid: false, isEmpty: true },
398
+ expiry: { isValid: false, isEmpty: true },
399
+ };
400
+ this.emit('validation', this.currentValidationState);
401
+ }
402
+ focus(field) {
403
+ var _a;
404
+ if (this.mode === 'bank_account') {
405
+ if (field === 'routingNumber' && this.routingNumberEl) {
406
+ this.routingNumberEl.focus();
407
+ }
408
+ else if (field === 'accountNumber' && this.accountNumberEl) {
409
+ this.accountNumberEl.focus();
410
+ }
411
+ }
412
+ else {
413
+ const fieldMap = {
414
+ cardNumber: 'number',
415
+ cvv: 'cvv',
416
+ expiry: 'expiry',
417
+ };
418
+ const iframeField = fieldMap[field];
419
+ if (iframeField) {
420
+ (_a = this.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage({
421
+ action: 'focus',
422
+ field: iframeField,
423
+ }, this.expectedOrigin);
424
+ }
425
+ }
426
+ }
427
+ destroy() {
428
+ if (this.messageHandler) {
429
+ window.removeEventListener('message', this.messageHandler);
430
+ }
431
+ if (this.containerEl) {
432
+ this.containerEl.innerHTML = '';
433
+ }
434
+ this.eventHandlers.clear();
435
+ }
436
+ hasToken() {
437
+ var _a, _b;
438
+ if (this.mode === 'credit_card') {
439
+ return (((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0' &&
440
+ !!((_b = this.cachedTokenResult) === null || _b === void 0 ? void 0 : _b.token));
441
+ }
442
+ return false;
443
+ }
444
+ getToken() {
445
+ var _a;
446
+ if (this.mode === 'credit_card' &&
447
+ ((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0') {
448
+ return {
449
+ token: this.cachedTokenResult.token,
450
+ lastFour: this.cachedTokenResult.token.slice(-4),
451
+ cardType: this.normalizeCardType('unknown'),
452
+ provider: 'cardconnect',
453
+ };
454
+ }
455
+ return null;
456
+ }
457
+ get tokenizationMode() {
458
+ return this.mode === 'credit_card' ? 'auto' : 'manual';
459
+ }
460
+ handleMessage(event) {
461
+ try {
462
+ const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
463
+ if (data.token && data.errorCode !== undefined) {
464
+ this.cachedTokenResult = data;
465
+ this.emit('tokenization', data);
466
+ if (data.errorCode === '0') {
467
+ const token = {
468
+ token: data.token,
469
+ lastFour: data.token.slice(-4),
470
+ cardType: this.normalizeCardType('unknown'),
471
+ provider: 'cardconnect',
472
+ };
473
+ if (this.tokenizationResolve) {
474
+ this.tokenizationResolve(token);
475
+ this.tokenizationPromise = undefined;
476
+ this.tokenizationResolve = undefined;
477
+ this.tokenizationReject = undefined;
478
+ }
479
+ this.currentValidationState = {
480
+ isValid: true,
481
+ cardNumber: { isValid: true, isEmpty: false },
482
+ cvv: { isValid: true, isEmpty: false },
483
+ expiry: { isValid: true, isEmpty: false },
484
+ };
485
+ this.emit('validation', { isValid: true });
486
+ this.emit('tokenReady', token);
487
+ }
488
+ else {
489
+ if (this.tokenizationReject) {
490
+ this.tokenizationReject(new TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
491
+ this.tokenizationPromise = undefined;
492
+ this.tokenizationResolve = undefined;
493
+ this.tokenizationReject = undefined;
494
+ }
495
+ }
496
+ }
497
+ if (data.event === 'validation' || data.validationError !== undefined) {
498
+ this.handleValidationMessage(data);
499
+ }
500
+ if (data.event === 'focus' || data.event === 'blur') {
501
+ this.emit(data.event, { field: data.data });
502
+ }
503
+ if (data.event === 'input' || data.event === 'change') {
504
+ this.emit('change', { field: data.data });
505
+ }
506
+ }
507
+ catch (error) {
508
+ }
509
+ }
510
+ handleValidationMessage(data) {
511
+ var _a, _b, _c, _d, _e, _f;
512
+ if (data.validationError) {
513
+ const errorLower = data.validationError.toLowerCase();
514
+ if (errorLower.includes('card') || errorLower.includes('number')) {
515
+ this.currentValidationState.cardNumber = {
516
+ isValid: false,
517
+ isEmpty: false,
518
+ };
519
+ }
520
+ else if (errorLower.includes('cvv') ||
521
+ errorLower.includes('security')) {
522
+ this.currentValidationState.cvv = { isValid: false, isEmpty: false };
523
+ }
524
+ else if (errorLower.includes('expir') ||
525
+ errorLower.includes('month') ||
526
+ errorLower.includes('year')) {
527
+ this.currentValidationState.expiry = { isValid: false, isEmpty: false };
528
+ }
529
+ this.emit('error', new TokenizationError(data.validationError));
530
+ }
531
+ this.currentValidationState.isValid =
532
+ ((_b = (_a = this.currentValidationState.cardNumber) === null || _a === void 0 ? void 0 : _a.isValid) !== null && _b !== void 0 ? _b : false) &&
533
+ ((_d = (_c = this.currentValidationState.cvv) === null || _c === void 0 ? void 0 : _c.isValid) !== null && _d !== void 0 ? _d : false) &&
534
+ ((_f = (_e = this.currentValidationState.expiry) === null || _e === void 0 ? void 0 : _e.isValid) !== null && _f !== void 0 ? _f : false);
535
+ }
536
+ static generateIframeUrl(baseUrl, container) {
537
+ const params = new URLSearchParams({
538
+ invalidinputevent: 'true',
539
+ enhancedresponse: 'true',
540
+ useexpiry: 'true',
541
+ usecvv: 'true',
542
+ formatinput: 'true',
543
+ unique: 'true',
544
+ norsa: 'true',
545
+ placeholder: 'Card Number *',
546
+ placeholdercvv: 'CVV',
547
+ invalidcreditcardevent: 'true',
548
+ invalidexpiry: 'true',
549
+ invalidcvv: 'true',
550
+ });
551
+ if (container.layout === 'two-line') {
552
+ params.set('useexpiryfield', 'true');
553
+ params.set('orientation', 'horizontal');
554
+ params.set('placeholdermonth', 'MM');
555
+ params.set('placeholderyear', 'YYYY');
556
+ }
557
+ else {
558
+ params.set('orientation', 'horizontal');
559
+ params.set('placeholdermonth', 'MM');
560
+ params.set('placeholderyear', 'YYYY');
561
+ }
562
+ const mergedStyles = mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling);
563
+ const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, container.layout || 'single-line');
564
+ const queryPairs = [];
565
+ params.forEach((value, key) => {
566
+ queryPairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
567
+ });
568
+ queryPairs.push(`css=${cssString}`);
569
+ const tokenizerPath = '/itoke/ajax-tokenizer.html';
570
+ return `${baseUrl}${tokenizerPath}?${queryPairs.join('&')}`;
571
+ }
572
+ static createIframe(url, styles) {
573
+ const iframe = document.createElement('iframe');
574
+ iframe.src = url;
575
+ iframe.style.width = '100%';
576
+ iframe.style.height = styles.input.height;
577
+ iframe.style.border = 'none';
578
+ iframe.style.overflow = 'hidden';
579
+ iframe.style.display = 'block';
580
+ iframe.style.minWidth = '0';
581
+ if (styles.container) {
582
+ Object.entries(styles.container).forEach(([key, value]) => {
583
+ if (key !== 'height' && key !== 'width') {
584
+ iframe.style[key] = value;
585
+ }
586
+ });
587
+ if (styles.container.width) {
588
+ iframe.style.width = styles.container.width;
589
+ }
590
+ }
591
+ iframe.setAttribute('scrolling', 'no');
592
+ iframe.setAttribute('title', 'Secure card input');
593
+ iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms');
594
+ return iframe;
595
+ }
596
+ static generateCardConnectCss(styles, layout = 'single-line') {
597
+ var _a, _b, _c;
598
+ const css = [];
599
+ if (layout === 'two-line') {
600
+ css.push('html,form,body{margin:0;padding:0;}');
601
+ css.push('label{display:none;}');
602
+ css.push('br{display:none;}');
603
+ }
604
+ else {
605
+ css.push('body{margin:0;padding:0;display:flex;align-items:center;}');
606
+ css.push('form{margin:0;padding:0;display:flex;width:100%;align-items:center;}');
607
+ css.push('label{display:none;}');
608
+ css.push('br{display:none;}');
609
+ }
610
+ const isConnected = styles.container.gap === '0';
611
+ const gap = isConnected ? '0' : styles.container.gap || '1rem';
612
+ if (styles.input) {
613
+ const commonStyles = [];
614
+ if (styles.input.height)
615
+ commonStyles.push(`height:${styles.input.height}`);
616
+ if (styles.input.padding)
617
+ commonStyles.push(`padding:${styles.input.padding}`);
618
+ if (styles.input.fontSize)
619
+ commonStyles.push(`font-size:${styles.input.fontSize}`);
620
+ if (styles.input.fontFamily)
621
+ commonStyles.push(`font-family:${styles.input.fontFamily}`);
622
+ if (styles.input.border)
623
+ commonStyles.push(`border:${styles.input.border}`);
624
+ if (styles.input.backgroundColor)
625
+ commonStyles.push(`background-color:${styles.input.backgroundColor}`);
626
+ if (styles.input.color)
627
+ commonStyles.push(`color:${styles.input.color}`);
628
+ commonStyles.push('box-sizing:border-box');
629
+ const baseStyles = commonStyles.join(';');
630
+ css.push(`input{${baseStyles};}`);
631
+ css.push(`select{${baseStyles};}`);
632
+ }
633
+ if (layout === 'two-line') {
634
+ css.push('input#ccnumfield{width:100%;display:block;margin-bottom:8px;}');
635
+ css.push('input#ccexpiryfieldmonth{width:20%;}');
636
+ css.push('input#ccexpiryfieldyear{width:24%;}');
637
+ css.push('input#cccvvfield{width:calc(56% - 20px);}');
638
+ if ((_a = styles.input) === null || _a === void 0 ? void 0 : _a.borderRadius) {
639
+ css.push(`input{border-radius:${styles.input.borderRadius};}`);
640
+ }
641
+ }
642
+ else if (isConnected) {
643
+ css.push('input#ccnumfield{width:60%;margin:0;}');
644
+ css.push('select#ccexpirymonth{width:10%;margin:0;margin-right:-12px;}');
645
+ css.push('select#ccexpiryyear{width:10%;}');
646
+ css.push('input#cccvvfield{width:20%;margin:0;margin-left:-12px;}');
647
+ if ((_b = styles.input) === null || _b === void 0 ? void 0 : _b.borderRadius) {
648
+ css.push(`input#ccnumfield{border-radius:${styles.input.borderRadius} 0 0 ${styles.input.borderRadius};border-right:none;}`);
649
+ css.push('select#ccexpirymonth{border-radius:0;border-right:none;}');
650
+ css.push('select#ccexpiryyear{border-radius:0;border-right:none;}');
651
+ css.push(`input#cccvvfield{border-radius:0 ${styles.input.borderRadius} ${styles.input.borderRadius} 0;}`);
652
+ }
653
+ else {
654
+ css.push('input#ccnumfield{border-right:none;}');
655
+ css.push('select#ccexpirymonth{border-right:none;}');
656
+ css.push('select#ccexpiryyear{border-right:none;}');
657
+ }
658
+ }
659
+ else {
660
+ const marginRight = gap === '0' ? '0' : '8px';
661
+ css.push(`input#ccnumfield{width:60%;margin-right:${marginRight};}`);
662
+ css.push(`select#ccexpirymonth{width:10%;margin-right:${marginRight};}`);
663
+ css.push(`select#ccexpiryyear{width:10%;margin-right:${marginRight};}`);
664
+ css.push('input#cccvvfield{width:20%;}');
665
+ if ((_c = styles.input) === null || _c === void 0 ? void 0 : _c.borderRadius) {
666
+ css.push(`input,select{border-radius:${styles.input.borderRadius};}`);
667
+ }
668
+ }
669
+ if (styles.focus) {
670
+ const focusStyles = [];
671
+ if (styles.focus.borderColor)
672
+ focusStyles.push(`border-color:${styles.focus.borderColor}`);
673
+ if (styles.focus.outline) {
674
+ focusStyles.push(`outline:none`);
675
+ }
676
+ if (styles.focus.boxShadow)
677
+ focusStyles.push(`box-shadow:${styles.focus.boxShadow}`);
678
+ if (focusStyles.length > 0) {
679
+ css.push(`input:focus{${focusStyles.join(';')};}`);
680
+ }
681
+ }
682
+ if (styles.error) {
683
+ const errorStyles = [];
684
+ if (styles.error.borderColor)
685
+ errorStyles.push(`border-color:${styles.error.borderColor}`);
686
+ if (styles.error.backgroundColor)
687
+ errorStyles.push(`background-color:${styles.error.backgroundColor}`);
688
+ if (errorStyles.length > 0) {
689
+ css.push(`.error{${errorStyles.join(';')};}`);
690
+ }
691
+ }
692
+ return encodeURIComponent(css.join(''));
693
+ }
694
+ static tokenizeBankAccount(routingNumber, accountNumber, config) {
695
+ return fetch(`${config.cardConnectBaseUrl}/cardsecure/api/v1/ccn/tokenize`, {
696
+ method: 'POST',
697
+ headers: {
698
+ 'Content-Type': 'application/json',
699
+ },
700
+ body: JSON.stringify({
701
+ account: `${routingNumber}/${accountNumber}`,
702
+ unique: true,
703
+ }),
704
+ }).then((response) => response.json());
705
+ }
706
+ }