@gnpdev/rpa-tools 1.0.19 → 1.1.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.
package/README.md CHANGED
@@ -77,8 +77,8 @@ import { logger } from './lib/rpa.js';
77
77
  logger.info('Procesando orden');
78
78
  ```
79
79
 
80
- ### 3. Gestión de Credenciales
81
- Recupera de forma segura el `usuario`, `password` e `idUsuario` de una aplicación específica vinculada al bot.
80
+ ### 3. Gestión de Credenciales y Estado de Aplicaciones
81
+ Recupera de forma segura el `usuario`, `password` e `idUsuario` de una aplicación específica vinculada al bot. También permite actualizar el estado y observaciones (útil para fallos de login).
82
82
 
83
83
  ```javascript
84
84
  import { rpa, logger } from './lib/rpa.js';
@@ -90,49 +90,48 @@ if (credentials) {
90
90
  const { usuario, password, idUsuario } = credentials;
91
91
  // usar en el login de la web
92
92
  }
93
+
94
+ // En caso de fallo de login o error en la aplicación
95
+ await rpa.updateAppStatus('Portal CRM', false, 'Credenciales inválidas o bloqueo de cuenta');
93
96
  ```
94
97
 
95
98
  ### 4. Verificar Estado del Bot (Kill Switch)
96
- Permite consultar si el bot debe seguir en ejecución según la base de datos (columna `estado` en `bots.tb_bots`). Útil para implementar una parada de emergencia desde el panel de control.
97
-
99
+ ...
98
100
  ```javascript
99
101
  import { rpa, logger } from './lib/rpa.js';
100
102
 
101
103
  const active = await rpa.isActive();
102
-
103
- if (!active) {
104
- logger.warn('El bot ha sido desactivado desde la base de datos. Finalizando...');
105
- await rpa.destroy();
106
- process.exit(0);
107
- }
104
+ ...
108
105
  ```
109
106
 
110
- ### 5. Capturas de Pantalla bajo demanda (Playwright / Puppeteer)
111
- Activa el watcher pasando la instancia de `page`. El bot detectará cambios en la tabla de la DB para tomar screenshots automáticamente. Compatible con ambos motores.
107
+ ### 5. Capturas de Pantalla
108
+ Existen tres formas de realizar capturas de pantalla:
109
+
110
+ #### A. Captura Manual Estructurada
111
+ Captura la página actual y la guarda con una estructura de carpetas: `capturas/id_bot/fecha/nombre.webp`.
112
112
 
113
- #### Ejemplo con Playwright
114
113
  ```javascript
115
- import { chromium } from 'playwright';
116
114
  import { rpa } from './lib/rpa.js';
117
115
 
118
- const browser = await chromium.launch();
119
- const page = await browser.newPage();
120
-
121
- rpa.watchDebugFlag(page);
116
+ // Captura la página actual con el nombre 'dashboard_principal'
117
+ const key = await rpa.capturePage(page, 'dashboard_principal');
122
118
  ```
123
119
 
124
- #### Ejemplo con Puppeteer
120
+ #### B. Monitoreo en Tiempo Real (Debug)
121
+ Activa el watcher pasando la instancia de `page`. El bot detectará cambios en la tabla de la DB para tomar screenshots automáticamente.
122
+
125
123
  ```javascript
126
- import puppeteer from 'puppeteer';
124
+ import { chromium } from 'playwright';
127
125
  import { rpa } from './lib/rpa.js';
128
126
 
129
- const browser = await puppeteer.launch();
127
+ const browser = await chromium.launch();
130
128
  const page = await browser.newPage();
131
129
 
132
130
  rpa.watchDebugFlag(page);
133
131
  ```
134
132
 
135
- ### 6. Captura Automática de Errores (Screenshot + Trace)
133
+ #### C. Captura Automática de Errores (Screenshot + Trace)
134
+ ...
136
135
  Captura el estado completo del bot cuando ocurre una excepción. **`captureError` detecta automáticamente el paso actual** definido con `step()`.
137
136
 
138
137
  > **Nota:** El soporte de `tracing` (archivos .zip de depuración) es exclusivo de **Playwright**. En **Puppeteer** se capturará el error y el screenshot, pero el `traceKey` será nulo.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gnpdev/rpa-tools",
3
- "version": "1.0.19",
3
+ "version": "1.1.0",
4
4
  "description": "Libreria para logs y screenshot de bots",
5
5
  "author": "Sergio Antonio Trujillo del Valle",
6
6
  "main": "src/index.js",
@@ -20,7 +20,8 @@
20
20
  "minio": "^8.0.7",
21
21
  "pino": "^10.3.1",
22
22
  "pino-pretty": "^13.1.3",
23
- "sharp": "^0.34.5"
23
+ "sharp": "^0.34.5",
24
+ "pg": "^8.11.0"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@commitlint/cli": "^20.5.0",
package/src/capture.js ADDED
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+ const sharp = require('sharp');
3
+
4
+ /**
5
+ * Gestor de capturas de pantalla de la página actual.
6
+ */
7
+ class PageCapturer {
8
+ /**
9
+ * @param {object} params
10
+ * @param {string} params.botId - UUID del bot
11
+ * @param {import('minio').Client} params.minioClient - Cliente MinIO
12
+ * @param {string} params.bucket - Bucket de MinIO
13
+ * @param {import('pino').Logger} [params.logger] - Instancia de Logger
14
+ */
15
+ constructor({ botId, minioClient, bucket, logger }) {
16
+ this.botId = botId;
17
+ this.minioClient = minioClient;
18
+ this.bucket = bucket;
19
+ this.logger = logger;
20
+ }
21
+
22
+ /**
23
+ * Captura la página actual y la sube a MinIO con una ruta estructurada.
24
+ * Estructura: capturas/{botId}/{YYYY-MM-DD}/{nombre}.webp
25
+ *
26
+ * @param {any} page - Instancia de Page (Playwright o Puppeteer)
27
+ * @param {string} nombre - Nombre del elemento/captura
28
+ * @returns {Promise<string|null>} - Key de la captura en MinIO
29
+ */
30
+ async capture(page, nombre) {
31
+ try {
32
+ const now = new Date();
33
+ const date = now.toISOString().slice(0, 10);
34
+ const key = `capturas/${this.botId}/${date}/${nombre}.webp`;
35
+
36
+ const buffer = await page.screenshot({
37
+ type: 'jpeg',
38
+ quality: 80,
39
+ fullPage: true,
40
+ });
41
+
42
+ const finalBuffer = await sharp(buffer)
43
+ .webp({ quality: 70 })
44
+ .toBuffer();
45
+
46
+ await this.minioClient.putObject(this.bucket, key, finalBuffer, finalBuffer.length, {
47
+ 'Content-Type': 'image/webp',
48
+ });
49
+
50
+ if (this.logger) {
51
+ this.logger.info({ key, nombre }, 'Captura de pantalla guardada exitosamente');
52
+ }
53
+
54
+ return key;
55
+ } catch (err) {
56
+ if (this.logger) {
57
+ this.logger.error({ err, nombre }, 'Error al capturar pantalla');
58
+ }
59
+ return null;
60
+ }
61
+ }
62
+ }
63
+
64
+ module.exports = { PageCapturer };
@@ -1,35 +1,56 @@
1
- 'use strict';
2
-
3
- /**
4
- * Gestor de credenciales de aplicaciones para bots.
5
- */
6
- class CredentialManager {
7
- /**
8
- * @param {object} params
9
- * @param {import('pg').Pool} params.pool - Pool de pg
10
- * @param {string} params.botId - UUID del bot
11
- */
12
- constructor({ pool, botId }) {
13
- this.pool = pool;
14
- this.botId = botId;
15
- }
16
-
17
- /**
18
- * Obtiene las credenciales de una aplicación.
19
- * @param {string} nombre - Nombre de la aplicación
20
- * @returns {Promise<{usuario: string, password: string, idUsuario: string}|null>}
21
- */
22
- async getAppCredentials(nombre) {
23
- const { rows } = await this.pool.query(
24
- `SELECT usuario, password, "idUsuario"
25
- FROM bots.tb_aplicaciones_bots
26
- WHERE nombre = $1 AND bot_id = $2
27
- LIMIT 1`,
28
- [nombre, this.botId]
29
- );
30
-
31
- return rows.length > 0 ? rows[0] : null;
32
- }
33
- }
34
-
35
- module.exports = { CredentialManager };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Gestor de credenciales de aplicaciones para bots.
5
+ */
6
+ class CredentialManager {
7
+ /**
8
+ * @param {object} params
9
+ * @param {import('pg').Pool} params.pool - Pool de pg
10
+ * @param {string} params.botId - UUID del bot
11
+ */
12
+ constructor({ pool, botId }) {
13
+ this.pool = pool;
14
+ this.botId = botId;
15
+ }
16
+
17
+ /**
18
+ * Obtiene las credenciales de una aplicación.
19
+ * @param {string} nombre - Nombre de la aplicación
20
+ * @returns {Promise<{usuario: string, password: string, idUsuario: string}|null>}
21
+ */
22
+ async getAppCredentials(nombre) {
23
+ const { rows } = await this.pool.query(
24
+ `SELECT usuario, password, "idUsuario"
25
+ FROM bots.tb_aplicaciones_bots
26
+ WHERE nombre = $1 AND bot_id = $2
27
+ LIMIT 1`,
28
+ [nombre, this.botId]
29
+ );
30
+
31
+ return rows.length > 0 ? rows[0] : null;
32
+ }
33
+
34
+ /**
35
+ * Actualiza el estado y las observaciones de una aplicación.
36
+ * @param {string} nombre - Nombre de la aplicación
37
+ * @param {boolean} status - Estado (true/false)
38
+ * @param {string} observations - Observaciones/Errores
39
+ * @returns {Promise<boolean>}
40
+ */
41
+ async updateAppStatus(nombre, status, observations) {
42
+ try {
43
+ await this.pool.query(
44
+ `UPDATE bots.tb_aplicaciones_bots
45
+ SET status = $1, observations = $2
46
+ WHERE nombre = $3 AND bot_id = $4`,
47
+ [status, observations, nombre, this.botId]
48
+ );
49
+ return true;
50
+ } catch (err) {
51
+ return false;
52
+ }
53
+ }
54
+ }
55
+
56
+ module.exports = { CredentialManager };
package/src/index.d.ts CHANGED
@@ -74,12 +74,27 @@ export interface RpaTools {
74
74
  */
75
75
  getCredentials: (nombre: string) => Promise<{ usuario: string; password: string; idUsuario: string } | null>;
76
76
 
77
+ /**
78
+ * Actualiza el estado y las observaciones de una aplicación.
79
+ * @param nombre - Nombre de la aplicación (ej. 'Portal CRM')
80
+ * @param status - Estado (true/false)
81
+ * @param observations - Observaciones/Errores
82
+ */
83
+ updateAppStatus: (nombre: string, status: boolean, observations: string) => Promise<boolean>;
84
+
77
85
  /**
78
86
  * Consulta si el bot está activo en la base de datos (columna 'estado').
79
87
  * @returns {Promise<boolean>}
80
88
  */
81
89
  isActive: () => Promise<boolean>;
82
90
 
91
+ /**
92
+ * Captura el estado de la página actual y lo sube a MinIO.
93
+ * @param page - Instancia de Page (Playwright o Puppeteer)
94
+ * @param nombre - Nombre del elemento/captura
95
+ */
96
+ capturePage: (page: any, nombre: string) => Promise<string | null>;
97
+
83
98
  /**
84
99
  * Captura screenshot, trace y registra error en base de datos.
85
100
  */
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ const { createMinioClient, ensureBucket } = require('./storage');
4
4
  const { ScreenshotWatcher } = require('./watcher');
5
5
  const { CredentialManager } = require('./credentials');
6
6
  const { captureError } = require('./errorCapture');
7
+ const { PageCapturer } = require('./capture');
7
8
 
8
9
  /**
9
10
  * Factory principal de la librería.
@@ -14,7 +15,7 @@ const { captureError } = require('./errorCapture');
14
15
  * @param {object} opts.minio - config de MinIO
15
16
  * @param {object} [opts.log] - opciones de Pino
16
17
  *
17
- * @returns {{ logger, state, step, watchDebugFlag, getCredentials, isActive, captureError, destroy }}
18
+ * @returns {{ logger, state, step, watchDebugFlag, getCredentials, updateAppStatus, isActive, capturePage, captureError, destroy }}
18
19
  */
19
20
  async function createRpaTools(opts = {}) {
20
21
  const {
@@ -45,6 +46,7 @@ async function createRpaTools(opts = {}) {
45
46
 
46
47
  const watcher = new ScreenshotWatcher({ botId, pool: db, minioClient, bucket, logger });
47
48
  const credentials = new CredentialManager({ botId, pool: db });
49
+ const capturer = new PageCapturer({ botId, minioClient, bucket, logger });
48
50
 
49
51
  const state = { currentStep: 'Inicio' };
50
52
 
@@ -62,6 +64,7 @@ async function createRpaTools(opts = {}) {
62
64
  */
63
65
  watchDebugFlag: (page, pollMs) => watcher.watch(page, pollMs),
64
66
  getCredentials: (nombre) => credentials.getAppCredentials(nombre),
67
+ updateAppStatus: (nombre, status, observations) => credentials.updateAppStatus(nombre, status, observations),
65
68
  /**
66
69
  * Consulta si el bot está activo en la base de datos (columna 'estado').
67
70
  * @returns {Promise<boolean>}
@@ -78,6 +81,12 @@ async function createRpaTools(opts = {}) {
78
81
  return false;
79
82
  }
80
83
  },
84
+ /**
85
+ * Captura el estado de la página actual y lo sube a MinIO.
86
+ * @param {any} page - Instancia de Page
87
+ * @param {string} nombre - Nombre del elemento/captura
88
+ */
89
+ capturePage: (page, nombre) => capturer.capture(page, nombre),
81
90
  /**
82
91
  * Captura screenshot y registra error en base de datos.
83
92
  * Soporta Playwright (con tracing opcional) y Puppeteer.
package/src/logger.js CHANGED
@@ -1,26 +1,26 @@
1
- 'use strict';
2
- const pino = require('pino');
3
-
4
- /**
5
- * Crea una instancia de Pino ya configurada con el botId como campo base.
6
- * @param {string} botId
7
- * @param {object} opts
8
- * @param {'trace'|'debug'|'info'|'warn'|'error'} [opts.level='info']
9
- * @param {boolean} [opts.pretty=false] - activar pino-pretty (solo en dev)
10
- * @param {object} [opts.pinoOptions] - opciones adicionales de Pino
11
- */
12
- function createLogger(botId, opts = {}) {
13
- const { level = 'info', pretty = false, pinoOptions = {} } = opts;
14
-
15
- return pino({
16
- level,
17
- base: { botId },
18
- timestamp: pino.stdTimeFunctions.isoTime,
19
- transport: pretty
20
- ? { target: 'pino-pretty', options: { colorize: true } }
21
- : undefined,
22
- ...pinoOptions,
23
- });
24
- }
25
-
1
+ 'use strict';
2
+ const pino = require('pino');
3
+
4
+ /**
5
+ * Crea una instancia de Pino ya configurada con el botId como campo base.
6
+ * @param {string} botId
7
+ * @param {object} opts
8
+ * @param {'trace'|'debug'|'info'|'warn'|'error'} [opts.level='info']
9
+ * @param {boolean} [opts.pretty=false] - activar pino-pretty (solo en dev)
10
+ * @param {object} [opts.pinoOptions] - opciones adicionales de Pino
11
+ */
12
+ function createLogger(botId, opts = {}) {
13
+ const { level = 'info', pretty = false, pinoOptions = {} } = opts;
14
+
15
+ return pino({
16
+ level,
17
+ base: { botId },
18
+ timestamp: pino.stdTimeFunctions.isoTime,
19
+ transport: pretty
20
+ ? { target: 'pino-pretty', options: { colorize: true } }
21
+ : undefined,
22
+ ...pinoOptions,
23
+ });
24
+ }
25
+
26
26
  module.exports = { createLogger };