@gnpdev/rpa-tools 1.0.15 → 1.0.17
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/package.json +1 -1
- package/src/errorCapture.js +154 -148
- package/src/index.d.ts +4 -4
- package/src/index.js +1 -1
- package/src/storage.js +100 -82
- package/src/watcher.js +4 -4
package/package.json
CHANGED
package/src/errorCapture.js
CHANGED
|
@@ -1,149 +1,155 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const fs = require('fs/promises');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Sube un buffer o archivo local a MinIO y retorna el key generado.
|
|
7
|
-
* @param {import('minio').Client} client
|
|
8
|
-
* @param {string} bucket
|
|
9
|
-
* @param {string} key
|
|
10
|
-
* @param {Buffer|string} source - Buffer o ruta de archivo local
|
|
11
|
-
* @param {string} contentType
|
|
12
|
-
*/
|
|
13
|
-
async function uploadToMinio(client, bucket, key, source, contentType) {
|
|
14
|
-
const buffer = typeof source === 'string'
|
|
15
|
-
? await fs.readFile(source)
|
|
16
|
-
: source;
|
|
17
|
-
|
|
18
|
-
await client.putObject(bucket, key, buffer, buffer.length, {
|
|
19
|
-
'Content-Type': contentType,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
return key;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Genera el prefijo base para los archivos de error en MinIO.
|
|
27
|
-
* Estructura: errors/{botId}/{YYYY-MM-DD}/{ISO-timestamp}
|
|
28
|
-
*/
|
|
29
|
-
function errorPrefix(botId) {
|
|
30
|
-
const now = new Date();
|
|
31
|
-
const date = now.toISOString().slice(0, 10);
|
|
32
|
-
const ts = now.toISOString().replace(/[:.]/g, '-');
|
|
33
|
-
return `errors/${botId}/${date}/${ts}`;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Captura el estado completo cuando ocurre un error:
|
|
38
|
-
* - Screenshot WebP de la página actual
|
|
39
|
-
* - Trace de Playwright (.zip con video, red, consola, DOM snapshots)
|
|
40
|
-
* - Registro en bots.tb_error_bots
|
|
41
|
-
*
|
|
42
|
-
* @param {object} p
|
|
43
|
-
* @param {import('playwright').Page} p.page
|
|
44
|
-
* @param {import('playwright').BrowserContext} p.context
|
|
45
|
-
* @param {Error} p.err
|
|
46
|
-
* @param {string} p.botId - UUID del bot
|
|
47
|
-
* @param {import('pg').Pool} p.pool
|
|
48
|
-
* @param {import('minio').Client} p.minioClient
|
|
49
|
-
* @param {string} p.bucket
|
|
50
|
-
* @param {import('pino').Logger} p.logger
|
|
51
|
-
* @param {string} [p.step] - paso donde falló
|
|
52
|
-
*
|
|
53
|
-
* @returns {Promise<{ screenshotKey: string|null, traceKey: string|null, errorId: number|null }>}
|
|
54
|
-
*/
|
|
55
|
-
async function captureError({ page, context, err, botId, pool, minioClient, bucket, logger, step }) {
|
|
56
|
-
const prefix = errorPrefix(botId);
|
|
57
|
-
const stepInfo = step ? { step } : {};
|
|
58
|
-
const result = { screenshotKey: null, traceKey: null, errorId: null };
|
|
59
|
-
|
|
60
|
-
// ── 1. Screenshot ────────────────────────────────────────────────────────
|
|
61
|
-
try {
|
|
62
|
-
const buffer = await page.screenshot({
|
|
63
|
-
type: 'jpeg',
|
|
64
|
-
quality: 90,
|
|
65
|
-
fullPage: true,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
let finalBuffer = buffer;
|
|
69
|
-
let ext = 'jpg';
|
|
70
|
-
let contentType = 'image/jpeg';
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
const sharp = require('sharp');
|
|
74
|
-
finalBuffer = await sharp(buffer).webp({ quality: 80 }).toBuffer();
|
|
75
|
-
ext = 'webp';
|
|
76
|
-
contentType = 'image/webp';
|
|
77
|
-
} catch {
|
|
78
|
-
// sharp no disponible, se sube en jpeg
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
result.screenshotKey = await uploadToMinio(
|
|
82
|
-
minioClient, bucket,
|
|
83
|
-
`${prefix}-error.${ext}`,
|
|
84
|
-
finalBuffer,
|
|
85
|
-
contentType
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
logger.info({ ...stepInfo, screenshotKey: result.screenshotKey }, 'Screenshot de error subido');
|
|
89
|
-
} catch (screenshotErr) {
|
|
90
|
-
logger.error({ err: screenshotErr }, 'No se pudo capturar screenshot de error');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// ── 2. Trace ─────────────────────────────────────────────────────────────
|
|
94
|
-
const tracePath = path.join(require('os').tmpdir(), `trace-${botId}-${Date.now()}.zip`);
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
err,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs/promises');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sube un buffer o archivo local a MinIO y retorna el key generado.
|
|
7
|
+
* @param {import('minio').Client} client
|
|
8
|
+
* @param {string} bucket
|
|
9
|
+
* @param {string} key
|
|
10
|
+
* @param {Buffer|string} source - Buffer o ruta de archivo local
|
|
11
|
+
* @param {string} contentType
|
|
12
|
+
*/
|
|
13
|
+
async function uploadToMinio(client, bucket, key, source, contentType) {
|
|
14
|
+
const buffer = typeof source === 'string'
|
|
15
|
+
? await fs.readFile(source)
|
|
16
|
+
: source;
|
|
17
|
+
|
|
18
|
+
await client.putObject(bucket, key, buffer, buffer.length, {
|
|
19
|
+
'Content-Type': contentType,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return key;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Genera el prefijo base para los archivos de error en MinIO.
|
|
27
|
+
* Estructura: errors/{botId}/{YYYY-MM-DD}/{ISO-timestamp}
|
|
28
|
+
*/
|
|
29
|
+
function errorPrefix(botId) {
|
|
30
|
+
const now = new Date();
|
|
31
|
+
const date = now.toISOString().slice(0, 10);
|
|
32
|
+
const ts = now.toISOString().replace(/[:.]/g, '-');
|
|
33
|
+
return `errors/${botId}/${date}/${ts}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Captura el estado completo cuando ocurre un error:
|
|
38
|
+
* - Screenshot WebP de la página actual
|
|
39
|
+
* - Trace de Playwright (.zip con video, red, consola, DOM snapshots)
|
|
40
|
+
* - Registro en bots.tb_error_bots
|
|
41
|
+
*
|
|
42
|
+
* @param {object} p
|
|
43
|
+
* @param {import('playwright').Page} p.page
|
|
44
|
+
* @param {import('playwright').BrowserContext} p.context
|
|
45
|
+
* @param {Error} p.err
|
|
46
|
+
* @param {string} p.botId - UUID del bot
|
|
47
|
+
* @param {import('pg').Pool} p.pool
|
|
48
|
+
* @param {import('minio').Client} p.minioClient
|
|
49
|
+
* @param {string} p.bucket
|
|
50
|
+
* @param {import('pino').Logger} p.logger
|
|
51
|
+
* @param {string} [p.step] - paso donde falló
|
|
52
|
+
*
|
|
53
|
+
* @returns {Promise<{ screenshotKey: string|null, traceKey: string|null, errorId: number|null }>}
|
|
54
|
+
*/
|
|
55
|
+
async function captureError({ page, context, err, botId, pool, minioClient, bucket, logger, step }) {
|
|
56
|
+
const prefix = errorPrefix(botId);
|
|
57
|
+
const stepInfo = step ? { step } : {};
|
|
58
|
+
const result = { screenshotKey: null, traceKey: null, errorId: null };
|
|
59
|
+
|
|
60
|
+
// ── 1. Screenshot ────────────────────────────────────────────────────────
|
|
61
|
+
try {
|
|
62
|
+
const buffer = await page.screenshot({
|
|
63
|
+
type: 'jpeg',
|
|
64
|
+
quality: 90,
|
|
65
|
+
fullPage: true,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
let finalBuffer = buffer;
|
|
69
|
+
let ext = 'jpg';
|
|
70
|
+
let contentType = 'image/jpeg';
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const sharp = require('sharp');
|
|
74
|
+
finalBuffer = await sharp(buffer).webp({ quality: 80 }).toBuffer();
|
|
75
|
+
ext = 'webp';
|
|
76
|
+
contentType = 'image/webp';
|
|
77
|
+
} catch {
|
|
78
|
+
// sharp no disponible, se sube en jpeg
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
result.screenshotKey = await uploadToMinio(
|
|
82
|
+
minioClient, bucket,
|
|
83
|
+
`${prefix}-error.${ext}`,
|
|
84
|
+
finalBuffer,
|
|
85
|
+
contentType
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
logger.info({ ...stepInfo, screenshotKey: result.screenshotKey }, 'Screenshot de error subido');
|
|
89
|
+
} catch (screenshotErr) {
|
|
90
|
+
logger.error({ err: screenshotErr }, 'No se pudo capturar screenshot de error');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── 2. Trace ─────────────────────────────────────────────────────────────
|
|
94
|
+
const tracePath = path.join(require('os').tmpdir(), `trace-${botId}-${Date.now()}.zip`);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
if (context?.tracing) {
|
|
98
|
+
await context.tracing.stop({ path: tracePath });
|
|
99
|
+
|
|
100
|
+
result.traceKey = await uploadToMinio(
|
|
101
|
+
minioClient, bucket,
|
|
102
|
+
`${prefix}-trace.zip`,
|
|
103
|
+
tracePath,
|
|
104
|
+
'application/zip'
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
logger.info({ ...stepInfo, traceKey: result.traceKey }, 'Trace de error subido');
|
|
108
|
+
} else {
|
|
109
|
+
logger.debug('Tracing no disponible (Puppeteer o no activado)');
|
|
110
|
+
}
|
|
111
|
+
} catch (traceErr) {
|
|
112
|
+
logger.error({ err: traceErr }, 'No se pudo capturar trace de error');
|
|
113
|
+
} finally {
|
|
114
|
+
if (context?.tracing) {
|
|
115
|
+
await fs.unlink(tracePath).catch(() => {});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── 3. Registro en bots.tb_error_bots ───────────────────────────────────
|
|
120
|
+
try {
|
|
121
|
+
const { rows } = await pool.query(
|
|
122
|
+
`INSERT INTO bots.tb_error_bots
|
|
123
|
+
(bot_id, step, error_message, url, screenshot_key, trace_key)
|
|
124
|
+
VALUES ($1::uuid, $2, $3, $4, $5, $6)
|
|
125
|
+
RETURNING id`,
|
|
126
|
+
[
|
|
127
|
+
botId,
|
|
128
|
+
step ?? null,
|
|
129
|
+
err.message,
|
|
130
|
+
page.url() ?? null,
|
|
131
|
+
result.screenshotKey ?? null,
|
|
132
|
+
result.traceKey ?? null,
|
|
133
|
+
]
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
result.errorId = rows[0].id;
|
|
137
|
+
logger.info({ ...stepInfo, errorId: result.errorId }, 'Error registrado en BD');
|
|
138
|
+
} catch (dbErr) {
|
|
139
|
+
logger.error({ err: dbErr }, 'No se pudo registrar el error en BD');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ── 4. Log estructurado final ────────────────────────────────────────────
|
|
143
|
+
logger.error({
|
|
144
|
+
...stepInfo,
|
|
145
|
+
err,
|
|
146
|
+
url: page.url(),
|
|
147
|
+
screenshotKey: result.screenshotKey,
|
|
148
|
+
traceKey: result.traceKey,
|
|
149
|
+
errorId: result.errorId,
|
|
150
|
+
}, 'Error capturado en playground');
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
149
155
|
module.exports = { captureError };
|
package/src/index.d.ts
CHANGED
|
@@ -63,10 +63,10 @@ export interface RpaTools {
|
|
|
63
63
|
/**
|
|
64
64
|
* Inicia el polling que activa/desactiva screenshots
|
|
65
65
|
* según bot_debug_config en la BD.
|
|
66
|
-
* @param page - Objeto Page de Playwright
|
|
66
|
+
* @param page - Objeto Page de Playwright o Puppeteer
|
|
67
67
|
* @param pollMs - Intervalo de polling en ms. Default: 3000
|
|
68
68
|
*/
|
|
69
|
-
watchDebugFlag: (page:
|
|
69
|
+
watchDebugFlag: (page: any, pollMs?: number) => void;
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Recupera credenciales de una aplicación desde la base de datos.
|
|
@@ -78,8 +78,8 @@ export interface RpaTools {
|
|
|
78
78
|
* Captura screenshot, trace y registra error en base de datos.
|
|
79
79
|
*/
|
|
80
80
|
captureError: (params: {
|
|
81
|
-
page:
|
|
82
|
-
context
|
|
81
|
+
page: any;
|
|
82
|
+
context?: any;
|
|
83
83
|
err: Error;
|
|
84
84
|
step?: string;
|
|
85
85
|
}) => Promise<{ errorId: number | null; screenshotKey: string | null; traceKey: string | null }>;
|
package/src/index.js
CHANGED
|
@@ -53,7 +53,7 @@ async function createRpaTools(opts = {}) {
|
|
|
53
53
|
state,
|
|
54
54
|
step: (name) => {
|
|
55
55
|
state.currentStep = name;
|
|
56
|
-
logger.info(
|
|
56
|
+
logger.info(name + ' - Nuevo paso');
|
|
57
57
|
},
|
|
58
58
|
watchDebugFlag: (page, pollMs) => watcher.watch(page, pollMs),
|
|
59
59
|
getCredentials: (nombre) => credentials.getAppCredentials(nombre),
|
package/src/storage.js
CHANGED
|
@@ -1,83 +1,101 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const Minio = require('minio');
|
|
3
|
-
const sharp = require('sharp');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Crea y retorna el cliente de MinIO.
|
|
7
|
-
* @param {object} cfg
|
|
8
|
-
* @param {string} cfg.endPoint
|
|
9
|
-
* @param {number} [cfg.port=9000]
|
|
10
|
-
* @param {boolean} [cfg.useSSL=false]
|
|
11
|
-
* @param {string} cfg.accessKey
|
|
12
|
-
* @param {string} cfg.secretKey
|
|
13
|
-
*/
|
|
14
|
-
function createMinioClient(cfg) {
|
|
15
|
-
return new Minio.Client({
|
|
16
|
-
endPoint: cfg.endPoint,
|
|
17
|
-
port: cfg.port ?? 9000,
|
|
18
|
-
useSSL: cfg.useSSL ?? false,
|
|
19
|
-
accessKey: cfg.accessKey,
|
|
20
|
-
secretKey: cfg.secretKey,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Garantiza que el bucket exista; lo crea si no.
|
|
26
|
-
* @param {import('minio').Client} client
|
|
27
|
-
* @param {string} bucket
|
|
28
|
-
* @param {string} [region='us-east-1']
|
|
29
|
-
*/
|
|
30
|
-
async function ensureBucket(client, bucket, region = 'us-east-1') {
|
|
31
|
-
const exists = await client.bucketExists(bucket);
|
|
32
|
-
if (!exists) await client.makeBucket(bucket, region);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Convierte un buffer de imagen a WebP usando sharp.
|
|
37
|
-
* @param {Buffer} buffer - buffer fuente (jpeg/png)
|
|
38
|
-
* @param {number} [quality=70]
|
|
39
|
-
* @returns {Promise<Buffer>}
|
|
40
|
-
*/
|
|
41
|
-
async function toWebp(buffer, quality = 70) {
|
|
42
|
-
return sharp(buffer)
|
|
43
|
-
.webp({ quality })
|
|
44
|
-
.toBuffer();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Sube un screenshot a MinIO.
|
|
49
|
-
* Si format='webp' convierte el buffer antes de subir.
|
|
50
|
-
* Ruta generada: {botId}/{YYYY-MM-DD}/{ISO-timestamp}.{ext}
|
|
51
|
-
*
|
|
52
|
-
* @param {import('minio').Client} client
|
|
53
|
-
* @param {string} bucket
|
|
54
|
-
* @param {string} botId
|
|
55
|
-
* @param {Buffer} buffer - buffer raw de Playwright (jpeg)
|
|
56
|
-
* @param {object} [opts]
|
|
57
|
-
* @param {'webp'|'jpeg'} [opts.format='webp']
|
|
58
|
-
* @param {number} [opts.quality=70] - calidad 1-100
|
|
59
|
-
* @
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
const Minio = require('minio');
|
|
3
|
+
const sharp = require('sharp');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Crea y retorna el cliente de MinIO.
|
|
7
|
+
* @param {object} cfg
|
|
8
|
+
* @param {string} cfg.endPoint
|
|
9
|
+
* @param {number} [cfg.port=9000]
|
|
10
|
+
* @param {boolean} [cfg.useSSL=false]
|
|
11
|
+
* @param {string} cfg.accessKey
|
|
12
|
+
* @param {string} cfg.secretKey
|
|
13
|
+
*/
|
|
14
|
+
function createMinioClient(cfg) {
|
|
15
|
+
return new Minio.Client({
|
|
16
|
+
endPoint: cfg.endPoint,
|
|
17
|
+
port: cfg.port ?? 9000,
|
|
18
|
+
useSSL: cfg.useSSL ?? false,
|
|
19
|
+
accessKey: cfg.accessKey,
|
|
20
|
+
secretKey: cfg.secretKey,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Garantiza que el bucket exista; lo crea si no.
|
|
26
|
+
* @param {import('minio').Client} client
|
|
27
|
+
* @param {string} bucket
|
|
28
|
+
* @param {string} [region='us-east-1']
|
|
29
|
+
*/
|
|
30
|
+
async function ensureBucket(client, bucket, region = 'us-east-1') {
|
|
31
|
+
const exists = await client.bucketExists(bucket);
|
|
32
|
+
if (!exists) await client.makeBucket(bucket, region);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Convierte un buffer de imagen a WebP usando sharp.
|
|
37
|
+
* @param {Buffer} buffer - buffer fuente (jpeg/png)
|
|
38
|
+
* @param {number} [quality=70]
|
|
39
|
+
* @returns {Promise<Buffer>}
|
|
40
|
+
*/
|
|
41
|
+
async function toWebp(buffer, quality = 70) {
|
|
42
|
+
return sharp(buffer)
|
|
43
|
+
.webp({ quality })
|
|
44
|
+
.toBuffer();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Sube un screenshot a MinIO.
|
|
49
|
+
* Si format='webp' convierte el buffer antes de subir.
|
|
50
|
+
* Ruta generada: {botId}/{YYYY-MM-DD}/{ISO-timestamp}.{ext}
|
|
51
|
+
*
|
|
52
|
+
* @param {import('minio').Client} client
|
|
53
|
+
* @param {string} bucket
|
|
54
|
+
* @param {string} botId
|
|
55
|
+
* @param {Buffer} buffer - buffer raw de Playwright (jpeg)
|
|
56
|
+
* @param {object} [opts]
|
|
57
|
+
* @param {'webp'|'jpeg'} [opts.format='webp']
|
|
58
|
+
* @param {number} [opts.quality=70] - calidad 1-100
|
|
59
|
+
* @param {object} [opts.pool] - Pool de base de datos
|
|
60
|
+
* @param {object} [opts.logger] - Instancia de logger
|
|
61
|
+
* @returns {Promise<string>} - object key en MinIO
|
|
62
|
+
*/
|
|
63
|
+
async function uploadScreenshot(client, bucket, botId, buffer, opts = {}) {
|
|
64
|
+
const { format = 'webp', quality = 70, pool, logger } = opts;
|
|
65
|
+
|
|
66
|
+
const finalBuffer = format === 'webp'
|
|
67
|
+
? await toWebp(buffer, quality)
|
|
68
|
+
: buffer;
|
|
69
|
+
|
|
70
|
+
const contentType = format === 'webp' ? 'image/webp' : 'image/jpeg';
|
|
71
|
+
const ext = format === 'webp' ? 'webp' : 'jpg';
|
|
72
|
+
const key = `${botId}.${ext}`;
|
|
73
|
+
|
|
74
|
+
await client.putObject(bucket, key, finalBuffer, finalBuffer.length, {
|
|
75
|
+
'Content-Type': contentType,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// ── 3. Registro en base de datos ─────────────────────────────────────────
|
|
79
|
+
if (pool) {
|
|
80
|
+
try {
|
|
81
|
+
await pool.query(
|
|
82
|
+
`UPDATE bots.tb_bots
|
|
83
|
+
SET url_screenshot = $1,
|
|
84
|
+
updated_at = NOW()
|
|
85
|
+
WHERE id = $2::uuid`,
|
|
86
|
+
[key, botId]
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
} catch (err) {
|
|
90
|
+
if (logger) {
|
|
91
|
+
logger.error({ err, botId, key }, 'No se pudo actualizar url_screenshot en BD');
|
|
92
|
+
} else {
|
|
93
|
+
console.error(`[Storage] Error BD (${botId}):`, err.message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return key;
|
|
99
|
+
}
|
|
100
|
+
|
|
83
101
|
module.exports = { createMinioClient, ensureBucket, uploadScreenshot };
|
package/src/watcher.js
CHANGED
|
@@ -63,13 +63,13 @@ class ScreenshotWatcher {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
if (cfg.
|
|
67
|
-
this.logger.info({ intervalSec: cfg.
|
|
68
|
-
this._startScreenshots(page, cfg.
|
|
66
|
+
if (cfg.screenshots_activo && !this._shotTimer) {
|
|
67
|
+
this.logger.info({ intervalSec: cfg.intervalo_sec }, 'Screenshots activados');
|
|
68
|
+
this._startScreenshots(page, cfg.intervalo_sec * 1000);
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
if (!cfg.
|
|
72
|
+
if (!cfg.screenshots_activo && this._shotTimer) {
|
|
73
73
|
this.logger.info('Screenshots desactivados');
|
|
74
74
|
this._stopScreenshots();
|
|
75
75
|
}
|