@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 +21 -22
- package/package.json +3 -2
- package/src/capture.js +64 -0
- package/src/credentials.js +56 -35
- package/src/index.d.ts +15 -0
- package/src/index.js +10 -1
- package/src/logger.js +25 -25
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
|
-
|
|
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
|
|
111
|
-
|
|
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
|
-
|
|
119
|
-
const
|
|
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
|
-
####
|
|
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
|
|
124
|
+
import { chromium } from 'playwright';
|
|
127
125
|
import { rpa } from './lib/rpa.js';
|
|
128
126
|
|
|
129
|
-
const browser = await
|
|
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
|
-
|
|
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
|
|
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 };
|
package/src/credentials.js
CHANGED
|
@@ -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
|
-
|
|
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 };
|