jerkjs 2.1.7 → 2.3.0

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 (51) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +204 -4
  3. package/README_EN.md +1 -1
  4. package/README_PT.md +1 -1
  5. package/docs/ARQUITECTURA_ROUTES.md +84 -38
  6. package/{JERK_FRAMEWORK_DOCUMENTATION.md → docs/JERK_FRAMEWORK_DOCUMENTATION.md} +28 -2
  7. package/docs/JERK_MODELOS_HOWTO.md +566 -0
  8. package/index.js +41 -5
  9. package/jerk-qbuilder/CHANGELOG.md +71 -0
  10. package/jerk-qbuilder/HOWTO.md +325 -0
  11. package/jerk-qbuilder/README.md +52 -0
  12. package/lib/core/server.js +328 -27
  13. package/lib/loader/routeLoader.js +148 -117
  14. package/lib/mvc/GenericAdapter.js +136 -0
  15. package/lib/mvc/MariaDBAdapter.js +315 -0
  16. package/lib/mvc/MemoryAdapter.js +269 -0
  17. package/lib/mvc/ModelControllerExample.js +285 -0
  18. package/lib/mvc/controllerBase.js +77 -0
  19. package/lib/mvc/modelBase.js +383 -0
  20. package/lib/mvc/modelManager.js +284 -0
  21. package/lib/mvc/userModel.js +265 -0
  22. package/lib/mvc/viewEngine.js +32 -1
  23. package/lib/query/MariaDBAdapter.js +78 -0
  24. package/lib/query/consoleAdapter.js +184 -0
  25. package/lib/query/queryBuilder.js +953 -0
  26. package/lib/query/queryBuilderHooks.js +455 -0
  27. package/lib/query/queryBuilderMiddleware.js +332 -0
  28. package/lib/utils/mimeType.js +62 -0
  29. package/package.json +5 -3
  30. package/utils/find_file_path.sh +36 -0
  31. package/BUG_REPORTE_COMPRESION.txt +0 -72
  32. package/standard/CompressionTestController.js +0 -56
  33. package/standard/HealthController.js +0 -16
  34. package/standard/HomeController.js +0 -12
  35. package/standard/ProductController.js +0 -18
  36. package/standard/README.md +0 -47
  37. package/standard/UserController.js +0 -23
  38. package/standard/package.json +0 -22
  39. package/standard/routes.json +0 -65
  40. package/standard/server.js +0 -140
  41. package/standardA/controllers/AuthController.js +0 -82
  42. package/standardA/controllers/HomeController.js +0 -19
  43. package/standardA/controllers/UserController.js +0 -41
  44. package/standardA/server.js +0 -311
  45. package/standardA/views/auth/dashboard.html +0 -51
  46. package/standardA/views/auth/login.html +0 -47
  47. package/standardA/views/index.html +0 -32
  48. package/standardA/views/users/detail.html +0 -28
  49. package/standardA/views/users/list.html +0 -36
  50. /package/{JERK_FRAMEWORK_DIAGRAM.txt → docs/JERK_FRAMEWORK_DIAGRAM.txt} +0 -0
  51. /package/{JERK_FRAMEWORK_DIAGRAM_MERMAID.mmd → docs/JERK_FRAMEWORK_DIAGRAM_MERMAID.mmd} +0 -0
@@ -83,12 +83,29 @@ class RouteLoader {
83
83
  throw new Error(`La ruta en la posición ${i} no tiene propiedad 'method'`);
84
84
  }
85
85
 
86
- if (!route.controller) {
87
- throw new Error(`La ruta en la posición ${i} no tiene propiedad 'controller'`);
88
- }
86
+ // Verificar si es una ruta estática
87
+ if (route.static) {
88
+ if (typeof route.static !== 'object' || route.static === null) {
89
+ throw new Error(`La ruta en la posición ${i} tiene una propiedad 'static' inválida`);
90
+ }
91
+
92
+ if (!route.static.dir) {
93
+ throw new Error(`La ruta en la posición ${i} tiene una configuración 'static' sin directorio 'dir'`);
94
+ }
95
+
96
+ // El método debe ser GET para rutas estáticas
97
+ if (route.method.toUpperCase() !== 'GET') {
98
+ throw new Error(`Las rutas estáticas deben usar el método GET, no ${route.method}`);
99
+ }
100
+ } else {
101
+ // Validación normal para rutas dinámicas
102
+ if (!route.controller) {
103
+ throw new Error(`La ruta en la posición ${i} no tiene propiedad 'controller'`);
104
+ }
89
105
 
90
- if (!route.handler) {
91
- throw new Error(`La ruta en la posición ${i} no tiene propiedad 'handler'`);
106
+ if (!route.handler) {
107
+ throw new Error(`La ruta en la posición ${i} no tiene propiedad 'handler'`);
108
+ }
92
109
  }
93
110
 
94
111
  // Validar que el content-type sea un string si está presente
@@ -104,134 +121,148 @@ class RouteLoader {
104
121
  * @param {Object} route - Objeto de ruta a cargar
105
122
  */
106
123
  async loadSingleRoute(server, route) {
107
- // Obtener el controlador
108
- const controllerPath = path.resolve(process.cwd(), route.controller);
109
- let controllerModule;
110
-
111
- try {
112
- controllerModule = require(controllerPath);
113
- } catch (error) {
114
- throw new Error(`No se pudo cargar el controlador: ${route.controller}. Error: ${error.message}`);
115
- }
124
+ // Verificar si es una ruta estática
125
+ if (route.static) {
126
+ // Para rutas estáticas, simplemente llamar a addRoute con la configuración estática
127
+ server.addRoute({
128
+ method: route.method,
129
+ path: route.path,
130
+ static: route.static,
131
+ contentType: route.contentType,
132
+ auth: route.auth,
133
+ authOptions: route.authOptions
134
+ });
135
+ } else {
136
+ // Lógica existente para rutas dinámicas
137
+ // Obtener el controlador
138
+ const controllerPath = path.resolve(process.cwd(), route.controller);
139
+ let controllerModule;
140
+
141
+ try {
142
+ controllerModule = require(controllerPath);
143
+ } catch (error) {
144
+ throw new Error(`No se pudo cargar el controlador: ${route.controller}. Error: ${error.message}`);
145
+ }
116
146
 
117
- // Obtener el handler del controlador
118
- const handler = controllerModule[route.handler];
119
- if (typeof handler !== 'function') {
120
- throw new Error(`El handler '${route.handler}' no es una función en el controlador: ${route.controller}`);
121
- }
147
+ // Obtener el handler del controlador
148
+ const handler = controllerModule[route.handler];
149
+ if (typeof handler !== 'function') {
150
+ throw new Error(`El handler '${route.handler}' no es una función en el controlador: ${route.controller}`);
151
+ }
122
152
 
123
- // Crear un handler que establezca el content-type si está especificado
124
- let finalHandler = handler;
153
+ // Crear un handler que establezca el content-type si está especificado
154
+ let finalHandler = handler;
125
155
 
126
- if (route.contentType) {
127
- finalHandler = async (req, res) => {
128
- // Establecer el content-type antes de ejecutar el handler original
129
- res.setHeader('Content-Type', route.contentType);
156
+ if (route.contentType) {
157
+ finalHandler = async (req, res) => {
158
+ // Establecer el content-type antes de ejecutar el handler original
159
+ res.setHeader('Content-Type', route.contentType);
130
160
 
131
- // Si el handler es asíncrono, esperarlo
132
- if (handler.constructor.name === 'AsyncFunction') {
133
- await handler(req, res);
134
- } else {
135
- handler(req, res);
136
- }
137
- };
138
- }
161
+ // Si el handler es asíncrono, esperarlo
162
+ if (handler.constructor.name === 'AsyncFunction') {
163
+ await handler(req, res);
164
+ } else {
165
+ handler(req, res);
166
+ }
167
+ };
168
+ }
139
169
 
140
- // Aplicar autenticación si está especificada
141
- if (route.auth && route.auth !== 'none') {
142
- // Verificar si es autenticación de sesión
143
- if (route.auth === 'session') {
144
- // Verificar si el servidor tiene sessionManager
145
- if (server.sessionManager) {
146
- // Importar el middleware de autenticación de sesión
147
- const { sessionAuth } = require('../middleware/session');
148
- const authMiddleware = sessionAuth(server.sessionManager, route.authOptions || {});
149
-
150
- // Crear un nuevo handler que ejecute la autenticación primero
151
- const authenticatedHandler = async (req, res) => {
152
- try {
153
- // Ejecutar el middleware de autenticación y esperar a que se resuelva
154
- await new Promise((resolve, reject) => {
155
- const next = () => resolve();
156
- const result = authMiddleware(req, res, next);
157
-
158
- // Si authMiddleware devuelve una promesa, esperarla
159
- if (result && typeof result.then === 'function') {
160
- result.then(resolve).catch(reject);
170
+ // Aplicar autenticación si está especificada
171
+ if (route.auth && route.auth !== 'none') {
172
+ // Verificar si es autenticación de sesión
173
+ if (route.auth === 'session') {
174
+ // Verificar si el servidor tiene sessionManager
175
+ if (server.sessionManager) {
176
+ // Importar el middleware de autenticación de sesión
177
+ const { sessionAuth } = require('../middleware/session');
178
+ const authMiddleware = sessionAuth(server.sessionManager, route.authOptions || {});
179
+
180
+ // Crear un nuevo handler que ejecute la autenticación primero
181
+ const authenticatedHandler = async (req, res) => {
182
+ try {
183
+ // Ejecutar el middleware de autenticación y esperar a que se resuelva
184
+ await new Promise((resolve, reject) => {
185
+ const next = () => resolve();
186
+ const result = authMiddleware(req, res, next);
187
+
188
+ // Si authMiddleware devuelve una promesa, esperarla
189
+ if (result && typeof result.then === 'function') {
190
+ result.then(resolve).catch(reject);
191
+ }
192
+ });
193
+
194
+ // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
195
+ if (!res.headersSent) {
196
+ // Si el handler es asíncrono, esperarlo también
197
+ if (finalHandler.constructor.name === 'AsyncFunction') {
198
+ await finalHandler(req, res);
199
+ } else {
200
+ finalHandler(req, res);
201
+ }
161
202
  }
162
- });
163
-
164
- // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
165
- if (!res.headersSent) {
166
- // Si el handler es asíncrono, esperarlo también
167
- if (finalHandler.constructor.name === 'AsyncFunction') {
168
- await finalHandler(req, res);
169
- } else {
170
- finalHandler(req, res);
203
+ } catch (error) {
204
+ console.error('Error en el manejo de autenticación de sesión:', error);
205
+ if (!res.headersSent) {
206
+ res.writeHead(500, { 'Content-Type': 'application/json' });
207
+ res.end(JSON.stringify({ error: 'Error interno del servidor' }));
171
208
  }
172
209
  }
173
- } catch (error) {
174
- console.error('Error en el manejo de autenticación de sesión:', error);
175
- if (!res.headersSent) {
176
- res.writeHead(500, { 'Content-Type': 'application/json' });
177
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
178
- }
179
- }
180
- };
210
+ };
181
211
 
182
- // Agregar la ruta con el handler autenticado
183
- server.addRoute(route.method, route.path, authenticatedHandler);
212
+ // Agregar la ruta con el handler autenticado
213
+ server.addRoute(route.method, route.path, authenticatedHandler);
214
+ } else {
215
+ // Si no hay sessionManager en el servidor, agregar la ruta normalmente
216
+ server.addRoute(route.method, route.path, finalHandler);
217
+ }
184
218
  } else {
185
- // Si no hay sessionManager en el servidor, agregar la ruta normalmente
186
- server.addRoute(route.method, route.path, finalHandler);
187
- }
188
- } else {
189
- // Usar el authenticator del servidor si está disponible para otros tipos de autenticación
190
- if (server.authenticator) {
191
- const authMiddleware = server.authenticator.authenticate(route.auth, route.authOptions || {});
192
-
193
- // Crear un nuevo handler que ejecute la autenticación primero
194
- const authenticatedHandler = async (req, res) => {
195
- try {
196
- // Ejecutar el middleware de autenticación y esperar a que se resuelva
197
- await new Promise((resolve, reject) => {
198
- const next = () => resolve();
199
- const result = authMiddleware(req, res, next);
200
-
201
- // Si authMiddleware devuelve una promesa, esperarla
202
- if (result && typeof result.then === 'function') {
203
- result.then(resolve).catch(reject);
219
+ // Usar el authenticator del servidor si está disponible para otros tipos de autenticación
220
+ if (server.authenticator) {
221
+ const authMiddleware = server.authenticator.authenticate(route.auth, route.authOptions || {});
222
+
223
+ // Crear un nuevo handler que ejecute la autenticación primero
224
+ const authenticatedHandler = async (req, res) => {
225
+ try {
226
+ // Ejecutar el middleware de autenticación y esperar a que se resuelva
227
+ await new Promise((resolve, reject) => {
228
+ const next = () => resolve();
229
+ const result = authMiddleware(req, res, next);
230
+
231
+ // Si authMiddleware devuelve una promesa, esperarla
232
+ if (result && typeof result.then === 'function') {
233
+ result.then(resolve).catch(reject);
234
+ }
235
+ });
236
+
237
+ // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
238
+ if (!res.headersSent) {
239
+ // Si el handler es asíncrono, esperarlo también
240
+ if (finalHandler.constructor.name === 'AsyncFunction') {
241
+ await finalHandler(req, res);
242
+ } else {
243
+ finalHandler(req, res);
244
+ }
204
245
  }
205
- });
206
-
207
- // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
208
- if (!res.headersSent) {
209
- // Si el handler es asíncrono, esperarlo también
210
- if (finalHandler.constructor.name === 'AsyncFunction') {
211
- await finalHandler(req, res);
212
- } else {
213
- finalHandler(req, res);
246
+ } catch (error) {
247
+ console.error('Error en el manejo de autenticación:', error);
248
+ if (!res.headersSent) {
249
+ res.writeHead(500, { 'Content-Type': 'application/json' });
250
+ res.end(JSON.stringify({ error: 'Error interno del servidor' }));
214
251
  }
215
252
  }
216
- } catch (error) {
217
- console.error('Error en el manejo de autenticación:', error);
218
- if (!res.headersSent) {
219
- res.writeHead(500, { 'Content-Type': 'application/json' });
220
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
221
- }
222
- }
223
- };
253
+ };
224
254
 
225
- // Agregar la ruta con el handler autenticado
226
- server.addRoute(route.method, route.path, authenticatedHandler);
227
- } else {
228
- // Si no hay authenticator en el servidor, agregar la ruta normalmente
229
- server.addRoute(route.method, route.path, finalHandler);
255
+ // Agregar la ruta con el handler autenticado
256
+ server.addRoute(route.method, route.path, authenticatedHandler);
257
+ } else {
258
+ // Si no hay authenticator en el servidor, agregar la ruta normalmente
259
+ server.addRoute(route.method, route.path, finalHandler);
260
+ }
230
261
  }
262
+ } else {
263
+ // Si no hay autenticación requerida, agregar la ruta normalmente
264
+ server.addRoute(route.method, route.path, finalHandler);
231
265
  }
232
- } else {
233
- // Si no hay autenticación requerida, agregar la ruta normalmente
234
- server.addRoute(route.method, route.path, finalHandler);
235
266
  }
236
267
  }
237
268
 
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Adaptador genérico para modelos en el framework JERK
3
+ * Implementación del componente MVC GenericAdapter.js
4
+ * Proporciona una interfaz común para diferentes tipos de almacenamiento
5
+ */
6
+
7
+ class GenericAdapter {
8
+ /**
9
+ * Constructor del adaptador genérico
10
+ * @param {Object} options - Opciones de configuración
11
+ */
12
+ constructor(options = {}) {
13
+ this.options = options;
14
+ this.type = options.type || 'generic';
15
+ this.logger = options.logger || console;
16
+ }
17
+
18
+ /**
19
+ * Método para crear un registro
20
+ * @param {string} tableName - Nombre de la tabla
21
+ * @param {Object} data - Datos a crear
22
+ * @returns {Promise<Object>} - Promesa con el resultado
23
+ */
24
+ async create(tableName, data) {
25
+ throw new Error('Método create no implementado en el adaptador genérico');
26
+ }
27
+
28
+ /**
29
+ * Método para encontrar registros
30
+ * @param {string} tableName - Nombre de la tabla
31
+ * @param {Object} conditions - Condiciones de búsqueda
32
+ * @param {Object} options - Opciones adicionales
33
+ * @returns {Promise<Array>} - Promesa con los resultados
34
+ */
35
+ async find(tableName, conditions, options) {
36
+ throw new Error('Método find no implementado en el adaptador genérico');
37
+ }
38
+
39
+ /**
40
+ * Método para encontrar un solo registro
41
+ * @param {string} tableName - Nombre de la tabla
42
+ * @param {Object} conditions - Condiciones de búsqueda
43
+ * @param {Object} options - Opciones adicionales
44
+ * @returns {Promise<Object|null>} - Promesa con el resultado o null
45
+ */
46
+ async findOne(tableName, conditions, options) {
47
+ throw new Error('Método findOne no implementado en el adaptador genérico');
48
+ }
49
+
50
+ /**
51
+ * Método para actualizar registros
52
+ * @param {string} tableName - Nombre de la tabla
53
+ * @param {Object} conditions - Condiciones para seleccionar registros
54
+ * @param {Object} data - Datos a actualizar
55
+ * @returns {Promise<number>} - Promesa con el número de registros afectados
56
+ */
57
+ async update(tableName, conditions, data) {
58
+ throw new Error('Método update no implementado en el adaptador genérico');
59
+ }
60
+
61
+ /**
62
+ * Método para eliminar registros
63
+ * @param {string} tableName - Nombre de la tabla
64
+ * @param {Object} conditions - Condiciones para seleccionar registros
65
+ * @returns {Promise<number>} - Promesa con el número de registros eliminados
66
+ */
67
+ async delete(tableName, conditions) {
68
+ throw new Error('Método delete no implementado en el adaptador genérico');
69
+ }
70
+
71
+ /**
72
+ * Método para contar registros
73
+ * @param {string} tableName - Nombre de la tabla
74
+ * @param {Object} conditions - Condiciones de conteo
75
+ * @returns {Promise<number>} - Promesa con el número de registros
76
+ */
77
+ async count(tableName, conditions) {
78
+ throw new Error('Método count no implementado en el adaptador genérico');
79
+ }
80
+
81
+ /**
82
+ * Método para ejecutar consultas personalizadas
83
+ * @param {string} query - Consulta personalizada
84
+ * @param {Array} params - Parámetros de la consulta
85
+ * @returns {Promise<any>} - Promesa con el resultado
86
+ */
87
+ async query(query, params = []) {
88
+ throw new Error('Método query no implementado en el adaptador genérico');
89
+ }
90
+
91
+ /**
92
+ * Método para inicializar el adaptador
93
+ * @returns {Promise<void>}
94
+ */
95
+ async initialize() {
96
+ // Implementación por defecto
97
+ }
98
+
99
+ /**
100
+ * Método para cerrar la conexión
101
+ * @returns {Promise<void>}
102
+ */
103
+ async close() {
104
+ // Implementación por defecto
105
+ }
106
+
107
+ /**
108
+ * Método para verificar si el adaptador está conectado
109
+ * @returns {boolean} - Verdadero si está conectado
110
+ */
111
+ isConnected() {
112
+ return true; // Por defecto, asumimos que está conectado
113
+ }
114
+
115
+ /**
116
+ * Método para migrar una tabla
117
+ * @param {string} tableName - Nombre de la tabla a migrar
118
+ * @returns {Promise<void>}
119
+ */
120
+ async migrate(tableName) {
121
+ throw new Error('Método migrate no implementado en el adaptador genérico');
122
+ }
123
+
124
+ /**
125
+ * Serializa el adaptador a JSON
126
+ * @returns {Object} - Representación JSON del adaptador
127
+ */
128
+ toJSON() {
129
+ return {
130
+ type: this.type,
131
+ initialized: true
132
+ };
133
+ }
134
+ }
135
+
136
+ module.exports = GenericAdapter;