wu-framework 1.0.3 → 1.0.5
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/package.json +1 -1
- package/src/core/wu-cache.js +33 -3
- package/src/core/wu-core.js +97 -43
- package/src/core/wu-logger.js +18 -2
- package/src/core/wu-registry.js +9 -92
- package/src/index.js +15 -1
- package/src/api/wu-simple.js +0 -316
package/package.json
CHANGED
package/src/core/wu-cache.js
CHANGED
|
@@ -102,7 +102,11 @@ export class WuCache {
|
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
// Verificar si necesitamos hacer espacio
|
|
105
|
-
this.ensureSpace(entry.size);
|
|
105
|
+
const hasSpace = this.ensureSpace(entry.size);
|
|
106
|
+
if (hasSpace === false) {
|
|
107
|
+
console.warn(`[WuCache] ⚠️ Cannot cache item: ${key} (too large)`);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
106
110
|
|
|
107
111
|
// Guardar en memoria
|
|
108
112
|
this.memoryCache.set(key, entry);
|
|
@@ -194,9 +198,28 @@ export class WuCache {
|
|
|
194
198
|
ensureSpace(neededSize) {
|
|
195
199
|
const maxSizeBytes = this.config.maxSize * 1024 * 1024;
|
|
196
200
|
|
|
201
|
+
// 🛡️ FIX: Validar que el item no sea más grande que el máximo permitido
|
|
202
|
+
if (neededSize > maxSizeBytes) {
|
|
203
|
+
console.warn(`[WuCache] ⚠️ Item size (${neededSize}) exceeds max cache size (${maxSizeBytes}). Skipping.`);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 🛡️ FIX: Límite de iteraciones para evitar loop infinito
|
|
208
|
+
const maxIterations = this.config.maxItems + 10;
|
|
209
|
+
let iterations = 0;
|
|
210
|
+
|
|
197
211
|
// Verificar si necesitamos limpiar
|
|
198
|
-
while (this.stats.size + neededSize > maxSizeBytes ||
|
|
199
|
-
this.memoryCache.size >= this.config.maxItems)
|
|
212
|
+
while ((this.stats.size + neededSize > maxSizeBytes ||
|
|
213
|
+
this.memoryCache.size >= this.config.maxItems) &&
|
|
214
|
+
iterations < maxIterations) {
|
|
215
|
+
|
|
216
|
+
iterations++;
|
|
217
|
+
|
|
218
|
+
// 🛡️ FIX: Si el cache está vacío pero aún no hay espacio, salir
|
|
219
|
+
if (this.memoryCache.size === 0) {
|
|
220
|
+
console.warn('[WuCache] ⚠️ Cache empty but still no space. Breaking loop.');
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
200
223
|
|
|
201
224
|
// Encontrar entrada menos recientemente usada (LRU)
|
|
202
225
|
let oldestKey = null;
|
|
@@ -217,6 +240,13 @@ export class WuCache {
|
|
|
217
240
|
break;
|
|
218
241
|
}
|
|
219
242
|
}
|
|
243
|
+
|
|
244
|
+
// 🛡️ FIX: Log si alcanzamos el límite de iteraciones
|
|
245
|
+
if (iterations >= maxIterations) {
|
|
246
|
+
console.error(`[WuCache] 🚨 Max eviction iterations reached (${maxIterations}). Possible infinite loop prevented.`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return true;
|
|
220
250
|
}
|
|
221
251
|
|
|
222
252
|
/**
|
package/src/core/wu-core.js
CHANGED
|
@@ -104,56 +104,79 @@ export class WuCore {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
* 🔍 SMART MUTATION OBSERVER:
|
|
107
|
+
* 🔍 SMART MUTATION OBSERVER: Observa SOLO los contenedores de apps montadas
|
|
108
|
+
* FIX: Ya no observa todo document.body (memory leak)
|
|
108
109
|
*/
|
|
109
110
|
initializeMutationObserver() {
|
|
110
|
-
if (!window.MutationObserver) return;
|
|
111
|
+
if (!window.MutationObserver) return;
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
// Map para trackear observers por contenedor (evita memory leak)
|
|
114
|
+
this.healthState.containerObservers = new Map();
|
|
115
|
+
|
|
116
|
+
// Callback compartido para todos los observers
|
|
117
|
+
this.healthState.mutationCallback = (mutations, observer) => {
|
|
118
|
+
let affectedAppName = null;
|
|
114
119
|
|
|
115
120
|
for (const mutation of mutations) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
if (node === mounted.container) {
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
121
|
+
if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
|
|
122
|
+
// Encontrar qué app fue afectada
|
|
123
|
+
for (const [appName, mounted] of this.mounted) {
|
|
124
|
+
const container = mounted.hostContainer || mounted.container;
|
|
125
|
+
if (mutation.target === container ||
|
|
126
|
+
mutation.target.contains?.(container)) {
|
|
127
|
+
affectedAppName = appName;
|
|
128
|
+
break;
|
|
130
129
|
}
|
|
131
|
-
return false;
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
if (affectedApps) {
|
|
135
|
-
shouldCheckHealth = true;
|
|
136
|
-
break;
|
|
137
130
|
}
|
|
138
131
|
}
|
|
132
|
+
if (affectedAppName) break;
|
|
139
133
|
}
|
|
140
134
|
|
|
141
|
-
|
|
142
|
-
if (shouldCheckHealth) {
|
|
135
|
+
if (affectedAppName) {
|
|
143
136
|
clearTimeout(this.healthState.mutationCheckTimeout);
|
|
144
137
|
this.healthState.mutationCheckTimeout = setTimeout(() => {
|
|
145
138
|
this.performHealthCheck();
|
|
146
|
-
}, 1000);
|
|
139
|
+
}, 1000);
|
|
147
140
|
}
|
|
148
|
-
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
logger.wuDebug('🔍 MutationObserver system initialized (lazy per-container)');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 🔗 Observar contenedor específico cuando se monta una app
|
|
148
|
+
*/
|
|
149
|
+
observeContainer(appName, container) {
|
|
150
|
+
if (!this.healthState.containerObservers || !container) return;
|
|
151
|
+
|
|
152
|
+
// No observar si ya existe
|
|
153
|
+
if (this.healthState.containerObservers.has(appName)) return;
|
|
149
154
|
|
|
150
|
-
|
|
151
|
-
|
|
155
|
+
const observer = new MutationObserver(this.healthState.mutationCallback);
|
|
156
|
+
|
|
157
|
+
// Observar solo el contenedor padre directo (no subtree profundo)
|
|
158
|
+
const parentToObserve = container.parentElement || container;
|
|
159
|
+
observer.observe(parentToObserve, {
|
|
152
160
|
childList: true,
|
|
153
|
-
subtree:
|
|
161
|
+
subtree: false // ✅ Solo hijos directos, no todo el árbol
|
|
154
162
|
});
|
|
155
163
|
|
|
156
|
-
|
|
164
|
+
this.healthState.containerObservers.set(appName, observer);
|
|
165
|
+
logger.wuDebug(`🔍 Observing container for ${appName}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 🔓 Dejar de observar contenedor cuando se desmonta
|
|
170
|
+
*/
|
|
171
|
+
unobserveContainer(appName) {
|
|
172
|
+
if (!this.healthState.containerObservers) return;
|
|
173
|
+
|
|
174
|
+
const observer = this.healthState.containerObservers.get(appName);
|
|
175
|
+
if (observer) {
|
|
176
|
+
observer.disconnect();
|
|
177
|
+
this.healthState.containerObservers.delete(appName);
|
|
178
|
+
logger.wuDebug(`🔓 Stopped observing container for ${appName}`);
|
|
179
|
+
}
|
|
157
180
|
}
|
|
158
181
|
|
|
159
182
|
/**
|
|
@@ -606,10 +629,14 @@ export class WuCore {
|
|
|
606
629
|
poolSandbox,
|
|
607
630
|
lifecycle,
|
|
608
631
|
container: sandbox.container,
|
|
632
|
+
hostContainer: container,
|
|
609
633
|
timestamp: Date.now(),
|
|
610
634
|
state: 'stable'
|
|
611
635
|
});
|
|
612
636
|
|
|
637
|
+
// 🔍 Observar contenedor para health monitoring (sin memory leak)
|
|
638
|
+
this.observeContainer(appName, container);
|
|
639
|
+
|
|
613
640
|
// ⚡ End performance measurement
|
|
614
641
|
const mountTime = this.performance.endMeasure('mount', appName);
|
|
615
642
|
|
|
@@ -1017,6 +1044,7 @@ export class WuCore {
|
|
|
1017
1044
|
/**
|
|
1018
1045
|
* 📦 MODULE LOADER: Advanced registration patterns
|
|
1019
1046
|
* Handles asynchronous registration with timing synchronization
|
|
1047
|
+
* FIX: Verifica que definitions tenga el lifecycle después de cargar
|
|
1020
1048
|
*/
|
|
1021
1049
|
async moduleLoader(moduleUrl, appName) {
|
|
1022
1050
|
// ✅ Check if already registered
|
|
@@ -1027,16 +1055,37 @@ export class WuCore {
|
|
|
1027
1055
|
|
|
1028
1056
|
console.log(`[Wu] 📡 Using event-based registration for ${appName}`);
|
|
1029
1057
|
|
|
1030
|
-
//
|
|
1031
|
-
|
|
1058
|
+
// 🚀 Load module first
|
|
1059
|
+
try {
|
|
1060
|
+
await import(/* @vite-ignore */ moduleUrl);
|
|
1061
|
+
} catch (loadError) {
|
|
1062
|
+
console.error(`[Wu] ❌ Failed to import module ${moduleUrl}:`, loadError);
|
|
1063
|
+
throw loadError;
|
|
1064
|
+
}
|
|
1032
1065
|
|
|
1033
|
-
//
|
|
1034
|
-
const
|
|
1066
|
+
// 🛡️ FIX: Esperar a que wu.define() se ejecute con verificación real
|
|
1067
|
+
const maxWaitTime = 10000; // 10 segundos
|
|
1068
|
+
const checkInterval = 50; // Verificar cada 50ms
|
|
1069
|
+
const startTime = Date.now();
|
|
1070
|
+
|
|
1071
|
+
while (!this.definitions.has(appName)) {
|
|
1072
|
+
const elapsed = Date.now() - startTime;
|
|
1073
|
+
|
|
1074
|
+
if (elapsed >= maxWaitTime) {
|
|
1075
|
+
throw new Error(
|
|
1076
|
+
`App '${appName}' module loaded but wu.define() was not called within ${maxWaitTime}ms.\n\n` +
|
|
1077
|
+
`Make sure your module calls:\n` +
|
|
1078
|
+
` wu.define('${appName}', { mount, unmount })\n\n` +
|
|
1079
|
+
`Or using window.wu:\n` +
|
|
1080
|
+
` window.wu.define('${appName}', { mount, unmount })`
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1035
1083
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1084
|
+
// Esperar un poco antes de verificar de nuevo
|
|
1085
|
+
await new Promise(resolve => setTimeout(resolve, checkInterval));
|
|
1086
|
+
}
|
|
1038
1087
|
|
|
1039
|
-
console.log(`[Wu] ✅ App ${appName} loaded and registered
|
|
1088
|
+
console.log(`[Wu] ✅ App ${appName} loaded and registered (verified in definitions)`);
|
|
1040
1089
|
}
|
|
1041
1090
|
|
|
1042
1091
|
/**
|
|
@@ -1080,6 +1129,9 @@ export class WuCore {
|
|
|
1080
1129
|
this.sandboxPool.release(appName);
|
|
1081
1130
|
}
|
|
1082
1131
|
|
|
1132
|
+
// 🔓 Dejar de observar contenedor (evita memory leak)
|
|
1133
|
+
this.unobserveContainer(appName);
|
|
1134
|
+
|
|
1083
1135
|
// Remover del registro de montadas
|
|
1084
1136
|
this.mounted.delete(appName);
|
|
1085
1137
|
|
|
@@ -1243,10 +1295,12 @@ export class WuCore {
|
|
|
1243
1295
|
this.healthState.monitor = null;
|
|
1244
1296
|
}
|
|
1245
1297
|
|
|
1246
|
-
// Limpiar
|
|
1247
|
-
if (this.healthState.
|
|
1248
|
-
this.healthState.
|
|
1249
|
-
|
|
1298
|
+
// Limpiar todos los MutationObservers por contenedor
|
|
1299
|
+
if (this.healthState.containerObservers) {
|
|
1300
|
+
for (const [appName, observer] of this.healthState.containerObservers) {
|
|
1301
|
+
observer.disconnect();
|
|
1302
|
+
}
|
|
1303
|
+
this.healthState.containerObservers.clear();
|
|
1250
1304
|
}
|
|
1251
1305
|
|
|
1252
1306
|
// Limpiar timeouts pendientes
|
package/src/core/wu-logger.js
CHANGED
|
@@ -7,7 +7,8 @@ export class WuLogger {
|
|
|
7
7
|
constructor() {
|
|
8
8
|
// Detectar entorno automáticamente
|
|
9
9
|
this.isDevelopment = this.detectEnvironment();
|
|
10
|
-
|
|
10
|
+
// En desarrollo: warn (menos ruido), en producción: error
|
|
11
|
+
this.logLevel = this.isDevelopment ? 'warn' : 'error';
|
|
11
12
|
|
|
12
13
|
this.levels = {
|
|
13
14
|
debug: 0,
|
|
@@ -116,4 +117,19 @@ export const wuLog = {
|
|
|
116
117
|
info: (...args) => logger.wuInfo(...args),
|
|
117
118
|
warn: (...args) => logger.wuWarn(...args),
|
|
118
119
|
error: (...args) => logger.wuError(...args)
|
|
119
|
-
};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 🔇 Silenciar todos los logs de Wu Framework
|
|
124
|
+
* Útil en producción para eliminar todo el ruido
|
|
125
|
+
*/
|
|
126
|
+
export function silenceAllLogs() {
|
|
127
|
+
logger.setLevel('silent');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 🔊 Restaurar logs (nivel debug)
|
|
132
|
+
*/
|
|
133
|
+
export function enableAllLogs() {
|
|
134
|
+
logger.setLevel('debug');
|
|
135
|
+
}
|
package/src/core/wu-registry.js
CHANGED
|
@@ -1,52 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 🔔 WU-REGISTRY:
|
|
3
|
-
*
|
|
4
|
-
* Reemplaza el polling con Custom Events para mejor performance
|
|
2
|
+
* 🔔 WU-REGISTRY: APP REGISTRATION TRACKER
|
|
3
|
+
* Simplificado - solo trackea apps registradas
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
6
|
export class WuRegistry {
|
|
8
7
|
constructor() {
|
|
9
8
|
this.registeredApps = new Set();
|
|
10
|
-
this.waitingPromises = new Map();
|
|
11
|
-
|
|
12
|
-
// Event listeners para registro
|
|
13
|
-
this.setupEventListeners();
|
|
14
|
-
|
|
15
|
-
console.log('[WuRegistry] 🔔 Event-based registration system initialized');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 📡 SETUP EVENT LISTENERS
|
|
20
|
-
*/
|
|
21
|
-
setupEventListeners() {
|
|
22
|
-
// Escuchar eventos de registro de apps
|
|
23
|
-
window.addEventListener('wu:app:ready', (event) => {
|
|
24
|
-
const { appName } = event.detail;
|
|
25
|
-
console.log(`[WuRegistry] ✅ App registered via event: ${appName}`);
|
|
26
|
-
|
|
27
|
-
this.registeredApps.add(appName);
|
|
28
|
-
|
|
29
|
-
// Resolver promesas pendientes
|
|
30
|
-
if (this.waitingPromises.has(appName)) {
|
|
31
|
-
const { resolve } = this.waitingPromises.get(appName);
|
|
32
|
-
resolve();
|
|
33
|
-
this.waitingPromises.delete(appName);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// API para que apps notifiquen que están listas (se agrega a window.wu cuando exista)
|
|
38
|
-
// No crear window.wu aquí - eso lo hace index.js con la instancia completa
|
|
39
9
|
this._setupNotifyReady();
|
|
40
10
|
}
|
|
41
11
|
|
|
42
12
|
/**
|
|
43
|
-
* 🔔 Setup notifyReady API
|
|
13
|
+
* 🔔 Setup notifyReady API en window.wu
|
|
44
14
|
*/
|
|
45
15
|
_setupNotifyReady() {
|
|
46
16
|
const setupFn = () => {
|
|
47
17
|
if (window.wu && !window.wu.notifyReady) {
|
|
48
18
|
window.wu.notifyReady = (appName) => {
|
|
49
|
-
console.log(`[WuRegistry] 📢 App ${appName} called notifyReady()`);
|
|
50
19
|
const event = new CustomEvent('wu:app:ready', {
|
|
51
20
|
detail: { appName, timestamp: Date.now() }
|
|
52
21
|
});
|
|
@@ -55,89 +24,37 @@ export class WuRegistry {
|
|
|
55
24
|
}
|
|
56
25
|
};
|
|
57
26
|
|
|
58
|
-
// Intentar setup inmediato
|
|
59
27
|
setupFn();
|
|
60
|
-
|
|
61
|
-
// Si window.wu no existe aún, esperar un tick
|
|
62
28
|
if (!window.wu) {
|
|
63
29
|
queueMicrotask(setupFn);
|
|
64
30
|
}
|
|
65
31
|
}
|
|
66
32
|
|
|
67
33
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @param {string} appName - Nombre de la app
|
|
70
|
-
* @param {number} timeout - Timeout en ms (default: 10000)
|
|
71
|
-
* @returns {Promise}
|
|
34
|
+
* ✅ MARK AS REGISTERED
|
|
72
35
|
*/
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (this.registeredApps.has(appName)) {
|
|
76
|
-
console.log(`[WuRegistry] ⚡ App ${appName} already registered`);
|
|
77
|
-
return Promise.resolve();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log(`[WuRegistry] ⏳ Waiting for app ${appName} to register...`);
|
|
81
|
-
|
|
82
|
-
return new Promise((resolve, reject) => {
|
|
83
|
-
// Guardar promesa
|
|
84
|
-
this.waitingPromises.set(appName, { resolve, reject });
|
|
85
|
-
|
|
86
|
-
// Timeout
|
|
87
|
-
const timeoutId = setTimeout(() => {
|
|
88
|
-
if (this.waitingPromises.has(appName)) {
|
|
89
|
-
this.waitingPromises.delete(appName);
|
|
90
|
-
|
|
91
|
-
const error = new Error(
|
|
92
|
-
`App '${appName}' failed to register within ${timeout}ms.\n\n` +
|
|
93
|
-
`Possible causes:\n` +
|
|
94
|
-
` - Module failed to load\n` +
|
|
95
|
-
` - wu.define() was not called\n` +
|
|
96
|
-
` - Check browser console for import errors\n\n` +
|
|
97
|
-
`Make sure your app calls:\n` +
|
|
98
|
-
` wu.define('${appName}', { mount, unmount })`
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
reject(error);
|
|
102
|
-
}
|
|
103
|
-
}, timeout);
|
|
104
|
-
|
|
105
|
-
// Limpiar timeout cuando se resuelva
|
|
106
|
-
this.waitingPromises.get(appName).timeoutId = timeoutId;
|
|
107
|
-
});
|
|
36
|
+
markAsRegistered(appName) {
|
|
37
|
+
this.registeredApps.add(appName);
|
|
108
38
|
}
|
|
109
39
|
|
|
110
40
|
/**
|
|
111
|
-
*
|
|
112
|
-
* @param {string} appName
|
|
41
|
+
* ❓ IS REGISTERED
|
|
113
42
|
*/
|
|
114
|
-
|
|
115
|
-
this.registeredApps.
|
|
116
|
-
console.log(`[WuRegistry] ✅ App ${appName} marked as registered`);
|
|
43
|
+
isRegistered(appName) {
|
|
44
|
+
return this.registeredApps.has(appName);
|
|
117
45
|
}
|
|
118
46
|
|
|
119
47
|
/**
|
|
120
48
|
* ❌ UNREGISTER APP
|
|
121
|
-
* @param {string} appName
|
|
122
49
|
*/
|
|
123
50
|
unregister(appName) {
|
|
124
51
|
this.registeredApps.delete(appName);
|
|
125
|
-
console.log(`[WuRegistry] ❌ App ${appName} unregistered`);
|
|
126
52
|
}
|
|
127
53
|
|
|
128
54
|
/**
|
|
129
55
|
* 🧹 CLEANUP
|
|
130
56
|
*/
|
|
131
57
|
cleanup() {
|
|
132
|
-
// Rechazar todas las promesas pendientes
|
|
133
|
-
for (const [appName, { reject, timeoutId }] of this.waitingPromises) {
|
|
134
|
-
clearTimeout(timeoutId);
|
|
135
|
-
reject(new Error(`Registry cleanup: ${appName}`));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
this.waitingPromises.clear();
|
|
139
58
|
this.registeredApps.clear();
|
|
140
|
-
|
|
141
|
-
console.log('[WuRegistry] 🧹 Registry cleaned up');
|
|
142
59
|
}
|
|
143
60
|
}
|
package/src/index.js
CHANGED
|
@@ -103,7 +103,7 @@ if (typeof window !== 'undefined') {
|
|
|
103
103
|
|
|
104
104
|
// Configurar propiedades si no existen
|
|
105
105
|
if (!wu.version) {
|
|
106
|
-
wu.version = '1.0.
|
|
106
|
+
wu.version = '1.0.5';
|
|
107
107
|
console.log('🚀 Wu Framework loaded - Universal Microfrontends ready');
|
|
108
108
|
wu.info = {
|
|
109
109
|
name: 'Wu Framework',
|
|
@@ -126,6 +126,19 @@ if (typeof window !== 'undefined') {
|
|
|
126
126
|
wu.once = (eventName, callback) => wu.eventBus.once(eventName, callback);
|
|
127
127
|
wu.off = (eventName, callback) => wu.eventBus.off(eventName, callback);
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
// 🔇 Exponer funciones de control de logs
|
|
131
|
+
// window.wu.silence() para silenciar, window.wu.verbose() para debug
|
|
132
|
+
if (!wu.silence) {
|
|
133
|
+
wu.silence = async () => {
|
|
134
|
+
const { silenceAllLogs } = await import('./core/wu-logger.js');
|
|
135
|
+
silenceAllLogs();
|
|
136
|
+
};
|
|
137
|
+
wu.verbose = async () => {
|
|
138
|
+
const { enableAllLogs } = await import('./core/wu-logger.js');
|
|
139
|
+
enableAllLogs();
|
|
140
|
+
};
|
|
141
|
+
}
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
// Exportar API principal
|
|
@@ -167,6 +180,7 @@ export {
|
|
|
167
180
|
} from './core/wu-hooks.js';
|
|
168
181
|
export { WuSandboxPool } from './core/wu-sandbox-pool.js';
|
|
169
182
|
export { WuRegistry } from './core/wu-registry.js';
|
|
183
|
+
export { silenceAllLogs, enableAllLogs } from './core/wu-logger.js';
|
|
170
184
|
|
|
171
185
|
/**
|
|
172
186
|
* Utilidades de conveniencia para uso común
|
package/src/api/wu-simple.js
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🚀 WU-FRAMEWORK SIMPLIFIED API
|
|
3
|
-
* Developer-friendly interface for universal microfrontends
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { wu as wuCore } from '../index.js'
|
|
7
|
-
import { logger } from '../core/wu-logger.js'
|
|
8
|
-
|
|
9
|
-
class WuSimpleAPI {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.core = wuCore
|
|
12
|
-
this.autoInitialized = false
|
|
13
|
-
this.defaultConfig = {
|
|
14
|
-
container: '#app',
|
|
15
|
-
mode: 'auto', // auto, spa, microfrontend
|
|
16
|
-
debug: false,
|
|
17
|
-
timeout: 30000,
|
|
18
|
-
retries: 3
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 🌟 SMART MOUNT: Intelligent mounting with auto-discovery
|
|
24
|
-
* wu.mount('dashboard').into('#container')
|
|
25
|
-
* wu.mount('http://localhost:3001/dashboard')
|
|
26
|
-
*/
|
|
27
|
-
mount(appNameOrUrl) {
|
|
28
|
-
const mountAPI = {
|
|
29
|
-
into: async (containerSelector = this.defaultConfig.container) => {
|
|
30
|
-
await this._ensureInitialized()
|
|
31
|
-
|
|
32
|
-
// 🔍 Detect if it's a URL or app name
|
|
33
|
-
if (this._isUrl(appNameOrUrl)) {
|
|
34
|
-
return await this._mountFromUrl(appNameOrUrl, containerSelector)
|
|
35
|
-
} else {
|
|
36
|
-
return await this._mountFromName(appNameOrUrl, containerSelector)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Support direct call: wu.mount('dashboard', '#container')
|
|
42
|
-
if (typeof arguments[1] === 'string') {
|
|
43
|
-
return mountAPI.into(arguments[1])
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return mountAPI
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 🚀 QUICK LOAD: One-liner for loading remote microfrontends
|
|
51
|
-
* wu.load('http://localhost:3001/dashboard')
|
|
52
|
-
* wu.load('http://localhost:3001', { name: 'dashboard' })
|
|
53
|
-
*/
|
|
54
|
-
async load(url, options = {}) {
|
|
55
|
-
await this._ensureInitialized()
|
|
56
|
-
|
|
57
|
-
const appName = options.name || this._extractAppName(url)
|
|
58
|
-
const container = options.container || this.defaultConfig.container
|
|
59
|
-
|
|
60
|
-
// Auto-register and mount
|
|
61
|
-
await this._registerFromUrl(url, appName)
|
|
62
|
-
return await this.mount(appName).into(container)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 🎯 BATCH OPERATIONS: Load multiple apps at once
|
|
67
|
-
* wu.loadMany([
|
|
68
|
-
* { name: 'dashboard', url: 'http://localhost:3001' },
|
|
69
|
-
* { name: 'sidebar', url: 'http://localhost:3002' }
|
|
70
|
-
* ])
|
|
71
|
-
*/
|
|
72
|
-
async loadMany(apps) {
|
|
73
|
-
await this._ensureInitialized()
|
|
74
|
-
|
|
75
|
-
const results = []
|
|
76
|
-
for (const app of apps) {
|
|
77
|
-
try {
|
|
78
|
-
await this._registerFromUrl(app.url, app.name)
|
|
79
|
-
results.push({ name: app.name, status: 'registered' })
|
|
80
|
-
} catch (error) {
|
|
81
|
-
results.push({ name: app.name, status: 'failed', error: error.message })
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return results
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* 🔧 CONFIGURATION: Flexible configuration methods
|
|
90
|
-
* wu.config({ debug: true, timeout: 60000 })
|
|
91
|
-
* wu.debug(true)
|
|
92
|
-
* wu.timeout(30000)
|
|
93
|
-
*/
|
|
94
|
-
config(options = {}) {
|
|
95
|
-
Object.assign(this.defaultConfig, options)
|
|
96
|
-
|
|
97
|
-
if (options.debug) {
|
|
98
|
-
logger.wuDebug('🔧 Configuration updated:', this.defaultConfig)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return this
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* 🐛 DEBUG MODE: Quick debug toggle
|
|
106
|
-
* wu.debug(true)
|
|
107
|
-
* wu.debug() // toggle
|
|
108
|
-
*/
|
|
109
|
-
debug(enabled) {
|
|
110
|
-
if (enabled === undefined) {
|
|
111
|
-
this.defaultConfig.debug = !this.defaultConfig.debug
|
|
112
|
-
} else {
|
|
113
|
-
this.defaultConfig.debug = !!enabled
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
logger.wuInfo(`🐛 Debug mode: ${this.defaultConfig.debug ? 'ON' : 'OFF'}`)
|
|
117
|
-
return this
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* ⏱️ TIMEOUT: Set operation timeout
|
|
122
|
-
* wu.timeout(60000) // 60 seconds
|
|
123
|
-
*/
|
|
124
|
-
timeout(ms) {
|
|
125
|
-
this.defaultConfig.timeout = ms
|
|
126
|
-
logger.wuDebug(`⏱️ Timeout set to ${ms}ms`)
|
|
127
|
-
return this
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* 🔄 RETRIES: Set retry attempts
|
|
132
|
-
* wu.retries(5)
|
|
133
|
-
*/
|
|
134
|
-
retries(count) {
|
|
135
|
-
this.defaultConfig.retries = count
|
|
136
|
-
logger.wuDebug(`🔄 Retries set to ${count}`)
|
|
137
|
-
return this
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 🎯 DEFAULT CONTAINER: Set default mounting container
|
|
142
|
-
* wu.container('#main-app')
|
|
143
|
-
*/
|
|
144
|
-
container(selector) {
|
|
145
|
-
this.defaultConfig.container = selector
|
|
146
|
-
logger.wuDebug(`🎯 Default container set to ${selector}`)
|
|
147
|
-
return this
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* 🌐 GLOBAL SETTINGS: Environment-based configuration
|
|
152
|
-
* wu.development() // Sets debug: true, retries: 1
|
|
153
|
-
* wu.production() // Sets debug: false, retries: 3
|
|
154
|
-
*/
|
|
155
|
-
development() {
|
|
156
|
-
return this.config({
|
|
157
|
-
debug: true,
|
|
158
|
-
retries: 1,
|
|
159
|
-
timeout: 60000
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
production() {
|
|
164
|
-
return this.config({
|
|
165
|
-
debug: false,
|
|
166
|
-
retries: 3,
|
|
167
|
-
timeout: 30000
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* 🚀 QUICK SETUP: Common configurations
|
|
173
|
-
* wu.spa() // Single Page App mode
|
|
174
|
-
* wu.micro() // Microfrontend mode
|
|
175
|
-
*/
|
|
176
|
-
spa() {
|
|
177
|
-
return this.config({
|
|
178
|
-
mode: 'spa',
|
|
179
|
-
container: '#app',
|
|
180
|
-
debug: false
|
|
181
|
-
})
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
micro() {
|
|
185
|
-
return this.config({
|
|
186
|
-
mode: 'microfrontend',
|
|
187
|
-
debug: true,
|
|
188
|
-
retries: 5
|
|
189
|
-
})
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* 📊 STATUS: Get framework and apps status
|
|
194
|
-
* wu.status()
|
|
195
|
-
*/
|
|
196
|
-
status() {
|
|
197
|
-
const stats = this.core.getStats?.() || {}
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
initialized: this.autoInitialized,
|
|
201
|
-
apps: {
|
|
202
|
-
registered: stats.registered || 0,
|
|
203
|
-
mounted: stats.mounted || 0,
|
|
204
|
-
available: stats.apps || []
|
|
205
|
-
},
|
|
206
|
-
health: this.core.quantumState?.dimensionalStability || 'unknown',
|
|
207
|
-
config: this.defaultConfig
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* 🧹 CLEANUP: Clean shutdown
|
|
213
|
-
* wu.destroy()
|
|
214
|
-
*/
|
|
215
|
-
async destroy() {
|
|
216
|
-
if (this.core.destroy) {
|
|
217
|
-
await this.core.destroy()
|
|
218
|
-
}
|
|
219
|
-
this.autoInitialized = false
|
|
220
|
-
logger.wuInfo('🧹 Framework destroyed')
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
// 🔒 PRIVATE METHODS
|
|
225
|
-
|
|
226
|
-
async _ensureInitialized() {
|
|
227
|
-
if (!this.autoInitialized) {
|
|
228
|
-
await this._autoInitialize()
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async _autoInitialize() {
|
|
233
|
-
if (this.defaultConfig.debug) {
|
|
234
|
-
logger.wuDebug('🚀 Auto-initializing Wu Framework...')
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Smart initialization with minimal config
|
|
238
|
-
await this.core.init({ apps: [] })
|
|
239
|
-
this.autoInitialized = true
|
|
240
|
-
|
|
241
|
-
if (this.defaultConfig.debug) {
|
|
242
|
-
logger.wuDebug('✅ Wu Framework auto-initialized')
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
_isUrl(str) {
|
|
247
|
-
try {
|
|
248
|
-
new URL(str)
|
|
249
|
-
return true
|
|
250
|
-
} catch {
|
|
251
|
-
return str.includes('://') || str.startsWith('http')
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
_extractAppName(url) {
|
|
256
|
-
try {
|
|
257
|
-
const urlObj = new URL(url)
|
|
258
|
-
const pathSegments = urlObj.pathname.split('/').filter(Boolean)
|
|
259
|
-
return pathSegments[pathSegments.length - 1] || urlObj.hostname.split('.')[0]
|
|
260
|
-
} catch {
|
|
261
|
-
return 'app-' + Date.now()
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
async _registerFromUrl(url, appName) {
|
|
266
|
-
const baseUrl = this._getBaseUrl(url)
|
|
267
|
-
|
|
268
|
-
await this.core.registerApp({
|
|
269
|
-
name: appName,
|
|
270
|
-
url: baseUrl
|
|
271
|
-
})
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
_getBaseUrl(url) {
|
|
275
|
-
try {
|
|
276
|
-
const urlObj = new URL(url)
|
|
277
|
-
return `${urlObj.protocol}//${urlObj.host}`
|
|
278
|
-
} catch {
|
|
279
|
-
return url
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async _mountFromUrl(url, containerSelector) {
|
|
284
|
-
const appName = this._extractAppName(url)
|
|
285
|
-
await this._registerFromUrl(url, appName)
|
|
286
|
-
return await this._mountFromName(appName, containerSelector)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async _mountFromName(appName, containerSelector) {
|
|
290
|
-
try {
|
|
291
|
-
await this.core.mount(appName, containerSelector)
|
|
292
|
-
|
|
293
|
-
if (this.defaultConfig.debug) {
|
|
294
|
-
logger.wuDebug(`✅ ${appName} mounted successfully in ${containerSelector}`)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return {
|
|
298
|
-
app: appName,
|
|
299
|
-
container: containerSelector,
|
|
300
|
-
status: 'mounted',
|
|
301
|
-
unmount: () => this.core.unmount(appName)
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
} catch (error) {
|
|
305
|
-
console.error(`[Wu] ❌ Failed to mount ${appName}:`, error.message)
|
|
306
|
-
throw new Error(`Failed to mount ${appName}: ${error.message}`)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// 🌟 Create singleton instance
|
|
312
|
-
const wuSimple = new WuSimpleAPI()
|
|
313
|
-
|
|
314
|
-
// 🎯 Export simple API
|
|
315
|
-
export { wuSimple as wu }
|
|
316
|
-
export default wuSimple
|