@idonatedev/idonate-sdk 1.2.0-dev0 → 1.2.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.
Files changed (36) hide show
  1. package/dist/constants.js +11 -2
  2. package/dist/esm/constants.js +11 -2
  3. package/dist/esm/recaptcha.d.ts +1 -0
  4. package/dist/esm/recaptcha.js +17 -0
  5. package/dist/esm/tokenize/CardConnectTokenizer.d.ts +1 -1
  6. package/dist/esm/tokenize/CardConnectTokenizer.js +71 -28
  7. package/dist/esm/tokenize/PayPalTokenizer.d.ts +5 -1
  8. package/dist/esm/tokenize/PayPalTokenizer.js +24 -20
  9. package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +9 -2
  10. package/dist/esm/tokenize/SpreedlyTokenizer.js +90 -19
  11. package/dist/esm/tokenize/Tokenizer.d.ts +2 -0
  12. package/dist/esm/tokenize/Tokenizer.js +14 -0
  13. package/dist/esm/tokenize/index.d.ts +1 -1
  14. package/dist/esm/tokenize/styles.d.ts +1 -1
  15. package/dist/esm/tokenize/styles.js +6 -0
  16. package/dist/esm/tokenize/tokenizer-constants.d.ts +1 -0
  17. package/dist/esm/tokenize/tokenizer-constants.js +1 -0
  18. package/dist/esm/tokenize/types.d.ts +13 -7
  19. package/dist/recaptcha.d.ts +1 -0
  20. package/dist/recaptcha.js +18 -0
  21. package/dist/tokenize/CardConnectTokenizer.d.ts +1 -1
  22. package/dist/tokenize/CardConnectTokenizer.js +70 -27
  23. package/dist/tokenize/PayPalTokenizer.d.ts +5 -1
  24. package/dist/tokenize/PayPalTokenizer.js +24 -20
  25. package/dist/tokenize/SpreedlyTokenizer.d.ts +9 -2
  26. package/dist/tokenize/SpreedlyTokenizer.js +89 -18
  27. package/dist/tokenize/Tokenizer.d.ts +2 -0
  28. package/dist/tokenize/Tokenizer.js +14 -0
  29. package/dist/tokenize/index.d.ts +1 -1
  30. package/dist/tokenize/styles.d.ts +1 -1
  31. package/dist/tokenize/styles.js +6 -0
  32. package/dist/tokenize/tokenizer-constants.d.ts +1 -0
  33. package/dist/tokenize/tokenizer-constants.js +2 -1
  34. package/dist/tokenize/types.d.ts +13 -7
  35. package/package.json +13 -2
  36. 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-dev0';
4
+ exports.SDK_VERSION = '1.2.0-dev9';
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';
@@ -78,7 +78,16 @@ input#cccvvfield {
78
78
  color: #8b959d;
79
79
  }
80
80
  `.replace(/\s+/gi, ' ');
81
+ function getUserAgent() {
82
+ if (typeof navigator !== 'undefined') {
83
+ return navigator.userAgent;
84
+ }
85
+ if (typeof process !== 'undefined' && process.version) {
86
+ return `Node.js/${process.version} (${process.platform})`;
87
+ }
88
+ return 'unknown-runtime';
89
+ }
81
90
  exports.CLIENT_HEADERS = {
82
- 'User-Agent': navigator.userAgent + ` idonate-sdk@${exports.SDK_VERSION}`,
91
+ 'User-Agent': getUserAgent() + ` idonate-sdk@${exports.SDK_VERSION}`,
83
92
  'Content-Type': 'application/json',
84
93
  };
@@ -1,4 +1,4 @@
1
- export const SDK_VERSION = '1.2.0-dev0';
1
+ export const SDK_VERSION = '1.2.0-dev9';
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';
@@ -75,7 +75,16 @@ input#cccvvfield {
75
75
  color: #8b959d;
76
76
  }
77
77
  `.replace(/\s+/gi, ' ');
78
+ function getUserAgent() {
79
+ if (typeof navigator !== 'undefined') {
80
+ return navigator.userAgent;
81
+ }
82
+ if (typeof process !== 'undefined' && process.version) {
83
+ return `Node.js/${process.version} (${process.platform})`;
84
+ }
85
+ return 'unknown-runtime';
86
+ }
78
87
  export const CLIENT_HEADERS = {
79
- 'User-Agent': navigator.userAgent + ` idonate-sdk@${SDK_VERSION}`,
88
+ 'User-Agent': getUserAgent() + ` idonate-sdk@${SDK_VERSION}`,
80
89
  'Content-Type': 'application/json',
81
90
  };
@@ -10,3 +10,4 @@ export declare class RecaptchaElement {
10
10
  resolveToken(): Promise<string>;
11
11
  }
12
12
  export declare function wrapElement(container: string, sitekey: string, extraParams?: any): RecaptchaElement;
13
+ export declare function wrapElementWithThrow(container: string, sitekey: string, extraParams?: any): Promise<RecaptchaElement>;
@@ -1,3 +1,12 @@
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
+ };
1
10
  function resolveLib() {
2
11
  const startWait = new Date();
3
12
  return new Promise((resolve, reject) => {
@@ -87,3 +96,11 @@ export function wrapElement(container, sitekey, extraParams) {
87
96
  captcha.render();
88
97
  return captcha;
89
98
  }
99
+ export function wrapElementWithThrow(container, sitekey, extraParams) {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ const params = Object.assign(Object.assign({}, (extraParams || {})), { sitekey });
102
+ const captcha = new RecaptchaElement(container, params);
103
+ yield captcha.render();
104
+ return captcha;
105
+ });
106
+ }
@@ -9,7 +9,6 @@ export declare class CardConnectTokenizer extends Tokenizer {
9
9
  private iframe;
10
10
  private messageHandler?;
11
11
  private expectedOrigin;
12
- private isReady;
13
12
  private currentValidationState;
14
13
  private containerEl?;
15
14
  private routingNumberEl?;
@@ -20,6 +19,7 @@ export declare class CardConnectTokenizer extends Tokenizer {
20
19
  private tokenizationPromise?;
21
20
  private tokenizationResolve?;
22
21
  private tokenizationReject?;
22
+ private currentCardType?;
23
23
  private constructor();
24
24
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
25
25
  organizationId: string;
@@ -11,7 +11,7 @@ import { Tokenizer } from './Tokenizer';
11
11
  import { TokenizationError, } from './types';
12
12
  import ConfigHandler from '../config-handler';
13
13
  import { DEFAULT_UNIFIED_STYLES, mergeStyles, getContainerStylesForLayout, } from './styles';
14
- import { INIT_TIMEOUT, TOKENIZE_TIMEOUT, BANK_FIELD_FLEX, } from './tokenizer-constants';
14
+ import { INIT_TIMEOUT, TOKENIZE_TIMEOUT, BANK_FIELD_FLEX, RESPONSIVE_BREAKPOINT, } from './tokenizer-constants';
15
15
  import { createInputElement, validateRoutingNumber, validateAccountNumber, createAccountTypeSelect, } from './tokenizer-utils';
16
16
  export class CardConnectTokenizer extends Tokenizer {
17
17
  constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false, layout = 'single-line') {
@@ -19,7 +19,6 @@ export class CardConnectTokenizer extends Tokenizer {
19
19
  this.iframeUrl = iframeUrl;
20
20
  this.containerId = containerId;
21
21
  this.layout = layout;
22
- this.isReady = false;
23
22
  this.enableTestMode = false;
24
23
  this.mode = mode;
25
24
  this.enableTestMode = enableTestMode;
@@ -39,13 +38,25 @@ export class CardConnectTokenizer extends Tokenizer {
39
38
  if (container.mode === 'bank_account' && container.bankCountry === 'CA') {
40
39
  throw new Error('CardConnect does not support Canadian bank accounts');
41
40
  }
41
+ let effectiveLayout = 'single-line';
42
+ if (container.layout === 'responsive') {
43
+ const containerEl = document.getElementById(container.containerId);
44
+ const containerWidth = (containerEl === null || containerEl === void 0 ? void 0 : containerEl.offsetWidth) || 0;
45
+ const breakpoint = container.responsiveBreakpoint || RESPONSIVE_BREAKPOINT;
46
+ effectiveLayout =
47
+ containerWidth < breakpoint ? 'two-line' : 'single-line';
48
+ }
49
+ else if (container.layout === 'two-line') {
50
+ effectiveLayout = 'two-line';
51
+ }
52
+ const resolvedContainer = Object.assign(Object.assign({}, container), { layout: effectiveLayout });
42
53
  let baseUrl = ((_a = gateway.config) === null || _a === void 0 ? void 0 : _a.base_url) || config.clientConfig.cardConnectBaseUrl;
43
54
  config.cardConnectBaseUrl = baseUrl;
44
55
  const mergedStyles = mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling);
45
- const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, container);
56
+ const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, resolvedContainer);
46
57
  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);
58
+ const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false, effectiveLayout);
59
+ tokenizer.createInternalElements(resolvedContainer);
49
60
  yield tokenizer.init();
50
61
  return tokenizer;
51
62
  });
@@ -68,7 +79,7 @@ export class CardConnectTokenizer extends Tokenizer {
68
79
  }
69
80
  createCreditCardFields(containerEl, mergedStyles) {
70
81
  this.iframe.style.width = '100%';
71
- if (this.layout === 'two-line') {
82
+ if (this.layout === 'two-line' || this.layout === 'responsive') {
72
83
  const inputHeight = mergedStyles.input.height || '40px';
73
84
  this.iframe.style.height = `calc((${inputHeight}) * 2 + 10px)`;
74
85
  }
@@ -132,7 +143,6 @@ export class CardConnectTokenizer extends Tokenizer {
132
143
  init() {
133
144
  return __awaiter(this, void 0, void 0, function* () {
134
145
  if (this.mode === 'bank_account') {
135
- this.isReady = true;
136
146
  if (this.enableTestMode) {
137
147
  setTimeout(() => {
138
148
  if (this.routingNumberEl) {
@@ -165,7 +175,6 @@ export class CardConnectTokenizer extends Tokenizer {
165
175
  window.addEventListener('message', this.messageHandler);
166
176
  this.iframe.onload = () => {
167
177
  clearTimeout(timeout);
168
- this.isReady = true;
169
178
  if (this.enableTestMode && this.mode === 'credit_card') {
170
179
  }
171
180
  this.emit('ready');
@@ -445,10 +454,14 @@ export class CardConnectTokenizer extends Tokenizer {
445
454
  var _a;
446
455
  if (this.mode === 'credit_card' &&
447
456
  ((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0') {
457
+ const cardType = this.cachedTokenResult.cardType
458
+ ? this.normalizeCardType(this.cachedTokenResult.cardType)
459
+ : this.normalizeCardType('unknown');
448
460
  return {
449
461
  token: this.cachedTokenResult.token,
450
- lastFour: this.cachedTokenResult.token.slice(-4),
451
- cardType: this.normalizeCardType('unknown'),
462
+ lastFour: this.cachedTokenResult.last4 ||
463
+ this.cachedTokenResult.token.slice(-4),
464
+ cardType,
452
465
  provider: 'cardconnect',
453
466
  };
454
467
  }
@@ -464,10 +477,17 @@ export class CardConnectTokenizer extends Tokenizer {
464
477
  this.cachedTokenResult = data;
465
478
  this.emit('tokenization', data);
466
479
  if (data.errorCode === '0') {
480
+ const cardType = data.cardType
481
+ ? this.normalizeCardType(data.cardType)
482
+ : this.normalizeCardType('unknown');
483
+ if (data.cardType && cardType !== this.currentCardType) {
484
+ this.currentCardType = cardType;
485
+ this.emit('cardTypeChange', { cardType });
486
+ }
467
487
  const token = {
468
488
  token: data.token,
469
- lastFour: data.token.slice(-4),
470
- cardType: this.normalizeCardType('unknown'),
489
+ lastFour: data.last4 || data.token.slice(-4),
490
+ cardType,
471
491
  provider: 'cardconnect',
472
492
  };
473
493
  if (this.tokenizationResolve) {
@@ -502,6 +522,13 @@ export class CardConnectTokenizer extends Tokenizer {
502
522
  }
503
523
  if (data.event === 'input' || data.event === 'change') {
504
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
+ }
531
+ }
505
532
  }
506
533
  }
507
534
  catch (error) {
@@ -526,12 +553,15 @@ export class CardConnectTokenizer extends Tokenizer {
526
553
  errorLower.includes('year')) {
527
554
  this.currentValidationState.expiry = { isValid: false, isEmpty: false };
528
555
  }
529
- this.emit('error', new TokenizationError(data.validationError));
556
+ this.currentValidationState.isValid = false;
557
+ this.emit('validation', this.currentValidationState);
558
+ }
559
+ 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);
530
564
  }
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
565
  }
536
566
  static generateIframeUrl(baseUrl, container) {
537
567
  const params = new URLSearchParams({
@@ -560,7 +590,12 @@ export class CardConnectTokenizer extends Tokenizer {
560
590
  params.set('placeholderyear', 'YYYY');
561
591
  }
562
592
  const mergedStyles = mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling);
563
- const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, container.layout || 'single-line');
593
+ const isDesktopSafari = typeof navigator !== 'undefined' &&
594
+ /Safari/.test(navigator.userAgent) &&
595
+ /Apple Computer/.test(navigator.vendor) &&
596
+ !/Chrome/.test(navigator.userAgent) &&
597
+ !/Mobile/.test(navigator.userAgent);
598
+ const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, (container.layout || 'single-line'), isDesktopSafari);
564
599
  const queryPairs = [];
565
600
  params.forEach((value, key) => {
566
601
  queryPairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
@@ -593,8 +628,8 @@ export class CardConnectTokenizer extends Tokenizer {
593
628
  iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms');
594
629
  return iframe;
595
630
  }
596
- static generateCardConnectCss(styles, layout = 'single-line') {
597
- var _a, _b, _c, _d;
631
+ static generateCardConnectCss(styles, layout = 'single-line', isDesktopSafari = false) {
632
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
598
633
  const css = [];
599
634
  if (layout === 'two-line') {
600
635
  css.push('html,form,body{margin:0;padding:0;}');
@@ -628,14 +663,22 @@ export class CardConnectTokenizer extends Tokenizer {
628
663
  commonStyles.push('box-sizing:border-box');
629
664
  const baseStyles = commonStyles.join(';');
630
665
  css.push(`input{${baseStyles};}`);
631
- css.push(`select{${baseStyles};}`);
666
+ if (isDesktopSafari) {
667
+ css.push(`select{${baseStyles};-webkit-appearance:none;appearance:none;}`);
668
+ }
669
+ else {
670
+ css.push(`select{${baseStyles};}`);
671
+ }
632
672
  }
633
673
  if (layout === 'two-line') {
634
674
  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) {
675
+ const twoLinePadding = ((_a = styles.twoLine) === null || _a === void 0 ? void 0 : _a.padding) || ((_b = styles.input) === null || _b === void 0 ? void 0 : _b.padding) || '10px';
676
+ const twoLineFontSize = ((_c = styles.twoLine) === null || _c === void 0 ? void 0 : _c.fontSize) || ((_d = styles.input) === null || _d === void 0 ? void 0 : _d.fontSize) || '14px';
677
+ const twoLineTextAlign = ((_e = styles.twoLine) === null || _e === void 0 ? void 0 : _e.textAlign) || 'left';
678
+ css.push(`input#ccexpiryfieldmonth{width:25%;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
679
+ css.push(`input#ccexpiryfieldyear{width:35%;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
680
+ css.push(`input#cccvvfield{width:calc(40% - 16px);padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};margin-left:-4px;}`);
681
+ if ((_f = styles.input) === null || _f === void 0 ? void 0 : _f.borderRadius) {
639
682
  css.push(`input{border-radius:${styles.input.borderRadius};}`);
640
683
  }
641
684
  }
@@ -644,7 +687,7 @@ export class CardConnectTokenizer extends Tokenizer {
644
687
  css.push('select#ccexpirymonth{width:16%;margin:0;margin-right:-12px;}');
645
688
  css.push('select#ccexpiryyear{width:20%;}');
646
689
  css.push('input#cccvvfield{width:20%;margin:0;margin-left:-12px;}');
647
- if ((_b = styles.input) === null || _b === void 0 ? void 0 : _b.borderRadius) {
690
+ if ((_g = styles.input) === null || _g === void 0 ? void 0 : _g.borderRadius) {
648
691
  css.push(`input#ccnumfield{border-radius:${styles.input.borderRadius} 0 0 ${styles.input.borderRadius};border-right:none;}`);
649
692
  css.push('select#ccexpirymonth{border-radius:0;border-right:none;}');
650
693
  css.push('select#ccexpiryyear{border-radius:0;border-right:none;}');
@@ -662,7 +705,7 @@ export class CardConnectTokenizer extends Tokenizer {
662
705
  css.push(`select#ccexpirymonth{width:15%;margin-right:${marginRight};}`);
663
706
  css.push(`select#ccexpiryyear{width:20%;margin-right:${marginRight};}`);
664
707
  css.push('input#cccvvfield{width:15%;}');
665
- if ((_c = styles.input) === null || _c === void 0 ? void 0 : _c.borderRadius) {
708
+ if ((_h = styles.input) === null || _h === void 0 ? void 0 : _h.borderRadius) {
666
709
  css.push(`input,select{border-radius:${styles.input.borderRadius};}`);
667
710
  }
668
711
  }
@@ -678,7 +721,7 @@ export class CardConnectTokenizer extends Tokenizer {
678
721
  if (focusStyles.length > 0) {
679
722
  css.push(`input:focus{${focusStyles.join(';')};}`);
680
723
  css.push(`select:focus{${focusStyles.join(';')};}`);
681
- if (isConnected && ((_d = styles.input) === null || _d === void 0 ? void 0 : _d.border)) {
724
+ if (isConnected && ((_j = styles.input) === null || _j === void 0 ? void 0 : _j.border)) {
682
725
  css.push(`input#ccnumfield:focus{border:${styles.input.border};${focusStyles.join(';')};}`);
683
726
  css.push(`select#ccexpirymonth:focus{border:${styles.input.border};${focusStyles.join(';')};}`);
684
727
  css.push(`select#ccexpiryyear:focus{border:${styles.input.border};${focusStyles.join(';')};}`);
@@ -31,11 +31,14 @@ interface PayPalApproveData {
31
31
  payerID?: string;
32
32
  facilitatorAccessToken?: string;
33
33
  }
34
+ export interface PayPalCreateOrderData {
35
+ amount: number;
36
+ currency?: string;
37
+ }
34
38
  export declare class PayPalTokenizer extends Tokenizer {
35
39
  private gateway;
36
40
  private containerId;
37
41
  private configContext;
38
- private isReady;
39
42
  private containerEl?;
40
43
  private paypalButtonContainer?;
41
44
  private cachedToken?;
@@ -50,6 +53,7 @@ export declare class PayPalTokenizer extends Tokenizer {
50
53
  private clientConfig;
51
54
  private paymentTransactionId?;
52
55
  private paymentMethodId?;
56
+ private onCreateOrder?;
53
57
  private constructor();
54
58
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
55
59
  organizationId: string;
@@ -19,7 +19,6 @@ export class PayPalTokenizer extends Tokenizer {
19
19
  this.gateway = gateway;
20
20
  this.containerId = containerId;
21
21
  this.configContext = configContext;
22
- this.isReady = false;
23
22
  this.mode = 'credit_card';
24
23
  const gatewayConfig = gateway.config;
25
24
  if (!(gatewayConfig === null || gatewayConfig === void 0 ? void 0 : gatewayConfig.client_id)) {
@@ -31,6 +30,7 @@ export class PayPalTokenizer extends Tokenizer {
31
30
  this.amount = config.amount;
32
31
  this.enableVenmo = (_b = config.enableVenmo) !== null && _b !== void 0 ? _b : true;
33
32
  this.locale = config.locale || 'en_US';
33
+ this.onCreateOrder = config.onCreateOrder;
34
34
  this.organizationId = configContext.organizationId;
35
35
  this.embedId = configContext.embedId;
36
36
  this.clientConfig = configContext.clientConfig;
@@ -65,17 +65,13 @@ export class PayPalTokenizer extends Tokenizer {
65
65
  return this.renderButtons();
66
66
  })
67
67
  .then(() => {
68
- this.isReady = true;
69
68
  this.emit('ready');
69
+ this.emit('validation', { isValid: true });
70
70
  resolve();
71
71
  })
72
72
  .catch((error) => {
73
73
  clearTimeout(timeout);
74
- this.emit('error', {
75
- message: 'Failed to initialize PayPal',
76
- code: 'INIT_FAILED',
77
- details: error,
78
- });
74
+ this.emit('error', new TokenizationError('Failed to initialize PayPal', 'INIT_FAILED'));
79
75
  reject(error);
80
76
  });
81
77
  });
@@ -165,13 +161,26 @@ export class PayPalTokenizer extends Tokenizer {
165
161
  }
166
162
  createOrder() {
167
163
  const endpoint = `${this.clientConfig.embedApiBaseUrl}/payment/paypal/create-order`;
164
+ let orderAmount;
165
+ let orderCurrency = this.currency;
166
+ if (this.onCreateOrder) {
167
+ const orderData = this.onCreateOrder();
168
+ orderAmount = orderData.amount;
169
+ orderCurrency = orderData.currency || this.currency;
170
+ }
171
+ else {
172
+ orderAmount = this.amount;
173
+ }
174
+ if (orderAmount === undefined || orderAmount <= 0) {
175
+ const error = new Error('Amount is required to create PayPal order');
176
+ this.handleError(error, 'Order creation failed');
177
+ return Promise.reject(error);
178
+ }
168
179
  const requestBody = {
169
180
  payment_gateway_id: this.gateway.id,
170
- currency: this.currency,
181
+ currency: orderCurrency,
182
+ amount: orderAmount,
171
183
  };
172
- if (this.amount !== undefined) {
173
- requestBody.amount = this.amount;
174
- }
175
184
  return fetch(endpoint, {
176
185
  method: 'POST',
177
186
  headers: {
@@ -208,22 +217,16 @@ export class PayPalTokenizer extends Tokenizer {
208
217
  paymentTransactionId: this.paymentTransactionId,
209
218
  };
210
219
  this.cachedToken = token;
220
+ this.emit('validation', { isValid: true, hasToken: true });
211
221
  this.emit('tokenReady', token);
212
222
  });
213
223
  }
214
224
  handleCancel(data) {
215
- this.emit('error', {
216
- message: 'Payment cancelled by user',
217
- code: 'USER_CANCELLED',
218
- });
225
+ this.emit('error', new TokenizationError('Payment cancelled by user', 'USER_CANCELLED'));
219
226
  }
220
227
  handleError(error, context) {
221
228
  const errorMessage = (error === null || error === void 0 ? void 0 : error.message) || (error === null || error === void 0 ? void 0 : error.toString()) || 'Unknown error';
222
- this.emit('error', {
223
- message: `${context}: ${errorMessage}`,
224
- code: (error === null || error === void 0 ? void 0 : error.code) || 'PAYPAL_ERROR',
225
- details: error,
226
- });
229
+ this.emit('error', new TokenizationError(`${context}: ${errorMessage}`, (error === null || error === void 0 ? void 0 : error.code) || 'PAYPAL_ERROR'));
227
230
  }
228
231
  tokenize(paymentData) {
229
232
  return __awaiter(this, void 0, void 0, function* () {
@@ -246,6 +249,7 @@ export class PayPalTokenizer extends Tokenizer {
246
249
  }
247
250
  clear() {
248
251
  this.cachedToken = undefined;
252
+ this.emit('validation', { isValid: true, hasToken: false });
249
253
  }
250
254
  focus(field) {
251
255
  }
@@ -7,7 +7,6 @@ export declare class SpreedlyTokenizer extends Tokenizer {
7
7
  private containerId;
8
8
  private layout;
9
9
  private spreedly;
10
- private isReady;
11
10
  private currentValidationState;
12
11
  private mergedStyles;
13
12
  private expiryEl?;
@@ -25,6 +24,11 @@ export declare class SpreedlyTokenizer extends Tokenizer {
25
24
  private institutionNumberEl?;
26
25
  private transitNumberEl?;
27
26
  private enableTestMode;
27
+ private resizeObserver?;
28
+ private effectiveLayout;
29
+ private cardNumberDiv?;
30
+ private cvvDiv?;
31
+ private responsiveBreakpoint;
28
32
  private constructor();
29
33
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
30
34
  organizationId: string;
@@ -43,6 +47,9 @@ export declare class SpreedlyTokenizer extends Tokenizer {
43
47
  private stylesToCssString;
44
48
  clear(): void;
45
49
  focus(field: 'cardNumber' | 'cvv' | 'expiry' | 'routingNumber' | 'accountNumber'): void;
50
+ private determineLayout;
51
+ private setupResizeObserver;
52
+ private applyLayoutStyles;
46
53
  destroy(): void;
47
54
  hasToken(): boolean;
48
55
  getToken(): PaymentToken | null;
@@ -68,7 +75,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
68
75
  });
69
76
  address: Partial<Address>;
70
77
  account: Partial<ACHAccount> & Pick<ACHAccount, 'accountNumber' | 'routingNumber'>;
71
- }, config: ConfigHandler): Promise<string>;
78
+ }, config: ConfigHandler, environmentKeyOverride?: string): Promise<string>;
72
79
  static tokenizeCreditCard(data: {
73
80
  contact: Partial<Contact> & ({
74
81
  firstName: string;