jerkjs 2.5.8 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +162 -99
  2. package/README.md +113 -190
  3. package/RESULTADOS_WAF.md +63 -0
  4. package/doc-2.5/MANUAL_MODULOS_ADMIN.md +287 -0
  5. package/doc-2.5/QUEUE_CLI_MODULE_MANUAL.md +289 -0
  6. package/doc-2.5/QUEUE_SYSTEM_MANUAL.md +320 -0
  7. package/doc-2.5/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
  8. package/doc-2.5/WAF_MODULE_MANUAL.md +229 -0
  9. package/index.js +12 -3
  10. package/jerk-admin-client/README.md +69 -0
  11. package/jerk-admin-client/package.json +23 -0
  12. package/jerk-admin-client.js +257 -0
  13. package/lib/admin/AdminExtension.js +74 -19
  14. package/lib/admin/modules/ControllerGeneratorModule.js +414 -0
  15. package/lib/admin/modules/QueueManagementModule.js +265 -0
  16. package/lib/admin/modules/RouteCacheModule.js +227 -0
  17. package/lib/admin/modules/RouteManagerModule.js +468 -0
  18. package/lib/admin/modules/STATS_MODULE_README.md +15 -0
  19. package/lib/admin/modules/ViewCacheStatsModule.js +92 -0
  20. package/lib/admin/modules/WAFModule.js +737 -0
  21. package/lib/core/server.js +72 -69
  22. package/lib/middleware/firewall.js +112 -17
  23. package/lib/mvc/viewEngine.js +69 -10
  24. package/lib/queue/GlobalQueueStorage.js +38 -0
  25. package/lib/queue/QueueSystem.js +451 -0
  26. package/lib/queue/admin_example.js +114 -0
  27. package/lib/queue/example.js +268 -0
  28. package/lib/queue/integration.js +109 -0
  29. package/lib/utils/globalViewCacheInfo.js +16 -0
  30. package/lib/utils/globalWAFStats.js +54 -0
  31. package/package.json +2 -2
  32. package/test-colors.js +46 -0
  33. package/test-help-alias.js +31 -0
  34. package/ESTADISTICAS_RENDIMIENTO.md +0 -106
  35. package/debug_hook.js +0 -11
  36. package/docs/CACHE_SYSTEM_MAP.md +0 -206
@@ -168,29 +168,31 @@ class AdminExtension {
168
168
  loadCustomModules() {
169
169
  const fs = require('fs');
170
170
  const path = require('path');
171
-
171
+
172
172
  try {
173
173
  const modulesDir = path.join(__dirname, 'modules');
174
-
174
+
175
175
  if (fs.existsSync(modulesDir)) {
176
176
  const files = fs.readdirSync(modulesDir);
177
-
177
+
178
178
  for (const file of files) {
179
179
  if (file.endsWith('.js') && file !== 'index.js') {
180
180
  try {
181
181
  const moduleName = file.replace('.js', '');
182
- const ModuleClass = require(path.join(modulesDir, file));
183
182
 
183
+ const ModuleClass = require(path.join(modulesDir, file));
184
+
184
185
  if (typeof ModuleClass === 'function') {
185
186
  const moduleInstance = new ModuleClass(this);
186
-
187
+
187
188
  this.modules.set(moduleName.toLowerCase(), {
188
189
  name: moduleInstance.name,
189
190
  description: moduleInstance.description,
190
191
  commands: moduleInstance.commands,
191
- handler: (command, socket) => moduleInstance.handleCommand(command, socket)
192
+ handler: (command, socket) => moduleInstance.handleCommand(command, socket),
193
+ instance: moduleInstance // Mantener referencia a la instancia para manejo interactivo
192
194
  });
193
-
195
+
194
196
  console.log(`Módulo '${moduleName}' cargado exitosamente.`);
195
197
  }
196
198
  } catch (moduleError) {
@@ -233,8 +235,18 @@ class AdminExtension {
233
235
  break;
234
236
  case 'status':
235
237
  socket.write(`\nEstado del servidor:\n`);
236
- socket.write(`- Puerto: ${this.port}\n`);
237
- socket.write(`- Host: ${this.host}\n`);
238
+ socket.write(`- Puerto del servidor de administración: ${this.port}\n`);
239
+ socket.write(`- Host del servidor de administración: ${this.host}\n`);
240
+
241
+ // Mostrar información del servidor principal si está disponible
242
+ if (this.frameworkInstance) {
243
+ socket.write(`- Puerto del servidor principal: ${this.frameworkInstance.port || 'desconocido'}\n`);
244
+ socket.write(`- Host del servidor principal: ${this.frameworkInstance.host || 'desconocido'}\n`);
245
+ } else {
246
+ socket.write(`- Puerto del servidor principal: desconocido\n`);
247
+ socket.write(`- Host del servidor principal: desconocido\n`);
248
+ }
249
+
238
250
  socket.write(`- Clientes conectados: ${this.clients.size}\n`);
239
251
  socket.write(`- Rutas registradas: ${this.registeredRoutes.length}\n`);
240
252
  socket.write(`- Rutas activas: ${this.activeRoutes.size}\n\n`);
@@ -271,10 +283,10 @@ class AdminExtension {
271
283
 
272
284
  socket.write(`Comandos disponibles:\n`);
273
285
  for (const [name, module] of this.modules) {
274
- socket.write(` ${module.commands.join(', ')} - ${module.description}\n`);
286
+ socket.write(` \x1b[32m${module.commands.join(', ')}\x1b[0m - ${module.description}\n`);
275
287
  }
276
- socket.write(` help - Mostrar esta ayuda\n`);
277
- socket.write(` quit - Cerrar conexión\n\n`);
288
+ socket.write(` \x1b[32mhelp, ?\x1b[0m - Mostrar esta ayuda\n`);
289
+ socket.write(` \x1b[32mquit\x1b[0m - Cerrar conexión\n\n`);
278
290
 
279
291
  socket.write(`> `);
280
292
 
@@ -282,16 +294,59 @@ class AdminExtension {
282
294
  const input = data.toString();
283
295
  // Dividir la entrada en líneas y procesar cada una
284
296
  const lines = input.split('\n').filter(line => line.trim() !== '');
285
-
297
+
286
298
  for (const line of lines) {
299
+ // Verificar si hay un proceso interactivo activo para este socket
300
+ const controllerGenModule = this.modules.get('controllergeneratormodule');
301
+ if (controllerGenModule && controllerGenModule.instance && controllerGenModule.instance.currentProcess) {
302
+ const sessionId = controllerGenModule.instance.getSessionId(socket);
303
+ if (controllerGenModule.instance.currentProcess.has(sessionId)) {
304
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
305
+ controllerGenModule.instance.processInput(socket, line.trim());
306
+ continue; // Saltar el procesamiento normal
307
+ }
308
+ }
309
+
310
+ // Verificar si hay un proceso interactivo activo para el módulo de gestión de rutas
311
+ const routeManagerModule = this.modules.get('routemanagermodule');
312
+ if (routeManagerModule && routeManagerModule.instance && routeManagerModule.instance.currentProcess) {
313
+ const sessionId = routeManagerModule.instance.getSessionId(socket);
314
+ if (routeManagerModule.instance.currentProcess.has(sessionId)) {
315
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
316
+ routeManagerModule.instance.processInput(socket, line.trim());
317
+ continue; // Saltar el procesamiento normal
318
+ }
319
+ }
320
+
321
+ // Verificar si hay un proceso interactivo activo para el módulo de WAF
322
+ const wafModule = this.modules.get('wafmodule');
323
+ if (wafModule && wafModule.instance && wafModule.instance.currentProcess) {
324
+ const sessionId = wafModule.instance.getSessionId(socket);
325
+ if (wafModule.instance.currentProcess.has(sessionId)) {
326
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
327
+ wafModule.instance.processInput(socket, line.trim());
328
+ continue; // Saltar el procesamiento normal
329
+ }
330
+ }
331
+
332
+ // Verificar si hay un proceso interactivo activo para el módulo de gestión de colas
333
+ const queueModule = this.modules.get('queuemanagementmodule');
334
+ if (queueModule && queueModule.instance && queueModule.instance.inputState &&
335
+ queueModule.instance.inputState.has(socket)) {
336
+ // Si hay un proceso interactivo activo, delegar el manejo de la entrada
337
+ queueModule.instance.processQueueAction(socket, queueModule.instance.inputState.get(socket).action, line.trim());
338
+ continue; // Saltar el procesamiento normal
339
+ }
340
+
287
341
  const command = line.trim().toLowerCase();
288
342
  console.log(`DEBUG: Comando recibido: "${command}"`); // Mensaje de depuración
289
-
343
+
290
344
  // Verificar si es un comando de sistema
291
- if (['help', 'quit', 'exit'].includes(command)) {
345
+ if (['help', 'quit', 'exit', '?'].includes(command)) {
292
346
  console.log(`DEBUG: Comando de sistema encontrado: ${command}`); // Mensaje de depuración
293
347
  switch (command) {
294
348
  case 'help':
349
+ case '?':
295
350
  this.sendHelp(socket);
296
351
  break;
297
352
  case 'quit':
@@ -309,7 +364,7 @@ class AdminExtension {
309
364
  let handled = false;
310
365
  console.log(`DEBUG: Buscando módulo para el comando "${command}"`); // Mensaje de depuración
311
366
  console.log(`DEBUG: Módulos disponibles:`, Array.from(this.modules.keys())); // Mensaje de depuración
312
-
367
+
313
368
  for (const [moduleName, module] of this.modules) {
314
369
  console.log(`DEBUG: Revisando módulo "${moduleName}", comandos:`, module.commands); // Mensaje de depuración
315
370
  if (module.commands.includes(command)) {
@@ -403,11 +458,11 @@ class AdminExtension {
403
458
  socket.write(`Módulos disponibles:\n`);
404
459
  for (const [name, module] of this.modules) {
405
460
  socket.write(` ${name}: ${module.description}\n`);
406
- socket.write(` Comandos: ${module.commands.join(', ')}\n`);
461
+ socket.write(` Comandos: \x1b[32m${module.commands.join(', ')}\x1b[0m\n`);
407
462
  }
408
463
  socket.write(`\nComandos generales:\n`);
409
- socket.write(` help - Mostrar esta ayuda\n`);
410
- socket.write(` quit - Cerrar conexión\n\n`);
464
+ socket.write(` \x1b[32mhelp, ?\x1b[0m - Mostrar esta ayuda\n`);
465
+ socket.write(` \x1b[32mquit\x1b[0m - Cerrar conexión\n\n`);
411
466
  socket.write(`> `);
412
467
  }
413
468
 
@@ -0,0 +1,414 @@
1
+ /**
2
+ * Módulo de Generación de Controladores para la Extensión de Administración de JERK Framework
3
+ * Módulo personalizado para crear controladores de manera interactiva
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ class ControllerGeneratorModule {
10
+ /**
11
+ * Constructor del módulo de generación de controladores
12
+ * @param {Object} adminExtension - Instancia de la extensión de administración
13
+ */
14
+ constructor(adminExtension) {
15
+ this.adminExtension = adminExtension;
16
+ this.name = 'Controller Generator Module';
17
+ this.description = 'Módulo para crear controladores de manera interactiva';
18
+ this.commands = ['generate-controller', 'gen-ctrl', 'new-ctrl'];
19
+
20
+ // Estado para el proceso interactivo
21
+ this.currentProcess = new Map(); // Almacena el estado de generación por socket
22
+ }
23
+
24
+ /**
25
+ * Manejador para los comandos del módulo de generación de controladores
26
+ * @param {string} command - Comando a ejecutar
27
+ * @param {Object} socket - Socket de la conexión
28
+ */
29
+ handleCommand(command, socket) {
30
+ switch (command) {
31
+ case 'generate-controller':
32
+ case 'gen-ctrl':
33
+ case 'new-ctrl':
34
+ this.startControllerGeneration(socket);
35
+ break;
36
+ default:
37
+ socket.write(`Comando desconocido para el módulo de generación de controladores: ${command}\n`);
38
+ socket.write(`Comandos disponibles: generate-controller, gen-ctrl, new-ctrl\n\n`);
39
+ socket.write(`> `);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Inicia el proceso interactivo de generación de controlador
45
+ * @param {Object} socket - Socket de la conexión
46
+ */
47
+ startControllerGeneration(socket) {
48
+ const sessionId = this.getSessionId(socket);
49
+
50
+ // Inicializar el estado de la sesión
51
+ this.currentProcess.set(sessionId, {
52
+ step: 'name',
53
+ controllerData: {}
54
+ });
55
+
56
+ socket.write('\n=== Generador de Controladores ===\n');
57
+ socket.write('Por favor, introduce el nombre del controlador (sin la palabra "Controller"):\n');
58
+ socket.write('(Ej: "User", "Product", "Home")\n');
59
+ socket.write('Para cancelar, escribe "cancel"\n');
60
+ socket.write('> ');
61
+ }
62
+
63
+ /**
64
+ * Obtiene un ID único para la sesión del socket
65
+ * @param {Object} socket - Socket de la conexión
66
+ * @returns {string} - ID de sesión
67
+ */
68
+ getSessionId(socket) {
69
+ // Usar la dirección remota y puerto como identificador único
70
+ return `${socket.remoteAddress}:${socket.remotePort}`;
71
+ }
72
+
73
+ /**
74
+ * Procesa la entrada del usuario durante el proceso interactivo
75
+ * @param {Object} socket - Socket de la conexión
76
+ * @param {string} input - Entrada del usuario
77
+ */
78
+ processInput(socket, input) {
79
+ const sessionId = this.getSessionId(socket);
80
+ const processState = this.currentProcess.get(sessionId);
81
+
82
+ if (!processState) {
83
+ socket.write('No hay proceso activo. Usa "generate-controller" para iniciar.\n> ');
84
+ return;
85
+ }
86
+
87
+ const userInput = input.trim();
88
+
89
+ if (userInput.toLowerCase() === 'cancel') {
90
+ this.cancelProcess(socket, sessionId);
91
+ return;
92
+ }
93
+
94
+ switch (processState.step) {
95
+ case 'name':
96
+ this.handleControllerName(socket, sessionId, userInput);
97
+ break;
98
+ case 'methods':
99
+ this.handleMethodsSelection(socket, sessionId, userInput);
100
+ break;
101
+ case 'confirm':
102
+ this.handleConfirmation(socket, sessionId, userInput);
103
+ break;
104
+ case 'path':
105
+ this.handleControllerPath(socket, sessionId, userInput);
106
+ break;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Maneja la entrada del nombre del controlador
112
+ * @param {Object} socket - Socket de la conexión
113
+ * @param {string} sessionId - ID de la sesión
114
+ * @param {string} name - Nombre del controlador
115
+ */
116
+ handleControllerName(socket, sessionId, name) {
117
+ if (!name) {
118
+ socket.write('El nombre no puede estar vacío. Por favor, introduce un nombre válido:\n> ');
119
+ return;
120
+ }
121
+
122
+ // Validar nombre (solo letras, números y guiones bajos)
123
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
124
+ socket.write('Nombre inválido. Usa solo letras, números y guiones bajos, comenzando con una letra o guión bajo:\n> ');
125
+ return;
126
+ }
127
+
128
+ const processState = this.currentProcess.get(sessionId);
129
+ processState.controllerData.name = name;
130
+ processState.step = 'methods';
131
+
132
+ socket.write(`\nNombre del controlador: ${name}Controller\n`);
133
+ socket.write('\nSelecciona los métodos que deseas incluir (separados por comas):\n');
134
+ socket.write('Opciones disponibles:\n');
135
+ socket.write(' 1. index - Método para mostrar lista de elementos\n');
136
+ socket.write(' 2. show - Método para mostrar un elemento específico\n');
137
+ socket.write(' 3. create - Método para crear un nuevo elemento\n');
138
+ socket.write(' 4. update - Método para actualizar un elemento\n');
139
+ socket.write(' 5. delete - Método para eliminar un elemento\n');
140
+ socket.write(' 6. All - Todos los métodos anteriores\n');
141
+ socket.write('\nEjemplos: "1,2,3" o "index,show,create" o "All"\n> ');
142
+ }
143
+
144
+ /**
145
+ * Maneja la selección de métodos
146
+ * @param {Object} socket - Socket de la conexión
147
+ * @param {string} sessionId - ID de la sesión
148
+ * @param {string} selection - Selección de métodos
149
+ */
150
+ handleMethodsSelection(socket, sessionId, selection) {
151
+ const processState = this.currentProcess.get(sessionId);
152
+ const methodsMap = {
153
+ '1': 'index', '2': 'show', '3': 'create', '4': 'update', '5': 'delete'
154
+ };
155
+
156
+ let selectedMethods = [];
157
+
158
+ if (selection.toLowerCase() === 'all') {
159
+ selectedMethods = ['index', 'show', 'create', 'update', 'delete'];
160
+ } else {
161
+ // Separar por comas y procesar cada selección
162
+ const selections = selection.split(',').map(s => s.trim());
163
+
164
+ for (const sel of selections) {
165
+ if (methodsMap[sel]) {
166
+ selectedMethods.push(methodsMap[sel]);
167
+ } else if (['index', 'show', 'create', 'update', 'delete'].includes(sel)) {
168
+ selectedMethods.push(sel);
169
+ } else {
170
+ socket.write(`Selección inválida: ${sel}. Por favor, selecciona métodos válidos:\n> `);
171
+ return;
172
+ }
173
+ }
174
+ }
175
+
176
+ // Eliminar duplicados
177
+ selectedMethods = [...new Set(selectedMethods)];
178
+
179
+ processState.controllerData.methods = selectedMethods;
180
+ processState.step = 'path';
181
+
182
+ socket.write(`\nMétodos seleccionados: ${selectedMethods.join(', ')}\n`);
183
+ socket.write('\nIndica la ruta donde deseas crear el archivo del controlador:\n');
184
+ socket.write('(Ruta relativa desde la raíz del proyecto, ej: "./controllers/", "./src/controllers/")\n');
185
+ socket.write('Deja vacío para usar "./controllers/" por defecto:\n> ');
186
+ }
187
+
188
+ /**
189
+ * Maneja la selección de la ruta del controlador
190
+ * @param {Object} socket - Socket de la conexión
191
+ * @param {string} sessionId - ID de la sesión
192
+ * @param {string} pathInput - Ruta ingresada
193
+ */
194
+ handleControllerPath(socket, sessionId, pathInput) {
195
+ const processState = this.currentProcess.get(sessionId);
196
+
197
+ // Usar la ruta por defecto si no se proporciona ninguna
198
+ const controllerPath = pathInput.trim() || './controllers/';
199
+
200
+ // Asegurarse de que termine con '/'
201
+ const normalizedPath = controllerPath.endsWith('/') ? controllerPath : controllerPath + '/';
202
+
203
+ processState.controllerData.path = normalizedPath;
204
+ processState.step = 'confirm';
205
+
206
+ socket.write(`\nRuta del controlador: ${normalizedPath}\n`);
207
+ this.showControllerPreview(socket, processState.controllerData);
208
+ }
209
+
210
+ /**
211
+ * Muestra una vista previa del controlador que se va a generar
212
+ * @param {Object} socket - Socket de la conexión
213
+ * @param {Object} controllerData - Datos del controlador
214
+ */
215
+ showControllerPreview(socket, controllerData) {
216
+ socket.write('\n=== Vista Previa del Controlador ===\n');
217
+ socket.write(`Nombre del archivo: ${controllerData.name}Controller.js\n\n`);
218
+
219
+ let preview = `const ControllerBase = require('../../index.js').ControllerBase;\n\n`;
220
+ preview += `class ${controllerData.name}Controller extends ControllerBase {\n`;
221
+
222
+ for (const method of controllerData.methods) {
223
+ preview += this.generateMethodSkeleton(method, controllerData.name);
224
+ }
225
+
226
+ preview += `}\n\n`;
227
+ preview += `module.exports = new ${controllerData.name}Controller();\n`;
228
+
229
+ socket.write(preview);
230
+ socket.write('\n¿Deseas crear este controlador? (sí/no):\n> ');
231
+ }
232
+
233
+ /**
234
+ * Genera el esqueleto de un método
235
+ * @param {string} method - Nombre del método
236
+ * @param {string} controllerName - Nombre del controlador
237
+ * @returns {string} - Código del método
238
+ */
239
+ generateMethodSkeleton(method, controllerName) {
240
+ let skeleton = '';
241
+
242
+ switch (method) {
243
+ case 'index':
244
+ skeleton += ` async index(req, res) {\n`;
245
+ skeleton += ` try {\n`;
246
+ skeleton += ` // Lógica para obtener y mostrar una lista de ${controllerName.toLowerCase()}s\n`;
247
+ skeleton += ` const items = await this.loadModel('${controllerName}Model').then(model => model.find({}));\n`;
248
+ skeleton += ` \n`;
249
+ skeleton += ` res.render('${controllerName.toLowerCase()}/index', { \n`;
250
+ skeleton += ` title: '${controllerName}s',\n`;
251
+ skeleton += ` items\n`;
252
+ skeleton += ` });\n`;
253
+ skeleton += ` } catch (error) {\n`;
254
+ skeleton += ` console.error('Error en el método index:', error);\n`;
255
+ skeleton += ` res.writeHead(500, { 'Content-Type': 'application/json' });\n`;
256
+ skeleton += ` res.end(JSON.stringify({ error: 'Error interno del servidor' }));\n`;
257
+ skeleton += ` }\n`;
258
+ skeleton += ` }\n\n`;
259
+ break;
260
+
261
+ case 'show':
262
+ skeleton += ` async show(req, res) {\n`;
263
+ skeleton += ` try {\n`;
264
+ skeleton += ` const id = req.params.id;\n`;
265
+ skeleton += ` // Lógica para obtener y mostrar un ${controllerName.toLowerCase()} específico\n`;
266
+ skeleton += ` const item = await this.loadModel('${controllerName}Model').then(model => model.findOne({ id: parseInt(id) }));\n`;
267
+ skeleton += ` \n`;
268
+ skeleton += ` if (!item) {\n`;
269
+ skeleton += ` res.writeHead(404, { 'Content-Type': 'application/json' });\n`;
270
+ skeleton += ` res.end(JSON.stringify({ error: '${controllerName} no encontrado' }));\n`;
271
+ skeleton += ` return;\n`;
272
+ skeleton += ` }\n`;
273
+ skeleton += ` \n`;
274
+ skeleton += ` res.render('${controllerName.toLowerCase()}/show', { \n`;
275
+ skeleton += ` title: '${controllerName} #' + id,\n`;
276
+ skeleton += ` item\n`;
277
+ skeleton += ` });\n`;
278
+ skeleton += ` } catch (error) {\n`;
279
+ skeleton += ` console.error('Error en el método show:', error);\n`;
280
+ skeleton += ` res.writeHead(500, { 'Content-Type': 'application/json' });\n`;
281
+ skeleton += ` res.end(JSON.stringify({ error: 'Error interno del servidor' }));\n`;
282
+ skeleton += ` }\n`;
283
+ skeleton += ` }\n\n`;
284
+ break;
285
+
286
+ case 'create':
287
+ skeleton += ` async create(req, res) {\n`;
288
+ skeleton += ` try {\n`;
289
+ skeleton += ` // Lógica para crear un nuevo ${controllerName.toLowerCase()}\n`;
290
+ skeleton += ` const data = req.body;\n`;
291
+ skeleton += ` const newItem = await this.loadModel('${controllerName}Model').then(model => model.create(data));\n`;
292
+ skeleton += ` \n`;
293
+ skeleton += ` res.writeHead(201, { 'Content-Type': 'application/json' });\n`;
294
+ skeleton += ` res.end(JSON.stringify({ success: true, data: newItem }));\n`;
295
+ skeleton += ` } catch (error) {\n`;
296
+ skeleton += ` console.error('Error en el método create:', error);\n`;
297
+ skeleton += ` res.writeHead(400, { 'Content-Type': 'application/json' });\n`;
298
+ skeleton += ` res.end(JSON.stringify({ error: error.message }));\n`;
299
+ skeleton += ` }\n`;
300
+ skeleton += ` }\n\n`;
301
+ break;
302
+
303
+ case 'update':
304
+ skeleton += ` async update(req, res) {\n`;
305
+ skeleton += ` try {\n`;
306
+ skeleton += ` const id = req.params.id;\n`;
307
+ skeleton += ` const data = req.body;\n`;
308
+ skeleton += ` // Lógica para actualizar un ${controllerName.toLowerCase()} existente\n`;
309
+ skeleton += ` const result = await this.loadModel('${controllerName}Model').then(model => model.update({ id: parseInt(id) }, data));\n`;
310
+ skeleton += ` \n`;
311
+ skeleton += ` res.writeHead(200, { 'Content-Type': 'application/json' });\n`;
312
+ skeleton += ` res.end(JSON.stringify({ success: true, data: result }));\n`;
313
+ skeleton += ` } catch (error) {\n`;
314
+ skeleton += ` console.error('Error en el método update:', error);\n`;
315
+ skeleton += ` res.writeHead(400, { 'Content-Type': 'application/json' });\n`;
316
+ skeleton += ` res.end(JSON.stringify({ error: error.message }));\n`;
317
+ skeleton += ` }\n`;
318
+ skeleton += ` }\n\n`;
319
+ break;
320
+
321
+ case 'delete':
322
+ skeleton += ` async delete(req, res) {\n`;
323
+ skeleton += ` try {\n`;
324
+ skeleton += ` const id = req.params.id;\n`;
325
+ skeleton += ` // Lógica para eliminar un ${controllerName.toLowerCase()}\n`;
326
+ skeleton += ` const result = await this.loadModel('${controllerName}Model').then(model => model.delete({ id: parseInt(id) }));\n`;
327
+ skeleton += ` \n`;
328
+ skeleton += ` res.writeHead(200, { 'Content-Type': 'application/json' });\n`;
329
+ skeleton += ` res.end(JSON.stringify({ success: true, message: '${controllerName} eliminado correctamente' }));\n`;
330
+ skeleton += ` } catch (error) {\n`;
331
+ skeleton += ` console.error('Error en el método delete:', error);\n`;
332
+ skeleton += ` res.writeHead(400, { 'Content-Type': 'application/json' });\n`;
333
+ skeleton += ` res.end(JSON.stringify({ error: error.message }));\n`;
334
+ skeleton += ` }\n`;
335
+ skeleton += ` }\n\n`;
336
+ break;
337
+ }
338
+
339
+ return skeleton;
340
+ }
341
+
342
+ /**
343
+ * Maneja la confirmación de creación del controlador
344
+ * @param {Object} socket - Socket de la conexión
345
+ * @param {string} sessionId - ID de la sesión
346
+ * @param {string} confirmation - Confirmación del usuario
347
+ */
348
+ handleConfirmation(socket, sessionId, confirmation) {
349
+ const processState = this.currentProcess.get(sessionId);
350
+
351
+ if (confirmation.toLowerCase() === 'sí' || confirmation.toLowerCase() === 'si' || confirmation.toLowerCase() === 'yes') {
352
+ this.createControllerFile(socket, processState.controllerData);
353
+ } else {
354
+ socket.write('\nGeneración del controlador cancelada.\n> ');
355
+ this.currentProcess.delete(sessionId);
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Crea el archivo del controlador
361
+ * @param {Object} socket - Socket de la conexión
362
+ * @param {Object} controllerData - Datos del controlador
363
+ */
364
+ createControllerFile(socket, controllerData) {
365
+ const { name, methods, path: controllerPath } = controllerData;
366
+
367
+ // Crear el contenido del archivo
368
+ let content = `const ControllerBase = require('../../index.js').ControllerBase;\n\n`;
369
+ content += `class ${name}Controller extends ControllerBase {\n`;
370
+
371
+ for (const method of methods) {
372
+ content += this.generateMethodSkeleton(method, name);
373
+ }
374
+
375
+ content += `}\n\n`;
376
+ content += `module.exports = new ${name}Controller();\n`;
377
+
378
+ // Crear directorio si no existe
379
+ const fullPath = path.join(process.cwd(), controllerPath);
380
+ if (!fs.existsSync(fullPath)) {
381
+ fs.mkdirSync(fullPath, { recursive: true });
382
+ }
383
+
384
+ // Ruta completa del archivo
385
+ const filePath = path.join(fullPath, `${name}Controller.js`);
386
+
387
+ try {
388
+ // Escribir el archivo
389
+ fs.writeFileSync(filePath, content);
390
+
391
+ socket.write(`\n✅ Controlador "${name}Controller" creado exitosamente en:\n${filePath}\n`);
392
+ socket.write(`\nMétodos incluidos: ${methods.join(', ')}\n`);
393
+ socket.write('\n> ');
394
+ } catch (error) {
395
+ socket.write(`\n❌ Error al crear el archivo: ${error.message}\n> `);
396
+ }
397
+
398
+ // Limpiar el estado
399
+ const sessionId = this.getSessionId(socket);
400
+ this.currentProcess.delete(sessionId);
401
+ }
402
+
403
+ /**
404
+ * Cancela el proceso de generación
405
+ * @param {Object} socket - Socket de la conexión
406
+ * @param {string} sessionId - ID de la sesión
407
+ */
408
+ cancelProcess(socket, sessionId) {
409
+ this.currentProcess.delete(sessionId);
410
+ socket.write('\nProceso cancelado.\n> ');
411
+ }
412
+ }
413
+
414
+ module.exports = ControllerGeneratorModule;