wu-framework 1.1.6 → 1.1.8

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/README.md +511 -977
  2. package/dist/wu-framework.cjs.js +3 -1
  3. package/dist/wu-framework.cjs.js.map +1 -0
  4. package/dist/wu-framework.dev.js +7533 -2761
  5. package/dist/wu-framework.dev.js.map +1 -1
  6. package/dist/wu-framework.esm.js +3 -0
  7. package/dist/wu-framework.esm.js.map +1 -0
  8. package/dist/wu-framework.umd.js +3 -1
  9. package/dist/wu-framework.umd.js.map +1 -0
  10. package/integrations/astro/README.md +127 -0
  11. package/integrations/astro/WuApp.astro +63 -0
  12. package/integrations/astro/WuShell.astro +39 -0
  13. package/integrations/astro/index.js +68 -0
  14. package/integrations/astro/package.json +38 -0
  15. package/integrations/astro/types.d.ts +53 -0
  16. package/package.json +94 -74
  17. package/src/adapters/angular/ai.js +30 -0
  18. package/src/adapters/angular/index.d.ts +154 -0
  19. package/src/adapters/angular/index.js +932 -0
  20. package/src/adapters/angular.d.ts +3 -154
  21. package/src/adapters/angular.js +3 -813
  22. package/src/adapters/index.js +35 -24
  23. package/src/adapters/lit/ai.js +20 -0
  24. package/src/adapters/lit/index.d.ts +120 -0
  25. package/src/adapters/lit/index.js +721 -0
  26. package/src/adapters/lit.d.ts +3 -120
  27. package/src/adapters/lit.js +3 -726
  28. package/src/adapters/preact/ai.js +33 -0
  29. package/src/adapters/preact/index.d.ts +108 -0
  30. package/src/adapters/preact/index.js +661 -0
  31. package/src/adapters/preact.d.ts +3 -108
  32. package/src/adapters/preact.js +3 -665
  33. package/src/adapters/react/ai.js +135 -0
  34. package/src/adapters/react/index.d.ts +246 -0
  35. package/src/adapters/react/index.js +689 -0
  36. package/src/adapters/react.d.ts +3 -212
  37. package/src/adapters/react.js +3 -513
  38. package/src/adapters/shared.js +64 -0
  39. package/src/adapters/solid/ai.js +32 -0
  40. package/src/adapters/solid/index.d.ts +101 -0
  41. package/src/adapters/solid/index.js +586 -0
  42. package/src/adapters/solid.d.ts +3 -101
  43. package/src/adapters/solid.js +3 -591
  44. package/src/adapters/svelte/ai.js +31 -0
  45. package/src/adapters/svelte/index.d.ts +166 -0
  46. package/src/adapters/svelte/index.js +798 -0
  47. package/src/adapters/svelte.d.ts +3 -166
  48. package/src/adapters/svelte.js +3 -803
  49. package/src/adapters/vanilla/ai.js +30 -0
  50. package/src/adapters/vanilla/index.d.ts +179 -0
  51. package/src/adapters/vanilla/index.js +785 -0
  52. package/src/adapters/vanilla.d.ts +3 -179
  53. package/src/adapters/vanilla.js +3 -791
  54. package/src/adapters/vue/ai.js +52 -0
  55. package/src/adapters/vue/index.d.ts +299 -0
  56. package/src/adapters/vue/index.js +608 -0
  57. package/src/adapters/vue.d.ts +3 -299
  58. package/src/adapters/vue.js +3 -611
  59. package/src/ai/wu-ai-actions.js +261 -0
  60. package/src/ai/wu-ai-browser.js +663 -0
  61. package/src/ai/wu-ai-context.js +332 -0
  62. package/src/ai/wu-ai-conversation.js +554 -0
  63. package/src/ai/wu-ai-permissions.js +381 -0
  64. package/src/ai/wu-ai-provider.js +605 -0
  65. package/src/ai/wu-ai-schema.js +225 -0
  66. package/src/ai/wu-ai-triggers.js +396 -0
  67. package/src/ai/wu-ai.js +474 -0
  68. package/src/core/wu-app.js +50 -8
  69. package/src/core/wu-cache.js +1 -1
  70. package/src/core/wu-core.js +645 -677
  71. package/src/core/wu-html-parser.js +121 -211
  72. package/src/core/wu-iframe-sandbox.js +328 -0
  73. package/src/core/wu-mcp-bridge.js +647 -0
  74. package/src/core/wu-overrides.js +510 -0
  75. package/src/core/wu-prefetch.js +414 -0
  76. package/src/core/wu-proxy-sandbox.js +398 -75
  77. package/src/core/wu-sandbox.js +86 -268
  78. package/src/core/wu-script-executor.js +79 -182
  79. package/src/core/wu-snapshot-sandbox.js +149 -106
  80. package/src/core/wu-strategies.js +13 -0
  81. package/src/core/wu-style-bridge.js +0 -2
  82. package/src/index.js +139 -665
  83. package/dist/wu-framework.hex.js +0 -23
  84. package/dist/wu-framework.min.js +0 -1
  85. package/dist/wu-framework.obf.js +0 -1
  86. package/scripts/build-protected.js +0 -366
  87. package/scripts/build.js +0 -212
  88. package/scripts/rollup-plugin-hex.js +0 -143
  89. package/src/core/wu-registry.js +0 -60
  90. package/src/core/wu-sandbox-pool.js +0 -390
@@ -0,0 +1,785 @@
1
+ /**
2
+ * 🚀 WU-FRAMEWORK VANILLA JS ADAPTER
3
+ *
4
+ * El adapter más simple - Para JavaScript puro sin frameworks.
5
+ * Ideal para microfrontends ligeros o legacy code.
6
+ *
7
+ * @example
8
+ * // Microfrontend (main.js)
9
+ * import { wuVanilla } from 'wu-framework/adapters/vanilla';
10
+ *
11
+ * wuVanilla.register('my-app', {
12
+ * render: (container) => {
13
+ * container.innerHTML = '<h1>Hello World</h1>';
14
+ * }
15
+ * });
16
+ *
17
+ * @example
18
+ * // Con clase
19
+ * class MyApp {
20
+ * constructor(container) {
21
+ * this.container = container;
22
+ * }
23
+ * render() {
24
+ * this.container.innerHTML = '<h1>My App</h1>';
25
+ * }
26
+ * destroy() {
27
+ * this.container.innerHTML = '';
28
+ * }
29
+ * }
30
+ *
31
+ * wuVanilla.registerClass('my-app', MyApp);
32
+ */
33
+
34
+ // Estado global del adapter
35
+ const adapterState = {
36
+ apps: new Map(),
37
+ instances: new Map()
38
+ };
39
+
40
+ /**
41
+ * Obtiene la instancia de Wu Framework
42
+ */
43
+ function getWuInstance() {
44
+ if (typeof window === 'undefined') return null;
45
+
46
+ return window.wu
47
+ || window.parent?.wu
48
+ || window.top?.wu
49
+ || null;
50
+ }
51
+
52
+ /**
53
+ * Espera a que Wu Framework esté disponible
54
+ */
55
+ function waitForWu(timeout = 5000) {
56
+ return new Promise((resolve, reject) => {
57
+ const wu = getWuInstance();
58
+ if (wu) {
59
+ resolve(wu);
60
+ return;
61
+ }
62
+
63
+ const startTime = Date.now();
64
+
65
+ const handleWuReady = () => {
66
+ cleanup();
67
+ resolve(getWuInstance());
68
+ };
69
+
70
+ window.addEventListener('wu:ready', handleWuReady);
71
+ window.addEventListener('wu:app:ready', handleWuReady);
72
+
73
+ const checkInterval = setInterval(() => {
74
+ const wu = getWuInstance();
75
+ if (wu) {
76
+ cleanup();
77
+ resolve(wu);
78
+ return;
79
+ }
80
+
81
+ if (Date.now() - startTime > timeout) {
82
+ cleanup();
83
+ reject(new Error(`Wu Framework not found after ${timeout}ms`));
84
+ }
85
+ }, 200);
86
+
87
+ function cleanup() {
88
+ clearInterval(checkInterval);
89
+ window.removeEventListener('wu:ready', handleWuReady);
90
+ window.removeEventListener('wu:app:ready', handleWuReady);
91
+ }
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Registra una app Vanilla JS como microfrontend
97
+ *
98
+ * @param {string} appName - Nombre único del microfrontend
99
+ * @param {Object} config - Configuración de la app
100
+ * @param {Function} config.render - Función para renderizar (recibe container)
101
+ * @param {Function} [config.destroy] - Función para limpiar (recibe container)
102
+ * @param {Function} [config.init] - Función de inicialización (recibe container)
103
+ * @param {Object} [config.state] - Estado inicial
104
+ * @param {Object} options - Opciones adicionales
105
+ *
106
+ * @example
107
+ * wuVanilla.register('counter', {
108
+ * state: { count: 0 },
109
+ * init: (container) => {
110
+ * console.log('Initializing...');
111
+ * },
112
+ * render: (container, state) => {
113
+ * container.innerHTML = `
114
+ * <div>
115
+ * <h1>Count: ${state.count}</h1>
116
+ * <button id="increment">+</button>
117
+ * </div>
118
+ * `;
119
+ * container.querySelector('#increment').onclick = () => {
120
+ * state.count++;
121
+ * // Re-render
122
+ * };
123
+ * },
124
+ * destroy: (container) => {
125
+ * container.innerHTML = '';
126
+ * }
127
+ * });
128
+ */
129
+ async function register(appName, config, options = {}) {
130
+ const {
131
+ render,
132
+ destroy = null,
133
+ init = null,
134
+ state = {}
135
+ } = config;
136
+
137
+ const {
138
+ onMount = null,
139
+ onUnmount = null,
140
+ standalone = true,
141
+ standaloneContainer = '#app'
142
+ } = options;
143
+
144
+ if (!render || typeof render !== 'function') {
145
+ throw new Error(`[WuVanilla] render function is required for ${appName}`);
146
+ }
147
+
148
+ // Estado local de la app
149
+ let appState = { ...state };
150
+
151
+ // Función de mount
152
+ const mountApp = (container) => {
153
+ if (!container) {
154
+ console.error(`[WuVanilla] Mount failed for ${appName}: container is null`);
155
+ return;
156
+ }
157
+
158
+ // Evitar doble mount
159
+ if (adapterState.apps.has(appName)) {
160
+ console.warn(`[WuVanilla] ${appName} already mounted, unmounting first`);
161
+ unmountApp();
162
+ }
163
+
164
+ try {
165
+ // Limpiar container
166
+ container.innerHTML = '';
167
+
168
+ // Ejecutar init si existe
169
+ if (init && typeof init === 'function') {
170
+ init(container, appState);
171
+ }
172
+
173
+ // Renderizar
174
+ render(container, appState);
175
+
176
+ // Guardar referencia
177
+ adapterState.apps.set(appName, {
178
+ container,
179
+ config,
180
+ state: appState
181
+ });
182
+
183
+ console.log(`[WuVanilla] ✅ ${appName} mounted successfully`);
184
+
185
+ if (onMount) {
186
+ onMount(container, appState);
187
+ }
188
+ } catch (error) {
189
+ console.error(`[WuVanilla] Mount error for ${appName}:`, error);
190
+ throw error;
191
+ }
192
+ };
193
+
194
+ // Función de unmount
195
+ const unmountApp = (container) => {
196
+ const appData = adapterState.apps.get(appName);
197
+
198
+ if (appData) {
199
+ try {
200
+ if (onUnmount) {
201
+ onUnmount(appData.container, appData.state);
202
+ }
203
+
204
+ // Ejecutar destroy si existe
205
+ if (destroy && typeof destroy === 'function') {
206
+ destroy(appData.container, appData.state);
207
+ } else {
208
+ // Cleanup por defecto
209
+ appData.container.innerHTML = '';
210
+ }
211
+
212
+ adapterState.apps.delete(appName);
213
+
214
+ console.log(`[WuVanilla] ✅ ${appName} unmounted successfully`);
215
+ } catch (error) {
216
+ console.error(`[WuVanilla] Unmount error for ${appName}:`, error);
217
+ }
218
+ }
219
+
220
+ if (container) {
221
+ container.innerHTML = '';
222
+ }
223
+ };
224
+
225
+ // Intentar registrar con Wu Framework
226
+ try {
227
+ const wu = await waitForWu(3000);
228
+
229
+ wu.define(appName, {
230
+ mount: mountApp,
231
+ unmount: unmountApp
232
+ });
233
+
234
+ console.log(`[WuVanilla] ✅ ${appName} registered with Wu Framework`);
235
+ return true;
236
+
237
+ } catch (error) {
238
+ console.warn(`[WuVanilla] Wu Framework not available for ${appName}`);
239
+
240
+ if (standalone) {
241
+ const containerElement = document.querySelector(standaloneContainer);
242
+
243
+ if (containerElement) {
244
+ console.log(`[WuVanilla] Running ${appName} in standalone mode`);
245
+ mountApp(containerElement);
246
+ return true;
247
+ }
248
+ }
249
+
250
+ return false;
251
+ }
252
+ }
253
+
254
+ /**
255
+ * Registra una clase como microfrontend
256
+ *
257
+ * @param {string} appName - Nombre único del microfrontend
258
+ * @param {Function} AppClass - Clase con constructor(container) y métodos render/destroy
259
+ * @param {Object} options - Opciones adicionales
260
+ *
261
+ * @example
262
+ * class TodoApp {
263
+ * constructor(container) {
264
+ * this.container = container;
265
+ * this.todos = [];
266
+ * }
267
+ *
268
+ * render() {
269
+ * this.container.innerHTML = `
270
+ * <ul>${this.todos.map(t => `<li>${t}</li>`).join('')}</ul>
271
+ * `;
272
+ * }
273
+ *
274
+ * addTodo(text) {
275
+ * this.todos.push(text);
276
+ * this.render();
277
+ * }
278
+ *
279
+ * destroy() {
280
+ * this.container.innerHTML = '';
281
+ * this.todos = [];
282
+ * }
283
+ * }
284
+ *
285
+ * wuVanilla.registerClass('todo-app', TodoApp);
286
+ */
287
+ async function registerClass(appName, AppClass, options = {}) {
288
+ const {
289
+ constructorArgs = [],
290
+ onMount = null,
291
+ onUnmount = null,
292
+ standalone = true,
293
+ standaloneContainer = '#app'
294
+ } = options;
295
+
296
+ // Función de mount
297
+ const mountApp = (container) => {
298
+ if (!container) {
299
+ console.error(`[WuVanilla] Mount failed for ${appName}: container is null`);
300
+ return;
301
+ }
302
+
303
+ // Evitar doble mount
304
+ if (adapterState.instances.has(appName)) {
305
+ console.warn(`[WuVanilla] ${appName} already mounted, unmounting first`);
306
+ unmountApp();
307
+ }
308
+
309
+ try {
310
+ container.innerHTML = '';
311
+
312
+ // Crear instancia de la clase
313
+ const instance = new AppClass(container, ...constructorArgs);
314
+
315
+ // Llamar render si existe
316
+ if (instance.render && typeof instance.render === 'function') {
317
+ instance.render();
318
+ }
319
+
320
+ // Guardar instancia
321
+ adapterState.instances.set(appName, {
322
+ instance,
323
+ container
324
+ });
325
+
326
+ console.log(`[WuVanilla] ✅ ${appName} (class) mounted successfully`);
327
+
328
+ if (onMount) {
329
+ onMount(container, instance);
330
+ }
331
+ } catch (error) {
332
+ console.error(`[WuVanilla] Mount error for ${appName}:`, error);
333
+ throw error;
334
+ }
335
+ };
336
+
337
+ // Función de unmount
338
+ const unmountApp = (container) => {
339
+ const appData = adapterState.instances.get(appName);
340
+
341
+ if (appData) {
342
+ try {
343
+ if (onUnmount) {
344
+ onUnmount(appData.container, appData.instance);
345
+ }
346
+
347
+ // Llamar destroy si existe
348
+ if (appData.instance.destroy && typeof appData.instance.destroy === 'function') {
349
+ appData.instance.destroy();
350
+ } else {
351
+ appData.container.innerHTML = '';
352
+ }
353
+
354
+ adapterState.instances.delete(appName);
355
+
356
+ console.log(`[WuVanilla] ✅ ${appName} (class) unmounted successfully`);
357
+ } catch (error) {
358
+ console.error(`[WuVanilla] Unmount error for ${appName}:`, error);
359
+ }
360
+ }
361
+
362
+ if (container) {
363
+ container.innerHTML = '';
364
+ }
365
+ };
366
+
367
+ // Intentar registrar con Wu Framework
368
+ try {
369
+ const wu = await waitForWu(3000);
370
+
371
+ wu.define(appName, {
372
+ mount: mountApp,
373
+ unmount: unmountApp
374
+ });
375
+
376
+ console.log(`[WuVanilla] ✅ ${appName} (class) registered with Wu Framework`);
377
+ return true;
378
+
379
+ } catch (error) {
380
+ console.warn(`[WuVanilla] Wu Framework not available for ${appName}`);
381
+
382
+ if (standalone) {
383
+ const containerElement = document.querySelector(standaloneContainer);
384
+
385
+ if (containerElement) {
386
+ console.log(`[WuVanilla] Running ${appName} in standalone mode`);
387
+ mountApp(containerElement);
388
+ return true;
389
+ }
390
+ }
391
+
392
+ return false;
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Registra un template HTML como microfrontend
398
+ *
399
+ * @param {string} appName - Nombre único del microfrontend
400
+ * @param {string|Function} template - HTML string o función que retorna HTML
401
+ * @param {Object} options - Opciones adicionales
402
+ *
403
+ * @example
404
+ * // Template estático
405
+ * wuVanilla.registerTemplate('header', '<header><h1>My Header</h1></header>');
406
+ *
407
+ * // Template dinámico
408
+ * wuVanilla.registerTemplate('greeting', (data) => `<h1>Hello ${data.name}!</h1>`, {
409
+ * data: { name: 'World' }
410
+ * });
411
+ */
412
+ async function registerTemplate(appName, template, options = {}) {
413
+ const {
414
+ data = {},
415
+ scripts = [],
416
+ styles = [],
417
+ onMount = null,
418
+ onUnmount = null,
419
+ standalone = true,
420
+ standaloneContainer = '#app'
421
+ } = options;
422
+
423
+ const mountApp = (container) => {
424
+ if (!container) {
425
+ console.error(`[WuVanilla] Mount failed for ${appName}: container is null`);
426
+ return;
427
+ }
428
+
429
+ try {
430
+ container.innerHTML = '';
431
+
432
+ // Inyectar estilos
433
+ if (styles.length > 0) {
434
+ const styleEl = document.createElement('style');
435
+ styleEl.textContent = styles.join('\n');
436
+ styleEl.setAttribute('data-wu-app', appName);
437
+ container.appendChild(styleEl);
438
+ }
439
+
440
+ // Crear wrapper
441
+ const wrapper = document.createElement('div');
442
+ wrapper.setAttribute('data-wu-template', appName);
443
+
444
+ // Renderizar template
445
+ if (typeof template === 'function') {
446
+ wrapper.innerHTML = template(data);
447
+ } else {
448
+ wrapper.innerHTML = template;
449
+ }
450
+
451
+ container.appendChild(wrapper);
452
+
453
+ // Ejecutar scripts
454
+ scripts.forEach(scriptFn => {
455
+ if (typeof scriptFn === 'function') {
456
+ scriptFn(container, data);
457
+ }
458
+ });
459
+
460
+ adapterState.apps.set(appName, { container, template, data });
461
+
462
+ console.log(`[WuVanilla] ✅ ${appName} (template) mounted successfully`);
463
+
464
+ if (onMount) {
465
+ onMount(container, data);
466
+ }
467
+ } catch (error) {
468
+ console.error(`[WuVanilla] Mount error for ${appName}:`, error);
469
+ throw error;
470
+ }
471
+ };
472
+
473
+ const unmountApp = (container) => {
474
+ const appData = adapterState.apps.get(appName);
475
+
476
+ if (appData) {
477
+ if (onUnmount) {
478
+ onUnmount(appData.container, appData.data);
479
+ }
480
+
481
+ appData.container.innerHTML = '';
482
+ adapterState.apps.delete(appName);
483
+
484
+ console.log(`[WuVanilla] ✅ ${appName} (template) unmounted successfully`);
485
+ }
486
+
487
+ if (container) {
488
+ container.innerHTML = '';
489
+ }
490
+ };
491
+
492
+ try {
493
+ const wu = await waitForWu(3000);
494
+
495
+ wu.define(appName, {
496
+ mount: mountApp,
497
+ unmount: unmountApp
498
+ });
499
+
500
+ console.log(`[WuVanilla] ✅ ${appName} (template) registered with Wu Framework`);
501
+ return true;
502
+
503
+ } catch (error) {
504
+ console.warn(`[WuVanilla] Wu Framework not available for ${appName}`);
505
+
506
+ if (standalone) {
507
+ const containerElement = document.querySelector(standaloneContainer);
508
+ if (containerElement) {
509
+ console.log(`[WuVanilla] Running ${appName} in standalone mode`);
510
+ mountApp(containerElement);
511
+ return true;
512
+ }
513
+ }
514
+
515
+ return false;
516
+ }
517
+ }
518
+
519
+ /**
520
+ * Helper para crear un componente reactivo simple
521
+ *
522
+ * @param {Object} config - Configuración del componente
523
+ * @returns {Object} Componente con métodos de estado
524
+ *
525
+ * @example
526
+ * const Counter = wuVanilla.createComponent({
527
+ * state: { count: 0 },
528
+ * template: (state) => `
529
+ * <div>
530
+ * <h1>Count: ${state.count}</h1>
531
+ * <button data-action="increment">+</button>
532
+ * <button data-action="decrement">-</button>
533
+ * </div>
534
+ * `,
535
+ * actions: {
536
+ * increment: (state) => ({ count: state.count + 1 }),
537
+ * decrement: (state) => ({ count: state.count - 1 })
538
+ * }
539
+ * });
540
+ *
541
+ * wuVanilla.register('counter', Counter);
542
+ */
543
+ function createComponent(config) {
544
+ const { state: initialState = {}, template, actions = {}, onInit, onDestroy } = config;
545
+
546
+ let currentState = { ...initialState };
547
+ let container = null;
548
+ let mounted = false;
549
+
550
+ const setState = (newState) => {
551
+ currentState = { ...currentState, ...newState };
552
+ if (mounted && container) {
553
+ render(container, currentState);
554
+ }
555
+ };
556
+
557
+ const render = (cont, state) => {
558
+ const html = template(state);
559
+
560
+ // Preservar focus si es posible
561
+ const activeId = document.activeElement?.id;
562
+
563
+ cont.innerHTML = html;
564
+
565
+ // Restaurar focus
566
+ if (activeId) {
567
+ const el = cont.querySelector(`#${activeId}`);
568
+ if (el) el.focus();
569
+ }
570
+
571
+ // Bind actions
572
+ cont.querySelectorAll('[data-action]').forEach(el => {
573
+ const actionName = el.getAttribute('data-action');
574
+ if (actions[actionName]) {
575
+ el.addEventListener('click', () => {
576
+ const result = actions[actionName](currentState, el);
577
+ if (result) {
578
+ setState(result);
579
+ }
580
+ });
581
+ }
582
+ });
583
+ };
584
+
585
+ return {
586
+ state: currentState,
587
+
588
+ init: (cont) => {
589
+ container = cont;
590
+ if (onInit) onInit(cont, currentState);
591
+ },
592
+
593
+ render: (cont, state) => {
594
+ container = cont;
595
+ currentState = state || currentState;
596
+ mounted = true;
597
+ render(cont, currentState);
598
+ },
599
+
600
+ destroy: (cont) => {
601
+ if (onDestroy) onDestroy(cont, currentState);
602
+ mounted = false;
603
+ container = null;
604
+ cont.innerHTML = '';
605
+ },
606
+
607
+ // Exponer setState para uso externo
608
+ setState,
609
+ getState: () => currentState
610
+ };
611
+ }
612
+
613
+ /**
614
+ * Helper para usar eventos de Wu Framework
615
+ */
616
+ function useWuEvents() {
617
+ const subscriptions = [];
618
+
619
+ return {
620
+ emit: (event, data, options) => {
621
+ const wu = getWuInstance();
622
+ if (wu?.eventBus) {
623
+ wu.eventBus.emit(event, data, options);
624
+ }
625
+ },
626
+
627
+ on: (event, callback) => {
628
+ const wu = getWuInstance();
629
+ if (wu?.eventBus) {
630
+ const unsubscribe = wu.eventBus.on(event, callback);
631
+ subscriptions.push(unsubscribe);
632
+ return unsubscribe;
633
+ }
634
+ return () => {};
635
+ },
636
+
637
+ once: (event, callback) => {
638
+ const wu = getWuInstance();
639
+ if (wu?.eventBus) {
640
+ return wu.eventBus.once(event, callback);
641
+ }
642
+ return () => {};
643
+ },
644
+
645
+ off: (event, callback) => {
646
+ const wu = getWuInstance();
647
+ if (wu?.eventBus) {
648
+ wu.eventBus.off(event, callback);
649
+ }
650
+ },
651
+
652
+ cleanup: () => {
653
+ subscriptions.forEach(unsub => unsub());
654
+ subscriptions.length = 0;
655
+ }
656
+ };
657
+ }
658
+
659
+ /**
660
+ * Helper para usar el Store de Wu Framework
661
+ */
662
+ function useWuStore(namespace = '') {
663
+ return {
664
+ get: (path = '') => {
665
+ const wu = getWuInstance();
666
+ if (wu?.store) {
667
+ const fullPath = namespace ? (path ? `${namespace}.${path}` : namespace) : path;
668
+ return wu.store.get(fullPath);
669
+ }
670
+ return null;
671
+ },
672
+
673
+ set: (path, value) => {
674
+ const wu = getWuInstance();
675
+ if (wu?.store) {
676
+ const fullPath = namespace ? `${namespace}.${path}` : path;
677
+ wu.store.set(fullPath, value);
678
+ }
679
+ },
680
+
681
+ onChange: (pattern, callback) => {
682
+ const wu = getWuInstance();
683
+ if (wu?.store) {
684
+ const fullPattern = namespace ? `${namespace}.${pattern}` : pattern;
685
+ return wu.store.on(fullPattern, callback);
686
+ }
687
+ return () => {};
688
+ }
689
+ };
690
+ }
691
+
692
+ /**
693
+ * Crea un WuSlot en JavaScript puro
694
+ */
695
+ function createWuSlot(target, props) {
696
+ const { name, url, fallbackText = null, onLoad = null, onError = null } = props;
697
+
698
+ const container = document.createElement('div');
699
+ container.className = 'wu-slot';
700
+ container.style.cssText = 'min-height: 100px; position: relative;';
701
+ container.setAttribute('data-wu-app', name);
702
+ container.setAttribute('data-wu-url', url);
703
+
704
+ // Loading state
705
+ container.innerHTML = `
706
+ <div style="display: flex; align-items: center; justify-content: center; padding: 2rem; color: #666;">
707
+ ${fallbackText || `Loading ${name}...`}
708
+ </div>
709
+ `;
710
+
711
+ target.appendChild(container);
712
+
713
+ let appInstance = null;
714
+
715
+ const mount = async () => {
716
+ try {
717
+ const wu = getWuInstance();
718
+ if (!wu) throw new Error('Wu Framework not initialized');
719
+
720
+ const containerId = `wu-slot-${name}-${Date.now()}`;
721
+ const innerContainer = document.createElement('div');
722
+ innerContainer.id = containerId;
723
+ innerContainer.style.cssText = 'width: 100%; height: 100%;';
724
+
725
+ container.innerHTML = '';
726
+ container.appendChild(innerContainer);
727
+
728
+ const app = wu.app(name, {
729
+ url,
730
+ container: `#${containerId}`,
731
+ autoInit: true
732
+ });
733
+
734
+ appInstance = app;
735
+ await app.mount();
736
+
737
+ if (onLoad) onLoad({ name, url });
738
+
739
+ } catch (err) {
740
+ container.innerHTML = `
741
+ <div style="padding: 1rem; border: 1px solid #f5c6cb; border-radius: 4px; background: #f8d7da; color: #721c24;">
742
+ <strong>Error loading ${name}</strong>
743
+ <p style="margin: 0.5rem 0 0 0;">${err.message}</p>
744
+ </div>
745
+ `;
746
+ if (onError) onError(err);
747
+ }
748
+ };
749
+
750
+ const destroy = async () => {
751
+ if (appInstance) {
752
+ try {
753
+ await appInstance.unmount();
754
+ } catch (e) {}
755
+ appInstance = null;
756
+ }
757
+ container.remove();
758
+ };
759
+
760
+ mount();
761
+
762
+ return { container, destroy };
763
+ }
764
+
765
+ // ============================================
766
+ // AI INTEGRATION
767
+ // ============================================
768
+ export { useWuAI } from './ai.js';
769
+ import { useWuAI } from './ai.js';
770
+
771
+ // API pública del adapter
772
+ export const wuVanilla = {
773
+ register,
774
+ registerClass,
775
+ registerTemplate,
776
+ createComponent,
777
+ createWuSlot,
778
+ useWuEvents,
779
+ useWuStore,
780
+ useWuAI,
781
+ getWuInstance,
782
+ waitForWu
783
+ };
784
+
785
+ export default wuVanilla;