jerkjs 2.5.6 → 2.6.1

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 (46) hide show
  1. package/CHANGELOG.md +167 -79
  2. package/README.md +134 -146
  3. package/RESULTADOS_WAF.md +63 -0
  4. package/doc-2.5/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
  5. package/doc-2.5/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
  6. package/doc-2.5/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
  7. package/doc-2.5/CACHE_SYSTEM_MAP.md +206 -0
  8. package/doc-2.5/MANUAL_MODULOS_ADMIN.md +287 -0
  9. package/doc-2.5/QUEUE_CLI_MODULE_MANUAL.md +289 -0
  10. package/doc-2.5/QUEUE_SYSTEM_MANUAL.md +320 -0
  11. package/doc-2.5/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
  12. package/doc-2.5/WAF_MODULE_MANUAL.md +229 -0
  13. package/index.js +19 -4
  14. package/jerk-admin-client/README.md +69 -0
  15. package/jerk-admin-client/package.json +23 -0
  16. package/jerk-admin-client.js +257 -0
  17. package/lib/admin/AdminExtension.js +491 -0
  18. package/lib/admin/ModuleLoader.js +77 -0
  19. package/lib/admin/config.js +21 -0
  20. package/lib/admin/modules/CacheModule.js +145 -0
  21. package/lib/admin/modules/ControllerGeneratorModule.js +414 -0
  22. package/lib/admin/modules/QueueManagementModule.js +265 -0
  23. package/lib/admin/modules/RouteCacheModule.js +227 -0
  24. package/lib/admin/modules/RouteManagerModule.js +468 -0
  25. package/lib/admin/modules/STATS_MODULE_README.md +113 -0
  26. package/lib/admin/modules/StatsModule.js +140 -0
  27. package/lib/admin/modules/SystemModule.js +140 -0
  28. package/lib/admin/modules/TimeModule.js +95 -0
  29. package/lib/admin/modules/ViewCacheStatsModule.js +92 -0
  30. package/lib/admin/modules/WAFModule.js +737 -0
  31. package/lib/cache/CacheHooks.js +141 -0
  32. package/lib/core/server.js +223 -77
  33. package/lib/middleware/firewall.js +112 -17
  34. package/lib/mvc/viewEngine.js +89 -5
  35. package/lib/queue/GlobalQueueStorage.js +38 -0
  36. package/lib/queue/QueueSystem.js +451 -0
  37. package/lib/queue/admin_example.js +114 -0
  38. package/lib/queue/example.js +268 -0
  39. package/lib/queue/integration.js +109 -0
  40. package/lib/router/RouteMatcher.js +242 -54
  41. package/lib/utils/globalStats.js +16 -0
  42. package/lib/utils/globalViewCacheInfo.js +16 -0
  43. package/lib/utils/globalWAFStats.js +54 -0
  44. package/package.json +2 -2
  45. package/test-colors.js +46 -0
  46. package/test-help-alias.js +31 -0
@@ -0,0 +1,468 @@
1
+ /**
2
+ * Módulo de Gestión de Rutas para la Extensión de Administración de JERK Framework
3
+ * Módulo personalizado para crear y deshabilitar rutas de manera interactiva
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ class RouteManagerModule {
10
+ /**
11
+ * Constructor del módulo de gestión de rutas
12
+ * @param {Object} adminExtension - Instancia de la extensión de administración
13
+ */
14
+ constructor(adminExtension) {
15
+ this.adminExtension = adminExtension;
16
+ this.name = 'Route Manager Module';
17
+ this.description = 'Módulo para crear y deshabilitar rutas de manera interactiva';
18
+ this.commands = ['manage-routes', 'route-manager', 'route-mgmt'];
19
+
20
+ // Estado para el proceso interactivo
21
+ this.currentProcess = new Map(); // Almacena el estado de gestión por socket
22
+ }
23
+
24
+ /**
25
+ * Manejador para los comandos del módulo de gestión de rutas
26
+ * @param {string} command - Comando a ejecutar
27
+ * @param {Object} socket - Socket de la conexión
28
+ */
29
+ handleCommand(command, socket) {
30
+ switch (command) {
31
+ case 'manage-routes':
32
+ case 'route-manager':
33
+ case 'route-mgmt':
34
+ this.startRouteManagement(socket);
35
+ break;
36
+ default:
37
+ socket.write(`Comando desconocido para el módulo de gestión de rutas: ${command}\n`);
38
+ socket.write(`Comandos disponibles: manage-routes, route-manager, route-mgmt\n\n`);
39
+ socket.write(`> `);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Inicia el proceso interactivo de gestión de rutas
45
+ * @param {Object} socket - Socket de la conexión
46
+ */
47
+ startRouteManagement(socket) {
48
+ const sessionId = this.getSessionId(socket);
49
+
50
+ // Inicializar el estado de la sesión
51
+ this.currentProcess.set(sessionId, {
52
+ step: 'action',
53
+ routeData: {}
54
+ });
55
+
56
+ socket.write('\n=== Gestión de Rutas ===\n');
57
+ socket.write('¿Qué deseas hacer?\n');
58
+ socket.write('1. Crear nueva ruta\n');
59
+ socket.write('2. Deshabilitar ruta existente\n');
60
+ socket.write('3. Ver rutas registradas\n');
61
+ socket.write('4. Ver rutas activas\n');
62
+ socket.write('\nEscribe el número de la opción (1-4) o "cancel" para cancelar:\n> ');
63
+ }
64
+
65
+ /**
66
+ * Obtiene un ID único para la sesión del socket
67
+ * @param {Object} socket - Socket de la conexión
68
+ * @returns {string} - ID de sesión
69
+ */
70
+ getSessionId(socket) {
71
+ // Usar la dirección remota y puerto como identificador único
72
+ return `${socket.remoteAddress}:${socket.remotePort}`;
73
+ }
74
+
75
+ /**
76
+ * Procesa la entrada del usuario durante el proceso interactivo
77
+ * @param {Object} socket - Socket de la conexión
78
+ * @param {string} input - Entrada del usuario
79
+ */
80
+ processInput(socket, input) {
81
+ const sessionId = this.getSessionId(socket);
82
+ const processState = this.currentProcess.get(sessionId);
83
+
84
+ if (!processState) {
85
+ socket.write('No hay proceso activo. Usa "manage-routes" para iniciar.\n> ');
86
+ return;
87
+ }
88
+
89
+ const userInput = input.trim();
90
+
91
+ if (userInput.toLowerCase() === 'cancel') {
92
+ this.cancelProcess(socket, sessionId);
93
+ return;
94
+ }
95
+
96
+ switch (processState.step) {
97
+ case 'action':
98
+ this.handleActionSelection(socket, sessionId, userInput);
99
+ break;
100
+ case 'create_method':
101
+ this.handleCreateMethod(socket, sessionId, userInput);
102
+ break;
103
+ case 'create_path':
104
+ this.handleCreatePath(socket, sessionId, userInput);
105
+ break;
106
+ case 'create_controller':
107
+ this.handleCreateController(socket, sessionId, userInput);
108
+ break;
109
+ case 'create_handler':
110
+ this.handleCreateHandler(socket, sessionId, userInput);
111
+ break;
112
+ case 'create_confirm':
113
+ this.handleCreateConfirmation(socket, sessionId, userInput);
114
+ break;
115
+ case 'disable_select':
116
+ this.handleDisableSelection(socket, sessionId, userInput);
117
+ break;
118
+ case 'disable_confirm':
119
+ this.handleDisableConfirmation(socket, sessionId, userInput);
120
+ break;
121
+ case 'view_routes':
122
+ if (userInput.toLowerCase() === 'sí' || userInput.toLowerCase() === 'si' || userInput.toLowerCase() === 'yes') {
123
+ this.showRegisteredRoutes(socket);
124
+ } else {
125
+ socket.write('\nVolviendo al menú principal...\n> ');
126
+ this.resetProcess(socket);
127
+ }
128
+ break;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Maneja la selección de acción (crear, deshabilitar, ver rutas)
134
+ * @param {Object} socket - Socket de la conexión
135
+ * @param {string} sessionId - ID de la sesión
136
+ * @param {string} selection - Selección del usuario
137
+ */
138
+ handleActionSelection(socket, sessionId, selection) {
139
+ const processState = this.currentProcess.get(sessionId);
140
+
141
+ switch (selection) {
142
+ case '1':
143
+ processState.step = 'create_method';
144
+ processState.action = 'create';
145
+ socket.write('\n=== Crear Nueva Ruta ===\n');
146
+ socket.write('Selecciona el método HTTP:\n');
147
+ socket.write('1. GET\n2. POST\n3. PUT\n4. DELETE\n5. PATCH\n6. Otro\n');
148
+ socket.write('Escribe el número o el método directamente (GET, POST, etc.):\n> ');
149
+ break;
150
+ case '2':
151
+ processState.step = 'disable_select';
152
+ processState.action = 'disable';
153
+ this.listAvailableRoutes(socket);
154
+ break;
155
+ case '3':
156
+ this.showRegisteredRoutes(socket);
157
+ this.resetProcess(socket);
158
+ break;
159
+ case '4':
160
+ this.showActiveRoutes(socket);
161
+ this.resetProcess(socket);
162
+ break;
163
+ default:
164
+ socket.write('Opción inválida. Por favor, selecciona 1, 2, 3 o 4:\n> ');
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Muestra las rutas registradas
170
+ * @param {Object} socket - Socket de la conexión
171
+ */
172
+ showRegisteredRoutes(socket) {
173
+ if (this.adminExtension.registeredRoutes && this.adminExtension.registeredRoutes.length > 0) {
174
+ socket.write('\n=== Rutas Registradas ===\n');
175
+ this.adminExtension.registeredRoutes.forEach((route, index) => {
176
+ socket.write(`${index + 1}. ${route.method} ${route.path}\n`);
177
+ });
178
+ } else {
179
+ socket.write('\n=== Rutas Registradas ===\n');
180
+ socket.write('No hay rutas registradas.\n');
181
+ }
182
+ socket.write('\n> ');
183
+ }
184
+
185
+ /**
186
+ * Muestra las rutas activas
187
+ * @param {Object} socket - Socket de la conexión
188
+ */
189
+ showActiveRoutes(socket) {
190
+ if (this.adminExtension.activeRoutes && this.adminExtension.activeRoutes.size > 0) {
191
+ socket.write('\n=== Rutas Activas ===\n');
192
+ for (const [url, info] of this.adminExtension.activeRoutes) {
193
+ socket.write(`${info.method} ${url} - ${info.timestamp} (${info.remoteAddress})\n`);
194
+ }
195
+ } else {
196
+ socket.write('\n=== Rutas Activas ===\n');
197
+ socket.write('No hay rutas activas registradas.\n');
198
+ }
199
+ socket.write('\n> ');
200
+ }
201
+
202
+ /**
203
+ * Lista las rutas disponibles para deshabilitar
204
+ * @param {Object} socket - Socket de la conexión
205
+ */
206
+ listAvailableRoutes(socket) {
207
+ if (this.adminExtension.registeredRoutes && this.adminExtension.registeredRoutes.length > 0) {
208
+ socket.write('\n=== Rutas Disponibles para Deshabilitar ===\n');
209
+ this.adminExtension.registeredRoutes.forEach((route, index) => {
210
+ socket.write(`${index + 1}. ${route.method} ${route.path}\n`);
211
+ });
212
+ socket.write('\nSelecciona el número de la ruta que deseas deshabilitar:\n> ');
213
+ } else {
214
+ socket.write('\nNo hay rutas registradas para deshabilitar.\n');
215
+ socket.write('Volviendo al menú principal...\n> ');
216
+ this.resetProcess(socket);
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Maneja la selección del método HTTP para crear ruta
222
+ * @param {Object} socket - Socket de la conexión
223
+ * @param {string} sessionId - ID de la sesión
224
+ * @param {string} method - Método HTTP seleccionado
225
+ */
226
+ handleCreateMethod(socket, sessionId, method) {
227
+ const processState = this.currentProcess.get(sessionId);
228
+ const methodMap = {
229
+ '1': 'GET', '2': 'POST', '3': 'PUT', '4': 'DELETE', '5': 'PATCH', '6': 'OTHER'
230
+ };
231
+
232
+ let selectedMethod;
233
+ if (methodMap[method]) {
234
+ selectedMethod = methodMap[method];
235
+ if (selectedMethod === 'OTHER') {
236
+ socket.write('Escribe el método HTTP personalizado:\n> ');
237
+ return;
238
+ }
239
+ } else {
240
+ selectedMethod = method.toUpperCase();
241
+ }
242
+
243
+ processState.routeData.method = selectedMethod;
244
+ processState.step = 'create_path';
245
+
246
+ socket.write(`\nMétodo seleccionado: ${selectedMethod}\n`);
247
+ socket.write('Introduce la ruta (ej: /api/users, /users/:id):\n> ');
248
+ }
249
+
250
+ /**
251
+ * Maneja la introducción de la ruta
252
+ * @param {Object} socket - Socket de la conexión
253
+ * @param {string} sessionId - ID de la sesión
254
+ * @param {string} routePath - Ruta introducida
255
+ */
256
+ handleCreatePath(socket, sessionId, routePath) {
257
+ const processState = this.currentProcess.get(sessionId);
258
+
259
+ if (!routePath || !routePath.startsWith('/')) {
260
+ socket.write('La ruta debe comenzar con "/". Por favor, introduce una ruta válida:\n> ');
261
+ return;
262
+ }
263
+
264
+ processState.routeData.path = routePath;
265
+ processState.step = 'create_controller';
266
+
267
+ socket.write(`\nRuta: ${routePath}\n`);
268
+ socket.write('Introduce la ruta al archivo del controlador (ej: ./controllers/UserController.js):\n> ');
269
+ }
270
+
271
+ /**
272
+ * Maneja la introducción del controlador
273
+ * @param {Object} socket - Socket de la conexión
274
+ * @param {string} sessionId - ID de la sesión
275
+ * @param {string} controller - Ruta al controlador
276
+ */
277
+ handleCreateController(socket, sessionId, controller) {
278
+ const processState = this.currentProcess.get(sessionId);
279
+
280
+ if (!controller) {
281
+ socket.write('La ruta al controlador no puede estar vacía. Por favor, introduce una ruta válida:\n> ');
282
+ return;
283
+ }
284
+
285
+ processState.routeData.controller = controller;
286
+ processState.step = 'create_handler';
287
+
288
+ socket.write(`\nControlador: ${controller}\n`);
289
+ socket.write('Introduce el nombre del método del controlador (ej: index, show, create):\n> ');
290
+ }
291
+
292
+ /**
293
+ * Maneja la introducción del handler
294
+ * @param {Object} socket - Socket de la conexión
295
+ * @param {string} sessionId - ID de la sesión
296
+ * @param {string} handler - Nombre del handler
297
+ */
298
+ handleCreateHandler(socket, sessionId, handler) {
299
+ const processState = this.currentProcess.get(sessionId);
300
+
301
+ if (!handler) {
302
+ socket.write('El nombre del handler no puede estar vacío. Por favor, introduce un nombre válido:\n> ');
303
+ return;
304
+ }
305
+
306
+ processState.routeData.handler = handler;
307
+ processState.step = 'create_confirm';
308
+
309
+ socket.write(`\nHandler: ${handler}\n`);
310
+ this.showRoutePreview(socket, processState.routeData);
311
+ }
312
+
313
+ /**
314
+ * Muestra una vista previa de la ruta que se va a crear
315
+ * @param {Object} socket - Socket de la conexión
316
+ * @param {Object} routeData - Datos de la ruta
317
+ */
318
+ showRoutePreview(socket, routeData) {
319
+ socket.write('\n=== Vista Previa de la Ruta ===\n');
320
+ socket.write(`Método: ${routeData.method}\n`);
321
+ socket.write(`Ruta: ${routeData.path}\n`);
322
+ socket.write(`Controlador: ${routeData.controller}\n`);
323
+ socket.write(`Handler: ${routeData.handler}\n\n`);
324
+
325
+ const routeEntry = {
326
+ path: routeData.path,
327
+ method: routeData.method,
328
+ controller: routeData.controller,
329
+ handler: routeData.handler,
330
+ contentType: "application/json"
331
+ };
332
+
333
+ socket.write('Entrada para routes.json:\n');
334
+ socket.write(JSON.stringify(routeEntry, null, 2) + '\n\n');
335
+
336
+ socket.write('¿Deseas crear esta ruta? (sí/no):\n> ');
337
+ }
338
+
339
+ /**
340
+ * Maneja la confirmación de creación de ruta
341
+ * @param {Object} socket - Socket de la conexión
342
+ * @param {string} sessionId - ID de la sesión
343
+ * @param {string} confirmation - Confirmación del usuario
344
+ */
345
+ handleCreateConfirmation(socket, sessionId, confirmation) {
346
+ const processState = this.currentProcess.get(sessionId);
347
+
348
+ if (confirmation.toLowerCase() === 'sí' || confirmation.toLowerCase() === 'si' || confirmation.toLowerCase() === 'yes') {
349
+ this.createRoute(socket, processState.routeData);
350
+ } else {
351
+ socket.write('\nCreación de ruta cancelada.\n> ');
352
+ this.resetProcess(socket);
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Crea la ruta en el sistema
358
+ * @param {Object} socket - Socket de la conexión
359
+ * @param {Object} routeData - Datos de la ruta
360
+ */
361
+ createRoute(socket, routeData) {
362
+ // En un entorno real, aquí se agregaría la ruta al servidor
363
+ // Por ahora, solo mostramos un mensaje de confirmación
364
+
365
+ socket.write(`\n✅ Ruta "${routeData.method} ${routeData.path}" creada exitosamente.\n`);
366
+ socket.write(`- Controlador: ${routeData.controller}\n`);
367
+ socket.write(`- Handler: ${routeData.handler}\n`);
368
+
369
+ // Agregar a las rutas registradas
370
+ if (this.adminExtension.registeredRoutes) {
371
+ const newRoute = {
372
+ method: routeData.method,
373
+ path: routeData.path,
374
+ controller: routeData.controller,
375
+ handler: routeData.handler
376
+ };
377
+ this.adminExtension.registeredRoutes.push(newRoute);
378
+ }
379
+
380
+ socket.write('\n> ');
381
+ this.resetProcess(socket);
382
+ }
383
+
384
+ /**
385
+ * Maneja la selección de ruta para deshabilitar
386
+ * @param {Object} socket - Socket de la conexión
387
+ * @param {string} sessionId - ID de la sesión
388
+ * @param {string} selection - Selección del usuario
389
+ */
390
+ handleDisableSelection(socket, sessionId, selection) {
391
+ const processState = this.currentProcess.get(sessionId);
392
+
393
+ const routeIndex = parseInt(selection) - 1;
394
+
395
+ if (isNaN(routeIndex) || routeIndex < 0 || routeIndex >= this.adminExtension.registeredRoutes.length) {
396
+ socket.write('Número de ruta inválido. Por favor, selecciona un número válido:\n> ');
397
+ return;
398
+ }
399
+
400
+ processState.routeToDisable = this.adminExtension.registeredRoutes[routeIndex];
401
+ processState.step = 'disable_confirm';
402
+
403
+ socket.write(`\nRuta seleccionada para deshabilitar:\n`);
404
+ socket.write(`${processState.routeToDisable.method} ${processState.routeToDisable.path}\n`);
405
+ socket.write(`¿Estás seguro de que deseas deshabilitar esta ruta? (sí/no):\n> `);
406
+ }
407
+
408
+ /**
409
+ * Maneja la confirmación de deshabilitación de ruta
410
+ * @param {Object} socket - Socket de la conexión
411
+ * @param {string} sessionId - ID de la sesión
412
+ * @param {string} confirmation - Confirmación del usuario
413
+ */
414
+ handleDisableConfirmation(socket, sessionId, confirmation) {
415
+ const processState = this.currentProcess.get(sessionId);
416
+
417
+ if (confirmation.toLowerCase() === 'sí' || confirmation.toLowerCase() === 'si' || confirmation.toLowerCase() === 'yes') {
418
+ this.disableRoute(socket, processState.routeToDisable);
419
+ } else {
420
+ socket.write('\nDeshabilitación de ruta cancelada.\n> ');
421
+ this.resetProcess(socket);
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Deshabilita la ruta del sistema
427
+ * @param {Object} socket - Socket de la conexión
428
+ * @param {Object} route - Ruta a deshabilitar
429
+ */
430
+ disableRoute(socket, route) {
431
+ // En un entorno real, aquí se removería la ruta del servidor
432
+ // Por ahora, solo mostramos un mensaje de confirmación
433
+
434
+ socket.write(`\n✅ Ruta "${route.method} ${route.path}" deshabilitada exitosamente.\n`);
435
+
436
+ // Remover de las rutas registradas
437
+ if (this.adminExtension.registeredRoutes) {
438
+ const index = this.adminExtension.registeredRoutes.indexOf(route);
439
+ if (index !== -1) {
440
+ this.adminExtension.registeredRoutes.splice(index, 1);
441
+ }
442
+ }
443
+
444
+ socket.write('\n> ');
445
+ this.resetProcess(socket);
446
+ }
447
+
448
+ /**
449
+ * Reinicia el proceso de gestión de rutas
450
+ * @param {Object} socket - Socket de la conexión
451
+ */
452
+ resetProcess(socket) {
453
+ const sessionId = this.getSessionId(socket);
454
+ this.currentProcess.delete(sessionId);
455
+ }
456
+
457
+ /**
458
+ * Cancela el proceso de gestión de rutas
459
+ * @param {Object} socket - Socket de la conexión
460
+ * @param {string} sessionId - ID de la sesión
461
+ */
462
+ cancelProcess(socket, sessionId) {
463
+ this.currentProcess.delete(sessionId);
464
+ socket.write('\nProceso cancelado.\n> ');
465
+ }
466
+ }
467
+
468
+ module.exports = RouteManagerModule;
@@ -0,0 +1,113 @@
1
+ # Módulo de Estadísticas para la Extensión de Administración de JERK Framework
2
+
3
+ ## Descripción
4
+
5
+ El módulo de estadísticas es una extensión de la extensión de administración de JERK Framework que permite monitorear y visualizar métricas importantes del servidor en tiempo real.
6
+
7
+ ## Características
8
+
9
+ - Conteo de solicitudes procesadas y respuestas enviadas
10
+ - Medición del tráfico de entrada y salida en kilobytes
11
+ - Registro de accesos a rutas y endpoints
12
+ - Identificación de endpoints y rutas más accedidas
13
+ - Sistema de estadísticas global para acceso directo y confiable
14
+
15
+ ## Comandos Disponibles
16
+
17
+ - `stats` o `statistics`: Muestra estadísticas generales del servidor
18
+ - `requests`: Muestra estadísticas específicas de solicitudes
19
+ - `endpoints`: Muestra estadísticas de endpoints y rutas más accedidas
20
+
21
+ ## Métricas Monitorizadas
22
+
23
+ ### Estadísticas Generales
24
+ - Solicitudes procesadas totales
25
+ - Cantidad de datos recibidos (en KB)
26
+ - Respuestas enviadas totales
27
+ - Cantidad de datos enviados (en KB)
28
+ - Número de rutas registradas
29
+ - Número de rutas activas
30
+
31
+ ### Estadísticas de Solicitudes
32
+ - Total de solicitudes procesadas
33
+ - Total de bytes recibidos
34
+ - Accesos a rutas (Input/Output)
35
+
36
+ ### Estadísticas de Endpoints
37
+ - Top 10 endpoints más accedidos
38
+ - Top 10 rutas más accedidas
39
+
40
+ ## Sistema de Almacenamiento de Estadísticas
41
+
42
+ A diferencia de enfoques basados en hooks, este módulo utiliza un sistema de almacenamiento global de estadísticas (`globalStats`) que se actualiza directamente en el servidor cuando ocurren eventos, garantizando:
43
+
44
+ - Acceso directo y confiable a las métricas
45
+ - Actualización en tiempo real sin dependencia de hooks
46
+ - Persistencia de datos entre solicitudes
47
+ - Mayor rendimiento y menor latencia
48
+
49
+ ### Componentes del Sistema de Estadísticas
50
+
51
+ - `globalStats.requestsProcessed`: Contador de solicitudes procesadas
52
+ - `globalStats.responsesSent`: Contador de respuestas enviadas
53
+ - `globalStats.requestBytes`: Total de bytes recibidos
54
+ - `globalStats.responseBytes`: Total de bytes enviados
55
+ - `globalStats.routeAccesses`: Mapa de accesos a rutas
56
+ - `globalStats.endpointHits`: Mapa de hits a endpoints
57
+
58
+ ### Actualización de Estadísticas en el Servidor
59
+
60
+ Las estadísticas se actualizan directamente en el servidor en los siguientes puntos:
61
+
62
+ - Al procesar el cuerpo de la solicitud: actualiza `requestBytes`
63
+ - Al enviar la respuesta: actualiza `responseBytes`
64
+ - Al procesar una ruta: actualiza `requestsProcessed`, `responsesSent`, `routeAccesses`, `endpointHits`
65
+
66
+ ## Sistema de Caché de Vistas
67
+
68
+ Además del sistema de estadísticas general, el framework también incluye un sistema de caché de vistas con estadísticas globales:
69
+
70
+ - `globalViewCacheInfo.viewCache`: Mapa de vistas en caché
71
+ - `globalViewCacheInfo.cacheStats`: Estadísticas de hits/misses
72
+ - `globalViewCacheInfo.viewDependencies`: Registro de dependencias entre vistas (inclusiones)
73
+
74
+ ### Estadísticas del Caché de Vistas
75
+
76
+ - Hits: Número de accesos exitosos al caché
77
+ - Misses: Número de veces que se leyó desde disco
78
+ - Tasa de aciertos: Porcentaje de accesos exitosos
79
+ - Dependencias: Registro de inclusiones entre vistas
80
+
81
+ ## Instalación
82
+
83
+ El módulo se carga automáticamente cuando se inicializa la extensión de administración, ya que está ubicado en el directorio `modules` de la extensión.
84
+
85
+ ## Uso
86
+
87
+ 1. Inicialice la extensión de administración en su servidor:
88
+
89
+ ```javascript
90
+ const server = new APIServer({ port: 3000 });
91
+ server.initializeAdminExtension({
92
+ port: 9999,
93
+ host: '127.0.0.1'
94
+ });
95
+ ```
96
+
97
+ 2. Conéctese al servidor de administración:
98
+
99
+ ```bash
100
+ telnet localhost 9999
101
+ ```
102
+
103
+ 3. Use cualquiera de los comandos disponibles:
104
+
105
+ ```
106
+ stats
107
+ requests
108
+ endpoints
109
+ ```
110
+
111
+ ## Contribución
112
+
113
+ Las contribuciones son bienvenidas. Si desea mejorar este módulo, por favor cree un fork del repositorio y envíe un pull request con sus cambios.