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,356 @@
|
|
|
1
|
+
# Frontend y Sesiones con API SDK JS
|
|
2
|
+
|
|
3
|
+
Visita nuestra página web: https://jerk.page.gd/
|
|
4
|
+
Repositorio oficial: https://gitlab.com/bytedogssyndicate1/jerk/
|
|
5
|
+
|
|
6
|
+
## Introducción
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
## Características del Frontend
|
|
11
|
+
|
|
12
|
+
### Especificación de Content-Type en routes.json
|
|
13
|
+
|
|
14
|
+
Una de las nuevas características es la capacidad de especificar el content-type directamente en el archivo routes.json:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
[
|
|
18
|
+
{
|
|
19
|
+
"path": "/",
|
|
20
|
+
"method": "GET",
|
|
21
|
+
"controller": "./controllers/pageController.js",
|
|
22
|
+
"handler": "homePage",
|
|
23
|
+
"auth": "none",
|
|
24
|
+
"contentType": "text/html"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "/api/data",
|
|
28
|
+
"method": "GET",
|
|
29
|
+
"controller": "./controllers/apiController.js",
|
|
30
|
+
"handler": "getData",
|
|
31
|
+
"auth": "none",
|
|
32
|
+
"contentType": "application/json"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Soporte para diferentes tipos de contenido
|
|
38
|
+
|
|
39
|
+
El framework ahora puede servir diferentes tipos de contenido:
|
|
40
|
+
- HTML para páginas web
|
|
41
|
+
- CSS para estilos
|
|
42
|
+
- JavaScript para scripts
|
|
43
|
+
- JSON para APIs
|
|
44
|
+
- Y cualquier otro tipo de contenido
|
|
45
|
+
|
|
46
|
+
## Sistema de Sesiones
|
|
47
|
+
|
|
48
|
+
### Configuración
|
|
49
|
+
|
|
50
|
+
Para usar el sistema de sesiones, primero debes configurar el middleware en tu aplicación:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const { APIServer, SessionManager, Cors } = require('@jerkjs/jerk');
|
|
54
|
+
|
|
55
|
+
async function startServer() {
|
|
56
|
+
const server = new APIServer({
|
|
57
|
+
port: 3000,
|
|
58
|
+
host: 'localhost'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Crear instancia del administrador de sesiones
|
|
62
|
+
const sessionManager = new SessionManager({
|
|
63
|
+
cookieName: 'myapp_session',
|
|
64
|
+
secret: 'my-super-secret-session-key',
|
|
65
|
+
timeout: 3600000 // 1 hora
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Aplicar middleware de sesión
|
|
69
|
+
server.use(sessionManager.middleware());
|
|
70
|
+
|
|
71
|
+
// Hacer que sessionManager esté disponible para el RouteLoader
|
|
72
|
+
server.sessionManager = sessionManager;
|
|
73
|
+
|
|
74
|
+
// Cargar rutas
|
|
75
|
+
const routeLoader = new RouteLoader();
|
|
76
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
77
|
+
|
|
78
|
+
server.start();
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Protección de rutas
|
|
83
|
+
|
|
84
|
+
Puedes proteger rutas específicas usando `"auth": "session"` en tu archivo routes.json:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
[
|
|
88
|
+
{
|
|
89
|
+
"path": "/dashboard",
|
|
90
|
+
"method": "GET",
|
|
91
|
+
"controller": "./controllers/dashboardController.js",
|
|
92
|
+
"handler": "showDashboard",
|
|
93
|
+
"auth": "session",
|
|
94
|
+
"contentType": "text/html"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Uso en controladores
|
|
100
|
+
|
|
101
|
+
En tus controladores, puedes acceder a la sesión a través de `req.session`:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
const authController = {
|
|
105
|
+
// Controlador para iniciar sesión
|
|
106
|
+
processLogin: async (req, res) => {
|
|
107
|
+
const { username, password } = req.body;
|
|
108
|
+
|
|
109
|
+
// Validar credenciales (tu lógica aquí)
|
|
110
|
+
const user = await validateUser(username, password);
|
|
111
|
+
|
|
112
|
+
if (user) {
|
|
113
|
+
// Crear sesión de usuario autenticado
|
|
114
|
+
req.session.create({
|
|
115
|
+
authenticated: true,
|
|
116
|
+
userId: user.id,
|
|
117
|
+
username: user.username
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
121
|
+
res.end(JSON.stringify({
|
|
122
|
+
success: true,
|
|
123
|
+
message: 'Inicio de sesión exitoso'
|
|
124
|
+
}));
|
|
125
|
+
} else {
|
|
126
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
127
|
+
res.end(JSON.stringify({
|
|
128
|
+
success: false,
|
|
129
|
+
message: 'Credenciales inválidas'
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// Controlador para cerrar sesión
|
|
135
|
+
processLogout: (req, res) => {
|
|
136
|
+
if (req.session) {
|
|
137
|
+
req.session.destroy();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
141
|
+
res.end(JSON.stringify({
|
|
142
|
+
success: true,
|
|
143
|
+
message: 'Sesión cerrada exitosamente'
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Sistema de Hooks, Filters y Actions
|
|
150
|
+
|
|
151
|
+
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.
|
|
152
|
+
|
|
153
|
+
### Hooks Disponibles
|
|
154
|
+
|
|
155
|
+
#### Sesion Creation Hooks
|
|
156
|
+
- `session_create_data`: Filtra los datos antes de crear una sesión
|
|
157
|
+
- `session_created`: Acción disparada después de crear una sesión
|
|
158
|
+
- `session_create_user_data`: Filtra los datos de usuario antes de crear la sesión
|
|
159
|
+
|
|
160
|
+
#### Sesion Retrieval Hooks
|
|
161
|
+
- `session_get_id`: Filtra el ID de sesión antes de buscarla
|
|
162
|
+
- `session_retrieved`: Acción disparada después de obtener una sesión
|
|
163
|
+
- `session_not_found`: Acción disparada cuando no se encuentra una sesión
|
|
164
|
+
- `session_expired`: Acción disparada cuando una sesión ha expirado
|
|
165
|
+
|
|
166
|
+
#### Sesion Update Hooks
|
|
167
|
+
- `session_update_data`: Filtra los nuevos datos antes de actualizar la sesión
|
|
168
|
+
- `session_updated`: Acción disparada después de actualizar una sesión
|
|
169
|
+
- `session_update_user_data`: Filtra los datos de usuario antes de actualizar
|
|
170
|
+
|
|
171
|
+
#### Sesion Destruction Hooks
|
|
172
|
+
- `session_destroy_before`: Acción disparada antes de destruir una sesión
|
|
173
|
+
- `session_destroyed`: Acción disparada después de destruir una sesión
|
|
174
|
+
- `session_destroy_failed`: Acción disparada cuando falla la destrucción
|
|
175
|
+
|
|
176
|
+
#### Middleware Hooks
|
|
177
|
+
- `session_middleware_before`: Acción disparada antes del middleware de sesión
|
|
178
|
+
- `session_middleware_after`: Acción disparada después del middleware de sesión
|
|
179
|
+
|
|
180
|
+
#### Authentication Hooks
|
|
181
|
+
- `session_auth_check_before`: Acción disparada antes de verificar autenticación
|
|
182
|
+
- `session_auth_success`: Acción disparada cuando la autenticación es exitosa
|
|
183
|
+
- `session_auth_failed`: Acción disparada cuando la autenticación falla
|
|
184
|
+
- `session_created_response`: Acción disparada después de crear sesión en respuesta
|
|
185
|
+
- `session_updated_response`: Acción disparada después de actualizar sesión en respuesta
|
|
186
|
+
- `session_destroyed_response`: Acción disparada después de destruir sesión en respuesta
|
|
187
|
+
|
|
188
|
+
### Ejemplos de Uso de Hooks
|
|
189
|
+
|
|
190
|
+
#### Registrar actividad de sesión
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const { hooks } = require('@jerkjs/jerk');
|
|
194
|
+
|
|
195
|
+
// Registrar cuando se crea una sesión
|
|
196
|
+
hooks.addAction('session_created', (sessionId, sessionData) => {
|
|
197
|
+
console.log(`Sesión creada: ${sessionId} para el usuario: ${sessionData.username}`);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Registrar cuando se destruye una sesión
|
|
201
|
+
hooks.addAction('session_destroyed', (sessionId, sessionData) => {
|
|
202
|
+
console.log(`Sesión destruida: ${sessionId} para el usuario: ${sessionData.username}`);
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Modificar datos de sesión antes de crearla
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
const { hooks } = require('@jerkjs/jerk');
|
|
210
|
+
|
|
211
|
+
// Añadir información de IP y fecha a los datos de sesión
|
|
212
|
+
hooks.addFilter('session_create_data', (userData, req) => {
|
|
213
|
+
return {
|
|
214
|
+
...userData,
|
|
215
|
+
ipAddress: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
|
|
216
|
+
createdAt: new Date().toISOString()
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### Personalizar el manejo de autenticación fallida
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
const { hooks } = require('@jerkjs/jerk');
|
|
225
|
+
|
|
226
|
+
// Registrar intentos de acceso no autorizado
|
|
227
|
+
hooks.addAction('session_auth_failed', (req, res, redirectTo) => {
|
|
228
|
+
console.log(`Intento de acceso no autorizado a: ${req.url} desde IP: ${req.connection.remoteAddress}`);
|
|
229
|
+
|
|
230
|
+
// Puedes personalizar la respuesta aquí
|
|
231
|
+
if (req.headers.accept && req.headers.accept.includes('application/json')) {
|
|
232
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
233
|
+
res.end(JSON.stringify({ error: 'No autorizado', code: 'AUTH_REQUIRED' }));
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Extender datos de sesión durante la actualización
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const { hooks } = require('@jerkjs/jerk');
|
|
242
|
+
|
|
243
|
+
// Añadir marca de tiempo a cada actualización de sesión
|
|
244
|
+
hooks.addFilter('session_update_data', (newData, req, sessionId) => {
|
|
245
|
+
return {
|
|
246
|
+
...newData,
|
|
247
|
+
lastUpdated: new Date().toISOString(),
|
|
248
|
+
lastActivity: new Date().toISOString()
|
|
249
|
+
};
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Ejemplo Completo
|
|
254
|
+
|
|
255
|
+
Aquí tienes un ejemplo completo de una aplicación que combina frontend y sesiones:
|
|
256
|
+
|
|
257
|
+
### app.js
|
|
258
|
+
```javascript
|
|
259
|
+
const {
|
|
260
|
+
APIServer,
|
|
261
|
+
RouteLoader,
|
|
262
|
+
Logger,
|
|
263
|
+
Cors,
|
|
264
|
+
SessionManager
|
|
265
|
+
} = require('@jerkjs/jerk');
|
|
266
|
+
|
|
267
|
+
async function startServer() {
|
|
268
|
+
const server = new APIServer({
|
|
269
|
+
port: 3000,
|
|
270
|
+
host: 'localhost'
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const logger = new Logger({ level: 'info' });
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
// Configurar sesiones
|
|
277
|
+
const sessionManager = new SessionManager({
|
|
278
|
+
cookieName: 'myapp_session',
|
|
279
|
+
secret: 'my-super-secret-session-key',
|
|
280
|
+
timeout: 3600000
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
server.use(sessionManager.middleware());
|
|
284
|
+
server.sessionManager = sessionManager;
|
|
285
|
+
|
|
286
|
+
// Configurar CORS
|
|
287
|
+
const cors = new Cors({
|
|
288
|
+
origin: '*',
|
|
289
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
290
|
+
allowedHeaders: ['Content-Type', 'Authorization']
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
server.use(cors.middleware());
|
|
294
|
+
|
|
295
|
+
// Cargar rutas
|
|
296
|
+
const routeLoader = new RouteLoader();
|
|
297
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
298
|
+
|
|
299
|
+
server.start();
|
|
300
|
+
logger.info('Servidor iniciado en http://localhost:3000');
|
|
301
|
+
} catch (error) {
|
|
302
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
startServer();
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### routes.json
|
|
311
|
+
```json
|
|
312
|
+
[
|
|
313
|
+
{
|
|
314
|
+
"path": "/",
|
|
315
|
+
"method": "GET",
|
|
316
|
+
"controller": "./controllers/pageController.js",
|
|
317
|
+
"handler": "homePage",
|
|
318
|
+
"auth": "none",
|
|
319
|
+
"contentType": "text/html"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"path": "/login",
|
|
323
|
+
"method": "GET",
|
|
324
|
+
"controller": "./controllers/authController.js",
|
|
325
|
+
"handler": "showLoginPage",
|
|
326
|
+
"auth": "none",
|
|
327
|
+
"contentType": "text/html"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"path": "/dashboard",
|
|
331
|
+
"method": "GET",
|
|
332
|
+
"controller": "./controllers/dashboardController.js",
|
|
333
|
+
"handler": "showDashboard",
|
|
334
|
+
"auth": "session",
|
|
335
|
+
"contentType": "text/html"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"path": "/api/login",
|
|
339
|
+
"method": "POST",
|
|
340
|
+
"controller": "./controllers/authController.js",
|
|
341
|
+
"handler": "processLogin",
|
|
342
|
+
"auth": "none",
|
|
343
|
+
"contentType": "application/json"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"path": "/api/logout",
|
|
347
|
+
"method": "POST",
|
|
348
|
+
"controller": "./controllers/authController.js",
|
|
349
|
+
"handler": "processLogout",
|
|
350
|
+
"auth": "session",
|
|
351
|
+
"contentType": "application/json"
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
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,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlador de ejemplo para productos
|
|
3
|
+
* Archivo: examples/advanced/controllers/productController.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Simulación de base de datos de productos
|
|
7
|
+
let products = [
|
|
8
|
+
{ id: 1, name: 'Laptop', price: 1000, category: 'Electronics' },
|
|
9
|
+
{ id: 2, name: 'Mouse', price: 25, category: 'Accessories' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// Obtener todos los productos
|
|
13
|
+
function getProducts(req, res) {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
15
|
+
res.end(JSON.stringify({
|
|
16
|
+
success: true,
|
|
17
|
+
data: products
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Actualizar un producto por ID
|
|
22
|
+
function updateProduct(req, res) {
|
|
23
|
+
try {
|
|
24
|
+
const productId = parseInt(req.params.id);
|
|
25
|
+
const { name, price, category } = req.body;
|
|
26
|
+
|
|
27
|
+
const productIndex = products.findIndex(p => p.id === productId);
|
|
28
|
+
|
|
29
|
+
if (productIndex === -1) {
|
|
30
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
31
|
+
res.end(JSON.stringify({
|
|
32
|
+
success: false,
|
|
33
|
+
message: 'Producto no encontrado'
|
|
34
|
+
}));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Actualizar producto
|
|
39
|
+
products[productIndex] = {
|
|
40
|
+
...products[productIndex],
|
|
41
|
+
...(name && { name }),
|
|
42
|
+
...(price && { price }),
|
|
43
|
+
...(category && { category })
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
47
|
+
res.end(JSON.stringify({
|
|
48
|
+
success: true,
|
|
49
|
+
data: products[productIndex]
|
|
50
|
+
}));
|
|
51
|
+
} catch (error) {
|
|
52
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
53
|
+
res.end(JSON.stringify({
|
|
54
|
+
success: false,
|
|
55
|
+
message: 'Error al actualizar producto'
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Exportar handlers
|
|
61
|
+
module.exports = {
|
|
62
|
+
getProducts,
|
|
63
|
+
updateProduct
|
|
64
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controlador de ejemplo para usuarios
|
|
3
|
+
* Archivo: examples/basic/controllers/userController.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Simulación de base de datos
|
|
7
|
+
let users = [
|
|
8
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com' },
|
|
9
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// Obtener todos los usuarios
|
|
13
|
+
function getUsers(req, res) {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
15
|
+
res.end(JSON.stringify({
|
|
16
|
+
success: true,
|
|
17
|
+
data: users
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Obtener un usuario por ID
|
|
22
|
+
function getUserById(req, res) {
|
|
23
|
+
const userId = parseInt(req.params.id);
|
|
24
|
+
const user = users.find(u => u.id === userId);
|
|
25
|
+
|
|
26
|
+
if (!user) {
|
|
27
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
28
|
+
res.end(JSON.stringify({
|
|
29
|
+
success: false,
|
|
30
|
+
message: 'Usuario no encontrado'
|
|
31
|
+
}));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
36
|
+
res.end(JSON.stringify({
|
|
37
|
+
success: true,
|
|
38
|
+
data: user
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Crear un nuevo usuario
|
|
43
|
+
function createUser(req, res) {
|
|
44
|
+
try {
|
|
45
|
+
const { name, email } = req.body;
|
|
46
|
+
|
|
47
|
+
// Validar datos
|
|
48
|
+
if (!name || !email) {
|
|
49
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
50
|
+
res.end(JSON.stringify({
|
|
51
|
+
success: false,
|
|
52
|
+
message: 'Nombre y correo electrónico son requeridos'
|
|
53
|
+
}));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Crear nuevo usuario
|
|
58
|
+
const newUser = {
|
|
59
|
+
id: users.length + 1,
|
|
60
|
+
name,
|
|
61
|
+
email
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
users.push(newUser);
|
|
65
|
+
|
|
66
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
67
|
+
res.end(JSON.stringify({
|
|
68
|
+
success: true,
|
|
69
|
+
data: newUser
|
|
70
|
+
}));
|
|
71
|
+
} catch (error) {
|
|
72
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
73
|
+
res.end(JSON.stringify({
|
|
74
|
+
success: false,
|
|
75
|
+
message: 'Error al crear usuario'
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Exportar handlers
|
|
81
|
+
module.exports = {
|
|
82
|
+
getUsers,
|
|
83
|
+
getUserById,
|
|
84
|
+
createUser
|
|
85
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "/api/users",
|
|
4
|
+
"method": "GET",
|
|
5
|
+
"auth": "jwt",
|
|
6
|
+
"authOptions": {
|
|
7
|
+
"jwtSecret": "secret-jwt-key"
|
|
8
|
+
},
|
|
9
|
+
"controller": "./basic/controllers/userController.js",
|
|
10
|
+
"handler": "getUsers"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "/api/users/:id",
|
|
14
|
+
"method": "GET",
|
|
15
|
+
"auth": "jwt",
|
|
16
|
+
"authOptions": {
|
|
17
|
+
"jwtSecret": "secret-jwt-key"
|
|
18
|
+
},
|
|
19
|
+
"controller": "./basic/controllers/userController.js",
|
|
20
|
+
"handler": "getUserById"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "/api/users",
|
|
24
|
+
"method": "POST",
|
|
25
|
+
"auth": "apiKey",
|
|
26
|
+
"authOptions": {
|
|
27
|
+
"apiKeyHeader": "X-API-Key",
|
|
28
|
+
"apiKeyValues": ["secret-key-123"]
|
|
29
|
+
},
|
|
30
|
+
"controller": "./basic/controllers/userController.js",
|
|
31
|
+
"handler": "createUser"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"path": "/api/products",
|
|
35
|
+
"method": "GET",
|
|
36
|
+
"auth": "none",
|
|
37
|
+
"controller": "./advanced/controllers/productController.js",
|
|
38
|
+
"handler": "getProducts"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "/api/products/:id",
|
|
42
|
+
"method": "PUT",
|
|
43
|
+
"auth": "apiKey",
|
|
44
|
+
"authOptions": {
|
|
45
|
+
"apiKeyHeader": "X-API-Key",
|
|
46
|
+
"apiKeyValues": ["secret-key-123"]
|
|
47
|
+
},
|
|
48
|
+
"controller": "./advanced/controllers/productController.js",
|
|
49
|
+
"handler": "updateProduct"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo real de uso del framework API SDK
|
|
3
|
+
* Este script demuestra cómo cargar rutas desde un archivo JSON
|
|
4
|
+
* y usar los controladores definidos en el archivo de rutas
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { APISDK, RouteLoader, Authenticator, Logger } = require('../index');
|
|
9
|
+
|
|
10
|
+
// Crear instancia del logger
|
|
11
|
+
const logger = new Logger({ level: 'info', timestamp: true });
|
|
12
|
+
|
|
13
|
+
logger.info('Iniciando ejemplo real de carga de rutas desde JSON');
|
|
14
|
+
|
|
15
|
+
// Crear instancia del servidor
|
|
16
|
+
const server = new APISDK({
|
|
17
|
+
port: 9900,
|
|
18
|
+
host: 'localhost'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Crear instancia del autenticador
|
|
22
|
+
const authenticator = new Authenticator();
|
|
23
|
+
|
|
24
|
+
// Registrar estrategias de autenticación que se usan en routes.json
|
|
25
|
+
authenticator.use('apiKey', authenticator.apiKeyStrategy('X-API-Key', ['secret-key-123']));
|
|
26
|
+
authenticator.use('jwt', authenticator.jwtStrategy('secret-jwt-key'));
|
|
27
|
+
|
|
28
|
+
// Cargar rutas desde el archivo JSON
|
|
29
|
+
const routeLoader = new RouteLoader();
|
|
30
|
+
|
|
31
|
+
// Middleware de logging
|
|
32
|
+
server.use((req, res, next) => {
|
|
33
|
+
logger.info(`${req.method} ${req.url} - IP: ${req.connection.remoteAddress}`);
|
|
34
|
+
next();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
logger.info('Cargando rutas desde advanced/routes.json...');
|
|
38
|
+
|
|
39
|
+
// Cargar las rutas desde el archivo JSON
|
|
40
|
+
// Cambiamos temporalmente el directorio de trabajo para que las rutas relativas funcionen correctamente
|
|
41
|
+
const originalCwd = process.cwd();
|
|
42
|
+
process.chdir(__dirname); // Cambiar al directorio actual (examples)
|
|
43
|
+
|
|
44
|
+
routeLoader.loadRoutes(server, './advanced/routes.json')
|
|
45
|
+
.then(routes => {
|
|
46
|
+
process.chdir(originalCwd); // Restaurar directorio original
|
|
47
|
+
|
|
48
|
+
logger.info(`Cargadas ${routes.length} rutas desde el archivo JSON:`);
|
|
49
|
+
routes.forEach((route, index) => {
|
|
50
|
+
logger.info(` ${index + 1}. ${route.method} ${route.path} -> ${route.controller}#${route.handler}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
logger.info('\nIniciando servidor en http://localhost:9900');
|
|
54
|
+
|
|
55
|
+
// Iniciar el servidor
|
|
56
|
+
const httpServer = server.start();
|
|
57
|
+
|
|
58
|
+
logger.info('\nENDPOINTS DISPONIBLES (cargados desde routes.json):');
|
|
59
|
+
logger.info('GET /api/users - Obtener todos los usuarios (JWT req)');
|
|
60
|
+
logger.info('GET /api/users/:id - Obtener usuario por ID (JWT req)');
|
|
61
|
+
logger.info('POST /api/users - Crear usuario (API Key req)');
|
|
62
|
+
logger.info('GET /api/products - Obtener productos (sin auth)');
|
|
63
|
+
logger.info('PUT /api/products/:id - Actualizar producto (API Key req)');
|
|
64
|
+
|
|
65
|
+
logger.info('\nEJEMPLOS DE USO:');
|
|
66
|
+
logger.info('# Obtener productos (sin autenticación):');
|
|
67
|
+
logger.info('curl -X GET http://localhost:9900/api/products');
|
|
68
|
+
|
|
69
|
+
logger.info('\nEl servidor se detendrá automáticamente en 120 segundos...');
|
|
70
|
+
|
|
71
|
+
// Programar apagado automático para la demostración
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
logger.info('Finalizando ejemplo...');
|
|
74
|
+
httpServer.close(() => {
|
|
75
|
+
logger.info('Servidor detenido. Ejemplo completado.');
|
|
76
|
+
console.log('\nEjemplo real completado exitosamente!');
|
|
77
|
+
console.log('El framework ha demostrado su capacidad para:');
|
|
78
|
+
console.log(' - Cargar rutas dinámicamente desde archivos JSON');
|
|
79
|
+
console.log(' - Usar controladores definidos externamente');
|
|
80
|
+
console.log(' - Aplicar diferentes tipos de autenticación');
|
|
81
|
+
process.exit(0);
|
|
82
|
+
});
|
|
83
|
+
}, 120000);
|
|
84
|
+
|
|
85
|
+
})
|
|
86
|
+
.catch(error => {
|
|
87
|
+
process.chdir(originalCwd); // Asegurarse de restaurar el directorio en caso de error
|
|
88
|
+
logger.error('Error cargando rutas:', error.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Mantener el proceso activo
|
|
93
|
+
process.stdin.resume();
|