apacuana-sdk-core 0.10.0 → 0.12.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 (58) hide show
  1. package/README.md +305 -286
  2. package/coverage/clover.xml +345 -248
  3. package/coverage/coverage-final.json +9 -7
  4. package/coverage/lcov-report/index.html +41 -26
  5. package/coverage/lcov-report/src/api/certs.js.html +162 -87
  6. package/coverage/lcov-report/src/api/faceLiveness.js.html +523 -0
  7. package/coverage/lcov-report/src/api/index.html +43 -28
  8. package/coverage/lcov-report/src/api/revocations.js.html +132 -90
  9. package/coverage/lcov-report/src/api/signatures.js.html +25 -253
  10. package/coverage/lcov-report/src/api/users.js.html +23 -14
  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 +13 -13
  16. package/coverage/lcov-report/src/index.js.html +96 -12
  17. package/coverage/lcov-report/src/success/index.html +116 -0
  18. package/coverage/lcov-report/src/success/index.js.html +106 -0
  19. package/coverage/lcov-report/src/utils/constant.js.html +4 -4
  20. package/coverage/lcov-report/src/utils/helpers.js.html +1 -1
  21. package/coverage/lcov-report/src/utils/httpClient.js.html +1 -1
  22. package/coverage/lcov-report/src/utils/index.html +1 -1
  23. package/coverage/lcov.info +597 -414
  24. package/dist/api/certs.d.ts +9 -70
  25. package/dist/api/faceLiveness.d.ts +6 -0
  26. package/dist/api/revocations.d.ts +6 -42
  27. package/dist/api/signatures.d.ts +11 -153
  28. package/dist/api/users.d.ts +16 -6
  29. package/dist/index.d.ts +6 -0
  30. package/dist/index.js +513 -259
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +513 -259
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/success/index.d.ts +7 -0
  35. package/dist/types/certs.d.ts +97 -0
  36. package/dist/types/faceLiveness.d.ts +11 -0
  37. package/dist/types/revocations.d.ts +51 -0
  38. package/dist/types/signatures.d.ts +147 -0
  39. package/dist/types/users.d.ts +260 -0
  40. package/package.json +1 -1
  41. package/src/api/certs.js +74 -49
  42. package/src/api/faceLiveness.js +146 -0
  43. package/src/api/revocations.js +76 -62
  44. package/src/api/signatures.js +21 -97
  45. package/src/api/users.js +12 -9
  46. package/src/index.js +33 -5
  47. package/src/success/index.js +8 -0
  48. package/src/types/certs.js +56 -0
  49. package/src/types/faceLiveness.js +16 -0
  50. package/src/types/revocations.js +45 -0
  51. package/src/types/signatures.js +91 -0
  52. package/src/types/users.js +73 -0
  53. package/tests/api/certs.test.js +99 -6
  54. package/tests/api/faceLiveness.test.js +170 -0
  55. package/tests/api/revocations.test.js +35 -35
  56. package/tests/api/signatures.test.js +11 -5
  57. package/tests/api/users.test.js +3 -2
  58. package/tests/index.test.js +16 -8
@@ -0,0 +1,170 @@
1
+ import {
2
+ createFaceLivenessSession,
3
+ validateFaceLiveness,
4
+ } from "../../src/api/faceLiveness";
5
+ import { httpRequest } from "../../src/utils/httpClient";
6
+ import ApacuanaSuccess from "../../src/success";
7
+ import { setConfig, getConfig } from "../../src/config";
8
+ import { ApacuanaAPIError } from "../../src/errors";
9
+ import { INTEGRATION_TYPE } from "../../src/utils/constant";
10
+
11
+ jest.mock("../../src/utils/httpClient", () => ({
12
+ httpRequest: jest.fn(),
13
+ }));
14
+
15
+ jest.mock("../../src/config", () => ({
16
+ getConfig: jest.fn(),
17
+ setConfig: jest.fn(),
18
+ }));
19
+
20
+ describe("FaceLiveness API", () => {
21
+ beforeEach(() => {
22
+ jest.clearAllMocks();
23
+ getConfig.mockReturnValue({ integrationType: INTEGRATION_TYPE.ONBOARDING });
24
+ });
25
+
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" });
31
+
32
+ const result = await createFaceLivenessSession();
33
+
34
+ expect(httpRequest).toHaveBeenCalledWith(
35
+ "services/api/faceliveness/create",
36
+ {},
37
+ "POST"
38
+ );
39
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
40
+ expect(result.data).toEqual({ sessionId: mockSessionId });
41
+ });
42
+
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
+ )
52
+ );
53
+ });
54
+
55
+ it("should throw a NOT_IMPLEMENTED error for ONPREMISE integration", async () => {
56
+ getConfig.mockReturnValue({
57
+ integrationType: INTEGRATION_TYPE.ONPREMISE,
58
+ });
59
+
60
+ await expect(createFaceLivenessSession()).rejects.toThrow(
61
+ new ApacuanaAPIError(
62
+ "Creating a Face Liveness session is not supported for integration type: ONPREMISE",
63
+ 501,
64
+ "NOT_IMPLEMENTED"
65
+ )
66
+ );
67
+ });
68
+
69
+ it("should throw an UNSUPPORTED_INTEGRATION_TYPE error for unsupported integration types", async () => {
70
+ getConfig.mockReturnValue({ integrationType: "unsupported-type" });
71
+
72
+ await expect(createFaceLivenessSession()).rejects.toThrow(
73
+ new ApacuanaAPIError(
74
+ "Unsupported integration type: unsupported-type",
75
+ 400,
76
+ "UNSUPPORTED_INTEGRATION_TYPE"
77
+ )
78
+ );
79
+ });
80
+
81
+ it("should re-throw ApacuanaAPIError if caught during session creation", async () => {
82
+ const apiError = new ApacuanaAPIError("API Error", 500, "API_ERROR");
83
+ httpRequest.mockRejectedValue(apiError);
84
+
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
+ );
168
+ });
169
+ });
170
+ });
@@ -1,10 +1,11 @@
1
- import { httpRequest } from "../../src/utils/httpClient";
2
- import { ApacuanaAPIError } from "../../src/errors";
3
1
  import {
4
2
  requestRevocation,
5
3
  getRevocationReasons,
6
4
  } from "../../src/api/revocations";
5
+ import { httpRequest } from "../../src/utils/httpClient";
7
6
  import { getConfig } from "../../src/config";
7
+ import { ApacuanaAPIError } from "../../src/errors";
8
+ import ApacuanaSuccess from "../../src/success";
8
9
  import { INTEGRATION_TYPE } from "../../src/utils/constant";
9
10
 
10
11
  jest.mock("../../src/utils/httpClient");
@@ -13,67 +14,72 @@ jest.mock("../../src/config");
13
14
  describe("Revocations API", () => {
14
15
  beforeEach(() => {
15
16
  jest.clearAllMocks();
17
+ getConfig.mockReturnValue({ integrationType: INTEGRATION_TYPE.ONBOARDING });
16
18
  });
17
19
 
18
20
  describe("requestRevocation", () => {
19
21
  it("should throw an error if reasonCode is not provided", async () => {
20
22
  await expect(requestRevocation(null)).rejects.toThrow(
21
- "Código de motivo es requerido para requestRevocation."
23
+ 'The "params" object with a numeric "reasonCode" property is required.'
24
+ );
25
+ await expect(requestRevocation({})).rejects.toThrow(
26
+ 'The "params" object with a numeric "reasonCode" property is required.'
22
27
  );
23
28
  });
24
29
 
25
30
  it("should make a POST request to the correct endpoint with the reasonCode", async () => {
26
- const reasonCode = "COMPROMISED";
27
- const mockResponse = { success: true, message: "Revocation requested" };
31
+ const params = { reasonCode: 1 };
32
+ const mockResponse = { success: true };
28
33
  httpRequest.mockResolvedValue(mockResponse);
29
34
 
30
- const result = await requestRevocation(reasonCode);
35
+ const result = await requestRevocation(params);
31
36
 
32
37
  expect(httpRequest).toHaveBeenCalledWith(
33
38
  "services/api/onboardingclient/requestcert",
34
- { reason: reasonCode },
39
+ params,
35
40
  "POST"
36
41
  );
37
- expect(result).toEqual(mockResponse);
42
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
43
+ expect(result.data).toEqual(mockResponse);
38
44
  });
39
45
 
40
46
  it("should throw a generic error if the httpRequest fails", async () => {
41
- const reasonCode = "COMPROMISED";
42
- const apiError = new Error("Network error");
47
+ const params = { reasonCode: 1 };
48
+ const apiError = new Error("Something went wrong");
43
49
  httpRequest.mockRejectedValue(apiError);
44
50
 
45
- await expect(requestRevocation(reasonCode)).rejects.toThrow(
46
- `Fallo en la solicitud de revocación: ${apiError.message}`
51
+ await expect(requestRevocation(params)).rejects.toThrow(
52
+ `Failed to request revocation: ${apiError.message}`
47
53
  );
48
54
  });
55
+
56
+ it("should re-throw ApacuanaAPIError if caught", async () => {
57
+ const params = { reasonCode: 1 };
58
+ const apiError = new ApacuanaAPIError("API Error");
59
+ httpRequest.mockRejectedValue(apiError);
60
+
61
+ await expect(requestRevocation(params)).rejects.toThrow(apiError);
62
+ });
49
63
  });
50
64
 
51
65
  describe("getRevocationReasons", () => {
52
66
  it("should make a GET request and return the reasons for ONBOARDING", async () => {
53
- getConfig.mockReturnValue({
54
- integrationType: INTEGRATION_TYPE.ONBOARDING,
55
- });
56
- const mockReasons = [
57
- { code: "0", description: "Unspecified" },
58
- { code: "1", description: "Key Compromise" },
59
- ];
67
+ const mockReasons = [{ code: "01", description: "Test Reason" }];
60
68
  httpRequest.mockResolvedValue({ records: mockReasons });
61
69
 
62
70
  const result = await getRevocationReasons();
63
71
 
64
72
  expect(httpRequest).toHaveBeenCalledWith(
65
- "GET",
66
73
  "config/api/revocation/reasonsonboarding",
67
- {}
74
+ {},
75
+ "GET"
68
76
  );
69
- expect(result).toEqual(mockReasons);
77
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
78
+ expect(result.data).toEqual({ reasons: mockReasons });
70
79
  });
71
80
 
72
81
  it("should throw an error if the API response does not contain 'records'", async () => {
73
- getConfig.mockReturnValue({
74
- integrationType: INTEGRATION_TYPE.ONBOARDING,
75
- });
76
- httpRequest.mockResolvedValue({ data: [] }); // Respuesta inválida
82
+ httpRequest.mockResolvedValue({ data: [] }); // Invalid response
77
83
 
78
84
  await expect(getRevocationReasons()).rejects.toThrow(
79
85
  new ApacuanaAPIError("Failed to fetch revocation reasons.")
@@ -81,24 +87,18 @@ describe("Revocations API", () => {
81
87
  });
82
88
 
83
89
  it("should re-throw ApacuanaAPIError if caught", async () => {
84
- getConfig.mockReturnValue({
85
- integrationType: INTEGRATION_TYPE.ONBOARDING,
86
- });
87
- const apiError = new ApacuanaAPIError("API is down", 500);
90
+ const apiError = new ApacuanaAPIError("API Error");
88
91
  httpRequest.mockRejectedValue(apiError);
89
92
 
90
93
  await expect(getRevocationReasons()).rejects.toThrow(apiError);
91
94
  });
92
95
 
93
96
  it("should throw a generic error for other types of errors", async () => {
94
- getConfig.mockReturnValue({
95
- integrationType: INTEGRATION_TYPE.ONBOARDING,
96
- });
97
97
  const genericError = new Error("Something went wrong");
98
98
  httpRequest.mockRejectedValue(genericError);
99
99
 
100
100
  await expect(getRevocationReasons()).rejects.toThrow(
101
- "Failed to get revocation reasons. Please try again later."
101
+ `Failed to get revocation reasons: ${genericError.message}`
102
102
  );
103
103
  });
104
104
 
@@ -109,7 +109,7 @@ describe("Revocations API", () => {
109
109
 
110
110
  await expect(getRevocationReasons()).rejects.toThrow(
111
111
  new ApacuanaAPIError(
112
- "Get revocation reasons is not supported for integration type: ONPREMISE",
112
+ "Getting revocation reasons is not supported for integration type: ONPREMISE",
113
113
  501,
114
114
  "NOT_IMPLEMENTED"
115
115
  )
@@ -1,6 +1,7 @@
1
1
  import { getConfig } from "../../src/config";
2
2
  import { httpRequest } from "../../src/utils/httpClient";
3
3
  import { ApacuanaAPIError } from "../../src/errors";
4
+ import ApacuanaSuccess from "../../src/success";
4
5
  import {
5
6
  addSigner,
6
7
  getDocs,
@@ -184,7 +185,8 @@ describe("API - Signatures", () => {
184
185
  { publickey: signData.cert },
185
186
  "POST"
186
187
  );
187
- expect(result).toEqual({ digest: "test-digest", success: true });
188
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
189
+ expect(result.data).toEqual({ digest: "test-digest" });
188
190
  });
189
191
 
190
192
  it("should throw an error if digest is not in response for ONBOARDING", async () => {
@@ -257,7 +259,8 @@ describe("API - Signatures", () => {
257
259
  },
258
260
  "PUT"
259
261
  );
260
- expect(result).toEqual(mockResponse);
262
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
263
+ expect(result.data).toEqual(mockResponse);
261
264
  });
262
265
 
263
266
  it("should throw not implemented for ONPREMISE integration", async () => {
@@ -346,7 +349,8 @@ describe("API - Signatures", () => {
346
349
  { file: validFile },
347
350
  "POST"
348
351
  );
349
- expect(result).toEqual({ success: true, id: "123" });
352
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
353
+ expect(result.data).toEqual({ success: true, id: "123" });
350
354
  });
351
355
 
352
356
  it("should throw not implemented for ONPREMISE integration", async () => {
@@ -392,7 +396,8 @@ describe("API - Signatures", () => {
392
396
  {},
393
397
  "GET"
394
398
  );
395
- expect(result).toEqual(mockResponse);
399
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
400
+ expect(result.data).toEqual(mockResponse);
396
401
  });
397
402
 
398
403
  it("should throw not implemented for ONPREMISE integration", async () => {
@@ -436,7 +441,8 @@ describe("API - Signatures", () => {
436
441
  {},
437
442
  "DELETE"
438
443
  );
439
- expect(result).toEqual(mockResponse);
444
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
445
+ expect(result.data).toEqual(mockResponse);
440
446
  });
441
447
 
442
448
  it("should throw not implemented for ONPREMISE integration", async () => {
@@ -3,6 +3,7 @@ import { httpRequest } from "../../src/utils/httpClient.js";
3
3
  import { getConfig } from "../../src/config/index.js";
4
4
  import { ApacuanaAPIError } from "../../src/errors/index.js";
5
5
  import getCustomer from "../../src/api/users.js";
6
+ import ApacuanaSuccess from "../../src/success/index.js";
6
7
 
7
8
  // Mockear las dependencias:
8
9
  jest.mock("../../src/utils/httpClient.js", () => ({
@@ -56,8 +57,8 @@ describe("getCustomer", () => {
56
57
  "POST"
57
58
  );
58
59
 
59
- expect(result).toEqual({
60
- success: true,
60
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
61
+ expect(result.data).toEqual({
61
62
  token: "mock-session-id-12345",
62
63
  userData: {
63
64
  userId: "mock-user",
@@ -1,8 +1,9 @@
1
1
  // tests/index.test.js
2
2
  import apacuana from "../src/index.js";
3
3
  import { setConfig, getConfig } from "../src/config/index.js";
4
- import { initHttpClient } from "../src/utils/httpClient.js";
4
+ import { initHttpClient, setAuthToken } from "../src/utils/httpClient.js";
5
5
  import getCustomer from "../src/api/users.js";
6
+ import ApacuanaSuccess from "../src/success/index.js";
6
7
 
7
8
  // Mockear todas las dependencias del index.js
8
9
  jest.mock("../src/config/index.js", () => ({
@@ -36,8 +37,11 @@ describe("Apacuana SDK Initialization (init)", () => {
36
37
 
37
38
  // Mockear la respuesta exitosa de getCustomer para la mayoría de las pruebas.
38
39
  getCustomer.mockResolvedValue({
39
- token: "mock-session-token",
40
- userData: { id: "mock-user-id" }
40
+ success: true,
41
+ data: {
42
+ token: "mock-session-token",
43
+ userData: { id: "mock-user-id" },
44
+ },
41
45
  });
42
46
 
43
47
  // Opcional: Mockear console.log para no ensuciar la consola durante las pruebas.
@@ -63,8 +67,12 @@ describe("Apacuana SDK Initialization (init)", () => {
63
67
  // 3. Verificar que getCustomer fue llamado.
64
68
  expect(getCustomer).toHaveBeenCalledWith();
65
69
 
66
- // 4. Verificar que se retorna true al finalizar la inicialización.
67
- expect(result).toBe(true);
70
+ // 4. Verificar que se retorna una instancia de ApacuanaSuccess al finalizar la inicialización.
71
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
72
+ expect(result.data).toEqual({
73
+ initialized: true,
74
+ message: "SDK inicializado correctamente.",
75
+ });
68
76
 
69
77
  // 5. Verificar que las funciones se llamaron el número correcto de veces.
70
78
  expect(setConfig).toHaveBeenCalledTimes(2); // Una vez inicial, una vez para guardar token
@@ -113,10 +121,10 @@ describe("Apacuana SDK Initialization (init)", () => {
113
121
  expect(setConfig).toHaveBeenLastCalledWith({
114
122
  ...mockConfig,
115
123
  token: "mock-session-token",
116
- userData: { id: "mock-user-id" }
124
+ userData: { id: "mock-user-id" },
117
125
  });
118
126
 
119
- // Verificar que el token es devuelto.
120
- expect(result).toBe(true);
127
+ // Verificar que la respuesta es una instancia de ApacuanaSuccess.
128
+ expect(result).toBeInstanceOf(ApacuanaSuccess);
121
129
  });
122
130
  });