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,229 @@
1
+ # Manual del Módulo WAF (Web Application Firewall) para JERK Framework
2
+
3
+ ## Tabla de Contenidos
4
+ 1. [Introducción](#introducción)
5
+ 2. [Características del WAF](#características-del-waf)
6
+ 3. [Comandos Disponibles](#comandos-disponibles)
7
+ 4. [Estadísticas del Servidor](#estadísticas-del-servidor)
8
+ 5. [Gestión de Reglas X-Headers](#gestión-de-reglas-x-headers)
9
+ 6. [Listas de IPs](#listas-de-ips)
10
+ 7. [Persistencia de Reglas](#persistencia-de-reglas)
11
+ 8. [Ejemplos de Uso](#ejemplos-de-uso)
12
+
13
+ ## Introducción
14
+
15
+ El módulo WAF (Web Application Firewall) es una extensión de la extensión de administración de JERK Framework que permite monitorear, gestionar y proteger tu aplicación web. Proporciona estadísticas en tiempo real, gestión de reglas de seguridad y control de acceso basado en headers X-.
16
+
17
+ ## Características del WAF
18
+
19
+ - **Estadísticas en tiempo real**: Conteo de solicitudes procesadas y respuestas enviadas con medición en kilobytes
20
+ - **Monitoreo de tráfico**: Registro de accesos a rutas y endpoints
21
+ - **Sistema de reglas X-Headers**: Bloqueo basado en headers como X-Forwarded-For, X-Real-IP, etc.
22
+ - **Listas de IPs**: Sistema de whitelist (nunca bloqueadas) y blacklist (siempre bloqueadas)
23
+ - **Persistencia**: Guardado y carga de reglas de seguridad
24
+ - **Interfaz interactiva**: Sistema de comandos para gestión en tiempo real
25
+
26
+ ## Comandos Disponibles
27
+
28
+ ### Comandos Generales de Estadísticas
29
+ - `waf-status` o `waf-stats`: Muestra estadísticas generales del servidor
30
+ - `waf-blocked` o `waf-security`: Muestra estadísticas de seguridad
31
+ - `waf-x-headers`: Muestra reglas de headers X- configuradas
32
+
33
+ ### Comandos de Gestión de Reglas
34
+ - `create-x-rule`: Crea una nueva regla de seguridad basada en headers X-
35
+ - `remove-x-rule`: Remueve una regla de seguridad existente
36
+ - `save-rules`: Guarda todas las reglas a un archivo
37
+ - `load-rules`: Carga reglas desde un archivo
38
+
39
+ ### Comandos de Gestión de IPs
40
+ - `waf-block-ip`: Bloquea temporalmente una IP
41
+ - `waf-unblock-ip`: Desbloquea una IP temporalmente bloqueada
42
+ - `waf-whitelist`: Agrega una IP a la lista blanca
43
+ - `waf-blacklist`: Agrega una IP a la lista negra
44
+
45
+ ## Estadísticas del Servidor
46
+
47
+ ### waf-status / waf-stats
48
+ Muestra las estadísticas generales del servidor:
49
+
50
+ ```
51
+ === Estadísticas del WAF ===
52
+ Solicitudes procesadas: 15
53
+ Solicitudes procesadas (KB): 2.45 KB
54
+ Respuestas enviadas: 15
55
+ Respuestas enviadas (KB): 15.67 KB
56
+ IPs en lista blanca: 2
57
+ IPs en lista negra: 1
58
+ Reglas de seguridad activas: 3
59
+ ```
60
+
61
+ ### Campos de Estadísticas
62
+ - **Solicitudes procesadas**: Número total de solicitudes HTTP procesadas
63
+ - **Solicitudes procesadas (KB)**: Cantidad total de datos recibidos en kilobytes
64
+ - **Respuestas enviadas**: Número total de respuestas HTTP enviadas
65
+ - **Respuestas enviadas (KB)**: Cantidad total de datos enviados en kilobytes
66
+ - **IPs en lista blanca**: Número de IPs que nunca serán bloqueadas
67
+ - **IPs en lista negra**: Número de IPs que siempre serán bloqueadas
68
+ - **Reglas de seguridad activas**: Número de reglas de seguridad activas
69
+
70
+ ## Gestión de Reglas X-Headers
71
+
72
+ ### Crear Regla (`create-x-rule`)
73
+ Proceso interactivo para crear reglas de seguridad basadas en headers X-:
74
+
75
+ 1. **Nombre del header**: Introduce el nombre del header X- (ej: X-Forwarded-For, X-Real-IP)
76
+ 2. **Patrón**: Introduce el patrón para coincidir (cadena o expresión regular)
77
+ 3. **Acción**: Selecciona la acción a tomar:
78
+ - `1` o `block`: Bloquear solicitudes que coincidan
79
+ - `2` o `log`: Registrar solicitudes que coincidan
80
+ - `3` o `monitor`: Monitorear solicitudes que coincidan
81
+ 4. **Razón**: Introduce la razón para la regla (opcional)
82
+
83
+ ### Remover Regla (`remove-x-rule`)
84
+ Proceso interactivo para remover reglas existentes:
85
+ 1. Se muestra una lista numerada de reglas disponibles
86
+ 2. Introduce el número de la regla que deseas remover
87
+ 3. La regla se elimina inmediatamente del sistema
88
+
89
+ ## Listas de IPs
90
+
91
+ ### Whitelist (`waf-whitelist`)
92
+ Agrega una IP a la lista blanca (nunca será bloqueada):
93
+
94
+ ```
95
+ > waf-whitelist
96
+ Introduce la IP a agregar a la lista blanca (ej: 192.168.1.100):
97
+ > 192.168.1.100
98
+ IP 192.168.1.100 agregada a la lista blanca.
99
+ ```
100
+
101
+ ### Blacklist (`waf-blacklist`)
102
+ Agrega una IP a la lista negra (siempre será bloqueada):
103
+
104
+ ```
105
+ > waf-blacklist
106
+ Introduce la IP a agregar a la lista negra (ej: 10.0.0.100):
107
+ > 10.0.0.100
108
+ IP 10.0.0.100 agregada a la lista negra.
109
+ ```
110
+
111
+ ### Bloqueo Temporal (`waf-block-ip`)
112
+ Bloquea temporalmente una IP:
113
+
114
+ ```
115
+ > waf-block-ip
116
+ Introduce la IP a bloquear temporalmente (ej: 192.168.1.100):
117
+ > 192.168.1.200
118
+ IP 192.168.1.200 bloqueada temporalmente.
119
+ ```
120
+
121
+ ## Persistencia de Reglas
122
+
123
+ ### Guardar Reglas (`save-rules`)
124
+ Guarda todas las reglas de seguridad actuales a un archivo JSON:
125
+
126
+ ```
127
+ > save-rules
128
+ ✅ Reglas guardadas exitosamente en: /path/to/waf-rules/waf-rules-timestamp.json
129
+ Total de reglas guardadas: 3
130
+ ```
131
+
132
+ ### Cargar Reglas (`load-rules`)
133
+ Carga reglas de seguridad desde un archivo JSON:
134
+
135
+ ```
136
+ > load-rules
137
+ === Archivos de Reglas Disponibles ===
138
+ 1. waf-rules-1770795262452.json
139
+
140
+ Introduce el número del archivo a cargar (o "cancel" para cancelar):
141
+ > 1
142
+
143
+ ¿Deseas reemplazar las reglas actuales? (sí/no):
144
+ > sí
145
+
146
+ ✅ Reglas cargadas exitosamente desde: /path/to/waf-rules/waf-rules-1770795262452.json
147
+ Total de reglas cargadas: 3
148
+ ```
149
+
150
+ ## Ejemplos de Uso
151
+
152
+ ### Ejemplo 1: Crear Regla para Bloquear IPs Internas
153
+ ```
154
+ > create-x-rule
155
+ === Crear Regla de Header X- ===
156
+ Introduce el nombre del header X- (ej: X-Forwarded-For, X-Real-IP):
157
+ > X-Forwarded-For
158
+ Header seleccionado: X-Forwarded-For
159
+ Introduce el patrón para coincidir (cadena o expresión regular):
160
+ > 192.168.
161
+ Selecciona la acción a tomar:
162
+ 1. block - Bloquear solicitudes que coincidan
163
+ 2. log - Registrar solicitudes que coincidan
164
+ 3. monitor - Monitorear solicitudes que coincidan
165
+ Escribe el número o el nombre de la acción:
166
+ > 1
167
+ Acción seleccionada: block
168
+ Introduce la razón para la regla (opcional):
169
+ > Bloquear IPs internas
170
+ ✅ Regla de header X- creada exitosamente:
171
+ ID: xheader_x_forwarded_for_1770792842636
172
+ Header: x-forwarded-for
173
+ Patrón: 192.168.
174
+ Acción: block
175
+ Razón: Bloquear IPs internas
176
+ ```
177
+
178
+ ### Ejemplo 2: Ver Estadísticas de Seguridad
179
+ ```
180
+ > waf-security
181
+ === Estadísticas de Seguridad del WAF ===
182
+ IPs bloqueadas temporalmente: 2
183
+ Intentos de ataque detectados: 5
184
+ Tipos de ataques detectados: 3
185
+ Registros de seguridad: 10
186
+
187
+ Accesos a rutas (Input/Output):
188
+ GET /: 8 accesos
189
+ POST /api/users: 3 accesos
190
+ GET /api/users: 4 accesos
191
+
192
+ Endpoints más accedidos:
193
+ GET /: 8 hits
194
+ GET /api/users: 4 hits
195
+ POST /api/users: 3 hits
196
+ ```
197
+
198
+ ### Ejemplo 3: Agregar IP a Lista Negra
199
+ ```
200
+ > waf-blacklist
201
+ Introduce la IP a agregar a la lista negra (ej: 10.0.0.100):
202
+ > 10.0.0.100
203
+ IP 10.0.0.100 agregada a la lista negra.
204
+ ```
205
+
206
+ ## Consideraciones de Seguridad
207
+
208
+ - El servidor de administración solo escucha en localhost (127.0.0.1) por defecto
209
+ - Todas las operaciones de bloqueo son inmediatas y afectan al sistema en tiempo real
210
+ - Las reglas de seguridad se aplican antes de que la solicitud llegue a los controladores
211
+ - El sistema de persistencia permite mantener reglas entre reinicios del servidor
212
+
213
+ ## Solución de Problemas
214
+
215
+ ### Las estadísticas no se actualizan
216
+ - Verifica que el middleware de firewall esté activo en tu servidor
217
+ - Asegúrate de que las solicitudes estén pasando por el sistema de firewall
218
+
219
+ ### Las reglas no se aplican
220
+ - Verifica que el firewall esté correctamente integrado en tu pipeline de middlewares
221
+ - Confirma que las reglas se hayan creado correctamente usando `waf-x-headers`
222
+
223
+ ## Autor
224
+
225
+ JERK Framework Team
226
+
227
+ ## Versión
228
+
229
+ v2.5.8
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Punto de entrada del framework JERK
3
- * JERK Framework 2.5.1
3
+ * JERK Framework 2.5.8
4
4
  */
5
5
 
6
6
  // Mostrar mensaje de versión al iniciar
@@ -51,10 +51,15 @@ const { ErrorHandler, ValidationError, AuthenticationError, DatabaseError } = re
51
51
 
52
52
  // Componentes de caché
53
53
  const CacheHooks = require('./lib/cache/CacheHooks');
54
+
54
55
  // Componentes del QueryBuilder (v2.3.0) - MODIFICADO PARA USAR QBUILDERJS
55
56
  const QueryBuilder = require('qbuilderjs');
56
57
  // No hay middleware ni hooks ya que se eliminó la implementación interna
57
58
 
59
+ // Componentes de sistema de colas (v2.6.0)
60
+ const QueueSystem = require('./lib/queue/QueueSystem');
61
+ const QueueIntegration = require('./lib/queue/integration');
62
+
58
63
 
59
64
  // Exportar todos los componentes del framework
60
65
  module.exports = {
@@ -100,7 +105,7 @@ module.exports = {
100
105
  // Componentes de modelo (v2.4.0)
101
106
  ModelBase,
102
107
  ModelManager,
103
- // Componentes del QueryBuilder (v2.3.0)
108
+ // Componentes del QueryBuilder (v2.3.0)
104
109
  QueryBuilder,
105
110
  UserModel,
106
111
 
@@ -118,6 +123,10 @@ module.exports = {
118
123
  AuthenticationError,
119
124
  DatabaseError,
120
125
 
126
+ // Componentes de sistema de colas (v2.6.0)
127
+ QueueSystem,
128
+ QueueIntegration,
129
+
121
130
  // Componentes de administración (v2.5.7)
122
131
  AdminExtension: require('./lib/admin/AdminExtension')
123
132
  };
@@ -130,4 +139,4 @@ const hooksInstance = new HookSystem();
130
139
  module.exports.hooks = hooksInstance;
131
140
 
132
141
  // Disparar hooks de inicio del framework
133
- hooksInstance.doAction('framework_init');
142
+ hooksInstance.doAction('framework_init');
@@ -0,0 +1,69 @@
1
+ # Cliente CLI para JERK Framework Administration Server
2
+
3
+ Cliente de línea de comandos para interactuar con el servidor de administración de JERK Framework. Permite reutilizar comandos y cuenta con autocompletado.
4
+
5
+ ## Características
6
+
7
+ - **Autocompletado**: Presiona TAB para autocompletar comandos conocidos
8
+ - **Historial de comandos**: Accede a comandos previamente utilizados
9
+ - **Reutilización de comandos**: Reutiliza comandos por número o por texto
10
+ - **Conservación de contexto**: Mantiene el historial entre sesiones
11
+
12
+ ## Instalación
13
+
14
+ El cliente CLI está incluido en el framework JERK y se puede ejecutar directamente:
15
+
16
+ ```bash
17
+ node jerk-admin-client.js
18
+ ```
19
+
20
+ O con parámetros específicos:
21
+
22
+ ```bash
23
+ node jerk-admin-client.js --host 127.0.0.1 --port 9999
24
+ ```
25
+
26
+ ## Comandos del Cliente
27
+
28
+ Además de los comandos del servidor de administración, el cliente CLI incluye comandos especiales:
29
+
30
+ - `history` - Muestra el historial de comandos
31
+ - `clear` - Limpia la pantalla
32
+ - `re <número>` - Reutiliza el comando número n del historial
33
+ - `re <texto>` - Reutiliza el último comando que contiene el texto
34
+ - `help-cli` - Muestra la ayuda del cliente
35
+
36
+ ## Uso
37
+
38
+ 1. Inicia el cliente:
39
+ ```bash
40
+ node jerk-admin-client.js
41
+ ```
42
+
43
+ 2. El cliente se conectará automáticamente al servidor de administración en `localhost:9999`
44
+
45
+ 3. Usa los comandos estándar del servidor de administración:
46
+ - `stats` - Ver estadísticas generales
47
+ - `requests` - Ver estadísticas de solicitudes
48
+ - `endpoints` - Ver endpoints más accedidos
49
+ - `routes` - Ver rutas registradas
50
+ - `help` - Ver todos los comandos disponibles
51
+
52
+ 4. Usa los comandos especiales del cliente para mejorar la experiencia:
53
+ - `history` para ver comandos anteriores
54
+ - `re 3` para reutilizar el tercer comando del historial
55
+ - `re stats` para reutilizar el último comando que contenía "stats"
56
+
57
+ ## Atajos
58
+
59
+ - Presiona `↑` y `↓` para navegar por el historial de comandos
60
+ - Presiona `TAB` para autocompletar comandos
61
+ - Presiona `Ctrl+C` para salir del cliente
62
+
63
+ ## Configuración
64
+
65
+ Por defecto, el cliente intenta conectarse a `localhost:9999`. Puedes especificar un host y puerto diferente usando los argumentos `--host` y `--port`.
66
+
67
+ ## Archivo de Historial
68
+
69
+ El cliente guarda el historial de comandos en `~/.jerk_admin_history` para conservarlo entre sesiones.
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@jerkjs/admin-client",
3
+ "version": "1.0.0",
4
+ "description": "Cliente CLI para interactuar con el servidor de administración de JERK Framework",
5
+ "main": "jerk-admin-client.js",
6
+ "bin": {
7
+ "jerk-admin": "./jerk-admin-client.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node jerk-admin-client.js",
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [
14
+ "jerkjs",
15
+ "admin",
16
+ "cli",
17
+ "client",
18
+ "framework"
19
+ ],
20
+ "author": "JERK Framework Team",
21
+ "license": "Apache-2.0",
22
+ "dependencies": {}
23
+ }
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cliente CLI para interactuar con el servidor de administración de JERK Framework
5
+ * Permite reutilizar comandos y tiene autocompletado
6
+ */
7
+
8
+ const net = require('net');
9
+ const readline = require('readline');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ // Configuración por defecto
14
+ const DEFAULT_HOST = 'localhost';
15
+ const DEFAULT_PORT = 9999;
16
+
17
+ // Historial de comandos
18
+ let commandHistory = [];
19
+ const HISTORY_FILE = path.join(require('os').homedir(), '.jerk_admin_history');
20
+
21
+ // Cargar historial de comandos si existe
22
+ if (fs.existsSync(HISTORY_FILE)) {
23
+ try {
24
+ const historyData = fs.readFileSync(HISTORY_FILE, 'utf8');
25
+ commandHistory = JSON.parse(historyData);
26
+ } catch (error) {
27
+ console.error('Error al cargar el historial:', error.message);
28
+ }
29
+ }
30
+
31
+ // Comandos conocidos para autocompletado
32
+ const knownCommands = [
33
+ 'help',
34
+ 'stats',
35
+ 'statistics',
36
+ 'requests',
37
+ 'endpoints',
38
+ 'routes',
39
+ 'active',
40
+ 'version',
41
+ 'status',
42
+ 'cache',
43
+ 'cache-stats',
44
+ 'cache-clear',
45
+ 'cache-info',
46
+ 'sysinfo',
47
+ 'system',
48
+ 'resources',
49
+ 'time',
50
+ 'date',
51
+ 'quit',
52
+ 'exit'
53
+ ];
54
+
55
+ // Función para guardar el historial
56
+ function saveHistory() {
57
+ try {
58
+ fs.writeFileSync(HISTORY_FILE, JSON.stringify(commandHistory, null, 2));
59
+ } catch (error) {
60
+ console.error('Error al guardar el historial:', error.message);
61
+ }
62
+ }
63
+
64
+ // Función para autocompletar comandos
65
+ function completer(line) {
66
+ const hits = knownCommands.filter(cmd => cmd.startsWith(line));
67
+ return [hits.length ? hits : knownCommands, line];
68
+ }
69
+
70
+ // Función para crear el cliente
71
+ function createClient(host = DEFAULT_HOST, port = DEFAULT_PORT) {
72
+ const client = new net.Socket();
73
+
74
+ // Conectar al servidor de administración
75
+ client.connect(port, host, () => {
76
+ console.log(`Conectado al servidor de administración en ${host}:${port}`);
77
+ console.log('Escribe "help" para ver los comandos disponibles o "quit" para salir\n');
78
+
79
+ // Configurar readline con autocompletado
80
+ const rl = readline.createInterface({
81
+ input: process.stdin,
82
+ output: process.stdout,
83
+ completer: completer,
84
+ history: commandHistory
85
+ });
86
+
87
+ // Mostrar historial de comandos recientes
88
+ if (commandHistory.length > 0) {
89
+ console.log(`Comandos recientes: ${commandHistory.slice(-5).join(', ')}\n`);
90
+ }
91
+
92
+ // Función para manejar la entrada del usuario
93
+ function handleInput() {
94
+ rl.question('> ', (input) => {
95
+ const command = input.trim();
96
+
97
+ if (command.toLowerCase() === 'quit' || command.toLowerCase() === 'exit') {
98
+ console.log('Desconectando del servidor...');
99
+ client.end();
100
+ rl.close();
101
+ saveHistory();
102
+ return;
103
+ }
104
+
105
+ if (command.toLowerCase() === 'history') {
106
+ console.log('Historial de comandos:');
107
+ commandHistory.forEach((cmd, index) => {
108
+ console.log(`${index + 1}. ${cmd}`);
109
+ });
110
+ handleInput();
111
+ return;
112
+ }
113
+
114
+ if (command.toLowerCase() === 'clear') {
115
+ console.clear();
116
+ handleInput();
117
+ return;
118
+ }
119
+
120
+ if (command.toLowerCase() === 'help-cli') {
121
+ console.log('\n--- Comandos del Cliente CLI ---');
122
+ console.log('help-cli - Muestra esta ayuda');
123
+ console.log('history - Muestra el historial de comandos');
124
+ console.log('clear - Limpia la pantalla');
125
+ console.log('re <número> - Reutiliza el comando número n del historial');
126
+ console.log('re <texto> - Reutiliza el último comando que contiene el texto');
127
+ console.log('-----------------------------\n');
128
+ handleInput();
129
+ return;
130
+ }
131
+
132
+ // Comando para reutilizar comandos del historial
133
+ if (command.toLowerCase().startsWith('re ')) {
134
+ const arg = command.substring(3).trim();
135
+
136
+ if (/^\d+$/.test(arg)) {
137
+ // Reutilizar por número
138
+ const index = parseInt(arg) - 1;
139
+ if (index >= 0 && index < commandHistory.length) {
140
+ const reusedCmd = commandHistory[index];
141
+ console.log(`Reutilizando comando: ${reusedCmd}`);
142
+ client.write(reusedCmd + '\n');
143
+ if (!commandHistory.includes(reusedCmd)) {
144
+ commandHistory.push(reusedCmd);
145
+ }
146
+ } else {
147
+ console.log(`Número de comando inválido: ${arg}`);
148
+ handleInput();
149
+ }
150
+ } else {
151
+ // Reutilizar por texto
152
+ const matchingCmd = commandHistory.reverse().find(cmd => cmd.includes(arg));
153
+ commandHistory.reverse(); // Restaurar orden original
154
+
155
+ if (matchingCmd) {
156
+ console.log(`Reutilizando comando: ${matchingCmd}`);
157
+ client.write(matchingCmd + '\n');
158
+ } else {
159
+ console.log(`No se encontró comando que contenga: ${arg}`);
160
+ handleInput();
161
+ }
162
+ }
163
+ } else if (command) {
164
+ // Enviar comando al servidor
165
+ client.write(command + '\n');
166
+
167
+ // Agregar al historial si no está repetido
168
+ if (!commandHistory.includes(command)) {
169
+ commandHistory.push(command);
170
+ // Mantener solo los últimos 100 comandos
171
+ if (commandHistory.length > 100) {
172
+ commandHistory = commandHistory.slice(-100);
173
+ }
174
+ }
175
+ }
176
+
177
+ handleInput();
178
+ });
179
+ }
180
+
181
+ // Iniciar la interacción
182
+ handleInput();
183
+ });
184
+
185
+ // Manejar datos recibidos del servidor
186
+ client.on('data', (data) => {
187
+ const output = data.toString();
188
+ process.stdout.write(output);
189
+
190
+ // Si la salida termina con el prompt, significa que el comando terminó
191
+ if (output.endsWith('> ')) {
192
+ // No hacer nada, dejar que readline continúe
193
+ }
194
+ });
195
+
196
+ // Manejar errores
197
+ client.on('error', (error) => {
198
+ console.error(`Error de conexión: ${error.message}`);
199
+ process.exit(1);
200
+ });
201
+
202
+ // Manejar cierre de conexión
203
+ client.on('close', () => {
204
+ console.log('\nConexión cerrada');
205
+ process.exit(0);
206
+ });
207
+ }
208
+
209
+ // Mostrar ayuda
210
+ function showHelp() {
211
+ console.log(`
212
+ Cliente CLI para JERK Framework Administration Server
213
+
214
+ Uso: node jerk-admin-client.js [opciones]
215
+
216
+ Opciones:
217
+ -h, --host HOST Host del servidor (por defecto: ${DEFAULT_HOST})
218
+ -p, --port PORT Puerto del servidor (por defecto: ${DEFAULT_PORT})
219
+ --help Mostrar esta ayuda
220
+
221
+ Comandos especiales del cliente:
222
+ history Mostrar historial de comandos
223
+ clear Limpiar la pantalla
224
+ re <número> Reutilizar comando por número
225
+ re <texto> Reutilizar último comando que contiene texto
226
+ help-cli Mostrar ayuda del cliente
227
+
228
+ Ejemplos:
229
+ node jerk-admin-client.js
230
+ node jerk-admin-client.js --host 127.0.0.1 --port 9999
231
+ `);
232
+ }
233
+
234
+ // Parsear argumentos
235
+ const args = process.argv.slice(2);
236
+ let host = DEFAULT_HOST;
237
+ let port = DEFAULT_PORT;
238
+
239
+ for (let i = 0; i < args.length; i++) {
240
+ if (args[i] === '--help' || args[i] === '-h') {
241
+ showHelp();
242
+ process.exit(0);
243
+ } else if (args[i] === '--host' || args[i] === '-h') {
244
+ host = args[++i];
245
+ } else if (args[i] === '--port' || args[i] === '-p') {
246
+ port = parseInt(args[++i]);
247
+ }
248
+ }
249
+
250
+ // Validar puerto
251
+ if (isNaN(port) || port <= 0 || port > 65535) {
252
+ console.error(`Puerto inválido: ${port}`);
253
+ process.exit(1);
254
+ }
255
+
256
+ // Iniciar el cliente
257
+ createClient(host, port);