jerkjs 2.0.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.
- package/LICENSE +200 -0
- package/README.md +171 -0
- package/doc/EXTENSION_MANUAL.md +958 -0
- package/doc/FIREWALL_MANUAL.md +419 -0
- package/doc/HOOKS_REFERENCE_IMPROVED.md +599 -0
- package/doc/MANUAL_API_SDK.md +539 -0
- package/doc/MANUAL_MVC.md +397 -0
- package/doc/MARIADB_TOKENS_IMPLEMENTATION.md +113 -0
- package/doc/MIDDLEWARE_MANUAL.md +521 -0
- package/doc/OAUTH2_GOOGLE_MANUAL.md +408 -0
- package/doc/frontend-and-sessions.md +356 -0
- package/examples/advanced/controllers/productController.js +64 -0
- package/examples/advanced/controllers/userController.js +85 -0
- package/examples/advanced/routes.json +51 -0
- package/examples/advanced_example.js +93 -0
- package/examples/basic/controllers/userController.js +85 -0
- package/examples/basic_example.js +72 -0
- package/examples/frontend/README.md +71 -0
- package/examples/frontend/app.js +71 -0
- package/examples/frontend/controllers/apiController.js +39 -0
- package/examples/frontend/controllers/authController.js +220 -0
- package/examples/frontend/controllers/formController.js +47 -0
- package/examples/frontend/controllers/messageController.js +96 -0
- package/examples/frontend/controllers/pageController.js +178 -0
- package/examples/frontend/controllers/staticController.js +167 -0
- package/examples/frontend/routes.json +90 -0
- package/examples/mvc_example/app.js +138 -0
- package/examples/mvc_example/views/home/index.html +26 -0
- package/examples/mvc_example/views/home/simple.html +3 -0
- package/examples/mvc_example/views/layout.html +23 -0
- package/examples/mvc_example/views/test.html +3 -0
- package/examples/mvc_example/views/user/invalid.html +6 -0
- package/examples/mvc_example/views/user/list.html +36 -0
- package/examples/mvc_example/views/user/notfound.html +6 -0
- package/examples/mvc_example/views/user/profile.html +11 -0
- package/examples/mvc_routes_example/app.js +34 -0
- package/examples/mvc_routes_example/controllers/mainController.js +27 -0
- package/examples/mvc_routes_example/controllers/productController.js +47 -0
- package/examples/mvc_routes_example/controllers/userController.js +76 -0
- package/examples/mvc_routes_example/routes.json +30 -0
- package/examples/mvc_routes_example/views/layout.html +31 -0
- package/examples/mvc_routes_example/views/main/index.html +11 -0
- package/examples/mvc_routes_example/views/product/catalog.html +24 -0
- package/examples/mvc_routes_example/views/user/invalid.html +6 -0
- package/examples/mvc_routes_example/views/user/list.html +40 -0
- package/examples/mvc_routes_example/views/user/notfound.html +6 -0
- package/examples/mvc_routes_example/views/user/profile.html +18 -0
- package/examples/public/README.md +92 -0
- package/examples/public/app.js +72 -0
- package/examples/public/controllers/healthController.js +20 -0
- package/examples/public/controllers/mainController.js +22 -0
- package/examples/public/controllers/userController.js +139 -0
- package/examples/public/routes.json +51 -0
- package/examples/v2/README.md +72 -0
- package/examples/v2/app.js +74 -0
- package/examples/v2/app_fixed.js +74 -0
- package/examples/v2/controllers/authController.js +64 -0
- package/examples/v2/controllers/mainController.js +24 -0
- package/examples/v2/controllers/protectedController.js +12 -0
- package/examples/v2/controllers/userController.js +16 -0
- package/examples/v2/package.json +27 -0
- package/examples/v2/routes.json +30 -0
- package/examples/v2/test_api.sh +47 -0
- package/examples/v2/tokens_example.sqlite +0 -0
- package/examples/v2.1_firewall_demo/README.md +113 -0
- package/examples/v2.1_firewall_demo/app.js +182 -0
- package/examples/v2.1_firewall_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/README.md +85 -0
- package/examples/v2.1_hooks_demo/app.js +101 -0
- package/examples/v2.1_hooks_demo/controllers/hooksController.js +29 -0
- package/examples/v2.1_hooks_demo/controllers/mainController.js +18 -0
- package/examples/v2.1_hooks_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/routes.json +16 -0
- package/examples/v2.1_openapi_demo/README.md +82 -0
- package/examples/v2.1_openapi_demo/app.js +296 -0
- package/examples/v2.1_openapi_demo/package.json +26 -0
- package/examples/v2_cors/README.md +82 -0
- package/examples/v2_cors/app.js +108 -0
- package/examples/v2_cors/package.json +23 -0
- package/examples/v2_json_auth/README.md +83 -0
- package/examples/v2_json_auth/app.js +72 -0
- package/examples/v2_json_auth/controllers/authController.js +67 -0
- package/examples/v2_json_auth/controllers/mainController.js +16 -0
- package/examples/v2_json_auth/controllers/protectedController.js +12 -0
- package/examples/v2_json_auth/controllers/tokenController.js +28 -0
- package/examples/v2_json_auth/controllers/userController.js +15 -0
- package/examples/v2_json_auth/package.json +26 -0
- package/examples/v2_json_auth/routes.json +37 -0
- package/examples/v2_json_auth/tokens.json +20 -0
- package/examples/v2_mariadb_auth/README.md +94 -0
- package/examples/v2_mariadb_auth/app.js +81 -0
- package/examples/v2_mariadb_auth/controllers/authController.js +95 -0
- package/examples/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/examples/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/examples/v2_mariadb_auth/controllers/userController.js +17 -0
- package/examples/v2_mariadb_auth/package.json +27 -0
- package/examples/v2_mariadb_auth/routes.json +37 -0
- package/examples/v2_no_auth/README.md +75 -0
- package/examples/v2_no_auth/app.js +72 -0
- package/examples/v2_no_auth/controllers/healthController.js +14 -0
- package/examples/v2_no_auth/controllers/mainController.js +19 -0
- package/examples/v2_no_auth/controllers/productController.js +31 -0
- package/examples/v2_no_auth/controllers/publicController.js +16 -0
- package/examples/v2_no_auth/package.json +22 -0
- package/examples/v2_no_auth/routes.json +37 -0
- package/examples/v2_oauth/README.md +70 -0
- package/examples/v2_oauth/app.js +90 -0
- package/examples/v2_oauth/controllers/mainController.js +45 -0
- package/examples/v2_oauth/controllers/oauthController.js +247 -0
- package/examples/v2_oauth/controllers/protectedController.js +13 -0
- package/examples/v2_oauth/controllers/userController.js +17 -0
- package/examples/v2_oauth/package.json +26 -0
- package/examples/v2_oauth/routes.json +44 -0
- package/examples/v2_openapi/README.md +77 -0
- package/examples/v2_openapi/app.js +222 -0
- package/examples/v2_openapi/controllers/authController.js +52 -0
- package/examples/v2_openapi/controllers/mainController.js +26 -0
- package/examples/v2_openapi/controllers/productController.js +17 -0
- package/examples/v2_openapi/controllers/userController.js +27 -0
- package/examples/v2_openapi/package.json +26 -0
- package/examples/v2_openapi/routes.json +37 -0
- package/generate_token.js +10 -0
- package/index.js +85 -0
- package/jerk.jpg +0 -0
- package/lib/core/handler.js +86 -0
- package/lib/core/hooks.js +224 -0
- package/lib/core/router.js +204 -0
- package/lib/core/securityEnhancedServer.js +752 -0
- package/lib/core/server.js +369 -0
- package/lib/loader/controllerLoader.js +175 -0
- package/lib/loader/routeLoader.js +341 -0
- package/lib/middleware/auditLogger.js +208 -0
- package/lib/middleware/authenticator.js +565 -0
- package/lib/middleware/compressor.js +218 -0
- package/lib/middleware/cors.js +135 -0
- package/lib/middleware/firewall.js +443 -0
- package/lib/middleware/rateLimiter.js +210 -0
- package/lib/middleware/session.js +301 -0
- package/lib/middleware/validator.js +193 -0
- package/lib/mvc/controllerBase.js +207 -0
- package/lib/mvc/viewEngine.js +752 -0
- package/lib/utils/configParser.js +223 -0
- package/lib/utils/logger.js +145 -0
- package/lib/utils/mariadbTokenAdapter.js +226 -0
- package/lib/utils/openapiGenerator.js +140 -0
- package/lib/utils/sqliteTokenAdapter.js +224 -0
- package/lib/utils/tokenManager.js +254 -0
- package/package.json +47 -0
- package/v2examplle/v2_json_auth/README.md +83 -0
- package/v2examplle/v2_json_auth/app.js +72 -0
- package/v2examplle/v2_json_auth/controllers/authController.js +67 -0
- package/v2examplle/v2_json_auth/controllers/mainController.js +16 -0
- package/v2examplle/v2_json_auth/controllers/protectedController.js +12 -0
- package/v2examplle/v2_json_auth/controllers/tokenController.js +28 -0
- package/v2examplle/v2_json_auth/controllers/userController.js +15 -0
- package/v2examplle/v2_json_auth/package.json +26 -0
- package/v2examplle/v2_json_auth/routes.json +37 -0
- package/v2examplle/v2_json_auth/tokens.json +20 -0
- package/v2examplle/v2_mariadb_auth/README.md +94 -0
- package/v2examplle/v2_mariadb_auth/app.js +81 -0
- package/v2examplle/v2_mariadb_auth/controllers/authController.js +95 -0
- package/v2examplle/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/v2examplle/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/v2examplle/v2_mariadb_auth/controllers/userController.js +17 -0
- package/v2examplle/v2_mariadb_auth/package.json +27 -0
- package/v2examplle/v2_mariadb_auth/routes.json +37 -0
- package/v2examplle/v2_sqlite_auth/README.md +72 -0
- package/v2examplle/v2_sqlite_auth/app.js +74 -0
- package/v2examplle/v2_sqlite_auth/app_fixed.js +74 -0
- package/v2examplle/v2_sqlite_auth/controllers/authController.js +64 -0
- package/v2examplle/v2_sqlite_auth/controllers/mainController.js +24 -0
- package/v2examplle/v2_sqlite_auth/controllers/protectedController.js +12 -0
- package/v2examplle/v2_sqlite_auth/controllers/userController.js +16 -0
- package/v2examplle/v2_sqlite_auth/package.json +27 -0
- package/v2examplle/v2_sqlite_auth/routes.json +30 -0
- package/v2examplle/v2_sqlite_auth/test_api.sh +47 -0
- package/v2examplle/v2_sqlite_auth/tokens_example.sqlite +0 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# Manual del Sistema MVC para API SDK Framework
|
|
2
|
+
|
|
3
|
+
Visita nuestra página web: https://jerk.page.gd/
|
|
4
|
+
Repositorio oficial: https://gitlab.com/bytedogssyndicate1/jerk/
|
|
5
|
+
|
|
6
|
+
## Índice
|
|
7
|
+
1. [Introducción](#introducción)
|
|
8
|
+
2. [Arquitectura MVC](#arquitectura-mvc)
|
|
9
|
+
3. [Componentes del Sistema MVC](#componentes-del-sistema-mvc)
|
|
10
|
+
4. [Motor de Vistas (ViewEngine)](#motor-de-vistas-viewengine)
|
|
11
|
+
5. [Controladores Base (ControllerBase)](#controladores-base-controllerbase)
|
|
12
|
+
6. [Sintaxis de Plantillas](#sintaxis-de-plantillas)
|
|
13
|
+
7. [Hooks, Filters y Actions](#hooks-filters-y-actions)
|
|
14
|
+
8. [Ejemplos de Uso](#ejemplos-de-uso)
|
|
15
|
+
9. [Mejores Prácticas](#mejores-prácticas)
|
|
16
|
+
|
|
17
|
+
## Introducción
|
|
18
|
+
|
|
19
|
+
El sistema MVC (Modelo-Vista-Controlador) para el API SDK Framework proporciona una arquitectura organizada para desarrollar aplicaciones web. Este sistema permite separar la lógica de negocio, la presentación y el flujo de control de manera limpia y mantenible.
|
|
20
|
+
|
|
21
|
+
## Arquitectura MVC
|
|
22
|
+
|
|
23
|
+
La arquitectura MVC se divide en tres componentes principales:
|
|
24
|
+
|
|
25
|
+
- **Modelo**: Representa los datos y la lógica de negocio (manejado por el desarrollador)
|
|
26
|
+
- **Vista**: Presenta la información al usuario (manejado por el ViewEngine)
|
|
27
|
+
- **Controlador**: Coordina la interacción entre Modelo y Vista (manejado por ControllerBase)
|
|
28
|
+
|
|
29
|
+
## Componentes del Sistema MVC
|
|
30
|
+
|
|
31
|
+
### ViewEngine
|
|
32
|
+
Motor de vistas robusto que procesa plantillas con soporte para:
|
|
33
|
+
- Variables simples y anidadas
|
|
34
|
+
- Condiciones y bucles
|
|
35
|
+
- Filtros personalizables
|
|
36
|
+
- Hooks para extensibilidad
|
|
37
|
+
- Inclusiones de vistas
|
|
38
|
+
|
|
39
|
+
### ControllerBase
|
|
40
|
+
Clase base para controladores que proporciona:
|
|
41
|
+
- Métodos para pasar datos a vistas
|
|
42
|
+
- Renderizado de vistas
|
|
43
|
+
- Manejo de solicitudes y respuestas
|
|
44
|
+
- Acceso a parámetros de entrada
|
|
45
|
+
|
|
46
|
+
## Motor de Vistas (ViewEngine)
|
|
47
|
+
|
|
48
|
+
### Configuración
|
|
49
|
+
```javascript
|
|
50
|
+
const viewEngine = new ViewEngine({
|
|
51
|
+
viewsPath: './views', // Ruta a las vistas
|
|
52
|
+
defaultExtension: '.html', // Extensión por defecto
|
|
53
|
+
cacheEnabled: true // Habilitar cache
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Renderizado de Vistas
|
|
58
|
+
```javascript
|
|
59
|
+
// Renderizar una vista con datos
|
|
60
|
+
const html = viewEngine.render('home/index', {
|
|
61
|
+
title: 'Mi Aplicación',
|
|
62
|
+
users: [{name: 'Juan', email: 'juan@example.com'}]
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Controladores Base (ControllerBase)
|
|
67
|
+
|
|
68
|
+
### Extender ControllerBase
|
|
69
|
+
```javascript
|
|
70
|
+
const { ControllerBase } = require('@jerkjs');
|
|
71
|
+
|
|
72
|
+
class HomeController extends ControllerBase {
|
|
73
|
+
constructor(options = {}) {
|
|
74
|
+
super(options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
index(req, res) {
|
|
78
|
+
this.set('title', 'Página de Inicio');
|
|
79
|
+
this.set('message', '¡Bienvenido!');
|
|
80
|
+
|
|
81
|
+
this.render(res, 'home/index', {
|
|
82
|
+
currentTime: new Date()
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Métodos Disponibles
|
|
89
|
+
- `set(key, value)`: Establece variables para la vista
|
|
90
|
+
- `render(res, viewName, data)`: Renderiza y envía una vista como respuesta
|
|
91
|
+
- `view(viewName, data)`: Renderiza una vista y retorna el HTML
|
|
92
|
+
- `input(key, defaultValue)`: Obtiene valores de la solicitud
|
|
93
|
+
- `redirect(res, url)`: Redirecciona a otra URL
|
|
94
|
+
- `json(res, data)`: Envía una respuesta JSON
|
|
95
|
+
|
|
96
|
+
## Sintaxis de Plantillas
|
|
97
|
+
|
|
98
|
+
### Variables
|
|
99
|
+
```html
|
|
100
|
+
<h1>{{title}}</h1>
|
|
101
|
+
<p>{{user.name}}</p>
|
|
102
|
+
<p>{{user.profile.email}}</p>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Condiciones
|
|
106
|
+
```html
|
|
107
|
+
{{if user.active}}
|
|
108
|
+
<span class="active">Activo</span>
|
|
109
|
+
{{else}}
|
|
110
|
+
<span class="inactive">Inactivo</span>
|
|
111
|
+
{{endif}}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Bucles
|
|
115
|
+
```html
|
|
116
|
+
{{foreach:users}}
|
|
117
|
+
<div>
|
|
118
|
+
<h3>{{item.name}}</h3>
|
|
119
|
+
<p>{{item.email}}</p>
|
|
120
|
+
</div>
|
|
121
|
+
{{endforeach}}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Inclusiones
|
|
125
|
+
```html
|
|
126
|
+
{{include:header}}
|
|
127
|
+
{{include:./partials/navigation}}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Filtros
|
|
131
|
+
```html
|
|
132
|
+
<p>{{user.name|upper}}</p>
|
|
133
|
+
<p>{{user.bio|escape}}</p>
|
|
134
|
+
<p>{{post.date|date:'DD/MM/YYYY'}}</p>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Hooks, Filters y Actions
|
|
138
|
+
|
|
139
|
+
### Filtros Disponibles
|
|
140
|
+
- `escape`: Escapa caracteres HTML
|
|
141
|
+
- `upper`: Convierte a mayúsculas
|
|
142
|
+
- `lower`: Convierte a minúsculas
|
|
143
|
+
- `capitalize`: Capitaliza texto
|
|
144
|
+
- `date`: Formatea fechas
|
|
145
|
+
|
|
146
|
+
### Agregar Filtros Personalizados
|
|
147
|
+
```javascript
|
|
148
|
+
viewEngine.addFilter('truncate', (value, length = 100) => {
|
|
149
|
+
if (typeof value !== 'string') return value;
|
|
150
|
+
return value.length > length ? value.substring(0, length) + '...' : value;
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Agregar Helpers Personalizados
|
|
155
|
+
```javascript
|
|
156
|
+
// Registrar un helper para formatear fechas
|
|
157
|
+
viewEngine.addHelper('formatDate', (date, format = 'YYYY-MM-DD HH:mm:ss') => {
|
|
158
|
+
if (!date) return '';
|
|
159
|
+
const d = new Date(date);
|
|
160
|
+
if (isNaN(d.getTime())) return date;
|
|
161
|
+
|
|
162
|
+
const pad = (n) => n.toString().padStart(2, '0');
|
|
163
|
+
const padYear = (n) => n.toString().padStart(4, '0');
|
|
164
|
+
|
|
165
|
+
return format
|
|
166
|
+
.replace('YYYY', padYear(d.getFullYear()))
|
|
167
|
+
.replace('MM', pad(d.getMonth() + 1))
|
|
168
|
+
.replace('DD', pad(d.getDate()))
|
|
169
|
+
.replace('HH', pad(d.getHours()))
|
|
170
|
+
.replace('mm', pad(d.getMinutes()))
|
|
171
|
+
.replace('ss', pad(d.getSeconds()));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Registrar un helper para verificar si un número es par
|
|
175
|
+
viewEngine.addHelper('isEven', (value) => {
|
|
176
|
+
return Number(value) % 2 === 0;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Registrar un helper para contar elementos
|
|
180
|
+
viewEngine.addHelper('count', (array) => {
|
|
181
|
+
return Array.isArray(array) ? array.length : 0;
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Uso de Helpers en Plantillas
|
|
186
|
+
```html
|
|
187
|
+
<!-- Usar helper para formatear fecha -->
|
|
188
|
+
<p>Fecha de registro: {{formatDate(user.registered, 'DD/MM/YYYY')}}</p>
|
|
189
|
+
|
|
190
|
+
<!-- Usar helper para verificar si un número es par -->
|
|
191
|
+
{{if isEven(user.id)}}
|
|
192
|
+
<span class="even-id">ID Par</span>
|
|
193
|
+
{{else}}
|
|
194
|
+
<span class="odd-id">ID Impar</span>
|
|
195
|
+
{{endif}}
|
|
196
|
+
|
|
197
|
+
<!-- Usar helper para contar elementos -->
|
|
198
|
+
<p>Total de usuarios: {{count(users)}}</p>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Validación de Sintaxis de Plantillas
|
|
202
|
+
```javascript
|
|
203
|
+
// Validar un template antes de renderizarlo
|
|
204
|
+
const template = `
|
|
205
|
+
<h1>{{title}}</h1>
|
|
206
|
+
{{if users}}
|
|
207
|
+
{{foreach:users}}
|
|
208
|
+
<div>{{item.name}}</div>
|
|
209
|
+
{{endforeach}}
|
|
210
|
+
{{endif}}
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
const errors = ViewEngine.validateTemplate(template);
|
|
214
|
+
if (errors.length > 0) {
|
|
215
|
+
console.warn('Errores de sintaxis encontrados:', errors);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Opciones de Renderizado
|
|
220
|
+
```javascript
|
|
221
|
+
// Renderizar con opciones de validación y advertencias
|
|
222
|
+
const html = viewEngine.render('home/index', {
|
|
223
|
+
title: 'Mi Aplicación',
|
|
224
|
+
users: [{name: 'Juan', email: 'juan@example.com'}]
|
|
225
|
+
}, {
|
|
226
|
+
validateSyntax: true, // Validar sintaxis del template
|
|
227
|
+
showWarnings: true, // Mostrar advertencias sobre variables no definidas
|
|
228
|
+
preserveUndefined: false // Qué hacer con variables no definidas
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Ejemplos de Uso
|
|
233
|
+
|
|
234
|
+
### Ejemplo Completo de Controlador
|
|
235
|
+
```javascript
|
|
236
|
+
const { ControllerBase } = require('@jerkjs');
|
|
237
|
+
|
|
238
|
+
class UserController extends ControllerBase {
|
|
239
|
+
constructor(options = {}) {
|
|
240
|
+
super(options);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Mostrar lista de usuarios
|
|
244
|
+
index(req, res) {
|
|
245
|
+
const users = [
|
|
246
|
+
{ id: 1, name: 'Ana', email: 'ana@example.com', active: true },
|
|
247
|
+
{ id: 2, name: 'Carlos', email: 'carlos@example.com', active: false }
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
this.set('title', 'Lista de Usuarios');
|
|
251
|
+
this.set('users', users);
|
|
252
|
+
|
|
253
|
+
this.render(res, 'users/list');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Mostrar perfil de usuario
|
|
257
|
+
profile(req, res) {
|
|
258
|
+
const userId = parseInt(this.input('id'));
|
|
259
|
+
|
|
260
|
+
if (!userId || userId <= 0) {
|
|
261
|
+
this.set('title', 'ID Inválido');
|
|
262
|
+
this.render(res, 'users/invalid', { userId: this.input('id') });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const users = [
|
|
267
|
+
{ id: 1, name: 'Ana', email: 'ana@example.com', registered: '2026-01-01' },
|
|
268
|
+
{ id: 2, name: 'Carlos', email: 'carlos@example.com', registered: '2026-01-02' }
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
const user = users.find(u => u.id === userId);
|
|
272
|
+
|
|
273
|
+
if (!user) {
|
|
274
|
+
this.set('title', 'Usuario No Encontrado');
|
|
275
|
+
this.render(res, 'users/notfound', { userId });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
this.set('title', `Perfil de ${user.name}`);
|
|
280
|
+
this.set('user', user);
|
|
281
|
+
|
|
282
|
+
this.render(res, 'users/profile');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Ejemplo de Uso de Helpers y Filtros
|
|
288
|
+
```javascript
|
|
289
|
+
class ProductController extends ControllerBase {
|
|
290
|
+
constructor(options = {}) {
|
|
291
|
+
super(options);
|
|
292
|
+
|
|
293
|
+
// Registrar helpers personalizados para este controlador
|
|
294
|
+
this.getViewEngine().addHelper('calculateDiscount', (price, discountPercent) => {
|
|
295
|
+
return price - (price * discountPercent / 100);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
this.getViewEngine().addFilter('currency', (value, symbol = '$') => {
|
|
299
|
+
return `${symbol}${Number(value).toFixed(2)}`;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
products(req, res) {
|
|
304
|
+
const products = [
|
|
305
|
+
{ id: 1, name: 'Producto A', price: 100, discount: 10 },
|
|
306
|
+
{ id: 2, name: 'Producto B', price: 200, discount: 15 }
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
this.set('title', 'Catálogo de Productos');
|
|
310
|
+
this.set('products', products);
|
|
311
|
+
|
|
312
|
+
this.render(res, 'products/catalog');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Vista con Helpers y Filtros (products/catalog.html)
|
|
318
|
+
```html
|
|
319
|
+
<h1>{{title}}</h1>
|
|
320
|
+
|
|
321
|
+
{{if products}}
|
|
322
|
+
<div class="product-grid">
|
|
323
|
+
{{foreach:products}}
|
|
324
|
+
<div class="product-card">
|
|
325
|
+
<h3>{{item.name}}</h3>
|
|
326
|
+
<p>Precio original: {{item.price|currency}}</p>
|
|
327
|
+
<p>Descuento: {{item.discount}}%</p>
|
|
328
|
+
<p>Precio con descuento: {{calculateDiscount(item.price, item.discount)|currency}}</p>
|
|
329
|
+
</div>
|
|
330
|
+
{{endforeach}}
|
|
331
|
+
</div>
|
|
332
|
+
{{else}}
|
|
333
|
+
<p>No hay productos disponibles.</p>
|
|
334
|
+
{{endif}}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Vista de Lista de Usuarios (users/list.html)
|
|
338
|
+
```html
|
|
339
|
+
<h1>{{title}}</h1>
|
|
340
|
+
|
|
341
|
+
{{if users}}
|
|
342
|
+
<table>
|
|
343
|
+
<thead>
|
|
344
|
+
<tr>
|
|
345
|
+
<th>ID</th>
|
|
346
|
+
<th>Nombre</th>
|
|
347
|
+
<th>Email</th>
|
|
348
|
+
<th>Estado</th>
|
|
349
|
+
<th>Acciones</th>
|
|
350
|
+
</tr>
|
|
351
|
+
</thead>
|
|
352
|
+
<tbody>
|
|
353
|
+
{{foreach:users}}
|
|
354
|
+
<tr>
|
|
355
|
+
<td>{{item.id}}</td>
|
|
356
|
+
<td>{{item.name}}</td>
|
|
357
|
+
<td>{{item.email}}</td>
|
|
358
|
+
<td>
|
|
359
|
+
{{if item.active}}
|
|
360
|
+
<span class="active">Activo</span>
|
|
361
|
+
{{else}}
|
|
362
|
+
<span class="inactive">Inactivo</span>
|
|
363
|
+
{{endif}}
|
|
364
|
+
</td>
|
|
365
|
+
<td><a href="/profile?id={{item.id}}">Ver Perfil</a></td>
|
|
366
|
+
</tr>
|
|
367
|
+
{{endforeach}}
|
|
368
|
+
</tbody>
|
|
369
|
+
</table>
|
|
370
|
+
{{else}}
|
|
371
|
+
<p>No hay usuarios registrados.</p>
|
|
372
|
+
{{endif}}
|
|
373
|
+
|
|
374
|
+
<a href="/">Volver al inicio</a>
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Mejores Prácticas
|
|
378
|
+
|
|
379
|
+
1. **Organización de Archivos**:
|
|
380
|
+
- Colocar vistas en `./views/nombre_modulo/nombre_vista.html`
|
|
381
|
+
- Nombrar controladores con sufijo `Controller`
|
|
382
|
+
- Usar convención de nombres en minúsculas con guiones bajos
|
|
383
|
+
|
|
384
|
+
2. **Seguridad**:
|
|
385
|
+
- Siempre validar entradas de usuario
|
|
386
|
+
- Usar el filtro `|escape` para mostrar datos de usuario
|
|
387
|
+
- Validar IDs y parámetros antes de usarlos
|
|
388
|
+
|
|
389
|
+
3. **Rendimiento**:
|
|
390
|
+
- Habilitar cache de vistas en producción
|
|
391
|
+
- Minimizar la lógica en vistas
|
|
392
|
+
- Usar datos eficientes en bucles
|
|
393
|
+
|
|
394
|
+
4. **Mantenibilidad**:
|
|
395
|
+
- Separar lógica compleja en métodos del controlador
|
|
396
|
+
- Usar vistas parciales para componentes repetitivos
|
|
397
|
+
- Documentar controladores y vistas según sea necesario
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Implementación Completa: API SDK Framework v2.0 con Tokens en MariaDB
|
|
2
|
+
|
|
3
|
+
Visita nuestra página web: https://jerk.page.gd/
|
|
4
|
+
Repositorio oficial: https://gitlab.com/bytedogssyndicate1/jerk/
|
|
5
|
+
|
|
6
|
+
## Resumen Ejecutivo
|
|
7
|
+
|
|
8
|
+
Hemos implementado exitosamente una solución completa de gestión de tokens con MariaDB para el API SDK Framework v2.0, demostrando:
|
|
9
|
+
|
|
10
|
+
✅ **Conexión funcional a MariaDB**
|
|
11
|
+
✅ **Almacenamiento seguro de tokens JWT**
|
|
12
|
+
✅ **Validación en tiempo real contra base de datos**
|
|
13
|
+
✅ **Revocación de tokens**
|
|
14
|
+
✅ **Soporte para tokens de acceso y refresh**
|
|
15
|
+
✅ **Gestión de expiración automática**
|
|
16
|
+
|
|
17
|
+
## Componentes Implementados
|
|
18
|
+
|
|
19
|
+
### 1. Adaptador de Tokens para MariaDB (`lib/utils/mariadbTokenAdapter.js`)
|
|
20
|
+
- Conexión robusta a MariaDB usando pooling
|
|
21
|
+
- Almacenamiento seguro de tokens con índices
|
|
22
|
+
- Validación en tiempo real
|
|
23
|
+
- Revocación de tokens
|
|
24
|
+
- Gestión de expiración
|
|
25
|
+
|
|
26
|
+
### 2. Base de Datos
|
|
27
|
+
- Base de datos `token_api_db` creada
|
|
28
|
+
- Tabla `tokens` con estructura optimizada:
|
|
29
|
+
- `id`: Identificador único
|
|
30
|
+
- `token`: Token JWT almacenado
|
|
31
|
+
- `user_id`: ID del usuario propietario
|
|
32
|
+
- `token_type`: Tipo (access/refresh)
|
|
33
|
+
- `expires_at`: Fecha de expiración
|
|
34
|
+
- `revoked`: Indicador de revocación
|
|
35
|
+
|
|
36
|
+
### 3. Funcionalidades Clave
|
|
37
|
+
|
|
38
|
+
#### Almacenamiento Seguro
|
|
39
|
+
```sql
|
|
40
|
+
-- Tokens almacenados encriptados en base de datos
|
|
41
|
+
INSERT INTO tokens (token, user_id, token_type, expires_at) VALUES (?, ?, ?, ?);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
#### Validación en Tiempo Real
|
|
45
|
+
```javascript
|
|
46
|
+
// Validación instantánea contra la base de datos
|
|
47
|
+
const tokenRecord = await tokenAdapter.validateToken(token);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### Revocación Inmediata
|
|
51
|
+
```javascript
|
|
52
|
+
// Revocación que se refleja inmediatamente
|
|
53
|
+
await tokenAdapter.revokeToken(token);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Expiración Automática
|
|
57
|
+
```sql
|
|
58
|
+
-- Consultas que consideran tokens expirados
|
|
59
|
+
WHERE expires_at > NOW() AND revoked = FALSE
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Pruebas Realizadas
|
|
63
|
+
|
|
64
|
+
### 1. Prueba de Conexión
|
|
65
|
+
- ✅ Conexión estable a MariaDB
|
|
66
|
+
- ✅ Creación automática de base de datos y tablas
|
|
67
|
+
|
|
68
|
+
### 2. Prueba de Almacenamiento
|
|
69
|
+
- ✅ Almacenamiento de tokens JWT
|
|
70
|
+
- ✅ Diferenciación entre access y refresh tokens
|
|
71
|
+
|
|
72
|
+
### 3. Prueba de Validación
|
|
73
|
+
- ✅ Validación correcta de tokens válidos
|
|
74
|
+
- ✅ Rechazo de tokens inexistentes
|
|
75
|
+
|
|
76
|
+
### 4. Prueba de Expiración
|
|
77
|
+
- ✅ Detección de tokens expirados
|
|
78
|
+
- ✅ No validez de tokens fuera de tiempo
|
|
79
|
+
|
|
80
|
+
### 5. Prueba de Revocación
|
|
81
|
+
- ✅ Revocación efectiva de tokens
|
|
82
|
+
- ✅ No validez posterior a la revocación
|
|
83
|
+
|
|
84
|
+
## Beneficios de la Solución
|
|
85
|
+
|
|
86
|
+
### Seguridad
|
|
87
|
+
- Tokens almacenados en base de datos en lugar de memoria
|
|
88
|
+
- Posibilidad de revocación inmediata
|
|
89
|
+
- Validación en tiempo real
|
|
90
|
+
|
|
91
|
+
### Escalabilidad
|
|
92
|
+
- Uso de connection pooling
|
|
93
|
+
- Índices para búsquedas rápidas
|
|
94
|
+
- Gestión eficiente de recursos
|
|
95
|
+
|
|
96
|
+
### Control
|
|
97
|
+
- Visibilidad completa de tokens activos
|
|
98
|
+
- Auditoría de tokens por usuario
|
|
99
|
+
- Gestión centralizada
|
|
100
|
+
|
|
101
|
+
## Uso en Aplicaciones Reales
|
|
102
|
+
|
|
103
|
+
La implementación permite:
|
|
104
|
+
|
|
105
|
+
1. **Login seguro** con generación de tokens almacenados en MariaDB
|
|
106
|
+
2. **Acceso protegido** con validación contra base de datos
|
|
107
|
+
3. **Renovación automática** de tokens expirados
|
|
108
|
+
4. **Revocación inmediata** de tokens comprometidos
|
|
109
|
+
5. **Auditoría completa** de tokens por usuario
|
|
110
|
+
|
|
111
|
+
## Conclusión
|
|
112
|
+
|
|
113
|
+
La implementación de tokens en MariaDB para el API SDK Framework v2.0 está **completa, funcional y lista para producción**, ofreciendo un nivel superior de seguridad y control sobre la autenticación basada en tokens.
|