jerkjs 2.2.0 → 2.3.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.
- package/CHANGELOG.md +31 -0
- package/LICENSE +201 -0
- package/README.md +4 -1
- package/README_EN.md +230 -0
- package/README_PT.md +230 -0
- package/docs/ARQUITECTURA_ROUTES.md +186 -0
- package/docs/EXTENSION_MANUAL.md +955 -0
- package/docs/FIREWALL_MANUAL.md +416 -0
- package/docs/HOOK-2.0.md +512 -0
- package/docs/HOOKS_REFERENCE_IMPROVED.md +596 -0
- package/docs/JERK_FRAMEWORK_DIAGRAM.txt +492 -0
- package/docs/JERK_FRAMEWORK_DIAGRAM_MERMAID.mmd +124 -0
- package/docs/JERK_FRAMEWORK_DOCUMENTATION.md +553 -0
- package/docs/JERK_MODELOS_HOWTO.md +566 -0
- package/docs/MANUAL_API_SDK.md +536 -0
- package/docs/MARIADB_TOKENS_IMPLEMENTATION.md +110 -0
- package/docs/MIDDLEWARE_MANUAL.md +518 -0
- package/docs/OAUTH2_GOOGLE_MANUAL.md +405 -0
- package/docs/ROUTING_WITHOUT_JSON_GUIDE.md +454 -0
- package/docs/frontend-and-sessions.md +353 -0
- package/docs/guia_inicio_rapido_jerkjs.md +113 -0
- package/examples/examples.arj +0 -0
- package/index.js +12 -1
- package/jerk-qbuilder/CHANGELOG.md +71 -0
- package/jerk-qbuilder/HOWTO.md +325 -0
- package/jerk-qbuilder/README.md +52 -0
- package/lib/mvc/controllerBase.js +31 -14
- package/lib/query/MariaDBAdapter.js +78 -0
- package/lib/query/consoleAdapter.js +184 -0
- package/lib/query/queryBuilder.js +953 -0
- package/lib/query/queryBuilderHooks.js +455 -0
- package/lib/query/queryBuilderMiddleware.js +332 -0
- package/package.json +2 -2
- package/utils/find_file_path.sh +36 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# Frontend y Sesiones con API SDK JS
|
|
2
|
+
|
|
3
|
+
## Introducción
|
|
4
|
+
|
|
5
|
+
API SDK JS no solo es un framework para crear APIs, sino que ahora también soporta la creación de aplicaciones web completas con frontend y sistema de sesiones. Esta funcionalidad permite a los desarrolladores crear aplicaciones web completas con autenticación basada en sesiones, almacenamiento de datos y mucho más.
|
|
6
|
+
|
|
7
|
+
## Características del Frontend
|
|
8
|
+
|
|
9
|
+
### Especificación de Content-Type en routes.json
|
|
10
|
+
|
|
11
|
+
Una de las nuevas características es la capacidad de especificar el content-type directamente en el archivo routes.json:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
[
|
|
15
|
+
{
|
|
16
|
+
"path": "/",
|
|
17
|
+
"method": "GET",
|
|
18
|
+
"controller": "./controllers/pageController.js",
|
|
19
|
+
"handler": "homePage",
|
|
20
|
+
"auth": "none",
|
|
21
|
+
"contentType": "text/html"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "/api/data",
|
|
25
|
+
"method": "GET",
|
|
26
|
+
"controller": "./controllers/apiController.js",
|
|
27
|
+
"handler": "getData",
|
|
28
|
+
"auth": "none",
|
|
29
|
+
"contentType": "application/json"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Soporte para diferentes tipos de contenido
|
|
35
|
+
|
|
36
|
+
El framework ahora puede servir diferentes tipos de contenido:
|
|
37
|
+
- HTML para páginas web
|
|
38
|
+
- CSS para estilos
|
|
39
|
+
- JavaScript para scripts
|
|
40
|
+
- JSON para APIs
|
|
41
|
+
- Y cualquier otro tipo de contenido
|
|
42
|
+
|
|
43
|
+
## Sistema de Sesiones
|
|
44
|
+
|
|
45
|
+
### Configuración
|
|
46
|
+
|
|
47
|
+
Para usar el sistema de sesiones, primero debes configurar el middleware en tu aplicación:
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
const { APIServer, SessionManager, Cors } = require('@apisdkjs/apisdkjs');
|
|
51
|
+
|
|
52
|
+
async function startServer() {
|
|
53
|
+
const server = new APIServer({
|
|
54
|
+
port: 3000,
|
|
55
|
+
host: 'localhost'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Crear instancia del administrador de sesiones
|
|
59
|
+
const sessionManager = new SessionManager({
|
|
60
|
+
cookieName: 'myapp_session',
|
|
61
|
+
secret: 'my-super-secret-session-key',
|
|
62
|
+
timeout: 3600000 // 1 hora
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Aplicar middleware de sesión
|
|
66
|
+
server.use(sessionManager.middleware());
|
|
67
|
+
|
|
68
|
+
// Hacer que sessionManager esté disponible para el RouteLoader
|
|
69
|
+
server.sessionManager = sessionManager;
|
|
70
|
+
|
|
71
|
+
// Cargar rutas
|
|
72
|
+
const routeLoader = new RouteLoader();
|
|
73
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
74
|
+
|
|
75
|
+
server.start();
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Protección de rutas
|
|
80
|
+
|
|
81
|
+
Puedes proteger rutas específicas usando `"auth": "session"` en tu archivo routes.json:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
[
|
|
85
|
+
{
|
|
86
|
+
"path": "/dashboard",
|
|
87
|
+
"method": "GET",
|
|
88
|
+
"controller": "./controllers/dashboardController.js",
|
|
89
|
+
"handler": "showDashboard",
|
|
90
|
+
"auth": "session",
|
|
91
|
+
"contentType": "text/html"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Uso en controladores
|
|
97
|
+
|
|
98
|
+
En tus controladores, puedes acceder a la sesión a través de `req.session`:
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
const authController = {
|
|
102
|
+
// Controlador para iniciar sesión
|
|
103
|
+
processLogin: async (req, res) => {
|
|
104
|
+
const { username, password } = req.body;
|
|
105
|
+
|
|
106
|
+
// Validar credenciales (tu lógica aquí)
|
|
107
|
+
const user = await validateUser(username, password);
|
|
108
|
+
|
|
109
|
+
if (user) {
|
|
110
|
+
// Crear sesión de usuario autenticado
|
|
111
|
+
req.session.create({
|
|
112
|
+
authenticated: true,
|
|
113
|
+
userId: user.id,
|
|
114
|
+
username: user.username
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
118
|
+
res.end(JSON.stringify({
|
|
119
|
+
success: true,
|
|
120
|
+
message: 'Inicio de sesión exitoso'
|
|
121
|
+
}));
|
|
122
|
+
} else {
|
|
123
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
124
|
+
res.end(JSON.stringify({
|
|
125
|
+
success: false,
|
|
126
|
+
message: 'Credenciales inválidas'
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// Controlador para cerrar sesión
|
|
132
|
+
processLogout: (req, res) => {
|
|
133
|
+
if (req.session) {
|
|
134
|
+
req.session.destroy();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
138
|
+
res.end(JSON.stringify({
|
|
139
|
+
success: true,
|
|
140
|
+
message: 'Sesión cerrada exitosamente'
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Sistema de Hooks, Filters y Actions
|
|
147
|
+
|
|
148
|
+
El sistema de sesiones está completamente integrado con el sistema de hooks, filters y actions del framework, lo que permite extender y personalizar su comportamiento.
|
|
149
|
+
|
|
150
|
+
### Hooks Disponibles
|
|
151
|
+
|
|
152
|
+
#### Sesion Creation Hooks
|
|
153
|
+
- `session_create_data`: Filtra los datos antes de crear una sesión
|
|
154
|
+
- `session_created`: Acción disparada después de crear una sesión
|
|
155
|
+
- `session_create_user_data`: Filtra los datos de usuario antes de crear la sesión
|
|
156
|
+
|
|
157
|
+
#### Sesion Retrieval Hooks
|
|
158
|
+
- `session_get_id`: Filtra el ID de sesión antes de buscarla
|
|
159
|
+
- `session_retrieved`: Acción disparada después de obtener una sesión
|
|
160
|
+
- `session_not_found`: Acción disparada cuando no se encuentra una sesión
|
|
161
|
+
- `session_expired`: Acción disparada cuando una sesión ha expirado
|
|
162
|
+
|
|
163
|
+
#### Sesion Update Hooks
|
|
164
|
+
- `session_update_data`: Filtra los nuevos datos antes de actualizar la sesión
|
|
165
|
+
- `session_updated`: Acción disparada después de actualizar una sesión
|
|
166
|
+
- `session_update_user_data`: Filtra los datos de usuario antes de actualizar
|
|
167
|
+
|
|
168
|
+
#### Sesion Destruction Hooks
|
|
169
|
+
- `session_destroy_before`: Acción disparada antes de destruir una sesión
|
|
170
|
+
- `session_destroyed`: Acción disparada después de destruir una sesión
|
|
171
|
+
- `session_destroy_failed`: Acción disparada cuando falla la destrucción
|
|
172
|
+
|
|
173
|
+
#### Middleware Hooks
|
|
174
|
+
- `session_middleware_before`: Acción disparada antes del middleware de sesión
|
|
175
|
+
- `session_middleware_after`: Acción disparada después del middleware de sesión
|
|
176
|
+
|
|
177
|
+
#### Authentication Hooks
|
|
178
|
+
- `session_auth_check_before`: Acción disparada antes de verificar autenticación
|
|
179
|
+
- `session_auth_success`: Acción disparada cuando la autenticación es exitosa
|
|
180
|
+
- `session_auth_failed`: Acción disparada cuando la autenticación falla
|
|
181
|
+
- `session_created_response`: Acción disparada después de crear sesión en respuesta
|
|
182
|
+
- `session_updated_response`: Acción disparada después de actualizar sesión en respuesta
|
|
183
|
+
- `session_destroyed_response`: Acción disparada después de destruir sesión en respuesta
|
|
184
|
+
|
|
185
|
+
### Ejemplos de Uso de Hooks
|
|
186
|
+
|
|
187
|
+
#### Registrar actividad de sesión
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
191
|
+
|
|
192
|
+
// Registrar cuando se crea una sesión
|
|
193
|
+
hooks.addAction('session_created', (sessionId, sessionData) => {
|
|
194
|
+
console.log(`Sesión creada: ${sessionId} para el usuario: ${sessionData.username}`);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Registrar cuando se destruye una sesión
|
|
198
|
+
hooks.addAction('session_destroyed', (sessionId, sessionData) => {
|
|
199
|
+
console.log(`Sesión destruida: ${sessionId} para el usuario: ${sessionData.username}`);
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Modificar datos de sesión antes de crearla
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
207
|
+
|
|
208
|
+
// Añadir información de IP y fecha a los datos de sesión
|
|
209
|
+
hooks.addFilter('session_create_data', (userData, req) => {
|
|
210
|
+
return {
|
|
211
|
+
...userData,
|
|
212
|
+
ipAddress: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
|
|
213
|
+
createdAt: new Date().toISOString()
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### Personalizar el manejo de autenticación fallida
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
222
|
+
|
|
223
|
+
// Registrar intentos de acceso no autorizado
|
|
224
|
+
hooks.addAction('session_auth_failed', (req, res, redirectTo) => {
|
|
225
|
+
console.log(`Intento de acceso no autorizado a: ${req.url} desde IP: ${req.connection.remoteAddress}`);
|
|
226
|
+
|
|
227
|
+
// Puedes personalizar la respuesta aquí
|
|
228
|
+
if (req.headers.accept && req.headers.accept.includes('application/json')) {
|
|
229
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
230
|
+
res.end(JSON.stringify({ error: 'No autorizado', code: 'AUTH_REQUIRED' }));
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### Extender datos de sesión durante la actualización
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
const { hooks } = require('@apisdkjs/apisdkjs');
|
|
239
|
+
|
|
240
|
+
// Añadir marca de tiempo a cada actualización de sesión
|
|
241
|
+
hooks.addFilter('session_update_data', (newData, req, sessionId) => {
|
|
242
|
+
return {
|
|
243
|
+
...newData,
|
|
244
|
+
lastUpdated: new Date().toISOString(),
|
|
245
|
+
lastActivity: new Date().toISOString()
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Ejemplo Completo
|
|
251
|
+
|
|
252
|
+
Aquí tienes un ejemplo completo de una aplicación que combina frontend y sesiones:
|
|
253
|
+
|
|
254
|
+
### app.js
|
|
255
|
+
```javascript
|
|
256
|
+
const {
|
|
257
|
+
APIServer,
|
|
258
|
+
RouteLoader,
|
|
259
|
+
Logger,
|
|
260
|
+
Cors,
|
|
261
|
+
SessionManager
|
|
262
|
+
} = require('@apisdkjs/apisdkjs');
|
|
263
|
+
|
|
264
|
+
async function startServer() {
|
|
265
|
+
const server = new APIServer({
|
|
266
|
+
port: 3000,
|
|
267
|
+
host: 'localhost'
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const logger = new Logger({ level: 'info' });
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
// Configurar sesiones
|
|
274
|
+
const sessionManager = new SessionManager({
|
|
275
|
+
cookieName: 'myapp_session',
|
|
276
|
+
secret: 'my-super-secret-session-key',
|
|
277
|
+
timeout: 3600000
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
server.use(sessionManager.middleware());
|
|
281
|
+
server.sessionManager = sessionManager;
|
|
282
|
+
|
|
283
|
+
// Configurar CORS
|
|
284
|
+
const cors = new Cors({
|
|
285
|
+
origin: '*',
|
|
286
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
287
|
+
allowedHeaders: ['Content-Type', 'Authorization']
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
server.use(cors.middleware());
|
|
291
|
+
|
|
292
|
+
// Cargar rutas
|
|
293
|
+
const routeLoader = new RouteLoader();
|
|
294
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
295
|
+
|
|
296
|
+
server.start();
|
|
297
|
+
logger.info('Servidor iniciado en http://localhost:3000');
|
|
298
|
+
} catch (error) {
|
|
299
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
startServer();
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### routes.json
|
|
308
|
+
```json
|
|
309
|
+
[
|
|
310
|
+
{
|
|
311
|
+
"path": "/",
|
|
312
|
+
"method": "GET",
|
|
313
|
+
"controller": "./controllers/pageController.js",
|
|
314
|
+
"handler": "homePage",
|
|
315
|
+
"auth": "none",
|
|
316
|
+
"contentType": "text/html"
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"path": "/login",
|
|
320
|
+
"method": "GET",
|
|
321
|
+
"controller": "./controllers/authController.js",
|
|
322
|
+
"handler": "showLoginPage",
|
|
323
|
+
"auth": "none",
|
|
324
|
+
"contentType": "text/html"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"path": "/dashboard",
|
|
328
|
+
"method": "GET",
|
|
329
|
+
"controller": "./controllers/dashboardController.js",
|
|
330
|
+
"handler": "showDashboard",
|
|
331
|
+
"auth": "session",
|
|
332
|
+
"contentType": "text/html"
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"path": "/api/login",
|
|
336
|
+
"method": "POST",
|
|
337
|
+
"controller": "./controllers/authController.js",
|
|
338
|
+
"handler": "processLogin",
|
|
339
|
+
"auth": "none",
|
|
340
|
+
"contentType": "application/json"
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
"path": "/api/logout",
|
|
344
|
+
"method": "POST",
|
|
345
|
+
"controller": "./controllers/authController.js",
|
|
346
|
+
"handler": "processLogout",
|
|
347
|
+
"auth": "session",
|
|
348
|
+
"contentType": "application/json"
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Este ejemplo demuestra cómo crear una aplicación web completa con autenticación basada en sesiones, protección de rutas y soporte para frontend HTML.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Documentación de Aprendizajes con JERKJS
|
|
2
|
+
|
|
3
|
+
## 1. Formato del archivo routes.json
|
|
4
|
+
|
|
5
|
+
**Formato correcto:**
|
|
6
|
+
```json
|
|
7
|
+
[
|
|
8
|
+
{
|
|
9
|
+
"method": "GET",
|
|
10
|
+
"path": "/",
|
|
11
|
+
"controller": "./controllers/mainController.js",
|
|
12
|
+
"handler": "home",
|
|
13
|
+
"auth": "none"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Características importantes:**
|
|
19
|
+
- Debe ser un array directo de rutas, **NO** un objeto con propiedad "routes"
|
|
20
|
+
- Campos requeridos: `method`, `path`, `controller`, `handler`, `auth`
|
|
21
|
+
- El campo `controller` debe especificar la ruta completa al archivo del controlador
|
|
22
|
+
- El campo `handler` debe especificar el nombre exacto del método en el controlador
|
|
23
|
+
- El campo `auth` puede ser "none", "required", etc.
|
|
24
|
+
|
|
25
|
+
## 2. Estructura de controladores para usar con routes.json
|
|
26
|
+
|
|
27
|
+
**Formato correcto:**
|
|
28
|
+
```javascript
|
|
29
|
+
const { ControllerBase } = require('jerkjs');
|
|
30
|
+
|
|
31
|
+
class MainController extends ControllerBase {
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
super(options);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
home(req, res) {
|
|
37
|
+
// Lógica del controlador
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Exportar métodos directamente para que el RouteLoader pueda acceder a ellos
|
|
42
|
+
const controllerInstance = new MainController({ viewsPath: './views' });
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
home: (req, res) => {
|
|
46
|
+
controllerInstance.setRequestResponse(req, res);
|
|
47
|
+
controllerInstance.home(req, res);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Características importantes:**
|
|
53
|
+
- No se puede exportar directamente la instancia del controlador
|
|
54
|
+
- Debe exportar un objeto con funciones que encapsulan la llamada al método del controlador
|
|
55
|
+
- Se debe llamar a `setRequestResponse()` antes de ejecutar el método del controlador
|
|
56
|
+
|
|
57
|
+
## 3. Uso del motor de plantillas de JERK
|
|
58
|
+
|
|
59
|
+
**Características del motor de plantillas:**
|
|
60
|
+
- Usa sintaxis `{{variable}}` para mostrar variables
|
|
61
|
+
- Soporta condicionales: `{{if variable}}contenido{{endif}}`
|
|
62
|
+
- Soporta bucles: `{{foreach:array}}contenido{{endforeach}}`
|
|
63
|
+
- Se accede a los elementos del bucle con `{{item.property}}`
|
|
64
|
+
|
|
65
|
+
## 4. Sistema de hooks
|
|
66
|
+
|
|
67
|
+
**Tipos de hooks:**
|
|
68
|
+
- `addAction(nombre_hook, callback)` - Para acciones que se ejecutan en puntos específicos
|
|
69
|
+
- `addFilter(nombre_hook, callback)` - Para filtrar/modificar datos
|
|
70
|
+
|
|
71
|
+
**Hooks útiles:**
|
|
72
|
+
- `post_controller_load` - Se ejecuta después de cargar un controlador
|
|
73
|
+
- `pre_route_load` - Se ejecuta antes de cargar rutas
|
|
74
|
+
- `post_route_load` - Se ejecuta después de cargar rutas
|
|
75
|
+
- `request_received` - Se ejecuta cuando se recibe una solicitud
|
|
76
|
+
- `request_completed` - Se ejecuta cuando se completa una solicitud
|
|
77
|
+
|
|
78
|
+
## 5. Puerto y configuración del servidor
|
|
79
|
+
|
|
80
|
+
**Configuración del servidor:**
|
|
81
|
+
```javascript
|
|
82
|
+
const server = new APIServer({
|
|
83
|
+
port: 11000, // Puerto específico
|
|
84
|
+
host: 'localhost'
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 6. Controladores que extienden ControllerBase
|
|
89
|
+
|
|
90
|
+
**Características:**
|
|
91
|
+
- Deben extender `ControllerBase` del framework
|
|
92
|
+
- Usan `this.set()` para establecer variables de vista
|
|
93
|
+
- Usan `this.render()` para renderizar vistas
|
|
94
|
+
- Requieren que se llame a `setRequestResponse()` antes de usar métodos del controlador
|
|
95
|
+
|
|
96
|
+
## 7. Errores comunes y soluciones
|
|
97
|
+
|
|
98
|
+
**Error común:** "this.set is not a function"
|
|
99
|
+
**Solución:** Asegurarse de que se llama a `controllerInstance.setRequestResponse(req, res)` antes de ejecutar métodos del controlador
|
|
100
|
+
|
|
101
|
+
**Error común:** "Error cargando rutas desde ./routes.json: El archivo de rutas debe contener un array de rutas"
|
|
102
|
+
**Solución:** Asegurarse de que routes.json sea un array directo, no un objeto con propiedad "routes"
|
|
103
|
+
|
|
104
|
+
**Error común:** "controllerLoader.loadControllers is not a function"
|
|
105
|
+
**Solución:** El RouteLoader se encarga de cargar tanto rutas como controladores, no usar ControllerLoader por separado
|
|
106
|
+
|
|
107
|
+
## 8. Recursos útiles
|
|
108
|
+
|
|
109
|
+
- Directorio de ejemplos en `/node_modules/jerkjs/examples/`
|
|
110
|
+
- Archivos routes.json de ejemplo en los directorios de ejemplos
|
|
111
|
+
- Documentación en el README del paquete
|
|
112
|
+
|
|
113
|
+
Esta documentación servirá para futuros desarrollos con JERKJS y evitará caer en los mismos errores o confusiones.
|
|
Binary file
|
package/index.js
CHANGED
|
@@ -48,6 +48,11 @@ const ModelControllerExample = require('./lib/mvc/ModelControllerExample');
|
|
|
48
48
|
// Componentes de manejo de errores
|
|
49
49
|
const { ErrorHandler, ValidationError, AuthenticationError, DatabaseError } = require('./lib/utils/errorHandler');
|
|
50
50
|
|
|
51
|
+
// Componentes del QueryBuilder (v2.3.0)
|
|
52
|
+
const QueryBuilder = require('./lib/query/queryBuilder');
|
|
53
|
+
const QueryBuilderMiddleware = require('./lib/query/queryBuilderMiddleware');
|
|
54
|
+
const { initializeQueryBuilderHooks, extendQueryBuilderWithHooks } = require('./lib/query/queryBuilderHooks');
|
|
55
|
+
|
|
51
56
|
// Exportar todos los componentes del framework
|
|
52
57
|
module.exports = {
|
|
53
58
|
// Componentes fundamentales (v1.0)
|
|
@@ -105,7 +110,13 @@ module.exports = {
|
|
|
105
110
|
ErrorHandler,
|
|
106
111
|
ValidationError,
|
|
107
112
|
AuthenticationError,
|
|
108
|
-
DatabaseError
|
|
113
|
+
DatabaseError,
|
|
114
|
+
|
|
115
|
+
// Componentes del QueryBuilder (v2.3.0)
|
|
116
|
+
QueryBuilder,
|
|
117
|
+
QueryBuilderMiddleware,
|
|
118
|
+
initializeQueryBuilderHooks,
|
|
119
|
+
extendQueryBuilderWithHooks
|
|
109
120
|
};
|
|
110
121
|
|
|
111
122
|
// También exportar clases individuales por conveniencia
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Todos los cambios importantes en este proyecto se documentarán en este archivo.
|
|
4
|
+
|
|
5
|
+
El formato está basado en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
y este proyecto adhiere al [Versionado Semántico](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Versión 1.0.0] - 2026-01-21
|
|
9
|
+
|
|
10
|
+
### Cambios Importantes
|
|
11
|
+
|
|
12
|
+
#### 🚀 Características Nuevas
|
|
13
|
+
|
|
14
|
+
- **QueryBuilder principal**
|
|
15
|
+
- Implementación completa del QueryBuilder con API fluida
|
|
16
|
+
- Métodos para SELECT, INSERT, UPDATE, DELETE
|
|
17
|
+
- Soporte para condiciones WHERE, JOINs, GROUP BY, ORDER BY
|
|
18
|
+
- Paginación con LIMIT y OFFSET
|
|
19
|
+
- Funciones de agregación (COUNT, MAX, MIN, SUM, AVG)
|
|
20
|
+
|
|
21
|
+
- **Método setAdapter()**
|
|
22
|
+
- Implementación del método `setAdapter(adapter)` para configurar dinámicamente cualquier adaptador
|
|
23
|
+
- Permite cambiar de base de datos en tiempo de ejecución
|
|
24
|
+
- Compatible con múltiples sistemas de base de datos
|
|
25
|
+
|
|
26
|
+
- **Adaptador MariaDB**
|
|
27
|
+
- Implementación del adaptador para MariaDB/MySQL
|
|
28
|
+
- Conexión mediante pool de conexiones
|
|
29
|
+
- Ejecución segura de consultas SQL
|
|
30
|
+
|
|
31
|
+
- **Adaptador de Consola**
|
|
32
|
+
- Adaptador de ejemplo para mostrar consultas SQL por consola
|
|
33
|
+
- Útil para pruebas y desarrollo
|
|
34
|
+
- Simula resultados de consultas
|
|
35
|
+
|
|
36
|
+
- **Middleware de Integración**
|
|
37
|
+
- Sistema completo para inyectar QueryBuilder en solicitudes HTTP
|
|
38
|
+
- Middleware para configurar adaptadores
|
|
39
|
+
- Middleware para registrar QueryBuilder con hooks
|
|
40
|
+
- Middleware para habilitar registro de consultas
|
|
41
|
+
- Middleware para aplicar reglas de seguridad
|
|
42
|
+
|
|
43
|
+
- **Sistema de Hooks**
|
|
44
|
+
- Integración completa con el sistema de hooks de JERK
|
|
45
|
+
- Acciones y filtros para eventos del QueryBuilder
|
|
46
|
+
- Sistema de auditoría de consultas
|
|
47
|
+
- Aplicación de reglas de seguridad
|
|
48
|
+
|
|
49
|
+
#### 🔧 Cambios Técnicos
|
|
50
|
+
|
|
51
|
+
- **Arquitectura modular**
|
|
52
|
+
- Estructura de archivos separados para cada componente
|
|
53
|
+
- Dependencias claras entre módulos
|
|
54
|
+
- Código organizado y mantenible
|
|
55
|
+
|
|
56
|
+
- **Seguridad mejorada**
|
|
57
|
+
- Prevención de inyección SQL mediante el uso de parámetros
|
|
58
|
+
- Sistema de validación de consultas
|
|
59
|
+
- Reglas de seguridad configurables
|
|
60
|
+
|
|
61
|
+
- **Documentación completa**
|
|
62
|
+
- README.md con descripción general
|
|
63
|
+
- HOWTO.md con instrucciones detalladas de uso
|
|
64
|
+
- Ejemplos prácticos de implementación
|
|
65
|
+
|
|
66
|
+
#### 📝 Otros Cambios
|
|
67
|
+
|
|
68
|
+
- **Ejemplos de uso**
|
|
69
|
+
- Aplicación de demostración completa
|
|
70
|
+
- Ejemplos de integración con JERK Framework
|
|
71
|
+
- Casos de uso prácticos con base de datos real
|