tonder-web-sdk 1.12.3 → 1.15.2
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/package.json +1 -1
- package/src/classes/3dsHandler.js +12 -16
- package/src/classes/BaseInlineCheckout.js +23 -16
- package/src/classes/inlineCheckout.js +23 -12
- package/src/data/cardApi.js +21 -4
- package/src/index-dev.js +11 -4
- package/types/common.d.ts +1 -0
- package/v1/bundle.min.js +1 -1
package/package.json
CHANGED
|
@@ -4,8 +4,8 @@ export class ThreeDSHandler {
|
|
|
4
4
|
apiKey,
|
|
5
5
|
baseUrl,
|
|
6
6
|
}) {
|
|
7
|
-
this.baseUrl = baseUrl
|
|
8
|
-
this.apiKey = apiKey
|
|
7
|
+
this.baseUrl = baseUrl
|
|
8
|
+
this.apiKey = apiKey
|
|
9
9
|
this.payload = payload
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -60,12 +60,12 @@ export class ThreeDSHandler {
|
|
|
60
60
|
|
|
61
61
|
loadIframe() {
|
|
62
62
|
const iframe = this.payload?.next_action?.iframe_resources?.iframe
|
|
63
|
-
|
|
64
63
|
if (iframe) {
|
|
65
64
|
return new Promise((resolve, reject) => {
|
|
66
65
|
const iframe = this.payload?.next_action?.iframe_resources?.iframe
|
|
67
66
|
|
|
68
67
|
if (iframe) {
|
|
68
|
+
// TODO: This is not working for Azul
|
|
69
69
|
this.saveVerifyTransactionUrl()
|
|
70
70
|
const container = document.createElement('div')
|
|
71
71
|
container.innerHTML = iframe
|
|
@@ -127,8 +127,6 @@ export class ThreeDSHandler {
|
|
|
127
127
|
return response;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
// TODO: the method below needs to be tested with a real 3DS challenge
|
|
131
|
-
// since we couldn't get a test card that works with this feature
|
|
132
130
|
async handle3dsChallenge(response_json) {
|
|
133
131
|
// Create the form element:
|
|
134
132
|
const form = document.createElement('form');
|
|
@@ -139,27 +137,26 @@ export class ThreeDSHandler {
|
|
|
139
137
|
// Add hidden fields:
|
|
140
138
|
const creqInput = document.createElement('input');
|
|
141
139
|
creqInput.type = 'hidden';
|
|
142
|
-
creqInput.name =
|
|
140
|
+
creqInput.name = 'creq';
|
|
143
141
|
creqInput.value = response_json.creq;
|
|
144
142
|
form.appendChild(creqInput);
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
144
|
+
if (response_json.term_url) {
|
|
145
|
+
const termUrlInput = document.createElement('input');
|
|
146
|
+
termUrlInput.type = 'hidden';
|
|
147
|
+
termUrlInput.name = 'TermUrl';
|
|
148
|
+
termUrlInput.value = response_json.term_url;
|
|
149
|
+
form.appendChild(termUrlInput);
|
|
150
|
+
}
|
|
151
151
|
|
|
152
152
|
// Append the form to the body:
|
|
153
153
|
document.body.appendChild(form);
|
|
154
154
|
form.submit();
|
|
155
|
-
|
|
156
|
-
await this.verifyTransactionStatus();
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
// TODO: This
|
|
157
|
+
// TODO: This works for Azul
|
|
160
158
|
async handleTransactionResponse(response) {
|
|
161
159
|
const response_json = await response.json();
|
|
162
|
-
|
|
163
160
|
// Azul property
|
|
164
161
|
if (response_json.status === "Pending" && response_json.redirect_post_url) {
|
|
165
162
|
return await this.handle3dsChallenge(response_json);
|
|
@@ -173,7 +170,6 @@ export class ThreeDSHandler {
|
|
|
173
170
|
|
|
174
171
|
async verifyTransactionStatus() {
|
|
175
172
|
const verifyUrl = this.getUrlWithExpiration();
|
|
176
|
-
|
|
177
173
|
if (verifyUrl) {
|
|
178
174
|
const url = `${this.baseUrl}${verifyUrl}`;
|
|
179
175
|
try {
|
|
@@ -34,6 +34,7 @@ export class BaseInlineCheckout {
|
|
|
34
34
|
*/
|
|
35
35
|
configureCheckout(data) {
|
|
36
36
|
if ("customer" in data) this.#handleCustomer(data["customer"]);
|
|
37
|
+
if ("secureToken" in data) this.#handleSecureToken(data["secureToken"]);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -46,8 +47,9 @@ export class BaseInlineCheckout {
|
|
|
46
47
|
const result3ds = await this.process3ds.verifyTransactionStatus();
|
|
47
48
|
const resultCheckout = await this.#resumeCheckout(result3ds);
|
|
48
49
|
this.process3ds.setPayload(resultCheckout);
|
|
50
|
+
const response = await this.#handle3dsRedirect(resultCheckout);
|
|
49
51
|
globalLoader.remove();
|
|
50
|
-
return
|
|
52
|
+
return response
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
/**
|
|
@@ -158,6 +160,7 @@ export class BaseInlineCheckout {
|
|
|
158
160
|
amount: total,
|
|
159
161
|
date: dateString,
|
|
160
162
|
order_id: jsonResponseOrder.id,
|
|
163
|
+
customer_order_reference: this.order_reference ? this.order_reference : reference,
|
|
161
164
|
};
|
|
162
165
|
const jsonResponsePayment = await createPayment(
|
|
163
166
|
this.baseUrl,
|
|
@@ -222,7 +225,7 @@ export class BaseInlineCheckout {
|
|
|
222
225
|
|
|
223
226
|
async #resumeCheckout(response) {
|
|
224
227
|
// Stop the routing process if the transaction is either hard declined or successful
|
|
225
|
-
if (response?.decline?.error_type === "Hard") {
|
|
228
|
+
if (response?.decline?.error_type === "Hard" || !!response?.checkout?.is_route_finished) {
|
|
226
229
|
return response;
|
|
227
230
|
}
|
|
228
231
|
|
|
@@ -265,8 +268,13 @@ export class BaseInlineCheckout {
|
|
|
265
268
|
this.customer = customer;
|
|
266
269
|
}
|
|
267
270
|
|
|
271
|
+
#handleSecureToken(secureToken) {
|
|
272
|
+
this.secureToken = secureToken;
|
|
273
|
+
}
|
|
274
|
+
|
|
268
275
|
#handleMetadata(data) {
|
|
269
276
|
this.metadata = data?.metadata;
|
|
277
|
+
this.order_reference = data?.order_reference;
|
|
270
278
|
}
|
|
271
279
|
|
|
272
280
|
#handleCurrency(data) {
|
|
@@ -282,23 +290,22 @@ export class BaseInlineCheckout {
|
|
|
282
290
|
}
|
|
283
291
|
|
|
284
292
|
async #handle3dsRedirect(response) {
|
|
293
|
+
console.log('Handling 3DS redirect...');
|
|
285
294
|
const iframe = response?.next_action?.iframe_resources?.iframe;
|
|
295
|
+
const threeDsChallenge = response?.next_action?.three_ds_challenge;
|
|
286
296
|
|
|
287
297
|
if (iframe) {
|
|
288
|
-
|
|
289
|
-
.loadIframe()
|
|
290
|
-
.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
.catch((error) => {
|
|
300
|
-
console.log("Error loading iframe:", error);
|
|
301
|
-
});
|
|
298
|
+
try {
|
|
299
|
+
await this.process3ds.loadIframe();
|
|
300
|
+
const res = await this.process3ds.verifyTransactionStatus();
|
|
301
|
+
return res;
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.log("Error loading iframe:", error);
|
|
304
|
+
}
|
|
305
|
+
} else if (threeDsChallenge) {
|
|
306
|
+
await this.process3ds.handle3dsChallenge(threeDsChallenge);
|
|
307
|
+
const res = await this.process3ds.verifyTransactionStatus();
|
|
308
|
+
return res;
|
|
302
309
|
} else {
|
|
303
310
|
const redirectUrl = this.process3ds.getRedirectUrl();
|
|
304
311
|
if (redirectUrl) {
|
|
@@ -63,14 +63,14 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
63
63
|
this.customStyles = styles
|
|
64
64
|
this.abortRefreshCardsController = new AbortController();
|
|
65
65
|
// TODO: Wait until SaveCards is ready (server token).
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
this.customization = {
|
|
67
|
+
...this.customization,
|
|
68
|
+
...(customization || {}),
|
|
69
|
+
saveCards: {
|
|
70
|
+
...this.customization.saveCards,
|
|
71
|
+
...(customization?.saveCards || {}),
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
#mountPayButton() {
|
|
@@ -295,9 +295,13 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
295
295
|
const saveCard = document.getElementById("save-checkout-card");
|
|
296
296
|
if ((saveCard && "checked" in saveCard && saveCard.checked) || !!this.customization.saveCards?.autoSave) {
|
|
297
297
|
try {
|
|
298
|
-
await saveCustomerCard(
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
await saveCustomerCard(
|
|
299
|
+
this.baseUrl,
|
|
300
|
+
auth_token,
|
|
301
|
+
this.secureToken,
|
|
302
|
+
businessId,
|
|
303
|
+
{ skyflow_id: cardTokens.skyflow_id, }
|
|
304
|
+
);
|
|
301
305
|
showMessage(MESSAGES.cardSaved, this.collectorIds.msgNotification);
|
|
302
306
|
} catch (error) {
|
|
303
307
|
if (error?.message) {
|
|
@@ -314,6 +318,7 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
314
318
|
const cardsResponse = await fetchCustomerCards(
|
|
315
319
|
this.baseUrl,
|
|
316
320
|
token,
|
|
321
|
+
this.secureToken,
|
|
317
322
|
this.merchantData.business.pk,
|
|
318
323
|
);
|
|
319
324
|
let cards = []
|
|
@@ -400,7 +405,13 @@ export class InlineCheckout extends BaseInlineCheckout {
|
|
|
400
405
|
this.abortRefreshCardsController = new AbortController();
|
|
401
406
|
}
|
|
402
407
|
const businessId = this.merchantData.business.pk
|
|
403
|
-
await removeCustomerCard(
|
|
408
|
+
await removeCustomerCard(
|
|
409
|
+
this.baseUrl,
|
|
410
|
+
customerToken,
|
|
411
|
+
this.secureToken,
|
|
412
|
+
skyflow_id,
|
|
413
|
+
businessId
|
|
414
|
+
)
|
|
404
415
|
} catch (error) { } finally {
|
|
405
416
|
this.deletingCards = this.deletingCards.filter(id => id !== skyflow_id);
|
|
406
417
|
this.#refreshCardOnDelete(customerToken)
|
package/src/data/cardApi.js
CHANGED
|
@@ -11,6 +11,7 @@ import {MESSAGES} from "../shared/constants/messages";
|
|
|
11
11
|
*
|
|
12
12
|
* @param {string} baseUrl - The base URL of the API.
|
|
13
13
|
* @param {string} customerToken - The customer's authentication token.
|
|
14
|
+
* @param {string} secureToken - Token generated by secure-token endpoint.
|
|
14
15
|
* @param {string | number} businessId - The business ID.
|
|
15
16
|
* @param {import("../../types").ISaveCardSkyflowRequest} data - The card information to be saved.
|
|
16
17
|
* @returns {Promise<import("../../types").ISaveCardResponse>} The saved card data.
|
|
@@ -20,6 +21,7 @@ import {MESSAGES} from "../shared/constants/messages";
|
|
|
20
21
|
export async function saveCustomerCard(
|
|
21
22
|
baseUrl,
|
|
22
23
|
customerToken,
|
|
24
|
+
secureToken,
|
|
23
25
|
businessId,
|
|
24
26
|
data,
|
|
25
27
|
) {
|
|
@@ -28,7 +30,8 @@ export async function saveCustomerCard(
|
|
|
28
30
|
const response = await fetch(url, {
|
|
29
31
|
method: "POST",
|
|
30
32
|
headers: {
|
|
31
|
-
Authorization: `
|
|
33
|
+
Authorization: `Bearer ${secureToken}`,
|
|
34
|
+
"User-Token": customerToken,
|
|
32
35
|
"Content-Type": "application/json",
|
|
33
36
|
},
|
|
34
37
|
body: JSON.stringify(data),
|
|
@@ -57,6 +60,7 @@ export async function saveCustomerCard(
|
|
|
57
60
|
* Removes a customer's card.
|
|
58
61
|
* @param {string} baseUrl - The base URL of the API.
|
|
59
62
|
* @param {string} customerToken - The customer's authentication token.
|
|
63
|
+
* @param {string} secureToken - Token generated by secure-token endpoint.
|
|
60
64
|
* @param {string} skyflowId - The Skyflow ID of the card to be removed.
|
|
61
65
|
* @param {string} businessId - The business ID.
|
|
62
66
|
* @returns {Promise<string>} The result of the card removal operation.
|
|
@@ -66,6 +70,7 @@ export async function saveCustomerCard(
|
|
|
66
70
|
export async function removeCustomerCard(
|
|
67
71
|
baseUrl,
|
|
68
72
|
customerToken,
|
|
73
|
+
secureToken,
|
|
69
74
|
skyflowId = "",
|
|
70
75
|
businessId,
|
|
71
76
|
) {
|
|
@@ -75,8 +80,9 @@ export async function removeCustomerCard(
|
|
|
75
80
|
const response = await fetch(url, {
|
|
76
81
|
method: "DELETE",
|
|
77
82
|
headers: {
|
|
78
|
-
Authorization: `
|
|
83
|
+
Authorization: `Bearer ${secureToken}`,
|
|
79
84
|
"Content-Type": "application/json",
|
|
85
|
+
"User-Token": customerToken,
|
|
80
86
|
},
|
|
81
87
|
});
|
|
82
88
|
|
|
@@ -94,6 +100,7 @@ export async function removeCustomerCard(
|
|
|
94
100
|
* Fetches a customer's saved cards.
|
|
95
101
|
* @param {string} baseUrl - The base URL of the API.
|
|
96
102
|
* @param {string} customerToken - The customer's authentication token.
|
|
103
|
+
* @param {string} secureToken - Token generated by secure-token endpoint.
|
|
97
104
|
* @param {string} businessId - The business ID.
|
|
98
105
|
* @param {AbortSignal} signal - The abort signal to cancel the request.
|
|
99
106
|
* @returns {Promise<import("../../types").ICustomerCardsResponse>} The customer's saved cards.
|
|
@@ -103,6 +110,7 @@ export async function removeCustomerCard(
|
|
|
103
110
|
export async function fetchCustomerCards(
|
|
104
111
|
baseUrl,
|
|
105
112
|
customerToken,
|
|
113
|
+
secureToken,
|
|
106
114
|
businessId,
|
|
107
115
|
signal= null,
|
|
108
116
|
) {
|
|
@@ -111,12 +119,21 @@ export async function fetchCustomerCards(
|
|
|
111
119
|
const response = await fetch(url, {
|
|
112
120
|
method: "GET",
|
|
113
121
|
headers: {
|
|
114
|
-
Authorization: `
|
|
115
|
-
"
|
|
122
|
+
Authorization: `Bearer ${secureToken}`,
|
|
123
|
+
"User-Token": customerToken,
|
|
116
124
|
},
|
|
117
125
|
signal,
|
|
118
126
|
});
|
|
119
127
|
if (response.ok) return await response.json();
|
|
128
|
+
if (response.status === 401) {
|
|
129
|
+
return {
|
|
130
|
+
code: 401,
|
|
131
|
+
body: {},
|
|
132
|
+
name: "",
|
|
133
|
+
message: "Unauthorized",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
120
137
|
const res_json = await response.json();
|
|
121
138
|
|
|
122
139
|
throw await buildErrorResponse(response, res_json, MESSAGES.getCardsError);
|
package/src/index-dev.js
CHANGED
|
@@ -98,11 +98,13 @@ const checkoutData = {
|
|
|
98
98
|
// metadata: {
|
|
99
99
|
// order_id: 123456
|
|
100
100
|
// }
|
|
101
|
+
// Reference from the merchant
|
|
102
|
+
order_reference: "ORD-123456"
|
|
101
103
|
};
|
|
102
104
|
|
|
103
105
|
// localhost
|
|
104
106
|
const apiKey = "11e3d3c3e95e0eaabbcae61ebad34ee5f93c3d27";
|
|
105
|
-
const returnUrl = "http://
|
|
107
|
+
const returnUrl = "http://localhost:8080/";
|
|
106
108
|
// stage
|
|
107
109
|
// const apiKey = "8365683bdc33dd6d50fe2397188d79f1a6765852";
|
|
108
110
|
|
|
@@ -113,7 +115,6 @@ const commonConfig = {
|
|
|
113
115
|
styles: customStyles,
|
|
114
116
|
};
|
|
115
117
|
|
|
116
|
-
let checkout;
|
|
117
118
|
let inlineCheckout;
|
|
118
119
|
let liteInlineCheckout;
|
|
119
120
|
|
|
@@ -133,7 +134,10 @@ function setupInlineCheckout() {
|
|
|
133
134
|
},
|
|
134
135
|
},
|
|
135
136
|
});
|
|
136
|
-
inlineCheckout.configureCheckout({
|
|
137
|
+
inlineCheckout.configureCheckout({
|
|
138
|
+
customer: checkoutData.customer,
|
|
139
|
+
secureToken: "eyJhbGc..."
|
|
140
|
+
});
|
|
137
141
|
inlineCheckout.injectCheckout();
|
|
138
142
|
// ['Declined', 'Cancelled', 'Failed', 'Success', 'Pending', 'Authorized']
|
|
139
143
|
inlineCheckout.verify3dsTransaction().then((response) => {
|
|
@@ -159,7 +163,10 @@ function setupInlineCheckout() {
|
|
|
159
163
|
function setupLiteInlineCheckout() {
|
|
160
164
|
loadMaskitoMask();
|
|
161
165
|
liteInlineCheckout = new LiteInlineCheckout(commonConfig);
|
|
162
|
-
liteInlineCheckout.configureCheckout({
|
|
166
|
+
liteInlineCheckout.configureCheckout({
|
|
167
|
+
customer: checkoutData.customer,
|
|
168
|
+
secureToken: "eyJhbGc..."
|
|
169
|
+
});
|
|
163
170
|
liteInlineCheckout.injectCheckout().then(() => {});
|
|
164
171
|
liteInlineCheckout.verify3dsTransaction().then((response) => {
|
|
165
172
|
console.log("Verify 3ds response", response);
|