jerkjs 2.0.1 → 2.0.2
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/README.md +4 -6
- package/docs/EXTENSION_MANUAL.md +955 -0
- package/docs/FIREWALL_MANUAL.md +416 -0
- package/docs/HOOKS_REFERENCE_IMPROVED.md +596 -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/frontend-and-sessions.md +6 -6
- 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/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/mvc_welcome/README.md +34 -0
- package/examples/mvc_welcome/app.js +50 -0
- package/examples/mvc_welcome/controllers/welcomeController.js +41 -0
- package/examples/mvc_welcome/package.json +26 -0
- package/examples/mvc_welcome/views/home/welcome.html +82 -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/index.js +11 -3
- package/lib/core/handler.js +1 -1
- package/lib/core/hooks.js +1 -1
- package/lib/core/router.js +1 -1
- package/lib/core/server.js +1 -1
- package/lib/loader/controllerLoader.js +1 -1
- package/lib/loader/routeLoader.js +1 -1
- package/lib/middleware/auditLogger.js +1 -1
- package/lib/middleware/authenticator.js +1 -1
- package/lib/middleware/compressor.js +1 -1
- package/lib/middleware/cors.js +1 -1
- package/lib/middleware/firewall.js +1 -1
- package/lib/middleware/rateLimiter.js +1 -1
- package/lib/middleware/session.js +1 -1
- package/lib/middleware/validator.js +1 -1
- package/lib/mvc/controllerBase.js +207 -0
- package/lib/mvc/viewEngine.js +752 -0
- package/lib/utils/configParser.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/openapiGenerator.js +1 -1
- package/lib/utils/tokenManager.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const { ControllerBase } = require('../../../index');
|
|
2
|
+
|
|
3
|
+
class UserController extends ControllerBase {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
list(req, res) {
|
|
9
|
+
const users = [
|
|
10
|
+
{ id: 1, name: 'Ana García', email: 'ana@example.com', registered: '2026-01-01', active: true },
|
|
11
|
+
{ id: 2, name: 'Carlos López', email: 'carlos@example.com', registered: '2026-01-02', active: false },
|
|
12
|
+
{ id: 3, name: 'Laura Martínez', email: 'laura@example.com', registered: '2026-01-03', active: true },
|
|
13
|
+
{ id: 4, name: 'Pedro Rodríguez', email: 'pedro@example.com', registered: '2026-01-04', active: true },
|
|
14
|
+
{ id: 5, name: 'María Sánchez', email: 'maria@example.com', registered: '2026-01-05', active: false }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
this.set('title', 'Lista de Usuarios');
|
|
18
|
+
this.set('users', users);
|
|
19
|
+
|
|
20
|
+
this.render(res, 'user/list', {
|
|
21
|
+
totalUsers: users.length
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
profile(req, res) {
|
|
26
|
+
const userIdParam = this.input('id', '1');
|
|
27
|
+
|
|
28
|
+
// Validar que el ID sea un número entero positivo
|
|
29
|
+
if (!/^\d+$/.test(userIdParam) || parseInt(userIdParam) <= 0) {
|
|
30
|
+
this.set('title', 'ID de usuario inválido');
|
|
31
|
+
this.render(res, 'user/invalid', {
|
|
32
|
+
userId: userIdParam
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const userId = parseInt(userIdParam);
|
|
38
|
+
|
|
39
|
+
const users = [
|
|
40
|
+
{ id: 1, name: 'Ana García', email: 'ana@example.com', registered: '2026-01-01', active: true },
|
|
41
|
+
{ id: 2, name: 'Carlos López', email: 'carlos@example.com', registered: '2026-01-02', active: false },
|
|
42
|
+
{ id: 3, name: 'Laura Martínez', email: 'laura@example.com', registered: '2026-01-03', active: true },
|
|
43
|
+
{ id: 4, name: 'Pedro Rodríguez', email: 'pedro@example.com', registered: '2026-01-04', active: true },
|
|
44
|
+
{ id: 5, name: 'María Sánchez', email: 'maria@example.com', registered: '2026-01-05', active: false }
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const user = users.find(u => u.id === userId);
|
|
48
|
+
|
|
49
|
+
if (!user) {
|
|
50
|
+
this.set('title', 'Usuario no encontrado');
|
|
51
|
+
this.render(res, 'user/notfound', {
|
|
52
|
+
userId: userId
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.set('title', `Perfil de ${user.name}`);
|
|
58
|
+
this.set('user', user);
|
|
59
|
+
|
|
60
|
+
this.render(res, 'user/profile');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Exportar métodos directamente para que el RouteLoader pueda acceder a ellos
|
|
65
|
+
const controllerInstance = new UserController({ viewsPath: './examples/mvc_routes_example/views' });
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
list: (req, res) => {
|
|
69
|
+
controllerInstance.setRequestResponse(req, res);
|
|
70
|
+
controllerInstance.list(req, res);
|
|
71
|
+
},
|
|
72
|
+
profile: (req, res) => {
|
|
73
|
+
controllerInstance.setRequestResponse(req, res);
|
|
74
|
+
controllerInstance.profile(req, res);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"method": "GET",
|
|
4
|
+
"path": "/",
|
|
5
|
+
"controller": "./examples/mvc_routes_example/controllers/mainController.js",
|
|
6
|
+
"handler": "index",
|
|
7
|
+
"auth": "none"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"method": "GET",
|
|
11
|
+
"path": "/users",
|
|
12
|
+
"controller": "./examples/mvc_routes_example/controllers/userController.js",
|
|
13
|
+
"handler": "list",
|
|
14
|
+
"auth": "none"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"method": "GET",
|
|
18
|
+
"path": "/profile",
|
|
19
|
+
"controller": "./examples/mvc_routes_example/controllers/userController.js",
|
|
20
|
+
"handler": "profile",
|
|
21
|
+
"auth": "none"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"method": "GET",
|
|
25
|
+
"path": "/products",
|
|
26
|
+
"controller": "./examples/mvc_routes_example/controllers/productController.js",
|
|
27
|
+
"handler": "catalog",
|
|
28
|
+
"auth": "none"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }
|
|
9
|
+
.container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|
10
|
+
h1 { color: #333; }
|
|
11
|
+
nav { margin: 20px 0; }
|
|
12
|
+
nav a { margin-right: 15px; text-decoration: none; color: #007bff; }
|
|
13
|
+
nav a:hover { text-decoration: underline; }
|
|
14
|
+
</style>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<div class="container">
|
|
18
|
+
<h1>{{title}}</h1>
|
|
19
|
+
<p>{{message}}</p>
|
|
20
|
+
|
|
21
|
+
<nav>
|
|
22
|
+
<a href="/">Inicio</a>
|
|
23
|
+
<a href="/users">Usuarios</a>
|
|
24
|
+
<a href="/products">Productos</a>
|
|
25
|
+
</nav>
|
|
26
|
+
|
|
27
|
+
<p>Versión: {{version}}</p>
|
|
28
|
+
<p>Hora actual: {{currentTime}}</p>
|
|
29
|
+
</div>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<h1>{{title}}</h1>
|
|
2
|
+
|
|
3
|
+
{{if products}}
|
|
4
|
+
<div class="product-grid">
|
|
5
|
+
{{foreach:products}}
|
|
6
|
+
<div class="product-card">
|
|
7
|
+
<h3>{{item.name}}</h3>
|
|
8
|
+
<p>Categoría: {{item.category}}</p>
|
|
9
|
+
<p>Precio original: {{formatCurrency(item.price)}}</p>
|
|
10
|
+
<p>Descuento: {{item.discount}}%</p>
|
|
11
|
+
{{if item.discount > 0}}
|
|
12
|
+
<p>Precio con descuento: {{formatCurrency(calculateDiscount(item.price, item.discount))}}</p>
|
|
13
|
+
<p class="onsale">¡En oferta!</p>
|
|
14
|
+
{{else}}
|
|
15
|
+
<p class="regular">Precio regular</p>
|
|
16
|
+
{{endif}}
|
|
17
|
+
</div>
|
|
18
|
+
{{endforeach}}
|
|
19
|
+
</div>
|
|
20
|
+
{{else}}
|
|
21
|
+
<p>No hay productos disponibles.</p>
|
|
22
|
+
{{endif}}
|
|
23
|
+
|
|
24
|
+
<a href="/">Volver al inicio</a>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<h1>{{title}}</h1>
|
|
2
|
+
|
|
3
|
+
{{if users}}
|
|
4
|
+
<p>Total de usuarios: {{totalUsers}}</p>
|
|
5
|
+
|
|
6
|
+
<table>
|
|
7
|
+
<thead>
|
|
8
|
+
<tr>
|
|
9
|
+
<th>ID</th>
|
|
10
|
+
<th>Nombre</th>
|
|
11
|
+
<th>Email</th>
|
|
12
|
+
<th>Registrado</th>
|
|
13
|
+
<th>Estado</th>
|
|
14
|
+
<th>Acciones</th>
|
|
15
|
+
</tr>
|
|
16
|
+
</thead>
|
|
17
|
+
<tbody>
|
|
18
|
+
{{foreach:users}}
|
|
19
|
+
<tr>
|
|
20
|
+
<td>{{item.id}}</td>
|
|
21
|
+
<td>{{item.name}}</td>
|
|
22
|
+
<td>{{item.email}}</td>
|
|
23
|
+
<td>{{item.registered|date:'DD/MM/YYYY'}}</td>
|
|
24
|
+
<td>
|
|
25
|
+
{{if item.active}}
|
|
26
|
+
<span class="active">Activo</span>
|
|
27
|
+
{{else}}
|
|
28
|
+
<span class="inactive">Inactivo</span>
|
|
29
|
+
{{endif}}
|
|
30
|
+
</td>
|
|
31
|
+
<td><a href="/profile?id={{item.id}}">Ver Perfil</a></td>
|
|
32
|
+
</tr>
|
|
33
|
+
{{endforeach}}
|
|
34
|
+
</tbody>
|
|
35
|
+
</table>
|
|
36
|
+
{{else}}
|
|
37
|
+
<p>No hay usuarios registrados.</p>
|
|
38
|
+
{{endif}}
|
|
39
|
+
|
|
40
|
+
<a href="/">Volver al inicio</a>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<h1>{{title}}</h1>
|
|
2
|
+
|
|
3
|
+
<div>
|
|
4
|
+
<h2>Información del Usuario</h2>
|
|
5
|
+
<p><strong>ID:</strong> {{user.id}}</p>
|
|
6
|
+
<p><strong>Nombre:</strong> {{user.name}}</p>
|
|
7
|
+
<p><strong>Email:</strong> {{user.email}}</p>
|
|
8
|
+
<p><strong>Registrado:</strong> {{user.registered|date:'DD/MM/YYYY'}}</p>
|
|
9
|
+
<p><strong>Estado:</strong>
|
|
10
|
+
{{if user.active}}
|
|
11
|
+
<span class="active">Activo</span>
|
|
12
|
+
{{else}}
|
|
13
|
+
<span class="inactive">Inactivo</span>
|
|
14
|
+
{{endif}}
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<a href="/users">Volver a la lista de usuarios</a>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Ejemplo de Página de Bienvenida con Motor MVC
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo usar el motor de plantillas MVC del framework JERK para crear una página de bienvenida atractiva y funcional.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- **Sistema MVC**: Uso completo del sistema de vistas, controladores y modelos
|
|
8
|
+
- **Motor de Plantillas**: Uso del motor de plantillas con soporte para variables, condicionales y bucles
|
|
9
|
+
- **Vistas Dinámicas**: Renderizado de contenido dinámico desde el controlador
|
|
10
|
+
- **Estilos Modernos**: Diseño responsive y atractivo
|
|
11
|
+
|
|
12
|
+
## Componentes
|
|
13
|
+
|
|
14
|
+
- `app.js`: Archivo principal que configura el servidor y las rutas
|
|
15
|
+
- `controllers/welcomeController.js`: Controlador que maneja la lógica del sitio
|
|
16
|
+
- `views/home/welcome.html`: Vista principal con el diseño de la página de bienvenida
|
|
17
|
+
|
|
18
|
+
## Uso
|
|
19
|
+
|
|
20
|
+
1. Inicia el servidor:
|
|
21
|
+
```bash
|
|
22
|
+
node examples/mvc_welcome/app.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. Visita http://localhost:9002 para ver la página de bienvenida
|
|
26
|
+
|
|
27
|
+
## Características del Framework
|
|
28
|
+
|
|
29
|
+
Este ejemplo muestra algunas de las características clave del framework JERK:
|
|
30
|
+
|
|
31
|
+
- Motor de plantillas MVC profesional
|
|
32
|
+
- Sistema de vistas con soporte para variables, condicionales y bucles
|
|
33
|
+
- Controladores MVC con acceso fácil a vistas
|
|
34
|
+
- Arquitectura modular y extensible
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de página de bienvenida usando el motor de plantillas MVC de JERK
|
|
3
|
+
* Demostración del sistema MVC con vistas y controladores
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { APIServer, Router, Logger } = require('../../index');
|
|
7
|
+
const WelcomeController = require('./controllers/welcomeController');
|
|
8
|
+
|
|
9
|
+
async function startServer() {
|
|
10
|
+
// Crear instancia del servidor
|
|
11
|
+
const server = new APIServer({
|
|
12
|
+
port: 9002,
|
|
13
|
+
host: 'localhost'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Crear instancia del logger
|
|
17
|
+
const logger = new Logger({ level: 'info' });
|
|
18
|
+
|
|
19
|
+
// Crear instancia del controlador
|
|
20
|
+
const welcomeController = new WelcomeController({
|
|
21
|
+
viewsPath: './examples/mvc_welcome/views'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Definir rutas
|
|
25
|
+
const router = new Router();
|
|
26
|
+
|
|
27
|
+
router
|
|
28
|
+
.get('/', (req, res) => {
|
|
29
|
+
welcomeController.setRequestResponse(req, res);
|
|
30
|
+
welcomeController.index(req, res);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Agregar las rutas del router al servidor
|
|
34
|
+
const routes = router.getRoutes();
|
|
35
|
+
for (const route of routes) {
|
|
36
|
+
server.addRoute(route.method, route.path, route.handler);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Iniciar el servidor
|
|
40
|
+
server.start(() => {
|
|
41
|
+
logger.info('Servidor de bienvenida MVC iniciado en http://localhost:9002');
|
|
42
|
+
logger.info('Ruta disponible:');
|
|
43
|
+
logger.info('- http://localhost:9002/ (Página de bienvenida)');
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Iniciar el servidor
|
|
48
|
+
startServer();
|
|
49
|
+
|
|
50
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { ControllerBase } = require('../../../index');
|
|
2
|
+
|
|
3
|
+
class WelcomeController extends ControllerBase {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
index(req, res) {
|
|
9
|
+
// Establecer variables para la vista
|
|
10
|
+
this.set('title', 'Bienvenido a JERK Framework');
|
|
11
|
+
this.set('message', 'El poderoso framework para construir aplicaciones web completas con Node.js');
|
|
12
|
+
|
|
13
|
+
// Datos de características del framework
|
|
14
|
+
this.set('features', [
|
|
15
|
+
{
|
|
16
|
+
name: 'Motor MVC',
|
|
17
|
+
description: 'Sistema completo de vistas, controladores y modelos'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'Seguridad',
|
|
21
|
+
description: 'Firewall integrado y protección contra ataques'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Autenticación',
|
|
25
|
+
description: 'Soporte para JWT, OAuth, sesiones y más'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'Flexibilidad',
|
|
29
|
+
description: 'Arquitectura modular y altamente configurable'
|
|
30
|
+
}
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
this.set('documentationUrl', 'https://jerk.page.gd/');
|
|
34
|
+
this.set('examplesUrl', 'https://gitlab.com/bytedogssyndicate1/jerk');
|
|
35
|
+
|
|
36
|
+
// Renderizar la vista
|
|
37
|
+
this.render(res, 'home/welcome');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = WelcomeController;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-mvc-welcome-example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de página de bienvenida usando el motor de plantillas MVC del framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"jerk",
|
|
12
|
+
"mvc",
|
|
13
|
+
"template-engine",
|
|
14
|
+
"welcome-page",
|
|
15
|
+
"nodejs",
|
|
16
|
+
"framework"
|
|
17
|
+
],
|
|
18
|
+
"author": "JERK Framework Team",
|
|
19
|
+
"license": "Apache-2.0",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"jerkjs": "^2.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"nodemon": "^3.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: Arial, sans-serif;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
}
|
|
18
|
+
.container {
|
|
19
|
+
background: white;
|
|
20
|
+
padding: 2rem;
|
|
21
|
+
border-radius: 10px;
|
|
22
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
|
23
|
+
text-align: center;
|
|
24
|
+
max-width: 600px;
|
|
25
|
+
width: 90%;
|
|
26
|
+
}
|
|
27
|
+
h1 {
|
|
28
|
+
color: #333;
|
|
29
|
+
margin-bottom: 1rem;
|
|
30
|
+
}
|
|
31
|
+
.message {
|
|
32
|
+
font-size: 1.2rem;
|
|
33
|
+
color: #666;
|
|
34
|
+
margin-bottom: 2rem;
|
|
35
|
+
}
|
|
36
|
+
.features {
|
|
37
|
+
display: grid;
|
|
38
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
39
|
+
gap: 1rem;
|
|
40
|
+
margin: 2rem 0;
|
|
41
|
+
}
|
|
42
|
+
.feature {
|
|
43
|
+
background: #f8f9fa;
|
|
44
|
+
padding: 1rem;
|
|
45
|
+
border-radius: 5px;
|
|
46
|
+
border-left: 4px solid #667eea;
|
|
47
|
+
}
|
|
48
|
+
.btn {
|
|
49
|
+
display: inline-block;
|
|
50
|
+
background: #667eea;
|
|
51
|
+
color: white;
|
|
52
|
+
padding: 0.75rem 1.5rem;
|
|
53
|
+
text-decoration: none;
|
|
54
|
+
border-radius: 5px;
|
|
55
|
+
margin-top: 1rem;
|
|
56
|
+
transition: background 0.3s;
|
|
57
|
+
}
|
|
58
|
+
.btn:hover {
|
|
59
|
+
background: #5a6fd8;
|
|
60
|
+
}
|
|
61
|
+
</style>
|
|
62
|
+
</head>
|
|
63
|
+
<body>
|
|
64
|
+
<div class="container">
|
|
65
|
+
<h1>{{title}}</h1>
|
|
66
|
+
<div class="message">{{message}}</div>
|
|
67
|
+
|
|
68
|
+
<div class="features">
|
|
69
|
+
{{foreach:features}}
|
|
70
|
+
<div class="feature">
|
|
71
|
+
<h3>{{item.name}}</h3>
|
|
72
|
+
<p>{{item.description}}</p>
|
|
73
|
+
</div>
|
|
74
|
+
{{endforeach}}
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<p>¡Comienza a construir tu aplicación con JERK!</p>
|
|
78
|
+
<a href="{{documentationUrl}}" class="btn">Documentación</a>
|
|
79
|
+
<a href="{{examplesUrl}}" class="btn">Ejemplos</a>
|
|
80
|
+
</div>
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Ejemplo API con Autenticación SQLite
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo crear una API con autenticación basada en tokens almacenados en SQLite utilizando el Framework JERK.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- Autenticación JWT con tokens almacenados en SQLite
|
|
8
|
+
- Rutas protegidas y públicas
|
|
9
|
+
- Sistema de login para obtener tokens
|
|
10
|
+
- Controladores organizados por funcionalidad
|
|
11
|
+
|
|
12
|
+
## Configuración
|
|
13
|
+
|
|
14
|
+
1. Asegúrate de tener instaladas las dependencias del framework JERK
|
|
15
|
+
2. Instala sqlite3 si aún no está instalado: `npm install sqlite3`
|
|
16
|
+
|
|
17
|
+
## Uso
|
|
18
|
+
|
|
19
|
+
1. Inicia el servidor:
|
|
20
|
+
```bash
|
|
21
|
+
node app.js
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
2. El servidor escuchará en `http://localhost:8088`
|
|
25
|
+
|
|
26
|
+
## Endpoints
|
|
27
|
+
|
|
28
|
+
- `GET /` - Página de inicio (público)
|
|
29
|
+
- `POST /login` - Iniciar sesión y obtener token (público)
|
|
30
|
+
- `GET /protected` - Contenido protegido (requiere token)
|
|
31
|
+
- `GET /profile` - Perfil de usuario (requiere token)
|
|
32
|
+
|
|
33
|
+
## Ejemplo de uso
|
|
34
|
+
|
|
35
|
+
1. Iniciar sesión:
|
|
36
|
+
```bash
|
|
37
|
+
curl -X POST http://localhost:8088/login \
|
|
38
|
+
-H "Content-Type: application/json" \
|
|
39
|
+
-d '{"username": "admin", "password": "password"}'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. Acceder a contenido protegido:
|
|
43
|
+
```bash
|
|
44
|
+
curl -X GET http://localhost:8088/protected \
|
|
45
|
+
-H "Authorization: Bearer TU_TOKEN_AQUI"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. Ver perfil de usuario:
|
|
49
|
+
```bash
|
|
50
|
+
curl -X GET http://localhost:8088/profile \
|
|
51
|
+
-H "Authorization: Bearer TU_TOKEN_AQUI"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Estructura del proyecto
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
examples/v2/
|
|
58
|
+
├── app.js # Punto de entrada de la aplicación
|
|
59
|
+
├── routes.json # Definición de rutas
|
|
60
|
+
├── controllers/ # Controladores de las rutas
|
|
61
|
+
│ ├── mainController.js
|
|
62
|
+
│ ├── authController.js
|
|
63
|
+
│ ├── protectedController.js
|
|
64
|
+
│ └── userController.js
|
|
65
|
+
└── tokens_example.sqlite # Base de datos SQLite para tokens (generada automáticamente)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Seguridad
|
|
69
|
+
|
|
70
|
+
- Los tokens se almacenan en una base de datos SQLite
|
|
71
|
+
- Los tokens expiran después de 1 hora
|
|
72
|
+
- Las rutas protegidas requieren un token válido en el header Authorization
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const {
|
|
2
|
+
APIServer,
|
|
3
|
+
Authenticator,
|
|
4
|
+
RouteLoader,
|
|
5
|
+
Logger,
|
|
6
|
+
SQLiteTokenAdapter
|
|
7
|
+
} = require('../../index.js');
|
|
8
|
+
|
|
9
|
+
async function startServer() {
|
|
10
|
+
// Crear instancia del servidor
|
|
11
|
+
const server = new APIServer({
|
|
12
|
+
port: 8088,
|
|
13
|
+
host: 'localhost'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Crear instancia del logger
|
|
17
|
+
const logger = new Logger({ level: 'info' });
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Crear instancia del adaptador de tokens SQLite
|
|
21
|
+
const tokenAdapter = new SQLiteTokenAdapter({
|
|
22
|
+
dbPath: './tokens_example.sqlite',
|
|
23
|
+
tableName: 'example_tokens'
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Inicializar el adaptador de tokens
|
|
27
|
+
await tokenAdapter.initialize();
|
|
28
|
+
logger.info('SQLite Token Adapter inicializado correctamente');
|
|
29
|
+
|
|
30
|
+
// Crear instancia del autenticador
|
|
31
|
+
const authenticator = new Authenticator({ logger });
|
|
32
|
+
|
|
33
|
+
// Registrar estrategia de autenticación JWT que utiliza el adaptador SQLite
|
|
34
|
+
authenticator.use('jwt-sqlite', async (req, options = {}) => {
|
|
35
|
+
const authHeader = req.headers.authorization;
|
|
36
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
37
|
+
|
|
38
|
+
if (!token) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Validar el token contra la base de datos SQLite
|
|
43
|
+
const tokenRecord = await tokenAdapter.validateToken(token);
|
|
44
|
+
|
|
45
|
+
if (tokenRecord) {
|
|
46
|
+
// Agregar información del usuario a la solicitud
|
|
47
|
+
req.user = { userId: tokenRecord.user_id, tokenType: tokenRecord.token_type };
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return false;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Agregar el autenticador al servidor para que pueda ser usado por el RouteLoader
|
|
55
|
+
server.authenticator = authenticator;
|
|
56
|
+
|
|
57
|
+
// Cargar rutas desde archivo JSON
|
|
58
|
+
const routeLoader = new RouteLoader();
|
|
59
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
60
|
+
|
|
61
|
+
// Iniciar el servidor
|
|
62
|
+
server.start();
|
|
63
|
+
|
|
64
|
+
logger.info('Servidor iniciado en http://localhost:8088');
|
|
65
|
+
} catch (error) {
|
|
66
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Iniciar el servidor
|
|
72
|
+
startServer();
|
|
73
|
+
|
|
74
|
+
module.exports = { startServer };
|