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,491 @@
1
+ /**
2
+ * Extensión de Administración para JERK Framework
3
+ * Implementación del componente admin/AdminExtension.js
4
+ */
5
+
6
+ const net = require('net');
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ class AdminExtension {
11
+ /**
12
+ * Constructor de la extensión de administración
13
+ * @param {Object} options - Opciones de configuración
14
+ * @param {number} options.port - Puerto para el servidor de administración
15
+ * @param {string} options.host - Host para el servidor de administración
16
+ */
17
+ constructor(options = {}) {
18
+ this.port = options.port || 9999;
19
+ this.host = options.host || '127.0.0.1'; // Solo localhost
20
+ this.server = null;
21
+ this.clients = new Set();
22
+ this.frameworkVersion = this.getFrameworkVersion();
23
+ this.activeRoutes = new Map(); // Para rastrear rutas activas
24
+ this.registeredRoutes = []; // Para almacenar rutas registradas
25
+ this.modules = new Map(); // Para almacenar módulos de administración
26
+ this.hooks = null; // Referencia al sistema de hooks
27
+ }
28
+
29
+ /**
30
+ * Obtiene la versión del framework desde package.json
31
+ * @returns {string} - Versión del framework
32
+ */
33
+ getFrameworkVersion() {
34
+ try {
35
+ const packagePath = path.join(__dirname, '../../package.json');
36
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
37
+ return packageJson.version || 'unknown';
38
+ } catch (error) {
39
+ console.error('Error leyendo la versión del framework:', error.message);
40
+ return 'unknown';
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Inicializa la extensión y el servidor de administración
46
+ * @param {Object} frameworkInstance - Instancia del framework JERK
47
+ */
48
+ initialize(frameworkInstance) {
49
+ this.frameworkInstance = frameworkInstance;
50
+
51
+ // Obtener referencia al sistema de hooks
52
+ if (frameworkInstance && frameworkInstance.hooks) {
53
+ this.hooks = frameworkInstance.hooks;
54
+ } else {
55
+ // Si no se proporciona, crear uno nuevo
56
+ const { hooks } = require('../../index.js');
57
+ this.hooks = hooks;
58
+ }
59
+
60
+ // Registrar hooks para rastrear rutas
61
+ this.registerHooks();
62
+
63
+ // Registrar módulos
64
+ this.registerModules();
65
+
66
+ // Cargar módulos personalizados
67
+ this.loadCustomModules();
68
+
69
+ // Cargar rutas existentes si el servidor ya tiene rutas registradas
70
+ this.loadExistingRoutes();
71
+
72
+ // Iniciar servidor de administración
73
+ this.startAdminServer();
74
+ }
75
+
76
+ /**
77
+ * Carga módulos personalizados
78
+ */
79
+ loadCustomModules() {
80
+ try {
81
+ const ModuleLoader = require('./ModuleLoader');
82
+ const moduleLoader = new ModuleLoader(this);
83
+
84
+ // Cargar módulos desde el directorio de módulos
85
+ moduleLoader.loadModulesFromDirectory('./modules');
86
+ } catch (error) {
87
+ console.error('Error cargando módulos personalizados:', error.message);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Carga las rutas existentes en el servidor
93
+ */
94
+ loadExistingRoutes() {
95
+ if (this.frameworkInstance && this.frameworkInstance.routes) {
96
+ // Copiar las rutas existentes al registro de rutas registradas
97
+ for (const route of this.frameworkInstance.routes) {
98
+ this.registeredRoutes.push({
99
+ method: route.method,
100
+ path: route.path,
101
+ handler: route.handler,
102
+ isStatic: route.isStatic
103
+ });
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Registra los hooks necesarios para rastrear rutas
110
+ */
111
+ registerHooks() {
112
+ if (this.hooks) {
113
+ // Hook para rastrear rutas registradas
114
+ this.hooks.addAction('route_registered', (route) => {
115
+ this.registeredRoutes.push(route);
116
+ });
117
+
118
+ // Hook para rastrear rutas activas
119
+ this.hooks.addAction('request_received', (req, res) => {
120
+ const routeInfo = {
121
+ method: req.method,
122
+ url: req.url,
123
+ timestamp: new Date().toISOString(),
124
+ remoteAddress: req.connection.remoteAddress
125
+ };
126
+
127
+ // Usar la URL como clave y almacenar la última solicitud
128
+ this.activeRoutes.set(req.url, routeInfo);
129
+
130
+ // Disparar hook específico para módulos de administración
131
+ this.hooks.doAction('admin_route_active', routeInfo);
132
+ });
133
+
134
+ // Hook para cuando se cierra el servidor
135
+ this.hooks.addAction('server_stopped', () => {
136
+ this.close();
137
+ });
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Registra los módulos de administración
143
+ */
144
+ registerModules() {
145
+ // Módulo de rutas - el primer módulo
146
+ this.modules.set('routes', {
147
+ name: 'Routes Module',
148
+ description: 'Módulo para ver rutas registradas y activas',
149
+ commands: ['routes', 'active'],
150
+ handler: this.handleRoutesCommand.bind(this)
151
+ });
152
+
153
+ // Módulo de sistema - para comandos generales
154
+ this.modules.set('system', {
155
+ name: 'System Module',
156
+ description: 'Módulo para información del sistema',
157
+ commands: ['version', 'status', 'help'],
158
+ handler: this.handleSystemCommand.bind(this)
159
+ });
160
+
161
+ // Cargar módulos personalizados
162
+ this.loadCustomModules();
163
+ }
164
+
165
+ /**
166
+ * Carga módulos personalizados desde el directorio de módulos
167
+ */
168
+ loadCustomModules() {
169
+ const fs = require('fs');
170
+ const path = require('path');
171
+
172
+ try {
173
+ const modulesDir = path.join(__dirname, 'modules');
174
+
175
+ if (fs.existsSync(modulesDir)) {
176
+ const files = fs.readdirSync(modulesDir);
177
+
178
+ for (const file of files) {
179
+ if (file.endsWith('.js') && file !== 'index.js') {
180
+ try {
181
+ const moduleName = file.replace('.js', '');
182
+
183
+ const ModuleClass = require(path.join(modulesDir, file));
184
+
185
+ if (typeof ModuleClass === 'function') {
186
+ const moduleInstance = new ModuleClass(this);
187
+
188
+ this.modules.set(moduleName.toLowerCase(), {
189
+ name: moduleInstance.name,
190
+ description: moduleInstance.description,
191
+ commands: moduleInstance.commands,
192
+ handler: (command, socket) => moduleInstance.handleCommand(command, socket),
193
+ instance: moduleInstance // Mantener referencia a la instancia para manejo interactivo
194
+ });
195
+
196
+ console.log(`Módulo '${moduleName}' cargado exitosamente.`);
197
+ }
198
+ } catch (moduleError) {
199
+ console.error(`Error cargando módulo ${file}:`, moduleError.message);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ } catch (error) {
205
+ console.error('Error general al cargar módulos personalizados:', error.message);
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Manejador para el módulo de rutas
211
+ */
212
+ handleRoutesCommand(command, socket) {
213
+ switch (command) {
214
+ case 'routes':
215
+ this.sendRegisteredRoutes(socket);
216
+ break;
217
+ case 'active':
218
+ this.sendActiveRoutes(socket);
219
+ break;
220
+ default:
221
+ socket.write(`Comando desconocido para el módulo de rutas: ${command}\n`);
222
+ socket.write(`Comandos disponibles: routes, active\n\n`);
223
+ socket.write(`> `);
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Manejador para el módulo de sistema
229
+ */
230
+ handleSystemCommand(command, socket) {
231
+ switch (command) {
232
+ case 'version':
233
+ socket.write(`\nVersión del framework: ${this.frameworkVersion}\n\n`);
234
+ socket.write(`> `);
235
+ break;
236
+ case 'status':
237
+ socket.write(`\nEstado del servidor:\n`);
238
+ socket.write(`- Puerto del servidor de administración: ${this.port}\n`);
239
+ socket.write(`- Host del servidor de administración: ${this.host}\n`);
240
+
241
+ // Mostrar información del servidor principal si está disponible
242
+ if (this.frameworkInstance) {
243
+ socket.write(`- Puerto del servidor principal: ${this.frameworkInstance.port || 'desconocido'}\n`);
244
+ socket.write(`- Host del servidor principal: ${this.frameworkInstance.host || 'desconocido'}\n`);
245
+ } else {
246
+ socket.write(`- Puerto del servidor principal: desconocido\n`);
247
+ socket.write(`- Host del servidor principal: desconocido\n`);
248
+ }
249
+
250
+ socket.write(`- Clientes conectados: ${this.clients.size}\n`);
251
+ socket.write(`- Rutas registradas: ${this.registeredRoutes.length}\n`);
252
+ socket.write(`- Rutas activas: ${this.activeRoutes.size}\n\n`);
253
+ socket.write(`> `);
254
+ break;
255
+ case 'help':
256
+ this.sendHelp(socket);
257
+ break;
258
+ default:
259
+ socket.write(`Comando desconocido para el módulo de sistema: ${command}\n`);
260
+ socket.write(`Comandos disponibles: version, status, help\n\n`);
261
+ socket.write(`> `);
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Inicia el servidor de administración
267
+ */
268
+ startAdminServer() {
269
+ this.server = net.createServer((socket) => {
270
+ this.clients.add(socket);
271
+
272
+ // Enviar mensaje de bienvenida
273
+ socket.write(`Bienvenido al Servidor de Administración de JERK Framework\n`);
274
+ socket.write(`Versión: ${this.frameworkVersion}\n`);
275
+ socket.write(`Puerto: ${this.port}\n`);
276
+ socket.write(`Fecha: ${new Date().toISOString()}\n\n`);
277
+
278
+ socket.write(`Módulos disponibles:\n`);
279
+ for (const [name, module] of this.modules) {
280
+ socket.write(` ${name}: ${module.description}\n`);
281
+ }
282
+ socket.write(`\n`);
283
+
284
+ socket.write(`Comandos disponibles:\n`);
285
+ for (const [name, module] of this.modules) {
286
+ socket.write(` \x1b[32m${module.commands.join(', ')}\x1b[0m - ${module.description}\n`);
287
+ }
288
+ socket.write(` \x1b[32mhelp, ?\x1b[0m - Mostrar esta ayuda\n`);
289
+ socket.write(` \x1b[32mquit\x1b[0m - Cerrar conexión\n\n`);
290
+
291
+ socket.write(`> `);
292
+
293
+ socket.on('data', (data) => {
294
+ const input = data.toString();
295
+ // Dividir la entrada en líneas y procesar cada una
296
+ const lines = input.split('\n').filter(line => line.trim() !== '');
297
+
298
+ for (const line of lines) {
299
+ // Verificar si hay un proceso interactivo activo para este socket
300
+ const controllerGenModule = this.modules.get('controllergeneratormodule');
301
+ if (controllerGenModule && controllerGenModule.instance && controllerGenModule.instance.currentProcess) {
302
+ const sessionId = controllerGenModule.instance.getSessionId(socket);
303
+ if (controllerGenModule.instance.currentProcess.has(sessionId)) {
304
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
305
+ controllerGenModule.instance.processInput(socket, line.trim());
306
+ continue; // Saltar el procesamiento normal
307
+ }
308
+ }
309
+
310
+ // Verificar si hay un proceso interactivo activo para el módulo de gestión de rutas
311
+ const routeManagerModule = this.modules.get('routemanagermodule');
312
+ if (routeManagerModule && routeManagerModule.instance && routeManagerModule.instance.currentProcess) {
313
+ const sessionId = routeManagerModule.instance.getSessionId(socket);
314
+ if (routeManagerModule.instance.currentProcess.has(sessionId)) {
315
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
316
+ routeManagerModule.instance.processInput(socket, line.trim());
317
+ continue; // Saltar el procesamiento normal
318
+ }
319
+ }
320
+
321
+ // Verificar si hay un proceso interactivo activo para el módulo de WAF
322
+ const wafModule = this.modules.get('wafmodule');
323
+ if (wafModule && wafModule.instance && wafModule.instance.currentProcess) {
324
+ const sessionId = wafModule.instance.getSessionId(socket);
325
+ if (wafModule.instance.currentProcess.has(sessionId)) {
326
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
327
+ wafModule.instance.processInput(socket, line.trim());
328
+ continue; // Saltar el procesamiento normal
329
+ }
330
+ }
331
+
332
+ // Verificar si hay un proceso interactivo activo para el módulo de gestión de colas
333
+ const queueModule = this.modules.get('queuemanagementmodule');
334
+ if (queueModule && queueModule.instance && queueModule.instance.inputState &&
335
+ queueModule.instance.inputState.has(socket)) {
336
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
337
+ queueModule.instance.processQueueAction(socket, queueModule.instance.inputState.get(socket).action, line.trim());
338
+ continue; // Saltar el procesamiento normal
339
+ }
340
+
341
+ const command = line.trim().toLowerCase();
342
+ console.log(`DEBUG: Comando recibido: "${command}"`); // Mensaje de depuración
343
+
344
+ // Verificar si es un comando de sistema
345
+ if (['help', 'quit', 'exit', '?'].includes(command)) {
346
+ console.log(`DEBUG: Comando de sistema encontrado: ${command}`); // Mensaje de depuración
347
+ switch (command) {
348
+ case 'help':
349
+ case '?':
350
+ this.sendHelp(socket);
351
+ break;
352
+ case 'quit':
353
+ case 'exit':
354
+ socket.write('Cerrando conexión...\n');
355
+ socket.end();
356
+ return;
357
+ default:
358
+ socket.write(`> `);
359
+ }
360
+ continue; // Continuar con la siguiente línea
361
+ }
362
+
363
+ // Buscar el módulo que maneje este comando
364
+ let handled = false;
365
+ console.log(`DEBUG: Buscando módulo para el comando "${command}"`); // Mensaje de depuración
366
+ console.log(`DEBUG: Módulos disponibles:`, Array.from(this.modules.keys())); // Mensaje de depuración
367
+
368
+ for (const [moduleName, module] of this.modules) {
369
+ console.log(`DEBUG: Revisando módulo "${moduleName}", comandos:`, module.commands); // Mensaje de depuración
370
+ if (module.commands.includes(command)) {
371
+ console.log(`DEBUG: Módulo encontrado para el comando "${command}", llamando handler`); // Mensaje de depuración
372
+ module.handler(command, socket);
373
+ handled = true;
374
+ break;
375
+ }
376
+ }
377
+
378
+ if (!handled) {
379
+ console.log(`DEBUG: Comando no encontrado: "${command}"`); // Mensaje de depuración
380
+ socket.write(`Comando desconocido: ${command}\n`);
381
+ socket.write(`Escribe 'help' para ver los comandos disponibles.\n\n`);
382
+ socket.write(`> `);
383
+ }
384
+ }
385
+ });
386
+
387
+ socket.on('close', () => {
388
+ this.clients.delete(socket);
389
+ });
390
+
391
+ socket.on('error', (err) => {
392
+ console.error('Error en el socket de administración:', err);
393
+ });
394
+ });
395
+
396
+ this.server.listen(this.port, this.host, () => {
397
+ console.log(`Servidor de administración JERK iniciado en ${this.host}:${this.port}`);
398
+ console.log(`Versión del framework: ${this.frameworkVersion}`);
399
+
400
+ // Disparar hook cuando se inicia el servidor de administración
401
+ if (this.hooks) {
402
+ this.hooks.doAction('admin_server_started', this.port, this.host);
403
+ }
404
+ });
405
+
406
+ this.server.on('error', (err) => {
407
+ console.error('Error en el servidor de administración:', err);
408
+
409
+ // Disparar hook cuando hay un error en el servidor de administración
410
+ if (this.hooks) {
411
+ this.hooks.doAction('admin_server_error', err);
412
+ }
413
+ });
414
+ }
415
+
416
+ /**
417
+ * Envía la lista de rutas registradas al cliente
418
+ * @param {Object} socket - Socket del cliente
419
+ */
420
+ sendRegisteredRoutes(socket) {
421
+ socket.write('\n=== Rutas Registradas ===\n');
422
+
423
+ if (this.registeredRoutes.length === 0) {
424
+ socket.write('No hay rutas registradas.\n');
425
+ } else {
426
+ this.registeredRoutes.forEach((route, index) => {
427
+ socket.write(`${index + 1}. ${route.method} ${route.path}\n`);
428
+ });
429
+ }
430
+
431
+ socket.write('\n> ');
432
+ }
433
+
434
+ /**
435
+ * Envía la lista de rutas activas al cliente
436
+ * @param {Object} socket - Socket del cliente
437
+ */
438
+ sendActiveRoutes(socket) {
439
+ socket.write('\n=== Rutas Activas (Últimas Solicitudes) ===\n');
440
+
441
+ if (this.activeRoutes.size === 0) {
442
+ socket.write('No hay rutas activas registradas.\n');
443
+ } else {
444
+ for (const [url, info] of this.activeRoutes) {
445
+ socket.write(`${info.method} ${url} - ${info.timestamp} (${info.remoteAddress})\n`);
446
+ }
447
+ }
448
+
449
+ socket.write('\n> ');
450
+ }
451
+
452
+ /**
453
+ * Envía la ayuda al cliente
454
+ * @param {Object} socket - Socket del cliente
455
+ */
456
+ sendHelp(socket) {
457
+ socket.write('\n=== Ayuda del Servidor de Administración ===\n');
458
+ socket.write(`Módulos disponibles:\n`);
459
+ for (const [name, module] of this.modules) {
460
+ socket.write(` ${name}: ${module.description}\n`);
461
+ socket.write(` Comandos: \x1b[32m${module.commands.join(', ')}\x1b[0m\n`);
462
+ }
463
+ socket.write(`\nComandos generales:\n`);
464
+ socket.write(` \x1b[32mhelp, ?\x1b[0m - Mostrar esta ayuda\n`);
465
+ socket.write(` \x1b[32mquit\x1b[0m - Cerrar conexión\n\n`);
466
+ socket.write(`> `);
467
+ }
468
+
469
+ /**
470
+ * Cierra el servidor de administración
471
+ */
472
+ close() {
473
+ if (this.server) {
474
+ // Cerrar todas las conexiones de clientes
475
+ for (const client of this.clients) {
476
+ client.end();
477
+ }
478
+
479
+ this.server.close(() => {
480
+ console.log('Servidor de administración cerrado');
481
+
482
+ // Disparar hook cuando se cierra el servidor de administración
483
+ if (this.hooks) {
484
+ this.hooks.doAction('admin_server_closed');
485
+ }
486
+ });
487
+ }
488
+ }
489
+ }
490
+
491
+ module.exports = AdminExtension;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Sistema de Carga de Módulos Personalizados para la Extensión de Administración
3
+ * Permite cargar módulos externos como submódulos de la extensión
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ class ModuleLoader {
10
+ /**
11
+ * Constructor del cargador de módulos
12
+ * @param {Object} adminExtension - Instancia de la extensión de administración
13
+ */
14
+ constructor(adminExtension) {
15
+ this.adminExtension = adminExtension;
16
+ this.modules = new Map();
17
+ }
18
+
19
+ /**
20
+ * Carga un módulo personalizado
21
+ * @param {string} moduleName - Nombre del módulo
22
+ * @param {Object} moduleClass - Clase del módulo
23
+ */
24
+ loadModule(moduleName, moduleClass) {
25
+ const moduleInstance = new moduleClass(this.adminExtension);
26
+ this.modules.set(moduleName, moduleInstance);
27
+
28
+ // Registrar el módulo en la extensión de administración
29
+ this.adminExtension.modules.set(moduleName, {
30
+ name: moduleInstance.name,
31
+ description: moduleInstance.description,
32
+ commands: moduleInstance.commands,
33
+ handler: moduleInstance.handleCommand.bind(moduleInstance)
34
+ });
35
+
36
+ console.log(`Módulo '${moduleName}' cargado exitosamente.`);
37
+ }
38
+
39
+ /**
40
+ * Carga módulos desde un directorio
41
+ * @param {string} directoryPath - Ruta del directorio de módulos
42
+ */
43
+ loadModulesFromDirectory(directoryPath) {
44
+ const modulesDir = path.resolve(__dirname, directoryPath);
45
+
46
+ if (!fs.existsSync(modulesDir)) {
47
+ console.log(`Directorio de módulos no encontrado: ${modulesDir}`);
48
+ return;
49
+ }
50
+
51
+ const files = fs.readdirSync(modulesDir);
52
+
53
+ for (const file of files) {
54
+ if (file.endsWith('.js') && file !== 'index.js') {
55
+ const moduleName = file.replace('.js', '');
56
+ const modulePath = path.join(modulesDir, file);
57
+
58
+ try {
59
+ const ModuleClass = require(modulePath);
60
+ this.loadModule(moduleName.toLowerCase(), ModuleClass);
61
+ } catch (error) {
62
+ console.error(`Error cargando módulo ${file}:`, error.message);
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Obtiene todos los módulos cargados
70
+ * @returns {Map} - Mapa de módulos cargados
71
+ */
72
+ getLoadedModules() {
73
+ return this.modules;
74
+ }
75
+ }
76
+
77
+ module.exports = ModuleLoader;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Configuración de la extensión de administración para JERK Framework
3
+ */
4
+
5
+ module.exports = {
6
+ adminExtension: {
7
+ enabled: true,
8
+ port: 9999,
9
+ host: '127.0.0.1', // Solo localhost
10
+ modules: {
11
+ routes: {
12
+ enabled: true,
13
+ options: {}
14
+ },
15
+ system: {
16
+ enabled: true,
17
+ options: {}
18
+ }
19
+ }
20
+ }
21
+ };