@idonatedev/idonate-sdk 1.1.0-dev0 → 1.1.0-dev10

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.
@@ -26,6 +26,9 @@ class ConfigHandler {
26
26
  if (options.overrideApplePayUrl) {
27
27
  this.applePayUrl = options.overrideApplePayUrl;
28
28
  }
29
+ if (options.overrideCardConnectBaseUrl) {
30
+ this.cardConnectBaseUrl = options.overrideCardConnectBaseUrl;
31
+ }
29
32
  this.pcScriptBase = options.pcScriptBase || constants_1.FALLBACK_PC_SCRIPT_URL;
30
33
  this.pcScriptId = options.pcScriptId || constants_1.FALLBACK_PC_SCRIPT_ID;
31
34
  this.turnstileCdnUrl =
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "1.1.0";
1
+ export declare const SDK_VERSION: string;
2
2
  export declare const PRODUCTION_BASE_URL = "https://secure-api.idonate.com";
3
3
  export declare const SANDBOX_BASE_URL = "https://api.qa-idonate.com";
4
4
  export declare const PRODUCTION_CARD_CONNECT_BASE_URL = "https://boltgw.cardconnect.com:8443";
package/dist/constants.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  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.1.0';
7
+ const package_json_1 = __importDefault(require("../package.json"));
8
+ exports.SDK_VERSION = package_json_1.default.version;
5
9
  exports.PRODUCTION_BASE_URL = 'https://secure-api.idonate.com';
6
10
  exports.SANDBOX_BASE_URL = 'https://api.qa-idonate.com';
7
11
  exports.PRODUCTION_CARD_CONNECT_BASE_URL = 'https://boltgw.cardconnect.com:8443';
@@ -79,6 +83,6 @@ input#cccvvfield {
79
83
  }
80
84
  `.replace(/\s+/gi, ' ');
81
85
  exports.CLIENT_HEADERS = {
82
- 'User-Agent': navigator.userAgent + ' idonate-sdk@1.0.16',
86
+ 'User-Agent': navigator.userAgent + ` idonate-sdk@${package_json_1.default.version}`,
83
87
  'Content-Type': 'application/json',
84
88
  };
@@ -1,4 +1,4 @@
1
- import { ClientOptions, CreatePaymentMethodRequest, CreatePaymentMethodResult, CreateDonationRequest, CreateDonationResult, TokenizeApplePayResult } from './types';
1
+ import { ClientOptions, Contact, Address, CreatePaymentMethodRequest, CreatePaymentMethodResult, CreateDonationRequest, CreateDonationResult, TokenizeApplePayResult } from './types';
2
2
  import ConfigHandler from './config-handler';
3
3
  import { Tokenizer, PaymentMethodType, PaymentGateway, TokenizerContainer } from './tokenize';
4
4
  export default class iDonateClient {
@@ -20,5 +20,9 @@ export default class iDonateClient {
20
20
  waitForDonationResult(donationId: string, afterEachCheck?: () => void): Promise<any>;
21
21
  tokenizeCardConnectApplePay(applePayRequest: Partial<ApplePayJS.ApplePayPaymentRequest>): Promise<TokenizeApplePayResult>;
22
22
  createTokenizer(gateway: PaymentGateway, container: TokenizerContainer): Promise<Tokenizer>;
23
+ tokenizeSpreedlyPayPal(data: {
24
+ contact: Contact;
25
+ address: Address;
26
+ }): Promise<string>;
23
27
  selectGateway(availableGateways: PaymentGateway[], paymentType: PaymentMethodType, preferredGatewayId?: string): PaymentGateway | undefined;
24
28
  }
@@ -51,6 +51,7 @@ const constants_1 = require("./constants");
51
51
  const util_1 = require("./util");
52
52
  const apple_pay_1 = __importDefault(require("./apple-pay"));
53
53
  const config_handler_1 = __importDefault(require("./config-handler"));
54
+ const SpreedlyTokenizer_1 = require("./tokenize/SpreedlyTokenizer");
54
55
  const shared = __importStar(require("./shared"));
55
56
  const uuid_1 = require("uuid");
56
57
  const cloudflare_challenge_handler_1 = require("./cloudflare-challenge-handler");
@@ -275,9 +276,13 @@ class iDonateClient {
275
276
  return tokenize_1.Tokenizer.create(gateway, container, {
276
277
  organizationId: this.organizationId,
277
278
  embedId: this.embedId,
279
+ clientConfig: this.config,
278
280
  });
279
281
  });
280
282
  }
283
+ tokenizeSpreedlyPayPal(data) {
284
+ return SpreedlyTokenizer_1.SpreedlyTokenizer.tokenizePayPal(data, this.config);
285
+ }
281
286
  selectGateway(availableGateways, paymentType, preferredGatewayId) {
282
287
  if (preferredGatewayId) {
283
288
  const preferred = availableGateways.find((g) => g.id === preferredGatewayId);
@@ -5,6 +5,7 @@ import ConfigHandler from '../config-handler';
5
5
  export declare class CardConnectTokenizer extends Tokenizer {
6
6
  private iframeUrl;
7
7
  private containerId;
8
+ private layout;
8
9
  private iframe;
9
10
  private messageHandler?;
10
11
  private expectedOrigin;
@@ -16,10 +17,14 @@ export declare class CardConnectTokenizer extends Tokenizer {
16
17
  private accountTypeEl?;
17
18
  private enableTestMode;
18
19
  private cachedTokenResult?;
20
+ private tokenizationPromise?;
21
+ private tokenizationResolve?;
22
+ private tokenizationReject?;
19
23
  private constructor();
20
- static create(gateway: PaymentGateway, container: TokenizerContainer, config?: {
24
+ static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
21
25
  organizationId: string;
22
26
  embedId: string;
27
+ clientConfig: ConfigHandler;
23
28
  }): Promise<CardConnectTokenizer>;
24
29
  private createInternalElements;
25
30
  private createCreditCardFields;
@@ -34,6 +39,9 @@ export declare class CardConnectTokenizer extends Tokenizer {
34
39
  clear(): void;
35
40
  focus(field: 'cardNumber' | 'cvv' | 'expiry' | 'routingNumber' | 'accountNumber'): void;
36
41
  destroy(): void;
42
+ hasToken(): boolean;
43
+ getToken(): PaymentToken | null;
44
+ get tokenizationMode(): 'auto' | 'manual';
37
45
  private handleMessage;
38
46
  private handleValidationMessage;
39
47
  private static generateIframeUrl;
@@ -20,10 +20,11 @@ const styles_1 = require("./styles");
20
20
  const tokenizer_constants_1 = require("./tokenizer-constants");
21
21
  const tokenizer_utils_1 = require("./tokenizer-utils");
22
22
  class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
23
- constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false) {
23
+ constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false, layout = 'single-line') {
24
24
  super();
25
25
  this.iframeUrl = iframeUrl;
26
26
  this.containerId = containerId;
27
+ this.layout = layout;
27
28
  this.isReady = false;
28
29
  this.enableTestMode = false;
29
30
  this.mode = mode;
@@ -44,14 +45,12 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
44
45
  if (container.mode === 'bank_account' && container.bankCountry === 'CA') {
45
46
  throw new Error('CardConnect does not support Canadian bank accounts');
46
47
  }
47
- const baseUrl = (_a = gateway.config) === null || _a === void 0 ? void 0 : _a.base_url;
48
- if (!baseUrl) {
49
- throw new Error('CardConnect base URL not configured');
50
- }
48
+ let baseUrl = ((_a = gateway.config) === null || _a === void 0 ? void 0 : _a.base_url) || config.clientConfig.cardConnectBaseUrl;
49
+ config.cardConnectBaseUrl = baseUrl;
51
50
  const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
52
51
  const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, container);
53
52
  const iframe = CardConnectTokenizer.createIframe(iframeUrl, mergedStyles);
54
- const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false);
53
+ const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false, container.layout || 'single-line');
55
54
  tokenizer.createInternalElements(container);
56
55
  yield tokenizer.init();
57
56
  return tokenizer;
@@ -64,7 +63,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
64
63
  }
65
64
  this.containerEl = containerEl;
66
65
  containerEl.innerHTML = '';
67
- const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
66
+ const mergedStyles = (0, styles_1.getContainerStylesForLayout)((0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling), this.layout);
68
67
  Object.assign(containerEl.style, mergedStyles.container);
69
68
  if (this.mode === 'bank_account') {
70
69
  this.createBankAccountFields(containerEl, mergedStyles);
@@ -75,34 +74,67 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
75
74
  }
76
75
  createCreditCardFields(containerEl, mergedStyles) {
77
76
  this.iframe.style.width = '100%';
78
- this.iframe.style.height = mergedStyles.input.height || '40px';
77
+ if (this.layout === 'two-line') {
78
+ const inputHeight = mergedStyles.input.height || '40px';
79
+ const rowGap = mergedStyles.container.rowGap || '1rem';
80
+ this.iframe.style.height = `calc((${inputHeight}) * 2 + ${rowGap})`;
81
+ }
82
+ else {
83
+ this.iframe.style.height = mergedStyles.input.height || '40px';
84
+ }
79
85
  this.iframe.style.border = 'none';
80
86
  this.iframe.style.display = 'block';
81
87
  containerEl.appendChild(this.iframe);
82
88
  }
83
89
  createBankAccountFields(containerEl, mergedStyles) {
84
90
  this.iframe.style.display = 'none';
85
- this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
86
- Object.assign(this.routingNumberEl.style, {
87
- flex: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.flex,
88
- minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
89
- });
90
- this.applyInputStyles(this.routingNumberEl, mergedStyles, 'left');
91
- containerEl.appendChild(this.routingNumberEl);
92
- this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
93
- Object.assign(this.accountNumberEl.style, {
94
- flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.flex,
95
- minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
96
- });
97
- this.applyInputStyles(this.accountNumberEl, mergedStyles, 'middle');
98
- containerEl.appendChild(this.accountNumberEl);
99
- this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
100
- Object.assign(this.accountTypeEl.style, {
101
- flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.flex,
102
- minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
103
- });
104
- this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
105
- containerEl.appendChild(this.accountTypeEl);
91
+ if (this.layout === 'two-line') {
92
+ this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
93
+ Object.assign(this.accountTypeEl.style, {
94
+ flex: '1',
95
+ minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
96
+ });
97
+ this.applyInputStyles(this.accountTypeEl, mergedStyles, 'left');
98
+ containerEl.appendChild(this.accountTypeEl);
99
+ this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
100
+ Object.assign(this.routingNumberEl.style, {
101
+ flex: '1',
102
+ minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
103
+ });
104
+ this.applyInputStyles(this.routingNumberEl, mergedStyles, 'right');
105
+ containerEl.appendChild(this.routingNumberEl);
106
+ this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
107
+ Object.assign(this.accountNumberEl.style, {
108
+ flex: '1',
109
+ flexBasis: '100%',
110
+ minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
111
+ });
112
+ this.applyInputStyles(this.accountNumberEl, mergedStyles);
113
+ containerEl.appendChild(this.accountNumberEl);
114
+ }
115
+ else {
116
+ this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
117
+ Object.assign(this.routingNumberEl.style, {
118
+ flex: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.flex,
119
+ minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
120
+ });
121
+ this.applyInputStyles(this.routingNumberEl, mergedStyles, 'left');
122
+ containerEl.appendChild(this.routingNumberEl);
123
+ this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
124
+ Object.assign(this.accountNumberEl.style, {
125
+ flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.flex,
126
+ minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
127
+ });
128
+ this.applyInputStyles(this.accountNumberEl, mergedStyles, 'middle');
129
+ containerEl.appendChild(this.accountNumberEl);
130
+ this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
131
+ Object.assign(this.accountTypeEl.style, {
132
+ flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.flex,
133
+ minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
134
+ });
135
+ this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
136
+ containerEl.appendChild(this.accountTypeEl);
137
+ }
106
138
  }
107
139
  init() {
108
140
  return __awaiter(this, void 0, void 0, function* () {
@@ -142,7 +174,6 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
142
174
  clearTimeout(timeout);
143
175
  this.isReady = true;
144
176
  if (this.enableTestMode && this.mode === 'credit_card') {
145
- console.log('CardConnect test mode enabled - manual entry required for card fields');
146
177
  }
147
178
  this.emit('ready');
148
179
  resolve();
@@ -159,6 +190,12 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
159
190
  if (!this.isReady) {
160
191
  throw new Error('Tokenizer not initialized');
161
192
  }
193
+ if (this.mode === 'credit_card' && this.hasToken()) {
194
+ const cachedToken = this.getToken();
195
+ if (cachedToken) {
196
+ return cachedToken;
197
+ }
198
+ }
162
199
  if (this.mode === 'bank_account' || this.isBankAccountData(paymentData)) {
163
200
  return this.tokenizeBankAccountInternal(paymentData);
164
201
  }
@@ -177,27 +214,25 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
177
214
  provider: 'cardconnect',
178
215
  };
179
216
  }
180
- return new Promise((resolve, reject) => {
217
+ if (this.tokenizationPromise) {
218
+ return this.tokenizationPromise;
219
+ }
220
+ this.tokenizationPromise = new Promise((resolve, reject) => {
221
+ this.tokenizationResolve = resolve;
222
+ this.tokenizationReject = reject;
181
223
  const timeout = setTimeout(() => {
224
+ this.tokenizationPromise = undefined;
225
+ this.tokenizationResolve = undefined;
226
+ this.tokenizationReject = undefined;
182
227
  reject(new types_1.TokenizationError('Tokenization timeout - ensure all card fields are filled in iframe', 'TIMEOUT'));
183
228
  }, tokenizer_constants_1.TOKENIZE_TIMEOUT);
184
229
  const tokenizationHandler = (data) => {
185
230
  clearTimeout(timeout);
186
231
  this.off('tokenization', tokenizationHandler);
187
- if (data.errorCode === '0') {
188
- resolve({
189
- token: data.token,
190
- lastFour: data.token.slice(-4),
191
- cardType: this.normalizeCardType('unknown'),
192
- provider: 'cardconnect',
193
- });
194
- }
195
- else {
196
- reject(new types_1.TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
197
- }
198
232
  };
199
233
  this.on('tokenization', tokenizationHandler);
200
234
  });
235
+ return this.tokenizationPromise;
201
236
  });
202
237
  }
203
238
  tokenizeBankAccountInternal(bankData) {
@@ -245,28 +280,64 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
245
280
  validateCardInternal() {
246
281
  return __awaiter(this, void 0, void 0, function* () {
247
282
  const errors = [];
248
- if (this.currentValidationState.cardNumber &&
249
- !this.currentValidationState.cardNumber.isValid &&
250
- !this.currentValidationState.cardNumber.isEmpty) {
283
+ if (this.currentValidationState.cardNumber) {
284
+ if (this.currentValidationState.cardNumber.isEmpty) {
285
+ errors.push({
286
+ field: 'cardNumber',
287
+ message: 'Card number is required',
288
+ });
289
+ }
290
+ else if (!this.currentValidationState.cardNumber.isValid) {
291
+ errors.push({
292
+ field: 'cardNumber',
293
+ message: 'Invalid card number',
294
+ });
295
+ }
296
+ }
297
+ else {
251
298
  errors.push({
252
299
  field: 'cardNumber',
253
- message: 'Invalid card number',
300
+ message: 'Card number is required',
254
301
  });
255
302
  }
256
- if (this.currentValidationState.expiry &&
257
- !this.currentValidationState.expiry.isValid &&
258
- !this.currentValidationState.expiry.isEmpty) {
303
+ if (this.currentValidationState.expiry) {
304
+ if (this.currentValidationState.expiry.isEmpty) {
305
+ errors.push({
306
+ field: 'expiry',
307
+ message: 'Expiry date is required',
308
+ });
309
+ }
310
+ else if (!this.currentValidationState.expiry.isValid) {
311
+ errors.push({
312
+ field: 'expiry',
313
+ message: 'Invalid expiry date',
314
+ });
315
+ }
316
+ }
317
+ else {
259
318
  errors.push({
260
319
  field: 'expiry',
261
- message: 'Invalid expiry date',
320
+ message: 'Expiry date is required',
262
321
  });
263
322
  }
264
- if (this.currentValidationState.cvv &&
265
- !this.currentValidationState.cvv.isValid &&
266
- !this.currentValidationState.cvv.isEmpty) {
323
+ if (this.currentValidationState.cvv) {
324
+ if (this.currentValidationState.cvv.isEmpty) {
325
+ errors.push({
326
+ field: 'cvv',
327
+ message: 'CVV is required',
328
+ });
329
+ }
330
+ else if (!this.currentValidationState.cvv.isValid) {
331
+ errors.push({
332
+ field: 'cvv',
333
+ message: 'Invalid CVV',
334
+ });
335
+ }
336
+ }
337
+ else {
267
338
  errors.push({
268
339
  field: 'cvv',
269
- message: 'Invalid CVV',
340
+ message: 'CVV is required',
270
341
  });
271
342
  }
272
343
  return {
@@ -369,12 +440,66 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
369
440
  }
370
441
  this.eventHandlers.clear();
371
442
  }
443
+ hasToken() {
444
+ var _a, _b;
445
+ if (this.mode === 'credit_card') {
446
+ return (((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0' &&
447
+ !!((_b = this.cachedTokenResult) === null || _b === void 0 ? void 0 : _b.token));
448
+ }
449
+ return false;
450
+ }
451
+ getToken() {
452
+ var _a;
453
+ if (this.mode === 'credit_card' &&
454
+ ((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0') {
455
+ return {
456
+ token: this.cachedTokenResult.token,
457
+ lastFour: this.cachedTokenResult.token.slice(-4),
458
+ cardType: this.normalizeCardType('unknown'),
459
+ provider: 'cardconnect',
460
+ };
461
+ }
462
+ return null;
463
+ }
464
+ get tokenizationMode() {
465
+ return this.mode === 'credit_card' ? 'auto' : 'manual';
466
+ }
372
467
  handleMessage(event) {
373
468
  try {
374
469
  const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
375
470
  if (data.token && data.errorCode !== undefined) {
376
471
  this.cachedTokenResult = data;
377
472
  this.emit('tokenization', data);
473
+ if (data.errorCode === '0') {
474
+ const token = {
475
+ token: data.token,
476
+ lastFour: data.token.slice(-4),
477
+ cardType: this.normalizeCardType('unknown'),
478
+ provider: 'cardconnect',
479
+ };
480
+ if (this.tokenizationResolve) {
481
+ this.tokenizationResolve(token);
482
+ this.tokenizationPromise = undefined;
483
+ this.tokenizationResolve = undefined;
484
+ this.tokenizationReject = undefined;
485
+ }
486
+ this.currentValidationState = {
487
+ isValid: true,
488
+ cardNumber: { isValid: true, isEmpty: false },
489
+ cvv: { isValid: true, isEmpty: false },
490
+ expiry: { isValid: true, isEmpty: false },
491
+ };
492
+ this.emit('validation', { isValid: true });
493
+ this.emit('tokenReady', token);
494
+ }
495
+ else {
496
+ if (this.tokenizationReject) {
497
+ this.tokenizationReject(new types_1.TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
498
+ this.tokenizationPromise = undefined;
499
+ this.tokenizationResolve = undefined;
500
+ this.tokenizationReject = undefined;
501
+ }
502
+ }
378
503
  }
379
504
  if (data.event === 'validation' || data.validationError !== undefined) {
380
505
  this.handleValidationMessage(data);
@@ -397,38 +522,23 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
397
522
  this.currentValidationState.cardNumber = {
398
523
  isValid: false,
399
524
  isEmpty: false,
400
- error: data.validationError,
401
525
  };
402
526
  }
403
527
  else if (errorLower.includes('cvv') ||
404
528
  errorLower.includes('security')) {
405
- this.currentValidationState.cvv = {
406
- isValid: false,
407
- isEmpty: false,
408
- error: data.validationError,
409
- };
529
+ this.currentValidationState.cvv = { isValid: false, isEmpty: false };
410
530
  }
411
531
  else if (errorLower.includes('expir') ||
412
- errorLower.includes('exp') ||
413
532
  errorLower.includes('month') ||
414
533
  errorLower.includes('year')) {
415
- this.currentValidationState.expiry = {
416
- isValid: false,
417
- isEmpty: false,
418
- error: data.validationError,
419
- };
534
+ this.currentValidationState.expiry = { isValid: false, isEmpty: false };
420
535
  }
421
- }
422
- else if (data.event === 'validation') {
536
+ this.emit('error', new types_1.TokenizationError(data.validationError));
423
537
  }
424
538
  this.currentValidationState.isValid =
425
539
  ((_b = (_a = this.currentValidationState.cardNumber) === null || _a === void 0 ? void 0 : _a.isValid) !== null && _b !== void 0 ? _b : false) &&
426
540
  ((_d = (_c = this.currentValidationState.cvv) === null || _c === void 0 ? void 0 : _c.isValid) !== null && _d !== void 0 ? _d : false) &&
427
541
  ((_f = (_e = this.currentValidationState.expiry) === null || _e === void 0 ? void 0 : _e.isValid) !== null && _f !== void 0 ? _f : false);
428
- this.emit('validation', this.currentValidationState);
429
- if (data.validationError) {
430
- this.emit('error', new types_1.TokenizationError(data.validationError));
431
- }
432
542
  }
433
543
  static generateIframeUrl(baseUrl, container) {
434
544
  const params = new URLSearchParams({
@@ -436,20 +546,28 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
436
546
  enhancedresponse: 'true',
437
547
  useexpiry: 'true',
438
548
  usecvv: 'true',
439
- orientation: 'horizontal',
440
549
  formatinput: 'true',
441
550
  unique: 'true',
442
551
  norsa: 'true',
443
552
  placeholder: 'Card Number *',
444
- placeholdermonth: 'MM',
445
- placeholderyear: 'YYYY',
446
553
  placeholdercvv: 'CVV',
447
554
  invalidcreditcardevent: 'true',
448
555
  invalidexpiry: 'true',
449
556
  invalidcvv: 'true',
450
557
  });
558
+ if (container.layout === 'two-line') {
559
+ params.set('useexpiryfield', 'true');
560
+ params.set('orientation', 'horizontal');
561
+ params.set('placeholdermonth', 'MM');
562
+ params.set('placeholderyear', 'YYYY');
563
+ }
564
+ else {
565
+ params.set('orientation', 'horizontal');
566
+ params.set('placeholdermonth', 'MM');
567
+ params.set('placeholderyear', 'YYYY');
568
+ }
451
569
  const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
452
- const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles);
570
+ const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, container.layout || 'single-line');
453
571
  const queryPairs = [];
454
572
  params.forEach((value, key) => {
455
573
  queryPairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
@@ -482,13 +600,20 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
482
600
  iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms');
483
601
  return iframe;
484
602
  }
485
- static generateCardConnectCss(styles) {
486
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
603
+ static generateCardConnectCss(styles, layout = 'single-line') {
604
+ var _a, _b, _c;
487
605
  const css = [];
488
- css.push('body{margin:0;padding:0;display:flex;align-items:center;}');
489
- css.push('form{margin:0;padding:0;display:flex;width:100%;align-items:center;}');
490
- css.push('label{display:none;}');
491
- css.push('br{display:none;}');
606
+ if (layout === 'two-line') {
607
+ css.push('html,form,body{margin:0;padding:0;}');
608
+ css.push('label{display:none;}');
609
+ css.push('br{display:none;}');
610
+ }
611
+ else {
612
+ css.push('body{margin:0;padding:0;display:flex;align-items:center;}');
613
+ css.push('form{margin:0;padding:0;display:flex;width:100%;align-items:center;}');
614
+ css.push('label{display:none;}');
615
+ css.push('br{display:none;}');
616
+ }
492
617
  const isConnected = styles.container.gap === '0';
493
618
  const gap = isConnected ? '0' : styles.container.gap || '1rem';
494
619
  if (styles.input) {
@@ -512,73 +637,41 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
512
637
  css.push(`input{${baseStyles};}`);
513
638
  css.push(`select{${baseStyles};}`);
514
639
  }
515
- if (isConnected) {
516
- const cardNumStyles = ['width:60%', 'margin:0'];
640
+ if (layout === 'two-line') {
641
+ css.push('input#ccnumfield{width:100%;display:block;margin-bottom:8px;}');
642
+ css.push('input#ccexpiryfieldmonth{width:20%;}');
643
+ css.push('input#ccexpiryfieldyear{width:24%;}');
644
+ css.push('input#cccvvfield{width:calc(56% - 20px);}');
517
645
  if ((_a = styles.input) === null || _a === void 0 ? void 0 : _a.borderRadius) {
518
- cardNumStyles.push(`border-radius:${styles.input.borderRadius} 0 0 ${styles.input.borderRadius}`);
519
- }
520
- cardNumStyles.push('border-right:none');
521
- css.push(`input#ccnumfield{${cardNumStyles.join(';')};}`);
522
- const monthStyles = [
523
- 'width:10%',
524
- 'margin:0',
525
- 'margin-right:-12px',
526
- 'border-radius:0',
527
- `border-left:${((_b = styles.input) === null || _b === void 0 ? void 0 : _b.border) || '1px solid #ccc'}`,
528
- 'border-right:none',
529
- ];
530
- css.push(`select#ccexpirymonth{${monthStyles.join(';')};}`);
531
- const yearStyles = [
532
- 'width:10%',
533
- 'border-radius:0',
534
- `border-left:${((_c = styles.input) === null || _c === void 0 ? void 0 : _c.border) || '1px solid #ccc'}`,
535
- 'border-right:none',
536
- ];
537
- css.push(`select#ccexpiryyear{${yearStyles.join(';')};}`);
538
- const cvvStyles = [
539
- 'width:20%',
540
- 'margin:0',
541
- 'margin-left:-12px',
542
- ];
543
- if ((_d = styles.input) === null || _d === void 0 ? void 0 : _d.borderRadius) {
544
- cvvStyles.push(`border-radius:0 ${styles.input.borderRadius} ${styles.input.borderRadius} 0`);
545
- }
546
- cvvStyles.push(`border-left:${((_e = styles.input) === null || _e === void 0 ? void 0 : _e.border) || '1px solid #ccc'}`);
547
- css.push(`input#cccvvfield{${cvvStyles.join(';')};}`);
646
+ css.push(`input{border-radius:${styles.input.borderRadius};}`);
647
+ }
648
+ }
649
+ else if (isConnected) {
650
+ css.push('input#ccnumfield{width:60%;margin:0;}');
651
+ css.push('select#ccexpirymonth{width:10%;margin:0;margin-right:-12px;}');
652
+ css.push('select#ccexpiryyear{width:10%;}');
653
+ css.push('input#cccvvfield{width:20%;margin:0;margin-left:-12px;}');
654
+ if ((_b = styles.input) === null || _b === void 0 ? void 0 : _b.borderRadius) {
655
+ css.push(`input#ccnumfield{border-radius:${styles.input.borderRadius} 0 0 ${styles.input.borderRadius};border-right:none;}`);
656
+ css.push('select#ccexpirymonth{border-radius:0;border-right:none;}');
657
+ css.push('select#ccexpiryyear{border-radius:0;border-right:none;}');
658
+ css.push(`input#cccvvfield{border-radius:0 ${styles.input.borderRadius} ${styles.input.borderRadius} 0;}`);
659
+ }
660
+ else {
661
+ css.push('input#ccnumfield{border-right:none;}');
662
+ css.push('select#ccexpirymonth{border-right:none;}');
663
+ css.push('select#ccexpiryyear{border-right:none;}');
664
+ }
548
665
  }
549
666
  else {
550
- const gapValue = gap.replace(/[^\d.]/g, '');
551
- const gapUnit = gap.replace(/[\d.]/g, '');
552
- const halfGapValue = parseFloat(gapValue) / 2;
553
- const cardNumStyles = [
554
- `width:calc(60% - ${gapValue}${gapUnit})`,
555
- `margin-right:${gap}`,
556
- ];
557
- if ((_f = styles.input) === null || _f === void 0 ? void 0 : _f.borderRadius) {
558
- cardNumStyles.push(`border-radius:${styles.input.borderRadius}`);
559
- }
560
- css.push(`input#ccnumfield{${cardNumStyles.join(';')};}`);
561
- const monthStyles = [
562
- `width:calc(10% - ${halfGapValue}${gapUnit})`,
563
- `margin-right:calc(${gap} / 2)`,
564
- ];
565
- if ((_g = styles.input) === null || _g === void 0 ? void 0 : _g.borderRadius) {
566
- monthStyles.push(`border-radius:${styles.input.borderRadius}`);
567
- }
568
- css.push(`select#ccexpirymonth{${monthStyles.join(';')};}`);
569
- const yearStyles = [
570
- `width:calc(10% - ${halfGapValue}${gapUnit})`,
571
- `margin-right:${gap}`,
572
- ];
573
- if ((_h = styles.input) === null || _h === void 0 ? void 0 : _h.borderRadius) {
574
- yearStyles.push(`border-radius:${styles.input.borderRadius}`);
575
- }
576
- css.push(`select#ccexpiryyear{${yearStyles.join(';')};}`);
577
- const cvvStyles = ['width:20%'];
578
- if ((_j = styles.input) === null || _j === void 0 ? void 0 : _j.borderRadius) {
579
- cvvStyles.push(`border-radius:${styles.input.borderRadius}`);
580
- }
581
- css.push(`input#cccvvfield{${cvvStyles.join(';')};}`);
667
+ const marginRight = gap === '0' ? '0' : '8px';
668
+ css.push(`input#ccnumfield{width:60%;margin-right:${marginRight};}`);
669
+ css.push(`select#ccexpirymonth{width:10%;margin-right:${marginRight};}`);
670
+ css.push(`select#ccexpiryyear{width:10%;margin-right:${marginRight};}`);
671
+ css.push('input#cccvvfield{width:20%;}');
672
+ if ((_c = styles.input) === null || _c === void 0 ? void 0 : _c.borderRadius) {
673
+ css.push(`input,select{border-radius:${styles.input.borderRadius};}`);
674
+ }
582
675
  }
583
676
  if (styles.focus) {
584
677
  const focusStyles = [];