apacuana-sdk-core 0.2.0 → 0.3.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 (32) hide show
  1. package/README.md +64 -15
  2. package/coverage/clover.xml +145 -111
  3. package/coverage/coverage-final.json +6 -6
  4. package/coverage/lcov-report/index.html +30 -30
  5. package/coverage/lcov-report/src/api/certs.js.html +73 -28
  6. package/coverage/lcov-report/src/api/index.html +31 -31
  7. package/coverage/lcov-report/src/api/revocations.js.html +1 -1
  8. package/coverage/lcov-report/src/api/signatures.js.html +186 -159
  9. package/coverage/lcov-report/src/api/users.js.html +24 -63
  10. package/coverage/lcov-report/src/config/index.html +1 -1
  11. package/coverage/lcov-report/src/config/index.js.html +1 -1
  12. package/coverage/lcov-report/src/errors/index.html +1 -1
  13. package/coverage/lcov-report/src/errors/index.js.html +8 -8
  14. package/coverage/lcov-report/src/index.html +1 -1
  15. package/coverage/lcov-report/src/index.js.html +1 -1
  16. package/coverage/lcov-report/src/utils/constant.js.html +4 -4
  17. package/coverage/lcov-report/src/utils/helpers.js.html +101 -50
  18. package/coverage/lcov-report/src/utils/httpClient.js.html +1 -1
  19. package/coverage/lcov-report/src/utils/index.html +19 -19
  20. package/coverage/lcov.info +277 -205
  21. package/dist/index.js +136 -242
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +136 -242
  24. package/dist/index.mjs.map +1 -1
  25. package/package.json +1 -1
  26. package/src/api/certs.js +25 -10
  27. package/src/api/signatures.js +106 -97
  28. package/src/api/users.js +16 -29
  29. package/src/utils/helpers.js +17 -0
  30. package/tests/api/certs.test.js +58 -74
  31. package/tests/api/signatures.test.js +18 -73
  32. package/tests/api/users.test.js +10 -10
@@ -1,128 +1,112 @@
1
- import { generateCert, getCertStatus } from "../../src/api/certs";
2
- import { getConfig } from "../../src/config";
1
+ import { getConfig } from "../../src/config/index";
3
2
  import { httpRequest } from "../../src/utils/httpClient";
3
+ import helpers from "../../src/utils/helpers";
4
4
  import { ApacuanaAPIError } from "../../src/errors";
5
- import {
6
- INTEGRATION_TYPE,
7
- STATUS_CERTIFICATE,
8
- } from "../../src/utils/constant";
5
+ import { generateCert, getCertStatus } from "../../src/api/certs";
6
+ import { INTEGRATION_TYPE } from "../../src/utils/constant";
9
7
 
8
+ jest.mock("../../src/config/index");
10
9
  jest.mock("../../src/utils/httpClient");
11
- jest.mock("../../src/config");
10
+ jest.mock("../../src/utils/helpers");
12
11
 
13
- describe("API de Certificados - certs.js", () => {
14
- const validBase64Csr = "dGVzdA=="; // "test" in base64
15
-
16
- afterEach(() => {
12
+ describe("Certificate API - certs.js", () => {
13
+ beforeEach(() => {
17
14
  jest.clearAllMocks();
18
15
  });
19
16
 
20
17
  describe("generateCert", () => {
21
- it("debería generar un certificado con éxito para ONBOARDING", async () => {
22
- const mockResponse = { cert: "new-cert", success: true };
23
- httpRequest.mockResolvedValue(mockResponse);
18
+ it("should generate a certificate for ONBOARDING integration", async () => {
24
19
  getConfig.mockReturnValue({
25
20
  integrationType: INTEGRATION_TYPE.ONBOARDING,
26
21
  });
22
+ helpers.encryptedCsr.mockReturnValue("encrypted-csr");
23
+ httpRequest.mockResolvedValue({ cert: "new-cert", success: true });
27
24
 
28
- const result = await generateCert(validBase64Csr);
25
+ const result = await generateCert("some-csr");
29
26
 
30
- expect(result).toEqual(mockResponse);
27
+ expect(helpers.validateCsr).toHaveBeenCalledWith("some-csr");
28
+ expect(helpers.encryptedCsr).toHaveBeenCalledWith("some-csr");
31
29
  expect(httpRequest).toHaveBeenCalledWith(
32
30
  "services/api/register/certificate",
33
- expect.any(Object),
31
+ "encrypted-csr",
34
32
  "POST"
35
33
  );
34
+ expect(result).toEqual({ cert: "new-cert", success: true });
36
35
  });
37
36
 
38
- it("debería lanzar un error si el CSR no se proporciona", async () => {
37
+ it("should throw an error if API response does not contain a certificate", async () => {
39
38
  getConfig.mockReturnValue({
40
39
  integrationType: INTEGRATION_TYPE.ONBOARDING,
41
40
  });
42
- await expect(generateCert()).rejects.toThrow(
41
+ helpers.encryptedCsr.mockReturnValue("encrypted-csr");
42
+ httpRequest.mockResolvedValue({ success: false });
43
+
44
+ await expect(generateCert("some-csr")).rejects.toThrow(
43
45
  new ApacuanaAPIError(
44
- "La solicitud de firma de certificado (CSR) es requerida.",
45
- 400,
46
- "CSR_REQUIRED"
46
+ "The API response does not contain the certificate.",
47
+ undefined,
48
+ "INVALID_API_RESPONSE"
47
49
  )
48
50
  );
49
51
  });
50
52
 
51
- it("debería lanzar un error si el CSR no es un string", async () => {
53
+ it("should throw an error for ONPREMISE", async () => {
52
54
  getConfig.mockReturnValue({
53
- integrationType: INTEGRATION_TYPE.ONBOARDING,
55
+ integrationType: INTEGRATION_TYPE.ONPREMISE,
54
56
  });
55
- await expect(generateCert(12345)).rejects.toThrow(
57
+
58
+ await expect(generateCert("some-csr")).rejects.toThrow(
56
59
  new ApacuanaAPIError(
57
- "El CSR debe ser una cadena de texto válida y no puede estar vacía.",
58
- 400,
59
- "INVALID_CSR_FORMAT"
60
+ "Certificate generation is not supported for integration type: ONPREMISE",
61
+ 501,
62
+ "NOT_IMPLEMENTED"
60
63
  )
61
64
  );
62
65
  });
63
66
 
64
- it("debería lanzar un error si el CSR no está en formato Base64", async () => {
65
- getConfig.mockReturnValue({
66
- integrationType: INTEGRATION_TYPE.ONBOARDING,
67
- });
68
- await expect(generateCert("csr-invalido")).rejects.toThrow(
69
- new ApacuanaAPIError(
70
- "El CSR debe estar codificado en formato base64 válido.",
71
- 400,
72
- "INVALID_CSR_ENCODING"
73
- )
67
+ it("should throw an error if integration type is not supported", async () => {
68
+ getConfig.mockReturnValue({ integrationType: "INVALID_TYPE" });
69
+ await expect(generateCert("some-csr")).rejects.toThrow(
70
+ "Unsupported integration type: INVALID_TYPE"
74
71
  );
75
72
  });
76
73
 
77
- it("debería manejar la lógica para ONPREMISE", async () => {
78
- getConfig.mockReturnValue({ integrationType: INTEGRATION_TYPE.ONPREMISE });
79
- const consoleSpy = jest.spyOn(console, "log").mockImplementation(() => {});
80
- await generateCert(validBase64Csr);
81
- expect(consoleSpy).toHaveBeenCalledWith("-> Lógica para On-premise");
82
- consoleSpy.mockRestore();
83
- });
74
+ it("should re-throw ApacuanaAPIError if httpRequest fails", async () => {
75
+ getConfig.mockReturnValue({
76
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
77
+ });
78
+ const apiError = new ApacuanaAPIError("API Error", 500, "API_ERROR");
79
+ httpRequest.mockRejectedValue(apiError);
84
80
 
85
- it("debería lanzar un error para tipos de integración no soportados", async () => {
86
- getConfig.mockReturnValue({ integrationType: "UNSUPPORTED_TYPE" });
87
- await expect(generateCert(validBase64Csr)).rejects.toThrow(
88
- new ApacuanaAPIError(
89
- "Tipo de integración no soportado: UNSUPPORTED_TYPE",
90
- 400,
91
- "UNSUPPORTED_INTEGRATION_TYPE"
92
- )
93
- );
81
+ await expect(generateCert("some-csr")).rejects.toThrow(apiError);
94
82
  });
95
83
 
96
- it("debería lanzar un ApacuanaAPIError si la respuesta de la API no contiene el certificado", async () => {
97
- httpRequest.mockResolvedValue({ success: true }); // No 'cert' property
84
+ it("should throw a generic error if something else fails", async () => {
98
85
  getConfig.mockReturnValue({
99
86
  integrationType: INTEGRATION_TYPE.ONBOARDING,
100
87
  });
88
+ const genericError = new Error("Something failed");
89
+ httpRequest.mockRejectedValue(genericError);
101
90
 
102
- await expect(generateCert(validBase64Csr)).rejects.toThrow(
103
- new ApacuanaAPIError(
104
- "La respuesta de la API no contiene el certificado.",
105
- undefined,
106
- "INVALID_API_RESPONSE"
107
- )
91
+ await expect(generateCert("some-csr")).rejects.toThrow(
92
+ "Certificate generation failed: Something failed"
108
93
  );
109
94
  });
110
95
  });
111
96
 
112
97
  describe("getCertStatus", () => {
113
- it("debería devolver el estado del certificado correctamente", () => {
114
- const mockUserData = {
115
- cert: "some-cert-data",
116
- verificationstatus: { id: 1 }, // VERIFICATION_STATUS.APPROVED
117
- certificationId: "some-cert-id",
118
- approvedUser: true,
119
- };
98
+ it("should return the certificate status from helpers", () => {
99
+ const mockUserData = { certStatus: "VALID" };
120
100
  getConfig.mockReturnValue({ userData: mockUserData });
101
+ helpers.getCertificateStatus.mockReturnValue("VALID");
102
+
121
103
  const result = getCertStatus(true);
122
- expect(result).toEqual({
123
- status: STATUS_CERTIFICATE.current,
124
- success: true,
125
- });
104
+
105
+ expect(helpers.getCertificateStatus).toHaveBeenCalledWith(
106
+ mockUserData,
107
+ true
108
+ );
109
+ expect(result).toEqual({ status: "VALID", success: true });
126
110
  });
127
111
  });
128
- });
112
+ });
@@ -1,7 +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 { addSigner, getDocs } from "../../src/api/signatures";
4
+ import { addSigner, getDocs, getDigest, signDocument } from "../../src/api/signatures";
5
5
  import helpers from "../../src/utils/helpers";
6
6
  import { INTEGRATION_TYPE } from "../../src/utils/constant";
7
7
 
@@ -13,6 +13,7 @@ jest.mock("../../src/utils/helpers", () => ({
13
13
  validateSignOnPremiseData: jest.fn(),
14
14
  signDigest: jest.fn(),
15
15
  validateGetDocsData: jest.fn(),
16
+ validateGetDigestData: jest.fn(),
16
17
  }));
17
18
 
18
19
  describe("API - Signatures", () => {
@@ -38,18 +39,19 @@ describe("API - Signatures", () => {
38
39
  );
39
40
  });
40
41
 
41
- it("should call addSignerOnPremise for ONPREMISE integration", async () => {
42
+ it("should throw not implemented for ONPREMISE integration", async () => {
42
43
  getConfig.mockReturnValue({
43
44
  integrationType: INTEGRATION_TYPE.ONPREMISE,
44
45
  });
45
46
  const signerData = { name: "John Doe" };
46
47
 
47
- const result = await addSigner(signerData);
48
-
49
- expect(result).toEqual({
50
- signerId: "on-premise-signer-id",
51
- status: "added",
52
- });
48
+ await expect(addSigner(signerData)).rejects.toThrow(
49
+ new ApacuanaAPIError(
50
+ "Adding signers is not supported for integration type: ONPREMISE",
51
+ 501,
52
+ "NOT_IMPLEMENTED"
53
+ )
54
+ );
53
55
  });
54
56
 
55
57
  it("should throw an error for unsupported integration type", async () => {
@@ -57,7 +59,7 @@ describe("API - Signatures", () => {
57
59
  const signerData = { name: "test" };
58
60
  await expect(addSigner(signerData)).rejects.toThrow(
59
61
  new ApacuanaAPIError(
60
- "Tipo de integración no soportado: UNSUPPORTED",
62
+ "Unsupported integration type: UNSUPPORTED",
61
63
  400,
62
64
  "UNSUPPORTED_INTEGRATION_TYPE"
63
65
  )
@@ -67,70 +69,13 @@ describe("API - Signatures", () => {
67
69
  it("should throw an error if signerData is invalid", async () => {
68
70
  await expect(addSigner(null)).rejects.toThrow(
69
71
  new ApacuanaAPIError(
70
- "Los datos del firmante (signerData) son requeridos y deben ser un objeto no vacío.",
71
- 400,
72
- "INVALID_PARAMETER"
73
- )
74
- );
75
- });
76
- });
77
-
78
- /*
79
- describe("signDocument", () => {
80
- const onBoardingData = {
81
- documentData: { id: "doc1" },
82
- signatureData: { id: "sig1" },
83
- };
84
- const onPremiseData = {
85
- signature: { id: "sig1", positions: [] },
86
- cert: "my-cert",
87
- privateKey: "my-key",
88
- };
89
-
90
- it("should call signDocumentOnBoarding for ONBOARDING integration", async () => {
91
- getConfig.mockReturnValue({ integrationType: INTEGRATION_TYPE.ONBOARDING });
92
- const mockResponse = {
93
- success: true,
94
- id: "signed-doc-id",
95
- message: "Firmado",
96
- };
97
- httpRequest.mockResolvedValue(mockResponse);
98
-
99
- const result = await signDocument(onBoardingData);
100
-
101
- expect(httpRequest).toHaveBeenCalledWith(
102
- "/docs/sign",
103
- onBoardingData,
104
- "POST"
105
- );
106
- expect(result).toEqual(mockResponse);
107
- });
108
-
109
- it("should throw TypeError for ONPREMISE integration due to implementation issue", async () => {
110
- getConfig.mockReturnValue({
111
- integrationType: INTEGRATION_TYPE.ONPREMISE,
112
- });
113
- httpRequest
114
- .mockResolvedValueOnce({ data: { digest: "test-digest" } })
115
- .mockResolvedValueOnce({ data: "signed-response" });
116
- helpers.signDigest.mockResolvedValue("signed-digest");
117
-
118
- await expect(signDocument(onPremiseData)).rejects.toThrow(
119
- "Fallo en la firma del documento (on-premise): Cannot read properties of undefined (reading 'map')"
120
- );
121
- });
122
-
123
- it("should throw an error if data is invalid", async () => {
124
- await expect(signDocument({})).rejects.toThrow(
125
- new ApacuanaAPIError(
126
- "El parámetro 'data' es requerido y debe ser un objeto no vacío.",
72
+ "Signer data (signerData) is required and must be a non-empty object.",
127
73
  400,
128
74
  "INVALID_PARAMETER"
129
75
  )
130
76
  );
131
77
  });
132
78
  });
133
- */
134
79
 
135
80
  describe("getDocs", () => {
136
81
  const paginationData = { page: 1, size: 10 };
@@ -153,7 +98,7 @@ describe("API - Signatures", () => {
153
98
  );
154
99
  });
155
100
 
156
- it("should throw an error for ONPREMISE integration due to implementation issue", async () => {
101
+ it("should throw an error for ONPREMISE integration", async () => {
157
102
  getConfig.mockReturnValue({
158
103
  integrationType: INTEGRATION_TYPE.ONPREMISE,
159
104
  customerId: "test-customer",
@@ -161,13 +106,13 @@ describe("API - Signatures", () => {
161
106
  httpRequest.mockResolvedValue({ docs: [] });
162
107
 
163
108
  await expect(getDocs(paginationData)).rejects.toThrow(
164
- "La obtención de documentos no está soportada para el tipo de integración: ONBOARDING"
109
+ "Document retrieval is not supported for integration type: ONBOARDING"
165
110
  );
166
111
  });
167
112
 
168
113
  it("should throw an error if page or size are missing", async () => {
169
114
  const validationError = new ApacuanaAPIError(
170
- "Los parámetros 'page' y 'size' son requeridos.",
115
+ "Parameters 'page' and 'size' are required.",
171
116
  400,
172
117
  "INVALID_PARAMETER"
173
118
  );
@@ -180,7 +125,7 @@ describe("API - Signatures", () => {
180
125
 
181
126
  it("should throw an error if status is invalid", async () => {
182
127
  const validationError = new ApacuanaAPIError(
183
- "El parámetro 'status' no es válido.",
128
+ "Parameter 'status' is not valid.",
184
129
  400,
185
130
  "INVALID_PARAMETER"
186
131
  );
@@ -193,13 +138,13 @@ describe("API - Signatures", () => {
193
138
  );
194
139
  });
195
140
 
196
- it("should throw an error for non-on-premise integrations", async () => {
141
+ it("should throw an error for non-on-premise integrations when customerId is missing", async () => {
197
142
  getConfig.mockReturnValue({
198
143
  integrationType: INTEGRATION_TYPE.ONBOARDING,
199
144
  });
200
145
  await expect(getDocs(paginationData)).rejects.toThrow(
201
146
  new ApacuanaAPIError(
202
- "El 'customerId' no está configurado. Por favor, configure el SDK.",
147
+ "'customerId' is not configured. Please configure the SDK.",
203
148
  400,
204
149
  "CONFIGURATION_ERROR"
205
150
  )
@@ -67,34 +67,34 @@ describe("getCustomer", () => {
67
67
  });
68
68
  });
69
69
 
70
- test("debe lanzar un error si la configuración está incompleta", async () => {
70
+ test("should throw an error if configuration is incomplete", async () => {
71
71
  getConfig.mockReturnValue({
72
72
  verificationId: "mock-verify-id",
73
73
  customerId: null,
74
74
  });
75
75
 
76
76
  await expect(getCustomer()).rejects.toThrow(
77
- "El 'body' con 'userId' es un parámetro requerido para getCustomer."
77
+ "Both 'verificationId' and 'customerId' must be configured."
78
78
  );
79
79
  expect(httpRequest).not.toHaveBeenCalled();
80
80
  });
81
81
 
82
- test("debe lanzar un ApacuanaAPIError si el backend no devuelve sessionid o entry", async () => {
82
+ test("should throw ApacuanaAPIError if backend does not return sessionid or entry", async () => {
83
83
  httpRequest.mockResolvedValueOnce({
84
84
  success: true,
85
- message: "Error en el backend, no se pudo generar el token.",
85
+ message: "Backend error, token could not be generated.",
86
86
  entry: { userId: "mock-user" },
87
87
  });
88
88
 
89
89
  await expect(getCustomer()).rejects.toThrow(
90
- "La respuesta de la API no contiene el usuario."
90
+ "The API response does not contain the user."
91
91
  );
92
92
  expect(httpRequest).toHaveBeenCalledTimes(1);
93
93
  });
94
94
 
95
- test("debe relanzar el ApacuanaAPIError si la petición falla en el httpClient", async () => {
95
+ test("should rethrow ApacuanaAPIError if httpClient request fails", async () => {
96
96
  const apiError = new ApacuanaAPIError(
97
- "Error de autenticación",
97
+ "Authentication error",
98
98
  401,
99
99
  "AUTH_ERROR"
100
100
  );
@@ -104,12 +104,12 @@ describe("getCustomer", () => {
104
104
  expect(httpRequest).toHaveBeenCalledTimes(1);
105
105
  });
106
106
 
107
- test("debe lanzar un ApacuanaAPIError si ocurre un error inesperado", async () => {
108
- const genericError = new Error("Error de red o desconocido");
107
+ test("should throw ApacuanaAPIError on unexpected error", async () => {
108
+ const genericError = new Error("Network or unknown error");
109
109
  httpRequest.mockRejectedValueOnce(genericError);
110
110
 
111
111
  await expect(getCustomer()).rejects.toThrow(
112
- "Fallo inesperado al obtener el token: Error de red o desconocido"
112
+ "Unexpected failure getting token: Network or unknown error"
113
113
  );
114
114
  expect(httpRequest).toHaveBeenCalledTimes(1);
115
115
  });