wu-framework 1.1.14 → 1.1.16

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 (90) hide show
  1. package/LICENSE +39 -39
  2. package/README.md +408 -408
  3. package/dist/wu-framework.cjs.js.map +1 -1
  4. package/dist/wu-framework.dev.js +15151 -15151
  5. package/dist/wu-framework.dev.js.map +1 -1
  6. package/dist/wu-framework.esm.js.map +1 -1
  7. package/dist/wu-framework.umd.js.map +1 -1
  8. package/integrations/astro/README.md +127 -127
  9. package/integrations/astro/WuApp.astro +63 -63
  10. package/integrations/astro/WuShell.astro +39 -39
  11. package/integrations/astro/index.js +68 -68
  12. package/integrations/astro/package.json +38 -38
  13. package/integrations/astro/types.d.ts +53 -53
  14. package/package.json +161 -161
  15. package/src/adapters/angular/ai.js +30 -30
  16. package/src/adapters/angular/index.d.ts +154 -154
  17. package/src/adapters/angular/index.js +932 -932
  18. package/src/adapters/angular.d.ts +3 -3
  19. package/src/adapters/angular.js +3 -3
  20. package/src/adapters/index.js +168 -168
  21. package/src/adapters/lit/ai.js +20 -20
  22. package/src/adapters/lit/index.d.ts +120 -120
  23. package/src/adapters/lit/index.js +721 -721
  24. package/src/adapters/lit.d.ts +3 -3
  25. package/src/adapters/lit.js +3 -3
  26. package/src/adapters/preact/ai.js +33 -33
  27. package/src/adapters/preact/index.d.ts +108 -108
  28. package/src/adapters/preact/index.js +661 -661
  29. package/src/adapters/preact.d.ts +3 -3
  30. package/src/adapters/preact.js +3 -3
  31. package/src/adapters/react/index.js +48 -54
  32. package/src/adapters/react.d.ts +3 -3
  33. package/src/adapters/react.js +3 -3
  34. package/src/adapters/shared.js +64 -64
  35. package/src/adapters/solid/ai.js +32 -32
  36. package/src/adapters/solid/index.d.ts +101 -101
  37. package/src/adapters/solid/index.js +586 -586
  38. package/src/adapters/solid.d.ts +3 -3
  39. package/src/adapters/solid.js +3 -3
  40. package/src/adapters/svelte/ai.js +31 -31
  41. package/src/adapters/svelte/index.d.ts +166 -166
  42. package/src/adapters/svelte/index.js +798 -798
  43. package/src/adapters/svelte.d.ts +3 -3
  44. package/src/adapters/svelte.js +3 -3
  45. package/src/adapters/vanilla/ai.js +30 -30
  46. package/src/adapters/vanilla/index.d.ts +179 -179
  47. package/src/adapters/vanilla/index.js +785 -785
  48. package/src/adapters/vanilla.d.ts +3 -3
  49. package/src/adapters/vanilla.js +3 -3
  50. package/src/adapters/vue/ai.js +52 -52
  51. package/src/adapters/vue/index.d.ts +299 -299
  52. package/src/adapters/vue/index.js +610 -610
  53. package/src/adapters/vue.d.ts +3 -3
  54. package/src/adapters/vue.js +3 -3
  55. package/src/ai/wu-ai-actions.js +261 -261
  56. package/src/ai/wu-ai-agent.js +546 -546
  57. package/src/ai/wu-ai-browser-primitives.js +354 -354
  58. package/src/ai/wu-ai-browser.js +380 -380
  59. package/src/ai/wu-ai-context.js +332 -332
  60. package/src/ai/wu-ai-conversation.js +613 -613
  61. package/src/ai/wu-ai-orchestrate.js +1021 -1021
  62. package/src/ai/wu-ai-permissions.js +381 -381
  63. package/src/ai/wu-ai-provider.js +700 -700
  64. package/src/ai/wu-ai-schema.js +225 -225
  65. package/src/ai/wu-ai-triggers.js +396 -396
  66. package/src/ai/wu-ai.js +804 -804
  67. package/src/core/wu-app.js +236 -236
  68. package/src/core/wu-cache.js +477 -477
  69. package/src/core/wu-core.js +1398 -1398
  70. package/src/core/wu-error-boundary.js +382 -382
  71. package/src/core/wu-event-bus.js +348 -348
  72. package/src/core/wu-hooks.js +350 -350
  73. package/src/core/wu-html-parser.js +190 -190
  74. package/src/core/wu-iframe-sandbox.js +328 -328
  75. package/src/core/wu-loader.js +272 -272
  76. package/src/core/wu-logger.js +134 -134
  77. package/src/core/wu-manifest.js +509 -509
  78. package/src/core/wu-mcp-bridge.js +432 -432
  79. package/src/core/wu-overrides.js +510 -510
  80. package/src/core/wu-performance.js +228 -228
  81. package/src/core/wu-plugin.js +348 -348
  82. package/src/core/wu-prefetch.js +414 -414
  83. package/src/core/wu-proxy-sandbox.js +476 -476
  84. package/src/core/wu-sandbox.js +779 -779
  85. package/src/core/wu-script-executor.js +113 -113
  86. package/src/core/wu-snapshot-sandbox.js +227 -227
  87. package/src/core/wu-strategies.js +256 -256
  88. package/src/core/wu-style-bridge.js +477 -477
  89. package/src/index.js +224 -224
  90. package/src/utils/dependency-resolver.js +327 -327
@@ -1,350 +1,350 @@
1
- /**
2
- * 🪝 WU-HOOKS: LIFECYCLE MIDDLEWARE SYSTEM
3
- *
4
- * Sistema de hooks basado en middleware pattern para control fino:
5
- * - Middleware chain con next()
6
- * - Puede cancelar operaciones (no llamar next)
7
- * - Puede modificar contexto
8
- * - Prioridad de hooks
9
- * - Async/await support
10
- */
11
-
12
- import { logger } from './wu-logger.js';
13
-
14
- export class WuLifecycleHooks {
15
- constructor(core) {
16
- this.core = core;
17
- this.hooks = new Map();
18
- this.executionLog = [];
19
- this.maxLogSize = 100;
20
-
21
- // Lifecycle phases disponibles
22
- this.lifecyclePhases = [
23
- 'beforeInit', // Antes de inicializar framework
24
- 'afterInit', // Después de inicializar
25
- 'beforeLoad', // Antes de cargar una app
26
- 'afterLoad', // Después de cargar
27
- 'beforeMount', // Antes de montar
28
- 'afterMount', // Después de montar
29
- 'beforeUnmount', // Antes de desmontar
30
- 'afterUnmount', // Después de desmontar
31
- 'beforeDestroy', // Antes de destruir framework
32
- 'afterDestroy' // Después de destruir
33
- ];
34
-
35
- // Inicializar hooks
36
- this.lifecyclePhases.forEach(phase => {
37
- this.hooks.set(phase, []);
38
- });
39
-
40
- logger.debug('[WuHooks] 🪝 Lifecycle hooks initialized');
41
- }
42
-
43
- /**
44
- * 📦 USE: Registrar middleware hook
45
- * @param {string} phase - Fase del lifecycle
46
- * @param {Function} middleware - Función middleware (context, next)
47
- * @param {Object} options - { priority, name }
48
- */
49
- use(phase, middleware, options = {}) {
50
- if (!this.hooks.has(phase)) {
51
- throw new Error(`[WuHooks] Unknown lifecycle phase: ${phase}`);
52
- }
53
-
54
- if (typeof middleware !== 'function') {
55
- throw new Error('[WuHooks] Middleware must be a function');
56
- }
57
-
58
- const hook = {
59
- middleware,
60
- name: options.name || `hook_${Date.now()}`,
61
- priority: options.priority || 0,
62
- registeredAt: Date.now()
63
- };
64
-
65
- const hooks = this.hooks.get(phase);
66
- hooks.push(hook);
67
-
68
- // Ordenar por prioridad (mayor primero)
69
- hooks.sort((a, b) => b.priority - a.priority);
70
-
71
- logger.debug(`[WuHooks] Hook "${hook.name}" registered for ${phase} (priority: ${hook.priority})`);
72
-
73
- // Retornar función para desregistrar
74
- return () => this.remove(phase, hook.name);
75
- }
76
-
77
- /**
78
- * 🗑️ REMOVE: Remover hook
79
- * @param {string} phase - Fase del lifecycle
80
- * @param {string} name - Nombre del hook
81
- */
82
- remove(phase, name) {
83
- if (!this.hooks.has(phase)) return;
84
-
85
- const hooks = this.hooks.get(phase);
86
- const index = hooks.findIndex(h => h.name === name);
87
-
88
- if (index > -1) {
89
- hooks.splice(index, 1);
90
- logger.debug(`[WuHooks] Hook "${name}" removed from ${phase}`);
91
- }
92
- }
93
-
94
- /**
95
- * 🎯 EXECUTE: Ejecutar middleware chain
96
- * @param {string} phase - Fase del lifecycle
97
- * @param {Object} context - Contexto a pasar
98
- * @returns {Promise<Object>} Contexto modificado o { cancelled: true }
99
- */
100
- async execute(phase, context = {}) {
101
- const hooks = this.hooks.get(phase);
102
-
103
- if (!hooks || hooks.length === 0) {
104
- return context;
105
- }
106
-
107
- logger.debug(`[WuHooks] Executing ${hooks.length} hooks for ${phase}`);
108
-
109
- // Log para debugging
110
- const executionEntry = {
111
- phase,
112
- timestamp: Date.now(),
113
- hooksCount: hooks.length,
114
- hookNames: hooks.map(h => h.name)
115
- };
116
-
117
- let currentContext = { ...context };
118
- let cancelled = false;
119
-
120
- // Crear cadena de middleware
121
- const executeChain = async (index) => {
122
- // Si llegamos al final de la cadena, retornar contexto
123
- if (index >= hooks.length) {
124
- return currentContext;
125
- }
126
-
127
- const hook = hooks[index];
128
- const startTime = Date.now();
129
-
130
- try {
131
- let nextCalled = false;
132
-
133
- // Función next
134
- const next = async (modifiedContext) => {
135
- nextCalled = true;
136
-
137
- // Si se pasa un contexto modificado, usarlo
138
- if (modifiedContext !== undefined) {
139
- currentContext = { ...currentContext, ...modifiedContext };
140
- }
141
-
142
- // Continuar con siguiente hook
143
- return await executeChain(index + 1);
144
- };
145
-
146
- // Ejecutar middleware
147
- await hook.middleware(currentContext, next);
148
-
149
- // Si no se llamó next(), la operación fue cancelada
150
- if (!nextCalled) {
151
- logger.debug(`[WuHooks] Hook "${hook.name}" cancelled execution`);
152
- cancelled = true;
153
- return { cancelled: true };
154
- }
155
-
156
- const duration = Date.now() - startTime;
157
- logger.debug(`[WuHooks] Hook "${hook.name}" executed in ${duration}ms`);
158
-
159
- } catch (error) {
160
- console.error(`[WuHooks] Error in hook "${hook.name}":`, error);
161
-
162
- // Si hay error, pasar al siguiente hook
163
- return await executeChain(index + 1);
164
- }
165
-
166
- return currentContext;
167
- };
168
-
169
- // Ejecutar cadena
170
- const result = await executeChain(0);
171
-
172
- // Completar log
173
- executionEntry.duration = Date.now() - executionEntry.timestamp;
174
- executionEntry.cancelled = cancelled;
175
- executionEntry.success = !cancelled;
176
-
177
- this.executionLog.push(executionEntry);
178
-
179
- // Mantener límite de log
180
- if (this.executionLog.length > this.maxLogSize) {
181
- this.executionLog.shift();
182
- }
183
-
184
- return result;
185
- }
186
-
187
- /**
188
- * 🚀 HELPER: Registrar hook para múltiples fases
189
- * @param {Array<string>} phases - Fases del lifecycle
190
- * @param {Function} middleware - Función middleware
191
- * @param {Object} options - Opciones
192
- * @returns {Function} Función para desregistrar de todas las fases
193
- */
194
- useMultiple(phases, middleware, options = {}) {
195
- const unregisterFns = phases.map(phase =>
196
- this.use(phase, middleware, { ...options, name: `${options.name}_${phase}` })
197
- );
198
-
199
- // Retornar función que desregistra de todas las fases
200
- return () => unregisterFns.forEach(fn => fn());
201
- }
202
-
203
- /**
204
- * 📋 GET HOOKS: Obtener hooks registrados
205
- * @param {string} phase - Fase del lifecycle (opcional)
206
- * @returns {Object|Array}
207
- */
208
- getHooks(phase) {
209
- if (phase) {
210
- return this.hooks.get(phase) || [];
211
- }
212
-
213
- // Retornar todos los hooks
214
- const allHooks = {};
215
- this.hooks.forEach((hooks, phase) => {
216
- allHooks[phase] = hooks.map(h => ({
217
- name: h.name,
218
- priority: h.priority,
219
- registeredAt: h.registeredAt
220
- }));
221
- });
222
-
223
- return allHooks;
224
- }
225
-
226
- /**
227
- * 📊 GET STATS: Estadísticas de hooks
228
- * @returns {Object}
229
- */
230
- getStats() {
231
- const totalHooks = Array.from(this.hooks.values())
232
- .reduce((sum, hooks) => sum + hooks.length, 0);
233
-
234
- const executionsByPhase = {};
235
- this.executionLog.forEach(entry => {
236
- executionsByPhase[entry.phase] = (executionsByPhase[entry.phase] || 0) + 1;
237
- });
238
-
239
- const avgDuration = this.executionLog.length > 0
240
- ? this.executionLog.reduce((sum, entry) => sum + entry.duration, 0) / this.executionLog.length
241
- : 0;
242
-
243
- const cancelledCount = this.executionLog.filter(entry => entry.cancelled).length;
244
-
245
- return {
246
- totalHooks,
247
- totalExecutions: this.executionLog.length,
248
- executionsByPhase,
249
- avgDuration: Math.round(avgDuration),
250
- cancelledCount,
251
- recentExecutions: this.executionLog.slice(-10)
252
- };
253
- }
254
-
255
- /**
256
- * 🧹 CLEANUP: Limpiar todos los hooks
257
- * @param {string} phase - Fase específica (opcional)
258
- */
259
- cleanup(phase) {
260
- if (phase) {
261
- this.hooks.set(phase, []);
262
- logger.debug(`[WuHooks] Hooks cleaned for ${phase}`);
263
- } else {
264
- this.lifecyclePhases.forEach(p => {
265
- this.hooks.set(p, []);
266
- });
267
- this.executionLog = [];
268
- logger.debug('[WuHooks] 🧹 All hooks cleaned');
269
- }
270
- }
271
- }
272
-
273
- /**
274
- * 🔧 HELPER: Crear middleware hooks fácilmente
275
- */
276
-
277
- /**
278
- * Crear hook simple que siempre llama next
279
- * @param {Function} fn - Función a ejecutar
280
- * @returns {Function} Middleware function
281
- */
282
- export const createSimpleHook = (fn) => {
283
- return async (context, next) => {
284
- await fn(context);
285
- await next();
286
- };
287
- };
288
-
289
- /**
290
- * Crear hook condicional
291
- * @param {Function} condition - Función de condición (context) => boolean
292
- * @param {Function} fn - Función a ejecutar si condición es true
293
- * @returns {Function} Middleware function
294
- */
295
- export const createConditionalHook = (condition, fn) => {
296
- return async (context, next) => {
297
- if (await condition(context)) {
298
- await fn(context);
299
- }
300
- await next();
301
- };
302
- };
303
-
304
- /**
305
- * Crear hook que puede cancelar operación
306
- * @param {Function} shouldContinue - Función que retorna true para continuar
307
- * @returns {Function} Middleware function
308
- */
309
- export const createGuardHook = (shouldContinue) => {
310
- return async (context, next) => {
311
- if (await shouldContinue(context)) {
312
- await next();
313
- }
314
- // Si no retorna true, no llama next() y cancela
315
- };
316
- };
317
-
318
- /**
319
- * Crear hook que modifica contexto
320
- * @param {Function} transformer - Función que transforma el contexto
321
- * @returns {Function} Middleware function
322
- */
323
- export const createTransformHook = (transformer) => {
324
- return async (context, next) => {
325
- const modified = await transformer(context);
326
- await next(modified);
327
- };
328
- };
329
-
330
- /**
331
- * Crear hook con timeout
332
- * @param {Function} fn - Función a ejecutar
333
- * @param {number} timeout - Timeout en ms
334
- * @returns {Function} Middleware function
335
- */
336
- export const createTimedHook = (fn, timeout = 5000) => {
337
- return async (context, next) => {
338
- const timeoutPromise = new Promise((_, reject) =>
339
- setTimeout(() => reject(new Error('Hook timeout')), timeout)
340
- );
341
-
342
- try {
343
- await Promise.race([fn(context), timeoutPromise]);
344
- await next();
345
- } catch (error) {
346
- console.error('[WuHooks] Timed hook failed:', error);
347
- await next(); // Continuar a pesar del error
348
- }
349
- };
350
- };
1
+ /**
2
+ * 🪝 WU-HOOKS: LIFECYCLE MIDDLEWARE SYSTEM
3
+ *
4
+ * Sistema de hooks basado en middleware pattern para control fino:
5
+ * - Middleware chain con next()
6
+ * - Puede cancelar operaciones (no llamar next)
7
+ * - Puede modificar contexto
8
+ * - Prioridad de hooks
9
+ * - Async/await support
10
+ */
11
+
12
+ import { logger } from './wu-logger.js';
13
+
14
+ export class WuLifecycleHooks {
15
+ constructor(core) {
16
+ this.core = core;
17
+ this.hooks = new Map();
18
+ this.executionLog = [];
19
+ this.maxLogSize = 100;
20
+
21
+ // Lifecycle phases disponibles
22
+ this.lifecyclePhases = [
23
+ 'beforeInit', // Antes de inicializar framework
24
+ 'afterInit', // Después de inicializar
25
+ 'beforeLoad', // Antes de cargar una app
26
+ 'afterLoad', // Después de cargar
27
+ 'beforeMount', // Antes de montar
28
+ 'afterMount', // Después de montar
29
+ 'beforeUnmount', // Antes de desmontar
30
+ 'afterUnmount', // Después de desmontar
31
+ 'beforeDestroy', // Antes de destruir framework
32
+ 'afterDestroy' // Después de destruir
33
+ ];
34
+
35
+ // Inicializar hooks
36
+ this.lifecyclePhases.forEach(phase => {
37
+ this.hooks.set(phase, []);
38
+ });
39
+
40
+ logger.debug('[WuHooks] 🪝 Lifecycle hooks initialized');
41
+ }
42
+
43
+ /**
44
+ * 📦 USE: Registrar middleware hook
45
+ * @param {string} phase - Fase del lifecycle
46
+ * @param {Function} middleware - Función middleware (context, next)
47
+ * @param {Object} options - { priority, name }
48
+ */
49
+ use(phase, middleware, options = {}) {
50
+ if (!this.hooks.has(phase)) {
51
+ throw new Error(`[WuHooks] Unknown lifecycle phase: ${phase}`);
52
+ }
53
+
54
+ if (typeof middleware !== 'function') {
55
+ throw new Error('[WuHooks] Middleware must be a function');
56
+ }
57
+
58
+ const hook = {
59
+ middleware,
60
+ name: options.name || `hook_${Date.now()}`,
61
+ priority: options.priority || 0,
62
+ registeredAt: Date.now()
63
+ };
64
+
65
+ const hooks = this.hooks.get(phase);
66
+ hooks.push(hook);
67
+
68
+ // Ordenar por prioridad (mayor primero)
69
+ hooks.sort((a, b) => b.priority - a.priority);
70
+
71
+ logger.debug(`[WuHooks] Hook "${hook.name}" registered for ${phase} (priority: ${hook.priority})`);
72
+
73
+ // Retornar función para desregistrar
74
+ return () => this.remove(phase, hook.name);
75
+ }
76
+
77
+ /**
78
+ * 🗑️ REMOVE: Remover hook
79
+ * @param {string} phase - Fase del lifecycle
80
+ * @param {string} name - Nombre del hook
81
+ */
82
+ remove(phase, name) {
83
+ if (!this.hooks.has(phase)) return;
84
+
85
+ const hooks = this.hooks.get(phase);
86
+ const index = hooks.findIndex(h => h.name === name);
87
+
88
+ if (index > -1) {
89
+ hooks.splice(index, 1);
90
+ logger.debug(`[WuHooks] Hook "${name}" removed from ${phase}`);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * 🎯 EXECUTE: Ejecutar middleware chain
96
+ * @param {string} phase - Fase del lifecycle
97
+ * @param {Object} context - Contexto a pasar
98
+ * @returns {Promise<Object>} Contexto modificado o { cancelled: true }
99
+ */
100
+ async execute(phase, context = {}) {
101
+ const hooks = this.hooks.get(phase);
102
+
103
+ if (!hooks || hooks.length === 0) {
104
+ return context;
105
+ }
106
+
107
+ logger.debug(`[WuHooks] Executing ${hooks.length} hooks for ${phase}`);
108
+
109
+ // Log para debugging
110
+ const executionEntry = {
111
+ phase,
112
+ timestamp: Date.now(),
113
+ hooksCount: hooks.length,
114
+ hookNames: hooks.map(h => h.name)
115
+ };
116
+
117
+ let currentContext = { ...context };
118
+ let cancelled = false;
119
+
120
+ // Crear cadena de middleware
121
+ const executeChain = async (index) => {
122
+ // Si llegamos al final de la cadena, retornar contexto
123
+ if (index >= hooks.length) {
124
+ return currentContext;
125
+ }
126
+
127
+ const hook = hooks[index];
128
+ const startTime = Date.now();
129
+
130
+ try {
131
+ let nextCalled = false;
132
+
133
+ // Función next
134
+ const next = async (modifiedContext) => {
135
+ nextCalled = true;
136
+
137
+ // Si se pasa un contexto modificado, usarlo
138
+ if (modifiedContext !== undefined) {
139
+ currentContext = { ...currentContext, ...modifiedContext };
140
+ }
141
+
142
+ // Continuar con siguiente hook
143
+ return await executeChain(index + 1);
144
+ };
145
+
146
+ // Ejecutar middleware
147
+ await hook.middleware(currentContext, next);
148
+
149
+ // Si no se llamó next(), la operación fue cancelada
150
+ if (!nextCalled) {
151
+ logger.debug(`[WuHooks] Hook "${hook.name}" cancelled execution`);
152
+ cancelled = true;
153
+ return { cancelled: true };
154
+ }
155
+
156
+ const duration = Date.now() - startTime;
157
+ logger.debug(`[WuHooks] Hook "${hook.name}" executed in ${duration}ms`);
158
+
159
+ } catch (error) {
160
+ console.error(`[WuHooks] Error in hook "${hook.name}":`, error);
161
+
162
+ // Si hay error, pasar al siguiente hook
163
+ return await executeChain(index + 1);
164
+ }
165
+
166
+ return currentContext;
167
+ };
168
+
169
+ // Ejecutar cadena
170
+ const result = await executeChain(0);
171
+
172
+ // Completar log
173
+ executionEntry.duration = Date.now() - executionEntry.timestamp;
174
+ executionEntry.cancelled = cancelled;
175
+ executionEntry.success = !cancelled;
176
+
177
+ this.executionLog.push(executionEntry);
178
+
179
+ // Mantener límite de log
180
+ if (this.executionLog.length > this.maxLogSize) {
181
+ this.executionLog.shift();
182
+ }
183
+
184
+ return result;
185
+ }
186
+
187
+ /**
188
+ * 🚀 HELPER: Registrar hook para múltiples fases
189
+ * @param {Array<string>} phases - Fases del lifecycle
190
+ * @param {Function} middleware - Función middleware
191
+ * @param {Object} options - Opciones
192
+ * @returns {Function} Función para desregistrar de todas las fases
193
+ */
194
+ useMultiple(phases, middleware, options = {}) {
195
+ const unregisterFns = phases.map(phase =>
196
+ this.use(phase, middleware, { ...options, name: `${options.name}_${phase}` })
197
+ );
198
+
199
+ // Retornar función que desregistra de todas las fases
200
+ return () => unregisterFns.forEach(fn => fn());
201
+ }
202
+
203
+ /**
204
+ * 📋 GET HOOKS: Obtener hooks registrados
205
+ * @param {string} phase - Fase del lifecycle (opcional)
206
+ * @returns {Object|Array}
207
+ */
208
+ getHooks(phase) {
209
+ if (phase) {
210
+ return this.hooks.get(phase) || [];
211
+ }
212
+
213
+ // Retornar todos los hooks
214
+ const allHooks = {};
215
+ this.hooks.forEach((hooks, phase) => {
216
+ allHooks[phase] = hooks.map(h => ({
217
+ name: h.name,
218
+ priority: h.priority,
219
+ registeredAt: h.registeredAt
220
+ }));
221
+ });
222
+
223
+ return allHooks;
224
+ }
225
+
226
+ /**
227
+ * 📊 GET STATS: Estadísticas de hooks
228
+ * @returns {Object}
229
+ */
230
+ getStats() {
231
+ const totalHooks = Array.from(this.hooks.values())
232
+ .reduce((sum, hooks) => sum + hooks.length, 0);
233
+
234
+ const executionsByPhase = {};
235
+ this.executionLog.forEach(entry => {
236
+ executionsByPhase[entry.phase] = (executionsByPhase[entry.phase] || 0) + 1;
237
+ });
238
+
239
+ const avgDuration = this.executionLog.length > 0
240
+ ? this.executionLog.reduce((sum, entry) => sum + entry.duration, 0) / this.executionLog.length
241
+ : 0;
242
+
243
+ const cancelledCount = this.executionLog.filter(entry => entry.cancelled).length;
244
+
245
+ return {
246
+ totalHooks,
247
+ totalExecutions: this.executionLog.length,
248
+ executionsByPhase,
249
+ avgDuration: Math.round(avgDuration),
250
+ cancelledCount,
251
+ recentExecutions: this.executionLog.slice(-10)
252
+ };
253
+ }
254
+
255
+ /**
256
+ * 🧹 CLEANUP: Limpiar todos los hooks
257
+ * @param {string} phase - Fase específica (opcional)
258
+ */
259
+ cleanup(phase) {
260
+ if (phase) {
261
+ this.hooks.set(phase, []);
262
+ logger.debug(`[WuHooks] Hooks cleaned for ${phase}`);
263
+ } else {
264
+ this.lifecyclePhases.forEach(p => {
265
+ this.hooks.set(p, []);
266
+ });
267
+ this.executionLog = [];
268
+ logger.debug('[WuHooks] 🧹 All hooks cleaned');
269
+ }
270
+ }
271
+ }
272
+
273
+ /**
274
+ * 🔧 HELPER: Crear middleware hooks fácilmente
275
+ */
276
+
277
+ /**
278
+ * Crear hook simple que siempre llama next
279
+ * @param {Function} fn - Función a ejecutar
280
+ * @returns {Function} Middleware function
281
+ */
282
+ export const createSimpleHook = (fn) => {
283
+ return async (context, next) => {
284
+ await fn(context);
285
+ await next();
286
+ };
287
+ };
288
+
289
+ /**
290
+ * Crear hook condicional
291
+ * @param {Function} condition - Función de condición (context) => boolean
292
+ * @param {Function} fn - Función a ejecutar si condición es true
293
+ * @returns {Function} Middleware function
294
+ */
295
+ export const createConditionalHook = (condition, fn) => {
296
+ return async (context, next) => {
297
+ if (await condition(context)) {
298
+ await fn(context);
299
+ }
300
+ await next();
301
+ };
302
+ };
303
+
304
+ /**
305
+ * Crear hook que puede cancelar operación
306
+ * @param {Function} shouldContinue - Función que retorna true para continuar
307
+ * @returns {Function} Middleware function
308
+ */
309
+ export const createGuardHook = (shouldContinue) => {
310
+ return async (context, next) => {
311
+ if (await shouldContinue(context)) {
312
+ await next();
313
+ }
314
+ // Si no retorna true, no llama next() y cancela
315
+ };
316
+ };
317
+
318
+ /**
319
+ * Crear hook que modifica contexto
320
+ * @param {Function} transformer - Función que transforma el contexto
321
+ * @returns {Function} Middleware function
322
+ */
323
+ export const createTransformHook = (transformer) => {
324
+ return async (context, next) => {
325
+ const modified = await transformer(context);
326
+ await next(modified);
327
+ };
328
+ };
329
+
330
+ /**
331
+ * Crear hook con timeout
332
+ * @param {Function} fn - Función a ejecutar
333
+ * @param {number} timeout - Timeout en ms
334
+ * @returns {Function} Middleware function
335
+ */
336
+ export const createTimedHook = (fn, timeout = 5000) => {
337
+ return async (context, next) => {
338
+ const timeoutPromise = new Promise((_, reject) =>
339
+ setTimeout(() => reject(new Error('Hook timeout')), timeout)
340
+ );
341
+
342
+ try {
343
+ await Promise.race([fn(context), timeoutPromise]);
344
+ await next();
345
+ } catch (error) {
346
+ console.error('[WuHooks] Timed hook failed:', error);
347
+ await next(); // Continuar a pesar del error
348
+ }
349
+ };
350
+ };