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,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,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo basico de uso del framework API SDK
|
|
3
|
+
* Este script demuestra cómo usar directamente los controladores
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { APISDK, Logger } = require('../index');
|
|
7
|
+
const userController = require('./basic/controllers/userController');
|
|
8
|
+
|
|
9
|
+
// Crear instancia del logger
|
|
10
|
+
const logger = new Logger({ level: 'info', timestamp: true });
|
|
11
|
+
|
|
12
|
+
logger.info('Iniciando ejemplo basico con controladores');
|
|
13
|
+
|
|
14
|
+
// Crear instancia del servidor
|
|
15
|
+
const server = new APISDK({
|
|
16
|
+
port: 6001,
|
|
17
|
+
host: 'localhost'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Middleware de logging
|
|
21
|
+
server.use((req, res, next) => {
|
|
22
|
+
logger.info(`${req.method} ${req.url}`);
|
|
23
|
+
next();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Usar los handlers directamente desde el controlador
|
|
27
|
+
server.addRoute('GET', '/api/users', userController.getUsers);
|
|
28
|
+
server.addRoute('GET', '/api/users/:id', userController.getUserById);
|
|
29
|
+
server.addRoute('POST', '/api/users', userController.createUser);
|
|
30
|
+
|
|
31
|
+
logger.info('Agregando rutas usando handlers del controlador userController');
|
|
32
|
+
|
|
33
|
+
logger.info('\nIniciando servidor en http://localhost:6001');
|
|
34
|
+
|
|
35
|
+
// Iniciar el servidor
|
|
36
|
+
const httpServer = server.start();
|
|
37
|
+
|
|
38
|
+
logger.info('\nENDPOINTS DISPONIBLES:');
|
|
39
|
+
logger.info('GET /api/users - Obtener todos los usuarios');
|
|
40
|
+
logger.info('GET /api/users/:id - Obtener usuario por ID');
|
|
41
|
+
logger.info('POST /api/users - Crear nuevo usuario');
|
|
42
|
+
|
|
43
|
+
logger.info('\nEJEMPLOS DE USO:');
|
|
44
|
+
logger.info('# Obtener todos los usuarios:');
|
|
45
|
+
logger.info('curl -X GET http://localhost:6001/api/users');
|
|
46
|
+
logger.info('');
|
|
47
|
+
logger.info('# Obtener usuario por ID:');
|
|
48
|
+
logger.info('curl -X GET http://localhost:6001/api/users/1');
|
|
49
|
+
logger.info('');
|
|
50
|
+
logger.info('# Crear nuevo usuario:');
|
|
51
|
+
logger.info('curl -X POST -H "Content-Type: application/json" \\');
|
|
52
|
+
logger.info(' -d \'{"name":"Juan Perez", "email":"juan@example.com"}\' \\');
|
|
53
|
+
logger.info(' http://localhost:6001/api/users');
|
|
54
|
+
|
|
55
|
+
logger.info('\nEl servidor se detendrá automáticamente en 60 segundos...');
|
|
56
|
+
|
|
57
|
+
// Programar apagado automático para la demostración
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
logger.info('Finalizando ejemplo basico...');
|
|
60
|
+
httpServer.close(() => {
|
|
61
|
+
logger.info('Servidor detenido. Ejemplo basico completado.');
|
|
62
|
+
console.log('\nEjemplo basico completado exitosamente!');
|
|
63
|
+
console.log('El framework ha demostrado su capacidad para:');
|
|
64
|
+
console.log(' - Usar controladores directamente');
|
|
65
|
+
console.log(' - Manejar rutas parametrizadas');
|
|
66
|
+
console.log(' - Procesar solicitudes POST con cuerpo JSON');
|
|
67
|
+
process.exit(0);
|
|
68
|
+
});
|
|
69
|
+
}, 60000);
|
|
70
|
+
|
|
71
|
+
// Mantener el proceso activo
|
|
72
|
+
process.stdin.resume();
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Ejemplo Frontend con API SDK JS
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra cómo el Framework API SDK JS puede utilizarse para servir tanto APIs como contenido HTML para frontends, gracias a la nueva funcionalidad de especificación de content-type en el archivo routes.json.
|
|
4
|
+
|
|
5
|
+
## Características
|
|
6
|
+
|
|
7
|
+
- API REST y páginas HTML en el mismo servidor
|
|
8
|
+
- Especificación de content-type en routes.json
|
|
9
|
+
- Soporte para diferentes tipos de contenido (HTML, CSS, JavaScript, JSON)
|
|
10
|
+
- Frontend completamente funcional con estilos y scripts
|
|
11
|
+
- Navegación entre páginas HTML
|
|
12
|
+
|
|
13
|
+
## Configuración
|
|
14
|
+
|
|
15
|
+
1. Asegúrate de tener instaladas las dependencias del framework API SDK
|
|
16
|
+
2. No se requiere configuración adicional para este ejemplo
|
|
17
|
+
|
|
18
|
+
## Uso
|
|
19
|
+
|
|
20
|
+
1. Inicia el servidor:
|
|
21
|
+
```bash
|
|
22
|
+
node app.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. El servidor escuchará en `http://localhost:8082`
|
|
26
|
+
|
|
27
|
+
## Endpoints
|
|
28
|
+
|
|
29
|
+
- `GET /` - Página de inicio HTML
|
|
30
|
+
- `GET /about` - Página Acerca de HTML
|
|
31
|
+
- `GET /contact` - Formulario de contacto HTML
|
|
32
|
+
- `GET /api/users` - API JSON de usuarios
|
|
33
|
+
- `GET /api/users/:id` - API JSON de usuario específico
|
|
34
|
+
- `GET /styles.css` - Archivo CSS
|
|
35
|
+
- `GET /script.js` - Archivo JavaScript
|
|
36
|
+
|
|
37
|
+
## Nueva funcionalidad: Content-Type en routes.json
|
|
38
|
+
|
|
39
|
+
Este ejemplo demuestra la nueva funcionalidad que permite especificar el content-type directamente en el archivo routes.json:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"path": "/",
|
|
44
|
+
"method": "GET",
|
|
45
|
+
"controller": "./controllers/pageController.js",
|
|
46
|
+
"handler": "homePage",
|
|
47
|
+
"auth": "none",
|
|
48
|
+
"contentType": "text/html"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
El campo `contentType` permite especificar el header Content-Type que se enviará con la respuesta, lo que permite servir diferentes tipos de contenido desde el mismo servidor.
|
|
53
|
+
|
|
54
|
+
## Estructura del proyecto
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
examples/frontend/
|
|
58
|
+
├── app.js # Punto de entrada de la aplicación
|
|
59
|
+
├── routes.json # Definición de rutas con content-type
|
|
60
|
+
├── controllers/ # Controladores de las rutas
|
|
61
|
+
│ ├── pageController.js # Controladores para páginas HTML
|
|
62
|
+
│ ├── apiController.js # Controladores para endpoints API
|
|
63
|
+
│ └── staticController.js # Controladores para recursos estáticos
|
|
64
|
+
└── README.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Seguridad
|
|
68
|
+
|
|
69
|
+
- CORS configurado para permitir solicitudes desde navegadores
|
|
70
|
+
- No se requiere autenticación para acceder a los endpoints
|
|
71
|
+
- El framework incluye protección WAF por defecto
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const {
|
|
2
|
+
APIServer,
|
|
3
|
+
RouteLoader,
|
|
4
|
+
Logger,
|
|
5
|
+
Cors,
|
|
6
|
+
SessionManager
|
|
7
|
+
} = require('../../index.js');
|
|
8
|
+
|
|
9
|
+
async function startServer() {
|
|
10
|
+
// Crear instancia del servidor
|
|
11
|
+
const server = new APIServer({
|
|
12
|
+
port: 8082,
|
|
13
|
+
host: 'localhost'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Crear instancia del logger
|
|
17
|
+
const logger = new Logger({ level: 'info' });
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Crear instancia del administrador de sesiones
|
|
21
|
+
const sessionManager = new SessionManager({
|
|
22
|
+
cookieName: 'frontend_session',
|
|
23
|
+
secret: 'frontend-session-secret-change-in-production',
|
|
24
|
+
timeout: 3600000 // 1 hora
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Aplicar middleware de sesión
|
|
28
|
+
server.use(sessionManager.middleware());
|
|
29
|
+
|
|
30
|
+
// Hacer que sessionManager esté disponible en el servidor para el RouteLoader
|
|
31
|
+
server.sessionManager = sessionManager;
|
|
32
|
+
|
|
33
|
+
// Configurar CORS para permitir solicitudes desde navegadores
|
|
34
|
+
const cors = new Cors({
|
|
35
|
+
origin: '*',
|
|
36
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
37
|
+
allowedHeaders: [
|
|
38
|
+
'Content-Type',
|
|
39
|
+
'Authorization',
|
|
40
|
+
'X-Requested-With',
|
|
41
|
+
'Accept',
|
|
42
|
+
'Origin'
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Aplicar middleware de CORS
|
|
47
|
+
server.use(cors.middleware());
|
|
48
|
+
|
|
49
|
+
// Cargar rutas desde archivo JSON
|
|
50
|
+
const routeLoader = new RouteLoader();
|
|
51
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
52
|
+
|
|
53
|
+
// Iniciar el servidor
|
|
54
|
+
server.start();
|
|
55
|
+
|
|
56
|
+
logger.info('Servidor frontend iniciado en http://localhost:8082');
|
|
57
|
+
logger.info('Endpoints disponibles:');
|
|
58
|
+
logger.info('- GET / (Página de inicio HTML)');
|
|
59
|
+
logger.info('- GET /about (Página Acerca de HTML)');
|
|
60
|
+
logger.info('- GET /api/users (API JSON)');
|
|
61
|
+
logger.info('- GET /contact (Formulario de contacto HTML)');
|
|
62
|
+
} catch (error) {
|
|
63
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Iniciar el servidor
|
|
69
|
+
startServer();
|
|
70
|
+
|
|
71
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Simulación de base de datos en memoria
|
|
2
|
+
const users = [
|
|
3
|
+
{ id: 1, name: 'Juan Pérez', email: 'juan@example.com', age: 30 },
|
|
4
|
+
{ id: 2, name: 'María García', email: 'maria@example.com', age: 25 },
|
|
5
|
+
{ id: 3, name: 'Pedro Rodríguez', email: 'pedro@example.com', age: 35 }
|
|
6
|
+
];
|
|
7
|
+
|
|
8
|
+
const apiController = {
|
|
9
|
+
getUsers: (req, res) => {
|
|
10
|
+
res.writeHead(200);
|
|
11
|
+
res.end(JSON.stringify({
|
|
12
|
+
success: true,
|
|
13
|
+
data: users,
|
|
14
|
+
count: users.length
|
|
15
|
+
}));
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
getUserById: (req, res) => {
|
|
19
|
+
const userId = parseInt(req.params.id);
|
|
20
|
+
const user = users.find(u => u.id === userId);
|
|
21
|
+
|
|
22
|
+
if (!user) {
|
|
23
|
+
res.writeHead(404);
|
|
24
|
+
res.end(JSON.stringify({
|
|
25
|
+
success: false,
|
|
26
|
+
error: 'Usuario no encontrado'
|
|
27
|
+
}));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
res.writeHead(200);
|
|
32
|
+
res.end(JSON.stringify({
|
|
33
|
+
success: true,
|
|
34
|
+
data: user
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
module.exports = apiController;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
const messageController = require('./messageController');
|
|
2
|
+
|
|
3
|
+
const authController = {
|
|
4
|
+
// Mostrar formulario de login
|
|
5
|
+
showLoginPage: (req, res) => {
|
|
6
|
+
const html = `
|
|
7
|
+
<!DOCTYPE html>
|
|
8
|
+
<html lang="es">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="UTF-8">
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
12
|
+
<title>Login - API Frontend Demo</title>
|
|
13
|
+
<link rel="stylesheet" href="/styles.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div class="container">
|
|
17
|
+
<header>
|
|
18
|
+
<h1>Área de Administración</h1>
|
|
19
|
+
<nav>
|
|
20
|
+
<ul>
|
|
21
|
+
<li><a href="/">Inicio</a></li>
|
|
22
|
+
<li><a href="/about">Acerca de</a></li>
|
|
23
|
+
<li><a href="/contact">Contacto</a></li>
|
|
24
|
+
<li><a href="/login">Login</a></li>
|
|
25
|
+
<li><a href="/api/users">Usuarios (API)</a></li>
|
|
26
|
+
</ul>
|
|
27
|
+
</nav>
|
|
28
|
+
</header>
|
|
29
|
+
|
|
30
|
+
<main>
|
|
31
|
+
<section class="login-section">
|
|
32
|
+
<h2>Iniciar Sesión</h2>
|
|
33
|
+
<form id="loginForm">
|
|
34
|
+
<div class="form-group">
|
|
35
|
+
<label for="username">Usuario:</label>
|
|
36
|
+
<input type="text" id="username" name="username" required>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div class="form-group">
|
|
40
|
+
<label for="password">Contraseña:</label>
|
|
41
|
+
<input type="password" id="password" name="password" required>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<button type="submit">Ingresar</button>
|
|
45
|
+
</form>
|
|
46
|
+
|
|
47
|
+
<div id="login-response"></div>
|
|
48
|
+
|
|
49
|
+
<p><em>Usuario: admin | Contraseña: password123</em></p>
|
|
50
|
+
</section>
|
|
51
|
+
</main>
|
|
52
|
+
|
|
53
|
+
<footer>
|
|
54
|
+
<p>© 2026 API SDK JS Framework</p>
|
|
55
|
+
</footer>
|
|
56
|
+
</div>
|
|
57
|
+
<script src="/script.js"></script>
|
|
58
|
+
<script>
|
|
59
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
60
|
+
const loginForm = document.getElementById('loginForm');
|
|
61
|
+
|
|
62
|
+
if (loginForm) {
|
|
63
|
+
loginForm.addEventListener('submit', function(e) {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
|
|
66
|
+
const formData = new FormData(loginForm);
|
|
67
|
+
const data = Object.fromEntries(formData);
|
|
68
|
+
|
|
69
|
+
fetch('/api/login', {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/json'
|
|
73
|
+
},
|
|
74
|
+
body: JSON.stringify(data)
|
|
75
|
+
})
|
|
76
|
+
.then(response => response.json())
|
|
77
|
+
.then(result => {
|
|
78
|
+
const responseDiv = document.getElementById('login-response');
|
|
79
|
+
|
|
80
|
+
if (result.success) {
|
|
81
|
+
responseDiv.innerHTML = '<p style="color: green;">Inicio de sesión exitoso. Redirigiendo...</p>';
|
|
82
|
+
|
|
83
|
+
// Redirigir después de un breve delay
|
|
84
|
+
setTimeout(() => {
|
|
85
|
+
window.location.href = '/messages';
|
|
86
|
+
}, 1500);
|
|
87
|
+
} else {
|
|
88
|
+
responseDiv.innerHTML = '<p style="color: red;">' + result.message + '</p>';
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
.catch(error => {
|
|
92
|
+
console.error('Error:', error);
|
|
93
|
+
const responseDiv = document.getElementById('login-response');
|
|
94
|
+
responseDiv.innerHTML = '<p style="color: red;">Error de conexión</p>';
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
</script>
|
|
100
|
+
</body>
|
|
101
|
+
</html>`;
|
|
102
|
+
|
|
103
|
+
res.writeHead(200);
|
|
104
|
+
res.end(html);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
// Procesar login
|
|
108
|
+
processLogin: async (req, res) => {
|
|
109
|
+
try {
|
|
110
|
+
// req.body puede ser un string o un objeto, dependiendo de cómo se haya procesado
|
|
111
|
+
let body;
|
|
112
|
+
if (typeof req.body === 'string') {
|
|
113
|
+
body = JSON.parse(req.body);
|
|
114
|
+
} else {
|
|
115
|
+
body = req.body;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { username, password } = body;
|
|
119
|
+
|
|
120
|
+
// Validar credenciales
|
|
121
|
+
const user = await messageController.validateUser(username, password);
|
|
122
|
+
|
|
123
|
+
if (user) {
|
|
124
|
+
// Crear sesión de usuario autenticado
|
|
125
|
+
if (req.session) {
|
|
126
|
+
req.session.create({
|
|
127
|
+
authenticated: true,
|
|
128
|
+
userId: user.id,
|
|
129
|
+
username: user.username
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
134
|
+
res.end(JSON.stringify({
|
|
135
|
+
success: true,
|
|
136
|
+
message: 'Inicio de sesión exitoso',
|
|
137
|
+
userId: user.id
|
|
138
|
+
}));
|
|
139
|
+
} else {
|
|
140
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
141
|
+
res.end(JSON.stringify({
|
|
142
|
+
success: false,
|
|
143
|
+
message: 'Credenciales inválidas'
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error('Error en login:', error);
|
|
148
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
149
|
+
res.end(JSON.stringify({
|
|
150
|
+
success: false,
|
|
151
|
+
message: 'Error interno del servidor'
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// Mostrar mensajes (requiere estar logueado - en este ejemplo simplificado no verificamos sesión)
|
|
157
|
+
showMessages: async (req, res) => {
|
|
158
|
+
try {
|
|
159
|
+
// Obtener mensajes de la base de datos
|
|
160
|
+
const messages = await messageController.getMessages();
|
|
161
|
+
|
|
162
|
+
const messagesHtml = messages.length > 0
|
|
163
|
+
? messages.map(msg => `
|
|
164
|
+
<div class="message-item">
|
|
165
|
+
<h4>${msg.name} (${msg.email})</h4>
|
|
166
|
+
<p>${msg.message}</p>
|
|
167
|
+
<small>Fecha: ${msg.created_at}</small>
|
|
168
|
+
</div>
|
|
169
|
+
`).join('')
|
|
170
|
+
: '<p>No hay mensajes aún.</p>';
|
|
171
|
+
|
|
172
|
+
const html = `
|
|
173
|
+
<!DOCTYPE html>
|
|
174
|
+
<html lang="es">
|
|
175
|
+
<head>
|
|
176
|
+
<meta charset="UTF-8">
|
|
177
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
178
|
+
<title>Mensajes - API Frontend Demo</title>
|
|
179
|
+
<link rel="stylesheet" href="/styles.css">
|
|
180
|
+
</head>
|
|
181
|
+
<body>
|
|
182
|
+
<div class="container">
|
|
183
|
+
<header>
|
|
184
|
+
<h1>Mensajes Recibidos</h1>
|
|
185
|
+
<nav>
|
|
186
|
+
<ul>
|
|
187
|
+
<li><a href="/">Inicio</a></li>
|
|
188
|
+
<li><a href="/about">Acerca de</a></li>
|
|
189
|
+
<li><a href="/contact">Contacto</a></li>
|
|
190
|
+
<li><a href="/login">Login</a></li>
|
|
191
|
+
<li><a href="/api/users">Usuarios (API)</a></li>
|
|
192
|
+
</ul>
|
|
193
|
+
</nav>
|
|
194
|
+
</header>
|
|
195
|
+
|
|
196
|
+
<main>
|
|
197
|
+
<section class="messages-section">
|
|
198
|
+
${messagesHtml}
|
|
199
|
+
</section>
|
|
200
|
+
</main>
|
|
201
|
+
|
|
202
|
+
<footer>
|
|
203
|
+
<p>© 2026 API SDK JS Framework</p>
|
|
204
|
+
</footer>
|
|
205
|
+
</div>
|
|
206
|
+
<script src="/script.js"></script>
|
|
207
|
+
</body>
|
|
208
|
+
</html>`;
|
|
209
|
+
|
|
210
|
+
res.writeHead(200);
|
|
211
|
+
res.end(html);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.error('Error obteniendo mensajes:', error);
|
|
214
|
+
res.writeHead(500);
|
|
215
|
+
res.end('<h1>Error obteniendo mensajes</h1>');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
module.exports = authController;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const messageController = require('./messageController');
|
|
2
|
+
|
|
3
|
+
const formController = {
|
|
4
|
+
// Procesar el envío del formulario de contacto
|
|
5
|
+
processContactForm: async (req, res) => {
|
|
6
|
+
try {
|
|
7
|
+
// req.body puede ser un string o un objeto, dependiendo de cómo se haya procesado
|
|
8
|
+
let body;
|
|
9
|
+
if (typeof req.body === 'string') {
|
|
10
|
+
body = JSON.parse(req.body);
|
|
11
|
+
} else {
|
|
12
|
+
body = req.body;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { name, email, message } = body;
|
|
16
|
+
|
|
17
|
+
// Validar campos
|
|
18
|
+
if (!name || !email || !message) {
|
|
19
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
20
|
+
res.end(JSON.stringify({
|
|
21
|
+
success: false,
|
|
22
|
+
message: 'Todos los campos son obligatorios'
|
|
23
|
+
}));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Guardar el mensaje en la base de datos
|
|
28
|
+
await messageController.saveMessage(name, email, message);
|
|
29
|
+
|
|
30
|
+
// Responder con éxito
|
|
31
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
32
|
+
res.end(JSON.stringify({
|
|
33
|
+
success: true,
|
|
34
|
+
message: 'Mensaje enviado exitosamente'
|
|
35
|
+
}));
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('Error procesando formulario:', error);
|
|
38
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
39
|
+
res.end(JSON.stringify({
|
|
40
|
+
success: false,
|
|
41
|
+
message: 'Error interno del servidor'
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
module.exports = formController;
|