@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.
- package/dist/constants.js +11 -2
- package/dist/esm/constants.js +11 -2
- package/dist/esm/idonate-client.js +18 -8
- package/dist/esm/recaptcha.d.ts +1 -0
- package/dist/esm/recaptcha.js +26 -2
- package/dist/esm/shared.js +9 -1
- package/dist/esm/tokenize/CardConnectTokenizer.d.ts +8 -1
- package/dist/esm/tokenize/CardConnectTokenizer.js +353 -104
- package/dist/esm/tokenize/PayPalTokenizer.d.ts +6 -0
- package/dist/esm/tokenize/PayPalTokenizer.js +66 -16
- package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +17 -1
- package/dist/esm/tokenize/SpreedlyTokenizer.js +270 -138
- package/dist/esm/tokenize/Tokenizer.d.ts +6 -2
- package/dist/esm/tokenize/Tokenizer.js +24 -8
- package/dist/esm/tokenize/gateway-utils.d.ts +2 -0
- package/dist/esm/tokenize/gateway-utils.js +27 -0
- package/dist/esm/tokenize/index.d.ts +3 -2
- package/dist/esm/tokenize/index.js +1 -0
- package/dist/esm/tokenize/spreedly-secure.js +6 -2
- package/dist/esm/tokenize/styles.d.ts +1 -1
- package/dist/esm/tokenize/styles.js +20 -1
- package/dist/esm/tokenize/tokenizer-constants.d.ts +1 -0
- package/dist/esm/tokenize/tokenizer-constants.js +1 -0
- package/dist/esm/tokenize/tokenizer-utils.d.ts +4 -1
- package/dist/esm/tokenize/tokenizer-utils.js +77 -4
- package/dist/esm/tokenize/types.d.ts +33 -8
- package/dist/esm/typeAdapters.js +6 -4
- package/dist/esm/types.d.ts +4 -10
- package/dist/idonate-client.js +18 -8
- package/dist/recaptcha.d.ts +1 -0
- package/dist/recaptcha.js +27 -2
- package/dist/shared.js +9 -1
- package/dist/tokenize/CardConnectTokenizer.d.ts +8 -1
- package/dist/tokenize/CardConnectTokenizer.js +351 -105
- package/dist/tokenize/PayPalTokenizer.d.ts +6 -0
- package/dist/tokenize/PayPalTokenizer.js +66 -16
- package/dist/tokenize/SpreedlyTokenizer.d.ts +17 -1
- package/dist/tokenize/SpreedlyTokenizer.js +267 -135
- package/dist/tokenize/Tokenizer.d.ts +6 -2
- package/dist/tokenize/Tokenizer.js +24 -8
- package/dist/tokenize/gateway-utils.d.ts +2 -0
- package/dist/tokenize/gateway-utils.js +30 -0
- package/dist/tokenize/index.d.ts +3 -2
- package/dist/tokenize/index.js +3 -1
- package/dist/tokenize/spreedly-secure.js +6 -2
- package/dist/tokenize/styles.d.ts +1 -1
- package/dist/tokenize/styles.js +20 -1
- package/dist/tokenize/tokenizer-constants.d.ts +1 -0
- package/dist/tokenize/tokenizer-constants.js +2 -1
- package/dist/tokenize/tokenizer-utils.d.ts +4 -1
- package/dist/tokenize/tokenizer-utils.js +80 -4
- package/dist/tokenize/types.d.ts +33 -8
- package/dist/typeAdapters.js +6 -4
- package/dist/types.d.ts +4 -10
- package/package.json +33 -2
- 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<
|
|
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(
|
|
38
|
+
static create(rawGateway: PaymentGateway, container: TokenizerContainer, config: {
|
|
35
39
|
organizationId: string;
|
|
36
40
|
embedId: string;
|
|
37
41
|
clientConfig: ConfigHandler;
|
|
@@ -7,15 +7,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
import { normalizeGateway } from './gateway-utils';
|
|
10
11
|
import { formatExpiryInput, parseExpiryDate, addFocusHandlers, getConnectedBorderRadius, } from './tokenizer-utils';
|
|
11
12
|
export class Tokenizer {
|
|
12
13
|
constructor() {
|
|
13
14
|
this.mode = 'credit_card';
|
|
14
15
|
this.eventHandlers = new Map();
|
|
16
|
+
this.focusHandlerElements = new WeakSet();
|
|
15
17
|
this._isReady = false;
|
|
18
|
+
this._isDestroyed = false;
|
|
16
19
|
}
|
|
17
20
|
get isReady() {
|
|
18
|
-
return this._isReady;
|
|
21
|
+
return this._isReady && !this._isDestroyed;
|
|
22
|
+
}
|
|
23
|
+
get isDestroyed() {
|
|
24
|
+
return this._isDestroyed;
|
|
25
|
+
}
|
|
26
|
+
markDestroyed() {
|
|
27
|
+
this._isDestroyed = true;
|
|
19
28
|
}
|
|
20
29
|
getMode() {
|
|
21
30
|
return this.mode;
|
|
@@ -81,7 +90,6 @@ export class Tokenizer {
|
|
|
81
90
|
expiryEl.addEventListener('input', (e) => {
|
|
82
91
|
const target = e.target;
|
|
83
92
|
target.value = formatExpiryInput(target.value);
|
|
84
|
-
this.emit('change', { field: 'expiry' });
|
|
85
93
|
});
|
|
86
94
|
expiryEl.addEventListener('keypress', (e) => {
|
|
87
95
|
const char = String.fromCharCode(e.which);
|
|
@@ -115,11 +123,15 @@ export class Tokenizer {
|
|
|
115
123
|
switch (position) {
|
|
116
124
|
case 'left':
|
|
117
125
|
element.style.borderLeft = inputStyles.border;
|
|
118
|
-
element.style.
|
|
126
|
+
element.style.borderRightStyle = 'solid';
|
|
127
|
+
element.style.borderRightWidth = '1px';
|
|
128
|
+
element.style.borderRightColor = 'transparent';
|
|
119
129
|
break;
|
|
120
130
|
case 'middle':
|
|
121
131
|
element.style.borderLeft = inputStyles.border;
|
|
122
|
-
element.style.
|
|
132
|
+
element.style.borderRightStyle = 'solid';
|
|
133
|
+
element.style.borderRightWidth = '1px';
|
|
134
|
+
element.style.borderRightColor = 'transparent';
|
|
123
135
|
break;
|
|
124
136
|
case 'right':
|
|
125
137
|
element.style.borderLeft = inputStyles.border;
|
|
@@ -132,7 +144,10 @@ export class Tokenizer {
|
|
|
132
144
|
element.style.border = inputStyles.border;
|
|
133
145
|
element.style.borderRadius = inputStyles.borderRadius;
|
|
134
146
|
}
|
|
135
|
-
|
|
147
|
+
if (!this.focusHandlerElements.has(element)) {
|
|
148
|
+
addFocusHandlers(element, styles, position);
|
|
149
|
+
this.focusHandlerElements.add(element);
|
|
150
|
+
}
|
|
136
151
|
}
|
|
137
152
|
generateFieldIds(containerId) {
|
|
138
153
|
return {
|
|
@@ -141,9 +156,10 @@ export class Tokenizer {
|
|
|
141
156
|
cvvId: `${containerId}-cvv`,
|
|
142
157
|
};
|
|
143
158
|
}
|
|
144
|
-
static create(
|
|
159
|
+
static create(rawGateway, container, config) {
|
|
145
160
|
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
-
|
|
161
|
+
const gateway = normalizeGateway(rawGateway);
|
|
162
|
+
switch (gateway.backendName) {
|
|
147
163
|
case 'spreedly': {
|
|
148
164
|
const { SpreedlyTokenizer } = yield import('./SpreedlyTokenizer');
|
|
149
165
|
return SpreedlyTokenizer.create(gateway, container, config);
|
|
@@ -157,7 +173,7 @@ export class Tokenizer {
|
|
|
157
173
|
return PayPalTokenizer.create(gateway, container, config);
|
|
158
174
|
}
|
|
159
175
|
default:
|
|
160
|
-
throw new Error(`Unsupported payment backend: ${gateway.
|
|
176
|
+
throw new Error(`Unsupported payment backend: ${gateway.backendName}`);
|
|
161
177
|
}
|
|
162
178
|
});
|
|
163
179
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
export function normalizeGateway(input) {
|
|
13
|
+
if (!input) {
|
|
14
|
+
throw new Error('Gateway is required but received ' + String(input));
|
|
15
|
+
}
|
|
16
|
+
if (input.backendName !== undefined)
|
|
17
|
+
return input;
|
|
18
|
+
const _a = input.config || {}, { environment_key, base_url, merchant_id } = _a, extraConfigKeys = __rest(_a, ["environment_key", "base_url", "merchant_id"]);
|
|
19
|
+
return {
|
|
20
|
+
id: input.id,
|
|
21
|
+
backendName: input.backend_name,
|
|
22
|
+
gatewayType: input.gateway_type,
|
|
23
|
+
name: input.name,
|
|
24
|
+
config: input.config
|
|
25
|
+
? Object.assign({ environmentKey: environment_key, baseUrl: base_url, merchantId: merchant_id }, extraConfigKeys) : undefined,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -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 };
|
|
@@ -4,4 +4,5 @@ export { SpreedlyTokenizer } from './SpreedlyTokenizer';
|
|
|
4
4
|
export { CardConnectTokenizer } from './CardConnectTokenizer';
|
|
5
5
|
export { PayPalTokenizer } from './PayPalTokenizer';
|
|
6
6
|
export { TokenizationError, } from './types';
|
|
7
|
+
export { normalizeGateway } from './gateway-utils';
|
|
7
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,13 +25,16 @@ 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
|
-
|
|
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();
|
|
31
33
|
}
|
|
32
34
|
catch (error) {
|
|
33
|
-
|
|
35
|
+
const isNetworkError = error instanceof TypeError && error.message.includes('fetch');
|
|
36
|
+
const isServerError = error instanceof Error && error.message.includes('failed: 5');
|
|
37
|
+
if (isNetworkError || isServerError) {
|
|
34
38
|
yield new Promise((resolve) => setTimeout(resolve, 1000));
|
|
35
39
|
return makeRequest();
|
|
36
40
|
}
|
|
@@ -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;
|
|
@@ -27,16 +27,35 @@ export const DEFAULT_UNIFIED_STYLES = {
|
|
|
27
27
|
flexWrap: 'nowrap',
|
|
28
28
|
rowGap: '1rem',
|
|
29
29
|
},
|
|
30
|
+
twoLine: {
|
|
31
|
+
padding: '',
|
|
32
|
+
fontSize: '',
|
|
33
|
+
textAlign: '',
|
|
34
|
+
},
|
|
35
|
+
label: {
|
|
36
|
+
show: false,
|
|
37
|
+
fontSize: '0.875rem',
|
|
38
|
+
fontWeight: 'bold',
|
|
39
|
+
fontFamily: '',
|
|
40
|
+
color: '#333',
|
|
41
|
+
marginBottom: '0.25rem',
|
|
42
|
+
},
|
|
30
43
|
};
|
|
31
44
|
export function mergeStyles(defaults, userStyles) {
|
|
32
45
|
if (!userStyles)
|
|
33
46
|
return defaults;
|
|
34
|
-
|
|
47
|
+
const merged = {
|
|
35
48
|
input: Object.assign(Object.assign({}, defaults.input), userStyles.input),
|
|
36
49
|
focus: Object.assign(Object.assign({}, defaults.focus), userStyles.focus),
|
|
37
50
|
error: Object.assign(Object.assign({}, defaults.error), userStyles.error),
|
|
38
51
|
container: Object.assign(Object.assign({}, defaults.container), userStyles.container),
|
|
52
|
+
twoLine: Object.assign(Object.assign({}, defaults.twoLine), userStyles.twoLine),
|
|
53
|
+
label: Object.assign(Object.assign({}, defaults.label), userStyles.label),
|
|
39
54
|
};
|
|
55
|
+
if (!merged.label.fontFamily) {
|
|
56
|
+
merged.label.fontFamily = merged.input.fontFamily;
|
|
57
|
+
}
|
|
58
|
+
return merged;
|
|
40
59
|
}
|
|
41
60
|
export function getContainerStylesForLayout(baseStyles, layout = 'single-line') {
|
|
42
61
|
if (layout === 'two-line') {
|
|
@@ -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;
|
|
@@ -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,12 +47,69 @@ 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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
case 'middle':
|
|
57
|
+
element.style.borderLeft = styles.input.border;
|
|
58
|
+
element.style.borderRightStyle = 'solid';
|
|
59
|
+
element.style.borderRightWidth = '1px';
|
|
60
|
+
element.style.borderRightColor = 'transparent';
|
|
61
|
+
break;
|
|
62
|
+
case 'right':
|
|
63
|
+
element.style.borderLeft = styles.input.border;
|
|
64
|
+
element.style.borderRight = styles.input.border;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
element.style.border = styles.input.border;
|
|
70
|
+
}
|
|
71
|
+
element.style.outline = '';
|
|
72
|
+
element.style.boxShadow = '';
|
|
53
73
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur();
|
|
54
74
|
});
|
|
55
75
|
}
|
|
76
|
+
export function createFieldLabel(text, forId, styles) {
|
|
77
|
+
const label = document.createElement('label');
|
|
78
|
+
label.htmlFor = forId;
|
|
79
|
+
label.textContent = text;
|
|
80
|
+
label.style.display = styles.label.show ? 'block' : 'none';
|
|
81
|
+
label.style.fontSize = styles.label.fontSize;
|
|
82
|
+
label.style.fontWeight = styles.label.fontWeight;
|
|
83
|
+
label.style.fontFamily = styles.label.fontFamily;
|
|
84
|
+
label.style.color = styles.label.color;
|
|
85
|
+
label.style.marginBottom = styles.label.marginBottom;
|
|
86
|
+
return label;
|
|
87
|
+
}
|
|
88
|
+
export function wrapFieldWithLabel(field, labelText, styles) {
|
|
89
|
+
if (!styles.label.show)
|
|
90
|
+
return field;
|
|
91
|
+
const wrapper = document.createElement('div');
|
|
92
|
+
wrapper.style.display = 'flex';
|
|
93
|
+
wrapper.style.flexDirection = 'column';
|
|
94
|
+
if (field.style.flex) {
|
|
95
|
+
wrapper.style.flex = field.style.flex;
|
|
96
|
+
field.style.flex = '';
|
|
97
|
+
}
|
|
98
|
+
if (field.style.minWidth) {
|
|
99
|
+
wrapper.style.minWidth = field.style.minWidth;
|
|
100
|
+
}
|
|
101
|
+
if (field.style.maxWidth) {
|
|
102
|
+
wrapper.style.maxWidth = field.style.maxWidth;
|
|
103
|
+
}
|
|
104
|
+
if (field.style.flexBasis) {
|
|
105
|
+
wrapper.style.flexBasis = field.style.flexBasis;
|
|
106
|
+
field.style.flexBasis = '';
|
|
107
|
+
}
|
|
108
|
+
const label = createFieldLabel(labelText, field.id, styles);
|
|
109
|
+
wrapper.appendChild(label);
|
|
110
|
+
wrapper.appendChild(field);
|
|
111
|
+
return wrapper;
|
|
112
|
+
}
|
|
56
113
|
export function createFieldContainer(id, flex, minWidth, maxWidth) {
|
|
57
114
|
const div = document.createElement('div');
|
|
58
115
|
div.id = id;
|
|
@@ -137,3 +194,19 @@ export function formatCanadianRoutingNumber(institutionNumber, transitNumber) {
|
|
|
137
194
|
const transit = transitNumber.replace(/\D/g, '').padStart(5, '0');
|
|
138
195
|
return '0' + institution + transit;
|
|
139
196
|
}
|
|
197
|
+
export function cssLengthToPixels(value) {
|
|
198
|
+
const num = parseFloat(value);
|
|
199
|
+
if (isNaN(num)) {
|
|
200
|
+
console.warn(`[cssLengthToPixels] Cannot parse "${value}", defaulting to 14px`);
|
|
201
|
+
return 14;
|
|
202
|
+
}
|
|
203
|
+
if (value.endsWith('rem'))
|
|
204
|
+
return num * 16;
|
|
205
|
+
if (value.endsWith('pt'))
|
|
206
|
+
return num * 1.333;
|
|
207
|
+
if (value.endsWith('px') || !value.match(/[a-z%]/i))
|
|
208
|
+
return num;
|
|
209
|
+
console.warn(`[cssLengthToPixels] Unsupported unit in "${value}". ` +
|
|
210
|
+
`Only px, rem, and pt are supported. Using ${num}px as approximation.`);
|
|
211
|
+
return num;
|
|
212
|
+
}
|
|
@@ -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
|
-
|
|
6
|
-
|
|
6
|
+
backendName: BackendName;
|
|
7
|
+
gatewayType?: string;
|
|
7
8
|
name: string;
|
|
8
9
|
config?: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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' | '
|
|
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;
|
package/dist/esm/typeAdapters.js
CHANGED
|
@@ -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 (
|
|
109
|
-
donationOptions[key] =
|
|
110
|
-
delete
|
|
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:
|
|
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;
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -53,7 +53,8 @@ export type ACHAccount = {
|
|
|
53
53
|
accountHolderType: 'personal' | 'business';
|
|
54
54
|
accountType: 'checking' | 'savings';
|
|
55
55
|
};
|
|
56
|
-
|
|
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
|
-
|
|
278
|
-
|
|
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/dist/idonate-client.js
CHANGED
|
@@ -149,10 +149,10 @@ class iDonateClient {
|
|
|
149
149
|
if (!this.allowTransaction) {
|
|
150
150
|
throw new Error('Wow, that was fast - try again');
|
|
151
151
|
}
|
|
152
|
-
|
|
153
|
-
donation
|
|
154
|
-
|
|
155
|
-
const payload = (0, typeAdapters_1.buildCashPaymentPayload)(this.organizationId,
|
|
152
|
+
const donationWithEmbed = donation.embedId
|
|
153
|
+
? donation
|
|
154
|
+
: Object.assign(Object.assign({}, donation), { embedId: this.embedId });
|
|
155
|
+
const payload = (0, typeAdapters_1.buildCashPaymentPayload)(this.organizationId, donationWithEmbed);
|
|
156
156
|
const fetchCall = (clearanceToken) => fetch(`${this.config.embedApiBaseUrl}/donate/cash-payment`, {
|
|
157
157
|
method: 'POST',
|
|
158
158
|
headers: Object.assign(Object.assign(Object.assign({}, constants_1.CLIENT_HEADERS), (clearanceToken ? { 'cf-validation-token': clearanceToken } : {})), { 'User-Agent': constants_1.CLIENT_HEADERS['User-Agent'] + ' source:' + this.config.client }),
|
|
@@ -180,10 +180,10 @@ class iDonateClient {
|
|
|
180
180
|
});
|
|
181
181
|
}
|
|
182
182
|
createPaymentMethod(paymentMethod) {
|
|
183
|
-
|
|
184
|
-
paymentMethod
|
|
185
|
-
|
|
186
|
-
return shared.createPaymentMethod(
|
|
183
|
+
const pmWithEmbed = paymentMethod.embedId
|
|
184
|
+
? paymentMethod
|
|
185
|
+
: Object.assign(Object.assign({}, paymentMethod), { embedId: this.embedId });
|
|
186
|
+
return shared.createPaymentMethod(pmWithEmbed, this.config);
|
|
187
187
|
}
|
|
188
188
|
setOrganizationId(organizationId) {
|
|
189
189
|
this.currentOrganizationId = organizationId;
|
|
@@ -195,7 +195,16 @@ class iDonateClient {
|
|
|
195
195
|
return new Promise((resolve, reject) => {
|
|
196
196
|
setTimeout(() => {
|
|
197
197
|
let pollHandle;
|
|
198
|
+
let attempts = 0;
|
|
199
|
+
const maxAttempts = 90;
|
|
198
200
|
pollHandle = setInterval(() => {
|
|
201
|
+
attempts++;
|
|
202
|
+
if (attempts > maxAttempts) {
|
|
203
|
+
clearInterval(pollHandle);
|
|
204
|
+
pollHandle = null;
|
|
205
|
+
reject(new types_1.ClientError('Donation processing timed out. Please check your email for a receipt or contact support.'));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
199
208
|
fetch(`${this.config.embedApiBaseUrl}/donate/cash-payment/${donationId}/payment_status`, {
|
|
200
209
|
method: 'GET',
|
|
201
210
|
headers: {
|
|
@@ -212,6 +221,7 @@ class iDonateClient {
|
|
|
212
221
|
}
|
|
213
222
|
if (response.error) {
|
|
214
223
|
reject(new types_1.ClientError(response.error));
|
|
224
|
+
return;
|
|
215
225
|
}
|
|
216
226
|
resolve((0, typeAdapters_1.buildDonationResult)({
|
|
217
227
|
_raw_response: Object.assign({ campaign: null, designation: {}, donor: {}, form_data: {}, id: null, schedule: {}, transaction: {} }, response),
|
package/dist/recaptcha.d.ts
CHANGED
|
@@ -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>;
|
package/dist/recaptcha.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.RecaptchaElement = void 0;
|
|
4
13
|
exports.injectScript = injectScript;
|
|
5
14
|
exports.wrapElement = wrapElement;
|
|
15
|
+
exports.wrapElementWithThrow = wrapElementWithThrow;
|
|
6
16
|
function resolveLib() {
|
|
7
17
|
const startWait = new Date();
|
|
8
18
|
return new Promise((resolve, reject) => {
|
|
@@ -57,9 +67,16 @@ class RecaptchaElement {
|
|
|
57
67
|
this.widgetId = lib.render(this.container, Object.assign(Object.assign({}, this.params), { callback: (token) => {
|
|
58
68
|
var _a;
|
|
59
69
|
this.resolvedToken = token;
|
|
60
|
-
(_a = this.executeResolveQueue.
|
|
70
|
+
(_a = this.executeResolveQueue.shift()) === null || _a === void 0 ? void 0 : _a.resolve(token);
|
|
61
71
|
}, 'expired-callback': () => {
|
|
62
72
|
this.resolvedToken = undefined;
|
|
73
|
+
}, 'error-callback': () => {
|
|
74
|
+
var _a;
|
|
75
|
+
this.resolvedToken = undefined;
|
|
76
|
+
const error = new Error('reCAPTCHA encountered an error. Please try again.');
|
|
77
|
+
while (this.executeResolveQueue.length > 0) {
|
|
78
|
+
(_a = this.executeResolveQueue.shift()) === null || _a === void 0 ? void 0 : _a.reject(error);
|
|
79
|
+
}
|
|
63
80
|
} }));
|
|
64
81
|
});
|
|
65
82
|
}
|
|
@@ -73,7 +90,7 @@ class RecaptchaElement {
|
|
|
73
90
|
? resolve(response)
|
|
74
91
|
: reject(new Error('checkbox recaptcha is not checked'));
|
|
75
92
|
}
|
|
76
|
-
this.executeResolveQueue.push(resolve);
|
|
93
|
+
this.executeResolveQueue.push({ resolve, reject });
|
|
77
94
|
if (this.resolvedToken !== undefined) {
|
|
78
95
|
this.resolvedToken = undefined;
|
|
79
96
|
lib.reset(this.widgetId);
|
|
@@ -93,3 +110,11 @@ function wrapElement(container, sitekey, extraParams) {
|
|
|
93
110
|
captcha.render();
|
|
94
111
|
return captcha;
|
|
95
112
|
}
|
|
113
|
+
function wrapElementWithThrow(container, sitekey, extraParams) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
const params = Object.assign(Object.assign({}, (extraParams || {})), { sitekey });
|
|
116
|
+
const captcha = new RecaptchaElement(container, params);
|
|
117
|
+
yield captcha.render();
|
|
118
|
+
return captcha;
|
|
119
|
+
});
|
|
120
|
+
}
|
package/dist/shared.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.fetchEmbedConfig = fetchEmbedConfig;
|
|
|
5
5
|
const typeAdapters_1 = require("./typeAdapters");
|
|
6
6
|
const constants_1 = require("./constants");
|
|
7
7
|
const util_1 = require("./util");
|
|
8
|
+
const gateway_utils_1 = require("./tokenize/gateway-utils");
|
|
8
9
|
function createPaymentMethod(paymentMethod, config) {
|
|
9
10
|
const payload = (0, typeAdapters_1.buildCreatePaymentMethodPayload)(paymentMethod);
|
|
10
11
|
return fetch(`${config.embedApiBaseUrl}/payment/payment-methods`, {
|
|
@@ -21,5 +22,12 @@ function fetchEmbedConfig(embedId, config) {
|
|
|
21
22
|
headers: constants_1.CLIENT_HEADERS,
|
|
22
23
|
})
|
|
23
24
|
.then((response) => (0, util_1.parseResponse)(response, { throwErrors: true }))
|
|
24
|
-
.then((response) =>
|
|
25
|
+
.then((response) => {
|
|
26
|
+
const config = response._raw_response.result;
|
|
27
|
+
if (config.available_gateways) {
|
|
28
|
+
config.available_gateways =
|
|
29
|
+
config.available_gateways.map(gateway_utils_1.normalizeGateway);
|
|
30
|
+
}
|
|
31
|
+
return config;
|
|
32
|
+
});
|
|
25
33
|
}
|