@idonatedev/idonate-sdk 1.1.0-dev0 → 1.1.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.
- package/dist/config-handler.js +3 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +6 -2
- package/dist/idonate-client.d.ts +5 -1
- package/dist/idonate-client.js +5 -0
- package/dist/tokenize/CardConnectTokenizer.d.ts +9 -1
- package/dist/tokenize/CardConnectTokenizer.js +239 -146
- package/dist/tokenize/SpreedlyTokenizer.d.ts +10 -3
- package/dist/tokenize/SpreedlyTokenizer.js +382 -190
- package/dist/tokenize/Tokenizer.d.ts +6 -1
- package/dist/tokenize/index.d.ts +1 -1
- package/dist/tokenize/styles.d.ts +1 -0
- package/dist/tokenize/styles.js +9 -0
- package/dist/tokenize/types.d.ts +4 -3
- package/package.json +10 -3
- package/umd/idonate-sdk.js +1 -1
package/dist/config-handler.js
CHANGED
|
@@ -26,6 +26,9 @@ class ConfigHandler {
|
|
|
26
26
|
if (options.overrideApplePayUrl) {
|
|
27
27
|
this.applePayUrl = options.overrideApplePayUrl;
|
|
28
28
|
}
|
|
29
|
+
if (options.overrideCardConnectBaseUrl) {
|
|
30
|
+
this.cardConnectBaseUrl = options.overrideCardConnectBaseUrl;
|
|
31
|
+
}
|
|
29
32
|
this.pcScriptBase = options.pcScriptBase || constants_1.FALLBACK_PC_SCRIPT_URL;
|
|
30
33
|
this.pcScriptId = options.pcScriptId || constants_1.FALLBACK_PC_SCRIPT_ID;
|
|
31
34
|
this.turnstileCdnUrl =
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SDK_VERSION
|
|
1
|
+
export declare const SDK_VERSION: string;
|
|
2
2
|
export declare const PRODUCTION_BASE_URL = "https://secure-api.idonate.com";
|
|
3
3
|
export declare const SANDBOX_BASE_URL = "https://api.qa-idonate.com";
|
|
4
4
|
export declare const PRODUCTION_CARD_CONNECT_BASE_URL = "https://boltgw.cardconnect.com:8443";
|
package/dist/constants.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
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
|
-
|
|
7
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
8
|
+
exports.SDK_VERSION = package_json_1.default.version;
|
|
5
9
|
exports.PRODUCTION_BASE_URL = 'https://secure-api.idonate.com';
|
|
6
10
|
exports.SANDBOX_BASE_URL = 'https://api.qa-idonate.com';
|
|
7
11
|
exports.PRODUCTION_CARD_CONNECT_BASE_URL = 'https://boltgw.cardconnect.com:8443';
|
|
@@ -79,6 +83,6 @@ input#cccvvfield {
|
|
|
79
83
|
}
|
|
80
84
|
`.replace(/\s+/gi, ' ');
|
|
81
85
|
exports.CLIENT_HEADERS = {
|
|
82
|
-
'User-Agent': navigator.userAgent +
|
|
86
|
+
'User-Agent': navigator.userAgent + ` idonate-sdk@${package_json_1.default.version}`,
|
|
83
87
|
'Content-Type': 'application/json',
|
|
84
88
|
};
|
package/dist/idonate-client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClientOptions, CreatePaymentMethodRequest, CreatePaymentMethodResult, CreateDonationRequest, CreateDonationResult, TokenizeApplePayResult } from './types';
|
|
1
|
+
import { ClientOptions, Contact, Address, CreatePaymentMethodRequest, CreatePaymentMethodResult, CreateDonationRequest, CreateDonationResult, TokenizeApplePayResult } from './types';
|
|
2
2
|
import ConfigHandler from './config-handler';
|
|
3
3
|
import { Tokenizer, PaymentMethodType, PaymentGateway, TokenizerContainer } from './tokenize';
|
|
4
4
|
export default class iDonateClient {
|
|
@@ -20,5 +20,9 @@ export default class iDonateClient {
|
|
|
20
20
|
waitForDonationResult(donationId: string, afterEachCheck?: () => void): Promise<any>;
|
|
21
21
|
tokenizeCardConnectApplePay(applePayRequest: Partial<ApplePayJS.ApplePayPaymentRequest>): Promise<TokenizeApplePayResult>;
|
|
22
22
|
createTokenizer(gateway: PaymentGateway, container: TokenizerContainer): Promise<Tokenizer>;
|
|
23
|
+
tokenizeSpreedlyPayPal(data: {
|
|
24
|
+
contact: Contact;
|
|
25
|
+
address: Address;
|
|
26
|
+
}): Promise<string>;
|
|
23
27
|
selectGateway(availableGateways: PaymentGateway[], paymentType: PaymentMethodType, preferredGatewayId?: string): PaymentGateway | undefined;
|
|
24
28
|
}
|
package/dist/idonate-client.js
CHANGED
|
@@ -51,6 +51,7 @@ const constants_1 = require("./constants");
|
|
|
51
51
|
const util_1 = require("./util");
|
|
52
52
|
const apple_pay_1 = __importDefault(require("./apple-pay"));
|
|
53
53
|
const config_handler_1 = __importDefault(require("./config-handler"));
|
|
54
|
+
const SpreedlyTokenizer_1 = require("./tokenize/SpreedlyTokenizer");
|
|
54
55
|
const shared = __importStar(require("./shared"));
|
|
55
56
|
const uuid_1 = require("uuid");
|
|
56
57
|
const cloudflare_challenge_handler_1 = require("./cloudflare-challenge-handler");
|
|
@@ -275,9 +276,13 @@ class iDonateClient {
|
|
|
275
276
|
return tokenize_1.Tokenizer.create(gateway, container, {
|
|
276
277
|
organizationId: this.organizationId,
|
|
277
278
|
embedId: this.embedId,
|
|
279
|
+
clientConfig: this.config,
|
|
278
280
|
});
|
|
279
281
|
});
|
|
280
282
|
}
|
|
283
|
+
tokenizeSpreedlyPayPal(data) {
|
|
284
|
+
return SpreedlyTokenizer_1.SpreedlyTokenizer.tokenizePayPal(data, this.config);
|
|
285
|
+
}
|
|
281
286
|
selectGateway(availableGateways, paymentType, preferredGatewayId) {
|
|
282
287
|
if (preferredGatewayId) {
|
|
283
288
|
const preferred = availableGateways.find((g) => g.id === preferredGatewayId);
|
|
@@ -5,6 +5,7 @@ import ConfigHandler from '../config-handler';
|
|
|
5
5
|
export declare class CardConnectTokenizer extends Tokenizer {
|
|
6
6
|
private iframeUrl;
|
|
7
7
|
private containerId;
|
|
8
|
+
private layout;
|
|
8
9
|
private iframe;
|
|
9
10
|
private messageHandler?;
|
|
10
11
|
private expectedOrigin;
|
|
@@ -16,10 +17,14 @@ export declare class CardConnectTokenizer extends Tokenizer {
|
|
|
16
17
|
private accountTypeEl?;
|
|
17
18
|
private enableTestMode;
|
|
18
19
|
private cachedTokenResult?;
|
|
20
|
+
private tokenizationPromise?;
|
|
21
|
+
private tokenizationResolve?;
|
|
22
|
+
private tokenizationReject?;
|
|
19
23
|
private constructor();
|
|
20
|
-
static create(gateway: PaymentGateway, container: TokenizerContainer, config
|
|
24
|
+
static create(gateway: PaymentGateway, container: TokenizerContainer, config: {
|
|
21
25
|
organizationId: string;
|
|
22
26
|
embedId: string;
|
|
27
|
+
clientConfig: ConfigHandler;
|
|
23
28
|
}): Promise<CardConnectTokenizer>;
|
|
24
29
|
private createInternalElements;
|
|
25
30
|
private createCreditCardFields;
|
|
@@ -34,6 +39,9 @@ export declare class CardConnectTokenizer extends Tokenizer {
|
|
|
34
39
|
clear(): void;
|
|
35
40
|
focus(field: 'cardNumber' | 'cvv' | 'expiry' | 'routingNumber' | 'accountNumber'): void;
|
|
36
41
|
destroy(): void;
|
|
42
|
+
hasToken(): boolean;
|
|
43
|
+
getToken(): PaymentToken | null;
|
|
44
|
+
get tokenizationMode(): 'auto' | 'manual';
|
|
37
45
|
private handleMessage;
|
|
38
46
|
private handleValidationMessage;
|
|
39
47
|
private static generateIframeUrl;
|
|
@@ -20,10 +20,11 @@ const styles_1 = require("./styles");
|
|
|
20
20
|
const tokenizer_constants_1 = require("./tokenizer-constants");
|
|
21
21
|
const tokenizer_utils_1 = require("./tokenizer-utils");
|
|
22
22
|
class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
23
|
-
constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false) {
|
|
23
|
+
constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false, layout = 'single-line') {
|
|
24
24
|
super();
|
|
25
25
|
this.iframeUrl = iframeUrl;
|
|
26
26
|
this.containerId = containerId;
|
|
27
|
+
this.layout = layout;
|
|
27
28
|
this.isReady = false;
|
|
28
29
|
this.enableTestMode = false;
|
|
29
30
|
this.mode = mode;
|
|
@@ -44,14 +45,12 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
44
45
|
if (container.mode === 'bank_account' && container.bankCountry === 'CA') {
|
|
45
46
|
throw new Error('CardConnect does not support Canadian bank accounts');
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
throw new Error('CardConnect base URL not configured');
|
|
50
|
-
}
|
|
48
|
+
let baseUrl = ((_a = gateway.config) === null || _a === void 0 ? void 0 : _a.base_url) || config.clientConfig.cardConnectBaseUrl;
|
|
49
|
+
config.cardConnectBaseUrl = baseUrl;
|
|
51
50
|
const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
|
|
52
51
|
const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, container);
|
|
53
52
|
const iframe = CardConnectTokenizer.createIframe(iframeUrl, mergedStyles);
|
|
54
|
-
const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false);
|
|
53
|
+
const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false, container.layout || 'single-line');
|
|
55
54
|
tokenizer.createInternalElements(container);
|
|
56
55
|
yield tokenizer.init();
|
|
57
56
|
return tokenizer;
|
|
@@ -64,7 +63,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
64
63
|
}
|
|
65
64
|
this.containerEl = containerEl;
|
|
66
65
|
containerEl.innerHTML = '';
|
|
67
|
-
const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
|
|
66
|
+
const mergedStyles = (0, styles_1.getContainerStylesForLayout)((0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling), this.layout);
|
|
68
67
|
Object.assign(containerEl.style, mergedStyles.container);
|
|
69
68
|
if (this.mode === 'bank_account') {
|
|
70
69
|
this.createBankAccountFields(containerEl, mergedStyles);
|
|
@@ -75,34 +74,67 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
75
74
|
}
|
|
76
75
|
createCreditCardFields(containerEl, mergedStyles) {
|
|
77
76
|
this.iframe.style.width = '100%';
|
|
78
|
-
this.
|
|
77
|
+
if (this.layout === 'two-line') {
|
|
78
|
+
const inputHeight = mergedStyles.input.height || '40px';
|
|
79
|
+
const rowGap = mergedStyles.container.rowGap || '1rem';
|
|
80
|
+
this.iframe.style.height = `calc((${inputHeight}) * 2 + ${rowGap})`;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.iframe.style.height = mergedStyles.input.height || '40px';
|
|
84
|
+
}
|
|
79
85
|
this.iframe.style.border = 'none';
|
|
80
86
|
this.iframe.style.display = 'block';
|
|
81
87
|
containerEl.appendChild(this.iframe);
|
|
82
88
|
}
|
|
83
89
|
createBankAccountFields(containerEl, mergedStyles) {
|
|
84
90
|
this.iframe.style.display = 'none';
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
if (this.layout === 'two-line') {
|
|
92
|
+
this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
|
|
93
|
+
Object.assign(this.accountTypeEl.style, {
|
|
94
|
+
flex: '1',
|
|
95
|
+
minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
|
|
96
|
+
});
|
|
97
|
+
this.applyInputStyles(this.accountTypeEl, mergedStyles, 'left');
|
|
98
|
+
containerEl.appendChild(this.accountTypeEl);
|
|
99
|
+
this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
|
|
100
|
+
Object.assign(this.routingNumberEl.style, {
|
|
101
|
+
flex: '1',
|
|
102
|
+
minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
|
|
103
|
+
});
|
|
104
|
+
this.applyInputStyles(this.routingNumberEl, mergedStyles, 'right');
|
|
105
|
+
containerEl.appendChild(this.routingNumberEl);
|
|
106
|
+
this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
|
|
107
|
+
Object.assign(this.accountNumberEl.style, {
|
|
108
|
+
flex: '1',
|
|
109
|
+
flexBasis: '100%',
|
|
110
|
+
minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
|
|
111
|
+
});
|
|
112
|
+
this.applyInputStyles(this.accountNumberEl, mergedStyles);
|
|
113
|
+
containerEl.appendChild(this.accountNumberEl);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
|
|
117
|
+
Object.assign(this.routingNumberEl.style, {
|
|
118
|
+
flex: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.flex,
|
|
119
|
+
minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
|
|
120
|
+
});
|
|
121
|
+
this.applyInputStyles(this.routingNumberEl, mergedStyles, 'left');
|
|
122
|
+
containerEl.appendChild(this.routingNumberEl);
|
|
123
|
+
this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
|
|
124
|
+
Object.assign(this.accountNumberEl.style, {
|
|
125
|
+
flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.flex,
|
|
126
|
+
minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
|
|
127
|
+
});
|
|
128
|
+
this.applyInputStyles(this.accountNumberEl, mergedStyles, 'middle');
|
|
129
|
+
containerEl.appendChild(this.accountNumberEl);
|
|
130
|
+
this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
|
|
131
|
+
Object.assign(this.accountTypeEl.style, {
|
|
132
|
+
flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.flex,
|
|
133
|
+
minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
|
|
134
|
+
});
|
|
135
|
+
this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
|
|
136
|
+
containerEl.appendChild(this.accountTypeEl);
|
|
137
|
+
}
|
|
106
138
|
}
|
|
107
139
|
init() {
|
|
108
140
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -142,7 +174,6 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
142
174
|
clearTimeout(timeout);
|
|
143
175
|
this.isReady = true;
|
|
144
176
|
if (this.enableTestMode && this.mode === 'credit_card') {
|
|
145
|
-
console.log('CardConnect test mode enabled - manual entry required for card fields');
|
|
146
177
|
}
|
|
147
178
|
this.emit('ready');
|
|
148
179
|
resolve();
|
|
@@ -159,6 +190,12 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
159
190
|
if (!this.isReady) {
|
|
160
191
|
throw new Error('Tokenizer not initialized');
|
|
161
192
|
}
|
|
193
|
+
if (this.mode === 'credit_card' && this.hasToken()) {
|
|
194
|
+
const cachedToken = this.getToken();
|
|
195
|
+
if (cachedToken) {
|
|
196
|
+
return cachedToken;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
162
199
|
if (this.mode === 'bank_account' || this.isBankAccountData(paymentData)) {
|
|
163
200
|
return this.tokenizeBankAccountInternal(paymentData);
|
|
164
201
|
}
|
|
@@ -177,27 +214,25 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
177
214
|
provider: 'cardconnect',
|
|
178
215
|
};
|
|
179
216
|
}
|
|
180
|
-
|
|
217
|
+
if (this.tokenizationPromise) {
|
|
218
|
+
return this.tokenizationPromise;
|
|
219
|
+
}
|
|
220
|
+
this.tokenizationPromise = new Promise((resolve, reject) => {
|
|
221
|
+
this.tokenizationResolve = resolve;
|
|
222
|
+
this.tokenizationReject = reject;
|
|
181
223
|
const timeout = setTimeout(() => {
|
|
224
|
+
this.tokenizationPromise = undefined;
|
|
225
|
+
this.tokenizationResolve = undefined;
|
|
226
|
+
this.tokenizationReject = undefined;
|
|
182
227
|
reject(new types_1.TokenizationError('Tokenization timeout - ensure all card fields are filled in iframe', 'TIMEOUT'));
|
|
183
228
|
}, tokenizer_constants_1.TOKENIZE_TIMEOUT);
|
|
184
229
|
const tokenizationHandler = (data) => {
|
|
185
230
|
clearTimeout(timeout);
|
|
186
231
|
this.off('tokenization', tokenizationHandler);
|
|
187
|
-
if (data.errorCode === '0') {
|
|
188
|
-
resolve({
|
|
189
|
-
token: data.token,
|
|
190
|
-
lastFour: data.token.slice(-4),
|
|
191
|
-
cardType: this.normalizeCardType('unknown'),
|
|
192
|
-
provider: 'cardconnect',
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
reject(new types_1.TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
|
|
197
|
-
}
|
|
198
232
|
};
|
|
199
233
|
this.on('tokenization', tokenizationHandler);
|
|
200
234
|
});
|
|
235
|
+
return this.tokenizationPromise;
|
|
201
236
|
});
|
|
202
237
|
}
|
|
203
238
|
tokenizeBankAccountInternal(bankData) {
|
|
@@ -245,28 +280,64 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
245
280
|
validateCardInternal() {
|
|
246
281
|
return __awaiter(this, void 0, void 0, function* () {
|
|
247
282
|
const errors = [];
|
|
248
|
-
if (this.currentValidationState.cardNumber
|
|
249
|
-
|
|
250
|
-
|
|
283
|
+
if (this.currentValidationState.cardNumber) {
|
|
284
|
+
if (this.currentValidationState.cardNumber.isEmpty) {
|
|
285
|
+
errors.push({
|
|
286
|
+
field: 'cardNumber',
|
|
287
|
+
message: 'Card number is required',
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else if (!this.currentValidationState.cardNumber.isValid) {
|
|
291
|
+
errors.push({
|
|
292
|
+
field: 'cardNumber',
|
|
293
|
+
message: 'Invalid card number',
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
251
298
|
errors.push({
|
|
252
299
|
field: 'cardNumber',
|
|
253
|
-
message: '
|
|
300
|
+
message: 'Card number is required',
|
|
254
301
|
});
|
|
255
302
|
}
|
|
256
|
-
if (this.currentValidationState.expiry
|
|
257
|
-
|
|
258
|
-
|
|
303
|
+
if (this.currentValidationState.expiry) {
|
|
304
|
+
if (this.currentValidationState.expiry.isEmpty) {
|
|
305
|
+
errors.push({
|
|
306
|
+
field: 'expiry',
|
|
307
|
+
message: 'Expiry date is required',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
else if (!this.currentValidationState.expiry.isValid) {
|
|
311
|
+
errors.push({
|
|
312
|
+
field: 'expiry',
|
|
313
|
+
message: 'Invalid expiry date',
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
259
318
|
errors.push({
|
|
260
319
|
field: 'expiry',
|
|
261
|
-
message: '
|
|
320
|
+
message: 'Expiry date is required',
|
|
262
321
|
});
|
|
263
322
|
}
|
|
264
|
-
if (this.currentValidationState.cvv
|
|
265
|
-
|
|
266
|
-
|
|
323
|
+
if (this.currentValidationState.cvv) {
|
|
324
|
+
if (this.currentValidationState.cvv.isEmpty) {
|
|
325
|
+
errors.push({
|
|
326
|
+
field: 'cvv',
|
|
327
|
+
message: 'CVV is required',
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
else if (!this.currentValidationState.cvv.isValid) {
|
|
331
|
+
errors.push({
|
|
332
|
+
field: 'cvv',
|
|
333
|
+
message: 'Invalid CVV',
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
267
338
|
errors.push({
|
|
268
339
|
field: 'cvv',
|
|
269
|
-
message: '
|
|
340
|
+
message: 'CVV is required',
|
|
270
341
|
});
|
|
271
342
|
}
|
|
272
343
|
return {
|
|
@@ -369,12 +440,66 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
369
440
|
}
|
|
370
441
|
this.eventHandlers.clear();
|
|
371
442
|
}
|
|
443
|
+
hasToken() {
|
|
444
|
+
var _a, _b;
|
|
445
|
+
if (this.mode === 'credit_card') {
|
|
446
|
+
return (((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0' &&
|
|
447
|
+
!!((_b = this.cachedTokenResult) === null || _b === void 0 ? void 0 : _b.token));
|
|
448
|
+
}
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
getToken() {
|
|
452
|
+
var _a;
|
|
453
|
+
if (this.mode === 'credit_card' &&
|
|
454
|
+
((_a = this.cachedTokenResult) === null || _a === void 0 ? void 0 : _a.errorCode) === '0') {
|
|
455
|
+
return {
|
|
456
|
+
token: this.cachedTokenResult.token,
|
|
457
|
+
lastFour: this.cachedTokenResult.token.slice(-4),
|
|
458
|
+
cardType: this.normalizeCardType('unknown'),
|
|
459
|
+
provider: 'cardconnect',
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
get tokenizationMode() {
|
|
465
|
+
return this.mode === 'credit_card' ? 'auto' : 'manual';
|
|
466
|
+
}
|
|
372
467
|
handleMessage(event) {
|
|
373
468
|
try {
|
|
374
469
|
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
|
|
375
470
|
if (data.token && data.errorCode !== undefined) {
|
|
376
471
|
this.cachedTokenResult = data;
|
|
377
472
|
this.emit('tokenization', data);
|
|
473
|
+
if (data.errorCode === '0') {
|
|
474
|
+
const token = {
|
|
475
|
+
token: data.token,
|
|
476
|
+
lastFour: data.token.slice(-4),
|
|
477
|
+
cardType: this.normalizeCardType('unknown'),
|
|
478
|
+
provider: 'cardconnect',
|
|
479
|
+
};
|
|
480
|
+
if (this.tokenizationResolve) {
|
|
481
|
+
this.tokenizationResolve(token);
|
|
482
|
+
this.tokenizationPromise = undefined;
|
|
483
|
+
this.tokenizationResolve = undefined;
|
|
484
|
+
this.tokenizationReject = undefined;
|
|
485
|
+
}
|
|
486
|
+
this.currentValidationState = {
|
|
487
|
+
isValid: true,
|
|
488
|
+
cardNumber: { isValid: true, isEmpty: false },
|
|
489
|
+
cvv: { isValid: true, isEmpty: false },
|
|
490
|
+
expiry: { isValid: true, isEmpty: false },
|
|
491
|
+
};
|
|
492
|
+
this.emit('validation', { isValid: true });
|
|
493
|
+
this.emit('tokenReady', token);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
if (this.tokenizationReject) {
|
|
497
|
+
this.tokenizationReject(new types_1.TokenizationError(data.errorMessage || 'Tokenization failed', data.errorCode || 'UNKNOWN'));
|
|
498
|
+
this.tokenizationPromise = undefined;
|
|
499
|
+
this.tokenizationResolve = undefined;
|
|
500
|
+
this.tokenizationReject = undefined;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
378
503
|
}
|
|
379
504
|
if (data.event === 'validation' || data.validationError !== undefined) {
|
|
380
505
|
this.handleValidationMessage(data);
|
|
@@ -397,38 +522,23 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
397
522
|
this.currentValidationState.cardNumber = {
|
|
398
523
|
isValid: false,
|
|
399
524
|
isEmpty: false,
|
|
400
|
-
error: data.validationError,
|
|
401
525
|
};
|
|
402
526
|
}
|
|
403
527
|
else if (errorLower.includes('cvv') ||
|
|
404
528
|
errorLower.includes('security')) {
|
|
405
|
-
this.currentValidationState.cvv = {
|
|
406
|
-
isValid: false,
|
|
407
|
-
isEmpty: false,
|
|
408
|
-
error: data.validationError,
|
|
409
|
-
};
|
|
529
|
+
this.currentValidationState.cvv = { isValid: false, isEmpty: false };
|
|
410
530
|
}
|
|
411
531
|
else if (errorLower.includes('expir') ||
|
|
412
|
-
errorLower.includes('exp') ||
|
|
413
532
|
errorLower.includes('month') ||
|
|
414
533
|
errorLower.includes('year')) {
|
|
415
|
-
this.currentValidationState.expiry = {
|
|
416
|
-
isValid: false,
|
|
417
|
-
isEmpty: false,
|
|
418
|
-
error: data.validationError,
|
|
419
|
-
};
|
|
534
|
+
this.currentValidationState.expiry = { isValid: false, isEmpty: false };
|
|
420
535
|
}
|
|
421
|
-
|
|
422
|
-
else if (data.event === 'validation') {
|
|
536
|
+
this.emit('error', new types_1.TokenizationError(data.validationError));
|
|
423
537
|
}
|
|
424
538
|
this.currentValidationState.isValid =
|
|
425
539
|
((_b = (_a = this.currentValidationState.cardNumber) === null || _a === void 0 ? void 0 : _a.isValid) !== null && _b !== void 0 ? _b : false) &&
|
|
426
540
|
((_d = (_c = this.currentValidationState.cvv) === null || _c === void 0 ? void 0 : _c.isValid) !== null && _d !== void 0 ? _d : false) &&
|
|
427
541
|
((_f = (_e = this.currentValidationState.expiry) === null || _e === void 0 ? void 0 : _e.isValid) !== null && _f !== void 0 ? _f : false);
|
|
428
|
-
this.emit('validation', this.currentValidationState);
|
|
429
|
-
if (data.validationError) {
|
|
430
|
-
this.emit('error', new types_1.TokenizationError(data.validationError));
|
|
431
|
-
}
|
|
432
542
|
}
|
|
433
543
|
static generateIframeUrl(baseUrl, container) {
|
|
434
544
|
const params = new URLSearchParams({
|
|
@@ -436,20 +546,28 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
436
546
|
enhancedresponse: 'true',
|
|
437
547
|
useexpiry: 'true',
|
|
438
548
|
usecvv: 'true',
|
|
439
|
-
orientation: 'horizontal',
|
|
440
549
|
formatinput: 'true',
|
|
441
550
|
unique: 'true',
|
|
442
551
|
norsa: 'true',
|
|
443
552
|
placeholder: 'Card Number *',
|
|
444
|
-
placeholdermonth: 'MM',
|
|
445
|
-
placeholderyear: 'YYYY',
|
|
446
553
|
placeholdercvv: 'CVV',
|
|
447
554
|
invalidcreditcardevent: 'true',
|
|
448
555
|
invalidexpiry: 'true',
|
|
449
556
|
invalidcvv: 'true',
|
|
450
557
|
});
|
|
558
|
+
if (container.layout === 'two-line') {
|
|
559
|
+
params.set('useexpiryfield', 'true');
|
|
560
|
+
params.set('orientation', 'horizontal');
|
|
561
|
+
params.set('placeholdermonth', 'MM');
|
|
562
|
+
params.set('placeholderyear', 'YYYY');
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
params.set('orientation', 'horizontal');
|
|
566
|
+
params.set('placeholdermonth', 'MM');
|
|
567
|
+
params.set('placeholderyear', 'YYYY');
|
|
568
|
+
}
|
|
451
569
|
const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
|
|
452
|
-
const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles);
|
|
570
|
+
const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, container.layout || 'single-line');
|
|
453
571
|
const queryPairs = [];
|
|
454
572
|
params.forEach((value, key) => {
|
|
455
573
|
queryPairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
|
|
@@ -482,13 +600,20 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
482
600
|
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms');
|
|
483
601
|
return iframe;
|
|
484
602
|
}
|
|
485
|
-
static generateCardConnectCss(styles) {
|
|
486
|
-
var _a, _b, _c
|
|
603
|
+
static generateCardConnectCss(styles, layout = 'single-line') {
|
|
604
|
+
var _a, _b, _c;
|
|
487
605
|
const css = [];
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
606
|
+
if (layout === 'two-line') {
|
|
607
|
+
css.push('html,form,body{margin:0;padding:0;}');
|
|
608
|
+
css.push('label{display:none;}');
|
|
609
|
+
css.push('br{display:none;}');
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
css.push('body{margin:0;padding:0;display:flex;align-items:center;}');
|
|
613
|
+
css.push('form{margin:0;padding:0;display:flex;width:100%;align-items:center;}');
|
|
614
|
+
css.push('label{display:none;}');
|
|
615
|
+
css.push('br{display:none;}');
|
|
616
|
+
}
|
|
492
617
|
const isConnected = styles.container.gap === '0';
|
|
493
618
|
const gap = isConnected ? '0' : styles.container.gap || '1rem';
|
|
494
619
|
if (styles.input) {
|
|
@@ -512,73 +637,41 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
|
|
|
512
637
|
css.push(`input{${baseStyles};}`);
|
|
513
638
|
css.push(`select{${baseStyles};}`);
|
|
514
639
|
}
|
|
515
|
-
if (
|
|
516
|
-
|
|
640
|
+
if (layout === 'two-line') {
|
|
641
|
+
css.push('input#ccnumfield{width:100%;display:block;margin-bottom:8px;}');
|
|
642
|
+
css.push('input#ccexpiryfieldmonth{width:20%;}');
|
|
643
|
+
css.push('input#ccexpiryfieldyear{width:24%;}');
|
|
644
|
+
css.push('input#cccvvfield{width:calc(56% - 20px);}');
|
|
517
645
|
if ((_a = styles.input) === null || _a === void 0 ? void 0 : _a.borderRadius) {
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
`border-
|
|
528
|
-
'border-right:none'
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
'border-
|
|
534
|
-
|
|
535
|
-
'border-right:none'
|
|
536
|
-
|
|
537
|
-
css.push(`select#ccexpiryyear{${yearStyles.join(';')};}`);
|
|
538
|
-
const cvvStyles = [
|
|
539
|
-
'width:20%',
|
|
540
|
-
'margin:0',
|
|
541
|
-
'margin-left:-12px',
|
|
542
|
-
];
|
|
543
|
-
if ((_d = styles.input) === null || _d === void 0 ? void 0 : _d.borderRadius) {
|
|
544
|
-
cvvStyles.push(`border-radius:0 ${styles.input.borderRadius} ${styles.input.borderRadius} 0`);
|
|
545
|
-
}
|
|
546
|
-
cvvStyles.push(`border-left:${((_e = styles.input) === null || _e === void 0 ? void 0 : _e.border) || '1px solid #ccc'}`);
|
|
547
|
-
css.push(`input#cccvvfield{${cvvStyles.join(';')};}`);
|
|
646
|
+
css.push(`input{border-radius:${styles.input.borderRadius};}`);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
else if (isConnected) {
|
|
650
|
+
css.push('input#ccnumfield{width:60%;margin:0;}');
|
|
651
|
+
css.push('select#ccexpirymonth{width:10%;margin:0;margin-right:-12px;}');
|
|
652
|
+
css.push('select#ccexpiryyear{width:10%;}');
|
|
653
|
+
css.push('input#cccvvfield{width:20%;margin:0;margin-left:-12px;}');
|
|
654
|
+
if ((_b = styles.input) === null || _b === void 0 ? void 0 : _b.borderRadius) {
|
|
655
|
+
css.push(`input#ccnumfield{border-radius:${styles.input.borderRadius} 0 0 ${styles.input.borderRadius};border-right:none;}`);
|
|
656
|
+
css.push('select#ccexpirymonth{border-radius:0;border-right:none;}');
|
|
657
|
+
css.push('select#ccexpiryyear{border-radius:0;border-right:none;}');
|
|
658
|
+
css.push(`input#cccvvfield{border-radius:0 ${styles.input.borderRadius} ${styles.input.borderRadius} 0;}`);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
css.push('input#ccnumfield{border-right:none;}');
|
|
662
|
+
css.push('select#ccexpirymonth{border-right:none;}');
|
|
663
|
+
css.push('select#ccexpiryyear{border-right:none;}');
|
|
664
|
+
}
|
|
548
665
|
}
|
|
549
666
|
else {
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
cardNumStyles.push(`border-radius:${styles.input.borderRadius}`);
|
|
559
|
-
}
|
|
560
|
-
css.push(`input#ccnumfield{${cardNumStyles.join(';')};}`);
|
|
561
|
-
const monthStyles = [
|
|
562
|
-
`width:calc(10% - ${halfGapValue}${gapUnit})`,
|
|
563
|
-
`margin-right:calc(${gap} / 2)`,
|
|
564
|
-
];
|
|
565
|
-
if ((_g = styles.input) === null || _g === void 0 ? void 0 : _g.borderRadius) {
|
|
566
|
-
monthStyles.push(`border-radius:${styles.input.borderRadius}`);
|
|
567
|
-
}
|
|
568
|
-
css.push(`select#ccexpirymonth{${monthStyles.join(';')};}`);
|
|
569
|
-
const yearStyles = [
|
|
570
|
-
`width:calc(10% - ${halfGapValue}${gapUnit})`,
|
|
571
|
-
`margin-right:${gap}`,
|
|
572
|
-
];
|
|
573
|
-
if ((_h = styles.input) === null || _h === void 0 ? void 0 : _h.borderRadius) {
|
|
574
|
-
yearStyles.push(`border-radius:${styles.input.borderRadius}`);
|
|
575
|
-
}
|
|
576
|
-
css.push(`select#ccexpiryyear{${yearStyles.join(';')};}`);
|
|
577
|
-
const cvvStyles = ['width:20%'];
|
|
578
|
-
if ((_j = styles.input) === null || _j === void 0 ? void 0 : _j.borderRadius) {
|
|
579
|
-
cvvStyles.push(`border-radius:${styles.input.borderRadius}`);
|
|
580
|
-
}
|
|
581
|
-
css.push(`input#cccvvfield{${cvvStyles.join(';')};}`);
|
|
667
|
+
const marginRight = gap === '0' ? '0' : '8px';
|
|
668
|
+
css.push(`input#ccnumfield{width:60%;margin-right:${marginRight};}`);
|
|
669
|
+
css.push(`select#ccexpirymonth{width:10%;margin-right:${marginRight};}`);
|
|
670
|
+
css.push(`select#ccexpiryyear{width:10%;margin-right:${marginRight};}`);
|
|
671
|
+
css.push('input#cccvvfield{width:20%;}');
|
|
672
|
+
if ((_c = styles.input) === null || _c === void 0 ? void 0 : _c.borderRadius) {
|
|
673
|
+
css.push(`input,select{border-radius:${styles.input.borderRadius};}`);
|
|
674
|
+
}
|
|
582
675
|
}
|
|
583
676
|
if (styles.focus) {
|
|
584
677
|
const focusStyles = [];
|