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,140 @@
1
+ /**
2
+ * Módulo de Estadísticas para la Extensión de Administración de JERK Framework
3
+ * Módulo personalizado para mostrar estadísticas del servidor
4
+ */
5
+
6
+ class StatsModule {
7
+ /**
8
+ * Constructor del módulo de estadísticas
9
+ * @param {Object} adminExtension - Instancia de la extensión de administración
10
+ */
11
+ constructor(adminExtension) {
12
+ this.adminExtension = adminExtension;
13
+ this.name = 'Statistics Module';
14
+ this.description = 'Módulo para mostrar estadísticas del servidor';
15
+ this.commands = ['stats', 'statistics', 'requests', 'endpoints'];
16
+
17
+ // Cargar el objeto global de estadísticas
18
+ this.globalStats = require('../../utils/globalStats').globalStats;
19
+ }
20
+
21
+ /**
22
+ * Manejador para los comandos del módulo de estadísticas
23
+ * @param {string} command - Comando a ejecutar
24
+ * @param {Object} socket - Socket de la conexión
25
+ */
26
+ handleCommand(command, socket) {
27
+ switch (command) {
28
+ case 'stats':
29
+ case 'statistics':
30
+ this.showGeneralStats(socket);
31
+ break;
32
+ case 'requests':
33
+ this.showRequestStats(socket);
34
+ break;
35
+ case 'endpoints':
36
+ this.showEndpointStats(socket);
37
+ break;
38
+ default:
39
+ socket.write(`Comando desconocido para el módulo de estadísticas: ${command}\n`);
40
+ socket.write(`Comandos disponibles: stats, statistics, requests, endpoints\n\n`);
41
+ socket.write(`> `);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Muestra estadísticas generales
47
+ * @param {Object} socket - Socket de la conexión
48
+ */
49
+ showGeneralStats(socket) {
50
+ const formattedRequestBytes = this.formatBytes(this.globalStats.requestBytes);
51
+ const formattedResponseBytes = this.formatBytes(this.globalStats.responseBytes);
52
+
53
+ socket.write('\n=== Estadísticas Generales ===\n');
54
+ socket.write(`Solicitudes procesadas: ${this.globalStats.requestsProcessed}\n`);
55
+ socket.write(`Solicitudes procesadas (KB): ${formattedRequestBytes}\n`);
56
+ socket.write(`Respuestas enviadas: ${this.globalStats.responsesSent}\n`);
57
+ socket.write(`Respuestas enviadas (KB): ${formattedResponseBytes}\n`);
58
+ socket.write(`Rutas registradas: ${this.adminExtension.registeredRoutes.length}\n`);
59
+ socket.write(`Rutas activas: ${this.adminExtension.activeRoutes.size}\n\n`);
60
+ socket.write(`> `);
61
+ }
62
+
63
+ /**
64
+ * Muestra estadísticas de solicitudes
65
+ * @param {Object} socket - Socket de la conexión
66
+ */
67
+ showRequestStats(socket) {
68
+ socket.write('\n=== Estadísticas de Solicitudes ===\n');
69
+ socket.write(`Total de solicitudes procesadas: ${this.globalStats.requestsProcessed}\n`);
70
+ socket.write(`Total de bytes recibidos: ${this.formatBytes(this.globalStats.requestBytes)}\n`);
71
+
72
+ // Mostrar accesos a rutas
73
+ if (this.globalStats.routeAccesses.size > 0) {
74
+ socket.write('\nAccesos a rutas (Input/Output):\n');
75
+ for (const [route, count] of this.globalStats.routeAccesses) {
76
+ socket.write(` ${route}: ${count} accesos\n`);
77
+ }
78
+ }
79
+
80
+ socket.write('\n> ');
81
+ }
82
+
83
+ /**
84
+ * Muestra estadísticas de endpoints
85
+ * @param {Object} socket - Socket de la conexión
86
+ */
87
+ showEndpointStats(socket) {
88
+ socket.write('\n=== Estadísticas de Endpoints y Rutas ===\n');
89
+
90
+ // Mostrar endpoints más accedidos
91
+ if (this.globalStats.endpointHits.size > 0) {
92
+ socket.write('Endpoints más accedidos:\n');
93
+
94
+ // Convertir el mapa a array y ordenar por número de hits
95
+ const sortedEndpoints = Array.from(this.globalStats.endpointHits.entries())
96
+ .sort((a, b) => b[1] - a[1])
97
+ .slice(0, 10); // Mostrar top 10
98
+
99
+ for (const [endpoint, hits] of sortedEndpoints) {
100
+ socket.write(` ${endpoint}: ${hits} hits\n`);
101
+ }
102
+ } else {
103
+ socket.write('No hay datos de endpoints accedidos.\n');
104
+ }
105
+
106
+ // Mostrar rutas más accedidas
107
+ if (this.globalStats.routeAccesses.size > 0) {
108
+ socket.write('\nRutas más accedidas:\n');
109
+
110
+ // Convertir el mapa a array y ordenar por número de accesos
111
+ const sortedRoutes = Array.from(this.globalStats.routeAccesses.entries())
112
+ .sort((a, b) => b[1] - a[1])
113
+ .slice(0, 10); // Mostrar top 10
114
+
115
+ for (const [route, accesses] of sortedRoutes) {
116
+ socket.write(` ${route}: ${accesses} accesos\n`);
117
+ }
118
+ } else {
119
+ socket.write('\nNo hay datos de rutas accedidas.\n');
120
+ }
121
+
122
+ socket.write('\n> ');
123
+ }
124
+
125
+ /**
126
+ * Formatea bytes a una unidad legible
127
+ * @param {number} bytes - Cantidad en bytes
128
+ * @returns {string} - Cantidad formateada con unidad
129
+ */
130
+ formatBytes(bytes) {
131
+ // Manejar valores nulos o indefinidos
132
+ if (bytes == null || isNaN(bytes) || bytes === 0) return '0 Bytes';
133
+ const k = 1024;
134
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
135
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
136
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
137
+ }
138
+ }
139
+
140
+ module.exports = StatsModule;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Módulo de Sistema para la Extensión de Administración de JERK Framework
3
+ * Módulo personalizado para mostrar información del sistema
4
+ */
5
+
6
+ class SystemModule {
7
+ /**
8
+ * Constructor del módulo de sistema
9
+ * @param {Object} adminExtension - Instancia de la extensión de administración
10
+ */
11
+ constructor(adminExtension) {
12
+ this.adminExtension = adminExtension;
13
+ this.name = 'System Info Module';
14
+ this.description = 'Módulo para mostrar información del sistema';
15
+ this.commands = ['sysinfo', 'system', 'resources'];
16
+ }
17
+
18
+ /**
19
+ * Manejador para los comandos del módulo de sistema
20
+ * @param {string} command - Comando a ejecutar
21
+ * @param {Object} socket - Socket de la conexión
22
+ */
23
+ handleCommand(command, socket) {
24
+ switch (command) {
25
+ case 'sysinfo':
26
+ case 'system':
27
+ case 'resources':
28
+ this.showSystemInfo(socket);
29
+ break;
30
+ default:
31
+ socket.write(`Comando desconocido para el módulo de sistema: ${command}\n`);
32
+ socket.write(`Comandos disponibles: sysinfo, system, resources\n\n`);
33
+ socket.write(`> `);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Muestra información del sistema en formato de tabla con color verde
39
+ * @param {Object} socket - Socket de la conexión
40
+ */
41
+ showSystemInfo(socket) {
42
+ const os = require('os');
43
+ const memUsage = process.memoryUsage();
44
+ const cpuInfo = os.cpus();
45
+ const totalMem = os.totalmem();
46
+ const freeMem = os.freemem();
47
+ const usedMem = totalMem - freeMem;
48
+ const uptime = process.uptime();
49
+
50
+ // Obtener información del proceso
51
+ const pid = process.pid;
52
+ const ppid = process.ppid;
53
+ const execPath = process.execPath;
54
+ const version = process.version;
55
+
56
+ // Calcular uso de CPU (aproximado)
57
+ let totalIdle = 0, totalTick = 0;
58
+ for (const cpu of cpuInfo) {
59
+ for (const type in cpu.times) {
60
+ totalTick += cpu.times[type];
61
+ }
62
+ totalIdle += cpu.times.idle;
63
+ }
64
+ const avgTick = totalTick / cpuInfo.length;
65
+ const avgIdle = totalIdle / cpuInfo.length;
66
+ const cpuUsage = Math.round((1 - avgIdle / avgTick) * 10000) / 100;
67
+
68
+ // Formatear la información en una tabla
69
+ const table = `
70
+ \x1b[32m
71
+ ╔════════════════════════════════════════════════════════════════╗
72
+ ║ INFORMACIÓN DEL SISTEMA ║
73
+ ╠════════════════════════════════════════════════════════════════╣
74
+ ║ Recursos del Sistema ║
75
+ ╠────────────────────────────────────────────────────────────────╣
76
+ ║ Memoria Total: ${this.padRight(this.formatBytes(totalMem), 15)} ║ Memoria Libre: ${this.padRight(this.formatBytes(freeMem), 15)} ║
77
+ ║ Memoria Usada: ${this.padRight(this.formatBytes(usedMem), 15)} ║ Uso de CPU: ${this.padRight(cpuUsage + '%', 15)} ║
78
+ ║ Procesos CPU: ${this.padRight(cpuInfo.length + '', 15)} ║ Uptime Proceso: ${this.padRight(this.formatUptime(uptime), 15)} ║
79
+ ╠════════════════════════════════════════════════════════════════╣
80
+ ║ Información del Proceso ║
81
+ ╠────────────────────────────────────────────────────────────────╣
82
+ ║ PID: ${this.padRight(pid + '', 15)} ║ PPID: ${this.padRight(ppid + '', 15)} ║
83
+ ║ Versión Node: ${this.padRight(version, 15)} ║ Ruta Ejecutable: ${this.padRight(execPath.split('/').pop().substring(0, 15), 15)} ║
84
+ ╠════════════════════════════════════════════════════════════════╣
85
+ ║ Uso de Memoria del Proceso ║
86
+ ╠────────────────────────────────────────────────────────────────╣
87
+ ║ RSS: ${this.padRight(this.formatBytes(memUsage.rss), 15)} ║ Heap Total: ${this.padRight(this.formatBytes(memUsage.heapTotal), 15)} ║
88
+ ║ Heap Usado: ${this.padRight(this.formatBytes(memUsage.heapUsed), 15)} ║ External: ${this.padRight(this.formatBytes(memUsage.external), 15)} ║
89
+ ╚════════════════════════════════════════════════════════════════╝\x1b[0m`;
90
+
91
+ socket.write(table + '\n\n');
92
+ socket.write(`> `);
93
+ }
94
+
95
+ /**
96
+ * Formatea bytes a una unidad legible
97
+ * @param {number} bytes - Cantidad en bytes
98
+ * @returns {string} - Cantidad formateada con unidad
99
+ */
100
+ formatBytes(bytes) {
101
+ if (bytes === 0) return '0 Bytes';
102
+ const k = 1024;
103
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
104
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
105
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
106
+ }
107
+
108
+ /**
109
+ * Formatea el uptime en una cadena legible
110
+ * @param {number} seconds - Segundos de uptime
111
+ * @returns {string} - Uptime formateado
112
+ */
113
+ formatUptime(seconds) {
114
+ const days = Math.floor(seconds / (3600 * 24));
115
+ const hours = Math.floor((seconds % (3600 * 24)) / 3600);
116
+ const minutes = Math.floor((seconds % 3600) / 60);
117
+ const secs = Math.floor(seconds % 60);
118
+
119
+ let result = '';
120
+ if (days > 0) result += `${days}d `;
121
+ if (hours > 0) result += `${hours}h `;
122
+ if (minutes > 0) result += `${minutes}m `;
123
+ result += `${secs}s`;
124
+
125
+ return result.trim();
126
+ }
127
+
128
+ /**
129
+ * Ajusta texto a la derecha con padding
130
+ * @param {string} str - Texto a ajustar
131
+ * @param {number} length - Longitud total
132
+ * @returns {string} - Texto ajustado
133
+ */
134
+ padRight(str, length) {
135
+ str = str + '';
136
+ return str.length < length ? str + ' '.repeat(length - str.length) : str.substring(0, length);
137
+ }
138
+ }
139
+
140
+ module.exports = SystemModule;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Módulo de Tiempo para la Extensión de Administración de JERK Framework
3
+ * Módulo personalizado para mostrar hora y fecha
4
+ */
5
+
6
+ class TimeModule {
7
+ /**
8
+ * Constructor del módulo de tiempo
9
+ * @param {Object} adminExtension - Instancia de la extensión de administración
10
+ */
11
+ constructor(adminExtension) {
12
+ this.adminExtension = adminExtension;
13
+ this.name = 'Time Module';
14
+ this.description = 'Módulo para mostrar hora y fecha';
15
+ this.commands = ['time', 'date'];
16
+ }
17
+
18
+ /**
19
+ * Manejador para los comandos del módulo de tiempo
20
+ * @param {string} command - Comando a ejecutar
21
+ * @param {Object} socket - Socket de la conexión
22
+ */
23
+ handleCommand(command, socket) {
24
+ switch (command) {
25
+ case 'time':
26
+ this.showTime(socket);
27
+ break;
28
+ case 'date':
29
+ this.showDate(socket);
30
+ break;
31
+ default:
32
+ socket.write(`Comando desconocido para el módulo de tiempo: ${command}\n`);
33
+ socket.write(`Comandos disponibles: time, date\n\n`);
34
+ socket.write(`> `);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Muestra la hora actual en color azul
40
+ * @param {Object} socket - Socket de la conexión
41
+ */
42
+ showTime(socket) {
43
+ const currentTime = new Date().toLocaleTimeString('es-ES', {
44
+ hour: '2-digit',
45
+ minute: '2-digit',
46
+ second: '2-digit',
47
+ hour12: false
48
+ });
49
+
50
+ // Enviar con código de color azul ANSI
51
+ socket.write(`\n\x1b[34mHora actual: ${currentTime}\x1b[0m\n\n`);
52
+ socket.write(`> `);
53
+ }
54
+
55
+ /**
56
+ * Muestra la fecha actual en color azul
57
+ * @param {Object} socket - Socket de la conexión
58
+ */
59
+ showDate(socket) {
60
+ const currentDate = new Date().toLocaleDateString('es-ES', {
61
+ weekday: 'long',
62
+ year: 'numeric',
63
+ month: 'long',
64
+ day: 'numeric'
65
+ });
66
+
67
+ // Enviar con código de color azul ANSI
68
+ socket.write(`\n\x1b[34mFecha actual: ${currentDate}\x1b[0m\n\n`);
69
+ socket.write(`> `);
70
+ }
71
+
72
+ /**
73
+ * Muestra la fecha y hora actual en color azul
74
+ * @param {Object} socket - Socket de la conexión
75
+ */
76
+ showDateTime(socket) {
77
+ const now = new Date();
78
+ const dateTime = now.toLocaleString('es-ES', {
79
+ weekday: 'long',
80
+ year: 'numeric',
81
+ month: 'long',
82
+ day: 'numeric',
83
+ hour: '2-digit',
84
+ minute: '2-digit',
85
+ second: '2-digit',
86
+ hour12: false
87
+ });
88
+
89
+ // Enviar con código de color azul ANSI
90
+ socket.write(`\n\x1b[34mFecha y hora actual: ${dateTime}\x1b[0m\n\n`);
91
+ socket.write(`> `);
92
+ }
93
+ }
94
+
95
+ module.exports = TimeModule;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Módulo de Estadísticas del Caché de Vistas para la Extensión de Administración de JERK Framework
3
+ * Módulo personalizado para mostrar estadísticas del caché de vistas
4
+ */
5
+
6
+ class ViewCacheStatsModule {
7
+ /**
8
+ * Constructor del módulo de estadísticas del caché de vistas
9
+ * @param {Object} adminExtension - Instancia de la extensión de administración
10
+ */
11
+ constructor(adminExtension) {
12
+ this.adminExtension = adminExtension;
13
+ this.name = 'View Cache Statistics Module';
14
+ this.description = 'Módulo para mostrar estadísticas del caché de vistas';
15
+ this.commands = ['view-cache'];
16
+
17
+ // Cargar el objeto global de estadísticas del caché de vistas
18
+ this.globalViewCacheInfo = require('../../utils/globalViewCacheInfo').globalViewCacheInfo;
19
+ }
20
+
21
+ /**
22
+ * Manejador para los comandos del módulo de estadísticas del caché de vistas
23
+ * @param {string} command - Comando a ejecutar
24
+ * @param {Object} socket - Socket de la conexión
25
+ */
26
+ handleCommand(command, socket) {
27
+ switch (command) {
28
+ case 'view-cache':
29
+ case 'vcache':
30
+ case 'view-stats':
31
+ this.showViewCacheStats(socket);
32
+ break;
33
+ default:
34
+ socket.write(`Comando desconocido para el módulo de estadísticas del caché de vistas: ${command}\n`);
35
+ socket.write(`Comandos disponibles: view-cache, vcache, view-stats\n\n`);
36
+ socket.write(`> `);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Muestra estadísticas del caché de vistas
42
+ * @param {Object} socket - Socket de la conexión
43
+ */
44
+ showViewCacheStats(socket) {
45
+ const { cacheStats, viewCache, viewDependencies } = this.globalViewCacheInfo;
46
+
47
+ // Codigos de color ANSI
48
+ const RESET = '\x1b[0m';
49
+ const BOLD = '\x1b[1m';
50
+ const GREEN = '\x1b[32m';
51
+ const YELLOW = '\x1b[33m';
52
+ const BLUE = '\x1b[34m';
53
+ const CYAN = '\x1b[36m';
54
+ const MAGENTA = '\x1b[35m';
55
+
56
+ socket.write(`\n${BOLD}${CYAN}=== Estadísticas del Caché de Vistas ===${RESET}\n`);
57
+ socket.write(`${GREEN}Vistas en caché:${RESET} ${viewCache.size}\n`);
58
+ socket.write(`${YELLOW}Hits (accesos exitosos):${RESET} ${cacheStats.hits}\n`);
59
+ socket.write(`${YELLOW}Misses (cargas desde disco):${RESET} ${cacheStats.misses}\n`);
60
+ socket.write(`${GREEN}Total de vistas únicas:${RESET} ${cacheStats.totalViews}\n`);
61
+
62
+ if (cacheStats.hits + cacheStats.misses > 0) {
63
+ const hitRate = (cacheStats.hits / (cacheStats.hits + cacheStats.misses) * 100).toFixed(2);
64
+ socket.write(`${BLUE}Tasa de aciertos:${RESET} ${hitRate}%\n`);
65
+ }
66
+
67
+ // Mostrar vistas más usadas (basado en el tamaño del caché)
68
+ if (viewCache.size > 0) {
69
+ socket.write(`\n${BOLD}${MAGENTA}Vistas en caché:${RESET}\n`);
70
+ for (const [viewPath, content] of viewCache) {
71
+ socket.write(` ${viewPath} (${content.length} chars)\n`);
72
+ }
73
+ }
74
+
75
+ // Mostrar dependencias de vistas
76
+ if (viewDependencies.size > 0) {
77
+ socket.write(`\n${BOLD}${MAGENTA}Dependencias de vistas (inclusiones):${RESET}\n`);
78
+ for (const [viewPath, dependencies] of viewDependencies) {
79
+ if (dependencies.size > 0) {
80
+ socket.write(` ${viewPath}:\n`);
81
+ for (const dependency of dependencies) {
82
+ socket.write(` - ${dependency}\n`);
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ socket.write(`\n${RESET}> `);
89
+ }
90
+ }
91
+
92
+ module.exports = ViewCacheStatsModule;