tonder-web-sdk 1.12.3 → 1.14.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tonder-web-sdk",
3
- "version": "1.12.3",
3
+ "version": "1.14.0",
4
4
  "description": "tonder sdk for integrations",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -6,7 +6,8 @@ export class ThreeDSHandler {
6
6
  }) {
7
7
  this.baseUrl = baseUrl,
8
8
  this.apiKey = apiKey,
9
- this.payload = payload
9
+ this.payload = payload,
10
+ this.isTransactionPending = false
10
11
  }
11
12
 
12
13
  saveVerifyTransactionUrl() {
@@ -127,8 +128,6 @@ export class ThreeDSHandler {
127
128
  return response;
128
129
  }
129
130
 
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
131
  async handle3dsChallenge(response_json) {
133
132
  // Create the form element:
134
133
  const form = document.createElement('form');
@@ -139,15 +138,17 @@ export class ThreeDSHandler {
139
138
  // Add hidden fields:
140
139
  const creqInput = document.createElement('input');
141
140
  creqInput.type = 'hidden';
142
- creqInput.name = response_json.creq;
141
+ creqInput.name = 'creq';
143
142
  creqInput.value = response_json.creq;
144
143
  form.appendChild(creqInput);
145
144
 
146
- const termUrlInput = document.createElement('input');
147
- termUrlInput.type = 'hidden';
148
- termUrlInput.name = response_json.term_url;
149
- termUrlInput.value = response_json.TermUrl;
150
- form.appendChild(termUrlInput);
145
+ if (response_json.term_url) {
146
+ const termUrlInput = document.createElement('input');
147
+ termUrlInput.type = 'hidden';
148
+ termUrlInput.name = 'TermUrl';
149
+ termUrlInput.value = response_json.term_url;
150
+ form.appendChild(termUrlInput);
151
+ }
151
152
 
152
153
  // Append the form to the body:
153
154
  document.body.appendChild(form);
@@ -172,6 +173,14 @@ export class ThreeDSHandler {
172
173
  }
173
174
 
174
175
  async verifyTransactionStatus() {
176
+ console.log('Verificando la transacción...');
177
+
178
+ if (this.isTransactionPending) {
179
+ console.log('La transacción ya está en proceso');
180
+ return
181
+ }
182
+
183
+ this.isTransactionPending = true
175
184
  const verifyUrl = this.getUrlWithExpiration();
176
185
 
177
186
  if (verifyUrl) {
@@ -199,6 +208,8 @@ export class ThreeDSHandler {
199
208
  } else {
200
209
  console.log('No verify_transaction_status_url found');
201
210
  }
211
+
212
+ this.isTransactionPending = false
202
213
  }
203
214
 
204
215
  setPayload = (payload) => {
@@ -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
  /**
@@ -265,6 +266,10 @@ export class BaseInlineCheckout {
265
266
  this.customer = customer;
266
267
  }
267
268
 
269
+ #handleSecureToken(secureToken) {
270
+ this.secureToken = secureToken;
271
+ }
272
+
268
273
  #handleMetadata(data) {
269
274
  this.metadata = data?.metadata;
270
275
  }
@@ -282,23 +287,19 @@ export class BaseInlineCheckout {
282
287
  }
283
288
 
284
289
  async #handle3dsRedirect(response) {
290
+ console.log('Handling 3DS redirect...');
285
291
  const iframe = response?.next_action?.iframe_resources?.iframe;
292
+ const threeDsChallenge = response?.next_action?.three_ds_challenge;
286
293
 
287
294
  if (iframe) {
288
- this.process3ds
289
- .loadIframe()
290
- .then(() => {
291
- //TODO: Check if this will be necessary on the frontend side
292
- // after some the tests in production, since the 3DS process
293
- // doesn't works properly on the sandbox environment
294
- // setTimeout(() => {
295
- // process3ds.verifyTransactionStatus();
296
- // }, 10000);
297
- this.process3ds.verifyTransactionStatus();
298
- })
299
- .catch((error) => {
300
- console.log("Error loading iframe:", error);
301
- });
295
+ try {
296
+ await this.process3ds.loadIframe();
297
+ await this.process3ds.verifyTransactionStatus();
298
+ } catch (error) {
299
+ console.log("Error loading iframe:", error);
300
+ }
301
+ } else if (threeDsChallenge) {
302
+ await this.process3ds.handle3dsChallenge(threeDsChallenge);
302
303
  } else {
303
304
  const redirectUrl = this.process3ds.getRedirectUrl();
304
305
  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
- // this.customization = {
67
- // ...this.customization,
68
- // ...(customization || {}),
69
- // saveCards: {
70
- // ...this.customization.saveCards,
71
- // ...(customization?.saveCards || {}),
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(this.baseUrl, auth_token, businessId, {
299
- skyflow_id: cardTokens.skyflow_id,
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(this.baseUrl, customerToken, skyflow_id, businessId)
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)
@@ -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: `Token ${customerToken}`,
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: `Token ${customerToken}`,
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: `Token ${customerToken}`,
115
- "Content-Type": "application/json",
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
@@ -113,7 +113,6 @@ const commonConfig = {
113
113
  styles: customStyles,
114
114
  };
115
115
 
116
- let checkout;
117
116
  let inlineCheckout;
118
117
  let liteInlineCheckout;
119
118
 
@@ -133,7 +132,10 @@ function setupInlineCheckout() {
133
132
  },
134
133
  },
135
134
  });
136
- inlineCheckout.configureCheckout({ customer: checkoutData.customer });
135
+ inlineCheckout.configureCheckout({
136
+ customer: checkoutData.customer,
137
+ secureToken: "eyJhbGc..."
138
+ });
137
139
  inlineCheckout.injectCheckout();
138
140
  // ['Declined', 'Cancelled', 'Failed', 'Success', 'Pending', 'Authorized']
139
141
  inlineCheckout.verify3dsTransaction().then((response) => {
@@ -159,7 +161,10 @@ function setupInlineCheckout() {
159
161
  function setupLiteInlineCheckout() {
160
162
  loadMaskitoMask();
161
163
  liteInlineCheckout = new LiteInlineCheckout(commonConfig);
162
- liteInlineCheckout.configureCheckout({ customer: checkoutData.customer });
164
+ liteInlineCheckout.configureCheckout({
165
+ customer: checkoutData.customer,
166
+ secureToken: "eyJhbGc..."
167
+ });
163
168
  liteInlineCheckout.injectCheckout().then(() => {});
164
169
  liteInlineCheckout.verify3dsTransaction().then((response) => {
165
170
  console.log("Verify 3ds response", response);
package/types/common.d.ts CHANGED
@@ -9,6 +9,7 @@ export interface IInlineCheckoutBaseOptions {
9
9
 
10
10
  export interface IConfigureCheckout {
11
11
  customer: ICustomer;
12
+ secureToken: string;
12
13
  }
13
14
 
14
15
  export interface IApiError {