apacuana-sdk-core 0.1.0 → 0.2.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 (35) hide show
  1. package/README.md +117 -46
  2. package/coverage/clover.xml +205 -91
  3. package/coverage/coverage-final.json +9 -6
  4. package/coverage/lcov-report/index.html +48 -33
  5. package/coverage/lcov-report/src/api/certs.js.html +74 -83
  6. package/coverage/lcov-report/src/api/index.html +36 -21
  7. package/coverage/lcov-report/src/api/revocations.js.html +1 -1
  8. package/coverage/lcov-report/src/api/signatures.js.html +528 -81
  9. package/coverage/lcov-report/src/api/users.js.html +5 -2
  10. package/coverage/lcov-report/src/config/index.html +21 -21
  11. package/coverage/lcov-report/src/config/index.js.html +65 -32
  12. package/coverage/lcov-report/src/errors/index.html +5 -5
  13. package/coverage/lcov-report/src/errors/index.js.html +13 -10
  14. package/coverage/lcov-report/src/index.html +1 -1
  15. package/coverage/lcov-report/src/index.js.html +13 -4
  16. package/coverage/lcov-report/src/utils/constant.js.html +4 -4
  17. package/coverage/lcov-report/src/utils/helpers.js.html +268 -145
  18. package/coverage/lcov-report/src/utils/httpClient.js.html +646 -0
  19. package/coverage/lcov-report/src/utils/index.html +32 -17
  20. package/coverage/lcov.info +429 -167
  21. package/dist/index.js +390 -150
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +390 -150
  24. package/dist/index.mjs.map +1 -1
  25. package/package.json +1 -1
  26. package/src/api/certs.js +27 -30
  27. package/src/api/signatures.js +205 -50
  28. package/src/api/users.js +1 -0
  29. package/src/errors/index.js +1 -0
  30. package/src/index.js +4 -1
  31. package/src/utils/helpers.js +140 -99
  32. package/tests/api/certs.test.js +126 -4
  33. package/tests/api/signatures.test.js +207 -4
  34. package/tests/api/users.test.js +1 -0
  35. package/src/auth/index.js +0 -24
@@ -1,9 +1,10 @@
1
- import * as pkijs from "pkijs";
2
- import * as asn1js from "asn1js";
1
+ import CryptoJS from "crypto-js";
3
2
  import { getCrypto } from "pkijs";
4
3
  import { STATUS_CERTIFICATE, VERIFICATION_STATUS } from "./constant";
5
4
  import { ApacuanaAPIError } from "../errors/index";
6
5
 
6
+ const KEY_HEX = "dRgUkXp2s5v8y/B?";
7
+
7
8
  const getCertificateStatus = (userData, certificateInDevice) => {
8
9
  if (!userData) {
9
10
  throw new Error("El parámetro userData es requerido.");
@@ -41,126 +42,166 @@ const getCertificateStatus = (userData, certificateInDevice) => {
41
42
  return STATUS_CERTIFICATE.revoque;
42
43
  };
43
44
 
44
- const generateKeyPair = async (
45
- signAlg = "RSASSA-PKCS1-v1_5",
46
- hashAlg = "SHA-256"
47
- ) => {
48
- try {
49
- const crypto = getCrypto();
50
- if (!crypto) {
51
- throw new Error("API criptográfica no disponible a través de pkijs.");
52
- }
45
+ // Función para convertir ArrayBuffer a Base64
46
+ const arrayBufferToBase64 = (buffer) => {
47
+ const binary = String.fromCharCode.apply(null, new Uint8Array(buffer));
48
+ return window.btoa(binary);
49
+ };
50
+
51
+ async function exportPrivateKey(key) {
52
+ const crypto = getCrypto();
53
+ const exported = await crypto.exportKey("pkcs8", key);
54
+ const exportablePrivateKey = new Uint8Array(exported);
55
+ return arrayBufferToBase64(exportablePrivateKey);
56
+ }
57
+
58
+ const encryptedCsr = (csr, encryptKey = KEY_HEX) => {
59
+ const body = {
60
+ csr: CryptoJS.AES.encrypt(csr, encryptKey, {
61
+ mode: CryptoJS.mode.ECB,
62
+ padding: CryptoJS.pad.Pkcs7,
63
+ }).toString(),
64
+ };
65
+ return body;
66
+ };
53
67
 
54
- const keyPair = await crypto.generateKey(
55
- {
56
- name: signAlg,
57
- modulusLength: 2048,
58
- publicExponent: new Uint8Array([1, 0, 1]),
59
- hash: { name: hashAlg },
60
- },
61
- true,
62
- ["sign", "verify"]
68
+ const validateOnBoardingSignerData = (signerData) => {
69
+ if (!signerData.name || typeof signerData.name !== "string") {
70
+ throw new ApacuanaAPIError(
71
+ 'El campo "name" es requerido y debe ser una cadena de texto.',
72
+ 400,
73
+ "INVALID_PARAMETER_FORMAT"
63
74
  );
75
+ }
64
76
 
65
- return keyPair;
66
- } catch (error) {
67
- console.error("Error durante la generación del par de claves:", error);
77
+ if (!signerData.reference || typeof signerData.reference !== "string") {
68
78
  throw new ApacuanaAPIError(
69
- `Fallo en la generación del par de claves: ${error.message}`,
70
- 0,
71
- "KEY_PAIR_GENERATION_ERROR"
79
+ 'El campo "reference" es requerido y debe ser una cadena de texto.',
80
+ 400,
81
+ "INVALID_PARAMETER_FORMAT"
72
82
  );
73
83
  }
74
- };
75
84
 
76
- const generateCSR = async (keyPair, userData, hashAlg = "SHA-256") => {
77
- try {
78
- const { publicKey, privateKey } = keyPair;
85
+ const validDocTypes = ["V", "P", "E"];
86
+ if (!signerData.typedoc || !validDocTypes.includes(signerData.typedoc)) {
87
+ throw new ApacuanaAPIError(
88
+ 'El campo "typedoc" es requerido y debe ser uno de los siguientes valores: V, P, E.',
89
+ 400,
90
+ "INVALID_PARAMETER_FORMAT"
91
+ );
92
+ }
79
93
 
80
- // 1. Validar los parámetros de entrada.
81
- if (!keyPair || !publicKey || !privateKey) {
82
- throw new Error(
83
- "Par de claves no válido. Es necesario un CryptoKeyPair."
94
+ if (!signerData.doc || typeof signerData.doc !== "string") {
95
+ throw new ApacuanaAPIError(
96
+ 'El campo "doc" es requerido y debe ser una cadena de texto.',
97
+ 400,
98
+ "INVALID_PARAMETER_FORMAT"
99
+ );
100
+ }
101
+
102
+ if (
103
+ !Array.isArray(signerData.signature) ||
104
+ signerData.signature.length === 0
105
+ ) {
106
+ throw new ApacuanaAPIError(
107
+ 'El campo "signature" es requerido y debe ser un array no vacío.',
108
+ 400,
109
+ "INVALID_PARAMETER_FORMAT"
110
+ );
111
+ }
112
+
113
+ signerData.signature.forEach((sig, index) => {
114
+ if (!Number.isInteger(sig.page) || sig.page < 1) {
115
+ throw new ApacuanaAPIError(
116
+ `La página de la firma ${
117
+ index + 1
118
+ } debe ser un número entero positivo.`,
119
+ 400,
120
+ "INVALID_PARAMETER_FORMAT"
84
121
  );
85
122
  }
86
- if (!userData || !userData.email) {
87
- throw new Error(
88
- "Datos de usuario incompletos. El correo electrónico es requerido."
123
+
124
+ if (typeof sig.x !== "number" || sig.x < 0 || sig.x > 1) {
125
+ throw new ApacuanaAPIError(
126
+ `La coordenada X de la firma ${
127
+ index + 1
128
+ } debe ser un número entre 0 y 1.`,
129
+ 400,
130
+ "INVALID_PARAMETER_FORMAT"
89
131
  );
90
132
  }
91
133
 
92
- const pkcs10 = new pkijs.CertificationRequest();
93
- pkcs10.version = 0;
94
-
95
- const subjectAttributes = [
96
- {
97
- type: "2.5.4.6", // OID para 'Country' (C)
98
- value: new asn1js.PrintableString({ value: userData.country || "VE" }),
99
- },
100
- {
101
- type: "2.5.4.3", // OID para 'Common Name' (CN)
102
- value: new asn1js.Utf8String({ value: userData.commonName || "N/A" }),
103
- },
104
- {
105
- type: "1.2.840.113549.1.9.1", // OID para 'E-mail' (E)
106
- value: new asn1js.IA5String({ value: userData.email }),
107
- },
108
- // Puedes agregar más atributos aquí, como:
109
- // {
110
- // type: '2.5.4.8', // OID para 'State or Province' (ST)
111
- // value: new asn1js.Utf8String({ value: userData.state || 'N/A' }),
112
- // },
113
- // {
114
- // type: '2.5.4.7', // OID para 'Locality' (L)
115
- // value: new asn1js.Utf8String({ value: userData.locality || 'N/A' }),
116
- // },
117
- ].filter((attr) => attr.value.value); // Filtra atributos sin valor.
118
-
119
- // 3. Asignar los atributos al Subject.
120
- subjectAttributes.forEach((attr) =>
121
- pkcs10.subject.typesAndValues.push(new pkijs.AttributeTypeAndValue(attr))
134
+ if (typeof sig.y !== "number" || sig.y < 0 || sig.y > 1) {
135
+ throw new ApacuanaAPIError(
136
+ `La coordenada Y de la firma ${
137
+ index + 1
138
+ } debe ser un número entre 0 y 1.`,
139
+ 400,
140
+ "INVALID_PARAMETER_FORMAT"
141
+ );
142
+ }
143
+ });
144
+ };
145
+
146
+ const validateCsr = (csr) => {
147
+ const base64Regex = /^[A-Za-z0-9+/=]+$/;
148
+
149
+ if (!csr) {
150
+ throw new ApacuanaAPIError(
151
+ "La solicitud de firma de certificado (CSR) es requerida.",
152
+ 400,
153
+ "INVALID_PARAMETER"
122
154
  );
155
+ }
123
156
 
124
- // 4. Importar la clave pública y firmar la solicitud con la clave privada.
125
- await pkcs10.subjectPublicKeyInfo.importKey(publicKey);
126
- await pkcs10.sign(privateKey, hashAlg);
127
-
128
- // 5. Codificar el CSR para el envío.
129
- const csr = pkcs10.toSchema().toBER(false);
130
-
131
- // 6. Retornar el CSR y el Subject.
132
- return {
133
- csr,
134
- subject: pkcs10.subject,
135
- };
136
- } catch (error) {
137
- // Manejo de errores centralizado.
138
- console.error("Error durante la generación del CSR:", error);
157
+ if (typeof csr !== "string" || csr.trim() === "") {
139
158
  throw new ApacuanaAPIError(
140
- `Fallo en la generación del CSR: ${error.message}`,
141
- 0,
142
- "CSR_GENERATION_ERROR"
159
+ "El CSR debe ser una cadena de texto válida y no puede estar vacía.",
160
+ 400,
161
+ "INVALID_PARAMETER_FORMAT"
143
162
  );
144
163
  }
145
- };
146
164
 
147
- // Función para convertir ArrayBuffer a Base64
148
- const arrayBufferToBase64 = (buffer) => {
149
- const binary = String.fromCharCode.apply(null, new Uint8Array(buffer));
150
- return window.btoa(binary);
165
+ if (!base64Regex.test(csr)) {
166
+ throw new ApacuanaAPIError(
167
+ "El CSR debe estar codificado en formato base64 válido.",
168
+ 400,
169
+ "INVALID_PARAMETER_FORMAT"
170
+ );
171
+ }
151
172
  };
152
173
 
153
- export async function exportPrivateKey(key) {
154
- const crypto = getCrypto();
155
- const exported = await crypto.exportKey("pkcs8", key);
156
- const exportablePrivateKey = new Uint8Array(exported);
157
- return arrayBufferToBase64(exportablePrivateKey);
158
- }
174
+ const validateGetDocsData = (data) => {
175
+ if (
176
+ !data ||
177
+ typeof data.page === "undefined" ||
178
+ typeof data.size === "undefined"
179
+ ) {
180
+ throw new ApacuanaAPIError(
181
+ "Los parámetros 'page' y 'size' son requeridos.",
182
+ 400,
183
+ "INVALID_PARAMETER"
184
+ );
185
+ }
186
+
187
+ if (
188
+ typeof data.status !== "undefined" &&
189
+ ![-1, 0, 1, 2].includes(data.status)
190
+ ) {
191
+ throw new ApacuanaAPIError(
192
+ "El parámetro 'status' no es válido. Los valores permitidos son: -1, 0, 1, 2.",
193
+ 400,
194
+ "INVALID_PARAMETER"
195
+ );
196
+ }
197
+ };
159
198
 
160
- export const helpers = {
199
+ export default {
161
200
  getCertificateStatus,
162
- generateKeyPair,
163
- generateCSR,
164
201
  exportPrivateKey,
165
202
  arrayBufferToBase64,
203
+ encryptedCsr,
204
+ validateOnBoardingSignerData,
205
+ validateCsr,
206
+ validateGetDocsData,
166
207
  };
@@ -1,6 +1,128 @@
1
- // tests/api/certs.test.js
2
- describe('Certificates API', () => {
3
- test('placeholder test', () => {
4
- expect(true).toBe(true);
1
+ import { generateCert, getCertStatus } from "../../src/api/certs";
2
+ import { getConfig } from "../../src/config";
3
+ import { httpRequest } from "../../src/utils/httpClient";
4
+ import { ApacuanaAPIError } from "../../src/errors";
5
+ import {
6
+ INTEGRATION_TYPE,
7
+ STATUS_CERTIFICATE,
8
+ } from "../../src/utils/constant";
9
+
10
+ jest.mock("../../src/utils/httpClient");
11
+ jest.mock("../../src/config");
12
+
13
+ describe("API de Certificados - certs.js", () => {
14
+ const validBase64Csr = "dGVzdA=="; // "test" in base64
15
+
16
+ afterEach(() => {
17
+ jest.clearAllMocks();
18
+ });
19
+
20
+ 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);
24
+ getConfig.mockReturnValue({
25
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
26
+ });
27
+
28
+ const result = await generateCert(validBase64Csr);
29
+
30
+ expect(result).toEqual(mockResponse);
31
+ expect(httpRequest).toHaveBeenCalledWith(
32
+ "services/api/register/certificate",
33
+ expect.any(Object),
34
+ "POST"
35
+ );
36
+ });
37
+
38
+ it("debería lanzar un error si el CSR no se proporciona", async () => {
39
+ getConfig.mockReturnValue({
40
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
41
+ });
42
+ await expect(generateCert()).rejects.toThrow(
43
+ new ApacuanaAPIError(
44
+ "La solicitud de firma de certificado (CSR) es requerida.",
45
+ 400,
46
+ "CSR_REQUIRED"
47
+ )
48
+ );
49
+ });
50
+
51
+ it("debería lanzar un error si el CSR no es un string", async () => {
52
+ getConfig.mockReturnValue({
53
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
54
+ });
55
+ await expect(generateCert(12345)).rejects.toThrow(
56
+ 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
+ )
61
+ );
62
+ });
63
+
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
+ )
74
+ );
75
+ });
76
+
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
+ });
84
+
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
+ );
94
+ });
95
+
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
98
+ getConfig.mockReturnValue({
99
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
100
+ });
101
+
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
+ )
108
+ );
109
+ });
110
+ });
111
+
112
+ 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
+ };
120
+ getConfig.mockReturnValue({ userData: mockUserData });
121
+ const result = getCertStatus(true);
122
+ expect(result).toEqual({
123
+ status: STATUS_CERTIFICATE.current,
124
+ success: true,
125
+ });
126
+ });
5
127
  });
6
128
  });
@@ -1,6 +1,209 @@
1
- // tests/api/signatures.test.js
2
- describe('Signatures API', () => {
3
- test('placeholder test', () => {
4
- expect(true).toBe(true);
1
+ import { getConfig } from "../../src/config";
2
+ import { httpRequest } from "../../src/utils/httpClient";
3
+ import { ApacuanaAPIError } from "../../src/errors";
4
+ import { addSigner, getDocs } from "../../src/api/signatures";
5
+ import helpers from "../../src/utils/helpers";
6
+ import { INTEGRATION_TYPE } from "../../src/utils/constant";
7
+
8
+ jest.mock("../../src/config");
9
+ jest.mock("../../src/utils/httpClient");
10
+ jest.mock("../../src/utils/helpers", () => ({
11
+ validateOnBoardingSignerData: jest.fn(),
12
+ validateSignOnBoardingData: jest.fn(),
13
+ validateSignOnPremiseData: jest.fn(),
14
+ signDigest: jest.fn(),
15
+ validateGetDocsData: jest.fn(),
16
+ }));
17
+
18
+ describe("API - Signatures", () => {
19
+ afterEach(() => {
20
+ jest.resetAllMocks();
21
+ });
22
+
23
+ describe("addSigner", () => {
24
+ it("should call addSignerOnBoarding for ONBOARDING integration", async () => {
25
+ getConfig.mockReturnValue({ integrationType: INTEGRATION_TYPE.ONBOARDING });
26
+ const signerData = { typedoc: "V", doc: "12345678" };
27
+ httpRequest.mockResolvedValue({ success: true });
28
+
29
+ await addSigner(signerData);
30
+
31
+ expect(helpers.validateOnBoardingSignerData).toHaveBeenCalledWith(
32
+ signerData
33
+ );
34
+ expect(httpRequest).toHaveBeenCalledWith(
35
+ "services/api/documents/signing",
36
+ signerData,
37
+ "POST"
38
+ );
39
+ });
40
+
41
+ it("should call addSignerOnPremise for ONPREMISE integration", async () => {
42
+ getConfig.mockReturnValue({
43
+ integrationType: INTEGRATION_TYPE.ONPREMISE,
44
+ });
45
+ const signerData = { name: "John Doe" };
46
+
47
+ const result = await addSigner(signerData);
48
+
49
+ expect(result).toEqual({
50
+ signerId: "on-premise-signer-id",
51
+ status: "added",
52
+ });
53
+ });
54
+
55
+ it("should throw an error for unsupported integration type", async () => {
56
+ getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
57
+ const signerData = { name: "test" };
58
+ await expect(addSigner(signerData)).rejects.toThrow(
59
+ new ApacuanaAPIError(
60
+ "Tipo de integración no soportado: UNSUPPORTED",
61
+ 400,
62
+ "UNSUPPORTED_INTEGRATION_TYPE"
63
+ )
64
+ );
65
+ });
66
+
67
+ it("should throw an error if signerData is invalid", async () => {
68
+ await expect(addSigner(null)).rejects.toThrow(
69
+ 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.",
127
+ 400,
128
+ "INVALID_PARAMETER"
129
+ )
130
+ );
131
+ });
132
+ });
133
+ */
134
+
135
+ describe("getDocs", () => {
136
+ const paginationData = { page: 1, size: 10 };
137
+
138
+ it("should call httpRequest with correct URL when status is provided", async () => {
139
+ getConfig.mockReturnValue({
140
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
141
+ customerId: "test-customer",
142
+ });
143
+ const dataWithStatus = { ...paginationData, status: 1 };
144
+ httpRequest.mockResolvedValue({ docs: [] });
145
+
146
+ await getDocs(dataWithStatus);
147
+
148
+ expect(helpers.validateGetDocsData).toHaveBeenCalledWith(dataWithStatus);
149
+ expect(httpRequest).toHaveBeenCalledWith(
150
+ "services/api/documents/listcustomer?page=1&customerid=test-customer&size=10&status=1",
151
+ {},
152
+ "GET"
153
+ );
154
+ });
155
+
156
+ it("should throw an error for ONPREMISE integration due to implementation issue", async () => {
157
+ getConfig.mockReturnValue({
158
+ integrationType: INTEGRATION_TYPE.ONPREMISE,
159
+ customerId: "test-customer",
160
+ });
161
+ httpRequest.mockResolvedValue({ docs: [] });
162
+
163
+ await expect(getDocs(paginationData)).rejects.toThrow(
164
+ "La obtención de documentos no está soportada para el tipo de integración: ONBOARDING"
165
+ );
166
+ });
167
+
168
+ it("should throw an error if page or size are missing", async () => {
169
+ const validationError = new ApacuanaAPIError(
170
+ "Los parámetros 'page' y 'size' son requeridos.",
171
+ 400,
172
+ "INVALID_PARAMETER"
173
+ );
174
+ helpers.validateGetDocsData.mockImplementation(() => {
175
+ throw validationError;
176
+ });
177
+
178
+ await expect(getDocs({})).rejects.toThrow(validationError);
179
+ });
180
+
181
+ it("should throw an error if status is invalid", async () => {
182
+ const validationError = new ApacuanaAPIError(
183
+ "El parámetro 'status' no es válido.",
184
+ 400,
185
+ "INVALID_PARAMETER"
186
+ );
187
+ helpers.validateGetDocsData.mockImplementationOnce(() => {
188
+ throw validationError;
189
+ });
190
+
191
+ await expect(getDocs({ ...paginationData, status: 99 })).rejects.toThrow(
192
+ validationError
193
+ );
194
+ });
195
+
196
+ it("should throw an error for non-on-premise integrations", async () => {
197
+ getConfig.mockReturnValue({
198
+ integrationType: INTEGRATION_TYPE.ONBOARDING,
199
+ });
200
+ await expect(getDocs(paginationData)).rejects.toThrow(
201
+ new ApacuanaAPIError(
202
+ "El 'customerId' no está configurado. Por favor, configure el SDK.",
203
+ 400,
204
+ "CONFIGURATION_ERROR"
205
+ )
206
+ );
207
+ });
5
208
  });
6
209
  });
@@ -57,6 +57,7 @@ describe("getCustomer", () => {
57
57
  );
58
58
 
59
59
  expect(result).toEqual({
60
+ success: true,
60
61
  token: "mock-session-id-12345",
61
62
  userData: {
62
63
  userId: "mock-user",
package/src/auth/index.js DELETED
@@ -1,24 +0,0 @@
1
- // src/auth/index.js
2
- // Si httpClient construye los headers directamente de la config,
3
- // este módulo se vuelve menos crítico o puede desaparecer por ahora.
4
- // Lo dejaremos por si hay lógica de auth más compleja después.
5
- import { getConfig } from '../config/index';
6
-
7
- export const getAuthHeaders = () => {
8
- const { secretKey, apiKey } = getConfig();
9
- if (!secretKey || !apiKey) {
10
- throw new Error('Apacuana SDK: secretKey o apiKey no configuradas.');
11
- }
12
- return {
13
- 'X-Api-Key': apiKey,
14
- Authorization: `Bearer ${secretKey}`,
15
- };
16
- };
17
-
18
- export const getVerificationId = () => {
19
- const { verificationId } = getConfig();
20
- if (!verificationId) {
21
- throw new Error('Apacuana SDK: verificationId no configurado.');
22
- }
23
- return verificationId;
24
- };