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.
- package/README.md +511 -977
- package/dist/wu-framework.cjs.js +3 -1
- package/dist/wu-framework.cjs.js.map +1 -0
- package/dist/wu-framework.dev.js +7533 -2761
- package/dist/wu-framework.dev.js.map +1 -1
- package/dist/wu-framework.esm.js +3 -0
- package/dist/wu-framework.esm.js.map +1 -0
- package/dist/wu-framework.umd.js +3 -1
- package/dist/wu-framework.umd.js.map +1 -0
- package/integrations/astro/README.md +127 -0
- package/integrations/astro/WuApp.astro +63 -0
- package/integrations/astro/WuShell.astro +39 -0
- package/integrations/astro/index.js +68 -0
- package/integrations/astro/package.json +38 -0
- package/integrations/astro/types.d.ts +53 -0
- package/package.json +94 -74
- package/src/adapters/angular/ai.js +30 -0
- package/src/adapters/angular/index.d.ts +154 -0
- package/src/adapters/angular/index.js +932 -0
- package/src/adapters/angular.d.ts +3 -154
- package/src/adapters/angular.js +3 -813
- package/src/adapters/index.js +35 -24
- package/src/adapters/lit/ai.js +20 -0
- package/src/adapters/lit/index.d.ts +120 -0
- package/src/adapters/lit/index.js +721 -0
- package/src/adapters/lit.d.ts +3 -120
- package/src/adapters/lit.js +3 -726
- package/src/adapters/preact/ai.js +33 -0
- package/src/adapters/preact/index.d.ts +108 -0
- package/src/adapters/preact/index.js +661 -0
- package/src/adapters/preact.d.ts +3 -108
- package/src/adapters/preact.js +3 -665
- package/src/adapters/react/ai.js +135 -0
- package/src/adapters/react/index.d.ts +246 -0
- package/src/adapters/react/index.js +689 -0
- package/src/adapters/react.d.ts +3 -212
- package/src/adapters/react.js +3 -513
- package/src/adapters/shared.js +64 -0
- package/src/adapters/solid/ai.js +32 -0
- package/src/adapters/solid/index.d.ts +101 -0
- package/src/adapters/solid/index.js +586 -0
- package/src/adapters/solid.d.ts +3 -101
- package/src/adapters/solid.js +3 -591
- package/src/adapters/svelte/ai.js +31 -0
- package/src/adapters/svelte/index.d.ts +166 -0
- package/src/adapters/svelte/index.js +798 -0
- package/src/adapters/svelte.d.ts +3 -166
- package/src/adapters/svelte.js +3 -803
- package/src/adapters/vanilla/ai.js +30 -0
- package/src/adapters/vanilla/index.d.ts +179 -0
- package/src/adapters/vanilla/index.js +785 -0
- package/src/adapters/vanilla.d.ts +3 -179
- package/src/adapters/vanilla.js +3 -791
- package/src/adapters/vue/ai.js +52 -0
- package/src/adapters/vue/index.d.ts +299 -0
- package/src/adapters/vue/index.js +608 -0
- package/src/adapters/vue.d.ts +3 -299
- package/src/adapters/vue.js +3 -611
- package/src/ai/wu-ai-actions.js +261 -0
- package/src/ai/wu-ai-browser.js +663 -0
- package/src/ai/wu-ai-context.js +332 -0
- package/src/ai/wu-ai-conversation.js +554 -0
- package/src/ai/wu-ai-permissions.js +381 -0
- package/src/ai/wu-ai-provider.js +605 -0
- package/src/ai/wu-ai-schema.js +225 -0
- package/src/ai/wu-ai-triggers.js +396 -0
- package/src/ai/wu-ai.js +474 -0
- package/src/core/wu-app.js +50 -8
- package/src/core/wu-cache.js +1 -1
- package/src/core/wu-core.js +645 -677
- package/src/core/wu-html-parser.js +121 -211
- package/src/core/wu-iframe-sandbox.js +328 -0
- package/src/core/wu-mcp-bridge.js +647 -0
- package/src/core/wu-overrides.js +510 -0
- package/src/core/wu-prefetch.js +414 -0
- package/src/core/wu-proxy-sandbox.js +398 -75
- package/src/core/wu-sandbox.js +86 -268
- package/src/core/wu-script-executor.js +79 -182
- package/src/core/wu-snapshot-sandbox.js +149 -106
- package/src/core/wu-strategies.js +13 -0
- package/src/core/wu-style-bridge.js +0 -2
- package/src/index.js +139 -665
- package/dist/wu-framework.hex.js +0 -23
- package/dist/wu-framework.min.js +0 -1
- package/dist/wu-framework.obf.js +0 -1
- package/scripts/build-protected.js +0 -366
- package/scripts/build.js +0 -212
- package/scripts/rollup-plugin-hex.js +0 -143
- package/src/core/wu-registry.js +0 -60
- package/src/core/wu-sandbox-pool.js +0 -390
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🚀 WU-FRAMEWORK PREACT ADAPTER
|
|
3
|
+
*
|
|
4
|
+
* Simplifica la integración de Preact con Wu Framework.
|
|
5
|
+
* Compatible con Preact 10+ y preact/compat para proyectos React migrados.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Microfrontend (main.jsx)
|
|
9
|
+
* import { wuPreact } from 'wu-framework/adapters/preact';
|
|
10
|
+
* import App from './App';
|
|
11
|
+
*
|
|
12
|
+
* wuPreact.register('my-app', App);
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Shell (cargar microfrontend)
|
|
16
|
+
* import { createWuSlot } from 'wu-framework/adapters/preact';
|
|
17
|
+
* import { h } from 'preact';
|
|
18
|
+
*
|
|
19
|
+
* const WuSlot = createWuSlot(h);
|
|
20
|
+
* <WuSlot name="my-app" url="http://localhost:3001" />
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Estado global del adapter
|
|
24
|
+
const adapterState = {
|
|
25
|
+
apps: new Map(),
|
|
26
|
+
preact: null,
|
|
27
|
+
render: null,
|
|
28
|
+
h: null,
|
|
29
|
+
initialized: false
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Detecta y obtiene Preact del contexto global o lo importa
|
|
34
|
+
*/
|
|
35
|
+
async function ensurePreact() {
|
|
36
|
+
if (adapterState.initialized) return true;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Intentar obtener de window
|
|
40
|
+
if (typeof window !== 'undefined' && window.preact) {
|
|
41
|
+
adapterState.preact = window.preact;
|
|
42
|
+
adapterState.render = window.preact.render;
|
|
43
|
+
adapterState.h = window.preact.h;
|
|
44
|
+
adapterState.initialized = true;
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Intentar import dinámico
|
|
49
|
+
const preact = await import('preact');
|
|
50
|
+
adapterState.preact = preact;
|
|
51
|
+
adapterState.render = preact.render;
|
|
52
|
+
adapterState.h = preact.h;
|
|
53
|
+
adapterState.initialized = true;
|
|
54
|
+
return true;
|
|
55
|
+
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('[WuPreact] Failed to load Preact:', error);
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Obtiene la instancia de Wu Framework
|
|
64
|
+
*/
|
|
65
|
+
function getWuInstance() {
|
|
66
|
+
if (typeof window === 'undefined') return null;
|
|
67
|
+
|
|
68
|
+
return window.wu
|
|
69
|
+
|| window.parent?.wu
|
|
70
|
+
|| window.top?.wu
|
|
71
|
+
|| null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Espera a que Wu Framework esté disponible
|
|
76
|
+
*/
|
|
77
|
+
function waitForWu(timeout = 5000) {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
const wu = getWuInstance();
|
|
80
|
+
if (wu) {
|
|
81
|
+
resolve(wu);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const startTime = Date.now();
|
|
86
|
+
|
|
87
|
+
const handleWuReady = () => {
|
|
88
|
+
cleanup();
|
|
89
|
+
resolve(getWuInstance());
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
window.addEventListener('wu:ready', handleWuReady);
|
|
93
|
+
window.addEventListener('wu:app:ready', handleWuReady);
|
|
94
|
+
|
|
95
|
+
const checkInterval = setInterval(() => {
|
|
96
|
+
const wu = getWuInstance();
|
|
97
|
+
if (wu) {
|
|
98
|
+
cleanup();
|
|
99
|
+
resolve(wu);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (Date.now() - startTime > timeout) {
|
|
104
|
+
cleanup();
|
|
105
|
+
reject(new Error(`Wu Framework not found after ${timeout}ms`));
|
|
106
|
+
}
|
|
107
|
+
}, 200);
|
|
108
|
+
|
|
109
|
+
function cleanup() {
|
|
110
|
+
clearInterval(checkInterval);
|
|
111
|
+
window.removeEventListener('wu:ready', handleWuReady);
|
|
112
|
+
window.removeEventListener('wu:app:ready', handleWuReady);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Registra un componente Preact como microfrontend
|
|
119
|
+
*
|
|
120
|
+
* @param {string} appName - Nombre único del microfrontend
|
|
121
|
+
* @param {Function} Component - Componente Preact principal
|
|
122
|
+
* @param {Object} options - Opciones adicionales
|
|
123
|
+
* @param {Object} options.props - Props iniciales para el componente
|
|
124
|
+
* @param {Function} options.onMount - Callback después de montar
|
|
125
|
+
* @param {Function} options.onUnmount - Callback antes de desmontar
|
|
126
|
+
* @param {boolean} options.standalone - Permitir ejecución standalone (default: true)
|
|
127
|
+
* @param {string} options.standaloneContainer - Selector para modo standalone (default: '#app')
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* // Básico
|
|
131
|
+
* wuPreact.register('my-app', App);
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* // Con props
|
|
135
|
+
* wuPreact.register('my-app', App, {
|
|
136
|
+
* props: { apiUrl: 'https://api.example.com' },
|
|
137
|
+
* onMount: (container) => console.log('Mounted!')
|
|
138
|
+
* });
|
|
139
|
+
*/
|
|
140
|
+
async function register(appName, Component, options = {}) {
|
|
141
|
+
const {
|
|
142
|
+
props = {},
|
|
143
|
+
onMount = null,
|
|
144
|
+
onUnmount = null,
|
|
145
|
+
standalone = true,
|
|
146
|
+
standaloneContainer = '#app'
|
|
147
|
+
} = options;
|
|
148
|
+
|
|
149
|
+
// Asegurar que Preact está disponible
|
|
150
|
+
const hasPreact = await ensurePreact();
|
|
151
|
+
if (!hasPreact) {
|
|
152
|
+
console.error(`[WuPreact] Cannot register ${appName}: Preact not available`);
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const { render, h } = adapterState;
|
|
157
|
+
|
|
158
|
+
// Función de mount interna
|
|
159
|
+
const mountApp = (container) => {
|
|
160
|
+
if (!container) {
|
|
161
|
+
console.error(`[WuPreact] Mount failed for ${appName}: container is null`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Evitar doble mount
|
|
166
|
+
if (adapterState.apps.has(appName)) {
|
|
167
|
+
console.warn(`[WuPreact] ${appName} already mounted, unmounting first`);
|
|
168
|
+
unmountApp();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
// Limpiar container
|
|
173
|
+
container.innerHTML = '';
|
|
174
|
+
|
|
175
|
+
// Renderizar componente
|
|
176
|
+
render(
|
|
177
|
+
h(Component, {
|
|
178
|
+
...props,
|
|
179
|
+
wuAppName: appName,
|
|
180
|
+
wuInstance: getWuInstance()
|
|
181
|
+
}),
|
|
182
|
+
container
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
// Guardar referencia
|
|
186
|
+
adapterState.apps.set(appName, { container, Component });
|
|
187
|
+
|
|
188
|
+
console.log(`[WuPreact] ✅ ${appName} mounted successfully`);
|
|
189
|
+
|
|
190
|
+
if (onMount) {
|
|
191
|
+
onMount(container);
|
|
192
|
+
}
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error(`[WuPreact] Mount error for ${appName}:`, error);
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Función de unmount interna
|
|
200
|
+
const unmountApp = (container) => {
|
|
201
|
+
const appData = adapterState.apps.get(appName);
|
|
202
|
+
|
|
203
|
+
if (appData) {
|
|
204
|
+
try {
|
|
205
|
+
if (onUnmount) {
|
|
206
|
+
onUnmount(appData.container);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Unmount en Preact: renderizar null
|
|
210
|
+
render(null, appData.container);
|
|
211
|
+
|
|
212
|
+
adapterState.apps.delete(appName);
|
|
213
|
+
|
|
214
|
+
console.log(`[WuPreact] ✅ ${appName} unmounted successfully`);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(`[WuPreact] 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(`[WuPreact] ✅ ${appName} registered with Wu Framework`);
|
|
235
|
+
return true;
|
|
236
|
+
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.warn(`[WuPreact] Wu Framework not available for ${appName}`);
|
|
239
|
+
|
|
240
|
+
if (standalone) {
|
|
241
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
242
|
+
|
|
243
|
+
if (containerElement) {
|
|
244
|
+
console.log(`[WuPreact] Running ${appName} in standalone mode`);
|
|
245
|
+
mountApp(containerElement);
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Registra usando preact/compat (para proyectos migrados de React)
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* import { wuPreact } from 'wu-framework/adapters/preact';
|
|
259
|
+
* import App from './App'; // Componente React-like
|
|
260
|
+
*
|
|
261
|
+
* wuPreact.registerCompat('my-app', App);
|
|
262
|
+
*/
|
|
263
|
+
async function registerCompat(appName, Component, options = {}) {
|
|
264
|
+
const {
|
|
265
|
+
props = {},
|
|
266
|
+
onMount = null,
|
|
267
|
+
onUnmount = null,
|
|
268
|
+
standalone = true,
|
|
269
|
+
standaloneContainer = '#app'
|
|
270
|
+
} = options;
|
|
271
|
+
|
|
272
|
+
let render, h;
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
// Intentar cargar preact/compat
|
|
276
|
+
const compat = await import('preact/compat');
|
|
277
|
+
render = compat.render;
|
|
278
|
+
h = compat.createElement;
|
|
279
|
+
} catch (e) {
|
|
280
|
+
console.error('[WuPreact] preact/compat not available');
|
|
281
|
+
// Fallback a registro normal
|
|
282
|
+
return register(appName, Component, options);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const mountApp = (container) => {
|
|
286
|
+
if (!container) return;
|
|
287
|
+
|
|
288
|
+
if (adapterState.apps.has(appName)) {
|
|
289
|
+
unmountApp();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
container.innerHTML = '';
|
|
294
|
+
|
|
295
|
+
render(
|
|
296
|
+
h(Component, {
|
|
297
|
+
...props,
|
|
298
|
+
wuAppName: appName,
|
|
299
|
+
wuInstance: getWuInstance()
|
|
300
|
+
}),
|
|
301
|
+
container
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
adapterState.apps.set(appName, { container, Component, isCompat: true });
|
|
305
|
+
|
|
306
|
+
console.log(`[WuPreact] ✅ ${appName} (compat) mounted successfully`);
|
|
307
|
+
|
|
308
|
+
if (onMount) onMount(container);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error(`[WuPreact] Mount error for ${appName}:`, error);
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const unmountApp = (container) => {
|
|
316
|
+
const appData = adapterState.apps.get(appName);
|
|
317
|
+
|
|
318
|
+
if (appData) {
|
|
319
|
+
try {
|
|
320
|
+
if (onUnmount) onUnmount(appData.container);
|
|
321
|
+
render(null, appData.container);
|
|
322
|
+
adapterState.apps.delete(appName);
|
|
323
|
+
console.log(`[WuPreact] ✅ ${appName} (compat) unmounted successfully`);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error(`[WuPreact] Unmount error for ${appName}:`, error);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (container) container.innerHTML = '';
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
const wu = await waitForWu(3000);
|
|
334
|
+
wu.define(appName, { mount: mountApp, unmount: unmountApp });
|
|
335
|
+
console.log(`[WuPreact] ✅ ${appName} (compat) registered with Wu Framework`);
|
|
336
|
+
return true;
|
|
337
|
+
} catch (error) {
|
|
338
|
+
if (standalone) {
|
|
339
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
340
|
+
if (containerElement) {
|
|
341
|
+
mountApp(containerElement);
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Crea un componente WuSlot para Preact
|
|
351
|
+
*
|
|
352
|
+
* @param {Function} h - Función h de Preact
|
|
353
|
+
* @returns {Function} Componente WuSlot
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* import { h } from 'preact';
|
|
357
|
+
* import { createWuSlot } from 'wu-framework/adapters/preact';
|
|
358
|
+
*
|
|
359
|
+
* const WuSlot = createWuSlot(h);
|
|
360
|
+
*
|
|
361
|
+
* function Shell() {
|
|
362
|
+
* return (
|
|
363
|
+
* <div>
|
|
364
|
+
* <WuSlot name="header" url="http://localhost:3001" />
|
|
365
|
+
* </div>
|
|
366
|
+
* );
|
|
367
|
+
* }
|
|
368
|
+
*/
|
|
369
|
+
function createWuSlot(h) {
|
|
370
|
+
// Importar hooks de Preact
|
|
371
|
+
let useState, useEffect, useRef, useCallback;
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
const hooks = require('preact/hooks');
|
|
375
|
+
useState = hooks.useState;
|
|
376
|
+
useEffect = hooks.useEffect;
|
|
377
|
+
useRef = hooks.useRef;
|
|
378
|
+
useCallback = hooks.useCallback;
|
|
379
|
+
} catch (e) {
|
|
380
|
+
// Si no hay hooks, crear versión sin hooks
|
|
381
|
+
return function WuSlotBasic(props) {
|
|
382
|
+
const { name, url } = props;
|
|
383
|
+
return h('div', {
|
|
384
|
+
class: 'wu-slot',
|
|
385
|
+
'data-wu-app': name,
|
|
386
|
+
'data-wu-url': url,
|
|
387
|
+
style: 'min-height: 100px;',
|
|
388
|
+
ref: (el) => {
|
|
389
|
+
if (el && !el._mounted) {
|
|
390
|
+
el._mounted = true;
|
|
391
|
+
mountSlot(el, name, url);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}, `Loading ${name}...`);
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return function WuSlot(props) {
|
|
399
|
+
const {
|
|
400
|
+
name,
|
|
401
|
+
url,
|
|
402
|
+
appName = null,
|
|
403
|
+
fallback = null,
|
|
404
|
+
onLoad = null,
|
|
405
|
+
onError = null,
|
|
406
|
+
className = '',
|
|
407
|
+
style = {}
|
|
408
|
+
} = props;
|
|
409
|
+
|
|
410
|
+
const containerRef = useRef(null);
|
|
411
|
+
const appInstanceRef = useRef(null);
|
|
412
|
+
const [loading, setLoading] = useState(true);
|
|
413
|
+
const [error, setError] = useState(null);
|
|
414
|
+
|
|
415
|
+
const actualAppName = appName || name;
|
|
416
|
+
|
|
417
|
+
const mountMicrofrontend = useCallback(async () => {
|
|
418
|
+
if (!containerRef.current) return;
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
setLoading(true);
|
|
422
|
+
setError(null);
|
|
423
|
+
|
|
424
|
+
const wu = getWuInstance();
|
|
425
|
+
if (!wu) throw new Error('Wu Framework not initialized');
|
|
426
|
+
|
|
427
|
+
const containerId = `wu-slot-${actualAppName}-${Date.now()}`;
|
|
428
|
+
const innerContainer = document.createElement('div');
|
|
429
|
+
innerContainer.id = containerId;
|
|
430
|
+
innerContainer.style.cssText = 'width: 100%; height: 100%;';
|
|
431
|
+
|
|
432
|
+
containerRef.current.innerHTML = '';
|
|
433
|
+
containerRef.current.appendChild(innerContainer);
|
|
434
|
+
|
|
435
|
+
const app = wu.app(actualAppName, {
|
|
436
|
+
url,
|
|
437
|
+
container: `#${containerId}`,
|
|
438
|
+
autoInit: true
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
appInstanceRef.current = app;
|
|
442
|
+
await app.mount();
|
|
443
|
+
|
|
444
|
+
setLoading(false);
|
|
445
|
+
if (onLoad) onLoad({ name: actualAppName, url });
|
|
446
|
+
|
|
447
|
+
} catch (err) {
|
|
448
|
+
console.error(`[WuSlot] Error loading ${actualAppName}:`, err);
|
|
449
|
+
setError(err.message || 'Failed to load microfrontend');
|
|
450
|
+
setLoading(false);
|
|
451
|
+
if (onError) onError(err);
|
|
452
|
+
}
|
|
453
|
+
}, [actualAppName, url, onLoad, onError]);
|
|
454
|
+
|
|
455
|
+
useEffect(() => {
|
|
456
|
+
mountMicrofrontend();
|
|
457
|
+
|
|
458
|
+
return () => {
|
|
459
|
+
if (appInstanceRef.current) {
|
|
460
|
+
appInstanceRef.current.unmount().catch(console.warn);
|
|
461
|
+
appInstanceRef.current = null;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
}, [mountMicrofrontend]);
|
|
465
|
+
|
|
466
|
+
if (error) {
|
|
467
|
+
return h('div', {
|
|
468
|
+
class: `wu-slot wu-slot-error ${className}`,
|
|
469
|
+
style: {
|
|
470
|
+
padding: '1rem',
|
|
471
|
+
border: '1px solid #f5c6cb',
|
|
472
|
+
borderRadius: '4px',
|
|
473
|
+
backgroundColor: '#f8d7da',
|
|
474
|
+
color: '#721c24',
|
|
475
|
+
...style
|
|
476
|
+
}
|
|
477
|
+
}, [
|
|
478
|
+
h('strong', null, `Error loading ${name}`),
|
|
479
|
+
h('p', { style: { margin: '0.5rem 0 0 0' } }, error)
|
|
480
|
+
]);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
return h('div', {
|
|
484
|
+
ref: containerRef,
|
|
485
|
+
class: `wu-slot ${loading ? 'wu-slot-loading' : 'wu-slot-loaded'} ${className}`,
|
|
486
|
+
style: {
|
|
487
|
+
minHeight: '100px',
|
|
488
|
+
position: 'relative',
|
|
489
|
+
...style
|
|
490
|
+
},
|
|
491
|
+
'data-wu-app': actualAppName,
|
|
492
|
+
'data-wu-url': url
|
|
493
|
+
}, loading && (fallback || h('div', {
|
|
494
|
+
style: {
|
|
495
|
+
display: 'flex',
|
|
496
|
+
alignItems: 'center',
|
|
497
|
+
justifyContent: 'center',
|
|
498
|
+
padding: '2rem',
|
|
499
|
+
color: '#666'
|
|
500
|
+
}
|
|
501
|
+
}, `Loading ${name}...`)));
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Hook para usar el EventBus de Wu Framework en Preact
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* import { createUseWuEvents } from 'wu-framework/adapters/preact';
|
|
510
|
+
* import { useState, useEffect, useRef, useCallback } from 'preact/hooks';
|
|
511
|
+
*
|
|
512
|
+
* const useWuEvents = createUseWuEvents({ useCallback, useEffect, useRef });
|
|
513
|
+
*
|
|
514
|
+
* function MyComponent() {
|
|
515
|
+
* const { emit, on } = useWuEvents();
|
|
516
|
+
*
|
|
517
|
+
* useEffect(() => {
|
|
518
|
+
* return on('user:login', (data) => console.log(data));
|
|
519
|
+
* }, [on]);
|
|
520
|
+
* }
|
|
521
|
+
*/
|
|
522
|
+
function createUseWuEvents(hooks) {
|
|
523
|
+
const { useCallback, useEffect, useRef } = hooks;
|
|
524
|
+
|
|
525
|
+
return function useWuEvents() {
|
|
526
|
+
const subscriptionsRef = useRef([]);
|
|
527
|
+
|
|
528
|
+
const emit = useCallback((event, data, options) => {
|
|
529
|
+
const wu = getWuInstance();
|
|
530
|
+
if (wu?.eventBus) {
|
|
531
|
+
wu.eventBus.emit(event, data, options);
|
|
532
|
+
}
|
|
533
|
+
}, []);
|
|
534
|
+
|
|
535
|
+
const on = useCallback((event, callback) => {
|
|
536
|
+
const wu = getWuInstance();
|
|
537
|
+
if (wu?.eventBus) {
|
|
538
|
+
const unsubscribe = wu.eventBus.on(event, callback);
|
|
539
|
+
subscriptionsRef.current.push(unsubscribe);
|
|
540
|
+
return unsubscribe;
|
|
541
|
+
}
|
|
542
|
+
return () => {};
|
|
543
|
+
}, []);
|
|
544
|
+
|
|
545
|
+
const once = useCallback((event, callback) => {
|
|
546
|
+
const wu = getWuInstance();
|
|
547
|
+
if (wu?.eventBus) {
|
|
548
|
+
return wu.eventBus.once(event, callback);
|
|
549
|
+
}
|
|
550
|
+
return () => {};
|
|
551
|
+
}, []);
|
|
552
|
+
|
|
553
|
+
useEffect(() => {
|
|
554
|
+
return () => {
|
|
555
|
+
subscriptionsRef.current.forEach(unsub => unsub());
|
|
556
|
+
subscriptionsRef.current = [];
|
|
557
|
+
};
|
|
558
|
+
}, []);
|
|
559
|
+
|
|
560
|
+
return { emit, on, once };
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Hook para usar el Store de Wu Framework en Preact
|
|
566
|
+
*
|
|
567
|
+
* @example
|
|
568
|
+
* const useWuStore = createUseWuStore({ useState, useCallback, useEffect });
|
|
569
|
+
*
|
|
570
|
+
* function MyComponent() {
|
|
571
|
+
* const { state, setState, getState } = useWuStore('user');
|
|
572
|
+
* // ...
|
|
573
|
+
* }
|
|
574
|
+
*/
|
|
575
|
+
function createUseWuStore(hooks) {
|
|
576
|
+
const { useState, useCallback, useEffect } = hooks;
|
|
577
|
+
|
|
578
|
+
return function useWuStore(namespace = '') {
|
|
579
|
+
const [state, setLocalState] = useState(() => {
|
|
580
|
+
const wu = getWuInstance();
|
|
581
|
+
return wu?.store?.get(namespace) || null;
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
const setState = useCallback((path, value) => {
|
|
585
|
+
const wu = getWuInstance();
|
|
586
|
+
if (wu?.store) {
|
|
587
|
+
const fullPath = namespace ? `${namespace}.${path}` : path;
|
|
588
|
+
wu.store.set(fullPath, value);
|
|
589
|
+
}
|
|
590
|
+
}, [namespace]);
|
|
591
|
+
|
|
592
|
+
const getState = useCallback((path = '') => {
|
|
593
|
+
const wu = getWuInstance();
|
|
594
|
+
if (wu?.store) {
|
|
595
|
+
const fullPath = namespace ? (path ? `${namespace}.${path}` : namespace) : path;
|
|
596
|
+
return wu.store.get(fullPath);
|
|
597
|
+
}
|
|
598
|
+
return null;
|
|
599
|
+
}, [namespace]);
|
|
600
|
+
|
|
601
|
+
useEffect(() => {
|
|
602
|
+
const wu = getWuInstance();
|
|
603
|
+
if (!wu?.store) return;
|
|
604
|
+
|
|
605
|
+
const pattern = namespace ? `${namespace}.*` : '*';
|
|
606
|
+
const unsubscribe = wu.store.on(pattern, () => {
|
|
607
|
+
setLocalState(wu.store.get(namespace));
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
return unsubscribe;
|
|
611
|
+
}, [namespace]);
|
|
612
|
+
|
|
613
|
+
return { state, setState, getState };
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Helper interno para montar slot sin hooks
|
|
618
|
+
async function mountSlot(container, name, url) {
|
|
619
|
+
try {
|
|
620
|
+
const wu = getWuInstance();
|
|
621
|
+
if (!wu) return;
|
|
622
|
+
|
|
623
|
+
const containerId = `wu-slot-${name}-${Date.now()}`;
|
|
624
|
+
const innerContainer = document.createElement('div');
|
|
625
|
+
innerContainer.id = containerId;
|
|
626
|
+
innerContainer.style.cssText = 'width: 100%; height: 100%;';
|
|
627
|
+
|
|
628
|
+
container.innerHTML = '';
|
|
629
|
+
container.appendChild(innerContainer);
|
|
630
|
+
|
|
631
|
+
const app = wu.app(name, {
|
|
632
|
+
url,
|
|
633
|
+
container: `#${containerId}`,
|
|
634
|
+
autoInit: true
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
await app.mount();
|
|
638
|
+
} catch (err) {
|
|
639
|
+
container.innerHTML = `<div style="color: red;">Error: ${err.message}</div>`;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// ============================================
|
|
644
|
+
// AI INTEGRATION
|
|
645
|
+
// ============================================
|
|
646
|
+
export { createUseWuAI } from './ai.js';
|
|
647
|
+
import { createUseWuAI } from './ai.js';
|
|
648
|
+
|
|
649
|
+
// API pública del adapter
|
|
650
|
+
export const wuPreact = {
|
|
651
|
+
register,
|
|
652
|
+
registerCompat,
|
|
653
|
+
createWuSlot,
|
|
654
|
+
createUseWuEvents,
|
|
655
|
+
createUseWuStore,
|
|
656
|
+
createUseWuAI,
|
|
657
|
+
getWuInstance,
|
|
658
|
+
waitForWu
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
export default wuPreact;
|