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,932 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🚀 WU-FRAMEWORK ANGULAR ADAPTER
|
|
3
|
+
*
|
|
4
|
+
* Integrates Angular (14+) with Wu Framework as microfrontends.
|
|
5
|
+
* Supports NgModule-based apps, standalone components, and Angular Elements.
|
|
6
|
+
* Works inside Shadow DOM (wu-framework's default isolation mode).
|
|
7
|
+
*
|
|
8
|
+
* ## Quick Start — Standalone Component (recommended)
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* // main.ts
|
|
12
|
+
* import 'zone.js';
|
|
13
|
+
* import '@angular/compiler'; // JIT mode (no AOT plugin needed)
|
|
14
|
+
* import { createApplication } from '@angular/platform-browser';
|
|
15
|
+
* import { createComponent, provideZoneChangeDetection } from '@angular/core';
|
|
16
|
+
* import { wuAngular } from 'wu-framework/adapters/angular';
|
|
17
|
+
* import { AppComponent } from './app/app.component';
|
|
18
|
+
*
|
|
19
|
+
* wuAngular.registerStandalone('my-app', AppComponent, {
|
|
20
|
+
* createApplication, // pass Angular APIs to avoid bundler issues
|
|
21
|
+
* createComponent,
|
|
22
|
+
* provideZoneChangeDetection,
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Using Wu Events & Store inside Angular
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { createWuService } from 'wu-framework/adapters/angular';
|
|
30
|
+
*
|
|
31
|
+
* @Component({ ... })
|
|
32
|
+
* export class MyComponent implements OnInit, OnDestroy {
|
|
33
|
+
* private wu = createWuService();
|
|
34
|
+
*
|
|
35
|
+
* ngOnInit() {
|
|
36
|
+
* this.wu.on('some:event', (data) => { ... });
|
|
37
|
+
* const user = this.wu.getState('user');
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* ngOnDestroy() {
|
|
41
|
+
* this.wu.destroy(); // cleans up all subscriptions
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* ## Vite Setup (no AnalogJS required)
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* // vite.config.ts
|
|
50
|
+
* import { defineConfig } from 'vite';
|
|
51
|
+
* export default defineConfig({
|
|
52
|
+
* server: { port: 5008, cors: true },
|
|
53
|
+
* esbuild: { target: 'es2022' },
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* ```json
|
|
58
|
+
* // tsconfig.json — enable decorators for esbuild
|
|
59
|
+
* { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* ## Why pass Angular APIs as options?
|
|
63
|
+
*
|
|
64
|
+
* When wu-framework is linked via `file:` or a monorepo, bundlers (Vite, Rollup)
|
|
65
|
+
* resolve imports relative to the adapter's source file — NOT your app's node_modules.
|
|
66
|
+
* Passing `createApplication`, `createComponent`, etc. from your own imports ensures
|
|
67
|
+
* the bundler resolves them from your app's dependencies. The adapter falls back to
|
|
68
|
+
* dynamic imports for environments where this isn't an issue (Webpack, non-bundled).
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Dynamic import helper — passes the module path through a function parameter
|
|
73
|
+
* so that bundlers (Vite, Rollup, Webpack) cannot statically resolve it.
|
|
74
|
+
* This is necessary because Angular dependencies (@angular/platform-browser-dynamic,
|
|
75
|
+
* @angular/elements, etc.) are optional and may not be installed.
|
|
76
|
+
*/
|
|
77
|
+
function _optionalImport(modulePath) {
|
|
78
|
+
return import(/* @vite-ignore */ modulePath);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Estado global del adapter
|
|
82
|
+
const adapterState = {
|
|
83
|
+
apps: new Map(),
|
|
84
|
+
platformRef: null,
|
|
85
|
+
initialized: false
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Obtiene la instancia de Wu Framework
|
|
90
|
+
*/
|
|
91
|
+
function getWuInstance() {
|
|
92
|
+
if (typeof window === 'undefined') return null;
|
|
93
|
+
|
|
94
|
+
return window.wu
|
|
95
|
+
|| window.parent?.wu
|
|
96
|
+
|| window.top?.wu
|
|
97
|
+
|| null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Espera a que Wu Framework esté disponible
|
|
102
|
+
*/
|
|
103
|
+
function waitForWu(timeout = 5000) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const wu = getWuInstance();
|
|
106
|
+
if (wu) {
|
|
107
|
+
resolve(wu);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const startTime = Date.now();
|
|
112
|
+
|
|
113
|
+
const handleWuReady = () => {
|
|
114
|
+
cleanup();
|
|
115
|
+
resolve(getWuInstance());
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
window.addEventListener('wu:ready', handleWuReady);
|
|
119
|
+
window.addEventListener('wu:app:ready', handleWuReady);
|
|
120
|
+
|
|
121
|
+
const checkInterval = setInterval(() => {
|
|
122
|
+
const wu = getWuInstance();
|
|
123
|
+
if (wu) {
|
|
124
|
+
cleanup();
|
|
125
|
+
resolve(wu);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (Date.now() - startTime > timeout) {
|
|
130
|
+
cleanup();
|
|
131
|
+
reject(new Error(`Wu Framework not found after ${timeout}ms`));
|
|
132
|
+
}
|
|
133
|
+
}, 200);
|
|
134
|
+
|
|
135
|
+
function cleanup() {
|
|
136
|
+
clearInterval(checkInterval);
|
|
137
|
+
window.removeEventListener('wu:ready', handleWuReady);
|
|
138
|
+
window.removeEventListener('wu:app:ready', handleWuReady);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Register an NgModule-based Angular app as a microfrontend.
|
|
145
|
+
*
|
|
146
|
+
* NOTE: Uses platformBrowserDynamic + bootstrapModule which does NOT work inside
|
|
147
|
+
* Shadow DOM (it calls document.querySelector internally). For Shadow DOM compatibility,
|
|
148
|
+
* use registerStandalone() instead — it uses createApplication + createComponent with
|
|
149
|
+
* an explicit hostElement, which works everywhere.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} appName - Unique name for the microfrontend
|
|
152
|
+
* @param {Type<any>} AppModule - Main Angular module (e.g. AppModule)
|
|
153
|
+
* @param {Object} options
|
|
154
|
+
* @param {Function} options.platformFactory - platformBrowserDynamic (pass it to avoid bundler issues)
|
|
155
|
+
* @param {Array} options.providers - Additional bootstrap providers
|
|
156
|
+
* @param {Function} options.onMount - Called after mount
|
|
157
|
+
* @param {Function} options.onUnmount - Called before unmount
|
|
158
|
+
* @param {boolean} options.standalone - Allow standalone fallback (default: true)
|
|
159
|
+
* @param {string} options.standaloneContainer - Selector for standalone mode (default: '#root')
|
|
160
|
+
* @param {string} options.rootSelector - Root component selector (default: 'app-root')
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
164
|
+
* import { wuAngular } from 'wu-framework/adapters/angular';
|
|
165
|
+
* import { AppModule } from './app/app.module';
|
|
166
|
+
*
|
|
167
|
+
* wuAngular.register('my-app', AppModule, {
|
|
168
|
+
* platformFactory: platformBrowserDynamic, // pass to avoid bundler issues
|
|
169
|
+
* });
|
|
170
|
+
*/
|
|
171
|
+
async function register(appName, AppModule, options = {}) {
|
|
172
|
+
const {
|
|
173
|
+
platformFactory = null,
|
|
174
|
+
providers = [],
|
|
175
|
+
onMount = null,
|
|
176
|
+
onUnmount = null,
|
|
177
|
+
standalone = true,
|
|
178
|
+
standaloneContainer = '#root',
|
|
179
|
+
rootSelector = 'app-root'
|
|
180
|
+
} = options;
|
|
181
|
+
|
|
182
|
+
// Función de mount interna
|
|
183
|
+
const mountApp = async (container) => {
|
|
184
|
+
if (!container) {
|
|
185
|
+
console.error(`[WuAngular] Mount failed for ${appName}: container is null`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Evitar doble mount
|
|
190
|
+
if (adapterState.apps.has(appName)) {
|
|
191
|
+
console.warn(`[WuAngular] ${appName} already mounted, unmounting first`);
|
|
192
|
+
await unmountApp();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
// Crear elemento root para Angular
|
|
197
|
+
const appElement = document.createElement(rootSelector);
|
|
198
|
+
appElement.setAttribute('data-wu-angular-root', appName);
|
|
199
|
+
container.innerHTML = '';
|
|
200
|
+
container.appendChild(appElement);
|
|
201
|
+
|
|
202
|
+
// Obtener platformBrowserDynamic
|
|
203
|
+
let platform;
|
|
204
|
+
if (platformFactory) {
|
|
205
|
+
platform = platformFactory;
|
|
206
|
+
} else {
|
|
207
|
+
// Intentar import dinámico
|
|
208
|
+
try {
|
|
209
|
+
const platformModule = await _optionalImport('@angular/platform-browser-dynamic');
|
|
210
|
+
platform = platformModule.platformBrowserDynamic;
|
|
211
|
+
} catch (e) {
|
|
212
|
+
// Intentar desde window
|
|
213
|
+
if (window.ng?.platformBrowserDynamic) {
|
|
214
|
+
platform = window.ng.platformBrowserDynamic;
|
|
215
|
+
} else {
|
|
216
|
+
throw new Error('platformBrowserDynamic not available. Please provide it via options.platformFactory');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Bootstrap del módulo
|
|
222
|
+
const platformRef = platform(providers);
|
|
223
|
+
const moduleRef = await platformRef.bootstrapModule(AppModule);
|
|
224
|
+
|
|
225
|
+
// Guardar referencias
|
|
226
|
+
adapterState.apps.set(appName, {
|
|
227
|
+
platformRef,
|
|
228
|
+
moduleRef,
|
|
229
|
+
container,
|
|
230
|
+
rootElement: appElement
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
console.log(`[WuAngular] ✅ ${appName} mounted successfully`);
|
|
234
|
+
|
|
235
|
+
if (onMount) {
|
|
236
|
+
onMount(container, moduleRef);
|
|
237
|
+
}
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error(`[WuAngular] Mount error for ${appName}:`, error);
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Función de unmount interna
|
|
245
|
+
const unmountApp = async (container) => {
|
|
246
|
+
const instance = adapterState.apps.get(appName);
|
|
247
|
+
|
|
248
|
+
if (instance) {
|
|
249
|
+
try {
|
|
250
|
+
if (onUnmount) {
|
|
251
|
+
onUnmount(instance.container, instance.moduleRef);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Destruir el módulo
|
|
255
|
+
if (instance.moduleRef) {
|
|
256
|
+
instance.moduleRef.destroy();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Destruir la plataforma
|
|
260
|
+
if (instance.platformRef) {
|
|
261
|
+
instance.platformRef.destroy();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Limpiar DOM
|
|
265
|
+
if (instance.rootElement && instance.rootElement.parentNode) {
|
|
266
|
+
instance.rootElement.parentNode.removeChild(instance.rootElement);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
adapterState.apps.delete(appName);
|
|
270
|
+
|
|
271
|
+
console.log(`[WuAngular] ✅ ${appName} unmounted successfully`);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error(`[WuAngular] Unmount error for ${appName}:`, error);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Limpiar container si se proporciona
|
|
278
|
+
if (container) {
|
|
279
|
+
container.innerHTML = '';
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Intentar registrar con Wu Framework
|
|
284
|
+
try {
|
|
285
|
+
const wu = await waitForWu(3000);
|
|
286
|
+
|
|
287
|
+
wu.define(appName, {
|
|
288
|
+
mount: mountApp,
|
|
289
|
+
unmount: unmountApp
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
console.log(`[WuAngular] ✅ ${appName} registered with Wu Framework`);
|
|
293
|
+
return true;
|
|
294
|
+
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.warn(`[WuAngular] Wu Framework not available for ${appName}`);
|
|
297
|
+
|
|
298
|
+
// Modo standalone si está habilitado
|
|
299
|
+
if (standalone) {
|
|
300
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
301
|
+
|
|
302
|
+
if (containerElement) {
|
|
303
|
+
console.log(`[WuAngular] Running ${appName} in standalone mode`);
|
|
304
|
+
await mountApp(containerElement);
|
|
305
|
+
return true;
|
|
306
|
+
} else {
|
|
307
|
+
console.warn(`[WuAngular] Standalone container ${standaloneContainer} not found`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Registra un componente Angular standalone como microfrontend (Angular 14+)
|
|
317
|
+
*
|
|
318
|
+
* @param {string} appName - Nombre único del microfrontend
|
|
319
|
+
* @param {Type<any>} RootComponent - Componente standalone principal
|
|
320
|
+
* @param {Object} options - Opciones adicionales
|
|
321
|
+
* @param {ApplicationConfig} options.appConfig - Configuración de la aplicación
|
|
322
|
+
* @param {Function} options.onMount - Callback después de montar
|
|
323
|
+
* @param {Function} options.onUnmount - Callback antes de desmontar
|
|
324
|
+
* @param {boolean} options.standalone - Permitir ejecución standalone (default: true)
|
|
325
|
+
* @param {string} options.standaloneContainer - Selector para modo standalone (default: '#root')
|
|
326
|
+
* @param {Function} options.createApplication - createApplication from @angular/platform-browser (recommended to avoid bundler issues)
|
|
327
|
+
* @param {Function} options.createComponent - createComponent from @angular/core
|
|
328
|
+
* @param {Function} options.provideZoneChangeDetection - provideZoneChangeDetection from @angular/core
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* // Angular 14+ con standalone components
|
|
332
|
+
* import { AppComponent } from './app/app.component';
|
|
333
|
+
* import { createApplication } from '@angular/platform-browser';
|
|
334
|
+
* import { createComponent, provideZoneChangeDetection } from '@angular/core';
|
|
335
|
+
*
|
|
336
|
+
* wuAngular.registerStandalone('my-app', AppComponent, {
|
|
337
|
+
* createApplication,
|
|
338
|
+
* createComponent,
|
|
339
|
+
* provideZoneChangeDetection,
|
|
340
|
+
* });
|
|
341
|
+
*/
|
|
342
|
+
async function registerStandalone(appName, RootComponent, options = {}) {
|
|
343
|
+
const {
|
|
344
|
+
appConfig = {},
|
|
345
|
+
onMount = null,
|
|
346
|
+
onUnmount = null,
|
|
347
|
+
standalone = true,
|
|
348
|
+
standaloneContainer = '#root',
|
|
349
|
+
createApplication: createApplicationOpt = null,
|
|
350
|
+
createComponent: createComponentOpt = null,
|
|
351
|
+
provideZoneChangeDetection: provideZoneChangeDetectionOpt = null
|
|
352
|
+
} = options;
|
|
353
|
+
|
|
354
|
+
// Función de mount para standalone components
|
|
355
|
+
const mountApp = async (container) => {
|
|
356
|
+
if (!container) {
|
|
357
|
+
console.error(`[WuAngular] Mount failed for ${appName}: container is null`);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Evitar doble mount
|
|
362
|
+
if (adapterState.apps.has(appName)) {
|
|
363
|
+
console.warn(`[WuAngular] ${appName} already mounted, unmounting first`);
|
|
364
|
+
await unmountApp();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
// Resolve Angular APIs: prefer options > dynamic import > window.ng
|
|
369
|
+
let createApplicationFn = createApplicationOpt;
|
|
370
|
+
let createComponentFn = createComponentOpt;
|
|
371
|
+
let provideZoneChangeDetectionFn = provideZoneChangeDetectionOpt;
|
|
372
|
+
|
|
373
|
+
if (!createApplicationFn) {
|
|
374
|
+
try {
|
|
375
|
+
const browserModule = await _optionalImport('@angular/platform-browser');
|
|
376
|
+
createApplicationFn = browserModule.createApplication;
|
|
377
|
+
const coreModule = await _optionalImport('@angular/core');
|
|
378
|
+
createComponentFn = coreModule.createComponent;
|
|
379
|
+
provideZoneChangeDetectionFn = coreModule.provideZoneChangeDetection;
|
|
380
|
+
} catch (e) {
|
|
381
|
+
if (window.ng?.createApplication) {
|
|
382
|
+
createApplicationFn = window.ng.createApplication;
|
|
383
|
+
createComponentFn = window.ng.createComponent;
|
|
384
|
+
provideZoneChangeDetectionFn = window.ng.provideZoneChangeDetection;
|
|
385
|
+
} else {
|
|
386
|
+
throw new Error(
|
|
387
|
+
'Angular APIs not available. Pass createApplication, createComponent via options, ' +
|
|
388
|
+
'or ensure @angular/platform-browser is resolvable. See docs for example.'
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Merge providers: add zone change detection if available
|
|
395
|
+
const providers = [...(appConfig.providers || [])];
|
|
396
|
+
if (provideZoneChangeDetectionFn) {
|
|
397
|
+
providers.push(provideZoneChangeDetectionFn({ eventCoalescing: true }));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Create Angular application
|
|
401
|
+
const appRef = await createApplicationFn({ providers });
|
|
402
|
+
|
|
403
|
+
// Create host element inside the container (Shadow DOM compatible)
|
|
404
|
+
container.innerHTML = '';
|
|
405
|
+
const selector = RootComponent.ɵcmp?.selectors?.[0]?.[0]
|
|
406
|
+
|| RootComponent.__annotations__?.[0]?.selector
|
|
407
|
+
|| 'app-root';
|
|
408
|
+
const hostEl = document.createElement(selector);
|
|
409
|
+
container.appendChild(hostEl);
|
|
410
|
+
|
|
411
|
+
// Create and attach the component using hostElement (bypasses document.querySelector)
|
|
412
|
+
const compRef = createComponentFn(RootComponent, {
|
|
413
|
+
environmentInjector: appRef.injector,
|
|
414
|
+
hostElement: hostEl,
|
|
415
|
+
});
|
|
416
|
+
appRef.attachView(compRef.hostView);
|
|
417
|
+
|
|
418
|
+
// Guardar referencias
|
|
419
|
+
adapterState.apps.set(appName, {
|
|
420
|
+
appRef,
|
|
421
|
+
compRef,
|
|
422
|
+
container,
|
|
423
|
+
hostElement: hostEl,
|
|
424
|
+
isStandalone: true
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
console.log(`[WuAngular] ✅ ${appName} (standalone) mounted successfully`);
|
|
428
|
+
|
|
429
|
+
if (onMount) {
|
|
430
|
+
onMount(container, appRef);
|
|
431
|
+
}
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.error(`[WuAngular] Mount error for ${appName}:`, error);
|
|
434
|
+
throw error;
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// Función de unmount para standalone
|
|
439
|
+
const unmountApp = async (container) => {
|
|
440
|
+
const instance = adapterState.apps.get(appName);
|
|
441
|
+
|
|
442
|
+
if (instance) {
|
|
443
|
+
try {
|
|
444
|
+
if (onUnmount) {
|
|
445
|
+
onUnmount(instance.container, instance.appRef);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Destruir el componente
|
|
449
|
+
if (instance.compRef) {
|
|
450
|
+
instance.compRef.destroy();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Destruir la aplicación
|
|
454
|
+
if (instance.appRef) {
|
|
455
|
+
instance.appRef.destroy();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
adapterState.apps.delete(appName);
|
|
459
|
+
|
|
460
|
+
console.log(`[WuAngular] ✅ ${appName} (standalone) unmounted successfully`);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
console.error(`[WuAngular] Unmount error for ${appName}:`, error);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (container) {
|
|
467
|
+
container.innerHTML = '';
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// Intentar registrar con Wu Framework
|
|
472
|
+
try {
|
|
473
|
+
const wu = await waitForWu(3000);
|
|
474
|
+
|
|
475
|
+
wu.define(appName, {
|
|
476
|
+
mount: mountApp,
|
|
477
|
+
unmount: unmountApp
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
console.log(`[WuAngular] ✅ ${appName} (standalone) registered with Wu Framework`);
|
|
481
|
+
return true;
|
|
482
|
+
|
|
483
|
+
} catch (error) {
|
|
484
|
+
console.warn(`[WuAngular] Wu Framework not available for ${appName}`);
|
|
485
|
+
|
|
486
|
+
if (standalone) {
|
|
487
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
488
|
+
|
|
489
|
+
if (containerElement) {
|
|
490
|
+
console.log(`[WuAngular] Running ${appName} in standalone mode`);
|
|
491
|
+
await mountApp(containerElement);
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Register an Angular Elements (Web Component) as a microfrontend.
|
|
502
|
+
* Requires @angular/elements to be installed.
|
|
503
|
+
*
|
|
504
|
+
* @param {string} appName - Unique microfrontend name
|
|
505
|
+
* @param {Type<any>} Component - Angular standalone component
|
|
506
|
+
* @param {Object} options
|
|
507
|
+
* @param {string} options.elementTag - Custom element tag (default: `${appName}-element`)
|
|
508
|
+
* @param {ApplicationConfig} options.appConfig - Angular application config
|
|
509
|
+
* @param {Function} options.onMount - Called after mount
|
|
510
|
+
* @param {Function} options.onUnmount - Called before unmount
|
|
511
|
+
* @param {boolean} options.standalone - Allow standalone fallback (default: true)
|
|
512
|
+
* @param {string} options.standaloneContainer - Selector for standalone mode (default: '#root')
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* import { wuAngular } from 'wu-framework/adapters/angular';
|
|
516
|
+
* import { AppComponent } from './app/app.component';
|
|
517
|
+
*
|
|
518
|
+
* wuAngular.registerElement('mfe-angular', AppComponent, {
|
|
519
|
+
* elementTag: 'mfe-angular-content',
|
|
520
|
+
* });
|
|
521
|
+
*/
|
|
522
|
+
async function registerElement(appName, Component, options = {}) {
|
|
523
|
+
const {
|
|
524
|
+
elementTag = `${appName}-element`,
|
|
525
|
+
appConfig = {},
|
|
526
|
+
onMount = null,
|
|
527
|
+
onUnmount = null,
|
|
528
|
+
standalone = true,
|
|
529
|
+
standaloneContainer = '#root'
|
|
530
|
+
} = options;
|
|
531
|
+
|
|
532
|
+
let customElementRegistered = false;
|
|
533
|
+
|
|
534
|
+
// Función para inicializar Angular Elements
|
|
535
|
+
const initializeElement = async () => {
|
|
536
|
+
if (customElementRegistered) return true;
|
|
537
|
+
|
|
538
|
+
try {
|
|
539
|
+
// Import dinámico de Angular
|
|
540
|
+
const [{ createApplication }, { createCustomElement }] = await Promise.all([
|
|
541
|
+
_optionalImport('@angular/platform-browser'),
|
|
542
|
+
_optionalImport('@angular/elements')
|
|
543
|
+
]);
|
|
544
|
+
|
|
545
|
+
// Crear aplicación Angular
|
|
546
|
+
const app = await createApplication(appConfig);
|
|
547
|
+
|
|
548
|
+
// Crear y registrar el custom element
|
|
549
|
+
const CustomElement = createCustomElement(Component, { injector: app.injector });
|
|
550
|
+
|
|
551
|
+
if (!customElements.get(elementTag)) {
|
|
552
|
+
customElements.define(elementTag, CustomElement);
|
|
553
|
+
console.log(`[WuAngular] ✅ Custom element registered: ${elementTag}`);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
customElementRegistered = true;
|
|
557
|
+
|
|
558
|
+
// Guardar referencia
|
|
559
|
+
adapterState.apps.set(`${appName}:element`, {
|
|
560
|
+
app,
|
|
561
|
+
elementTag,
|
|
562
|
+
CustomElement
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
return true;
|
|
566
|
+
} catch (error) {
|
|
567
|
+
console.error(`[WuAngular] Failed to initialize Angular Element:`, error);
|
|
568
|
+
throw error;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// Función de mount
|
|
573
|
+
const mountApp = async (container) => {
|
|
574
|
+
if (!container) {
|
|
575
|
+
console.error(`[WuAngular] Mount failed for ${appName}: container is null`);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
try {
|
|
580
|
+
// Asegurar que el elemento está registrado
|
|
581
|
+
await initializeElement();
|
|
582
|
+
|
|
583
|
+
// Crear el elemento custom
|
|
584
|
+
const element = document.createElement(elementTag);
|
|
585
|
+
element.setAttribute('data-wu-angular-element', appName);
|
|
586
|
+
|
|
587
|
+
// Limpiar y agregar al container
|
|
588
|
+
container.innerHTML = '';
|
|
589
|
+
container.appendChild(element);
|
|
590
|
+
|
|
591
|
+
// Guardar referencia del mount
|
|
592
|
+
adapterState.apps.set(appName, {
|
|
593
|
+
element,
|
|
594
|
+
container,
|
|
595
|
+
elementTag
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
console.log(`[WuAngular] ✅ ${appName} (element) mounted successfully`);
|
|
599
|
+
|
|
600
|
+
if (onMount) {
|
|
601
|
+
onMount(container, element);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return element;
|
|
605
|
+
} catch (error) {
|
|
606
|
+
console.error(`[WuAngular] Mount error for ${appName}:`, error);
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
// Función de unmount
|
|
612
|
+
const unmountApp = async (container) => {
|
|
613
|
+
const instance = adapterState.apps.get(appName);
|
|
614
|
+
|
|
615
|
+
if (instance) {
|
|
616
|
+
try {
|
|
617
|
+
if (onUnmount) {
|
|
618
|
+
onUnmount(instance.container, instance.element);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Remover elemento del DOM
|
|
622
|
+
if (instance.element && instance.element.parentNode) {
|
|
623
|
+
instance.element.remove();
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
adapterState.apps.delete(appName);
|
|
627
|
+
|
|
628
|
+
console.log(`[WuAngular] ✅ ${appName} (element) unmounted successfully`);
|
|
629
|
+
} catch (error) {
|
|
630
|
+
console.error(`[WuAngular] Unmount error for ${appName}:`, error);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (container) {
|
|
635
|
+
container.innerHTML = '';
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// Intentar registrar con Wu Framework
|
|
640
|
+
try {
|
|
641
|
+
const wu = await waitForWu(3000);
|
|
642
|
+
|
|
643
|
+
wu.define(appName, {
|
|
644
|
+
mount: mountApp,
|
|
645
|
+
unmount: unmountApp
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
console.log(`[WuAngular] ✅ ${appName} (element) registered with Wu Framework`);
|
|
649
|
+
return true;
|
|
650
|
+
|
|
651
|
+
} catch (error) {
|
|
652
|
+
console.warn(`[WuAngular] Wu Framework not available for ${appName}`);
|
|
653
|
+
|
|
654
|
+
if (standalone) {
|
|
655
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
656
|
+
|
|
657
|
+
if (containerElement) {
|
|
658
|
+
console.log(`[WuAngular] Running ${appName} in standalone mode`);
|
|
659
|
+
await mountApp(containerElement);
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Creates a lightweight service for wu-framework events and store access.
|
|
670
|
+
* Call destroy() in ngOnDestroy to clean up all subscriptions.
|
|
671
|
+
*
|
|
672
|
+
* @returns {{ emit, on, once, off, getState, setState, onStateChange, destroy, wu }}
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* import { createWuService } from 'wu-framework/adapters/angular';
|
|
676
|
+
*
|
|
677
|
+
* @Component({ selector: 'app-root', standalone: true, template: '...' })
|
|
678
|
+
* export class AppComponent implements OnInit, OnDestroy {
|
|
679
|
+
* private wu = createWuService();
|
|
680
|
+
*
|
|
681
|
+
* ngOnInit() {
|
|
682
|
+
* this.wu.on('order:new', (e) => this.orders.push(e.data));
|
|
683
|
+
* this.wu.onStateChange('theme.mode', (e) => this.theme = e.value);
|
|
684
|
+
* const user = this.wu.getState('user');
|
|
685
|
+
* }
|
|
686
|
+
*
|
|
687
|
+
* save() {
|
|
688
|
+
* this.wu.setState('store.name', this.storeName);
|
|
689
|
+
* this.wu.emit('settings:saved', { name: this.storeName });
|
|
690
|
+
* }
|
|
691
|
+
*
|
|
692
|
+
* ngOnDestroy() {
|
|
693
|
+
* this.wu.destroy(); // removes all on/onStateChange listeners
|
|
694
|
+
* }
|
|
695
|
+
* }
|
|
696
|
+
*/
|
|
697
|
+
function createWuService() {
|
|
698
|
+
const subscriptions = [];
|
|
699
|
+
|
|
700
|
+
return {
|
|
701
|
+
// Event Bus
|
|
702
|
+
emit: (event, data, options) => {
|
|
703
|
+
const wu = getWuInstance();
|
|
704
|
+
if (wu?.eventBus) {
|
|
705
|
+
wu.eventBus.emit(event, data, options);
|
|
706
|
+
} else {
|
|
707
|
+
console.warn('[WuService] Wu Framework not available');
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
|
|
711
|
+
on: (event, callback) => {
|
|
712
|
+
const wu = getWuInstance();
|
|
713
|
+
if (wu?.eventBus) {
|
|
714
|
+
const unsubscribe = wu.eventBus.on(event, callback);
|
|
715
|
+
subscriptions.push(unsubscribe);
|
|
716
|
+
return unsubscribe;
|
|
717
|
+
}
|
|
718
|
+
console.warn('[WuService] Wu Framework not available');
|
|
719
|
+
return () => {};
|
|
720
|
+
},
|
|
721
|
+
|
|
722
|
+
once: (event, callback) => {
|
|
723
|
+
const wu = getWuInstance();
|
|
724
|
+
if (wu?.eventBus) {
|
|
725
|
+
return wu.eventBus.once(event, callback);
|
|
726
|
+
}
|
|
727
|
+
return () => {};
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
off: (event, callback) => {
|
|
731
|
+
const wu = getWuInstance();
|
|
732
|
+
if (wu?.eventBus) {
|
|
733
|
+
wu.eventBus.off(event, callback);
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
|
|
737
|
+
// Store
|
|
738
|
+
getState: (path) => {
|
|
739
|
+
const wu = getWuInstance();
|
|
740
|
+
return wu?.store?.get(path) || null;
|
|
741
|
+
},
|
|
742
|
+
|
|
743
|
+
setState: (path, value) => {
|
|
744
|
+
const wu = getWuInstance();
|
|
745
|
+
if (wu?.store) {
|
|
746
|
+
wu.store.set(path, value);
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
|
|
750
|
+
onStateChange: (pattern, callback) => {
|
|
751
|
+
const wu = getWuInstance();
|
|
752
|
+
if (wu?.store) {
|
|
753
|
+
const unsubscribe = wu.store.on(pattern, callback);
|
|
754
|
+
subscriptions.push(unsubscribe);
|
|
755
|
+
return unsubscribe;
|
|
756
|
+
}
|
|
757
|
+
return () => {};
|
|
758
|
+
},
|
|
759
|
+
|
|
760
|
+
// Cleanup
|
|
761
|
+
destroy: () => {
|
|
762
|
+
subscriptions.forEach(unsub => unsub());
|
|
763
|
+
subscriptions.length = 0;
|
|
764
|
+
},
|
|
765
|
+
|
|
766
|
+
// Access to raw Wu instance
|
|
767
|
+
get wu() {
|
|
768
|
+
return getWuInstance();
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Crea un componente Angular para cargar microfrontends (para el Shell)
|
|
775
|
+
* Retorna la configuración del componente para ser usado con @Component
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* // wu-slot.component.ts
|
|
779
|
+
* import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
780
|
+
* import { createWuSlotComponent } from 'wu-framework/adapters/angular';
|
|
781
|
+
*
|
|
782
|
+
* const config = createWuSlotComponent();
|
|
783
|
+
*
|
|
784
|
+
* @Component({
|
|
785
|
+
* selector: 'wu-slot',
|
|
786
|
+
* template: config.template,
|
|
787
|
+
* styles: config.styles
|
|
788
|
+
* })
|
|
789
|
+
* export class WuSlotComponent {
|
|
790
|
+
* @Input() name!: string;
|
|
791
|
+
* @Input() url!: string;
|
|
792
|
+
* @Output() load = new EventEmitter();
|
|
793
|
+
* @Output() error = new EventEmitter();
|
|
794
|
+
*
|
|
795
|
+
* // ... implement lifecycle methods from config.methods
|
|
796
|
+
* }
|
|
797
|
+
*/
|
|
798
|
+
function createWuSlotComponent() {
|
|
799
|
+
return {
|
|
800
|
+
selector: 'wu-slot',
|
|
801
|
+
|
|
802
|
+
template: `
|
|
803
|
+
<div
|
|
804
|
+
#container
|
|
805
|
+
class="wu-slot"
|
|
806
|
+
[class.wu-slot-loading]="loading"
|
|
807
|
+
[class.wu-slot-error]="error"
|
|
808
|
+
[attr.data-wu-app]="name"
|
|
809
|
+
[attr.data-wu-url]="url"
|
|
810
|
+
style="min-height: 100px; position: relative;">
|
|
811
|
+
|
|
812
|
+
<div *ngIf="error" class="wu-slot-error-message"
|
|
813
|
+
style="padding: 1rem; border: 1px solid #f5c6cb; border-radius: 4px; background: #f8d7da; color: #721c24;">
|
|
814
|
+
<strong>Error loading {{ name }}</strong>
|
|
815
|
+
<p style="margin: 0.5rem 0 0 0;">{{ error }}</p>
|
|
816
|
+
</div>
|
|
817
|
+
|
|
818
|
+
<div *ngIf="loading && !error" class="wu-slot-loading-message"
|
|
819
|
+
style="display: flex; align-items: center; justify-content: center; padding: 2rem; color: #666;">
|
|
820
|
+
{{ fallbackText || 'Loading ' + name + '...' }}
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
`,
|
|
824
|
+
|
|
825
|
+
styles: [`
|
|
826
|
+
.wu-slot {
|
|
827
|
+
width: 100%;
|
|
828
|
+
min-height: 100px;
|
|
829
|
+
}
|
|
830
|
+
`],
|
|
831
|
+
|
|
832
|
+
// Métodos para implementar en el componente
|
|
833
|
+
methods: {
|
|
834
|
+
async ngOnInit() {
|
|
835
|
+
await this.mountMicrofrontend();
|
|
836
|
+
},
|
|
837
|
+
|
|
838
|
+
ngOnDestroy() {
|
|
839
|
+
this.unmountMicrofrontend();
|
|
840
|
+
},
|
|
841
|
+
|
|
842
|
+
async mountMicrofrontend() {
|
|
843
|
+
try {
|
|
844
|
+
this.loading = true;
|
|
845
|
+
this.error = null;
|
|
846
|
+
|
|
847
|
+
const wu = getWuInstance();
|
|
848
|
+
if (!wu) {
|
|
849
|
+
throw new Error('Wu Framework not initialized');
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Crear container único
|
|
853
|
+
const containerId = `wu-slot-${this.name}-${Date.now()}`;
|
|
854
|
+
const innerContainer = document.createElement('div');
|
|
855
|
+
innerContainer.id = containerId;
|
|
856
|
+
innerContainer.style.width = '100%';
|
|
857
|
+
innerContainer.style.height = '100%';
|
|
858
|
+
|
|
859
|
+
this.container.nativeElement.innerHTML = '';
|
|
860
|
+
this.container.nativeElement.appendChild(innerContainer);
|
|
861
|
+
|
|
862
|
+
// Crear y montar la app
|
|
863
|
+
const app = wu.app(this.name, {
|
|
864
|
+
url: this.url,
|
|
865
|
+
container: `#${containerId}`,
|
|
866
|
+
autoInit: true
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
this.appInstance = app;
|
|
870
|
+
await app.mount();
|
|
871
|
+
|
|
872
|
+
this.loading = false;
|
|
873
|
+
this.load.emit({ name: this.name, url: this.url });
|
|
874
|
+
|
|
875
|
+
} catch (err) {
|
|
876
|
+
console.error(`[WuSlot] Error loading ${this.name}:`, err);
|
|
877
|
+
this.error = err.message || 'Failed to load microfrontend';
|
|
878
|
+
this.loading = false;
|
|
879
|
+
this.errorEvent.emit(err);
|
|
880
|
+
}
|
|
881
|
+
},
|
|
882
|
+
|
|
883
|
+
async unmountMicrofrontend() {
|
|
884
|
+
if (this.appInstance) {
|
|
885
|
+
try {
|
|
886
|
+
await this.appInstance.unmount();
|
|
887
|
+
} catch (err) {
|
|
888
|
+
console.warn(`[WuSlot] Error unmounting ${this.name}:`, err);
|
|
889
|
+
}
|
|
890
|
+
this.appInstance = null;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* Helper para crear un módulo Angular que exporta WuSlotComponent
|
|
899
|
+
* Útil para shells que quieren usar <wu-slot> directamente
|
|
900
|
+
*/
|
|
901
|
+
function getWuSlotModuleConfig() {
|
|
902
|
+
return {
|
|
903
|
+
imports: ['CommonModule'],
|
|
904
|
+
declarations: ['WuSlotComponent'],
|
|
905
|
+
exports: ['WuSlotComponent']
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// ============================================
|
|
910
|
+
// AI INTEGRATION (placeholder — ai.js loaded on demand)
|
|
911
|
+
// ============================================
|
|
912
|
+
function createWuAIService(...args) {
|
|
913
|
+
throw new Error('[WuAngular] AI module not available. Install wu-framework AI extension.');
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Named exports for direct imports (e.g. import { createWuService } from 'wu-framework/adapters/angular')
|
|
917
|
+
export { createWuService, register, registerStandalone, registerElement, createWuSlotComponent, getWuSlotModuleConfig, getWuInstance, waitForWu };
|
|
918
|
+
|
|
919
|
+
// API pública del adapter
|
|
920
|
+
export const wuAngular = {
|
|
921
|
+
register,
|
|
922
|
+
registerStandalone,
|
|
923
|
+
registerElement,
|
|
924
|
+
createWuService,
|
|
925
|
+
createWuSlotComponent,
|
|
926
|
+
getWuSlotModuleConfig,
|
|
927
|
+
createWuAIService,
|
|
928
|
+
getWuInstance,
|
|
929
|
+
waitForWu
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
export default wuAngular;
|