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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apacuana-sdk-core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Core SDK para interacciones con las APIs de Apacuana.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/api/certs.js CHANGED
@@ -1,30 +1,18 @@
1
- import CryptoJS from "crypto-js";
2
- import { getConfig } from "../config";
3
- import { INTEGRATION_TYPE } from "../utils/constant";
4
- import { helpers } from "../utils/helpers";
5
- import { ApacuanaAPIError } from "../errors/index";
1
+ import { getConfig } from "../config/index";
6
2
  import { httpRequest } from "../utils/httpClient";
3
+ import helpers from "../utils/helpers";
4
+ import { ApacuanaAPIError } from "../errors";
5
+ import { INTEGRATION_TYPE } from "../utils/constant";
7
6
 
8
- const generateCertOnBoarding = async () => {
7
+ const generateCertOnBoarding = async (csr = undefined) => {
9
8
  try {
10
- const config = getConfig();
11
- const { userData } = config;
12
- const keyPair = await helpers.generateKeyPair();
13
- const { csrBase64 } = await helpers.generateCSR(keyPair, userData);
14
-
15
- const body = {
16
- csr: CryptoJS.AES.encrypt(csrBase64, config.secretKey, {
17
- mode: CryptoJS.mode.ECB,
18
- padding: CryptoJS.pad.Pkcs7,
19
- }).toString(),
20
- };
9
+ const encryptedCSR = helpers.encryptedCsr(csr);
21
10
 
22
11
  const response = await httpRequest(
23
12
  "services/api/register/certificate",
24
- body,
13
+ encryptedCSR,
25
14
  "POST"
26
15
  );
27
-
28
16
  const { cert } = response;
29
17
  if (!cert) {
30
18
  throw new ApacuanaAPIError(
@@ -34,11 +22,7 @@ const generateCertOnBoarding = async () => {
34
22
  );
35
23
  }
36
24
 
37
- const exportedPrivateKey = await helpers.exportPrivateKey(
38
- keyPair.privateKey
39
- );
40
-
41
- return { cert, privateKey: exportedPrivateKey };
25
+ return { cert, success: true };
42
26
  } catch (error) {
43
27
  // Se lanza el error capturado, que ya será de tipo ApacuanaAPIError o un Error nativo.
44
28
  if (error instanceof ApacuanaAPIError) {
@@ -48,23 +32,36 @@ const generateCertOnBoarding = async () => {
48
32
  }
49
33
  };
50
34
 
51
- export const generateCert = async () => {
35
+ export const generateCert = async (csr = undefined) => {
52
36
  const { integrationType } = getConfig();
53
-
37
+ helpers.validateCsr(csr);
54
38
  if (integrationType === INTEGRATION_TYPE.ONBOARDING) {
55
- await generateCertOnBoarding();
56
- } else if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
39
+ return generateCertOnBoarding(csr);
40
+ }
41
+ if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
57
42
  // eslint-disable-next-line no-console
58
43
  console.log("-> Lógica para On-premise");
59
44
  // Aquí iría la llamada a httpRequest para el endpoint de on-premise
60
45
  // return httpRequest('/certs/generate-onpremise', data);
46
+ return Promise.resolve(); // Retornar una promesa resuelta para consistencia
61
47
  }
48
+
49
+ // Lanzar un error si el tipo de integración no es soportado
50
+ throw new ApacuanaAPIError(
51
+ `Tipo de integración no soportado: ${integrationType}`,
52
+ 400,
53
+ "UNSUPPORTED_INTEGRATION_TYPE"
54
+ );
62
55
  };
63
56
 
64
- export const getCertStatus = () => {
57
+ export const getCertStatus = (isCertificateInDevice = false) => {
65
58
  const config = getConfig();
66
- const status = helpers.getCertificateStatus(config.userData, false);
59
+ const status = helpers.getCertificateStatus(
60
+ config.userData,
61
+ isCertificateInDevice
62
+ );
67
63
  return {
68
64
  status,
65
+ success: true,
69
66
  };
70
67
  };
@@ -1,77 +1,232 @@
1
1
  // src/api/signatures.js
2
- import { httpRequest } from '../utils/httpClient';
3
- import { ApacuanaAPIError } from '../errors/index';
4
-
5
- /**
6
- * Simula la firma de un documento.
7
- * @param {object} documentData - Datos del documento a firmar.
8
- * @param {object} signatureData - Datos de la firma.
9
- * @returns {Promise<object>} Objeto con el resultado de la firma.
10
- */
11
- export const signDocument = async (documentData, signatureData) => {
12
- console.log("-> Función 'signDocument' ejecutada.");
13
- console.log('Parámetros recibidos para firmar documento:', {
14
- documentData,
15
- signatureData,
16
- });
17
-
18
- if (!documentData || !signatureData) {
19
- throw new Error(
20
- 'Datos de documento y firma son requeridos para signDocument.',
21
- );
22
- }
2
+ import { getConfig } from "../config/index";
3
+ import { httpRequest } from "../utils/httpClient";
4
+ import { ApacuanaAPIError } from "../errors";
5
+ import helpers from "../utils/helpers";
6
+ import { INTEGRATION_TYPE } from "../utils/constant";
23
7
 
8
+ /*
9
+ const signDocumentOnBoarding = async (documentData, signatureData) => {
24
10
  try {
25
11
  const response = await httpRequest(
26
- '/docs/sign',
12
+ "/docs/sign",
27
13
  { documentData, signatureData },
28
- 'POST',
29
- );
30
- console.log(
31
- 'Respuesta del servidor simulada para firmar documento:',
32
- response,
14
+ "POST"
33
15
  );
34
16
  if (!response.success) {
35
17
  throw new ApacuanaAPIError(
36
- response.message || 'Error desconocido al firmar documento.',
18
+ response.message || "Error desconocido al firmar documento."
37
19
  );
38
20
  }
39
21
  return { signedDocId: response.id, status: response.message };
40
22
  } catch (error) {
41
- throw new Error(`Fallo en la firma del documento: ${error.message}`);
23
+ if (error.name === "ApacuanaAPIError") {
24
+ throw error;
25
+ }
26
+ throw new ApacuanaAPIError(
27
+ `Fallo en la firma del documento (on-boarding): ${error.message}`
28
+ );
29
+ }
30
+ };
31
+
32
+ const signDocumentOnPremise = async (signature, cert, privateKey) => {
33
+ helpers.validateSignOnPremiseData({ signature, cert, privateKey });
34
+ try {
35
+ const digestBody = {
36
+ publickey: cert,
37
+ };
38
+
39
+ const digestResponse = await httpRequest(
40
+ `services/api/documents/getdigest/${signature.id}`,
41
+ digestBody,
42
+ "POST"
43
+ );
44
+
45
+ const digest = digestResponse.data?.digest || digestResponse.digest;
46
+ if (!digest) {
47
+ throw new ApacuanaAPIError(
48
+ "La generación de firma ha fallado: no se pudo obtener el digest del documento."
49
+ );
50
+ }
51
+
52
+ const signedDigest = await helpers.signDigest(digest, privateKey);
53
+
54
+ const signBody = {
55
+ positions: JSON.stringify(
56
+ signature.positions.map((p) => ({
57
+ x: p.x,
58
+ y: p.y,
59
+ page: p.page,
60
+ status: 1,
61
+ }))
62
+ ),
63
+ publickey: cert,
64
+ signeddigest: signedDigest,
65
+ };
66
+
67
+ const signResponse = await httpRequest(
68
+ `services/api/documents/sign/${signature.id}`,
69
+ signBody,
70
+ "PUT"
71
+ );
72
+
73
+ return signResponse;
74
+ } catch (error) {
75
+ if (error.name === "ApacuanaAPIError") {
76
+ throw error;
77
+ }
78
+ throw new ApacuanaAPIError(
79
+ `Fallo en la firma del documento (on-premise): ${error.message}`
80
+ );
81
+ }
82
+ };
83
+ */
84
+
85
+ /**
86
+ * Firma un documento PDF con un certificado digital.
87
+ * @param {object} data - Datos para la firma. Para 'on-boarding', debe contener {documentData, signatureData}. Para 'on-premise', debe contener {signature, cert, privateKey}.
88
+ * @returns {Promise<object>} Objeto con el resultado de la firma.
89
+ */
90
+ /*
91
+ export const signDocument = async (signData) => {
92
+ if (
93
+ !signData ||
94
+ typeof signData !== "object" ||
95
+ Object.keys(signData).length === 0
96
+ ) {
97
+ throw new ApacuanaAPIError(
98
+ "El parámetro 'data' es requerido y debe ser un objeto no vacío.",
99
+ 400,
100
+ "INVALID_PARAMETER"
101
+ );
102
+ }
103
+
104
+ const { integrationType } = getConfig();
105
+
106
+ if (integrationType === INTEGRATION_TYPE.ONBOARDING) {
107
+ return signDocumentOnBoarding(signData);
108
+ }
109
+
110
+ if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
111
+ return signDocumentOnPremise(signData);
112
+ }
113
+
114
+ throw new ApacuanaAPIError(
115
+ `Tipo de integración no soportado: ${integrationType}`,
116
+ 400,
117
+ "UNSUPPORTED_INTEGRATION_TYPE"
118
+ );
119
+ };
120
+ */
121
+
122
+ const addSignerOnBoarding = async (signerData) => {
123
+ helpers.validateOnBoardingSignerData(signerData);
124
+ try {
125
+ // La lógica actual de httpRequest se mueve aquí
126
+ await httpRequest("services/api/documents/signing", signerData, "POST");
127
+ return { signer: signerData.typedoc + signerData.doc, success: true };
128
+ } catch (error) {
129
+ if (error instanceof ApacuanaAPIError) {
130
+ throw error;
131
+ }
132
+ throw new Error(
133
+ `Fallo al agregar firmante en On-Boarding: ${error.message}`
134
+ );
42
135
  }
43
136
  };
44
137
 
138
+ const addSignerOnPremise = async () =>
139
+ Promise.resolve({ signerId: "on-premise-signer-id", status: "added" });
140
+
45
141
  /**
46
- * Simula la adición de un firmante a un documento.
142
+ * Agrega un firmante a un documento, manejando diferentes tipos de integración.
47
143
  * @param {object} signerData - Datos del firmante a agregar.
48
144
  * @returns {Promise<object>} Objeto con el resultado de agregar el firmante.
49
145
  */
50
146
  export const addSigner = async (signerData) => {
51
- console.log("-> Función 'addSigner' ejecutada.");
52
- console.log('Parámetros recibidos para agregar firmante:', signerData);
147
+ if (
148
+ !signerData ||
149
+ typeof signerData !== "object" ||
150
+ Object.keys(signerData).length === 0
151
+ ) {
152
+ throw new ApacuanaAPIError(
153
+ "Los datos del firmante (signerData) son requeridos y deben ser un objeto no vacío.",
154
+ 400,
155
+ "INVALID_PARAMETER"
156
+ );
157
+ }
53
158
 
54
- if (!signerData || typeof signerData !== 'object') {
55
- throw new Error('Datos de firmante son requeridos para addSigner.');
159
+ const { integrationType } = getConfig();
160
+
161
+ if (integrationType === INTEGRATION_TYPE.ONBOARDING) {
162
+ return addSignerOnBoarding(signerData);
56
163
  }
57
164
 
58
- try {
59
- const response = await httpRequest(
60
- '/docs/signers',
61
- signerData,
62
- 'POST',
63
- );
64
- console.log(
65
- 'Respuesta del servidor simulada para agregar firmante:',
66
- response,
165
+ if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
166
+ return addSignerOnPremise(signerData);
167
+ }
168
+
169
+ throw new ApacuanaAPIError(
170
+ `Tipo de integración no soportado: ${integrationType}`,
171
+ 400,
172
+ "UNSUPPORTED_INTEGRATION_TYPE"
173
+ );
174
+ };
175
+
176
+ const getDocsOnPremise = async () => {
177
+ throw new ApacuanaAPIError(
178
+ "La obtención de documentos no está soportada para el tipo de integración: ONBOARDING",
179
+ 501,
180
+ "NOT_IMPLEMENTED"
181
+ );
182
+ };
183
+
184
+ const getDocsOnBoarding = async (data) => {
185
+ const { customerId } = getConfig();
186
+ if (!customerId) {
187
+ throw new ApacuanaAPIError(
188
+ "El 'customerId' no está configurado. Por favor, configure el SDK.",
189
+ 400,
190
+ "CONFIGURATION_ERROR"
67
191
  );
68
- if (!response.success) {
69
- throw new ApacuanaAPIError(
70
- response.message || 'Error desconocido al agregar firmante.',
71
- );
72
- }
73
- return { signerId: response.id, status: response.message };
192
+ }
193
+
194
+ try {
195
+ const apiUrl = `services/api/documents/listcustomer?page=${data.page}&customerid=${customerId}&size=${data.size}&status=${data.status}`;
196
+
197
+ const response = await httpRequest(apiUrl, {}, "GET");
198
+ return response;
74
199
  } catch (error) {
75
- throw new Error(`Fallo al agregar firmante: ${error.message}`);
200
+ if (error.name === "ApacuanaAPIError") {
201
+ throw error;
202
+ }
203
+ throw new ApacuanaAPIError(
204
+ `Fallo al obtener la lista de documentos (on-premise): ${error.message}`
205
+ );
76
206
  }
77
207
  };
208
+
209
+ /**
210
+ * Obtiene una lista de documentos.
211
+ * @param {object} data - Objeto con los parámetros de paginación. Debe contener {page, size}.
212
+ * @returns {Promise<object>} Objeto con la lista de documentos.
213
+ */
214
+ export const getDocs = async (data) => {
215
+ helpers.validateGetDocsData(data);
216
+
217
+ const { integrationType } = getConfig();
218
+
219
+ if (integrationType === INTEGRATION_TYPE.ONBOARDING) {
220
+ return getDocsOnBoarding(data);
221
+ }
222
+
223
+ if (integrationType === INTEGRATION_TYPE.ONPREMISE) {
224
+ return getDocsOnPremise();
225
+ }
226
+
227
+ throw new ApacuanaAPIError(
228
+ `La obtención de documentos no está soportada para un tipo de integración desconocido: ${integrationType}`,
229
+ 501,
230
+ "NOT_IMPLEMENTED"
231
+ );
232
+ };
package/src/api/users.js CHANGED
@@ -55,6 +55,7 @@ const getCustomer = async () => {
55
55
  return {
56
56
  token: response.sessionid,
57
57
  userData: response.entry,
58
+ success: true,
58
59
  }; // Retorna el objeto de usuario directamente
59
60
  } catch (error) {
60
61
  // 4. Manejo de Errores
@@ -9,6 +9,7 @@ export class ApacuanaAPIError extends Error {
9
9
  this.name = "ApacuanaAPIError";
10
10
  this.statusCode = statusCode;
11
11
  this.errorCode = errorCode;
12
+ this.success = false; // Añadir el atributo success con valor false
12
13
 
13
14
  // Mantener el stack trace correcto
14
15
  if (Error.captureStackTrace) {
package/src/index.js CHANGED
@@ -1,9 +1,9 @@
1
- // src/index.js
2
1
  import { setConfig, getConfig } from "./config/index";
3
2
  import { initHttpClient, setAuthToken } from "./utils/httpClient";
4
3
  import getCustomer from "./api/users";
5
4
  import requestRevocation from "./api/revocations";
6
5
  import { getCertStatus } from "./api/certs";
6
+ import { addSigner, getDocs } from "./api/signatures";
7
7
 
8
8
  const apacuana = {
9
9
  /**
@@ -62,6 +62,9 @@ const apacuana = {
62
62
  getConfig,
63
63
  requestRevocation,
64
64
  getCertStatus,
65
+ getCustomer,
66
+ addSigner,
67
+ getDocs,
65
68
  };
66
69
 
67
70
  export default apacuana;