wu-framework 1.1.15 → 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.
- package/LICENSE +39 -39
- package/README.md +408 -408
- package/dist/wu-framework.cjs.js.map +1 -1
- package/dist/wu-framework.dev.js +15151 -15151
- package/dist/wu-framework.dev.js.map +1 -1
- package/dist/wu-framework.esm.js.map +1 -1
- package/dist/wu-framework.umd.js.map +1 -1
- package/integrations/astro/README.md +127 -127
- package/integrations/astro/WuApp.astro +63 -63
- package/integrations/astro/WuShell.astro +39 -39
- package/integrations/astro/index.js +68 -68
- package/integrations/astro/package.json +38 -38
- package/integrations/astro/types.d.ts +53 -53
- package/package.json +161 -161
- package/src/adapters/angular/ai.js +30 -30
- package/src/adapters/angular/index.d.ts +154 -154
- package/src/adapters/angular/index.js +932 -932
- package/src/adapters/angular.d.ts +3 -3
- package/src/adapters/angular.js +3 -3
- package/src/adapters/index.js +168 -168
- package/src/adapters/lit/ai.js +20 -20
- package/src/adapters/lit/index.d.ts +120 -120
- package/src/adapters/lit/index.js +721 -721
- package/src/adapters/lit.d.ts +3 -3
- package/src/adapters/lit.js +3 -3
- package/src/adapters/preact/ai.js +33 -33
- package/src/adapters/preact/index.d.ts +108 -108
- package/src/adapters/preact/index.js +661 -661
- package/src/adapters/preact.d.ts +3 -3
- package/src/adapters/preact.js +3 -3
- package/src/adapters/react/index.js +48 -54
- package/src/adapters/react.d.ts +3 -3
- package/src/adapters/react.js +3 -3
- package/src/adapters/shared.js +64 -64
- package/src/adapters/solid/ai.js +32 -32
- package/src/adapters/solid/index.d.ts +101 -101
- package/src/adapters/solid/index.js +586 -586
- package/src/adapters/solid.d.ts +3 -3
- package/src/adapters/solid.js +3 -3
- package/src/adapters/svelte/ai.js +31 -31
- package/src/adapters/svelte/index.d.ts +166 -166
- package/src/adapters/svelte/index.js +798 -798
- package/src/adapters/svelte.d.ts +3 -3
- package/src/adapters/svelte.js +3 -3
- package/src/adapters/vanilla/ai.js +30 -30
- package/src/adapters/vanilla/index.d.ts +179 -179
- package/src/adapters/vanilla/index.js +785 -785
- package/src/adapters/vanilla.d.ts +3 -3
- package/src/adapters/vanilla.js +3 -3
- package/src/adapters/vue/ai.js +52 -52
- package/src/adapters/vue/index.d.ts +299 -299
- package/src/adapters/vue/index.js +610 -610
- package/src/adapters/vue.d.ts +3 -3
- package/src/adapters/vue.js +3 -3
- package/src/ai/wu-ai-actions.js +261 -261
- package/src/ai/wu-ai-agent.js +546 -546
- package/src/ai/wu-ai-browser-primitives.js +354 -354
- package/src/ai/wu-ai-browser.js +380 -380
- package/src/ai/wu-ai-context.js +332 -332
- package/src/ai/wu-ai-conversation.js +613 -613
- package/src/ai/wu-ai-orchestrate.js +1021 -1021
- package/src/ai/wu-ai-permissions.js +381 -381
- package/src/ai/wu-ai-provider.js +700 -700
- package/src/ai/wu-ai-schema.js +225 -225
- package/src/ai/wu-ai-triggers.js +396 -396
- package/src/ai/wu-ai.js +804 -804
- package/src/core/wu-app.js +236 -236
- package/src/core/wu-cache.js +477 -477
- package/src/core/wu-core.js +1398 -1398
- package/src/core/wu-error-boundary.js +382 -382
- package/src/core/wu-event-bus.js +348 -348
- package/src/core/wu-hooks.js +350 -350
- package/src/core/wu-html-parser.js +190 -190
- package/src/core/wu-iframe-sandbox.js +328 -328
- package/src/core/wu-loader.js +272 -272
- package/src/core/wu-logger.js +134 -134
- package/src/core/wu-manifest.js +509 -509
- package/src/core/wu-mcp-bridge.js +432 -432
- package/src/core/wu-overrides.js +510 -510
- package/src/core/wu-performance.js +228 -228
- package/src/core/wu-plugin.js +348 -348
- package/src/core/wu-prefetch.js +414 -414
- package/src/core/wu-proxy-sandbox.js +476 -476
- package/src/core/wu-sandbox.js +779 -779
- package/src/core/wu-script-executor.js +113 -113
- package/src/core/wu-snapshot-sandbox.js +227 -227
- package/src/core/wu-strategies.js +256 -256
- package/src/core/wu-style-bridge.js +477 -477
- package/src/index.js +224 -224
- package/src/utils/dependency-resolver.js +327 -327
package/src/core/wu-loader.js
CHANGED
|
@@ -1,273 +1,273 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🚀 WU-LOADER: SISTEMA DE CARGA DINÁMICA UNIVERSAL
|
|
3
|
-
* Carga aplicaciones y componentes sin depender del framework
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { logger } from './wu-logger.js';
|
|
7
|
-
|
|
8
|
-
export class WuLoader {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.cache = new Map();
|
|
11
|
-
this.loadingPromises = new Map();
|
|
12
|
-
|
|
13
|
-
logger.debug('[WuLoader] 📦 Dynamic loader initialized');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Cargar aplicación completa
|
|
18
|
-
* @param {string} appUrl - URL base de la aplicación
|
|
19
|
-
* @param {Object} manifest - Manifest de la aplicación
|
|
20
|
-
* @returns {string} Código JavaScript de la aplicación
|
|
21
|
-
*/
|
|
22
|
-
async loadApp(appUrl, manifest) {
|
|
23
|
-
const entryFile = manifest?.entry || 'index.js';
|
|
24
|
-
const fullUrl = `${appUrl}/${entryFile}`;
|
|
25
|
-
|
|
26
|
-
logger.debug(`[WuLoader] 📥 Loading app from: ${fullUrl}`);
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// Verificar cache
|
|
30
|
-
if (this.cache.has(fullUrl)) {
|
|
31
|
-
logger.debug(`[WuLoader] ⚡ Cache hit for: ${fullUrl}`);
|
|
32
|
-
return this.cache.get(fullUrl);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Verificar si ya está cargando
|
|
36
|
-
if (this.loadingPromises.has(fullUrl)) {
|
|
37
|
-
logger.debug(`[WuLoader] ⏳ Loading in progress for: ${fullUrl}`);
|
|
38
|
-
return await this.loadingPromises.get(fullUrl);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Crear promesa de carga
|
|
42
|
-
const loadingPromise = this.fetchCode(fullUrl);
|
|
43
|
-
this.loadingPromises.set(fullUrl, loadingPromise);
|
|
44
|
-
|
|
45
|
-
const code = await loadingPromise;
|
|
46
|
-
|
|
47
|
-
// Limpiar promesa de carga y cachear resultado
|
|
48
|
-
this.loadingPromises.delete(fullUrl);
|
|
49
|
-
this.cache.set(fullUrl, code);
|
|
50
|
-
|
|
51
|
-
logger.debug(`[WuLoader] ✅ App loaded successfully: ${fullUrl}`);
|
|
52
|
-
return code;
|
|
53
|
-
|
|
54
|
-
} catch (error) {
|
|
55
|
-
this.loadingPromises.delete(fullUrl);
|
|
56
|
-
console.error(`[WuLoader] ❌ Failed to load app: ${fullUrl}`, error);
|
|
57
|
-
throw new Error(`Failed to load app from ${fullUrl}: ${error.message}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Cargar componente específico
|
|
63
|
-
* @param {string} appUrl - URL base de la aplicación
|
|
64
|
-
* @param {string} componentPath - Ruta del componente
|
|
65
|
-
* @returns {Function} Función del componente
|
|
66
|
-
*/
|
|
67
|
-
async loadComponent(appUrl, componentPath) {
|
|
68
|
-
// Normalizar ruta del componente
|
|
69
|
-
let normalizedPath = componentPath;
|
|
70
|
-
if (normalizedPath.startsWith('./')) {
|
|
71
|
-
normalizedPath = normalizedPath.substring(2);
|
|
72
|
-
}
|
|
73
|
-
if (!normalizedPath.endsWith('.js') && !normalizedPath.endsWith('.jsx')) {
|
|
74
|
-
normalizedPath += '.js';
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const fullUrl = `${appUrl}/${normalizedPath}`;
|
|
78
|
-
|
|
79
|
-
logger.debug(`[WuLoader] 🧩 Loading component from: ${fullUrl}`);
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
// Cargar código del componente
|
|
83
|
-
const code = await this.loadCode(fullUrl);
|
|
84
|
-
|
|
85
|
-
// Crear función que retorna el componente
|
|
86
|
-
const componentFunction = new Function('require', 'module', 'exports', `
|
|
87
|
-
${code}
|
|
88
|
-
return typeof module.exports === 'function' ? module.exports :
|
|
89
|
-
typeof module.exports === 'object' && module.exports.default ? module.exports.default :
|
|
90
|
-
exports.default || exports;
|
|
91
|
-
`);
|
|
92
|
-
|
|
93
|
-
// Ejecutar y obtener el componente
|
|
94
|
-
const fakeModule = { exports: {} };
|
|
95
|
-
const fakeRequire = (name) => {
|
|
96
|
-
logger.warn(`[WuLoader] Component ${componentPath} requires ${name} - not supported yet`);
|
|
97
|
-
return {};
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const component = componentFunction(fakeRequire, fakeModule, fakeModule.exports);
|
|
101
|
-
|
|
102
|
-
logger.debug(`[WuLoader] ✅ Component loaded: ${componentPath}`);
|
|
103
|
-
return component;
|
|
104
|
-
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.error(`[WuLoader] ❌ Failed to load component: ${componentPath}`, error);
|
|
107
|
-
throw new Error(`Failed to load component ${componentPath}: ${error.message}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Cargar código con cache
|
|
113
|
-
* @param {string} url - URL del archivo
|
|
114
|
-
* @returns {string} Código JavaScript
|
|
115
|
-
*/
|
|
116
|
-
async loadCode(url) {
|
|
117
|
-
// Verificar cache
|
|
118
|
-
if (this.cache.has(url)) {
|
|
119
|
-
return this.cache.get(url);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Verificar si ya está cargando
|
|
123
|
-
if (this.loadingPromises.has(url)) {
|
|
124
|
-
return await this.loadingPromises.get(url);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Crear promesa de carga
|
|
128
|
-
const loadingPromise = this.fetchCode(url);
|
|
129
|
-
this.loadingPromises.set(url, loadingPromise);
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
const code = await loadingPromise;
|
|
133
|
-
this.loadingPromises.delete(url);
|
|
134
|
-
this.cache.set(url, code);
|
|
135
|
-
return code;
|
|
136
|
-
} catch (error) {
|
|
137
|
-
this.loadingPromises.delete(url);
|
|
138
|
-
throw error;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Realizar fetch del código
|
|
144
|
-
* @param {string} url - URL del archivo
|
|
145
|
-
* @returns {string} Código JavaScript
|
|
146
|
-
*/
|
|
147
|
-
async fetchCode(url) {
|
|
148
|
-
const response = await fetch(url, {
|
|
149
|
-
cache: 'no-cache',
|
|
150
|
-
headers: {
|
|
151
|
-
'Accept': 'application/javascript, text/javascript, */*'
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
if (!response.ok) {
|
|
156
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const code = await response.text();
|
|
160
|
-
|
|
161
|
-
if (!code.trim()) {
|
|
162
|
-
throw new Error('Empty response');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return code;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Precargar aplicaciones
|
|
170
|
-
* @param {Array} appConfigs - Configuraciones de aplicaciones
|
|
171
|
-
*/
|
|
172
|
-
async preload(appConfigs) {
|
|
173
|
-
logger.debug(`[WuLoader] 🚀 Preloading ${appConfigs.length} apps...`);
|
|
174
|
-
|
|
175
|
-
const preloadPromises = appConfigs.map(async (config) => {
|
|
176
|
-
try {
|
|
177
|
-
await this.loadApp(config.url, config.manifest);
|
|
178
|
-
logger.debug(`[WuLoader] ✅ Preloaded: ${config.name}`);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
logger.warn(`[WuLoader] ⚠️ Failed to preload ${config.name}:`, error.message);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
await Promise.allSettled(preloadPromises);
|
|
185
|
-
logger.debug(`[WuLoader] 🎉 Preload completed`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Verificar si una URL está disponible
|
|
190
|
-
* @param {string} url - URL a verificar
|
|
191
|
-
* @returns {boolean} True si está disponible
|
|
192
|
-
*/
|
|
193
|
-
async isAvailable(url) {
|
|
194
|
-
try {
|
|
195
|
-
const response = await fetch(url, { method: 'HEAD' });
|
|
196
|
-
return response.ok;
|
|
197
|
-
} catch {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Resolver dependencias de imports
|
|
204
|
-
* @param {Array} imports - Lista de imports del manifest
|
|
205
|
-
* @param {Map} availableApps - Apps disponibles
|
|
206
|
-
*/
|
|
207
|
-
async resolveDependencies(imports, availableApps) {
|
|
208
|
-
const resolved = new Map();
|
|
209
|
-
|
|
210
|
-
for (const importPath of imports || []) {
|
|
211
|
-
const [appName, componentName] = importPath.split('.');
|
|
212
|
-
|
|
213
|
-
if (!appName || !componentName) {
|
|
214
|
-
logger.warn(`[WuLoader] Invalid import format: ${importPath}`);
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const app = availableApps.get(appName);
|
|
219
|
-
if (!app) {
|
|
220
|
-
logger.warn(`[WuLoader] Import app not found: ${appName}`);
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const manifest = app.manifest;
|
|
225
|
-
const exportPath = manifest?.wu?.exports?.[componentName];
|
|
226
|
-
|
|
227
|
-
if (!exportPath) {
|
|
228
|
-
logger.warn(`[WuLoader] Export not found: ${importPath}`);
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
try {
|
|
233
|
-
const component = await this.loadComponent(app.url, exportPath);
|
|
234
|
-
resolved.set(importPath, component);
|
|
235
|
-
logger.debug(`[WuLoader] ✅ Resolved dependency: ${importPath}`);
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error(`[WuLoader] ❌ Failed to resolve: ${importPath}`, error);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return resolved;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Limpiar cache
|
|
246
|
-
* @param {string} pattern - Patrón opcional para limpiar URLs específicas
|
|
247
|
-
*/
|
|
248
|
-
clearCache(pattern) {
|
|
249
|
-
if (pattern) {
|
|
250
|
-
const regex = new RegExp(pattern);
|
|
251
|
-
for (const [url] of this.cache) {
|
|
252
|
-
if (regex.test(url)) {
|
|
253
|
-
this.cache.delete(url);
|
|
254
|
-
logger.debug(`[WuLoader] 🗑️ Cleared cache for: ${url}`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
} else {
|
|
258
|
-
this.cache.clear();
|
|
259
|
-
logger.debug(`[WuLoader] 🗑️ Cache cleared completely`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Obtener estadísticas del loader
|
|
265
|
-
*/
|
|
266
|
-
getStats() {
|
|
267
|
-
return {
|
|
268
|
-
cached: this.cache.size,
|
|
269
|
-
loading: this.loadingPromises.size,
|
|
270
|
-
cacheKeys: Array.from(this.cache.keys())
|
|
271
|
-
};
|
|
272
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 🚀 WU-LOADER: SISTEMA DE CARGA DINÁMICA UNIVERSAL
|
|
3
|
+
* Carga aplicaciones y componentes sin depender del framework
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logger } from './wu-logger.js';
|
|
7
|
+
|
|
8
|
+
export class WuLoader {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.cache = new Map();
|
|
11
|
+
this.loadingPromises = new Map();
|
|
12
|
+
|
|
13
|
+
logger.debug('[WuLoader] 📦 Dynamic loader initialized');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Cargar aplicación completa
|
|
18
|
+
* @param {string} appUrl - URL base de la aplicación
|
|
19
|
+
* @param {Object} manifest - Manifest de la aplicación
|
|
20
|
+
* @returns {string} Código JavaScript de la aplicación
|
|
21
|
+
*/
|
|
22
|
+
async loadApp(appUrl, manifest) {
|
|
23
|
+
const entryFile = manifest?.entry || 'index.js';
|
|
24
|
+
const fullUrl = `${appUrl}/${entryFile}`;
|
|
25
|
+
|
|
26
|
+
logger.debug(`[WuLoader] 📥 Loading app from: ${fullUrl}`);
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// Verificar cache
|
|
30
|
+
if (this.cache.has(fullUrl)) {
|
|
31
|
+
logger.debug(`[WuLoader] ⚡ Cache hit for: ${fullUrl}`);
|
|
32
|
+
return this.cache.get(fullUrl);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Verificar si ya está cargando
|
|
36
|
+
if (this.loadingPromises.has(fullUrl)) {
|
|
37
|
+
logger.debug(`[WuLoader] ⏳ Loading in progress for: ${fullUrl}`);
|
|
38
|
+
return await this.loadingPromises.get(fullUrl);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Crear promesa de carga
|
|
42
|
+
const loadingPromise = this.fetchCode(fullUrl);
|
|
43
|
+
this.loadingPromises.set(fullUrl, loadingPromise);
|
|
44
|
+
|
|
45
|
+
const code = await loadingPromise;
|
|
46
|
+
|
|
47
|
+
// Limpiar promesa de carga y cachear resultado
|
|
48
|
+
this.loadingPromises.delete(fullUrl);
|
|
49
|
+
this.cache.set(fullUrl, code);
|
|
50
|
+
|
|
51
|
+
logger.debug(`[WuLoader] ✅ App loaded successfully: ${fullUrl}`);
|
|
52
|
+
return code;
|
|
53
|
+
|
|
54
|
+
} catch (error) {
|
|
55
|
+
this.loadingPromises.delete(fullUrl);
|
|
56
|
+
console.error(`[WuLoader] ❌ Failed to load app: ${fullUrl}`, error);
|
|
57
|
+
throw new Error(`Failed to load app from ${fullUrl}: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Cargar componente específico
|
|
63
|
+
* @param {string} appUrl - URL base de la aplicación
|
|
64
|
+
* @param {string} componentPath - Ruta del componente
|
|
65
|
+
* @returns {Function} Función del componente
|
|
66
|
+
*/
|
|
67
|
+
async loadComponent(appUrl, componentPath) {
|
|
68
|
+
// Normalizar ruta del componente
|
|
69
|
+
let normalizedPath = componentPath;
|
|
70
|
+
if (normalizedPath.startsWith('./')) {
|
|
71
|
+
normalizedPath = normalizedPath.substring(2);
|
|
72
|
+
}
|
|
73
|
+
if (!normalizedPath.endsWith('.js') && !normalizedPath.endsWith('.jsx')) {
|
|
74
|
+
normalizedPath += '.js';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const fullUrl = `${appUrl}/${normalizedPath}`;
|
|
78
|
+
|
|
79
|
+
logger.debug(`[WuLoader] 🧩 Loading component from: ${fullUrl}`);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Cargar código del componente
|
|
83
|
+
const code = await this.loadCode(fullUrl);
|
|
84
|
+
|
|
85
|
+
// Crear función que retorna el componente
|
|
86
|
+
const componentFunction = new Function('require', 'module', 'exports', `
|
|
87
|
+
${code}
|
|
88
|
+
return typeof module.exports === 'function' ? module.exports :
|
|
89
|
+
typeof module.exports === 'object' && module.exports.default ? module.exports.default :
|
|
90
|
+
exports.default || exports;
|
|
91
|
+
`);
|
|
92
|
+
|
|
93
|
+
// Ejecutar y obtener el componente
|
|
94
|
+
const fakeModule = { exports: {} };
|
|
95
|
+
const fakeRequire = (name) => {
|
|
96
|
+
logger.warn(`[WuLoader] Component ${componentPath} requires ${name} - not supported yet`);
|
|
97
|
+
return {};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const component = componentFunction(fakeRequire, fakeModule, fakeModule.exports);
|
|
101
|
+
|
|
102
|
+
logger.debug(`[WuLoader] ✅ Component loaded: ${componentPath}`);
|
|
103
|
+
return component;
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(`[WuLoader] ❌ Failed to load component: ${componentPath}`, error);
|
|
107
|
+
throw new Error(`Failed to load component ${componentPath}: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Cargar código con cache
|
|
113
|
+
* @param {string} url - URL del archivo
|
|
114
|
+
* @returns {string} Código JavaScript
|
|
115
|
+
*/
|
|
116
|
+
async loadCode(url) {
|
|
117
|
+
// Verificar cache
|
|
118
|
+
if (this.cache.has(url)) {
|
|
119
|
+
return this.cache.get(url);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Verificar si ya está cargando
|
|
123
|
+
if (this.loadingPromises.has(url)) {
|
|
124
|
+
return await this.loadingPromises.get(url);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Crear promesa de carga
|
|
128
|
+
const loadingPromise = this.fetchCode(url);
|
|
129
|
+
this.loadingPromises.set(url, loadingPromise);
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const code = await loadingPromise;
|
|
133
|
+
this.loadingPromises.delete(url);
|
|
134
|
+
this.cache.set(url, code);
|
|
135
|
+
return code;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
this.loadingPromises.delete(url);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Realizar fetch del código
|
|
144
|
+
* @param {string} url - URL del archivo
|
|
145
|
+
* @returns {string} Código JavaScript
|
|
146
|
+
*/
|
|
147
|
+
async fetchCode(url) {
|
|
148
|
+
const response = await fetch(url, {
|
|
149
|
+
cache: 'no-cache',
|
|
150
|
+
headers: {
|
|
151
|
+
'Accept': 'application/javascript, text/javascript, */*'
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const code = await response.text();
|
|
160
|
+
|
|
161
|
+
if (!code.trim()) {
|
|
162
|
+
throw new Error('Empty response');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return code;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Precargar aplicaciones
|
|
170
|
+
* @param {Array} appConfigs - Configuraciones de aplicaciones
|
|
171
|
+
*/
|
|
172
|
+
async preload(appConfigs) {
|
|
173
|
+
logger.debug(`[WuLoader] 🚀 Preloading ${appConfigs.length} apps...`);
|
|
174
|
+
|
|
175
|
+
const preloadPromises = appConfigs.map(async (config) => {
|
|
176
|
+
try {
|
|
177
|
+
await this.loadApp(config.url, config.manifest);
|
|
178
|
+
logger.debug(`[WuLoader] ✅ Preloaded: ${config.name}`);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
logger.warn(`[WuLoader] ⚠️ Failed to preload ${config.name}:`, error.message);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
await Promise.allSettled(preloadPromises);
|
|
185
|
+
logger.debug(`[WuLoader] 🎉 Preload completed`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Verificar si una URL está disponible
|
|
190
|
+
* @param {string} url - URL a verificar
|
|
191
|
+
* @returns {boolean} True si está disponible
|
|
192
|
+
*/
|
|
193
|
+
async isAvailable(url) {
|
|
194
|
+
try {
|
|
195
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
196
|
+
return response.ok;
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Resolver dependencias de imports
|
|
204
|
+
* @param {Array} imports - Lista de imports del manifest
|
|
205
|
+
* @param {Map} availableApps - Apps disponibles
|
|
206
|
+
*/
|
|
207
|
+
async resolveDependencies(imports, availableApps) {
|
|
208
|
+
const resolved = new Map();
|
|
209
|
+
|
|
210
|
+
for (const importPath of imports || []) {
|
|
211
|
+
const [appName, componentName] = importPath.split('.');
|
|
212
|
+
|
|
213
|
+
if (!appName || !componentName) {
|
|
214
|
+
logger.warn(`[WuLoader] Invalid import format: ${importPath}`);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const app = availableApps.get(appName);
|
|
219
|
+
if (!app) {
|
|
220
|
+
logger.warn(`[WuLoader] Import app not found: ${appName}`);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const manifest = app.manifest;
|
|
225
|
+
const exportPath = manifest?.wu?.exports?.[componentName];
|
|
226
|
+
|
|
227
|
+
if (!exportPath) {
|
|
228
|
+
logger.warn(`[WuLoader] Export not found: ${importPath}`);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const component = await this.loadComponent(app.url, exportPath);
|
|
234
|
+
resolved.set(importPath, component);
|
|
235
|
+
logger.debug(`[WuLoader] ✅ Resolved dependency: ${importPath}`);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error(`[WuLoader] ❌ Failed to resolve: ${importPath}`, error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return resolved;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Limpiar cache
|
|
246
|
+
* @param {string} pattern - Patrón opcional para limpiar URLs específicas
|
|
247
|
+
*/
|
|
248
|
+
clearCache(pattern) {
|
|
249
|
+
if (pattern) {
|
|
250
|
+
const regex = new RegExp(pattern);
|
|
251
|
+
for (const [url] of this.cache) {
|
|
252
|
+
if (regex.test(url)) {
|
|
253
|
+
this.cache.delete(url);
|
|
254
|
+
logger.debug(`[WuLoader] 🗑️ Cleared cache for: ${url}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
this.cache.clear();
|
|
259
|
+
logger.debug(`[WuLoader] 🗑️ Cache cleared completely`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Obtener estadísticas del loader
|
|
265
|
+
*/
|
|
266
|
+
getStats() {
|
|
267
|
+
return {
|
|
268
|
+
cached: this.cache.size,
|
|
269
|
+
loading: this.loadingPromises.size,
|
|
270
|
+
cacheKeys: Array.from(this.cache.keys())
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
273
|
}
|