apacuana-sdk-core 1.22.0 → 1.25.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.
Files changed (37) hide show
  1. package/README.md +39 -27
  2. package/coverage/clover.xml +195 -214
  3. package/coverage/coverage-final.json +5 -5
  4. package/coverage/lcov-report/index.html +33 -33
  5. package/coverage/lcov-report/src/api/certs.js.html +1 -1
  6. package/coverage/lcov-report/src/api/faceLiveness.js.html +35 -269
  7. package/coverage/lcov-report/src/api/index.html +18 -18
  8. package/coverage/lcov-report/src/api/revocations.js.html +1 -1
  9. package/coverage/lcov-report/src/api/signatures.js.html +1 -1
  10. package/coverage/lcov-report/src/api/users.js.html +1 -1
  11. package/coverage/lcov-report/src/config/index.html +1 -1
  12. package/coverage/lcov-report/src/config/index.js.html +1 -1
  13. package/coverage/lcov-report/src/errors/index.html +1 -1
  14. package/coverage/lcov-report/src/errors/index.js.html +8 -8
  15. package/coverage/lcov-report/src/index.html +15 -15
  16. package/coverage/lcov-report/src/index.js.html +12 -42
  17. package/coverage/lcov-report/src/success/index.html +1 -1
  18. package/coverage/lcov-report/src/success/index.js.html +5 -5
  19. package/coverage/lcov-report/src/utils/constant.js.html +1 -1
  20. package/coverage/lcov-report/src/utils/helpers.js.html +59 -8
  21. package/coverage/lcov-report/src/utils/httpClient.js.html +1 -1
  22. package/coverage/lcov-report/src/utils/index.html +12 -12
  23. package/coverage/lcov.info +398 -434
  24. package/dist/api/faceLiveness.d.ts +3 -4
  25. package/dist/index.d.ts +1 -2
  26. package/dist/index.js +61 -165
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +61 -165
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/types/faceLiveness.d.ts +0 -10
  31. package/dist/utils/helpers.d.ts +2 -0
  32. package/package.json +3 -2
  33. package/src/api/faceLiveness.js +20 -98
  34. package/src/index.js +4 -14
  35. package/src/types/faceLiveness.js +1 -12
  36. package/src/utils/helpers.js +17 -0
  37. package/tests/api/faceLiveness.test.js +54 -115
@@ -1,11 +1 @@
1
1
  export type ApacuanaSuccess = import("../success").ApacuanaSuccess;
2
- export type CreateFaceLivenessSessionData = {
3
- /**
4
- * - The session ID for the face liveness check.
5
- */
6
- sessionId: string;
7
- };
8
- export type CreateFaceLivenessSessionResponse = {
9
- success: true;
10
- data: CreateFaceLivenessSessionData;
11
- };
@@ -9,6 +9,7 @@ declare namespace _default {
9
9
  export { validateGetDigestData };
10
10
  export { validateOnBoardingSignDocumentData };
11
11
  export { createPayloadGetDigest };
12
+ export { base64ToFile };
12
13
  }
13
14
  export default _default;
14
15
  declare function getCertificateStatus(userData: any, certificateInDevice: any, integrationType: any): string;
@@ -23,3 +24,4 @@ declare function validateGetDocsData(data: any): void;
23
24
  declare function validateGetDigestData(signData: any): void;
24
25
  declare function validateOnBoardingSignDocumentData(signData: any): FormData;
25
26
  declare function createPayloadGetDigest(signData: any): FormData;
27
+ declare function base64ToFile(dataurl: any, filename: any): File;
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "apacuana-sdk-core",
3
- "version": "1.22.0",
3
+ "version": "1.25.0",
4
4
  "description": "Core SDK para interacciones con las APIs de Apacuana.",
5
- "main": "dist/index.cjs",
5
+ "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
+ "type": "module",
8
9
  "scripts": {
9
10
  "clean": "rimraf dist",
10
11
  "clean-modules": "rimraf node_modules",
@@ -1,129 +1,51 @@
1
- /**
2
- * @typedef {import('../types/faceLiveness').CreateFaceLivenessSessionResponse} CreateFaceLivenessSessionResponse
3
- */
4
-
1
+ /* eslint-disable import/prefer-default-export */
5
2
  import { getConfig } from "../config/index";
6
3
  import { httpRequest } from "../utils/httpClient";
7
4
  import { ApacuanaAPIError } from "../errors";
8
5
  import ApacuanaSuccess from "../success";
9
6
  import { INTEGRATION_TYPE } from "../utils/constant";
7
+ import helpers from "../utils/helpers";
10
8
 
11
- /**
12
- * Creates a new Face Liveness session.
13
- * @returns {Promise<CreateFaceLivenessSessionResponse>} Object with the session ID and a success indicator.
14
- * @throws {ApacuanaAPIError} If the API response is invalid or the integration type is not supported.
15
- * @throws {Error} If the request fails for another reason.
16
- */
17
- const createFaceLivenessSessionOnBoarding = async () => {
9
+ const sendFaceLivenessOnBoarding = async (faceliveness, documentprefid) => {
18
10
  try {
19
- const response = await httpRequest(
20
- "services/api/faceliveness/create",
21
- {},
22
- "POST"
23
- );
24
- if (!response.sessionid) {
25
- throw new ApacuanaAPIError(
26
- "The API response does not contain the session ID.",
27
- response.status,
28
- "INVALID_API_RESPONSE"
29
- );
30
- }
31
-
32
- return new ApacuanaSuccess({
33
- sessionId: response.sessionid,
34
- });
35
- } catch (error) {
36
- if (error instanceof ApacuanaAPIError) {
37
- throw error;
38
- }
39
- throw new ApacuanaAPIError(
40
- `Failed to create Face Liveness session: ${error.message}`
11
+ const file = helpers.base64ToFile(
12
+ faceliveness,
13
+ `liveness_capture_${Date.now()}.png`
41
14
  );
42
- }
43
- };
44
-
45
- const createFaceLivenessSessionOnPremise = async () => {
46
- throw new ApacuanaAPIError(
47
- "Creating a Face Liveness session is not supported for integration type: ONPREMISE",
48
- 501,
49
- "NOT_IMPLEMENTED"
50
- );
51
- };
52
-
53
- const validateFaceLivenessOnBoarding = async (sessionId) => {
54
- try {
55
15
  const response = await httpRequest(
56
- "services/api/faceliveness/validate",
57
- { sessionid: sessionId },
16
+ "services/api/faceliveness/uploadfaceliveness",
17
+ { faceliveness: file, documentprefid },
58
18
  "POST"
59
19
  );
60
20
  return new ApacuanaSuccess({ status: "verified", ...response });
61
21
  } catch (error) {
62
22
  if (error instanceof ApacuanaAPIError) {
63
- let status;
64
- switch (error.statusCode) {
65
- case 402:
66
- status = "waitingForScan";
67
- break;
68
- case 403:
69
- status = "rejected";
70
- break;
71
- case 406:
72
- status = "processing";
73
- break;
74
- case 408:
75
- status = "expired";
76
- break;
77
- default:
78
- throw error;
79
- }
80
- return new ApacuanaSuccess({ status });
23
+ throw error;
81
24
  }
82
- throw error;
25
+ throw new Error(`Failed to send faceliveness: ${error.message}`);
83
26
  }
84
27
  };
85
28
 
86
- const validateFaceLivenessOnPremise = async () => {
29
+ const sendFaceLivenessOnPremise = async () => {
87
30
  throw new ApacuanaAPIError(
88
- "Validating a Face Liveness session is not supported for integration type: ONPREMISE",
31
+ "Send a Face Liveness is not supported for integration type: ONPREMISE",
89
32
  501,
90
33
  "NOT_IMPLEMENTED"
91
34
  );
92
35
  };
93
36
 
94
- /**
95
- * Creates a new Face Liveness session.
96
- * @returns {Promise<CreateFaceLivenessSessionResponse>} Object with the session ID and a success indicator.
97
- * @throws {ApacuanaAPIError} If the API response is invalid or the integration type is not supported.
98
- * @throws {Error} If the request fails for another reason.
99
- */
100
- export const createFaceLivenessSession = async () => {
101
- const { integrationType } = getConfig();
102
-
103
- if (integrationType === INTEGRATION_TYPE.ONBOARDING) {
104
- return createFaceLivenessSessionOnBoarding();
105
- }
106
- if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
107
- return createFaceLivenessSessionOnPremise();
108
- }
109
-
110
- throw new ApacuanaAPIError(
111
- `Unsupported integration type: ${integrationType}`,
112
- 400,
113
- "UNSUPPORTED_INTEGRATION_TYPE"
114
- );
115
- };
116
-
117
37
  /**
118
38
  * Validates a Face Liveness session and returns its status.
119
- * @param {{sessionId: string}} params - Object containing the session ID.
39
+ * @param {object} params - Parámetros para la solicitud.
40
+ * @param {string} params.faceLiveness - El faceLiveness.
41
+ * @param {string} params.documentprefid - El documentprefid.
120
42
  * @returns {Promise<ApacuanaSuccess>} Object with the validation status.
121
43
  * @throws {ApacuanaAPIError} If the API response is invalid or the integration type is not supported.
122
44
  */
123
- export const validateFaceLiveness = async ({ sessionId }) => {
124
- if (!sessionId) {
45
+ export const sendFaceLiveness = async ({ faceLiveness, documentprefid }) => {
46
+ if (!faceLiveness || !documentprefid) {
125
47
  throw new ApacuanaAPIError(
126
- "sessionId is a required parameter.",
48
+ "faceLiveness and documentprefid is a required parameter.",
127
49
  400,
128
50
  "INVALID_PARAMETER"
129
51
  );
@@ -132,10 +54,10 @@ export const validateFaceLiveness = async ({ sessionId }) => {
132
54
  const { integrationType } = getConfig();
133
55
 
134
56
  if (integrationType === INTEGRATION_TYPE.ONBOARDING) {
135
- return validateFaceLivenessOnBoarding(sessionId);
57
+ return sendFaceLivenessOnBoarding(faceLiveness, documentprefid);
136
58
  }
137
59
  if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
138
- return validateFaceLivenessOnPremise();
60
+ return sendFaceLivenessOnPremise();
139
61
  }
140
62
 
141
63
  throw new ApacuanaAPIError(
package/src/index.js CHANGED
@@ -16,10 +16,7 @@ import {
16
16
  signDocument,
17
17
  uploadSignatureVariant,
18
18
  } from "./api/signatures";
19
- import {
20
- createFaceLivenessSession,
21
- validateFaceLiveness,
22
- } from "./api/faceLiveness";
19
+ import { sendFaceLiveness } from "./api/faceLiveness";
23
20
  import ApacuanaSuccess from "./success/index";
24
21
  import { ApacuanaAPIError } from "./errors/index";
25
22
  import { createApacuanaUser, getCustomer } from "./api/users";
@@ -149,22 +146,15 @@ const apacuana = {
149
146
  checkSdk(true);
150
147
  return getCustomer();
151
148
  },
152
- createFaceLivenessSession: () => {
153
- checkSdk(true);
154
- return createFaceLivenessSession();
155
- },
149
+
156
150
  createApacuanaUser: (data) => {
157
151
  checkSdk(false);
158
152
  return createApacuanaUser(data);
159
153
  },
160
- validateFaceLiveness: (data) => {
154
+ sendFaceLiveness: (data) => {
161
155
  checkSdk(true);
162
- return validateFaceLiveness(data);
156
+ return sendFaceLiveness(data);
163
157
  },
164
- // validateCertificate: (data) => {
165
- // checkSdk(true);
166
- // validateCertificate(data);
167
- // },
168
158
 
169
159
  close: () => close(),
170
160
  getConfig,
@@ -2,15 +2,4 @@
2
2
  * @typedef {import('../success').ApacuanaSuccess} ApacuanaSuccess
3
3
  */
4
4
 
5
- /**
6
- * @typedef {object} CreateFaceLivenessSessionData
7
- * @property {string} sessionId - The session ID for the face liveness check.
8
- */
9
-
10
- /**
11
- * @typedef {object} CreateFaceLivenessSessionResponse
12
- * @property {true} success
13
- * @property {CreateFaceLivenessSessionData} data
14
- */
15
-
16
- export {};
5
+ export {};
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-plusplus */
1
2
  import CryptoJS from "crypto-js";
2
3
  import { getCrypto } from "pkijs";
3
4
  import {
@@ -387,6 +388,21 @@ const validateOnBoardingSignDocumentData = (signData) => {
387
388
  return formData;
388
389
  };
389
390
 
391
+ const base64ToFile = (dataurl, filename) => {
392
+ const arr = dataurl.split(",");
393
+ const mime = arr[0].match(/:(.*?);/)[1];
394
+ const bstr = atob(arr[1]);
395
+ let n = bstr.length;
396
+ const u8arr = new Uint8Array(n);
397
+
398
+ while (n--) {
399
+ u8arr[n] = bstr.charCodeAt(n);
400
+ }
401
+
402
+ const blob = new Blob([u8arr], { type: mime });
403
+ return new File([blob], filename, { type: mime });
404
+ };
405
+
390
406
  export default {
391
407
  getCertificateStatus,
392
408
  exportPrivateKey,
@@ -398,4 +414,5 @@ export default {
398
414
  validateGetDigestData,
399
415
  validateOnBoardingSignDocumentData,
400
416
  createPayloadGetDigest,
417
+ base64ToFile,
401
418
  };
@@ -1,13 +1,12 @@
1
- import {
2
- createFaceLivenessSession,
3
- validateFaceLiveness,
4
- } from "../../src/api/faceLiveness";
1
+ import { sendFaceLiveness } from "../../src/api/faceLiveness";
5
2
  import { httpRequest } from "../../src/utils/httpClient";
6
3
  import ApacuanaSuccess from "../../src/success";
7
- import { setConfig, getConfig } from "../../src/config";
4
+ import { getConfig } from "../../src/config";
8
5
  import { ApacuanaAPIError } from "../../src/errors";
9
6
  import { INTEGRATION_TYPE } from "../../src/utils/constant";
7
+ import helpers from "../../src/utils/helpers";
10
8
 
9
+ // Mocks de las dependencias
11
10
  jest.mock("../../src/utils/httpClient", () => ({
12
11
  httpRequest: jest.fn(),
13
12
  }));
@@ -17,154 +16,94 @@ jest.mock("../../src/config", () => ({
17
16
  setConfig: jest.fn(),
18
17
  }));
19
18
 
19
+ jest.mock("../../src/utils/helpers", () => ({
20
+ base64ToFile: jest.fn(),
21
+ }));
22
+
20
23
  describe("FaceLiveness API", () => {
24
+ const mockBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...";
25
+ const mockPrefId = "pref-abc-123";
26
+
21
27
  beforeEach(() => {
22
28
  jest.clearAllMocks();
29
+ // Configuración por defecto para la mayoría de las pruebas
23
30
  getConfig.mockReturnValue({ integrationType: INTEGRATION_TYPE.ONBOARDING });
24
31
  });
25
32
 
26
- describe("createFaceLivenessSession", () => {
27
- it("should create a session for ONBOARDING integration", async () => {
28
- const mockSessionId = "session-onboarding-123";
29
- httpRequest.mockResolvedValue({ sessionid: mockSessionId });
30
- setConfig({ onboardingId: "some-onboarding-id" });
33
+ describe("sendFaceLiveness", () => {
34
+ it("debe enviar la captura exitosamente para integración ONBOARDING", async () => {
35
+ // Configuramos el mock para que devuelva un objeto File simulado
36
+ helpers.base64ToFile.mockReturnValue(new File([""], "liveness.png"));
37
+ httpRequest.mockResolvedValue({ success: true, transactionId: "12345" });
31
38
 
32
- const result = await createFaceLivenessSession();
39
+ const result = await sendFaceLiveness({
40
+ faceLiveness: mockBase64,
41
+ documentprefid: mockPrefId,
42
+ });
33
43
 
44
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
45
+ expect(result.data.status).toBe("verified");
34
46
  expect(httpRequest).toHaveBeenCalledWith(
35
- "services/api/faceliveness/create",
36
- {},
47
+ "services/api/faceliveness/uploadfaceliveness",
48
+ expect.objectContaining({ documentprefid: mockPrefId }),
37
49
  "POST"
38
50
  );
39
- expect(result).toBeInstanceOf(ApacuanaSuccess);
40
- expect(result.data).toEqual({ sessionId: mockSessionId });
41
51
  });
42
52
 
43
- it("should throw an error if session ID is missing for ONBOARDING", async () => {
44
- httpRequest.mockResolvedValue({}); // No sessionId
45
-
46
- await expect(createFaceLivenessSession()).rejects.toThrow(
47
- new ApacuanaAPIError(
48
- "The API response does not contain the session ID.",
49
- undefined,
50
- "INVALID_API_RESPONSE"
51
- )
53
+ it("debe lanzar un error si faltan parámetros (validando el mensaje exacto)", async () => {
54
+ // El mensaje debe coincidir exactamente con la implementación (incluyendo espacios dobles si existen)
55
+ await expect(sendFaceLiveness({ faceLiveness: "" })).rejects.toThrow(
56
+ "faceLiveness and documentprefid is a required parameter."
52
57
  );
53
58
  });
54
59
 
55
- it("should throw a NOT_IMPLEMENTED error for ONPREMISE integration", async () => {
60
+ it("debe lanzar error 501 NOT_IMPLEMENTED para integración ONPREMISE", async () => {
56
61
  getConfig.mockReturnValue({
57
62
  integrationType: INTEGRATION_TYPE.ONPREMISE,
58
63
  });
59
64
 
60
- await expect(createFaceLivenessSession()).rejects.toThrow(
65
+ await expect(
66
+ sendFaceLiveness({
67
+ faceLiveness: mockBase64,
68
+ documentprefid: mockPrefId,
69
+ })
70
+ ).rejects.toThrow(
61
71
  new ApacuanaAPIError(
62
- "Creating a Face Liveness session is not supported for integration type: ONPREMISE",
72
+ "Send a Face Liveness is not supported for integration type: ONPREMISE",
63
73
  501,
64
74
  "NOT_IMPLEMENTED"
65
75
  )
66
76
  );
67
77
  });
68
78
 
69
- it("should throw an UNSUPPORTED_INTEGRATION_TYPE error for unsupported integration types", async () => {
70
- getConfig.mockReturnValue({ integrationType: "unsupported-type" });
79
+ it("debe lanzar UNSUPPORTED_INTEGRATION_TYPE para tipos no soportados", async () => {
80
+ getConfig.mockReturnValue({ integrationType: "INVALID_TYPE" });
71
81
 
72
- await expect(createFaceLivenessSession()).rejects.toThrow(
82
+ await expect(
83
+ sendFaceLiveness({
84
+ faceLiveness: mockBase64,
85
+ documentprefid: mockPrefId,
86
+ })
87
+ ).rejects.toThrow(
73
88
  new ApacuanaAPIError(
74
- "Unsupported integration type: unsupported-type",
89
+ "Unsupported integration type: INVALID_TYPE",
75
90
  400,
76
91
  "UNSUPPORTED_INTEGRATION_TYPE"
77
92
  )
78
93
  );
79
94
  });
80
95
 
81
- it("should re-throw ApacuanaAPIError if caught during session creation", async () => {
96
+ it("debe relanzar ApacuanaAPIError si ocurre durante el envío", async () => {
82
97
  const apiError = new ApacuanaAPIError("API Error", 500, "API_ERROR");
98
+ helpers.base64ToFile.mockReturnValue(new File([""], "test.png"));
83
99
  httpRequest.mockRejectedValue(apiError);
84
100
 
85
- await expect(createFaceLivenessSession()).rejects.toThrow(apiError);
86
- });
87
-
88
- it("should throw a generic error for other failures during session creation", async () => {
89
- const genericError = new Error("Network Error");
90
- httpRequest.mockRejectedValue(genericError);
91
-
92
- await expect(createFaceLivenessSession()).rejects.toThrow(
93
- `Failed to create Face Liveness session: ${genericError.message}`
94
- );
95
- });
96
- });
97
-
98
- describe("validateFaceLiveness", () => {
99
- const sessionId = "test-session-id";
100
-
101
- it("should throw an error if sessionId is not provided", async () => {
102
- await expect(validateFaceLiveness({})).rejects.toThrow(
103
- new ApacuanaAPIError(
104
- "sessionId is a required parameter.",
105
- 400,
106
- "INVALID_PARAMETER"
107
- )
108
- );
109
- });
110
-
111
- it("should return 'verified' on status 200", async () => {
112
- httpRequest.mockResolvedValue({ someData: "data" });
113
-
114
- const result = await validateFaceLiveness({ sessionId });
115
-
116
- expect(result).toBeInstanceOf(ApacuanaSuccess);
117
- expect(result.data).toEqual({ status: "verified", someData: "data" });
118
- expect(httpRequest).toHaveBeenCalledWith(
119
- "services/api/faceliveness/validate",
120
- { sessionid: sessionId },
121
- "POST"
122
- );
123
- });
124
-
125
- it.each([
126
- [402, "waitingForScan"],
127
- [403, "rejected"],
128
- [406, "processing"],
129
- [408, "expired"],
130
- ])(
131
- "should return status '%s' for statusCode %i",
132
- async (statusCode, status) => {
133
- const apiError = new ApacuanaAPIError("Error", statusCode, "API_ERROR");
134
- httpRequest.mockRejectedValue(apiError);
135
-
136
- const result = await validateFaceLiveness({ sessionId });
137
-
138
- expect(result).toBeInstanceOf(ApacuanaSuccess);
139
- expect(result.data).toEqual({ status });
140
- }
141
- );
142
-
143
- it("should throw an error for unhandled status codes", async () => {
144
- const apiError = new ApacuanaAPIError(
145
- "Unhandled Error",
146
- 500,
147
- "API_ERROR"
148
- );
149
- httpRequest.mockRejectedValue(apiError);
150
-
151
- await expect(validateFaceLiveness({ sessionId })).rejects.toThrow(
152
- apiError
153
- );
154
- });
155
-
156
- it("should throw a NOT_IMPLEMENTED error for ONPREMISE integration", async () => {
157
- getConfig.mockReturnValue({
158
- integrationType: INTEGRATION_TYPE.ONPREMISE,
159
- });
160
-
161
- await expect(validateFaceLiveness({ sessionId })).rejects.toThrow(
162
- new ApacuanaAPIError(
163
- "Validating a Face Liveness session is not supported for integration type: ONPREMISE",
164
- 501,
165
- "NOT_IMPLEMENTED"
166
- )
167
- );
101
+ await expect(
102
+ sendFaceLiveness({
103
+ faceLiveness: mockBase64,
104
+ documentprefid: mockPrefId,
105
+ })
106
+ ).rejects.toThrow(apiError);
168
107
  });
169
108
  });
170
109
  });