@tonder.io/ionic-lite-sdk 0.0.32-beta → 0.0.33-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/.gitlab-ci.yml +28 -28
  2. package/README.md +202 -193
  3. package/dist/classes/3dsHandler.d.ts +36 -0
  4. package/dist/classes/liteCheckout.d.ts +14 -5
  5. package/dist/data/api.d.ts +1 -0
  6. package/dist/helpers/constants.d.ts +62 -0
  7. package/dist/index.js +1 -1
  8. package/dist/types/requests.d.ts +3 -0
  9. package/dist/types/responses.d.ts +1 -0
  10. package/jest.config.ts +14 -14
  11. package/package.json +38 -38
  12. package/rollup.config.js +16 -16
  13. package/src/classes/3dsHandler.ts +254 -0
  14. package/src/classes/errorResponse.ts +16 -16
  15. package/src/classes/liteCheckout.ts +535 -462
  16. package/src/helpers/utils.ts +12 -12
  17. package/src/index.ts +4 -4
  18. package/src/types/commons.ts +62 -62
  19. package/src/types/requests.ts +93 -89
  20. package/src/types/responses.ts +188 -187
  21. package/src/types/skyflow.ts +17 -17
  22. package/tests/classes/liteCheckout.test.ts +57 -57
  23. package/tests/methods/createOrder.test.ts +142 -142
  24. package/tests/methods/createPayment.test.ts +122 -122
  25. package/tests/methods/customerRegister.test.ts +119 -119
  26. package/tests/methods/getBusiness.test.ts +115 -115
  27. package/tests/methods/getCustomerCards.test.ts +117 -117
  28. package/tests/methods/getOpenpayDeviceSessionID.test.ts +94 -94
  29. package/tests/methods/getSkyflowToken.test.ts +154 -154
  30. package/tests/methods/getVaultToken.test.ts +106 -106
  31. package/tests/methods/registerCustomerCard.test.ts +117 -117
  32. package/tests/methods/startCheckoutRouter.test.ts +119 -119
  33. package/tests/methods/startCheckoutRouterFull.test.ts +138 -138
  34. package/tests/utils/defaultMock.ts +20 -20
  35. package/tests/utils/mockClasses.ts +651 -649
  36. package/tsconfig.json +18 -18
@@ -42,6 +42,9 @@ export type StartCheckoutRequest = {
42
42
  metadata: any;
43
43
  currency: string;
44
44
  };
45
+ export type StartCheckoutIdRequest = {
46
+ checkout_id: any;
47
+ };
45
48
  export interface VaultRequest extends SkyflowRecord {
46
49
  records: SkyflowRecord[];
47
50
  continueOnError?: boolean;
@@ -133,6 +133,7 @@ export type StartCheckoutResponse = {
133
133
  method: string;
134
134
  object: string;
135
135
  };
136
+ is_route_finished: Boolean;
136
137
  transaction_status: string;
137
138
  transaction_id: number;
138
139
  payment_id: number;
package/jest.config.ts CHANGED
@@ -1,15 +1,15 @@
1
- import type { JestConfigWithTsJest } from 'ts-jest'
2
-
3
- const jestConfig: JestConfigWithTsJest = {
4
- testEnvironment: "jsdom",
5
- preset: 'ts-jest',
6
- transform: {
7
- '^.+\\.tsx?$': [
8
- 'ts-jest',
9
- {
10
- },
11
- ],
12
- },
13
- }
14
-
1
+ import type { JestConfigWithTsJest } from 'ts-jest'
2
+
3
+ const jestConfig: JestConfigWithTsJest = {
4
+ testEnvironment: "jsdom",
5
+ preset: 'ts-jest',
6
+ transform: {
7
+ '^.+\\.tsx?$': [
8
+ 'ts-jest',
9
+ {
10
+ },
11
+ ],
12
+ },
13
+ }
14
+
15
15
  export default jestConfig
package/package.json CHANGED
@@ -1,38 +1,38 @@
1
- {
2
- "name": "@tonder.io/ionic-lite-sdk",
3
- "version": "0.0.32-beta",
4
- "description": "Tonder ionic lite SDK",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "tsc -noEmit && rollup --config",
9
- "test": "jest",
10
- "ts-coverage": "typescript-coverage-report"
11
- },
12
- "author": "",
13
- "license": "ISC",
14
- "dependencies": {
15
- "skyflow-js": "^1.34.1",
16
- "ts-node": "^10.9.2"
17
- },
18
- "publishConfig": {
19
- "access": "public",
20
- "registry": "https://registry.npmjs.org/"
21
- },
22
- "devDependencies": {
23
- "@rollup/plugin-terser": "^0.4.4",
24
- "@rollup/plugin-typescript": "11.1.6",
25
- "@types/crypto-js": "^4.2.2",
26
- "@types/jest": "^29.5.11",
27
- "@types/node": "^20.11.5",
28
- "jest": "^29.7.0",
29
- "jest-environment-jsdom": "^29.7.0",
30
- "jsdom": "^24.0.0",
31
- "rollup": "4.9.6",
32
- "ts-jest": "^29.1.2",
33
- "ts-loader": "^9.5.1",
34
- "tslib": "^2.6.2",
35
- "typescript": "^5.3.3",
36
- "typescript-coverage-report": "^0.8.0"
37
- }
38
- }
1
+ {
2
+ "name": "@tonder.io/ionic-lite-sdk",
3
+ "version": "0.0.33-beta.1",
4
+ "description": "Tonder ionic lite SDK",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc -noEmit && rollup --config",
9
+ "test": "jest",
10
+ "ts-coverage": "typescript-coverage-report"
11
+ },
12
+ "author": "",
13
+ "license": "ISC",
14
+ "dependencies": {
15
+ "skyflow-js": "^1.34.1",
16
+ "ts-node": "^10.9.2"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org/"
21
+ },
22
+ "devDependencies": {
23
+ "@rollup/plugin-terser": "^0.4.4",
24
+ "@rollup/plugin-typescript": "11.1.6",
25
+ "@types/crypto-js": "^4.2.2",
26
+ "@types/jest": "^29.5.11",
27
+ "@types/node": "^20.11.5",
28
+ "jest": "^29.7.0",
29
+ "jest-environment-jsdom": "^29.7.0",
30
+ "jsdom": "^24.0.0",
31
+ "rollup": "4.9.6",
32
+ "ts-jest": "^29.1.2",
33
+ "ts-loader": "^9.5.1",
34
+ "tslib": "^2.6.2",
35
+ "typescript": "^5.3.3",
36
+ "typescript-coverage-report": "^0.8.0"
37
+ }
38
+ }
package/rollup.config.js CHANGED
@@ -1,17 +1,17 @@
1
- const typescript = require('@rollup/plugin-typescript');
2
- const terser = require('@rollup/plugin-terser');
3
-
4
- module.exports = {
5
- input: './src/index.ts',
6
- output: {
7
- dir: 'dist',
8
- format: 'es',
9
- plugins: [terser()]
10
- },
11
- plugins: [
12
- typescript({
13
- exclude: ["tests/**", "jest.config.ts"]
14
- })
15
- ],
16
- external: ["skyflow-js", "crypto-js"]
1
+ const typescript = require('@rollup/plugin-typescript');
2
+ const terser = require('@rollup/plugin-terser');
3
+
4
+ module.exports = {
5
+ input: './src/index.ts',
6
+ output: {
7
+ dir: 'dist',
8
+ format: 'es',
9
+ plugins: [terser()]
10
+ },
11
+ plugins: [
12
+ typescript({
13
+ exclude: ["tests/**", "jest.config.ts"]
14
+ })
15
+ ],
16
+ external: ["skyflow-js", "crypto-js"]
17
17
  };
@@ -0,0 +1,254 @@
1
+ type ThreeDSHandlerContructor = {
2
+ payload?: any,
3
+ apiKey?: string,
4
+ baseUrl?: string,
5
+ successUrl?: Location | string
6
+ }
7
+
8
+ export class ThreeDSHandler {
9
+
10
+ baseUrl?: string
11
+ apiKey?: string
12
+ payload?: any
13
+ successUrl?: Location | string
14
+ localStorageKey: string = "verify_transaction_status_url"
15
+
16
+ constructor({
17
+ payload = null,
18
+ apiKey,
19
+ baseUrl,
20
+ successUrl
21
+ }: ThreeDSHandlerContructor) {
22
+ this.baseUrl = baseUrl,
23
+ this.apiKey = apiKey,
24
+ this.payload = payload,
25
+ this.successUrl = successUrl
26
+ }
27
+
28
+ setStorageItem (data: any) {
29
+ return localStorage.setItem(this.localStorageKey, JSON.stringify(data))
30
+ }
31
+
32
+ getStorageItem () {
33
+ return localStorage.getItem(this.localStorageKey)
34
+ }
35
+
36
+ removeStorageItem () {
37
+ return localStorage.removeItem(this.localStorageKey)
38
+ }
39
+
40
+ saveVerifyTransactionUrl() {
41
+ const url = this.payload?.next_action?.redirect_to_url?.verify_transaction_status_url
42
+ if (url) {
43
+ this.saveUrlWithExpiration(url)
44
+ } else {
45
+ const url = this.payload?.next_action?.iframe_resources?.verify_transaction_status_url
46
+ if (url) {
47
+ this.saveUrlWithExpiration(url)
48
+ } else {
49
+ console.log('No verify_transaction_status_url found');
50
+ }
51
+ }
52
+ }
53
+
54
+ saveUrlWithExpiration(url: string) {
55
+ try {
56
+ const now = new Date()
57
+ const item = {
58
+ url: url,
59
+ // Expires after 20 minutes
60
+ expires: now.getTime() + 20 * 60 * 1000
61
+ }
62
+ this.setStorageItem(item)
63
+ } catch (error) {
64
+ console.log('error: ', error)
65
+ }
66
+ }
67
+
68
+ saveCheckoutId(checkoutId: any) {
69
+ localStorage.setItem('checkout_id', JSON.stringify(checkoutId))
70
+ }
71
+
72
+ removeCheckoutId() {
73
+ localStorage.removeItem("checkout_id")
74
+ }
75
+
76
+ getCurrentCheckoutId() {
77
+ const checkout_id = localStorage.getItem("checkout_id")
78
+ return checkout_id ? JSON.parse(checkout_id):null;
79
+ }
80
+
81
+ getUrlWithExpiration() {
82
+ const status = this.getStorageItem();
83
+ if(status) {
84
+ const item = JSON.parse(status)
85
+ if (!item) return
86
+ const now = new Date()
87
+ if (now.getTime() > item.expires) {
88
+ this.removeVerifyTransactionUrl()
89
+ return null
90
+ } else {
91
+ return item.url
92
+ }
93
+ } else {
94
+ return null
95
+ }
96
+ }
97
+
98
+ removeVerifyTransactionUrl() {
99
+ return this.removeStorageItem()
100
+ }
101
+
102
+ getVerifyTransactionUrl() {
103
+ return this.getStorageItem()
104
+ }
105
+
106
+ loadIframe() {
107
+ const iframe = this.payload?.next_action?.iframe_resources?.iframe
108
+
109
+ if (iframe) {
110
+ return new Promise((resolve, reject) => {
111
+ const iframe = this.payload?.next_action?.iframe_resources?.iframe
112
+
113
+ if (iframe) {
114
+ this.saveVerifyTransactionUrl()
115
+ const container = document.createElement('div')
116
+ container.innerHTML = iframe
117
+ document.body.appendChild(container)
118
+
119
+ // Create and append the script tag manually
120
+ const script = document.createElement('script')
121
+ script.textContent = 'document.getElementById("tdsMmethodForm").submit();'
122
+ container.appendChild(script)
123
+
124
+ // Resolve the promise when the iframe is loaded
125
+ const iframeElement = document.getElementById('tdsMmethodTgtFrame')
126
+ if(iframeElement) {
127
+ iframeElement.onload = () => resolve(true)
128
+ } else {
129
+ console.log('No redirection found');
130
+ reject(false)
131
+ }
132
+ } else {
133
+ console.log('No redirection found');
134
+ reject(false)
135
+ }
136
+ })
137
+ }
138
+ }
139
+
140
+ getRedirectUrl() {
141
+ return this.payload?.next_action?.redirect_to_url?.url
142
+ }
143
+
144
+ redirectToChallenge() {
145
+ const url = this.getRedirectUrl()
146
+ if (url) {
147
+ this.saveVerifyTransactionUrl()
148
+ window.location = url;
149
+ } else {
150
+ console.log('No redirection found');
151
+ }
152
+ }
153
+
154
+ // Returns an object
155
+ // https://example.com/?name=John&age=30&city=NewYork
156
+ // { name: "John", age: "30", city: "NewYork" }
157
+ getURLParameters() {
158
+ const parameters: any = {};
159
+ const urlParams: any = new URLSearchParams(window.location.search);
160
+
161
+ for (const [key, value] of urlParams) {
162
+ parameters[key] = value;
163
+ }
164
+
165
+ return parameters;
166
+ }
167
+
168
+ handleSuccessTransaction(response: any) {
169
+ this.removeVerifyTransactionUrl();
170
+ console.log('Transacción autorizada.');
171
+ return response;
172
+ }
173
+
174
+ handleDeclinedTransaction(response: any) {
175
+ this.removeVerifyTransactionUrl();
176
+ return response;
177
+ }
178
+
179
+ // TODO: the method below needs to be tested with a real 3DS challenge
180
+ // since we couldn't get a test card that works with this feature
181
+ async handle3dsChallenge(response_json: any) {
182
+ // Create the form element:
183
+ const form = document.createElement('form');
184
+ form.name = 'frm';
185
+ form.method = 'POST';
186
+ form.action = response_json.redirect_post_url;
187
+
188
+ // Add hidden fields:
189
+ const creqInput = document.createElement('input');
190
+ creqInput.type = 'hidden';
191
+ creqInput.name = response_json.creq;
192
+ creqInput.value = response_json.creq;
193
+ form.appendChild(creqInput);
194
+
195
+ const termUrlInput = document.createElement('input');
196
+ termUrlInput.type = 'hidden';
197
+ termUrlInput.name = response_json.term_url;
198
+ termUrlInput.value = response_json.TermUrl;
199
+ form.appendChild(termUrlInput);
200
+
201
+ // Append the form to the body:
202
+ document.body.appendChild(form);
203
+ form.submit();
204
+
205
+ await this.verifyTransactionStatus();
206
+ }
207
+
208
+ // TODO: This method could be removed
209
+ async handleTransactionResponse(response: any) {
210
+ const response_json = await response.json();
211
+ if (response_json.status === "Pending" && response_json.redirect_post_url) {
212
+ return await this.handle3dsChallenge(response_json);
213
+ } else if (["Success", "Authorized"].includes(response_json.status)) {
214
+ return this.handleSuccessTransaction(response_json);
215
+ } else {
216
+ this.handleDeclinedTransaction(response);
217
+ return response_json
218
+ }
219
+ }
220
+
221
+ async verifyTransactionStatus() {
222
+ const verifyUrl = this.getUrlWithExpiration();
223
+ if (verifyUrl) {
224
+ const url = `${this.baseUrl}${verifyUrl}`;
225
+ try {
226
+ const response = await fetch(url, {
227
+ method: "GET",
228
+ headers: {
229
+ "Content-Type": "application/json",
230
+ Authorization: `Token ${this.apiKey}`,
231
+ },
232
+ // body: JSON.stringify(data),
233
+ });
234
+
235
+ if (response.status !== 200) {
236
+ console.error('La verificación de la transacción falló.');
237
+ this.removeVerifyTransactionUrl();
238
+ return response
239
+ }
240
+
241
+ return await this.handleTransactionResponse(response);
242
+ } catch (error) {
243
+ console.error('Error al verificar la transacción:', error);
244
+ this.removeVerifyTransactionUrl();
245
+ }
246
+ } else {
247
+ console.log('No verify_transaction_status_url found');
248
+ }
249
+ }
250
+
251
+ setPayload = (payload: any) => {
252
+ this.payload = payload
253
+ }
254
+ }
@@ -1,17 +1,17 @@
1
- import { IErrorResponse } from "../types/responses";
2
-
3
- export class ErrorResponse implements IErrorResponse {
4
- code?: string | undefined;
5
- body?: string | undefined;
6
- name!: string;
7
- message!: string;
8
- stack?: string | undefined;
9
-
10
- constructor({ code, body, name, message, stack }: IErrorResponse) {
11
- this.code = code;
12
- this.body = body;
13
- this.name = name;
14
- this.message = message;
15
- this.stack = stack;
16
- }
1
+ import { IErrorResponse } from "../types/responses";
2
+
3
+ export class ErrorResponse implements IErrorResponse {
4
+ code?: string | undefined;
5
+ body?: string | undefined;
6
+ name!: string;
7
+ message!: string;
8
+ stack?: string | undefined;
9
+
10
+ constructor({ code, body, name, message, stack }: IErrorResponse) {
11
+ this.code = code;
12
+ this.body = body;
13
+ this.name = name;
14
+ this.message = message;
15
+ this.stack = stack;
16
+ }
17
17
  }