@idonatedev/idonate-sdk 1.2.0-dev2 → 1.2.0-dev20

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 (56) hide show
  1. package/dist/constants.js +11 -2
  2. package/dist/esm/constants.js +11 -2
  3. package/dist/esm/idonate-client.js +18 -8
  4. package/dist/esm/recaptcha.d.ts +1 -0
  5. package/dist/esm/recaptcha.js +26 -2
  6. package/dist/esm/shared.js +9 -1
  7. package/dist/esm/tokenize/CardConnectTokenizer.d.ts +8 -1
  8. package/dist/esm/tokenize/CardConnectTokenizer.js +353 -104
  9. package/dist/esm/tokenize/PayPalTokenizer.d.ts +6 -0
  10. package/dist/esm/tokenize/PayPalTokenizer.js +66 -16
  11. package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +17 -1
  12. package/dist/esm/tokenize/SpreedlyTokenizer.js +270 -138
  13. package/dist/esm/tokenize/Tokenizer.d.ts +6 -2
  14. package/dist/esm/tokenize/Tokenizer.js +24 -8
  15. package/dist/esm/tokenize/gateway-utils.d.ts +2 -0
  16. package/dist/esm/tokenize/gateway-utils.js +27 -0
  17. package/dist/esm/tokenize/index.d.ts +3 -2
  18. package/dist/esm/tokenize/index.js +1 -0
  19. package/dist/esm/tokenize/spreedly-secure.js +6 -2
  20. package/dist/esm/tokenize/styles.d.ts +1 -1
  21. package/dist/esm/tokenize/styles.js +20 -1
  22. package/dist/esm/tokenize/tokenizer-constants.d.ts +1 -0
  23. package/dist/esm/tokenize/tokenizer-constants.js +1 -0
  24. package/dist/esm/tokenize/tokenizer-utils.d.ts +4 -1
  25. package/dist/esm/tokenize/tokenizer-utils.js +77 -4
  26. package/dist/esm/tokenize/types.d.ts +33 -8
  27. package/dist/esm/typeAdapters.js +6 -4
  28. package/dist/esm/types.d.ts +4 -10
  29. package/dist/idonate-client.js +18 -8
  30. package/dist/recaptcha.d.ts +1 -0
  31. package/dist/recaptcha.js +27 -2
  32. package/dist/shared.js +9 -1
  33. package/dist/tokenize/CardConnectTokenizer.d.ts +8 -1
  34. package/dist/tokenize/CardConnectTokenizer.js +351 -105
  35. package/dist/tokenize/PayPalTokenizer.d.ts +6 -0
  36. package/dist/tokenize/PayPalTokenizer.js +66 -16
  37. package/dist/tokenize/SpreedlyTokenizer.d.ts +17 -1
  38. package/dist/tokenize/SpreedlyTokenizer.js +267 -135
  39. package/dist/tokenize/Tokenizer.d.ts +6 -2
  40. package/dist/tokenize/Tokenizer.js +24 -8
  41. package/dist/tokenize/gateway-utils.d.ts +2 -0
  42. package/dist/tokenize/gateway-utils.js +30 -0
  43. package/dist/tokenize/index.d.ts +3 -2
  44. package/dist/tokenize/index.js +3 -1
  45. package/dist/tokenize/spreedly-secure.js +6 -2
  46. package/dist/tokenize/styles.d.ts +1 -1
  47. package/dist/tokenize/styles.js +20 -1
  48. package/dist/tokenize/tokenizer-constants.d.ts +1 -0
  49. package/dist/tokenize/tokenizer-constants.js +2 -1
  50. package/dist/tokenize/tokenizer-utils.d.ts +4 -1
  51. package/dist/tokenize/tokenizer-utils.js +80 -4
  52. package/dist/tokenize/types.d.ts +33 -8
  53. package/dist/typeAdapters.js +6 -4
  54. package/dist/types.d.ts +4 -10
  55. package/package.json +33 -2
  56. package/umd/idonate-sdk.js +1 -1
@@ -2,9 +2,13 @@ import { CardData, BankAccountData, PaymentData, PaymentToken, ValidationResult,
2
2
  import ConfigHandler from '../config-handler';
3
3
  export declare abstract class Tokenizer {
4
4
  protected mode: PaymentMethodMode;
5
- protected eventHandlers: Map<TokenizerEvent, Set<(data?: any) => void>>;
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;
@@ -31,7 +35,7 @@ export declare abstract class Tokenizer {
31
35
  expiryId: string;
32
36
  cvvId: string;
33
37
  };
34
- static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
38
+ static create(rawGateway: PaymentGateway, container: TokenizerContainer, config: {
35
39
  organizationId: string;
36
40
  embedId: string;
37
41
  clientConfig: ConfigHandler;
@@ -43,15 +43,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
43
43
  };
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.Tokenizer = void 0;
46
+ const gateway_utils_1 = require("./gateway-utils");
46
47
  const tokenizer_utils_1 = require("./tokenizer-utils");
47
48
  class Tokenizer {
48
49
  constructor() {
49
50
  this.mode = 'credit_card';
50
51
  this.eventHandlers = new Map();
52
+ this.focusHandlerElements = new WeakSet();
51
53
  this._isReady = false;
54
+ this._isDestroyed = false;
52
55
  }
53
56
  get isReady() {
54
- return this._isReady;
57
+ return this._isReady && !this._isDestroyed;
58
+ }
59
+ get isDestroyed() {
60
+ return this._isDestroyed;
61
+ }
62
+ markDestroyed() {
63
+ this._isDestroyed = true;
55
64
  }
56
65
  getMode() {
57
66
  return this.mode;
@@ -117,7 +126,6 @@ class Tokenizer {
117
126
  expiryEl.addEventListener('input', (e) => {
118
127
  const target = e.target;
119
128
  target.value = (0, tokenizer_utils_1.formatExpiryInput)(target.value);
120
- this.emit('change', { field: 'expiry' });
121
129
  });
122
130
  expiryEl.addEventListener('keypress', (e) => {
123
131
  const char = String.fromCharCode(e.which);
@@ -151,11 +159,15 @@ class Tokenizer {
151
159
  switch (position) {
152
160
  case 'left':
153
161
  element.style.borderLeft = inputStyles.border;
154
- element.style.borderRight = 'none';
162
+ element.style.borderRightStyle = 'solid';
163
+ element.style.borderRightWidth = '1px';
164
+ element.style.borderRightColor = 'transparent';
155
165
  break;
156
166
  case 'middle':
157
167
  element.style.borderLeft = inputStyles.border;
158
- element.style.borderRight = 'none';
168
+ element.style.borderRightStyle = 'solid';
169
+ element.style.borderRightWidth = '1px';
170
+ element.style.borderRightColor = 'transparent';
159
171
  break;
160
172
  case 'right':
161
173
  element.style.borderLeft = inputStyles.border;
@@ -168,7 +180,10 @@ class Tokenizer {
168
180
  element.style.border = inputStyles.border;
169
181
  element.style.borderRadius = inputStyles.borderRadius;
170
182
  }
171
- (0, tokenizer_utils_1.addFocusHandlers)(element, styles);
183
+ if (!this.focusHandlerElements.has(element)) {
184
+ (0, tokenizer_utils_1.addFocusHandlers)(element, styles, position);
185
+ this.focusHandlerElements.add(element);
186
+ }
172
187
  }
173
188
  generateFieldIds(containerId) {
174
189
  return {
@@ -177,9 +192,10 @@ class Tokenizer {
177
192
  cvvId: `${containerId}-cvv`,
178
193
  };
179
194
  }
180
- static create(gateway, container, config) {
195
+ static create(rawGateway, container, config) {
181
196
  return __awaiter(this, void 0, void 0, function* () {
182
- switch (gateway.backend_name) {
197
+ const gateway = (0, gateway_utils_1.normalizeGateway)(rawGateway);
198
+ switch (gateway.backendName) {
183
199
  case 'spreedly': {
184
200
  const { SpreedlyTokenizer } = yield Promise.resolve().then(() => __importStar(require('./SpreedlyTokenizer')));
185
201
  return SpreedlyTokenizer.create(gateway, container, config);
@@ -193,7 +209,7 @@ class Tokenizer {
193
209
  return PayPalTokenizer.create(gateway, container, config);
194
210
  }
195
211
  default:
196
- throw new Error(`Unsupported payment backend: ${gateway.backend_name}`);
212
+ throw new Error(`Unsupported payment backend: ${gateway.backendName}`);
197
213
  }
198
214
  });
199
215
  }
@@ -0,0 +1,2 @@
1
+ import { PaymentGateway } from './types';
2
+ export declare function normalizeGateway(input: any): PaymentGateway;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.normalizeGateway = normalizeGateway;
15
+ function normalizeGateway(input) {
16
+ if (!input) {
17
+ throw new Error('Gateway is required but received ' + String(input));
18
+ }
19
+ if (input.backendName !== undefined)
20
+ return input;
21
+ const _a = input.config || {}, { environment_key, base_url, merchant_id } = _a, extraConfigKeys = __rest(_a, ["environment_key", "base_url", "merchant_id"]);
22
+ return {
23
+ id: input.id,
24
+ backendName: input.backend_name,
25
+ gatewayType: input.gateway_type,
26
+ name: input.name,
27
+ config: input.config
28
+ ? Object.assign({ environmentKey: environment_key, baseUrl: base_url, merchantId: merchant_id }, extraConfigKeys) : undefined,
29
+ };
30
+ }
@@ -2,6 +2,7 @@ import * as iats from './iats';
2
2
  export { Tokenizer } from './Tokenizer';
3
3
  export { SpreedlyTokenizer } from './SpreedlyTokenizer';
4
4
  export { CardConnectTokenizer } from './CardConnectTokenizer';
5
- export { PayPalTokenizer } from './PayPalTokenizer';
6
- export { PaymentMethodType, PaymentGateway, TokenizerContainer, TokenizerStyling, CardData, PaymentData, PaymentToken, CardType, TokenizerEvent, ValidationState, ValidationResult, ValidationError, TokenizationError, } from './types';
5
+ export { PayPalTokenizer, PayPalCreateOrderData } from './PayPalTokenizer';
6
+ export { BackendName, PaymentMethodType, PaymentMethodMode, PaymentGateway, TokenizerContainer, TokenizerStyling, CardData, BankAccountData, PaymentData, PaymentToken, CardType, TokenizerEvent, ValidationState, ValidationResult, ValidationError, TokenizationError, } from './types';
7
+ export { normalizeGateway } from './gateway-utils';
7
8
  export { iats };
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.iats = exports.TokenizationError = exports.PayPalTokenizer = exports.CardConnectTokenizer = exports.SpreedlyTokenizer = exports.Tokenizer = void 0;
36
+ exports.iats = exports.normalizeGateway = exports.TokenizationError = exports.PayPalTokenizer = exports.CardConnectTokenizer = exports.SpreedlyTokenizer = exports.Tokenizer = void 0;
37
37
  const iats = __importStar(require("./iats"));
38
38
  exports.iats = iats;
39
39
  var Tokenizer_1 = require("./Tokenizer");
@@ -46,3 +46,5 @@ var PayPalTokenizer_1 = require("./PayPalTokenizer");
46
46
  Object.defineProperty(exports, "PayPalTokenizer", { enumerable: true, get: function () { return PayPalTokenizer_1.PayPalTokenizer; } });
47
47
  var types_1 = require("./types");
48
48
  Object.defineProperty(exports, "TokenizationError", { enumerable: true, get: function () { return types_1.TokenizationError; } });
49
+ var gateway_utils_1 = require("./gateway-utils");
50
+ Object.defineProperty(exports, "normalizeGateway", { enumerable: true, get: function () { return gateway_utils_1.normalizeGateway; } });
@@ -16,6 +16,7 @@ function fetchSpreedlySecurityArgs(config, organizationId, embedId) {
16
16
  throw new Error('Secure tokenization is not enabled');
17
17
  }
18
18
  const makeRequest = () => __awaiter(this, void 0, void 0, function* () {
19
+ var _a;
19
20
  const response = yield fetch(`${config.embedApiBaseUrl}/spreedly/security-args`, {
20
21
  method: 'POST',
21
22
  headers: { 'Content-Type': 'application/json' },
@@ -27,13 +28,16 @@ function fetchSpreedlySecurityArgs(config, organizationId, embedId) {
27
28
  if (!response.ok) {
28
29
  throw new Error(`Security args request failed: ${response.status}`);
29
30
  }
30
- return response.json();
31
+ const data = yield response.json();
32
+ return (_a = data.result) !== null && _a !== void 0 ? _a : data;
31
33
  });
32
34
  try {
33
35
  return yield makeRequest();
34
36
  }
35
37
  catch (error) {
36
- if (error instanceof TypeError && error.message.includes('fetch')) {
38
+ const isNetworkError = error instanceof TypeError && error.message.includes('fetch');
39
+ const isServerError = error instanceof Error && error.message.includes('failed: 5');
40
+ if (isNetworkError || isServerError) {
37
41
  yield new Promise((resolve) => setTimeout(resolve, 1000));
38
42
  return makeRequest();
39
43
  }
@@ -1,4 +1,4 @@
1
1
  import { TokenizerStyling, TokenizerStylingComplete } from './types';
2
2
  export declare const DEFAULT_UNIFIED_STYLES: TokenizerStylingComplete;
3
3
  export declare function mergeStyles(defaults: TokenizerStylingComplete, userStyles?: TokenizerStyling): TokenizerStylingComplete;
4
- export declare function getContainerStylesForLayout(baseStyles: TokenizerStylingComplete, layout?: 'single-line' | 'two-line'): TokenizerStylingComplete;
4
+ export declare function getContainerStylesForLayout(baseStyles: TokenizerStylingComplete, layout?: 'single-line' | 'two-line' | 'responsive'): TokenizerStylingComplete;
@@ -32,16 +32,35 @@ exports.DEFAULT_UNIFIED_STYLES = {
32
32
  flexWrap: 'nowrap',
33
33
  rowGap: '1rem',
34
34
  },
35
+ twoLine: {
36
+ padding: '',
37
+ fontSize: '',
38
+ textAlign: '',
39
+ },
40
+ label: {
41
+ show: false,
42
+ fontSize: '0.875rem',
43
+ fontWeight: 'bold',
44
+ fontFamily: '',
45
+ color: '#333',
46
+ marginBottom: '0.25rem',
47
+ },
35
48
  };
36
49
  function mergeStyles(defaults, userStyles) {
37
50
  if (!userStyles)
38
51
  return defaults;
39
- return {
52
+ const merged = {
40
53
  input: Object.assign(Object.assign({}, defaults.input), userStyles.input),
41
54
  focus: Object.assign(Object.assign({}, defaults.focus), userStyles.focus),
42
55
  error: Object.assign(Object.assign({}, defaults.error), userStyles.error),
43
56
  container: Object.assign(Object.assign({}, defaults.container), userStyles.container),
57
+ twoLine: Object.assign(Object.assign({}, defaults.twoLine), userStyles.twoLine),
58
+ label: Object.assign(Object.assign({}, defaults.label), userStyles.label),
44
59
  };
60
+ if (!merged.label.fontFamily) {
61
+ merged.label.fontFamily = merged.input.fontFamily;
62
+ }
63
+ return merged;
45
64
  }
46
65
  function getContainerStylesForLayout(baseStyles, layout = 'single-line') {
47
66
  if (layout === 'two-line') {
@@ -60,3 +60,4 @@ export declare const FIELD_CONSTRAINTS: {
60
60
  readonly maxLength: 4;
61
61
  };
62
62
  };
63
+ export declare const RESPONSIVE_BREAKPOINT = 400;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FIELD_CONSTRAINTS = exports.PLACEHOLDERS = exports.CANADIAN_BANK_FIELD_FLEX = exports.BANK_FIELD_FLEX = exports.FIELD_FLEX = exports.TOKENIZE_TIMEOUT = exports.INIT_TIMEOUT = void 0;
3
+ exports.RESPONSIVE_BREAKPOINT = exports.FIELD_CONSTRAINTS = exports.PLACEHOLDERS = exports.CANADIAN_BANK_FIELD_FLEX = exports.BANK_FIELD_FLEX = exports.FIELD_FLEX = exports.TOKENIZE_TIMEOUT = exports.INIT_TIMEOUT = void 0;
4
4
  exports.INIT_TIMEOUT = 10000;
5
5
  exports.TOKENIZE_TIMEOUT = 30000;
6
6
  exports.FIELD_FLEX = {
@@ -63,3 +63,4 @@ exports.FIELD_CONSTRAINTS = {
63
63
  maxLength: 4,
64
64
  },
65
65
  };
66
+ exports.RESPONSIVE_BREAKPOINT = 400;
@@ -6,7 +6,9 @@ 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
+ export declare function createFieldLabel(text: string, forId: string, styles: TokenizerStylingComplete): HTMLLabelElement;
11
+ export declare function wrapFieldWithLabel(field: HTMLElement, labelText: string, styles: TokenizerStylingComplete): HTMLElement;
10
12
  export declare function createFieldContainer(id: string, flex: string, minWidth?: string, maxWidth?: string): HTMLDivElement;
11
13
  export declare function createInputElement(id: string, type: string, placeholder: string, maxLength?: number): HTMLInputElement;
12
14
  export declare function validateRoutingNumber(routingNumber: string): boolean;
@@ -17,3 +19,4 @@ export declare function validateInstitutionNumber(institutionNumber: string): bo
17
19
  export declare function validateTransitNumber(transitNumber: string): boolean;
18
20
  export declare function validateCanadianAccountNumber(accountNumber: string): boolean;
19
21
  export declare function formatCanadianRoutingNumber(institutionNumber: string, transitNumber: string): string;
22
+ export declare function cssLengthToPixels(value: string): number;
@@ -5,6 +5,8 @@ exports.formatExpiryInput = formatExpiryInput;
5
5
  exports.withTimeout = withTimeout;
6
6
  exports.getConnectedBorderRadius = getConnectedBorderRadius;
7
7
  exports.addFocusHandlers = addFocusHandlers;
8
+ exports.createFieldLabel = createFieldLabel;
9
+ exports.wrapFieldWithLabel = wrapFieldWithLabel;
8
10
  exports.createFieldContainer = createFieldContainer;
9
11
  exports.createInputElement = createInputElement;
10
12
  exports.validateRoutingNumber = validateRoutingNumber;
@@ -15,6 +17,7 @@ exports.validateInstitutionNumber = validateInstitutionNumber;
15
17
  exports.validateTransitNumber = validateTransitNumber;
16
18
  exports.validateCanadianAccountNumber = validateCanadianAccountNumber;
17
19
  exports.formatCanadianRoutingNumber = formatCanadianRoutingNumber;
20
+ exports.cssLengthToPixels = cssLengthToPixels;
18
21
  function parseExpiryDate(value) {
19
22
  const parts = value.split('/');
20
23
  if (parts.length !== 2)
@@ -56,7 +59,7 @@ function getConnectedBorderRadius(baseRadius, position, isConnected) {
56
59
  return baseRadius;
57
60
  }
58
61
  }
59
- function addFocusHandlers(element, styles, onFocus, onBlur) {
62
+ function addFocusHandlers(element, styles, position, onFocus, onBlur) {
60
63
  element.addEventListener('focus', () => {
61
64
  if (styles.focus) {
62
65
  Object.assign(element.style, styles.focus);
@@ -64,12 +67,69 @@ function addFocusHandlers(element, styles, onFocus, onBlur) {
64
67
  onFocus === null || onFocus === void 0 ? void 0 : onFocus();
65
68
  });
66
69
  element.addEventListener('blur', () => {
67
- element.style.border = styles.input.border;
68
- element.style.outline = 'none';
69
- element.style.boxShadow = 'none';
70
+ const isConnected = styles.container.gap === '0';
71
+ if (isConnected && position) {
72
+ element.style.borderTop = styles.input.border;
73
+ element.style.borderBottom = styles.input.border;
74
+ switch (position) {
75
+ case 'left':
76
+ case 'middle':
77
+ element.style.borderLeft = styles.input.border;
78
+ element.style.borderRightStyle = 'solid';
79
+ element.style.borderRightWidth = '1px';
80
+ element.style.borderRightColor = 'transparent';
81
+ break;
82
+ case 'right':
83
+ element.style.borderLeft = styles.input.border;
84
+ element.style.borderRight = styles.input.border;
85
+ break;
86
+ }
87
+ }
88
+ else {
89
+ element.style.border = styles.input.border;
90
+ }
91
+ element.style.outline = '';
92
+ element.style.boxShadow = '';
70
93
  onBlur === null || onBlur === void 0 ? void 0 : onBlur();
71
94
  });
72
95
  }
96
+ function createFieldLabel(text, forId, styles) {
97
+ const label = document.createElement('label');
98
+ label.htmlFor = forId;
99
+ label.textContent = text;
100
+ label.style.display = styles.label.show ? 'block' : 'none';
101
+ label.style.fontSize = styles.label.fontSize;
102
+ label.style.fontWeight = styles.label.fontWeight;
103
+ label.style.fontFamily = styles.label.fontFamily;
104
+ label.style.color = styles.label.color;
105
+ label.style.marginBottom = styles.label.marginBottom;
106
+ return label;
107
+ }
108
+ function wrapFieldWithLabel(field, labelText, styles) {
109
+ if (!styles.label.show)
110
+ return field;
111
+ const wrapper = document.createElement('div');
112
+ wrapper.style.display = 'flex';
113
+ wrapper.style.flexDirection = 'column';
114
+ if (field.style.flex) {
115
+ wrapper.style.flex = field.style.flex;
116
+ field.style.flex = '';
117
+ }
118
+ if (field.style.minWidth) {
119
+ wrapper.style.minWidth = field.style.minWidth;
120
+ }
121
+ if (field.style.maxWidth) {
122
+ wrapper.style.maxWidth = field.style.maxWidth;
123
+ }
124
+ if (field.style.flexBasis) {
125
+ wrapper.style.flexBasis = field.style.flexBasis;
126
+ field.style.flexBasis = '';
127
+ }
128
+ const label = createFieldLabel(labelText, field.id, styles);
129
+ wrapper.appendChild(label);
130
+ wrapper.appendChild(field);
131
+ return wrapper;
132
+ }
73
133
  function createFieldContainer(id, flex, minWidth, maxWidth) {
74
134
  const div = document.createElement('div');
75
135
  div.id = id;
@@ -154,3 +214,19 @@ function formatCanadianRoutingNumber(institutionNumber, transitNumber) {
154
214
  const transit = transitNumber.replace(/\D/g, '').padStart(5, '0');
155
215
  return '0' + institution + transit;
156
216
  }
217
+ function cssLengthToPixels(value) {
218
+ const num = parseFloat(value);
219
+ if (isNaN(num)) {
220
+ console.warn(`[cssLengthToPixels] Cannot parse "${value}", defaulting to 14px`);
221
+ return 14;
222
+ }
223
+ if (value.endsWith('rem'))
224
+ return num * 16;
225
+ if (value.endsWith('pt'))
226
+ return num * 1.333;
227
+ if (value.endsWith('px') || !value.match(/[a-z%]/i))
228
+ return num;
229
+ console.warn(`[cssLengthToPixels] Unsupported unit in "${value}". ` +
230
+ `Only px, rem, and pt are supported. Using ${num}px as approximation.`);
231
+ return num;
232
+ }
@@ -1,14 +1,15 @@
1
1
  export type PaymentMethodType = 'credit_card' | 'bank_account' | 'paypal' | 'apple_pay' | 'google_pay';
2
- export type PaymentMethodMode = 'credit_card' | 'bank_account';
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
- backend_name: string;
6
- gateway_type?: string;
6
+ backendName: BackendName;
7
+ gatewayType?: string;
7
8
  name: string;
8
9
  config?: {
9
- environment_key?: string;
10
- base_url?: string;
11
- merchant_id?: string;
10
+ environmentKey?: string;
11
+ baseUrl?: string;
12
+ merchantId?: string;
12
13
  [key: string]: any;
13
14
  };
14
15
  }
@@ -18,7 +19,17 @@ export interface TokenizerContainer {
18
19
  mode?: PaymentMethodMode;
19
20
  bankCountry?: 'US' | 'CA';
20
21
  enableTestMode?: boolean;
21
- layout?: 'single-line' | 'two-line';
22
+ layout?: 'single-line' | 'two-line' | 'responsive';
23
+ responsiveBreakpoint?: number;
24
+ placeholders?: {
25
+ cardNumber?: string;
26
+ expiry?: string;
27
+ expiryMonth?: string;
28
+ expiryYear?: string;
29
+ cvv?: string;
30
+ routingNumber?: string;
31
+ accountNumber?: string;
32
+ };
22
33
  }
23
34
  export interface TokenizerStylingComplete {
24
35
  input: {
@@ -52,6 +63,19 @@ export interface TokenizerStylingComplete {
52
63
  flexWrap?: string;
53
64
  rowGap?: string;
54
65
  };
66
+ twoLine: {
67
+ padding: string;
68
+ fontSize: string;
69
+ textAlign: string;
70
+ };
71
+ label: {
72
+ show: boolean;
73
+ fontSize: string;
74
+ fontWeight: string;
75
+ fontFamily: string;
76
+ color: string;
77
+ marginBottom: string;
78
+ };
55
79
  }
56
80
  type DeepPartial<T> = T extends object ? {
57
81
  [P in keyof T]?: DeepPartial<T[P]>;
@@ -100,9 +124,10 @@ export interface PaymentToken {
100
124
  paymentTransactionId?: string;
101
125
  }
102
126
  export type CardType = 'visa' | 'mastercard' | 'amex' | 'discover' | 'diners' | 'jcb' | 'unknown';
103
- export type TokenizerEvent = 'ready' | 'focus' | 'blur' | 'change' | 'validation' | 'cardTypeChange' | 'error' | 'tokenization' | 'tokenReady';
127
+ export type TokenizerEvent = 'ready' | 'validation' | 'cardTypeChange' | 'error' | 'tokenReady';
104
128
  export interface ValidationState {
105
129
  isValid: boolean;
130
+ hasToken?: boolean;
106
131
  cardNumber?: {
107
132
  isValid: boolean;
108
133
  isEmpty: boolean;
@@ -111,16 +111,18 @@ function buildCashPaymentPayload(organizationId, input) {
111
111
  utmFields.utm_term = input.utm.term;
112
112
  }
113
113
  }
114
+ let remainingMeta = input.customerMeta
115
+ ? Object.assign({}, input.customerMeta) : {};
114
116
  if (input.customerMeta) {
115
117
  [1, 2, 3, 4, 5].forEach((customNoteIndex) => {
116
118
  const key = `custom_note_${customNoteIndex}`;
117
- if (input.customerMeta[key]) {
118
- donationOptions[key] = input.customerMeta[key];
119
- delete input.customerMeta[key];
119
+ if (remainingMeta[key]) {
120
+ donationOptions[key] = remainingMeta[key];
121
+ delete remainingMeta[key];
120
122
  }
121
123
  });
122
124
  }
123
- 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 });
125
+ 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 });
124
126
  }
125
127
  function buildDonationResult(response) {
126
128
  let campaign;
package/dist/types.d.ts CHANGED
@@ -53,7 +53,8 @@ export type ACHAccount = {
53
53
  accountHolderType: 'personal' | 'business';
54
54
  accountType: 'checking' | 'savings';
55
55
  };
56
- export type PaymentMethodType = 'credit_card' | 'bank_account' | 'paypal' | 'apple_pay' | 'google_pay';
56
+ import { PaymentMethodType } from './tokenize/types';
57
+ export { PaymentMethodType } from './tokenize/types';
57
58
  export type RecaptchaType = 'v2' | 'v3' | 'invisible' | 'organization' | 'nonce' | 'bypass';
58
59
  export type RecaptchaSecuredRequest = {
59
60
  recaptchaType: RecaptchaType;
@@ -274,15 +275,8 @@ export type TokenizeCardConnectResult = {
274
275
  errorcode: number;
275
276
  };
276
277
  export type BackendName = 'spreedly' | 'card_connect' | 'iats' | 'paypal_checkout';
277
- export type PaymentGateway = {
278
- id: string;
279
- name: string;
280
- backend_name: BackendName;
281
- gateway_type?: string;
282
- config?: {
283
- [key: string]: any;
284
- };
285
- };
278
+ import { PaymentGateway } from './tokenize/types';
279
+ export { PaymentGateway } from './tokenize/types';
286
280
  export interface EmbedConfig {
287
281
  embed_id?: string;
288
282
  organization_id?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@idonatedev/idonate-sdk",
3
3
  "author": "iDonate",
4
- "version": "1.2.0-dev2",
4
+ "version": "1.2.0-dev20",
5
5
  "sideEffects": false,
6
6
  "description": "iDonate Web SDK",
7
7
  "engines": {
@@ -17,6 +17,31 @@
17
17
  "require": "./dist/index.js",
18
18
  "types": "./dist/index.d.ts"
19
19
  },
20
+ "./tokenize": {
21
+ "import": "./dist/esm/tokenize/index.js",
22
+ "require": "./dist/tokenize/index.js",
23
+ "types": "./dist/tokenize/index.d.ts"
24
+ },
25
+ "./client": {
26
+ "import": "./dist/esm/idonate-client.js",
27
+ "require": "./dist/idonate-client.js",
28
+ "types": "./dist/idonate-client.d.ts"
29
+ },
30
+ "./recaptcha": {
31
+ "import": "./dist/esm/recaptcha.js",
32
+ "require": "./dist/recaptcha.js",
33
+ "types": "./dist/recaptcha.d.ts"
34
+ },
35
+ "./cloudflare-challenge-handler": {
36
+ "import": "./dist/esm/cloudflare-challenge-handler.js",
37
+ "require": "./dist/cloudflare-challenge-handler.js",
38
+ "types": "./dist/cloudflare-challenge-handler.d.ts"
39
+ },
40
+ "./dist/tokenize": {
41
+ "import": "./dist/esm/tokenize/index.js",
42
+ "require": "./dist/tokenize/index.js",
43
+ "types": "./dist/tokenize/index.d.ts"
44
+ },
20
45
  "./dist/cloudflare-challenge-handler": {
21
46
  "import": "./dist/esm/cloudflare-challenge-handler.js",
22
47
  "require": "./dist/cloudflare-challenge-handler.js",
@@ -26,6 +51,11 @@
26
51
  "import": "./dist/esm/idonate-client.js",
27
52
  "require": "./dist/idonate-client.js",
28
53
  "types": "./dist/idonate-client.d.ts"
54
+ },
55
+ "./dist/recaptcha": {
56
+ "import": "./dist/esm/recaptcha.js",
57
+ "require": "./dist/recaptcha.js",
58
+ "types": "./dist/recaptcha.d.ts"
29
59
  }
30
60
  },
31
61
  "files": [
@@ -89,5 +119,6 @@
89
119
  "@types/spreedly-iframe-browser": "^1.0.3",
90
120
  "@types/uuid": "^8.3.1",
91
121
  "uuid": "^8.3.2"
92
- }
122
+ },
123
+ "packageManager": "pnpm@10.15.1+sha512.34e538c329b5553014ca8e8f4535997f96180a1d0f614339357449935350d924e22f8614682191264ec33d1462ac21561aff97f6bb18065351c162c7e8f6de67"
93
124
  }