jerkjs 2.5.4 → 2.5.8
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.
- package/BENCHMARK_RESULTS.md +60 -0
- package/CHANGELOG.md +43 -0
- package/ESTADISTICAS_RENDIMIENTO.md +106 -0
- package/README.md +142 -423
- package/README_LEGACY.md +513 -0
- package/debug_hook.js +11 -0
- package/doc-2.5/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
- package/doc-2.5/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
- package/doc-2.5/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
- package/doc-2.5/CACHE_SYSTEM_MAP.md +206 -0
- package/doc-2.5/SESSION_SECURITY_FLAGS.md +174 -0
- package/doc-2.5/an/303/241lisis-completo-jerk-framework.md +213 -0
- package/docs/CACHE_SYSTEM_MAP.md +206 -0
- package/docs/SERVER_OPTIMIZATION_NOTES.md +87 -0
- package/index.js +7 -1
- package/jerk2.5.webp +0 -0
- package/lib/admin/AdminExtension.js +436 -0
- package/lib/admin/ModuleLoader.js +77 -0
- package/lib/admin/config.js +21 -0
- package/lib/admin/modules/CacheModule.js +145 -0
- package/lib/admin/modules/STATS_MODULE_README.md +98 -0
- package/lib/admin/modules/StatsModule.js +140 -0
- package/lib/admin/modules/SystemModule.js +140 -0
- package/lib/admin/modules/TimeModule.js +95 -0
- package/lib/cache/CacheHooks.js +141 -0
- package/lib/core/server.js +199 -46
- package/lib/middleware/session.js +11 -3
- package/lib/mvc/viewEngine.js +26 -1
- package/lib/router/RouteMatcher.js +242 -54
- package/lib/utils/globalStats.js +16 -0
- package/package.json +2 -2
- package/@qaLoadModel/controllers/ProductController.js +0 -143
- package/@qaLoadModel/controllers/UserController.js +0 -143
- package/@qaLoadModel/models/ProductModel.js +0 -41
- package/@qaLoadModel/models/UserModel.js +0 -41
- package/@qaLoadModel/package.json +0 -22
- package/@qaLoadModel/qa_report.md +0 -71
- package/@qaLoadModel/results.md +0 -97
- package/@qaLoadModel/routes.json +0 -58
- package/@qaLoadModel/server.js +0 -43
- package/@qaLoadModel/simple-test.js +0 -96
- package/@qaLoadModel/test-models.js +0 -144
- package/@qaLoadModel/test_endpoints.sh +0 -35
- package/@qaLoadModel/test_final.js +0 -89
- package/@qaLoadModel/views/products/index.html +0 -45
- package/@qaLoadModel/views/products/show.html +0 -27
- package/@qaLoadModel/views/users/index.html +0 -44
- package/@qaLoadModel/views/users/show.html +0 -26
- package/qa/INFORME_QA_JERKJS_ROUTING.md +0 -108
- package/qa/informe_qa_fix_enrutamiento.md +0 -93
- package/qa-app/controllers/homeController.js +0 -9
- package/qa-app/controllers/userController.js +0 -76
- package/qa-app/hooks-config.js +0 -65
- package/qa-app/models/UserModel.js +0 -36
- package/qa-app/package-lock.json +0 -1683
- package/qa-app/package.json +0 -25
- package/qa-app/public/css/style.css +0 -15
- package/qa-app/public/images/logo.png +0 -3
- package/qa-app/public/index.html +0 -15
- package/qa-app/public/js/main.js +0 -7
- package/qa-app/routes/api-routes.json +0 -23
- package/qa-app/routes/page-routes.json +0 -16
- package/qa-app/routes/static-routes.json +0 -20
- package/qa-app/server.js +0 -68
- package/qa-app/views/footer.html +0 -3
- package/qa-app/views/index.html +0 -20
- package/qa-app/views/users.html +0 -20
- package/utils/find_file_path.sh +0 -36
- /package/{doc2.5.3 → doc-2.5}/manual-mvc-completo.md +0 -0
package/lib/core/server.js
CHANGED
|
@@ -6,13 +6,24 @@
|
|
|
6
6
|
|
|
7
7
|
const http = require('http');
|
|
8
8
|
const https = require('https');
|
|
9
|
-
const
|
|
9
|
+
const urlModule = require('url'); // Renombrado para evitar conflicto con variable local
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const { Logger } = require('../utils/logger');
|
|
13
13
|
const { ErrorHandler } = require('../utils/errorHandler');
|
|
14
14
|
const { getMimeType } = require('../utils/mimeType');
|
|
15
15
|
const RouteMatcher = require('../router/RouteMatcher');
|
|
16
|
+
const AdminExtension = require('../admin/AdminExtension');
|
|
17
|
+
const { globalStats } = require('../utils/globalStats');
|
|
18
|
+
|
|
19
|
+
// Carga anticipada de módulos comunes para evitar cargas repetidas
|
|
20
|
+
let hooksInstance = null;
|
|
21
|
+
const getHooks = () => {
|
|
22
|
+
if (!hooksInstance) {
|
|
23
|
+
hooksInstance = require('../../index.js').hooks;
|
|
24
|
+
}
|
|
25
|
+
return hooksInstance;
|
|
26
|
+
};
|
|
16
27
|
|
|
17
28
|
class APIServer {
|
|
18
29
|
/**
|
|
@@ -50,6 +61,42 @@ class APIServer {
|
|
|
50
61
|
|
|
51
62
|
// Inicializar el componente de enrutamiento
|
|
52
63
|
this.routeMatcher = new RouteMatcher();
|
|
64
|
+
|
|
65
|
+
// Inicializar la extensión de administración
|
|
66
|
+
this.adminExtension = null;
|
|
67
|
+
|
|
68
|
+
// Inicializar el sistema de hooks si no existe
|
|
69
|
+
if (!options.hooks) {
|
|
70
|
+
const { hooks } = require('../../index.js'); // Ruta corregida
|
|
71
|
+
this.hooks = hooks;
|
|
72
|
+
} else {
|
|
73
|
+
this.hooks = options.hooks;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Conectar el sistema de hooks al routeMatcher
|
|
77
|
+
this.routeMatcher.hooks = this.hooks;
|
|
78
|
+
|
|
79
|
+
// Propiedad para almacenar el viewEngine
|
|
80
|
+
this._viewEngine = null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Setter para el viewEngine que también conecta los hooks
|
|
85
|
+
*/
|
|
86
|
+
set viewEngine(engine) {
|
|
87
|
+
this._viewEngine = engine;
|
|
88
|
+
|
|
89
|
+
// Conectar el sistema de hooks al viewEngine si está disponible
|
|
90
|
+
if (this._viewEngine && this.hooks) {
|
|
91
|
+
this._viewEngine.hooks = this.hooks;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Getter para el viewEngine
|
|
97
|
+
*/
|
|
98
|
+
get viewEngine() {
|
|
99
|
+
return this._viewEngine;
|
|
53
100
|
}
|
|
54
101
|
|
|
55
102
|
/**
|
|
@@ -59,10 +106,15 @@ class APIServer {
|
|
|
59
106
|
* @returns {Function} - Handler para servir archivos estáticos
|
|
60
107
|
*/
|
|
61
108
|
createStaticFileHandler(staticConfig, routePath) {
|
|
109
|
+
// Pre-calcular valores comunes para evitar cálculos repetidos
|
|
110
|
+
const baseDir = path.isAbsolute(staticConfig.dir)
|
|
111
|
+
? staticConfig.dir
|
|
112
|
+
: path.resolve(process.cwd(), staticConfig.dir);
|
|
113
|
+
|
|
62
114
|
return async (req, res) => {
|
|
63
115
|
try {
|
|
64
116
|
// Disparar hook antes de procesar archivo estático
|
|
65
|
-
const hooks =
|
|
117
|
+
const hooks = getHooks();
|
|
66
118
|
if (hooks) {
|
|
67
119
|
const hookResult = hooks.applyFilters('pre_static_file_serve', {
|
|
68
120
|
req,
|
|
@@ -83,16 +135,16 @@ class APIServer {
|
|
|
83
135
|
// Extraer la subruta de la solicitud
|
|
84
136
|
// Si la ruta base es /static y la solicitud es /static/assets/hola.js
|
|
85
137
|
// entonces la subruta sería assets/hola.js
|
|
86
|
-
const parsedUrl =
|
|
138
|
+
const parsedUrl = urlModule.parse(req.url, true);
|
|
87
139
|
const pathname = parsedUrl.pathname;
|
|
88
|
-
|
|
140
|
+
|
|
89
141
|
// Extraer la subruta usando la ruta base conocida para esta ruta estática
|
|
90
142
|
let requestedPath = pathname.substring(routePath.length);
|
|
91
143
|
if (requestedPath.startsWith('/')) {
|
|
92
144
|
requestedPath = requestedPath.substring(1);
|
|
93
145
|
}
|
|
94
146
|
|
|
95
|
-
// Prevenir path traversal
|
|
147
|
+
// Prevenir path traversal - optimizado para evitar operaciones redundantes
|
|
96
148
|
const normalizedPath = path.normalize(requestedPath);
|
|
97
149
|
if (normalizedPath.includes('..')) {
|
|
98
150
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
@@ -104,12 +156,6 @@ class APIServer {
|
|
|
104
156
|
return;
|
|
105
157
|
}
|
|
106
158
|
|
|
107
|
-
// Asegurarse de que el directorio base sea absoluto
|
|
108
|
-
let baseDir = staticConfig.dir;
|
|
109
|
-
if (!path.isAbsolute(baseDir)) {
|
|
110
|
-
baseDir = path.resolve(process.cwd(), baseDir);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
159
|
// Construir la ruta física
|
|
114
160
|
const physicalPath = path.join(baseDir, normalizedPath);
|
|
115
161
|
|
|
@@ -262,7 +308,7 @@ class APIServer {
|
|
|
262
308
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
263
309
|
res.end(JSON.stringify({ error: 'Archivo no encontrado', path: error.path }));
|
|
264
310
|
|
|
265
|
-
const hooks =
|
|
311
|
+
const hooks = getHooks();
|
|
266
312
|
if (hooks) {
|
|
267
313
|
hooks.doAction('static_file_not_found', error.path, req, res);
|
|
268
314
|
}
|
|
@@ -270,7 +316,7 @@ class APIServer {
|
|
|
270
316
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
271
317
|
res.end(JSON.stringify({ error: 'Acceso denegado', path: error.path }));
|
|
272
318
|
|
|
273
|
-
const hooks =
|
|
319
|
+
const hooks = getHooks();
|
|
274
320
|
if (hooks) {
|
|
275
321
|
hooks.doAction('static_file_access_denied', error.path, req, res);
|
|
276
322
|
}
|
|
@@ -279,7 +325,7 @@ class APIServer {
|
|
|
279
325
|
const { ErrorHandler } = require('../utils/errorHandler');
|
|
280
326
|
ErrorHandler.handle(error, req, res, this.logger);
|
|
281
327
|
|
|
282
|
-
const hooks =
|
|
328
|
+
const hooks = getHooks();
|
|
283
329
|
if (hooks) {
|
|
284
330
|
hooks.doAction('static_file_error', error, req, res);
|
|
285
331
|
}
|
|
@@ -345,12 +391,18 @@ class APIServer {
|
|
|
345
391
|
// Crear handler para archivos estáticos
|
|
346
392
|
const staticHandler = this.createStaticFileHandler(routeConfig.static, routeConfig.path);
|
|
347
393
|
|
|
348
|
-
|
|
394
|
+
const route = {
|
|
349
395
|
method: routeConfig.method.toUpperCase(),
|
|
350
396
|
path: routeConfig.path,
|
|
351
397
|
handler: staticHandler,
|
|
352
398
|
isStatic: true // Marcar como ruta estática para posible procesamiento especial
|
|
353
|
-
}
|
|
399
|
+
};
|
|
400
|
+
this.routes.push(route);
|
|
401
|
+
|
|
402
|
+
// Disparar hook cuando se registra una ruta
|
|
403
|
+
if (this.hooks) {
|
|
404
|
+
this.hooks.doAction('route_registered', route);
|
|
405
|
+
}
|
|
354
406
|
|
|
355
407
|
return; // Salir después de procesar ruta estática
|
|
356
408
|
}
|
|
@@ -429,11 +481,17 @@ class APIServer {
|
|
|
429
481
|
};
|
|
430
482
|
|
|
431
483
|
// Agregar la ruta con el handler autenticado
|
|
432
|
-
|
|
484
|
+
const route = {
|
|
433
485
|
method: routeConfig.method.toUpperCase(),
|
|
434
486
|
path: routeConfig.path,
|
|
435
487
|
handler: authenticatedHandler
|
|
436
|
-
}
|
|
488
|
+
};
|
|
489
|
+
this.routes.push(route);
|
|
490
|
+
|
|
491
|
+
// Disparar hook cuando se registra una ruta
|
|
492
|
+
if (this.hooks) {
|
|
493
|
+
this.hooks.doAction('route_registered', route);
|
|
494
|
+
}
|
|
437
495
|
} else {
|
|
438
496
|
// Si no hay sessionManager en el servidor, agregar la ruta normalmente
|
|
439
497
|
this.routes.push({
|
|
@@ -480,27 +538,45 @@ class APIServer {
|
|
|
480
538
|
};
|
|
481
539
|
|
|
482
540
|
// Agregar la ruta con el handler autenticado
|
|
483
|
-
|
|
541
|
+
const route = {
|
|
484
542
|
method: routeConfig.method.toUpperCase(),
|
|
485
543
|
path: routeConfig.path,
|
|
486
544
|
handler: authenticatedHandler
|
|
487
|
-
}
|
|
545
|
+
};
|
|
546
|
+
this.routes.push(route);
|
|
547
|
+
|
|
548
|
+
// Disparar hook cuando se registra una ruta
|
|
549
|
+
if (this.hooks) {
|
|
550
|
+
this.hooks.doAction('route_registered', route);
|
|
551
|
+
}
|
|
488
552
|
} else {
|
|
489
553
|
// Si no hay authenticator en el servidor, agregar la ruta normalmente
|
|
490
|
-
|
|
554
|
+
const route = {
|
|
491
555
|
method: routeConfig.method.toUpperCase(),
|
|
492
556
|
path: routeConfig.path,
|
|
493
557
|
handler: finalHandler
|
|
494
|
-
}
|
|
558
|
+
};
|
|
559
|
+
this.routes.push(route);
|
|
560
|
+
|
|
561
|
+
// Disparar hook cuando se registra una ruta
|
|
562
|
+
if (this.hooks) {
|
|
563
|
+
this.hooks.doAction('route_registered', route);
|
|
564
|
+
}
|
|
495
565
|
}
|
|
496
566
|
}
|
|
497
567
|
} else {
|
|
498
568
|
// Si no hay autenticación requerida, agregar la ruta normalmente
|
|
499
|
-
|
|
569
|
+
const route = {
|
|
500
570
|
method: routeConfig.method.toUpperCase(),
|
|
501
571
|
path: routeConfig.path,
|
|
502
572
|
handler: finalHandler
|
|
503
|
-
}
|
|
573
|
+
};
|
|
574
|
+
this.routes.push(route);
|
|
575
|
+
|
|
576
|
+
// Disparar hook cuando se registra una ruta
|
|
577
|
+
if (this.hooks) {
|
|
578
|
+
this.hooks.doAction('route_registered', route);
|
|
579
|
+
}
|
|
504
580
|
}
|
|
505
581
|
}
|
|
506
582
|
|
|
@@ -527,7 +603,7 @@ class APIServer {
|
|
|
527
603
|
*/
|
|
528
604
|
start() {
|
|
529
605
|
// Disparar hook antes de iniciar el servidor
|
|
530
|
-
const hooks =
|
|
606
|
+
const hooks = getHooks();
|
|
531
607
|
if (hooks) {
|
|
532
608
|
hooks.doAction('pre_server_start', this);
|
|
533
609
|
}
|
|
@@ -571,12 +647,28 @@ class APIServer {
|
|
|
571
647
|
// Disparar hook después de iniciar el servidor
|
|
572
648
|
if (hooks) {
|
|
573
649
|
hooks.doAction('post_server_start', this);
|
|
650
|
+
|
|
651
|
+
// Disparar hook para inicializar extensiones después de que el servidor esté completamente iniciado
|
|
652
|
+
hooks.doAction('admin_extensions_initialize', this);
|
|
574
653
|
}
|
|
575
654
|
});
|
|
576
655
|
|
|
577
656
|
return this.server;
|
|
578
657
|
}
|
|
579
658
|
|
|
659
|
+
/**
|
|
660
|
+
* Inicializa la extensión de administración
|
|
661
|
+
* @param {Object} options - Opciones para la extensión de administración
|
|
662
|
+
*/
|
|
663
|
+
initializeAdminExtension(options = {}) {
|
|
664
|
+
if (!this.adminExtension) {
|
|
665
|
+
this.adminExtension = new AdminExtension(options);
|
|
666
|
+
this.adminExtension.initialize(this);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return this.adminExtension;
|
|
670
|
+
}
|
|
671
|
+
|
|
580
672
|
/**
|
|
581
673
|
* Detiene el servidor
|
|
582
674
|
*/
|
|
@@ -586,6 +678,11 @@ class APIServer {
|
|
|
586
678
|
this.logger.info('Servidor detenido');
|
|
587
679
|
});
|
|
588
680
|
}
|
|
681
|
+
|
|
682
|
+
// Cerrar la extensión de administración si está activa
|
|
683
|
+
if (this.adminExtension) {
|
|
684
|
+
this.adminExtension.close();
|
|
685
|
+
}
|
|
589
686
|
}
|
|
590
687
|
|
|
591
688
|
/**
|
|
@@ -594,11 +691,11 @@ class APIServer {
|
|
|
594
691
|
* @param {Object} res - Objeto de respuesta HTTP
|
|
595
692
|
*/
|
|
596
693
|
async handleRequest(req, res) {
|
|
597
|
-
const parsedUrl =
|
|
694
|
+
const parsedUrl = urlModule.parse(req.url, true);
|
|
598
695
|
const { pathname, query } = parsedUrl;
|
|
599
696
|
|
|
600
697
|
// Disparar hook antes de procesar la solicitud
|
|
601
|
-
const hooks =
|
|
698
|
+
const hooks = getHooks();
|
|
602
699
|
if (hooks) {
|
|
603
700
|
hooks.doAction('request_received', req, res);
|
|
604
701
|
}
|
|
@@ -635,6 +732,9 @@ class APIServer {
|
|
|
635
732
|
// Concatenar todos los chunks una sola vez
|
|
636
733
|
req.body = Buffer.concat(bodyChunks).toString();
|
|
637
734
|
|
|
735
|
+
// Actualizar estadísticas globales de bytes recibidos
|
|
736
|
+
globalStats.requestBytes += bodySize;
|
|
737
|
+
|
|
638
738
|
// Parsear body si es JSON
|
|
639
739
|
if (req.headers['content-type'] && req.headers['content-type'].includes('application/json')) {
|
|
640
740
|
try {
|
|
@@ -650,25 +750,29 @@ class APIServer {
|
|
|
650
750
|
|
|
651
751
|
// Agregar el método render a la respuesta si hay un viewEngine configurado
|
|
652
752
|
if (this.viewEngine) {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
753
|
+
// Definir render solo una vez si no existe
|
|
754
|
+
if (!res._renderDefined) {
|
|
755
|
+
res.render = (viewName, data = {}) => {
|
|
756
|
+
try {
|
|
757
|
+
const renderedHtml = this.viewEngine.render(viewName, data);
|
|
758
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
759
|
+
res.end(renderedHtml);
|
|
658
760
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
761
|
+
if (hooks) {
|
|
762
|
+
hooks.doAction('view_rendered', viewName, data, req, res);
|
|
763
|
+
}
|
|
764
|
+
} catch (error) {
|
|
765
|
+
// Usar el ErrorHandler para mostrar el stacktrace en color amarillo
|
|
766
|
+
const { ErrorHandler } = require('../utils/errorHandler');
|
|
767
|
+
ErrorHandler.handle(error, req, res, this.logger);
|
|
666
768
|
|
|
667
|
-
|
|
668
|
-
|
|
769
|
+
if (hooks) {
|
|
770
|
+
hooks.doAction('view_render_error', viewName, data, req, res, error);
|
|
771
|
+
}
|
|
669
772
|
}
|
|
670
|
-
}
|
|
671
|
-
|
|
773
|
+
};
|
|
774
|
+
res._renderDefined = true;
|
|
775
|
+
}
|
|
672
776
|
}
|
|
673
777
|
|
|
674
778
|
// Hacer que el modelManager esté disponible en la solicitud si está configurado
|
|
@@ -790,21 +894,70 @@ class APIServer {
|
|
|
790
894
|
}
|
|
791
895
|
}
|
|
792
896
|
|
|
897
|
+
// Capturar el tamaño de la respuesta antes de enviarla
|
|
898
|
+
const originalWrite = res.write;
|
|
899
|
+
const originalEnd = res.end;
|
|
900
|
+
let responseData = [];
|
|
901
|
+
|
|
902
|
+
res.write = function(chunk) {
|
|
903
|
+
if (chunk) {
|
|
904
|
+
responseData.push(Buffer.from(chunk));
|
|
905
|
+
}
|
|
906
|
+
return originalWrite.apply(this, arguments);
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
res.end = function(chunk) {
|
|
910
|
+
if (chunk) {
|
|
911
|
+
responseData.push(Buffer.from(chunk));
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Almacenar los datos de la respuesta para estadísticas
|
|
915
|
+
res._data = Buffer.concat(responseData);
|
|
916
|
+
|
|
917
|
+
// Actualizar estadísticas globales de bytes enviados
|
|
918
|
+
if (res._data) {
|
|
919
|
+
const responseSize = Buffer.byteLength(res._data, 'utf8');
|
|
920
|
+
globalStats.responseBytes += responseSize;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
return originalEnd.apply(this, arguments);
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
// Actualizar estadísticas globales de solicitudes procesadas
|
|
927
|
+
globalStats.requestsProcessed++;
|
|
928
|
+
|
|
793
929
|
// Ejecutar handler de la ruta
|
|
794
930
|
await matchedRoute.route.handler(req, res);
|
|
795
931
|
|
|
932
|
+
// Actualizar estadísticas globales de respuestas enviadas
|
|
933
|
+
globalStats.responsesSent++;
|
|
934
|
+
|
|
935
|
+
// Registrar acceso a ruta
|
|
936
|
+
if (req.originalUrl) {
|
|
937
|
+
const routeKey = `${req.method} ${req.originalUrl}`;
|
|
938
|
+
if (!globalStats.routeAccesses.has(routeKey)) {
|
|
939
|
+
globalStats.routeAccesses.set(routeKey, 0);
|
|
940
|
+
}
|
|
941
|
+
globalStats.routeAccesses.set(routeKey, globalStats.routeAccesses.get(routeKey) + 1);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Registrar hit al endpoint
|
|
945
|
+
const endpointKey = `${req.method} ${matchedRoute.route.path}`;
|
|
946
|
+
if (!globalStats.endpointHits.has(endpointKey)) {
|
|
947
|
+
globalStats.endpointHits.set(endpointKey, 0);
|
|
948
|
+
}
|
|
949
|
+
globalStats.endpointHits.set(endpointKey, globalStats.endpointHits.get(endpointKey) + 1);
|
|
950
|
+
|
|
796
951
|
if (hooks) {
|
|
797
952
|
hooks.doAction('route_handler_executed', matchedRoute, req, res);
|
|
798
953
|
}
|
|
799
954
|
} else {
|
|
800
955
|
// Ruta no encontrada
|
|
801
|
-
|
|
956
|
+
if (hooks) {
|
|
802
957
|
hooks.doAction('route_not_found', pathname, req, res);
|
|
803
958
|
}
|
|
804
959
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
805
960
|
res.end(JSON.stringify({ error: 'Ruta no encontrada', path: pathname }));
|
|
806
|
-
|
|
807
|
-
|
|
808
961
|
}
|
|
809
962
|
}
|
|
810
963
|
|
|
@@ -171,8 +171,12 @@ class SessionManager {
|
|
|
171
171
|
req.session.id = newSessionId;
|
|
172
172
|
req.session.data = processedUserData;
|
|
173
173
|
|
|
174
|
-
//
|
|
175
|
-
|
|
174
|
+
// Aplicar filtro para permitir modificación de las flags de la cookie
|
|
175
|
+
let cookieFlags = 'HttpOnly; Path=/';
|
|
176
|
+
cookieFlags = this.hooks.applyFilters('session_cookie_flags', cookieFlags, req, res, newSessionId);
|
|
177
|
+
|
|
178
|
+
// Establecer cookie con el ID de sesión y flags personalizadas
|
|
179
|
+
res.setHeader('Set-Cookie', `${this.cookieName}=${newSessionId}; ${cookieFlags}; Max-Age=${this.timeout / 1000}`);
|
|
176
180
|
|
|
177
181
|
// Disparar hook después de crear la sesión
|
|
178
182
|
this.hooks.doAction('session_created_response', req, res, newSessionId);
|
|
@@ -200,8 +204,12 @@ class SessionManager {
|
|
|
200
204
|
// Disparar hook antes de destruir la sesión
|
|
201
205
|
this.hooks.doAction('session_destroy_before', req, res, req.session.id);
|
|
202
206
|
|
|
207
|
+
// Aplicar filtro para permitir modificación de las flags de la cookie al destruir la sesión
|
|
208
|
+
let destroyCookieFlags = 'HttpOnly; Path=/';
|
|
209
|
+
destroyCookieFlags = this.hooks.applyFilters('session_cookie_destroy_flags', destroyCookieFlags, req, res, req.session.id);
|
|
210
|
+
|
|
203
211
|
// Borrar cookie
|
|
204
|
-
res.setHeader('Set-Cookie', `${this.cookieName}=;
|
|
212
|
+
res.setHeader('Set-Cookie', `${this.cookieName}=; ${destroyCookieFlags}; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:01 GMT`);
|
|
205
213
|
|
|
206
214
|
const result = this.destroySession(req.session.id);
|
|
207
215
|
req.session.id = null;
|
package/lib/mvc/viewEngine.js
CHANGED
|
@@ -274,7 +274,22 @@ class ViewEngine {
|
|
|
274
274
|
|
|
275
275
|
// Si el cache está habilitado, guardar la vista compilada (sin variables)
|
|
276
276
|
if (this.cacheEnabled) {
|
|
277
|
-
|
|
277
|
+
// Aplicar filter antes de cachear la vista
|
|
278
|
+
const contentToCache = this.hooks ?
|
|
279
|
+
this.hooks.applyFilters('before_view_cache', viewContent, viewPath) : viewContent;
|
|
280
|
+
|
|
281
|
+
// Verificar con hook si se debe cachear esta vista
|
|
282
|
+
const shouldCache = this.hooks ?
|
|
283
|
+
this.hooks.applyFilters('should_cache_view', true, viewPath, contentToCache) : true;
|
|
284
|
+
|
|
285
|
+
if (shouldCache) {
|
|
286
|
+
this.viewCache.set(viewPath, contentToCache);
|
|
287
|
+
|
|
288
|
+
// Disparar hook después de cachear
|
|
289
|
+
if (this.hooks) {
|
|
290
|
+
this.hooks.doAction('view_cached', viewPath, contentToCache);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
278
293
|
}
|
|
279
294
|
|
|
280
295
|
// Procesar el template con las variables
|
|
@@ -817,7 +832,17 @@ class ViewEngine {
|
|
|
817
832
|
* Limpia el cache de vistas
|
|
818
833
|
*/
|
|
819
834
|
clearCache() {
|
|
835
|
+
// Disparar hook antes de limpiar el caché
|
|
836
|
+
if (this.hooks) {
|
|
837
|
+
this.hooks.doAction('before_view_cache_clear', this);
|
|
838
|
+
}
|
|
839
|
+
|
|
820
840
|
this.viewCache.clear();
|
|
841
|
+
|
|
842
|
+
// Disparar hook después de limpiar el caché
|
|
843
|
+
if (this.hooks) {
|
|
844
|
+
this.hooks.doAction('view_cache_cleared');
|
|
845
|
+
}
|
|
821
846
|
}
|
|
822
847
|
}
|
|
823
848
|
|