@arela/uploader 1.0.24 → 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/docs/AUTO_PROCESSING_PIPELINE.md +258 -0
- package/docs/COMPLETE_USAGE_GUIDE.md +1363 -0
- package/docs/DATABASESERVICE_IMPROVEMENTS.md +546 -0
- package/docs/PASO_2_TEST_RESULTS.md +298 -0
- package/docs/PASO_3_PLAN.md +385 -0
- package/docs/PHASE_1_FILE_DETECTION.md +366 -0
- package/docs/PHASE_2_API_INTEGRATION.md +426 -0
- package/docs/PHASE_3_DATABASE_MANAGEMENT.md +480 -0
- package/docs/PHASE_4_FILE_OPERATIONS.md +448 -0
- package/docs/PHASE_5_WATCH_MODE.md +450 -0
- package/docs/PHASE_6_SIGNAL_HANDLING.md +472 -0
- package/docs/PHASE_7_ADVANCED_FEATURES.md +560 -0
- package/docs/PLAN_WATCH_FEATURE.md +417 -0
- package/docs/README.md +480 -0
- package/docs/SCHEMA_ALIGNMENT_SUMMARY.md +301 -0
- package/docs/SMARTWATCH_DATABASE_REFACTORING.md +181 -0
- package/docs/SMART_WATCH_DATABASE_CHANGES.md +502 -0
- package/docs/TESTING_WATCH_MODE.md +212 -0
- package/docs/WATCHER_API_IMPLEMENTATION.md +520 -0
- package/docs/WATCHER_API_INTEGRATION.md +562 -0
- package/docs/WATCHER_SETUP_GUIDE.md +614 -0
- package/docs/WATCH_ARCHITECTURE.md +395 -0
- package/docs/WATCH_AUTO_PIPELINE.md +334 -0
- package/docs/WATCH_CONFIGURATION.md +267 -0
- package/docs/WATCH_USAGE_GUIDE.md +567 -0
- package/docs/commands.md +14 -0
- package/package.json +1 -1
- package/src/commands/IdentifyCommand.js +8 -0
- package/src/config/config.js +2 -2
- package/src/file-detection.js +42 -1
- package/src/scoring/scoring-engine.js +35 -7
- package/.vscode/settings.json +0 -1
- package/coverage/IdentifyCommand.js.html +0 -1462
- package/coverage/PropagateCommand.js.html +0 -1507
- package/coverage/PushCommand.js.html +0 -1504
- package/coverage/ScanCommand.js.html +0 -1654
- package/coverage/UploadCommand.js.html +0 -1846
- package/coverage/WatchCommand.js.html +0 -4111
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -191
- package/coverage/lcov-report/IdentifyCommand.js.html +0 -1462
- package/coverage/lcov-report/PropagateCommand.js.html +0 -1507
- package/coverage/lcov-report/PushCommand.js.html +0 -1504
- package/coverage/lcov-report/ScanCommand.js.html +0 -1654
- package/coverage/lcov-report/UploadCommand.js.html +0 -1846
- package/coverage/lcov-report/WatchCommand.js.html +0 -4111
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -191
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -1937
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/docs/API_ENDPOINTS_FOR_DETECTION.md +0 -647
- package/docs/API_RETRY_MECHANISM.md +0 -338
- package/docs/ARELA_IDENTIFY_IMPLEMENTATION.md +0 -489
- package/docs/ARELA_IDENTIFY_QUICKREF.md +0 -186
- package/docs/ARELA_PROPAGATE_IMPLEMENTATION.md +0 -581
- package/docs/ARELA_PROPAGATE_QUICKREF.md +0 -272
- package/docs/ARELA_PUSH_IMPLEMENTATION.md +0 -577
- package/docs/ARELA_PUSH_QUICKREF.md +0 -322
- package/docs/ARELA_SCAN_IMPLEMENTATION.md +0 -373
- package/docs/ARELA_SCAN_QUICKREF.md +0 -139
- package/docs/CROSS_PLATFORM_PATH_HANDLING.md +0 -597
- package/docs/DETECTION_ATTEMPT_TRACKING.md +0 -414
- package/docs/MIGRATION_UPLOADER_TO_FILE_STATS.md +0 -1020
- package/docs/MULTI_LEVEL_DIRECTORY_SCANNING.md +0 -494
- package/docs/QUICK_REFERENCE_API_DETECTION.md +0 -264
- package/docs/REFACTORING_SUMMARY_DETECT_PEDIMENTOS.md +0 -200
- package/docs/STATS_COMMAND_SEQUENCE_DIAGRAM.md +0 -287
- package/docs/STATS_COMMAND_SIMPLE.md +0 -93
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
# 🚀 Guía Paso a Paso: Integrar Watcher con arela-api
|
|
2
|
+
|
|
3
|
+
## 📌 Objetivo Final
|
|
4
|
+
Permitir que el frontend monitoree el estado del watcher en tiempo real a través de endpoints REST en la arela-api.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ✅ Pasos de Implementación
|
|
9
|
+
|
|
10
|
+
### **Paso 1: Preparar arela-uploader para exportar WatchService**
|
|
11
|
+
|
|
12
|
+
#### 1.1 Crear archivo de exportaciones
|
|
13
|
+
|
|
14
|
+
Crear: `src/services/index.js`
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
// Exportar todos los servicios disponibles públicamente
|
|
18
|
+
export { default as watchService } from './WatchService.js';
|
|
19
|
+
export { default as databaseService } from './DatabaseService.js';
|
|
20
|
+
export { default as autoProcessingService } from './AutoProcessingService.js';
|
|
21
|
+
export { default as logger } from './LoggingService.js';
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### 1.2 Actualizar package.json de arela-uploader
|
|
25
|
+
|
|
26
|
+
Agregar campo `exports`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"name": "arela-uploader",
|
|
31
|
+
"version": "1.0.0",
|
|
32
|
+
"type": "module",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": "./src/index.js",
|
|
35
|
+
"./services": "./src/services/index.js",
|
|
36
|
+
"./commands": "./src/commands/index.js"
|
|
37
|
+
},
|
|
38
|
+
"main": "./src/index.js"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
✅ **Resultado:** Otros módulos pueden hacer:
|
|
43
|
+
```javascript
|
|
44
|
+
import { watchService } from 'arela-uploader/services';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### **Paso 2: Preparar arela-api para usar WatchService**
|
|
50
|
+
|
|
51
|
+
#### 2.1 Instalar dependencia de arela-uploader
|
|
52
|
+
|
|
53
|
+
En el directorio `arela-api`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Opción A: Instalar desde ruta local
|
|
57
|
+
npm install ../arela-uploader
|
|
58
|
+
|
|
59
|
+
# Opción B: Si está publicado en npm
|
|
60
|
+
npm install arela-uploader
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### 2.2 Crear carpeta de rutas si no existe
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mkdir -p src/routes
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### 2.3 Crear archivo de rutas del watcher
|
|
70
|
+
|
|
71
|
+
Crear: `arela-api/src/routes/watcher.routes.js`
|
|
72
|
+
|
|
73
|
+
**Copiar contenido completo del archivo en `WATCHER_API_IMPLEMENTATION.md`**
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
import express from 'express';
|
|
77
|
+
import logger from '../services/LoggingService.js';
|
|
78
|
+
|
|
79
|
+
const router = express.Router();
|
|
80
|
+
|
|
81
|
+
export function initWatcherRoutes(app, watchService) {
|
|
82
|
+
// ... copiar todos los endpoints de WATCHER_API_IMPLEMENTATION.md ...
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default router;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 2.4 Integrar rutas en app.js
|
|
89
|
+
|
|
90
|
+
En `arela-api/src/app.js`:
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
import express from 'express';
|
|
94
|
+
import { initWatcherRoutes } from './routes/watcher.routes.js';
|
|
95
|
+
import { watchService } from 'arela-uploader/services'; // ✨ Nuevo
|
|
96
|
+
|
|
97
|
+
const app = express();
|
|
98
|
+
|
|
99
|
+
// Middleware
|
|
100
|
+
app.use(express.json());
|
|
101
|
+
app.use(express.urlencoded({ extended: true }));
|
|
102
|
+
|
|
103
|
+
// ... otras rutas ...
|
|
104
|
+
|
|
105
|
+
// ✨ Inicializar rutas del watcher
|
|
106
|
+
initWatcherRoutes(app, watchService);
|
|
107
|
+
|
|
108
|
+
// Error handling
|
|
109
|
+
app.use((err, req, res, next) => {
|
|
110
|
+
console.error(err);
|
|
111
|
+
res.status(500).json({
|
|
112
|
+
error: 'Internal server error',
|
|
113
|
+
message: err.message,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
export default app;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### **Paso 3: Agregar Autenticación (Opcional pero Recomendado)**
|
|
123
|
+
|
|
124
|
+
#### 3.1 Crear middleware de autenticación
|
|
125
|
+
|
|
126
|
+
Crear: `arela-api/src/middleware/auth.js`
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
import jwt from 'jsonwebtoken';
|
|
130
|
+
|
|
131
|
+
export const verifyAuth = (req, res, next) => {
|
|
132
|
+
try {
|
|
133
|
+
const token = req.headers.authorization?.split(' ')[1];
|
|
134
|
+
|
|
135
|
+
if (!token) {
|
|
136
|
+
return res.status(401).json({ error: 'No token provided' });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
140
|
+
req.user = decoded;
|
|
141
|
+
next();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
res.status(401).json({ error: 'Invalid token' });
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const requireRole = (role) => (req, res, next) => {
|
|
148
|
+
if (req.user?.role !== role && req.user?.role !== 'admin') {
|
|
149
|
+
return res.status(403).json({ error: 'Insufficient permissions' });
|
|
150
|
+
}
|
|
151
|
+
next();
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### 3.2 Actualizar rutas para protegerlas
|
|
156
|
+
|
|
157
|
+
En `watcher.routes.js`, agregar autenticación:
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
import { verifyAuth, requireRole } from '../middleware/auth.js';
|
|
161
|
+
|
|
162
|
+
export function initWatcherRoutes(app, watchService) {
|
|
163
|
+
// Endpoints de lectura (cualquier usuario autenticado)
|
|
164
|
+
router.get('/status', verifyAuth, (req, res) => {
|
|
165
|
+
// ... implementación ...
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
router.get('/queue-stats', verifyAuth, async (req, res) => {
|
|
169
|
+
// ... implementación ...
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
router.get('/directories', verifyAuth, (req, res) => {
|
|
173
|
+
// ... implementación ...
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Endpoints de control (solo admin)
|
|
177
|
+
router.post('/start', verifyAuth, requireRole('admin'), async (req, res) => {
|
|
178
|
+
// ... implementación ...
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
router.post('/stop', verifyAuth, requireRole('admin'), async (req, res) => {
|
|
182
|
+
// ... implementación ...
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// ... resto de rutas ...
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### **Paso 4: Actualizar Frontend para Consumir Endpoints**
|
|
192
|
+
|
|
193
|
+
#### 4.1 Crear hook de React para monitorear watcher
|
|
194
|
+
|
|
195
|
+
Crear: `frontend/src/hooks/useWatcherMonitor.js`
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
199
|
+
|
|
200
|
+
export const useWatcherMonitor = (pollInterval = 5000) => {
|
|
201
|
+
const [status, setStatus] = useState(null);
|
|
202
|
+
const [queue, setQueue] = useState(null);
|
|
203
|
+
const [directories, setDirectories] = useState([]);
|
|
204
|
+
const [loading, setLoading] = useState(false);
|
|
205
|
+
const [error, setError] = useState(null);
|
|
206
|
+
|
|
207
|
+
// Refrescar datos
|
|
208
|
+
const refresh = useCallback(async () => {
|
|
209
|
+
try {
|
|
210
|
+
setLoading(true);
|
|
211
|
+
setError(null);
|
|
212
|
+
|
|
213
|
+
const token = localStorage.getItem('token'); // O de donde lo tengas
|
|
214
|
+
const headers = {
|
|
215
|
+
'Content-Type': 'application/json',
|
|
216
|
+
'Authorization': `Bearer ${token}`,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const [statusRes, queueRes, dirRes] = await Promise.all([
|
|
220
|
+
fetch('/api/watcher/status', { headers }),
|
|
221
|
+
fetch('/api/watcher/queue-stats', { headers }),
|
|
222
|
+
fetch('/api/watcher/directories', { headers }),
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
if (!statusRes.ok || !queueRes.ok || !dirRes.ok) {
|
|
226
|
+
throw new Error('Failed to fetch watcher data');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
setStatus(await statusRes.json());
|
|
230
|
+
setQueue(await queueRes.json());
|
|
231
|
+
setDirectories(await dirRes.json());
|
|
232
|
+
} catch (err) {
|
|
233
|
+
setError(err.message);
|
|
234
|
+
console.error('Error fetching watcher data:', err);
|
|
235
|
+
} finally {
|
|
236
|
+
setLoading(false);
|
|
237
|
+
}
|
|
238
|
+
}, []);
|
|
239
|
+
|
|
240
|
+
// Poll automático
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
refresh(); // Fetch inicial
|
|
243
|
+
const interval = setInterval(refresh, pollInterval);
|
|
244
|
+
return () => clearInterval(interval);
|
|
245
|
+
}, [pollInterval, refresh]);
|
|
246
|
+
|
|
247
|
+
// Acciones
|
|
248
|
+
const startWatcher = useCallback(
|
|
249
|
+
async (directories) => {
|
|
250
|
+
const token = localStorage.getItem('token');
|
|
251
|
+
const res = await fetch('/api/watcher/start', {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
headers: {
|
|
254
|
+
'Content-Type': 'application/json',
|
|
255
|
+
'Authorization': `Bearer ${token}`,
|
|
256
|
+
},
|
|
257
|
+
body: JSON.stringify({ directories, autoProcessing: true }),
|
|
258
|
+
});
|
|
259
|
+
if (!res.ok) throw new Error('Failed to start watcher');
|
|
260
|
+
await refresh();
|
|
261
|
+
return res.json();
|
|
262
|
+
},
|
|
263
|
+
[refresh]
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const stopWatcher = useCallback(async () => {
|
|
267
|
+
const token = localStorage.getItem('token');
|
|
268
|
+
const res = await fetch('/api/watcher/stop', {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
271
|
+
});
|
|
272
|
+
if (!res.ok) throw new Error('Failed to stop watcher');
|
|
273
|
+
await refresh();
|
|
274
|
+
return res.json();
|
|
275
|
+
}, [refresh]);
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
status,
|
|
279
|
+
queue,
|
|
280
|
+
directories,
|
|
281
|
+
loading,
|
|
282
|
+
error,
|
|
283
|
+
refresh,
|
|
284
|
+
startWatcher,
|
|
285
|
+
stopWatcher,
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### 4.2 Usar el hook en un componente
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
// WatcherDashboard.jsx
|
|
294
|
+
import React from 'react';
|
|
295
|
+
import { useWatcherMonitor } from './hooks/useWatcherMonitor';
|
|
296
|
+
|
|
297
|
+
export const WatcherDashboard = () => {
|
|
298
|
+
const { status, queue, directories, loading, error, startWatcher, stopWatcher } =
|
|
299
|
+
useWatcherMonitor(5000); // Refrescar cada 5 segundos
|
|
300
|
+
|
|
301
|
+
if (loading && !status) return <div>Loading...</div>;
|
|
302
|
+
if (error) return <div className="error">Error: {error}</div>;
|
|
303
|
+
|
|
304
|
+
return (
|
|
305
|
+
<div className="watcher-dashboard">
|
|
306
|
+
<h1>🔍 File Watcher Monitor</h1>
|
|
307
|
+
|
|
308
|
+
{/* Status Section */}
|
|
309
|
+
<section className="status-card">
|
|
310
|
+
<h2>Estado</h2>
|
|
311
|
+
<div className="status-grid">
|
|
312
|
+
<div>
|
|
313
|
+
<span>Estado:</span>
|
|
314
|
+
<strong>{status?.isRunning ? '✅ Activo' : '❌ Detenido'}</strong>
|
|
315
|
+
</div>
|
|
316
|
+
<div>
|
|
317
|
+
<span>Directorios monitoreados:</span>
|
|
318
|
+
<strong>{status?.watchedDirectories}</strong>
|
|
319
|
+
</div>
|
|
320
|
+
<div>
|
|
321
|
+
<span>Auto-procesamiento:</span>
|
|
322
|
+
<strong>
|
|
323
|
+
{status?.autoProcessingEnabled ? '✅ Activo' : '❌ Inactivo'}
|
|
324
|
+
</strong>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
</section>
|
|
328
|
+
|
|
329
|
+
{/* Queue Statistics Section */}
|
|
330
|
+
<section className="queue-stats-card">
|
|
331
|
+
<h2>Cola de Procesamiento</h2>
|
|
332
|
+
<div className="progress-bar">
|
|
333
|
+
<div
|
|
334
|
+
className="progress-fill"
|
|
335
|
+
style={{
|
|
336
|
+
width: `${queue?.progress?.percentComplete || 0}%`,
|
|
337
|
+
}}
|
|
338
|
+
/>
|
|
339
|
+
</div>
|
|
340
|
+
<p>{queue?.progress?.percentComplete?.toFixed(1)}% completado</p>
|
|
341
|
+
|
|
342
|
+
<div className="queue-grid">
|
|
343
|
+
<div className="queue-item">
|
|
344
|
+
<span>Pendientes</span>
|
|
345
|
+
<strong>{queue?.queue?.pending || 0}</strong>
|
|
346
|
+
</div>
|
|
347
|
+
<div className="queue-item">
|
|
348
|
+
<span>Listos</span>
|
|
349
|
+
<strong>{queue?.queue?.readyToUpload || 0}</strong>
|
|
350
|
+
</div>
|
|
351
|
+
<div className="queue-item">
|
|
352
|
+
<span>Procesando</span>
|
|
353
|
+
<strong>{queue?.queue?.processing || 0}</strong>
|
|
354
|
+
</div>
|
|
355
|
+
<div className="queue-item">
|
|
356
|
+
<span>Subidos</span>
|
|
357
|
+
<strong>{queue?.queue?.uploaded || 0}</strong>
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
</section>
|
|
361
|
+
|
|
362
|
+
{/* Directories Section */}
|
|
363
|
+
<section className="directories-card">
|
|
364
|
+
<h2>Directorios Monitoreados</h2>
|
|
365
|
+
<ul>
|
|
366
|
+
{directories?.directories?.map((dir) => (
|
|
367
|
+
<li key={dir.path}>
|
|
368
|
+
<span>{dir.isReady ? '✅' : '⏳'}</span>
|
|
369
|
+
<span>{dir.path}</span>
|
|
370
|
+
<small>{dir.folderStructure}</small>
|
|
371
|
+
</li>
|
|
372
|
+
))}
|
|
373
|
+
</ul>
|
|
374
|
+
</section>
|
|
375
|
+
|
|
376
|
+
{/* Control Buttons */}
|
|
377
|
+
<section className="controls">
|
|
378
|
+
<button
|
|
379
|
+
onClick={() => startWatcher(['/path/to/watch'])}
|
|
380
|
+
disabled={status?.isRunning}
|
|
381
|
+
>
|
|
382
|
+
Iniciar Watcher
|
|
383
|
+
</button>
|
|
384
|
+
<button onClick={stopWatcher} disabled={!status?.isRunning}>
|
|
385
|
+
Detener Watcher
|
|
386
|
+
</button>
|
|
387
|
+
</section>
|
|
388
|
+
</div>
|
|
389
|
+
);
|
|
390
|
+
};
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
### **Paso 5: Documentar API con Swagger (Opcional)**
|
|
396
|
+
|
|
397
|
+
#### 5.1 Instalar dependencias
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
cd arela-api
|
|
401
|
+
npm install swagger-ui-express swagger-jsdoc
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### 5.2 Crear especificación de Swagger
|
|
405
|
+
|
|
406
|
+
Crear: `arela-api/src/swagger/watcher.swagger.js`
|
|
407
|
+
|
|
408
|
+
```javascript
|
|
409
|
+
export const watcherSwaggerDef = {
|
|
410
|
+
paths: {
|
|
411
|
+
'/api/watcher/status': {
|
|
412
|
+
get: {
|
|
413
|
+
summary: 'Get watcher status',
|
|
414
|
+
tags: ['Watcher'],
|
|
415
|
+
responses: {
|
|
416
|
+
200: {
|
|
417
|
+
description: 'Current watcher status',
|
|
418
|
+
schema: {
|
|
419
|
+
type: 'object',
|
|
420
|
+
properties: {
|
|
421
|
+
isRunning: { type: 'boolean' },
|
|
422
|
+
autoProcessingEnabled: { type: 'boolean' },
|
|
423
|
+
watchedDirectories: { type: 'number' },
|
|
424
|
+
stats: { type: 'object' },
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
500: {
|
|
429
|
+
description: 'Error getting status',
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
'/api/watcher/start': {
|
|
435
|
+
post: {
|
|
436
|
+
summary: 'Start the watcher',
|
|
437
|
+
tags: ['Watcher'],
|
|
438
|
+
requestBody: {
|
|
439
|
+
required: true,
|
|
440
|
+
content: {
|
|
441
|
+
'application/json': {
|
|
442
|
+
schema: {
|
|
443
|
+
type: 'object',
|
|
444
|
+
properties: {
|
|
445
|
+
directories: {
|
|
446
|
+
type: 'array',
|
|
447
|
+
items: { type: 'string' },
|
|
448
|
+
},
|
|
449
|
+
autoProcessing: { type: 'boolean' },
|
|
450
|
+
folderStructure: { type: 'string' },
|
|
451
|
+
},
|
|
452
|
+
required: ['directories'],
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
responses: {
|
|
458
|
+
200: { description: 'Watcher started successfully' },
|
|
459
|
+
400: { description: 'Invalid request' },
|
|
460
|
+
500: { description: 'Error starting watcher' },
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
// ... agregar más endpoints ...
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### 5.3 Integrar en app.js
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
import swaggerUi from 'swagger-ui-express';
|
|
473
|
+
import swaggerJsdoc from 'swagger-jsdoc';
|
|
474
|
+
import { watcherSwaggerDef } from './swagger/watcher.swagger.js';
|
|
475
|
+
|
|
476
|
+
const swaggerSpec = swaggerJsdoc({
|
|
477
|
+
definition: {
|
|
478
|
+
openapi: '3.0.0',
|
|
479
|
+
info: {
|
|
480
|
+
title: 'Arela API',
|
|
481
|
+
version: '1.0.0',
|
|
482
|
+
},
|
|
483
|
+
servers: [
|
|
484
|
+
{ url: 'http://localhost:3000', description: 'Development' },
|
|
485
|
+
],
|
|
486
|
+
...watcherSwaggerDef,
|
|
487
|
+
},
|
|
488
|
+
apis: [],
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**Acceder en:** `http://localhost:3000/api-docs`
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
### **Paso 6: Testing**
|
|
499
|
+
|
|
500
|
+
#### 6.1 Crear tests de integración
|
|
501
|
+
|
|
502
|
+
Crear: `arela-api/test/watcher.test.js`
|
|
503
|
+
|
|
504
|
+
```javascript
|
|
505
|
+
import request from 'supertest';
|
|
506
|
+
import app from '../src/app.js';
|
|
507
|
+
|
|
508
|
+
describe('Watcher API Routes', () => {
|
|
509
|
+
it('GET /api/watcher/status should return watcher status', async () => {
|
|
510
|
+
const response = await request(app)
|
|
511
|
+
.get('/api/watcher/status')
|
|
512
|
+
.set('Authorization', `Bearer ${validToken}`);
|
|
513
|
+
|
|
514
|
+
expect(response.status).toBe(200);
|
|
515
|
+
expect(response.body).toHaveProperty('isRunning');
|
|
516
|
+
expect(response.body).toHaveProperty('stats');
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it('GET /api/watcher/queue-stats should return queue statistics', async () => {
|
|
520
|
+
const response = await request(app)
|
|
521
|
+
.get('/api/watcher/queue-stats')
|
|
522
|
+
.set('Authorization', `Bearer ${validToken}`);
|
|
523
|
+
|
|
524
|
+
expect(response.status).toBe(200);
|
|
525
|
+
expect(response.body).toHaveProperty('queue');
|
|
526
|
+
expect(response.body).toHaveProperty('progress');
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it('POST /api/watcher/start should start watcher with directories', async () => {
|
|
530
|
+
const response = await request(app)
|
|
531
|
+
.post('/api/watcher/start')
|
|
532
|
+
.set('Authorization', `Bearer ${validToken}`)
|
|
533
|
+
.send({
|
|
534
|
+
directories: ['/test/dir'],
|
|
535
|
+
autoProcessing: true,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
expect(response.status).toBe(200);
|
|
539
|
+
expect(response.body.success).toBe(true);
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
#### 6.2 Ejecutar tests
|
|
545
|
+
|
|
546
|
+
```bash
|
|
547
|
+
npm test -- test/watcher.test.js
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## 📋 Checklist Final
|
|
553
|
+
|
|
554
|
+
- [ ] Crear `src/services/index.js` en arela-uploader
|
|
555
|
+
- [ ] Actualizar `package.json` de arela-uploader con `exports`
|
|
556
|
+
- [ ] Instalar arela-uploader en arela-api
|
|
557
|
+
- [ ] Crear `src/routes/watcher.routes.js` en arela-api
|
|
558
|
+
- [ ] Integrar rutas en `app.js`
|
|
559
|
+
- [ ] Crear middleware de autenticación (opcional)
|
|
560
|
+
- [ ] Proteger rutas con autenticación
|
|
561
|
+
- [ ] Crear hook `useWatcherMonitor` en frontend
|
|
562
|
+
- [ ] Crear componente `WatcherDashboard` en frontend
|
|
563
|
+
- [ ] Agregar Swagger (opcional)
|
|
564
|
+
- [ ] Crear tests de integración
|
|
565
|
+
- [ ] Documentar endpoints
|
|
566
|
+
- [ ] Validar que funciona end-to-end
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## 🧪 Testing End-to-End
|
|
571
|
+
|
|
572
|
+
### 1. Iniciar arela-api
|
|
573
|
+
```bash
|
|
574
|
+
cd arela-api
|
|
575
|
+
npm start
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### 2. Probar endpoints con curl
|
|
579
|
+
|
|
580
|
+
```bash
|
|
581
|
+
# Get status
|
|
582
|
+
curl http://localhost:3000/api/watcher/status \
|
|
583
|
+
-H "Authorization: Bearer YOUR_TOKEN"
|
|
584
|
+
|
|
585
|
+
# Get queue stats
|
|
586
|
+
curl http://localhost:3000/api/watcher/queue-stats \
|
|
587
|
+
-H "Authorization: Bearer YOUR_TOKEN"
|
|
588
|
+
|
|
589
|
+
# Start watcher
|
|
590
|
+
curl -X POST http://localhost:3000/api/watcher/start \
|
|
591
|
+
-H "Content-Type: application/json" \
|
|
592
|
+
-H "Authorization: Bearer YOUR_TOKEN" \
|
|
593
|
+
-d '{
|
|
594
|
+
"directories": ["/path/to/watch"],
|
|
595
|
+
"autoProcessing": true
|
|
596
|
+
}'
|
|
597
|
+
|
|
598
|
+
# Stop watcher
|
|
599
|
+
curl -X POST http://localhost:3000/api/watcher/stop \
|
|
600
|
+
-H "Authorization: Bearer YOUR_TOKEN"
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### 3. Verificar en frontend
|
|
604
|
+
- Abrir DevTools (F12)
|
|
605
|
+
- Ir a Network tab
|
|
606
|
+
- Verificar que se hacen llamadas a `/api/watcher/*`
|
|
607
|
+
- Ver respuestas JSON en Preview
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
## 🎉 ¡Listo!
|
|
612
|
+
|
|
613
|
+
El frontend ahora puede monitorear el watcher en tiempo real a través de la API REST.
|
|
614
|
+
|