jerkjs 2.5.8 → 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 (36) hide show
  1. package/CHANGELOG.md +162 -99
  2. package/README.md +113 -190
  3. package/RESULTADOS_WAF.md +63 -0
  4. package/doc-2.5/MANUAL_MODULOS_ADMIN.md +287 -0
  5. package/doc-2.5/QUEUE_CLI_MODULE_MANUAL.md +289 -0
  6. package/doc-2.5/QUEUE_SYSTEM_MANUAL.md +320 -0
  7. package/doc-2.5/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
  8. package/doc-2.5/WAF_MODULE_MANUAL.md +229 -0
  9. package/index.js +12 -3
  10. package/jerk-admin-client/README.md +69 -0
  11. package/jerk-admin-client/package.json +23 -0
  12. package/jerk-admin-client.js +257 -0
  13. package/lib/admin/AdminExtension.js +74 -19
  14. package/lib/admin/modules/ControllerGeneratorModule.js +414 -0
  15. package/lib/admin/modules/QueueManagementModule.js +265 -0
  16. package/lib/admin/modules/RouteCacheModule.js +227 -0
  17. package/lib/admin/modules/RouteManagerModule.js +468 -0
  18. package/lib/admin/modules/STATS_MODULE_README.md +15 -0
  19. package/lib/admin/modules/ViewCacheStatsModule.js +92 -0
  20. package/lib/admin/modules/WAFModule.js +737 -0
  21. package/lib/core/server.js +72 -69
  22. package/lib/middleware/firewall.js +112 -17
  23. package/lib/mvc/viewEngine.js +69 -10
  24. package/lib/queue/GlobalQueueStorage.js +38 -0
  25. package/lib/queue/QueueSystem.js +451 -0
  26. package/lib/queue/admin_example.js +114 -0
  27. package/lib/queue/example.js +268 -0
  28. package/lib/queue/integration.js +109 -0
  29. package/lib/utils/globalViewCacheInfo.js +16 -0
  30. package/lib/utils/globalWAFStats.js +54 -0
  31. package/package.json +2 -2
  32. package/test-colors.js +46 -0
  33. package/test-help-alias.js +31 -0
  34. package/ESTADISTICAS_RENDIMIENTO.md +0 -106
  35. package/debug_hook.js +0 -11
  36. package/docs/CACHE_SYSTEM_MAP.md +0 -206
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Módulo de Gestión de Colas para el Sistema CLI
3
+ * Implementación del componente admin/modules/QueueManagementModule.js
4
+ * Permite gestionar las colas desde el sistema de administración CLI
5
+ */
6
+
7
+ class QueueManagementModule {
8
+ constructor(adminExtension) {
9
+ this.name = 'Queue Management Module';
10
+ this.description = 'Módulo para gestionar las colas del sistema';
11
+ this.commands = ['queues', 'queue-info', 'queue-pause', 'queue-resume', 'queue-clear', 'queue-retry-failed'];
12
+ this.adminExtension = adminExtension;
13
+
14
+ // Referencia al sistema de colas global
15
+ this.queueSystem = null;
16
+
17
+ // Inicializar estructuras de datos compartidas globalmente
18
+ this.initializeGlobalQueueStorage();
19
+ }
20
+
21
+ /**
22
+ * Inicializa el almacenamiento global de colas
23
+ */
24
+ initializeGlobalQueueStorage() {
25
+ // Importar el almacenamiento global de colas
26
+ const { queueSystem } = require('../../queue/GlobalQueueStorage');
27
+
28
+ this.queueSystem = queueSystem;
29
+ }
30
+
31
+ /**
32
+ * Maneja los comandos del módulo
33
+ */
34
+ handleCommand(command, socket) {
35
+ switch (command) {
36
+ case 'queues':
37
+ this.listQueues(socket);
38
+ break;
39
+ case 'queue-info':
40
+ this.promptQueueName(socket, 'info');
41
+ break;
42
+ case 'queue-pause':
43
+ this.promptQueueName(socket, 'pause');
44
+ break;
45
+ case 'queue-resume':
46
+ this.promptQueueName(socket, 'resume');
47
+ break;
48
+ case 'queue-clear':
49
+ this.promptQueueName(socket, 'clear');
50
+ break;
51
+ case 'queue-retry-failed':
52
+ this.promptQueueName(socket, 'retry-failed');
53
+ break;
54
+ default:
55
+ socket.write(`Comando desconocido para el módulo de gestión de colas: ${command}\n`);
56
+ socket.write(`Comandos disponibles: ${this.commands.join(', ')}\n\n`);
57
+ socket.write(`> `);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Lista todas las colas
63
+ */
64
+ listQueues(socket) {
65
+ socket.write('\n=== Colas del Sistema ===\n');
66
+
67
+ if (this.queueSystem.queues.size === 0) {
68
+ socket.write('No hay colas registradas.\n');
69
+ } else {
70
+ for (const [queueName, queue] of this.queueSystem.queues.entries()) {
71
+ const status = this.queueSystem.getStatus()[queueName] || {};
72
+ socket.write(`${queueName}:\n`);
73
+ socket.write(` Concurrencia: ${queue.concurrency}/${queue.maxWorkers}\n`);
74
+ socket.write(` Tareas pendientes: ${status.pendingTasks || 0}\n`);
75
+ socket.write(` Tareas en proceso: ${status.runningTasks || 0}\n`);
76
+ socket.write(` Tareas fallidas: ${status.failedTasks || 0}\n`);
77
+ socket.write(` Estado: ${queue.processing ? 'PROCESANDO' : 'INACTIVO'}\n`);
78
+ socket.write(` Reintentos: ${queue.retryAttempts}\n`);
79
+ socket.write(` Retraso de reintento: ${queue.retryDelay}ms\n`);
80
+ socket.write('\n');
81
+ }
82
+ }
83
+
84
+ socket.write(`> `);
85
+ }
86
+
87
+ /**
88
+ * Muestra información detallada de una cola específica
89
+ */
90
+ showQueueInfo(socket, queueName) {
91
+ const queue = this.queueSystem.queues.get(queueName);
92
+
93
+ if (!queue) {
94
+ socket.write(`\n❌ Cola '${queueName}' no encontrada.\n\n`);
95
+ socket.write(`> `);
96
+ return;
97
+ }
98
+
99
+ const status = this.queueSystem.getStatus()[queueName] || {};
100
+
101
+ socket.write(`\n=== Información de la Cola: ${queueName} ===\n`);
102
+ socket.write(`Concurrencia: ${queue.concurrency}/${queue.maxWorkers}\n`);
103
+ socket.write(`Tareas pendientes: ${status.pendingTasks || 0}\n`);
104
+ socket.write(`Tareas en proceso: ${status.runningTasks || 0}\n`);
105
+ socket.write(`Tareas fallidas: ${status.failedTasks || 0}\n`);
106
+ socket.write(`Estado: ${queue.processing ? 'PROCESANDO' : 'INACTIVO'}\n`);
107
+ socket.write(`Reintentos: ${queue.retryAttempts}\n`);
108
+ socket.write(`Retraso de reintento: ${queue.retryDelay}ms\n`);
109
+ socket.write(`Total de workers: ${queue.workers}\n`);
110
+
111
+ socket.write('\n> ');
112
+ }
113
+
114
+ /**
115
+ * Pausa una cola específica
116
+ */
117
+ pauseQueue(socket, queueName) {
118
+ const result = this.queueSystem.pauseQueue(queueName);
119
+
120
+ if (!result) {
121
+ socket.write(`\n❌ Cola '${queueName}' no encontrada.\n\n`);
122
+ socket.write(`> `);
123
+ return;
124
+ }
125
+
126
+ socket.write(`\n✅ Cola '${queueName}' pausada exitosamente.\n\n`);
127
+ socket.write(`> `);
128
+ }
129
+
130
+ /**
131
+ * Reanuda una cola específica
132
+ */
133
+ resumeQueue(socket, queueName) {
134
+ const result = this.queueSystem.resumeQueue(queueName);
135
+
136
+ if (!result) {
137
+ socket.write(`\n❌ Cola '${queueName}' no encontrada.\n\n`);
138
+ socket.write(`> `);
139
+ return;
140
+ }
141
+
142
+ socket.write(`\n✅ Cola '${queueName}' reanudada exitosamente.\n\n`);
143
+ socket.write(`> `);
144
+ }
145
+
146
+ /**
147
+ * Limpia una cola específica (elimina tareas pendientes)
148
+ */
149
+ clearQueue(socket, queueName) {
150
+ const result = this.queueSystem.clearQueue(queueName);
151
+
152
+ if (!result) {
153
+ socket.write(`\n❌ Cola '${queueName}' no encontrada.\n\n`);
154
+ socket.write(`> `);
155
+ return;
156
+ }
157
+
158
+ socket.write(`\n✅ Cola '${queueName}' limpiada exitosamente (tareas pendientes eliminadas).\n\n`);
159
+ socket.write(`> `);
160
+ }
161
+
162
+ /**
163
+ * Reintenta tareas fallidas en una cola específica
164
+ */
165
+ retryFailedTasks(socket, queueName) {
166
+ const queue = this.queueSystem.queues.get(queueName);
167
+
168
+ if (!queue) {
169
+ socket.write(`\n❌ Cola '${queueName}' no encontrada.\n\n`);
170
+ socket.write(`> `);
171
+ return;
172
+ }
173
+
174
+ // Usar el método existente para reintentar tareas fallidas
175
+ this.queueSystem.retryFailedTasks(queueName);
176
+
177
+ socket.write(`\n✅ Reintento de tareas fallidas iniciado para la cola '${queueName}'.\n\n`);
178
+ socket.write(`> `);
179
+ }
180
+
181
+ /**
182
+ * Solicita el nombre de una cola al usuario
183
+ */
184
+ promptQueueName(socket, action) {
185
+ socket.write(`\nIntroduce el nombre de la cola (o 'cancel' para abortar):\n> `);
186
+
187
+ // Establecer el estado de entrada para este socket
188
+ if (!this.inputState) {
189
+ this.inputState = new Map();
190
+ }
191
+
192
+ // Guardar el estado de entrada para este socket
193
+ this.inputState.set(socket, { action });
194
+
195
+ // Adjuntar un manejador temporal para esta entrada
196
+ const originalOnData = socket.listeners('data')[0];
197
+ if (originalOnData) {
198
+ socket.removeListener('data', originalOnData);
199
+ }
200
+
201
+ const tempHandler = (data) => {
202
+ const input = data.toString().trim();
203
+
204
+ // Recuperar el estado de entrada
205
+ const state = this.inputState.get(socket);
206
+ if (state) {
207
+ this.inputState.delete(socket);
208
+
209
+ // Restaurar el manejador original
210
+ if (originalOnData) {
211
+ socket.on('data', originalOnData);
212
+ }
213
+
214
+ // Procesar la acción
215
+ this.processQueueAction(socket, state.action, input);
216
+ }
217
+ };
218
+
219
+ socket.on('data', tempHandler);
220
+ }
221
+
222
+ /**
223
+ * Procesa la acción en base al nombre de cola proporcionado
224
+ */
225
+ processQueueAction(socket, action, queueName) {
226
+ // Verificar si la cola existe antes de procesar la acción
227
+ const queueExists = this.queueSystem.queues.has(queueName);
228
+
229
+ if (!queueExists && queueName !== 'cancel') {
230
+ socket.write(`\n❌ Cola '${queueName}' no encontrada.\n\n`);
231
+ // Volver a solicitar el nombre de la cola
232
+ this.promptQueueName(socket, action);
233
+ return;
234
+ }
235
+
236
+ if (queueName === 'cancel') {
237
+ socket.write(`\nOperación cancelada.\n\n`);
238
+ socket.write(`> `);
239
+ return;
240
+ }
241
+
242
+ switch (action) {
243
+ case 'info':
244
+ this.showQueueInfo(socket, queueName);
245
+ break;
246
+ case 'pause':
247
+ this.pauseQueue(socket, queueName);
248
+ break;
249
+ case 'resume':
250
+ this.resumeQueue(socket, queueName);
251
+ break;
252
+ case 'clear':
253
+ this.clearQueue(socket, queueName);
254
+ break;
255
+ case 'retry-failed':
256
+ this.retryFailedTasks(socket, queueName);
257
+ break;
258
+ default:
259
+ socket.write(`\n❌ Acción desconocida: ${action}\n\n`);
260
+ socket.write(`> `);
261
+ }
262
+ }
263
+ }
264
+
265
+ module.exports = QueueManagementModule;
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Módulo CLI para gestionar y visualizar el cache de rutas dinámicas y estáticas
3
+ * Implementación del componente admin/modules/RouteCacheModule.js
4
+ */
5
+
6
+ class RouteCacheModule {
7
+ constructor(adminExtension) {
8
+ this.adminExtension = adminExtension;
9
+ this.name = 'Route Cache Module';
10
+ this.description = 'Módulo para gestionar y visualizar el cache de rutas dinámicas y estáticas';
11
+ this.commands = ['route-cache', 'cache-stats', 'cache-view', 'cache-clear', 'cache-dynamic', 'cache-static'];
12
+ }
13
+
14
+ /**
15
+ * Maneja los comandos del módulo
16
+ */
17
+ handleCommand(command, socket) {
18
+ switch (command) {
19
+ case 'route-cache':
20
+ case 'cache-stats':
21
+ this.showCacheStats(socket);
22
+ break;
23
+ case 'cache-view':
24
+ this.showCacheContents(socket);
25
+ break;
26
+ case 'cache-clear':
27
+ this.clearCache(socket);
28
+ break;
29
+ case 'cache-dynamic':
30
+ this.showDynamicCache(socket);
31
+ break;
32
+ case 'cache-static':
33
+ this.showStaticCache(socket);
34
+ break;
35
+ default:
36
+ socket.write(`\x1b[31mComando desconocido para el módulo de cache de rutas: ${command}\x1b[0m\n`); // Rojo para error
37
+ socket.write(`\x1b[32mComandos disponibles: route-cache, cache-stats, cache-view, cache-clear, cache-dynamic, cache-static\x1b[0m\n\n`); // Verde para comandos
38
+ socket.write(`> `);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Muestra estadísticas del cache de rutas
44
+ */
45
+ showCacheStats(socket) {
46
+ const routeMatcher = this.adminExtension.frameworkInstance.routeMatcher;
47
+
48
+ if (!routeMatcher) {
49
+ socket.write('\n=== Estadísticas del Cache de Rutas ===\n');
50
+ socket.write('No se encontró el componente RouteMatcher.\n\n');
51
+ socket.write('> ');
52
+ return;
53
+ }
54
+
55
+ // Contar rutas dinámicas (parametrizadas) en el cache
56
+ let dynamicRoutesCount = 0;
57
+ if (routeMatcher.routeRegexCache) {
58
+ dynamicRoutesCount = routeMatcher.routeRegexCache.size;
59
+ }
60
+
61
+ // Contar rutas estáticas en los índices
62
+ let staticRoutesCount = 0;
63
+ if (routeMatcher.exactRoutes) {
64
+ staticRoutesCount = routeMatcher.exactRoutes.size;
65
+ }
66
+
67
+ // Calcular el tamaño total de los índices
68
+ let totalIndexSize = 0;
69
+ if (routeMatcher.routeBuckets) {
70
+ for (const method in routeMatcher.routeBuckets) {
71
+ for (const segmentCount in routeMatcher.routeBuckets[method]) {
72
+ for (const firstSegment in routeMatcher.routeBuckets[method][segmentCount]) {
73
+ totalIndexSize += routeMatcher.routeBuckets[method][segmentCount][firstSegment].length;
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ socket.write('\n=== Estadísticas del Cache de Rutas ===\n');
80
+ socket.write(`Rutas dinámicas (parametrizadas) en cache: ${dynamicRoutesCount}\n`);
81
+ socket.write(`Rutas estáticas exactas en cache: ${staticRoutesCount}\n`);
82
+ socket.write(`Tamaño total de índices: ${totalIndexSize}\n`);
83
+ socket.write(`Índices válidos: ${routeMatcher.indexesValid ? 'Sí' : 'No'}\n\n`);
84
+ socket.write('> ');
85
+ }
86
+
87
+ /**
88
+ * Muestra el contenido del cache de rutas
89
+ */
90
+ showCacheContents(socket) {
91
+ const routeMatcher = this.adminExtension.frameworkInstance.routeMatcher;
92
+
93
+ if (!routeMatcher) {
94
+ socket.write('\n=== Contenido del Cache de Rutas ===\n');
95
+ socket.write('No se encontró el componente RouteMatcher.\n\n');
96
+ socket.write('> ');
97
+ return;
98
+ }
99
+
100
+ socket.write('\n=== Contenido del Cache de Rutas ===\n');
101
+
102
+ // Mostrar rutas dinámicas (parametrizadas) en cache
103
+ socket.write('\n--- Rutas Dinámicas (Parametrizadas) en Cache ---\n');
104
+ if (routeMatcher.routeRegexCache && routeMatcher.routeRegexCache.size > 0) {
105
+ let count = 0;
106
+ for (const [path, regex] of routeMatcher.routeRegexCache) {
107
+ socket.write(`${++count}. ${path} -> ${regex}\n`);
108
+ }
109
+ } else {
110
+ socket.write('No hay rutas dinámicas en cache.\n');
111
+ }
112
+
113
+ // Mostrar rutas estáticas exactas en cache
114
+ socket.write('\n--- Rutas Estáticas Exactas en Cache ---\n');
115
+ if (routeMatcher.exactRoutes && routeMatcher.exactRoutes.size > 0) {
116
+ let count = 0;
117
+ for (const [methodPath, route] of routeMatcher.exactRoutes) {
118
+ socket.write(`${++count}. ${methodPath} -> ${route.handler.name || 'anonymous'}\n`);
119
+ }
120
+ } else {
121
+ socket.write('No hay rutas estáticas exactas en cache.\n');
122
+ }
123
+
124
+ socket.write('\n> ');
125
+ }
126
+
127
+ /**
128
+ * Muestra solo el cache de rutas dinámicas
129
+ */
130
+ showDynamicCache(socket) {
131
+ const routeMatcher = this.adminExtension.frameworkInstance.routeMatcher;
132
+
133
+ if (!routeMatcher) {
134
+ socket.write('\n=== Cache de Rutas Dinámicas ===\n');
135
+ socket.write('No se encontró el componente RouteMatcher.\n\n');
136
+ socket.write('> ');
137
+ return;
138
+ }
139
+
140
+ socket.write('\n=== Cache de Rutas Dinámicas (Parametrizadas) ===\n');
141
+ if (routeMatcher.routeRegexCache && routeMatcher.routeRegexCache.size > 0) {
142
+ let count = 0;
143
+ for (const [path, regex] of routeMatcher.routeRegexCache) {
144
+ socket.write(`${++count}. Ruta: ${path}\n`);
145
+ socket.write(` Regex: ${regex}\n\n`);
146
+ }
147
+ socket.write(`Total: ${routeMatcher.routeRegexCache.size} rutas dinámicas en cache.\n`);
148
+ } else {
149
+ socket.write('No hay rutas dinámicas en cache.\n');
150
+ }
151
+
152
+ socket.write('\n> ');
153
+ }
154
+
155
+ /**
156
+ * Muestra solo el cache de rutas estáticas
157
+ */
158
+ showStaticCache(socket) {
159
+ const routeMatcher = this.adminExtension.frameworkInstance.routeMatcher;
160
+
161
+ if (!routeMatcher) {
162
+ socket.write('\n=== Cache de Rutas Estáticas ===\n');
163
+ socket.write('No se encontró el componente RouteMatcher.\n\n');
164
+ socket.write('> ');
165
+ return;
166
+ }
167
+
168
+ socket.write('\n=== Cache de Rutas Estáticas (Exactas) ===\n');
169
+ if (routeMatcher.exactRoutes && routeMatcher.exactRoutes.size > 0) {
170
+ let count = 0;
171
+ for (const [methodPath, route] of routeMatcher.exactRoutes) {
172
+ socket.write(`${++count}. ${methodPath}\n`);
173
+ socket.write(` Handler: ${route.handler.name || 'anonymous'}\n`);
174
+ socket.write(` Static: ${!!route.isStatic}\n\n`);
175
+ }
176
+ socket.write(`Total: ${routeMatcher.exactRoutes.size} rutas estáticas en cache.\n`);
177
+ } else {
178
+ socket.write('No hay rutas estáticas en cache.\n');
179
+ }
180
+
181
+ socket.write('\n> ');
182
+ }
183
+
184
+ /**
185
+ * Limpia el cache de rutas
186
+ */
187
+ clearCache(socket) {
188
+ const routeMatcher = this.adminExtension.frameworkInstance.routeMatcher;
189
+
190
+ if (!routeMatcher) {
191
+ socket.write('\n=== Limpieza del Cache de Rutas ===\n');
192
+ socket.write('No se encontró el componente RouteMatcher.\n\n');
193
+ socket.write('> ');
194
+ return;
195
+ }
196
+
197
+ // Obtener tamaños antes de limpiar
198
+ const dynamicBefore = routeMatcher.routeRegexCache ? routeMatcher.routeRegexCache.size : 0;
199
+ const staticBefore = routeMatcher.exactRoutes ? routeMatcher.exactRoutes.size : 0;
200
+
201
+ // Limpiar caches
202
+ if (routeMatcher.clearCache) {
203
+ routeMatcher.clearCache();
204
+ } else {
205
+ // Si no existe el método clearCache, limpiar manualmente
206
+ if (routeMatcher.routeRegexCache) {
207
+ routeMatcher.routeRegexCache.clear();
208
+ }
209
+ if (routeMatcher.exactRoutes) {
210
+ routeMatcher.exactRoutes.clear();
211
+ }
212
+ }
213
+
214
+ // Actualizar índices
215
+ if (routeMatcher.updateIndexes && this.adminExtension.frameworkInstance.routes) {
216
+ routeMatcher.updateIndexes(this.adminExtension.frameworkInstance.routes);
217
+ }
218
+
219
+ socket.write('\n=== Limpieza del Cache de Rutas ===\n');
220
+ socket.write(`Rutas dinámicas eliminadas: ${dynamicBefore}\n`);
221
+ socket.write(`Rutas estáticas eliminadas: ${staticBefore}\n`);
222
+ socket.write('Cache de rutas limpiado exitosamente.\n\n');
223
+ socket.write('> ');
224
+ }
225
+ }
226
+
227
+ module.exports = RouteCacheModule;