blackcoffee2 2.1.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.
Files changed (170) hide show
  1. package/CHANGELOG.md +664 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +25 -0
  4. package/README.md +246 -0
  5. package/apps.zip +0 -0
  6. package/bin/adminclient +105 -0
  7. package/bin/blackcoffee +133 -0
  8. package/cli/admin-users.js +282 -0
  9. package/cli/commands/app.js +561 -0
  10. package/cli/commands/config.js +182 -0
  11. package/cli/commands/db.js +257 -0
  12. package/cli/commands/server.js +200 -0
  13. package/config/applications.json +5 -0
  14. package/config/database.json +28 -0
  15. package/config/database.json.example +23 -0
  16. package/config/server.json +32 -0
  17. package/controllers/admin/AdminController.js +529 -0
  18. package/controllers/admin/AdminViewController.js +90 -0
  19. package/controllers/admin/AuthController.js +293 -0
  20. package/controllers/admin/DatabaseAdminController.js +218 -0
  21. package/core/SQLiteAdapter.js +333 -0
  22. package/core/appLoader.js +385 -0
  23. package/core/databasePoolManager.js +431 -0
  24. package/core/hotReload.js +363 -0
  25. package/data/ADMIN-README.md +145 -0
  26. package/data/CHANGELOG.md +48 -0
  27. package/data/GTK3-NODE-PROPOSALS.md +410 -0
  28. package/data/admin-db.js +150 -0
  29. package/data/admin-gui.js +452 -0
  30. package/data/blackcoffee_admin.db-shm +0 -0
  31. package/data/blackcoffee_admin.db-wal +0 -0
  32. package/data/migrations/001_create_admin_users.sql +33 -0
  33. package/docs/APP_HOOKS_HANDLER.md +432 -0
  34. package/docs/APP_HOOKS_REQUIREMENTS.md +588 -0
  35. package/docs/ARCHITECTURE.md +435 -0
  36. package/docs/CREAR_APP_Y_USAR_POOLS.md +1595 -0
  37. package/docs/EVENTS_APP_MANUAL.md +289 -0
  38. package/docs/INSITU_BINARY_UPLOAD_PROPOSAL.md +186 -0
  39. package/docs/INSITU_FIREWALL_EXCEPTION.md +187 -0
  40. package/docs/ROADMAP.md +242 -0
  41. package/docs/ROADMAP.md.backup +243 -0
  42. package/includes/404-hooks.js +423 -0
  43. package/includes/adminAuth.js +214 -0
  44. package/includes/adminExtension.js +53 -0
  45. package/includes/appHooks.js +302 -0
  46. package/includes/initAdminDb.js +115 -0
  47. package/includes/routeLoader.js +67 -0
  48. package/includes/sessions.js +223 -0
  49. package/issues/001-duplicate-module-loading.md +92 -0
  50. package/manuales/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
  51. package/manuales/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
  52. package/manuales/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
  53. package/manuales/CACHE_REGEX_COMMANDS.md +136 -0
  54. package/manuales/CACHE_SYSTEM_MAP.md +206 -0
  55. package/manuales/CREACION_DE_CONTROLADORES_INSITU.md +383 -0
  56. package/manuales/QUEUE_CLI_MODULE_MANUAL.md +289 -0
  57. package/manuales/QUEUE_SYSTEM_MANUAL.md +320 -0
  58. package/manuales/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
  59. package/manuales/SESSION_MANAGER_GUIDE.md +529 -0
  60. package/manuales/SESSION_SECURITY_FLAGS.md +174 -0
  61. package/manuales/WAF_MODULE_MANUAL.md +229 -0
  62. package/manuales/after_route_handler_filter_example.md +116 -0
  63. package/manuales/after_route_handler_usage.md +130 -0
  64. package/manuales/an/303/241lisis-completo-insitu-framework.md +213 -0
  65. package/manuales/async_hooks_promises_guide.md +325 -0
  66. package/manuales/before_route_handler_filter_example.md +97 -0
  67. package/manuales/before_route_handler_usage.md +122 -0
  68. package/manuales/hooks_chaining_conditions_guide.md +261 -0
  69. package/manuales/hooks_filters_documentation.md +493 -0
  70. package/manuales/hooks_filters_documentation_en.md +493 -0
  71. package/manuales/hooks_vs_middlewares_comparison.md +87 -0
  72. package/manuales/manual-mvc-completo.md +934 -0
  73. package/manuales/modulos_administracion.md +89 -0
  74. package/manuales/router_execution_points.md +74 -0
  75. package/manuales/static_file_hooks_usage.md +222 -0
  76. package/models/AdminUserModel.js +132 -0
  77. package/package.json +45 -0
  78. package/programatically/PRoutes.js +89 -0
  79. package/programatically/initFlow.js +211 -0
  80. package/public/admin/css/db-pools.css +336 -0
  81. package/public/admin/css/styles.css +310 -0
  82. package/public/admin/database.html +312 -0
  83. package/public/admin/index.html +116 -0
  84. package/public/admin/js/app.js +470 -0
  85. package/public/admin/js/db-pools.js +253 -0
  86. package/public/admin/login.html +278 -0
  87. package/public/assets/css/styles.css +477 -0
  88. package/public/assets/js/main.js +89 -0
  89. package/public/index.html +136 -0
  90. package/public/templates/404.html +158 -0
  91. package/routes/admin-views.json +20 -0
  92. package/routes/admin.json +38 -0
  93. package/routes/auth.json +32 -0
  94. package/routes/static.json +18 -0
  95. package/server.js +299 -0
  96. package/test-aplicacion.con-logisession/BlackCoffee.js +226 -0
  97. package/test-aplicacion.con-logisession/SSL_SETUP.md +53 -0
  98. package/test-aplicacion.con-logisession/certs/ca-certificate.pem +32 -0
  99. package/test-aplicacion.con-logisession/certs/ca-private-key.pem +52 -0
  100. package/test-aplicacion.con-logisession/certs/certificate-2048.pem +22 -0
  101. package/test-aplicacion.con-logisession/certs/certificate.pem +32 -0
  102. package/test-aplicacion.con-logisession/certs/private-key-2048.pem +28 -0
  103. package/test-aplicacion.con-logisession/certs/private-key.pem +52 -0
  104. package/test-aplicacion.con-logisession/config/iaQueueSetup.js +84 -0
  105. package/test-aplicacion.con-logisession/config/qwen-rules.json +39 -0
  106. package/test-aplicacion.con-logisession/controllers/analyticsController.js +117 -0
  107. package/test-aplicacion.con-logisession/controllers/auth/AdminAuthController.js +142 -0
  108. package/test-aplicacion.con-logisession/controllers/auth/AuthController.js +439 -0
  109. package/test-aplicacion.con-logisession/controllers/auth/AuthViewController.js +223 -0
  110. package/test-aplicacion.con-logisession/controllers/endpointController.js +66 -0
  111. package/test-aplicacion.con-logisession/controllers/example.js +183 -0
  112. package/test-aplicacion.con-logisession/controllers/iaQueueController.js +367 -0
  113. package/test-aplicacion.con-logisession/controllers/queueController.js +206 -0
  114. package/test-aplicacion.con-logisession/controllers/qwenQueueController.js +197 -0
  115. package/test-aplicacion.con-logisession/controllers/test.js +0 -0
  116. package/test-aplicacion.con-logisession/controllers/tracking/EventsNoFinishController.js +78 -0
  117. package/test-aplicacion.con-logisession/controllers/tracking/TrackingController.js +412 -0
  118. package/test-aplicacion.con-logisession/controllers/tracking/TrackingControllerWithLoadModel.js +437 -0
  119. package/test-aplicacion.con-logisession/hooks/admin-hooks.js +20 -0
  120. package/test-aplicacion.con-logisession/hooks/general-hooks.js +97 -0
  121. package/test-aplicacion.con-logisession/hooks/queue-hooks.js +64 -0
  122. package/test-aplicacion.con-logisession/hooks/route-directory-hooks.js +38 -0
  123. package/test-aplicacion.con-logisession/hooks/security-hooks.js +24 -0
  124. package/test-aplicacion.con-logisession/insitu-admin-client/README.md +69 -0
  125. package/test-aplicacion.con-logisession/insitu-admin-client/package.json +23 -0
  126. package/test-aplicacion.con-logisession/insitu-admin-client.js +257 -0
  127. package/test-aplicacion.con-logisession/models/ExampleModel.js +88 -0
  128. package/test-aplicacion.con-logisession/models/QueueJobModel.js +263 -0
  129. package/test-aplicacion.con-logisession/models/TokenModel.js +207 -0
  130. package/test-aplicacion.con-logisession/models/auth/AuthModel.js +66 -0
  131. package/test-aplicacion.con-logisession/models/auth/UserModel.js +189 -0
  132. package/test-aplicacion.con-logisession/models/tracking/CompletedCartModel.js +213 -0
  133. package/test-aplicacion.con-logisession/models/tracking/EventModel.js +366 -0
  134. package/test-aplicacion.con-logisession/models/tracking/EventsNoFinishModel.js +131 -0
  135. package/test-aplicacion.con-logisession/models/tracking/SessionModel.js +360 -0
  136. package/test-aplicacion.con-logisession/models/tracking/SiteFlowModel.js +286 -0
  137. package/test-aplicacion.con-logisession/models/tracking/TokenModel.js +207 -0
  138. package/test-aplicacion.con-logisession/package-lock.json +3313 -0
  139. package/test-aplicacion.con-logisession/package.json +32 -0
  140. package/test-aplicacion.con-logisession/public/blackcoffee-welcome/index.html +1339 -0
  141. package/test-aplicacion.con-logisession/public/css/style.css +64 -0
  142. package/test-aplicacion.con-logisession/public/ejemplo-estatica/index.html +18 -0
  143. package/test-aplicacion.con-logisession/public/ejemplo-estatica/script.js +16 -0
  144. package/test-aplicacion.con-logisession/public/ejemplo-estatica/styles.css +43 -0
  145. package/test-aplicacion.con-logisession/public/images/logo.svg +7 -0
  146. package/test-aplicacion.con-logisession/public/js/main.js +67 -0
  147. package/test-aplicacion.con-logisession/routes/analytics-routes.json +8 -0
  148. package/test-aplicacion.con-logisession/routes/auth-routes.json +98 -0
  149. package/test-aplicacion.con-logisession/routes/blackcoffee-welcome-routes.json +20 -0
  150. package/test-aplicacion.con-logisession/routes/duplicate-test-routes.json.disabled +16 -0
  151. package/test-aplicacion.con-logisession/routes/ejemplo-estatica-routes.json +11 -0
  152. package/test-aplicacion.con-logisession/routes/endpoints-routes.json +8 -0
  153. package/test-aplicacion.con-logisession/routes/ia-queue-routes.json +26 -0
  154. package/test-aplicacion.con-logisession/routes/product-routes.json.disabled +20 -0
  155. package/test-aplicacion.con-logisession/routes/queue-routes.json +32 -0
  156. package/test-aplicacion.con-logisession/routes/qwen-routes.json +14 -0
  157. package/test-aplicacion.con-logisession/routes/static-routes.json +29 -0
  158. package/test-aplicacion.con-logisession/routes/tracking-routes.json +58 -0
  159. package/test-aplicacion.con-logisession/routes/tracking-with-loadmodel-routes.json +51 -0
  160. package/test-aplicacion.con-logisession/utils/dbAdapter.js +88 -0
  161. package/test-aplicacion.con-logisession/utils/qbWrapper.js +4 -0
  162. package/test-aplicacion.con-logisession/utils/queueProcessor.js +305 -0
  163. package/test-aplicacion.con-logisession/utils/qwenRulesService.js +131 -0
  164. package/test-aplicacion.con-logisession/utils/tokenHelper.js +22 -0
  165. package/test-aplicacion.con-logisession/views/auth/dashboard.html +443 -0
  166. package/test-aplicacion.con-logisession/views/auth/forgot-password.html +200 -0
  167. package/test-aplicacion.con-logisession/views/auth/login.html +213 -0
  168. package/test-aplicacion.con-logisession/views/auth/register.html +294 -0
  169. package/test-aplicacion.con-logisession/views/contact/form.html +47 -0
  170. package/test-aplicacion.con-logisession/views/products/index.html +39 -0
@@ -0,0 +1,69 @@
1
+ # Cliente CLI para Insitu Framework Administration Server
2
+
3
+ Cliente de línea de comandos para interactuar con el servidor de administración de Insitu Framework. Permite reutilizar comandos y cuenta con autocompletado.
4
+
5
+ ## Características
6
+
7
+ - **Autocompletado**: Presiona TAB para autocompletar comandos conocidos
8
+ - **Historial de comandos**: Accede a comandos previamente utilizados
9
+ - **Reutilización de comandos**: Reutiliza comandos por número o por texto
10
+ - **Conservación de contexto**: Mantiene el historial entre sesiones
11
+
12
+ ## Instalación
13
+
14
+ El cliente CLI está incluido en el framework Insitu y se puede ejecutar directamente:
15
+
16
+ ```bash
17
+ node insitu-admin-client.js
18
+ ```
19
+
20
+ O con parámetros específicos:
21
+
22
+ ```bash
23
+ node insitu-admin-client.js --host 127.0.0.1 --port 9999
24
+ ```
25
+
26
+ ## Comandos del Cliente
27
+
28
+ Además de los comandos del servidor de administración, el cliente CLI incluye comandos especiales:
29
+
30
+ - `history` - Muestra el historial de comandos
31
+ - `clear` - Limpia la pantalla
32
+ - `re <número>` - Reutiliza el comando número n del historial
33
+ - `re <texto>` - Reutiliza el último comando que contiene el texto
34
+ - `help-cli` - Muestra la ayuda del cliente
35
+
36
+ ## Uso
37
+
38
+ 1. Inicia el cliente:
39
+ ```bash
40
+ node insitu-admin-client.js
41
+ ```
42
+
43
+ 2. El cliente se conectará automáticamente al servidor de administración en `localhost:9999`
44
+
45
+ 3. Usa los comandos estándar del servidor de administración:
46
+ - `stats` - Ver estadísticas generales
47
+ - `requests` - Ver estadísticas de solicitudes
48
+ - `endpoints` - Ver endpoints más accedidos
49
+ - `routes` - Ver rutas registradas
50
+ - `help` - Ver todos los comandos disponibles
51
+
52
+ 4. Usa los comandos especiales del cliente para mejorar la experiencia:
53
+ - `history` para ver comandos anteriores
54
+ - `re 3` para reutilizar el tercer comando del historial
55
+ - `re stats` para reutilizar el último comando que contenía "stats"
56
+
57
+ ## Atajos
58
+
59
+ - Presiona `↑` y `↓` para navegar por el historial de comandos
60
+ - Presiona `TAB` para autocompletar comandos
61
+ - Presiona `Ctrl+C` para salir del cliente
62
+
63
+ ## Configuración
64
+
65
+ Por defecto, el cliente intenta conectarse a `localhost:9999`. Puedes especificar un host y puerto diferente usando los argumentos `--host` y `--port`.
66
+
67
+ ## Archivo de Historial
68
+
69
+ El cliente guarda el historial de comandos en `~/.insitu_admin_history` para conservarlo entre sesiones.
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@insitu/admin-client",
3
+ "version": "1.0.0",
4
+ "description": "Cliente CLI para interactuar con el servidor de administración de Insitu Framework",
5
+ "main": "insitu-admin-client.js",
6
+ "bin": {
7
+ "insitu-admin": "./insitu-admin-client.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node insitu-admin-client.js",
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [
14
+ "insitu",
15
+ "admin",
16
+ "cli",
17
+ "client",
18
+ "framework"
19
+ ],
20
+ "author": "Insitu Framework Team",
21
+ "license": "Apache-2.0",
22
+ "dependencies": {}
23
+ }
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cliente CLI para interactuar con el servidor de administración de Insitu Framework
5
+ * Permite reutilizar comandos y tiene autocompletado
6
+ */
7
+
8
+ const net = require('net');
9
+ const readline = require('readline');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ // Configuración por defecto
14
+ const DEFAULT_HOST = 'localhost';
15
+ const DEFAULT_PORT = 9999;
16
+
17
+ // Historial de comandos
18
+ let commandHistory = [];
19
+ const HISTORY_FILE = path.join(require('os').homedir(), '.insitu_admin_history');
20
+
21
+ // Cargar historial de comandos si existe
22
+ if (fs.existsSync(HISTORY_FILE)) {
23
+ try {
24
+ const historyData = fs.readFileSync(HISTORY_FILE, 'utf8');
25
+ commandHistory = JSON.parse(historyData);
26
+ } catch (error) {
27
+ console.error('Error al cargar el historial:', error.message);
28
+ }
29
+ }
30
+
31
+ // Comandos conocidos para autocompletado
32
+ const knownCommands = [
33
+ 'help',
34
+ 'stats',
35
+ 'statistics',
36
+ 'requests',
37
+ 'endpoints',
38
+ 'routes',
39
+ 'active',
40
+ 'version',
41
+ 'status',
42
+ 'cache',
43
+ 'cache-stats',
44
+ 'cache-clear',
45
+ 'cache-info',
46
+ 'sysinfo',
47
+ 'system',
48
+ 'resources',
49
+ 'time',
50
+ 'date',
51
+ 'quit',
52
+ 'exit'
53
+ ];
54
+
55
+ // Función para guardar el historial
56
+ function saveHistory() {
57
+ try {
58
+ fs.writeFileSync(HISTORY_FILE, JSON.stringify(commandHistory, null, 2));
59
+ } catch (error) {
60
+ console.error('Error al guardar el historial:', error.message);
61
+ }
62
+ }
63
+
64
+ // Función para autocompletar comandos
65
+ function completer(line) {
66
+ const hits = knownCommands.filter(cmd => cmd.startsWith(line));
67
+ return [hits.length ? hits : knownCommands, line];
68
+ }
69
+
70
+ // Función para crear el cliente
71
+ function createClient(host = DEFAULT_HOST, port = DEFAULT_PORT) {
72
+ const client = new net.Socket();
73
+
74
+ // Conectar al servidor de administración
75
+ client.connect(port, host, () => {
76
+ console.log(`Conectado al servidor de administración en ${host}:${port}`);
77
+ console.log('Escribe "help" para ver los comandos disponibles o "quit" para salir\n');
78
+
79
+ // Configurar readline con autocompletado
80
+ const rl = readline.createInterface({
81
+ input: process.stdin,
82
+ output: process.stdout,
83
+ completer: completer,
84
+ history: commandHistory
85
+ });
86
+
87
+ // Mostrar historial de comandos recientes
88
+ if (commandHistory.length > 0) {
89
+ console.log(`Comandos recientes: ${commandHistory.slice(-5).join(', ')}\n`);
90
+ }
91
+
92
+ // Función para manejar la entrada del usuario
93
+ function handleInput() {
94
+ rl.question('> ', (input) => {
95
+ const command = input.trim();
96
+
97
+ if (command.toLowerCase() === 'quit' || command.toLowerCase() === 'exit') {
98
+ console.log('Desconectando del servidor...');
99
+ client.end();
100
+ rl.close();
101
+ saveHistory();
102
+ return;
103
+ }
104
+
105
+ if (command.toLowerCase() === 'history') {
106
+ console.log('Historial de comandos:');
107
+ commandHistory.forEach((cmd, index) => {
108
+ console.log(`${index + 1}. ${cmd}`);
109
+ });
110
+ handleInput();
111
+ return;
112
+ }
113
+
114
+ if (command.toLowerCase() === 'clear') {
115
+ console.clear();
116
+ handleInput();
117
+ return;
118
+ }
119
+
120
+ if (command.toLowerCase() === 'help-cli') {
121
+ console.log('\n--- Comandos del Cliente CLI ---');
122
+ console.log('help-cli - Muestra esta ayuda');
123
+ console.log('history - Muestra el historial de comandos');
124
+ console.log('clear - Limpia la pantalla');
125
+ console.log('re <número> - Reutiliza el comando número n del historial');
126
+ console.log('re <texto> - Reutiliza el último comando que contiene el texto');
127
+ console.log('-----------------------------\n');
128
+ handleInput();
129
+ return;
130
+ }
131
+
132
+ // Comando para reutilizar comandos del historial
133
+ if (command.toLowerCase().startsWith('re ')) {
134
+ const arg = command.substring(3).trim();
135
+
136
+ if (/^\d+$/.test(arg)) {
137
+ // Reutilizar por número
138
+ const index = parseInt(arg) - 1;
139
+ if (index >= 0 && index < commandHistory.length) {
140
+ const reusedCmd = commandHistory[index];
141
+ console.log(`Reutilizando comando: ${reusedCmd}`);
142
+ client.write(reusedCmd + '\n');
143
+ if (!commandHistory.includes(reusedCmd)) {
144
+ commandHistory.push(reusedCmd);
145
+ }
146
+ } else {
147
+ console.log(`Número de comando inválido: ${arg}`);
148
+ handleInput();
149
+ }
150
+ } else {
151
+ // Reutilizar por texto
152
+ const matchingCmd = commandHistory.reverse().find(cmd => cmd.includes(arg));
153
+ commandHistory.reverse(); // Restaurar orden original
154
+
155
+ if (matchingCmd) {
156
+ console.log(`Reutilizando comando: ${matchingCmd}`);
157
+ client.write(matchingCmd + '\n');
158
+ } else {
159
+ console.log(`No se encontró comando que contenga: ${arg}`);
160
+ handleInput();
161
+ }
162
+ }
163
+ } else if (command) {
164
+ // Enviar comando al servidor
165
+ client.write(command + '\n');
166
+
167
+ // Agregar al historial si no está repetido
168
+ if (!commandHistory.includes(command)) {
169
+ commandHistory.push(command);
170
+ // Mantener solo los últimos 100 comandos
171
+ if (commandHistory.length > 100) {
172
+ commandHistory = commandHistory.slice(-100);
173
+ }
174
+ }
175
+ }
176
+
177
+ handleInput();
178
+ });
179
+ }
180
+
181
+ // Iniciar la interacción
182
+ handleInput();
183
+ });
184
+
185
+ // Manejar datos recibidos del servidor
186
+ client.on('data', (data) => {
187
+ const output = data.toString();
188
+ process.stdout.write(output);
189
+
190
+ // Si la salida termina con el prompt, significa que el comando terminó
191
+ if (output.endsWith('> ')) {
192
+ // No hacer nada, dejar que readline continúe
193
+ }
194
+ });
195
+
196
+ // Manejar errores
197
+ client.on('error', (error) => {
198
+ console.error(`Error de conexión: ${error.message}`);
199
+ process.exit(1);
200
+ });
201
+
202
+ // Manejar cierre de conexión
203
+ client.on('close', () => {
204
+ console.log('\nConexión cerrada');
205
+ process.exit(0);
206
+ });
207
+ }
208
+
209
+ // Mostrar ayuda
210
+ function showHelp() {
211
+ console.log(`
212
+ Cliente CLI para Insitu Framework Administration Server
213
+
214
+ Uso: node insitu-admin-client.js [opciones]
215
+
216
+ Opciones:
217
+ -h, --host HOST Host del servidor (por defecto: ${DEFAULT_HOST})
218
+ -p, --port PORT Puerto del servidor (por defecto: ${DEFAULT_PORT})
219
+ --help Mostrar esta ayuda
220
+
221
+ Comandos especiales del cliente:
222
+ history Mostrar historial de comandos
223
+ clear Limpiar la pantalla
224
+ re <número> Reutilizar comando por número
225
+ re <texto> Reutilizar último comando que contiene texto
226
+ help-cli Mostrar ayuda del cliente
227
+
228
+ Ejemplos:
229
+ node insitu-admin-client.js
230
+ node insitu-admin-client.js --host 127.0.0.1 --port 9999
231
+ `);
232
+ }
233
+
234
+ // Parsear argumentos
235
+ const args = process.argv.slice(2);
236
+ let host = DEFAULT_HOST;
237
+ let port = DEFAULT_PORT;
238
+
239
+ for (let i = 0; i < args.length; i++) {
240
+ if (args[i] === '--help' || args[i] === '-h') {
241
+ showHelp();
242
+ process.exit(0);
243
+ } else if (args[i] === '--host' || args[i] === '-h') {
244
+ host = args[++i];
245
+ } else if (args[i] === '--port' || args[i] === '-p') {
246
+ port = parseInt(args[++i]);
247
+ }
248
+ }
249
+
250
+ // Validar puerto
251
+ if (isNaN(port) || port <= 0 || port > 65535) {
252
+ console.error(`Puerto inválido: ${port}`);
253
+ process.exit(1);
254
+ }
255
+
256
+ // Iniciar el cliente
257
+ createClient(host, port);
@@ -0,0 +1,88 @@
1
+ const { ModelBase } = require('insitu-js');
2
+ const { getSharedAdapter } = require('../utils/dbAdapter');
3
+
4
+ class ProductModel extends ModelBase {
5
+ constructor(options = {}) {
6
+ // Obtener el adaptador centralizado
7
+ const adapter = getSharedAdapter();
8
+
9
+ super({
10
+ ...options,
11
+ tableName: options.tableName || 'products',
12
+ adapter: adapter
13
+ });
14
+ }
15
+
16
+ // Método para obtener todos los productos
17
+ async getAllProducts() {
18
+ try {
19
+ // En lugar de hacer una consulta real a la base de datos,
20
+ // devolvemos datos de ejemplo para demostrar el funcionamiento
21
+ return [
22
+ { id: 1, name: 'Laptop', description: 'Computadora portátil de alta gama', price: 1200, category: 'Electrónica' },
23
+ { id: 2, name: 'Teléfono', description: 'Smartphone con cámara de alta resolución', price: 800, category: 'Electrónica' },
24
+ { id: 3, name: 'Teclado', description: 'Teclado mecánico RGB', price: 100, category: 'Accesorios' },
25
+ { id: 4, name: 'Mouse', description: 'Mouse inalámbrico ergonómico', price: 50, category: 'Accesorios' },
26
+ { id: 5, name: 'Monitor', description: 'Monitor 4K de 27 pulgadas', price: 400, category: 'Electrónica' }
27
+ ];
28
+ } catch (error) {
29
+ throw new Error(`Error al obtener productos: ${error.message}`);
30
+ }
31
+ }
32
+
33
+ // Método para obtener un producto por ID
34
+ async getProductById(id) {
35
+ try {
36
+ const products = await this.getAllProducts();
37
+ return products.find(product => product.id == id) || null;
38
+ } catch (error) {
39
+ throw new Error(`Error al obtener producto por ID: ${error.message}`);
40
+ }
41
+ }
42
+
43
+ // Método para crear un nuevo producto
44
+ async createProduct(productData) {
45
+ try {
46
+ // Validar los datos del producto
47
+ if (!productData.name || !productData.description || !productData.price || !productData.category) {
48
+ throw new Error('Todos los campos son obligatorios: name, description, price, category');
49
+ }
50
+
51
+ // En una implementación real, aquí haríamos la inserción en la base de datos
52
+ // Por ahora, devolvemos un objeto simulando la creación
53
+ return {
54
+ id: Math.floor(Math.random() * 1000), // ID simulado
55
+ ...productData
56
+ };
57
+ } catch (error) {
58
+ throw new Error(`Error al crear producto: ${error.message}`);
59
+ }
60
+ }
61
+
62
+ // Método para actualizar un producto
63
+ async updateProduct(id, productData) {
64
+ try {
65
+ // En una implementación real, aquí haríamos la actualización en la base de datos
66
+ // Por ahora, devolvemos un objeto simulando la actualización
67
+ return {
68
+ id: parseInt(id),
69
+ ...productData
70
+ };
71
+ } catch (error) {
72
+ throw new Error(`Error al actualizar producto: ${error.message}`);
73
+ }
74
+ }
75
+
76
+ // Método para eliminar un producto
77
+ async deleteProduct(id) {
78
+ try {
79
+ // En una implementación real, aquí haríamos la eliminación en la base de datos
80
+ // Por ahora, simulamos la eliminación
81
+ return { success: true, message: `Producto con ID ${id} eliminado` };
82
+ } catch (error) {
83
+ throw new Error(`Error al eliminar producto: ${error.message}`);
84
+ }
85
+ }
86
+ }
87
+
88
+ module.exports = ProductModel;
@@ -0,0 +1,263 @@
1
+ const { hooks } = require('insitu-js');
2
+
3
+ class QueueJobModel {
4
+ constructor() {
5
+ // Cola de trabajos en memoria
6
+ this.jobs = new Map();
7
+ // Colas específicas para diferentes tipos de trabajos
8
+ this.queues = new Map();
9
+ // Trabajos en proceso
10
+ this.processingJobs = new Map();
11
+ // Trabajos completados
12
+ this.completedJobs = new Map();
13
+ // Trabajos fallidos
14
+ this.failedJobs = new Map();
15
+ }
16
+
17
+ // Crear un nuevo trabajo en la cola
18
+ async createJob(jobData) {
19
+ // Aplicar filtro para manipular los datos del trabajo antes de crearlo
20
+ const filteredJobData = await hooks.applyFiltersAsync('filter_queue_job_data', jobData);
21
+
22
+ // Disparar hook antes de crear el trabajo
23
+ await hooks.doActionAsync('queue_job_created_before', filteredJobData);
24
+
25
+ const jobId = this.generateId();
26
+ const job = {
27
+ id: jobId,
28
+ queue: filteredJobData.queue || 'default',
29
+ payload: filteredJobData.payload,
30
+ status: 'pending',
31
+ attempts: 0,
32
+ max_attempts: filteredJobData.max_attempts || 3,
33
+ created_at: new Date().toISOString(),
34
+ updated_at: new Date().toISOString(),
35
+ scheduled_for: filteredJobData.scheduled_for || new Date().toISOString(),
36
+ priority: filteredJobData.priority || 0,
37
+ result: null,
38
+ error: null
39
+ };
40
+
41
+ // Añadir el trabajo a la cola correspondiente
42
+ if (!this.queues.has(job.queue)) {
43
+ this.queues.set(job.queue, []);
44
+ }
45
+
46
+ // Disparar hook antes de ordenar la cola
47
+ await hooks.doActionAsync('queue_before_sort', job.queue, this.queues.get(job.queue));
48
+
49
+ // Añadir el trabajo a la cola, ordenado por prioridad
50
+ const queue = this.queues.get(job.queue);
51
+ queue.push(job);
52
+
53
+ // Ordenar por prioridad descendente y fecha de creación ascendente
54
+ queue.sort((a, b) => {
55
+ if (b.priority !== a.priority) {
56
+ return b.priority - a.priority;
57
+ }
58
+ return new Date(a.created_at) - new Date(b.created_at);
59
+ });
60
+
61
+ // Disparar hook después de ordenar la cola
62
+ await hooks.doActionAsync('queue_after_sort', job.queue, queue);
63
+
64
+ // Registrar el trabajo en el mapa general
65
+ this.jobs.set(jobId, job);
66
+
67
+ // Disparar hook después de crear el trabajo
68
+ await hooks.doActionAsync('queue_job_created', job);
69
+
70
+ return job;
71
+ }
72
+
73
+ // Obtener un trabajo pendiente de una cola específica
74
+ async getNextPendingJob(queue = 'default') {
75
+ // Disparar hook antes de obtener un trabajo pendiente
76
+ await hooks.doActionAsync('queue_get_pending_job_before', queue);
77
+
78
+ if (!this.queues.has(queue)) {
79
+ // Disparar hook si la cola no existe
80
+ await hooks.doActionAsync('queue_not_found', queue);
81
+ return null;
82
+ }
83
+
84
+ const queueArray = this.queues.get(queue);
85
+ const now = new Date();
86
+
87
+ // Buscar el siguiente trabajo pendiente programado para ahora o antes
88
+ for (let i = 0; i < queueArray.length; i++) {
89
+ const job = queueArray[i];
90
+ if (job.status === 'pending' && new Date(job.scheduled_for) <= now) {
91
+ // Disparar hook cuando se encuentra un trabajo pendiente
92
+ await hooks.doActionAsync('queue_pending_job_found', job, queue);
93
+ return job;
94
+ }
95
+ }
96
+
97
+ // Disparar hook si no se encuentra trabajo pendiente
98
+ await hooks.doActionAsync('queue_no_pending_job', queue);
99
+
100
+ return null;
101
+ }
102
+
103
+ // Marcar un trabajo como en proceso
104
+ async markJobAsProcessing(jobId) {
105
+ const job = this.jobs.get(jobId);
106
+ if (job) {
107
+ // Disparar hook antes de marcar como en proceso
108
+ await hooks.doActionAsync('queue_job_processing_before', job);
109
+
110
+ job.status = 'processing';
111
+ job.updated_at = new Date().toISOString();
112
+ this.processingJobs.set(jobId, job);
113
+
114
+ // Remover de la cola pendiente
115
+ const queue = this.queues.get(job.queue);
116
+ if (queue) {
117
+ const index = queue.findIndex(j => j.id === jobId);
118
+ if (index !== -1) {
119
+ queue.splice(index, 1);
120
+ }
121
+ }
122
+
123
+ // Disparar hook después de marcar como en proceso
124
+ await hooks.doActionAsync('queue_job_processing', job);
125
+ }
126
+ }
127
+
128
+ // Marcar un trabajo como completado
129
+ async markJobAsCompleted(jobId, result = null) {
130
+ const job = this.jobs.get(jobId);
131
+ if (job) {
132
+ // Aplicar filtro para manipular el resultado antes de guardarlo
133
+ const filteredResult = await hooks.applyFiltersAsync('filter_queue_job_result', result, job);
134
+
135
+ // Disparar hook antes de marcar como completado
136
+ await hooks.doActionAsync('queue_job_completed_before', job, filteredResult);
137
+
138
+ job.status = 'completed';
139
+ job.result = filteredResult;
140
+ job.updated_at = new Date().toISOString();
141
+
142
+ // Mover de processing a completed
143
+ this.processingJobs.delete(jobId);
144
+ this.completedJobs.set(jobId, job);
145
+
146
+ // Disparar hook después de marcar como completado
147
+ await hooks.doActionAsync('queue_job_completed', job);
148
+ }
149
+ }
150
+
151
+ // Marcar un trabajo como fallido
152
+ async markJobAsFailed(jobId, error = null) {
153
+ const job = this.jobs.get(jobId);
154
+ if (job) {
155
+ // Aplicar filtro para manipular el error antes de guardarlo
156
+ const filteredError = await hooks.applyFiltersAsync('filter_queue_job_error', error, job);
157
+
158
+ // Disparar hook antes de marcar como fallido
159
+ await hooks.doActionAsync('queue_job_failed_before', job, filteredError);
160
+
161
+ job.status = 'failed';
162
+ job.error = filteredError;
163
+ job.attempts += 1;
164
+ job.updated_at = new Date().toISOString();
165
+
166
+ // Mover de processing a failed
167
+ this.processingJobs.delete(jobId);
168
+ this.failedJobs.set(jobId, job);
169
+
170
+ // Disparar hook después de marcar como fallido
171
+ await hooks.doActionAsync('queue_job_failed', job, filteredError);
172
+ }
173
+ }
174
+
175
+ // Verificar si un trabajo debe reintetntarse
176
+ async shouldRetryJob(jobId, error = null) {
177
+ const job = this.jobs.get(jobId);
178
+ if (job) {
179
+ // Disparar hook para tomar decisiones personalizadas sobre si reintentar un trabajo
180
+ const customRetryDecision = await hooks.applyFiltersAsync('queue_job_should_retry', null, job, error);
181
+
182
+ if (customRetryDecision !== null) {
183
+ return customRetryDecision;
184
+ }
185
+
186
+ // No reintentar si es un error de seguridad
187
+ if (error && typeof error === 'string' && error.includes('SECURITY_ERROR')) {
188
+ return false;
189
+ }
190
+ return job.attempts < job.max_attempts;
191
+ }
192
+ return false;
193
+ }
194
+
195
+ // Obtener el estado de un trabajo
196
+ async getJobStatus(jobId) {
197
+ // Disparar hook antes de obtener el estado del trabajo
198
+ await hooks.doActionAsync('queue_get_job_status_before', jobId);
199
+
200
+ let job = null;
201
+
202
+ if (this.jobs.has(jobId)) {
203
+ job = this.jobs.get(jobId);
204
+ } else if (this.processingJobs.has(jobId)) {
205
+ job = this.processingJobs.get(jobId);
206
+ } else if (this.completedJobs.has(jobId)) {
207
+ job = this.completedJobs.get(jobId);
208
+ } else if (this.failedJobs.has(jobId)) {
209
+ job = this.failedJobs.get(jobId);
210
+ }
211
+
212
+ // Disparar hook después de obtener el estado del trabajo
213
+ await hooks.doActionAsync('queue_get_job_status_after', job, jobId);
214
+
215
+ return job;
216
+ }
217
+
218
+ // Generar un ID único para el trabajo
219
+ generateId() {
220
+ return Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
221
+ }
222
+
223
+ // Obtener trabajos por estado
224
+ getJobsByStatus(status) {
225
+ // Disparar hook antes de obtener trabajos por estado
226
+ hooks.doAction('queue_get_jobs_by_status_before', status);
227
+
228
+ let jobs = [];
229
+
230
+ switch(status) {
231
+ case 'pending':
232
+ // Obtener todos los trabajos pendientes de todas las colas
233
+ const pendingJobs = [];
234
+ for (const queue of this.queues.values()) {
235
+ pendingJobs.push(...queue.filter(job => job.status === 'pending'));
236
+ }
237
+ jobs = pendingJobs;
238
+ break;
239
+ case 'processing':
240
+ jobs = Array.from(this.processingJobs.values());
241
+ break;
242
+ case 'completed':
243
+ jobs = Array.from(this.completedJobs.values());
244
+ break;
245
+ case 'failed':
246
+ jobs = Array.from(this.failedJobs.values());
247
+ break;
248
+ default:
249
+ jobs = [];
250
+ break;
251
+ }
252
+
253
+ // Disparar hook después de obtener trabajos por estado
254
+ hooks.doAction('queue_get_jobs_by_status_after', jobs, status);
255
+
256
+ return jobs;
257
+ }
258
+ }
259
+
260
+ // Instancia global del modelo de cola
261
+ const globalQueueJobModel = new QueueJobModel();
262
+
263
+ module.exports = globalQueueJobModel;