@idonatedev/idonate-sdk 1.2.0-dev15 → 1.2.0-dev17

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.
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-dev15';
4
+ exports.SDK_VERSION = '1.2.0-dev17';
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-dev15';
1
+ export const SDK_VERSION = '1.2.0-dev17';
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,6 +16,7 @@ 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?;
@@ -19,6 +19,7 @@ export class CardConnectTokenizer extends Tokenizer {
19
19
  this.containerId = containerId;
20
20
  this.layout = layout;
21
21
  this.enableTestMode = false;
22
+ this.acceptAutoToken = true;
22
23
  this.mode = mode;
23
24
  this.enableTestMode = enableTestMode;
24
25
  this.iframe = iframe;
@@ -268,10 +269,15 @@ export class CardConnectTokenizer extends Tokenizer {
268
269
  return __awaiter(this, void 0, void 0, function* () {
269
270
  var _a, _b, _c;
270
271
  if (this.cachedTokenResult && this.cachedTokenResult.errorCode === '0') {
272
+ const cardType = this.cachedTokenResult.cardType
273
+ ? this.normalizeCardType(this.cachedTokenResult.cardType)
274
+ : this.normalizeCardType('unknown');
271
275
  return {
272
276
  token: this.cachedTokenResult.token,
273
- lastFour: this.cachedTokenResult.token.slice(-4),
274
- cardType: this.normalizeCardType('unknown'),
277
+ lastFour: this.cachedTokenResult.last4 ||
278
+ this.cachedTokenResult.token.slice(-4),
279
+ cardType,
280
+ paymentMethodType: 'credit_card',
275
281
  provider: 'cardconnect',
276
282
  };
277
283
  }
@@ -316,13 +322,15 @@ export class CardConnectTokenizer extends Tokenizer {
316
322
  }
317
323
  const baseUrl = new URL(this.iframeUrl).origin;
318
324
  const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, baseUrl);
319
- return {
325
+ const paymentToken = {
320
326
  token: result.token,
321
327
  lastFour: accountNumber.slice(-4),
322
328
  accountType: accountType,
323
329
  paymentMethodType: 'bank_account',
324
330
  provider: 'cardconnect',
325
331
  };
332
+ this.emit('tokenReady', paymentToken);
333
+ return paymentToken;
326
334
  });
327
335
  }
328
336
  validate() {
@@ -460,9 +468,23 @@ export class CardConnectTokenizer extends Tokenizer {
460
468
  }, this.expectedOrigin);
461
469
  }
462
470
  this.cachedTokenResult = undefined;
463
- this.tokenizationPromise = undefined;
464
- this.tokenizationResolve = undefined;
465
- this.tokenizationReject = 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
+ }
466
488
  if (this.mode === 'bank_account') {
467
489
  this.currentValidationState = {
468
490
  isValid: false,
@@ -506,6 +528,7 @@ export class CardConnectTokenizer extends Tokenizer {
506
528
  }
507
529
  }
508
530
  destroy() {
531
+ this.markDestroyed();
509
532
  if (this.tokenizationTimeout) {
510
533
  clearTimeout(this.tokenizationTimeout);
511
534
  this.tokenizationTimeout = undefined;
@@ -547,6 +570,7 @@ export class CardConnectTokenizer extends Tokenizer {
547
570
  lastFour: this.cachedTokenResult.last4 ||
548
571
  this.cachedTokenResult.token.slice(-4),
549
572
  cardType,
573
+ paymentMethodType: 'credit_card',
550
574
  provider: 'cardconnect',
551
575
  };
552
576
  }
@@ -559,6 +583,9 @@ export class CardConnectTokenizer extends Tokenizer {
559
583
  try {
560
584
  const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
561
585
  if (data.token && data.errorCode !== undefined) {
586
+ if (!this.acceptAutoToken && !this.tokenizationResolve) {
587
+ return;
588
+ }
562
589
  this.cachedTokenResult = data;
563
590
  if (this.tokenizationTimeout) {
564
591
  clearTimeout(this.tokenizationTimeout);
@@ -576,6 +603,7 @@ export class CardConnectTokenizer extends Tokenizer {
576
603
  token: data.token,
577
604
  lastFour: data.last4 || data.token.slice(-4),
578
605
  cardType,
606
+ paymentMethodType: 'credit_card',
579
607
  provider: 'cardconnect',
580
608
  };
581
609
  if (this.tokenizationResolve) {
@@ -605,10 +633,12 @@ export class CardConnectTokenizer extends Tokenizer {
605
633
  }
606
634
  }
607
635
  if (data.event === 'validation' || data.validationError !== undefined) {
636
+ this.acceptAutoToken = true;
608
637
  this.handleValidationMessage(data);
609
638
  }
610
639
  if ((data.event === 'input' || data.event === 'change') &&
611
640
  data.cardType) {
641
+ this.acceptAutoToken = true;
612
642
  const cardType = this.normalizeCardType(data.cardType);
613
643
  if (cardType !== this.currentCardType) {
614
644
  this.currentCardType = cardType;
@@ -235,6 +235,7 @@ export class PayPalTokenizer extends Tokenizer {
235
235
  const token = {
236
236
  token: data.orderID,
237
237
  lastFour: data.orderID.slice(-4),
238
+ paymentMethodType: 'paypal',
238
239
  provider: 'paypal_checkout',
239
240
  paymentMethodId: this.paymentMethodId,
240
241
  paymentTransactionId: this.paymentTransactionId,
@@ -280,6 +281,7 @@ export class PayPalTokenizer extends Tokenizer {
280
281
  focus(field) {
281
282
  }
282
283
  destroy() {
284
+ this.markDestroyed();
283
285
  if (this.buttonsInstance) {
284
286
  try {
285
287
  this.buttonsInstance.close();
@@ -42,6 +42,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
42
42
  private init;
43
43
  tokenize(paymentData: PaymentData): Promise<PaymentToken>;
44
44
  private tokenizeCardInternal;
45
+ private executeCardTokenization;
45
46
  private createCanadianBankAccountFields;
46
47
  private tokenizeBankAccountInternal;
47
48
  validate(): Promise<ValidationResult>;
@@ -163,6 +163,7 @@ export class SpreedlyTokenizer extends Tokenizer {
163
163
  token,
164
164
  lastFour: pmData.last_four_digits,
165
165
  cardType: this.normalizeCardType(pmData.card_type),
166
+ paymentMethodType: 'credit_card',
166
167
  provider: 'spreedly',
167
168
  };
168
169
  if (this.tokenizationResolve) {
@@ -173,13 +174,12 @@ export class SpreedlyTokenizer extends Tokenizer {
173
174
  }
174
175
  });
175
176
  this.spreedly.on('errors', (errors) => {
177
+ const error = new TokenizationError(errors);
178
+ this.emit('error', error);
176
179
  if (this.tokenizationReject) {
177
180
  const rejectTokenization = this.tokenizationReject;
178
181
  this.clearTokenizationState();
179
- rejectTokenization(new TokenizationError(errors));
180
- }
181
- else {
182
- this.emit('error', new TokenizationError(errors));
182
+ rejectTokenization(error);
183
183
  }
184
184
  });
185
185
  this.spreedly.on('fieldEvent', (fieldName, eventType, activeEl, inputProperties) => {
@@ -206,15 +206,21 @@ export class SpreedlyTokenizer extends Tokenizer {
206
206
  });
207
207
  }
208
208
  tokenizeCardInternal(cardData) {
209
+ if (this.tokenizationPromise) {
210
+ return this.tokenizationPromise;
211
+ }
212
+ const expiry = this.parseExpiry(this.expiryEl);
213
+ if (!expiry) {
214
+ return Promise.reject(new TokenizationError('Expiration date is required', 'VALIDATION_ERROR'));
215
+ }
216
+ this.tokenizationPromise = this.executeCardTokenization(cardData, expiry).finally(() => {
217
+ this.tokenizationPromise = undefined;
218
+ });
219
+ return this.tokenizationPromise;
220
+ }
221
+ executeCardTokenization(cardData, expiry) {
209
222
  return __awaiter(this, void 0, void 0, function* () {
210
223
  var _a;
211
- if (this.tokenizationPromise) {
212
- return this.tokenizationPromise;
213
- }
214
- const expiry = this.parseExpiry(this.expiryEl);
215
- if (!expiry) {
216
- throw new TokenizationError('Expiration date is required', 'VALIDATION_ERROR');
217
- }
218
224
  let securityFields = {};
219
225
  if ((_a = this.clientConfig) === null || _a === void 0 ? void 0 : _a.enableSpreedlySecureTokenization) {
220
226
  try {
@@ -222,7 +228,7 @@ export class SpreedlyTokenizer extends Tokenizer {
222
228
  securityFields = {
223
229
  nonce: args.nonce,
224
230
  timestamp: args.timestamp,
225
- certificate_token: args.certificate_token,
231
+ certificateToken: args.certificate_token,
226
232
  signature: args.signature,
227
233
  };
228
234
  }
@@ -230,7 +236,7 @@ export class SpreedlyTokenizer extends Tokenizer {
230
236
  throw new TokenizationError(`Secure tokenization failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'SECURE_TOKENIZATION_ERROR');
231
237
  }
232
238
  }
233
- this.tokenizationPromise = new Promise((resolve, reject) => {
239
+ return new Promise((resolve, reject) => {
234
240
  var _a, _b, _c, _d, _e, _f;
235
241
  this.tokenizationResolve = resolve;
236
242
  this.tokenizationReject = reject;
@@ -239,10 +245,7 @@ export class SpreedlyTokenizer extends Tokenizer {
239
245
  reject(new TokenizationError('Tokenization timeout', 'TIMEOUT'));
240
246
  }, TOKENIZE_TIMEOUT);
241
247
  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));
242
- }).finally(() => {
243
- this.tokenizationPromise = undefined;
244
248
  });
245
- return this.tokenizationPromise;
246
249
  });
247
250
  }
248
251
  createCanadianBankAccountFields(container) {
@@ -434,13 +437,15 @@ export class SpreedlyTokenizer extends Tokenizer {
434
437
  accountHolderType: accountHolderType,
435
438
  },
436
439
  }, this.clientConfig, this.environmentKey);
437
- return {
440
+ const paymentToken = {
438
441
  token: result,
439
442
  lastFour: accountNumber.slice(-4),
440
443
  accountType: accountType,
441
444
  paymentMethodType: 'bank_account',
442
445
  provider: 'spreedly',
443
446
  };
447
+ this.emit('tokenReady', paymentToken);
448
+ return paymentToken;
444
449
  });
445
450
  }
446
451
  validate() {
@@ -653,7 +658,14 @@ export class SpreedlyTokenizer extends Tokenizer {
653
658
  expiry: { isValid: false, isEmpty: true },
654
659
  };
655
660
  }
656
- this.clearTokenizationState();
661
+ if (this.tokenizationReject) {
662
+ const reject = this.tokenizationReject;
663
+ this.clearTokenizationState();
664
+ reject(new TokenizationError('Tokenizer cleared', 'CLEARED'));
665
+ }
666
+ else {
667
+ this.clearTokenizationState();
668
+ }
657
669
  this.emit('validation', this.currentValidationState);
658
670
  }
659
671
  focus(field) {
@@ -755,6 +767,7 @@ export class SpreedlyTokenizer extends Tokenizer {
755
767
  }
756
768
  destroy() {
757
769
  var _a;
770
+ this.markDestroyed();
758
771
  (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
759
772
  if (this.tokenizationReject) {
760
773
  const reject = this.tokenizationReject;
@@ -1069,13 +1082,14 @@ export class SpreedlyTokenizer extends Tokenizer {
1069
1082
  }
1070
1083
  else {
1071
1084
  const now = new Date();
1072
- const expiryDate = new Date(year, month - 1);
1073
- if (expiryDate < now) {
1085
+ const expiryEndDate = new Date(year, month);
1086
+ if (expiryEndDate <= now) {
1074
1087
  this.applyErrorStyles(this.expiryEl);
1075
1088
  }
1076
1089
  else {
1077
1090
  isValid = true;
1078
- this.applyInputStyles(this.expiryEl, this.mergedStyles, 'middle');
1091
+ const expiryPosition = this.effectiveLayout === 'two-line' ? 'left' : 'middle';
1092
+ this.applyInputStyles(this.expiryEl, this.mergedStyles, expiryPosition);
1079
1093
  }
1080
1094
  }
1081
1095
  }
@@ -3,8 +3,12 @@ import ConfigHandler from '../config-handler';
3
3
  export declare abstract class Tokenizer {
4
4
  protected mode: PaymentMethodMode;
5
5
  protected eventHandlers: Map<string, Set<(data?: any) => void>>;
6
+ private focusHandlerElements;
6
7
  private _isReady;
8
+ private _isDestroyed;
7
9
  get isReady(): boolean;
10
+ get isDestroyed(): boolean;
11
+ protected markDestroyed(): void;
8
12
  abstract tokenize(paymentData: PaymentData): Promise<PaymentToken>;
9
13
  abstract validate(): Promise<ValidationResult>;
10
14
  abstract clear(): void;
@@ -16,7 +20,7 @@ export declare abstract class Tokenizer {
16
20
  getMode(): PaymentMethodMode;
17
21
  on(event: TokenizerEvent, handler: (data?: any) => void): void;
18
22
  off(event: TokenizerEvent, handler: (data?: any) => void): void;
19
- protected emit(event: string, data?: any): void;
23
+ protected emit(event: TokenizerEvent, data?: any): void;
20
24
  protected isCardData(data: PaymentData): data is CardData;
21
25
  protected isBankAccountData(data: PaymentData): data is BankAccountData;
22
26
  protected normalizeCardType(providerCardType: string): CardType;
@@ -13,10 +13,18 @@ export class Tokenizer {
13
13
  constructor() {
14
14
  this.mode = 'credit_card';
15
15
  this.eventHandlers = new Map();
16
+ this.focusHandlerElements = new WeakSet();
16
17
  this._isReady = false;
18
+ this._isDestroyed = false;
17
19
  }
18
20
  get isReady() {
19
- return this._isReady;
21
+ return this._isReady && !this._isDestroyed;
22
+ }
23
+ get isDestroyed() {
24
+ return this._isDestroyed;
25
+ }
26
+ markDestroyed() {
27
+ this._isDestroyed = true;
20
28
  }
21
29
  getMode() {
22
30
  return this.mode;
@@ -132,7 +140,10 @@ export class Tokenizer {
132
140
  element.style.border = inputStyles.border;
133
141
  element.style.borderRadius = inputStyles.borderRadius;
134
142
  }
135
- addFocusHandlers(element, styles);
143
+ if (!this.focusHandlerElements.has(element)) {
144
+ addFocusHandlers(element, styles, position);
145
+ this.focusHandlerElements.add(element);
146
+ }
136
147
  }
137
148
  generateFieldIds(containerId) {
138
149
  return {
@@ -3,6 +3,6 @@ export { Tokenizer } from './Tokenizer';
3
3
  export { SpreedlyTokenizer } from './SpreedlyTokenizer';
4
4
  export { CardConnectTokenizer } from './CardConnectTokenizer';
5
5
  export { PayPalTokenizer, PayPalCreateOrderData } from './PayPalTokenizer';
6
- export { PaymentMethodType, PaymentMethodMode, PaymentGateway, TokenizerContainer, TokenizerStyling, CardData, BankAccountData, PaymentData, PaymentToken, CardType, TokenizerEvent, ValidationState, ValidationResult, ValidationError, TokenizationError, } from './types';
6
+ export { BackendName, PaymentMethodType, PaymentMethodMode, PaymentGateway, TokenizerContainer, TokenizerStyling, CardData, BankAccountData, PaymentData, PaymentToken, CardType, TokenizerEvent, ValidationState, ValidationResult, ValidationError, TokenizationError, } from './types';
7
7
  export { normalizeGateway } from './gateway-utils';
8
8
  export { iats };
@@ -13,6 +13,7 @@ export function fetchSpreedlySecurityArgs(config, organizationId, embedId) {
13
13
  throw new Error('Secure tokenization is not enabled');
14
14
  }
15
15
  const makeRequest = () => __awaiter(this, void 0, void 0, function* () {
16
+ var _a;
16
17
  const response = yield fetch(`${config.embedApiBaseUrl}/spreedly/security-args`, {
17
18
  method: 'POST',
18
19
  headers: { 'Content-Type': 'application/json' },
@@ -24,7 +25,8 @@ export function fetchSpreedlySecurityArgs(config, organizationId, embedId) {
24
25
  if (!response.ok) {
25
26
  throw new Error(`Security args request failed: ${response.status}`);
26
27
  }
27
- return response.json();
28
+ const data = yield response.json();
29
+ return (_a = data.result) !== null && _a !== void 0 ? _a : data;
28
30
  });
29
31
  try {
30
32
  return yield makeRequest();
@@ -6,7 +6,7 @@ export declare function parseExpiryDate(value: string): {
6
6
  export declare function formatExpiryInput(value: string): string;
7
7
  export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, errorMessage: string): Promise<T>;
8
8
  export declare function getConnectedBorderRadius(baseRadius: string, position: 'left' | 'middle' | 'right', isConnected: boolean): string;
9
- export declare function addFocusHandlers(element: HTMLElement, styles: TokenizerStylingComplete, onFocus?: () => void, onBlur?: () => void): void;
9
+ export declare function addFocusHandlers(element: HTMLElement, styles: TokenizerStylingComplete, position?: 'left' | 'middle' | 'right', onFocus?: () => void, onBlur?: () => void): void;
10
10
  export declare function createFieldContainer(id: string, flex: string, minWidth?: string, maxWidth?: string): HTMLDivElement;
11
11
  export declare function createInputElement(id: string, type: string, placeholder: string, maxLength?: number): HTMLInputElement;
12
12
  export declare function validateRoutingNumber(routingNumber: string): boolean;
@@ -39,7 +39,7 @@ export function getConnectedBorderRadius(baseRadius, position, isConnected) {
39
39
  return baseRadius;
40
40
  }
41
41
  }
42
- export function addFocusHandlers(element, styles, onFocus, onBlur) {
42
+ export function addFocusHandlers(element, styles, position, onFocus, onBlur) {
43
43
  element.addEventListener('focus', () => {
44
44
  if (styles.focus) {
45
45
  Object.assign(element.style, styles.focus);
@@ -47,7 +47,28 @@ export function addFocusHandlers(element, styles, onFocus, onBlur) {
47
47
  onFocus === null || onFocus === void 0 ? void 0 : onFocus();
48
48
  });
49
49
  element.addEventListener('blur', () => {
50
- element.style.border = styles.input.border;
50
+ const isConnected = styles.container.gap === '0';
51
+ if (isConnected && position) {
52
+ element.style.borderTop = styles.input.border;
53
+ element.style.borderBottom = styles.input.border;
54
+ switch (position) {
55
+ case 'left':
56
+ element.style.borderLeft = styles.input.border;
57
+ element.style.borderRight = 'none';
58
+ break;
59
+ case 'middle':
60
+ element.style.borderLeft = styles.input.border;
61
+ element.style.borderRight = 'none';
62
+ break;
63
+ case 'right':
64
+ element.style.borderLeft = styles.input.border;
65
+ element.style.borderRight = styles.input.border;
66
+ break;
67
+ }
68
+ }
69
+ else {
70
+ element.style.border = styles.input.border;
71
+ }
51
72
  element.style.outline = '';
52
73
  element.style.boxShadow = '';
53
74
  onBlur === null || onBlur === void 0 ? void 0 : onBlur();
@@ -1,8 +1,9 @@
1
1
  export type PaymentMethodType = 'credit_card' | 'bank_account' | 'paypal' | 'apple_pay' | 'google_pay';
2
2
  export type PaymentMethodMode = 'credit_card' | 'bank_account' | 'paypal';
3
+ export type BackendName = 'spreedly' | 'card_connect' | 'iats' | 'paypal_checkout';
3
4
  export interface PaymentGateway {
4
5
  id: string;
5
- backendName: string;
6
+ backendName: BackendName;
6
7
  gatewayType?: string;
7
8
  name: string;
8
9
  config?: {
@@ -102,16 +102,18 @@ export function buildCashPaymentPayload(organizationId, input) {
102
102
  utmFields.utm_term = input.utm.term;
103
103
  }
104
104
  }
105
+ let remainingMeta = input.customerMeta
106
+ ? Object.assign({}, input.customerMeta) : {};
105
107
  if (input.customerMeta) {
106
108
  [1, 2, 3, 4, 5].forEach((customNoteIndex) => {
107
109
  const key = `custom_note_${customNoteIndex}`;
108
- if (input.customerMeta[key]) {
109
- donationOptions[key] = input.customerMeta[key];
110
- delete input.customerMeta[key];
110
+ if (remainingMeta[key]) {
111
+ donationOptions[key] = remainingMeta[key];
112
+ delete remainingMeta[key];
111
113
  }
112
114
  });
113
115
  }
114
- return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, donationOptions), billingAddress), billingContact), payment), utmFields), { customer_meta: input.customerMeta || {}, recaptcha_token: input.recaptchaToken, recaptcha_type: input.recaptchaType });
116
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, donationOptions), billingAddress), billingContact), payment), utmFields), { customer_meta: remainingMeta, recaptcha_token: input.recaptchaToken, recaptcha_type: input.recaptchaType });
115
117
  }
116
118
  export function buildDonationResult(response) {
117
119
  let campaign;
@@ -16,6 +16,7 @@ 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,6 +22,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
22
22
  this.containerId = containerId;
23
23
  this.layout = layout;
24
24
  this.enableTestMode = false;
25
+ this.acceptAutoToken = true;
25
26
  this.mode = mode;
26
27
  this.enableTestMode = enableTestMode;
27
28
  this.iframe = iframe;
@@ -271,10 +272,15 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
271
272
  return __awaiter(this, void 0, void 0, function* () {
272
273
  var _a, _b, _c;
273
274
  if (this.cachedTokenResult && this.cachedTokenResult.errorCode === '0') {
275
+ const cardType = this.cachedTokenResult.cardType
276
+ ? this.normalizeCardType(this.cachedTokenResult.cardType)
277
+ : this.normalizeCardType('unknown');
274
278
  return {
275
279
  token: this.cachedTokenResult.token,
276
- lastFour: this.cachedTokenResult.token.slice(-4),
277
- cardType: this.normalizeCardType('unknown'),
280
+ lastFour: this.cachedTokenResult.last4 ||
281
+ this.cachedTokenResult.token.slice(-4),
282
+ cardType,
283
+ paymentMethodType: 'credit_card',
278
284
  provider: 'cardconnect',
279
285
  };
280
286
  }
@@ -319,13 +325,15 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
319
325
  }
320
326
  const baseUrl = new URL(this.iframeUrl).origin;
321
327
  const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, baseUrl);
322
- return {
328
+ const paymentToken = {
323
329
  token: result.token,
324
330
  lastFour: accountNumber.slice(-4),
325
331
  accountType: accountType,
326
332
  paymentMethodType: 'bank_account',
327
333
  provider: 'cardconnect',
328
334
  };
335
+ this.emit('tokenReady', paymentToken);
336
+ return paymentToken;
329
337
  });
330
338
  }
331
339
  validate() {
@@ -463,9 +471,23 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
463
471
  }, this.expectedOrigin);
464
472
  }
465
473
  this.cachedTokenResult = undefined;
466
- this.tokenizationPromise = undefined;
467
- this.tokenizationResolve = undefined;
468
- this.tokenizationReject = undefined;
474
+ this.acceptAutoToken = false;
475
+ if (this.tokenizationTimeout) {
476
+ clearTimeout(this.tokenizationTimeout);
477
+ this.tokenizationTimeout = undefined;
478
+ }
479
+ if (this.tokenizationReject) {
480
+ const reject = this.tokenizationReject;
481
+ this.tokenizationPromise = undefined;
482
+ this.tokenizationResolve = undefined;
483
+ this.tokenizationReject = undefined;
484
+ reject(new types_1.TokenizationError('Tokenizer cleared', 'CLEARED'));
485
+ }
486
+ else {
487
+ this.tokenizationPromise = undefined;
488
+ this.tokenizationResolve = undefined;
489
+ this.tokenizationReject = undefined;
490
+ }
469
491
  if (this.mode === 'bank_account') {
470
492
  this.currentValidationState = {
471
493
  isValid: false,
@@ -509,6 +531,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
509
531
  }
510
532
  }
511
533
  destroy() {
534
+ this.markDestroyed();
512
535
  if (this.tokenizationTimeout) {
513
536
  clearTimeout(this.tokenizationTimeout);
514
537
  this.tokenizationTimeout = undefined;
@@ -550,6 +573,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
550
573
  lastFour: this.cachedTokenResult.last4 ||
551
574
  this.cachedTokenResult.token.slice(-4),
552
575
  cardType,
576
+ paymentMethodType: 'credit_card',
553
577
  provider: 'cardconnect',
554
578
  };
555
579
  }
@@ -562,6 +586,9 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
562
586
  try {
563
587
  const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
564
588
  if (data.token && data.errorCode !== undefined) {
589
+ if (!this.acceptAutoToken && !this.tokenizationResolve) {
590
+ return;
591
+ }
565
592
  this.cachedTokenResult = data;
566
593
  if (this.tokenizationTimeout) {
567
594
  clearTimeout(this.tokenizationTimeout);
@@ -579,6 +606,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
579
606
  token: data.token,
580
607
  lastFour: data.last4 || data.token.slice(-4),
581
608
  cardType,
609
+ paymentMethodType: 'credit_card',
582
610
  provider: 'cardconnect',
583
611
  };
584
612
  if (this.tokenizationResolve) {
@@ -608,10 +636,12 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
608
636
  }
609
637
  }
610
638
  if (data.event === 'validation' || data.validationError !== undefined) {
639
+ this.acceptAutoToken = true;
611
640
  this.handleValidationMessage(data);
612
641
  }
613
642
  if ((data.event === 'input' || data.event === 'change') &&
614
643
  data.cardType) {
644
+ this.acceptAutoToken = true;
615
645
  const cardType = this.normalizeCardType(data.cardType);
616
646
  if (cardType !== this.currentCardType) {
617
647
  this.currentCardType = cardType;
@@ -238,6 +238,7 @@ class PayPalTokenizer extends Tokenizer_1.Tokenizer {
238
238
  const token = {
239
239
  token: data.orderID,
240
240
  lastFour: data.orderID.slice(-4),
241
+ paymentMethodType: 'paypal',
241
242
  provider: 'paypal_checkout',
242
243
  paymentMethodId: this.paymentMethodId,
243
244
  paymentTransactionId: this.paymentTransactionId,
@@ -283,6 +284,7 @@ class PayPalTokenizer extends Tokenizer_1.Tokenizer {
283
284
  focus(field) {
284
285
  }
285
286
  destroy() {
287
+ this.markDestroyed();
286
288
  if (this.buttonsInstance) {
287
289
  try {
288
290
  this.buttonsInstance.close();
@@ -42,6 +42,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
42
42
  private init;
43
43
  tokenize(paymentData: PaymentData): Promise<PaymentToken>;
44
44
  private tokenizeCardInternal;
45
+ private executeCardTokenization;
45
46
  private createCanadianBankAccountFields;
46
47
  private tokenizeBankAccountInternal;
47
48
  validate(): Promise<ValidationResult>;