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

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-dev13';
4
+ exports.SDK_VERSION = '1.2.0-dev15';
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-dev13';
1
+ export const SDK_VERSION = '1.2.0-dev15';
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';
@@ -20,6 +20,8 @@ export declare class CardConnectTokenizer extends Tokenizer {
20
20
  private tokenizationResolve?;
21
21
  private tokenizationReject?;
22
22
  private currentCardType?;
23
+ private tokenizationTimeout?;
24
+ private mergedStyles?;
23
25
  private constructor();
24
26
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
25
27
  organizationId: string;
@@ -29,6 +31,8 @@ export declare class CardConnectTokenizer extends Tokenizer {
29
31
  private createInternalElements;
30
32
  private createCreditCardFields;
31
33
  private createBankAccountFields;
34
+ private addBankAccountValidationListeners;
35
+ private updateBankAccountValidation;
32
36
  private init;
33
37
  tokenize(paymentData: PaymentData): Promise<PaymentToken>;
34
38
  private tokenizeCardInternal;
@@ -47,5 +51,5 @@ export declare class CardConnectTokenizer extends Tokenizer {
47
51
  private static generateIframeUrl;
48
52
  private static createIframe;
49
53
  private static generateCardConnectCss;
50
- static tokenizeBankAccount(routingNumber: string, accountNumber: string, config: ConfigHandler): Promise<TokenizeCardConnectBankAccountResult>;
54
+ static tokenizeBankAccount(routingNumber: string, accountNumber: string, configOrBaseUrl: ConfigHandler | string): Promise<TokenizeCardConnectBankAccountResult>;
51
55
  }
@@ -9,7 +9,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Tokenizer } from './Tokenizer';
11
11
  import { TokenizationError, } from './types';
12
- import ConfigHandler from '../config-handler';
13
12
  import { DEFAULT_UNIFIED_STYLES, mergeStyles, getContainerStylesForLayout, } from './styles';
14
13
  import { INIT_TIMEOUT, TOKENIZE_TIMEOUT, BANK_FIELD_FLEX, RESPONSIVE_BREAKPOINT, } from './tokenizer-constants';
15
14
  import { createInputElement, validateRoutingNumber, validateAccountNumber, createAccountTypeSelect, } from './tokenizer-utils';
@@ -34,7 +33,7 @@ export class CardConnectTokenizer extends Tokenizer {
34
33
  }
35
34
  static create(gateway, container, config) {
36
35
  return __awaiter(this, void 0, void 0, function* () {
37
- var _a;
36
+ var _a, _b;
38
37
  if (container.mode === 'bank_account' && container.bankCountry === 'CA') {
39
38
  throw new Error('CardConnect does not support Canadian bank accounts');
40
39
  }
@@ -42,7 +41,7 @@ export class CardConnectTokenizer extends Tokenizer {
42
41
  if (container.layout === 'responsive') {
43
42
  const containerEl = document.getElementById(container.containerId);
44
43
  const containerWidth = (containerEl === null || containerEl === void 0 ? void 0 : containerEl.offsetWidth) || 0;
45
- const breakpoint = container.responsiveBreakpoint || RESPONSIVE_BREAKPOINT;
44
+ const breakpoint = (_a = container.responsiveBreakpoint) !== null && _a !== void 0 ? _a : RESPONSIVE_BREAKPOINT;
46
45
  effectiveLayout =
47
46
  containerWidth < breakpoint ? 'two-line' : 'single-line';
48
47
  }
@@ -50,8 +49,7 @@ export class CardConnectTokenizer extends Tokenizer {
50
49
  effectiveLayout = 'two-line';
51
50
  }
52
51
  const resolvedContainer = Object.assign(Object.assign({}, container), { layout: effectiveLayout });
53
- let baseUrl = ((_a = gateway.config) === null || _a === void 0 ? void 0 : _a.baseUrl) || config.clientConfig.cardConnectBaseUrl;
54
- config.cardConnectBaseUrl = baseUrl;
52
+ const baseUrl = ((_b = gateway.config) === null || _b === void 0 ? void 0 : _b.baseUrl) || config.clientConfig.cardConnectBaseUrl;
55
53
  const mergedStyles = mergeStyles(DEFAULT_UNIFIED_STYLES, container.styling);
56
54
  const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, resolvedContainer);
57
55
  const iframe = CardConnectTokenizer.createIframe(iframeUrl, mergedStyles);
@@ -139,6 +137,66 @@ export class CardConnectTokenizer extends Tokenizer {
139
137
  this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
140
138
  containerEl.appendChild(this.accountTypeEl);
141
139
  }
140
+ this.mergedStyles = mergedStyles;
141
+ this.currentValidationState = {
142
+ isValid: false,
143
+ routingNumber: { isValid: false, isEmpty: true },
144
+ accountNumber: { isValid: false, isEmpty: true },
145
+ };
146
+ this.addBankAccountValidationListeners(mergedStyles);
147
+ }
148
+ addBankAccountValidationListeners(styles) {
149
+ if (this.routingNumberEl) {
150
+ this.routingNumberEl.addEventListener('blur', () => {
151
+ this.updateBankAccountValidation(styles);
152
+ });
153
+ this.routingNumberEl.addEventListener('input', () => {
154
+ this.updateBankAccountValidation(styles);
155
+ });
156
+ }
157
+ if (this.accountNumberEl) {
158
+ this.accountNumberEl.addEventListener('blur', () => {
159
+ this.updateBankAccountValidation(styles);
160
+ });
161
+ this.accountNumberEl.addEventListener('input', () => {
162
+ this.updateBankAccountValidation(styles);
163
+ });
164
+ }
165
+ }
166
+ updateBankAccountValidation(styles) {
167
+ var _a, _b;
168
+ const routingValue = ((_a = this.routingNumberEl) === null || _a === void 0 ? void 0 : _a.value) || '';
169
+ const accountValue = ((_b = this.accountNumberEl) === null || _b === void 0 ? void 0 : _b.value) || '';
170
+ const routingValid = routingValue.length > 0 && validateRoutingNumber(routingValue);
171
+ const accountValid = accountValue.length > 0 && validateAccountNumber(accountValue);
172
+ if (this.routingNumberEl) {
173
+ if (routingValue.length > 0 && !routingValid) {
174
+ this.routingNumberEl.style.borderColor = styles.error.borderColor;
175
+ }
176
+ else {
177
+ this.routingNumberEl.style.borderColor = '';
178
+ }
179
+ }
180
+ if (this.accountNumberEl) {
181
+ if (accountValue.length > 0 && !accountValid) {
182
+ this.accountNumberEl.style.borderColor = styles.error.borderColor;
183
+ }
184
+ else {
185
+ this.accountNumberEl.style.borderColor = '';
186
+ }
187
+ }
188
+ this.currentValidationState = {
189
+ isValid: routingValid && accountValid,
190
+ routingNumber: {
191
+ isValid: routingValid,
192
+ isEmpty: routingValue.length === 0,
193
+ },
194
+ accountNumber: {
195
+ isValid: accountValid,
196
+ isEmpty: accountValue.length === 0,
197
+ },
198
+ };
199
+ this.emit('validation', this.currentValidationState);
142
200
  }
143
201
  init() {
144
202
  return __awaiter(this, void 0, void 0, function* () {
@@ -208,6 +266,7 @@ export class CardConnectTokenizer extends Tokenizer {
208
266
  }
209
267
  tokenizeCardInternal(cardData) {
210
268
  return __awaiter(this, void 0, void 0, function* () {
269
+ var _a, _b, _c;
211
270
  if (this.cachedTokenResult && this.cachedTokenResult.errorCode === '0') {
212
271
  return {
213
272
  token: this.cachedTokenResult.token,
@@ -219,20 +278,22 @@ export class CardConnectTokenizer extends Tokenizer {
219
278
  if (this.tokenizationPromise) {
220
279
  return this.tokenizationPromise;
221
280
  }
281
+ if (!this.currentValidationState.isValid &&
282
+ (((_a = this.currentValidationState.cardNumber) === null || _a === void 0 ? void 0 : _a.isEmpty) ||
283
+ ((_b = this.currentValidationState.cvv) === null || _b === void 0 ? void 0 : _b.isEmpty) ||
284
+ ((_c = this.currentValidationState.expiry) === null || _c === void 0 ? void 0 : _c.isEmpty))) {
285
+ throw new TokenizationError('Card fields are incomplete', 'VALIDATION_ERROR');
286
+ }
222
287
  this.tokenizationPromise = new Promise((resolve, reject) => {
223
288
  this.tokenizationResolve = resolve;
224
289
  this.tokenizationReject = reject;
225
- const timeout = setTimeout(() => {
290
+ this.tokenizationTimeout = setTimeout(() => {
291
+ this.tokenizationTimeout = undefined;
226
292
  this.tokenizationPromise = undefined;
227
293
  this.tokenizationResolve = undefined;
228
294
  this.tokenizationReject = undefined;
229
295
  reject(new TokenizationError('Tokenization timeout - ensure all card fields are filled in iframe', 'TIMEOUT'));
230
296
  }, TOKENIZE_TIMEOUT);
231
- const tokenizationHandler = (data) => {
232
- clearTimeout(timeout);
233
- this.off('tokenization', tokenizationHandler);
234
- };
235
- this.on('tokenization', tokenizationHandler);
236
297
  });
237
298
  return this.tokenizationPromise;
238
299
  });
@@ -254,9 +315,7 @@ export class CardConnectTokenizer extends Tokenizer {
254
315
  throw new TokenizationError('Invalid account number', 'VALIDATION_ERROR');
255
316
  }
256
317
  const baseUrl = new URL(this.iframeUrl).origin;
257
- const config = new ConfigHandler({});
258
- config.cardConnectBaseUrl = baseUrl;
259
- const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, config);
318
+ const result = yield CardConnectTokenizer.tokenizeBankAccount(routingNumber, accountNumber, baseUrl);
260
319
  return {
261
320
  token: result.token,
262
321
  lastFour: accountNumber.slice(-4),
@@ -400,12 +459,25 @@ export class CardConnectTokenizer extends Tokenizer {
400
459
  action: 'clear',
401
460
  }, this.expectedOrigin);
402
461
  }
403
- this.currentValidationState = {
404
- isValid: false,
405
- cardNumber: { isValid: false, isEmpty: true },
406
- cvv: { isValid: false, isEmpty: true },
407
- expiry: { isValid: false, isEmpty: true },
408
- };
462
+ this.cachedTokenResult = undefined;
463
+ this.tokenizationPromise = undefined;
464
+ this.tokenizationResolve = undefined;
465
+ this.tokenizationReject = undefined;
466
+ if (this.mode === 'bank_account') {
467
+ this.currentValidationState = {
468
+ isValid: false,
469
+ routingNumber: { isValid: false, isEmpty: true },
470
+ accountNumber: { isValid: false, isEmpty: true },
471
+ };
472
+ }
473
+ else {
474
+ this.currentValidationState = {
475
+ isValid: false,
476
+ cardNumber: { isValid: false, isEmpty: true },
477
+ cvv: { isValid: false, isEmpty: true },
478
+ expiry: { isValid: false, isEmpty: true },
479
+ };
480
+ }
409
481
  this.emit('validation', this.currentValidationState);
410
482
  }
411
483
  focus(field) {
@@ -434,8 +506,21 @@ export class CardConnectTokenizer extends Tokenizer {
434
506
  }
435
507
  }
436
508
  destroy() {
509
+ if (this.tokenizationTimeout) {
510
+ clearTimeout(this.tokenizationTimeout);
511
+ this.tokenizationTimeout = undefined;
512
+ }
513
+ if (this.tokenizationReject) {
514
+ const reject = this.tokenizationReject;
515
+ this.tokenizationPromise = undefined;
516
+ this.tokenizationResolve = undefined;
517
+ this.tokenizationReject = undefined;
518
+ reject(new TokenizationError('Tokenizer destroyed', 'DESTROYED'));
519
+ }
520
+ this.cachedTokenResult = undefined;
437
521
  if (this.messageHandler) {
438
522
  window.removeEventListener('message', this.messageHandler);
523
+ this.messageHandler = undefined;
439
524
  }
440
525
  if (this.containerEl) {
441
526
  this.containerEl.innerHTML = '';
@@ -475,7 +560,10 @@ export class CardConnectTokenizer extends Tokenizer {
475
560
  const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
476
561
  if (data.token && data.errorCode !== undefined) {
477
562
  this.cachedTokenResult = data;
478
- this.emit('tokenization', data);
563
+ if (this.tokenizationTimeout) {
564
+ clearTimeout(this.tokenizationTimeout);
565
+ this.tokenizationTimeout = undefined;
566
+ }
479
567
  if (data.errorCode === '0') {
480
568
  const cardType = data.cardType
481
569
  ? this.normalizeCardType(data.cardType)
@@ -502,12 +590,14 @@ export class CardConnectTokenizer extends Tokenizer {
502
590
  cvv: { isValid: true, isEmpty: false },
503
591
  expiry: { isValid: true, isEmpty: false },
504
592
  };
505
- this.emit('validation', { isValid: true });
593
+ this.emit('validation', this.currentValidationState);
506
594
  this.emit('tokenReady', token);
507
595
  }
508
596
  else {
597
+ const error = new TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN');
598
+ this.emit('error', error);
509
599
  if (this.tokenizationReject) {
510
- this.tokenizationReject(new TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
600
+ this.tokenizationReject(error);
511
601
  this.tokenizationPromise = undefined;
512
602
  this.tokenizationResolve = undefined;
513
603
  this.tokenizationReject = undefined;
@@ -517,17 +607,12 @@ export class CardConnectTokenizer extends Tokenizer {
517
607
  if (data.event === 'validation' || data.validationError !== undefined) {
518
608
  this.handleValidationMessage(data);
519
609
  }
520
- if (data.event === 'focus' || data.event === 'blur') {
521
- this.emit(data.event, { field: data.data });
522
- }
523
- if (data.event === 'input' || data.event === 'change') {
524
- this.emit('change', { field: data.data });
525
- if (data.cardType) {
526
- const cardType = this.normalizeCardType(data.cardType);
527
- if (cardType !== this.currentCardType) {
528
- this.currentCardType = cardType;
529
- this.emit('cardTypeChange', { cardType });
530
- }
610
+ if ((data.event === 'input' || data.event === 'change') &&
611
+ data.cardType) {
612
+ const cardType = this.normalizeCardType(data.cardType);
613
+ if (cardType !== this.currentCardType) {
614
+ this.currentCardType = cardType;
615
+ this.emit('cardTypeChange', { cardType });
531
616
  }
532
617
  }
533
618
  }
@@ -535,7 +620,6 @@ export class CardConnectTokenizer extends Tokenizer {
535
620
  }
536
621
  }
537
622
  handleValidationMessage(data) {
538
- var _a, _b, _c, _d, _e, _f;
539
623
  if (data.validationError) {
540
624
  const errorLower = data.validationError.toLowerCase();
541
625
  if (errorLower.includes('card') || errorLower.includes('number')) {
@@ -557,10 +641,14 @@ export class CardConnectTokenizer extends Tokenizer {
557
641
  this.emit('validation', this.currentValidationState);
558
642
  }
559
643
  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);
644
+ this.currentValidationState.cardNumber = {
645
+ isValid: true,
646
+ isEmpty: false,
647
+ };
648
+ this.currentValidationState.cvv = { isValid: true, isEmpty: false };
649
+ this.currentValidationState.expiry = { isValid: true, isEmpty: false };
650
+ this.currentValidationState.isValid = true;
651
+ this.emit('validation', this.currentValidationState);
564
652
  }
565
653
  }
566
654
  static generateIframeUrl(baseUrl, container) {
@@ -740,16 +828,29 @@ export class CardConnectTokenizer extends Tokenizer {
740
828
  }
741
829
  return encodeURIComponent(css.join(''));
742
830
  }
743
- static tokenizeBankAccount(routingNumber, accountNumber, config) {
744
- return fetch(`${config.cardConnectBaseUrl}/cardsecure/api/v1/ccn/tokenize`, {
745
- method: 'POST',
746
- headers: {
747
- 'Content-Type': 'application/json',
748
- },
749
- body: JSON.stringify({
750
- account: `${routingNumber}/${accountNumber}`,
751
- unique: true,
752
- }),
753
- }).then((response) => response.json());
831
+ static tokenizeBankAccount(routingNumber, accountNumber, configOrBaseUrl) {
832
+ return __awaiter(this, void 0, void 0, function* () {
833
+ const baseUrl = typeof configOrBaseUrl === 'string'
834
+ ? configOrBaseUrl
835
+ : configOrBaseUrl.cardConnectBaseUrl;
836
+ const response = yield fetch(`${baseUrl}/cardsecure/api/v1/ccn/tokenize`, {
837
+ method: 'POST',
838
+ headers: {
839
+ 'Content-Type': 'application/json',
840
+ },
841
+ body: JSON.stringify({
842
+ account: `${routingNumber}/${accountNumber}`,
843
+ unique: true,
844
+ }),
845
+ });
846
+ if (!response.ok) {
847
+ throw new TokenizationError(`Bank account tokenization failed: HTTP ${response.status}`, 'API_ERROR');
848
+ }
849
+ const result = yield response.json();
850
+ if (!result.token) {
851
+ throw new TokenizationError(result.message || 'Bank account tokenization failed: no token returned', 'API_ERROR');
852
+ }
853
+ return result;
854
+ });
754
855
  }
755
856
  }
@@ -41,6 +41,7 @@ export declare class PayPalTokenizer extends Tokenizer {
41
41
  private configContext;
42
42
  private containerEl?;
43
43
  private paypalButtonContainer?;
44
+ private buttonsInstance?;
44
45
  private cachedToken?;
45
46
  private currency;
46
47
  private amount?;
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Tokenizer } from './Tokenizer';
11
11
  import { TokenizationError, } from './types';
12
+ import { CLIENT_HEADERS } from '../constants';
12
13
  const PAYPAL_SDK_URL = 'https://www.paypal.com/sdk/js';
13
14
  const PAYPAL_SCRIPT_ID = 'paypal-sdk-script';
14
15
  const INIT_TIMEOUT = 10000;
@@ -19,7 +20,7 @@ export class PayPalTokenizer extends Tokenizer {
19
20
  this.gateway = gateway;
20
21
  this.containerId = containerId;
21
22
  this.configContext = configContext;
22
- this.mode = 'credit_card';
23
+ this.mode = 'paypal';
23
24
  const gatewayConfig = gateway.config;
24
25
  if (!(gatewayConfig === null || gatewayConfig === void 0 ? void 0 : gatewayConfig.client_id)) {
25
26
  throw new Error('PayPal gateway configuration missing client_id');
@@ -66,7 +67,7 @@ export class PayPalTokenizer extends Tokenizer {
66
67
  })
67
68
  .then(() => {
68
69
  this.emit('ready');
69
- this.emit('validation', { isValid: true });
70
+ this.emit('validation', { isValid: true, hasToken: false });
70
71
  resolve();
71
72
  })
72
73
  .catch((error) => {
@@ -79,11 +80,20 @@ export class PayPalTokenizer extends Tokenizer {
79
80
  }
80
81
  loadPayPalSDK() {
81
82
  return __awaiter(this, void 0, void 0, function* () {
82
- if (window.paypal) {
83
- return Promise.resolve();
84
- }
85
- if (document.getElementById(PAYPAL_SCRIPT_ID)) {
86
- return this.waitForPayPalGlobal();
83
+ const configKey = `${this.clientId}|${this.currency}`;
84
+ const existingScript = document.getElementById(PAYPAL_SCRIPT_ID);
85
+ if (existingScript) {
86
+ const loadedConfig = existingScript.getAttribute('data-config-key');
87
+ if (loadedConfig && loadedConfig !== configKey) {
88
+ existingScript.remove();
89
+ delete window.paypal;
90
+ }
91
+ else if (window.paypal) {
92
+ return Promise.resolve();
93
+ }
94
+ else {
95
+ return this.waitForPayPalGlobal();
96
+ }
87
97
  }
88
98
  const params = new URLSearchParams({
89
99
  'client-id': this.clientId,
@@ -102,6 +112,7 @@ export class PayPalTokenizer extends Tokenizer {
102
112
  script.id = PAYPAL_SCRIPT_ID;
103
113
  script.src = `${PAYPAL_SDK_URL}?${params.toString()}`;
104
114
  script.async = true;
115
+ script.setAttribute('data-config-key', configKey);
105
116
  return new Promise((resolve, reject) => {
106
117
  script.onload = () => {
107
118
  this.waitForPayPalGlobal().then(resolve).catch(reject);
@@ -145,7 +156,7 @@ export class PayPalTokenizer extends Tokenizer {
145
156
  if (!window.paypal || !this.paypalButtonContainer) {
146
157
  return;
147
158
  }
148
- const button = window.paypal.Buttons({
159
+ this.buttonsInstance = window.paypal.Buttons({
149
160
  createOrder: () => this.createOrder(),
150
161
  onApprove: (data) => this.handleApprove(data),
151
162
  onCancel: (data) => this.handleCancel(data),
@@ -156,36 +167,48 @@ export class PayPalTokenizer extends Tokenizer {
156
167
  height: 40,
157
168
  },
158
169
  });
159
- yield button.render(this.paypalButtonContainer);
170
+ yield this.buttonsInstance.render(this.paypalButtonContainer);
160
171
  });
161
172
  }
162
173
  createOrder() {
163
174
  const endpoint = `${this.clientConfig.embedApiBaseUrl}/payment/paypal/create-order`;
175
+ this.paymentTransactionId = undefined;
176
+ this.paymentMethodId = undefined;
164
177
  let orderAmount;
165
178
  let orderCurrency = this.currency;
166
179
  if (this.onCreateOrder) {
167
- const orderData = this.onCreateOrder();
168
- orderAmount = orderData.amount;
169
- orderCurrency = orderData.currency || this.currency;
180
+ try {
181
+ const orderData = this.onCreateOrder();
182
+ orderAmount = orderData.amount;
183
+ orderCurrency = orderData.currency || this.currency;
184
+ }
185
+ catch (err) {
186
+ const error = err instanceof Error
187
+ ? err
188
+ : new Error('onCreateOrder callback failed');
189
+ this.handleError(error, 'Order creation failed');
190
+ return Promise.reject(error);
191
+ }
170
192
  }
171
193
  else {
172
194
  orderAmount = this.amount;
173
195
  }
174
- if (orderAmount === undefined || orderAmount <= 0) {
196
+ if (orderAmount === undefined || isNaN(orderAmount) || orderAmount <= 0) {
175
197
  const error = new Error('Amount is required to create PayPal order');
176
198
  this.handleError(error, 'Order creation failed');
177
199
  return Promise.reject(error);
178
200
  }
179
201
  const requestBody = {
180
202
  payment_gateway_id: this.gateway.id,
203
+ organization_id: this.organizationId,
204
+ embed_id: this.embedId,
181
205
  currency: orderCurrency,
182
206
  amount: orderAmount,
183
207
  };
184
208
  return fetch(endpoint, {
185
209
  method: 'POST',
186
- headers: {
187
- 'Content-Type': 'application/json',
188
- },
210
+ headers: CLIENT_HEADERS,
211
+ credentials: 'include',
189
212
  body: JSON.stringify(requestBody),
190
213
  })
191
214
  .then((response) => {
@@ -241,6 +264,9 @@ export class PayPalTokenizer extends Tokenizer {
241
264
  }
242
265
  validate() {
243
266
  return __awaiter(this, void 0, void 0, function* () {
267
+ if (!this.isReady) {
268
+ throw new Error('Tokenizer not initialized');
269
+ }
244
270
  return {
245
271
  isValid: true,
246
272
  errors: [],
@@ -254,6 +280,14 @@ export class PayPalTokenizer extends Tokenizer {
254
280
  focus(field) {
255
281
  }
256
282
  destroy() {
283
+ if (this.buttonsInstance) {
284
+ try {
285
+ this.buttonsInstance.close();
286
+ }
287
+ catch (_a) {
288
+ }
289
+ this.buttonsInstance = undefined;
290
+ }
257
291
  if (this.containerEl) {
258
292
  this.containerEl.innerHTML = '';
259
293
  }
@@ -29,6 +29,10 @@ export declare class SpreedlyTokenizer extends Tokenizer {
29
29
  private cardNumberDiv?;
30
30
  private cvvDiv?;
31
31
  private responsiveBreakpoint;
32
+ private tokenizationPromise?;
33
+ private tokenizationResolve?;
34
+ private tokenizationReject?;
35
+ private tokenizationTimeout?;
32
36
  private constructor();
33
37
  static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
34
38
  organizationId: string;
@@ -50,6 +54,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
50
54
  private determineLayout;
51
55
  private setupResizeObserver;
52
56
  private applyLayoutStyles;
57
+ private clearTokenizationState;
53
58
  destroy(): void;
54
59
  hasToken(): boolean;
55
60
  getToken(): PaymentToken | null;