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
|
@@ -1,280 +1,190 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* WU-HTML-PARSER: Fetch and parse HTML entries from micro-apps.
|
|
3
|
+
*
|
|
4
|
+
* Used in "strict" sandbox mode. The flow:
|
|
5
|
+
* 1. Fetch the HTML page at the app's URL
|
|
6
|
+
* 2. Parse it: extract inline/external scripts, inline/external styles, and clean DOM
|
|
7
|
+
* 3. Return structured result so wu-core can inject DOM + styles into Shadow DOM
|
|
8
|
+
* and execute scripts inside the proxy sandbox via WuScriptExecutor.
|
|
9
|
+
*
|
|
10
|
+
* This is the qiankun-style "HTML entry" approach that enables real JS isolation.
|
|
4
11
|
*/
|
|
5
12
|
|
|
13
|
+
import { logger } from './wu-logger.js';
|
|
14
|
+
|
|
6
15
|
export class WuHtmlParser {
|
|
7
16
|
constructor() {
|
|
8
|
-
this.
|
|
9
|
-
console.log('[WuHtmlParser] 📄 HTML parsing system initialized');
|
|
17
|
+
this._cache = new Map();
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param {string}
|
|
15
|
-
* @param {string} appName -
|
|
16
|
-
* @
|
|
17
|
-
* @returns {Object} { dom, scripts, styles, externalScripts, externalStyles }
|
|
21
|
+
* Fetch HTML content from a URL.
|
|
22
|
+
* @param {string} url - App URL (e.g. http://localhost:3001)
|
|
23
|
+
* @param {string} appName - For logging
|
|
24
|
+
* @returns {Promise<string>} Raw HTML string
|
|
18
25
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
async fetchHtml(url, appName) {
|
|
27
|
+
logger.wuDebug(`[HtmlParser] Fetching HTML for ${appName} from ${url}`);
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
const response = await fetch(url, {
|
|
30
|
+
method: 'GET',
|
|
31
|
+
headers: { 'Accept': 'text/html,application/xhtml+xml,*/*' }
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`[HtmlParser] Failed to fetch ${url}: HTTP ${response.status}`);
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
const html = await response.text();
|
|
39
|
+
if (!html || !html.trim()) {
|
|
40
|
+
throw new Error(`[HtmlParser] Empty HTML response from ${url}`);
|
|
41
|
+
}
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const inlineStyles = [];
|
|
38
|
-
const externalStyles = [];
|
|
43
|
+
logger.wuDebug(`[HtmlParser] Fetched ${html.length} chars for ${appName}`);
|
|
44
|
+
return html;
|
|
45
|
+
}
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Parse HTML string into structured parts.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} html - Raw HTML
|
|
51
|
+
* @param {string} appName - App identifier
|
|
52
|
+
* @param {string} baseUrl - Base URL for resolving relative paths
|
|
53
|
+
* @returns {{
|
|
54
|
+
* dom: string,
|
|
55
|
+
* scripts: { inline: string[], external: string[] },
|
|
56
|
+
* styles: { inline: string[], external: string[] }
|
|
57
|
+
* }}
|
|
58
|
+
*/
|
|
59
|
+
parse(html, appName, baseUrl) {
|
|
60
|
+
const cacheKey = `${appName}:${html.length}`;
|
|
61
|
+
if (this._cache.has(cacheKey)) {
|
|
62
|
+
return this._cache.get(cacheKey);
|
|
63
|
+
}
|
|
49
64
|
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
const temp = document.createElement('div');
|
|
66
|
+
temp.innerHTML = html;
|
|
52
67
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
external: externalScripts,
|
|
58
|
-
all: [...inlineScripts, ...externalScripts]
|
|
59
|
-
},
|
|
60
|
-
styles: {
|
|
61
|
-
inline: inlineStyles,
|
|
62
|
-
external: externalStyles,
|
|
63
|
-
all: [...inlineStyles, ...externalStyles]
|
|
64
|
-
}
|
|
65
|
-
};
|
|
68
|
+
const inlineScripts = [];
|
|
69
|
+
const externalScripts = [];
|
|
70
|
+
const inlineStyles = [];
|
|
71
|
+
const externalStyles = [];
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
this._extractResources(temp, {
|
|
74
|
+
inlineScripts, externalScripts,
|
|
75
|
+
inlineStyles, externalStyles,
|
|
76
|
+
baseUrl
|
|
77
|
+
});
|
|
69
78
|
|
|
70
|
-
|
|
79
|
+
const result = {
|
|
80
|
+
dom: temp.innerHTML,
|
|
81
|
+
scripts: { inline: inlineScripts, external: externalScripts },
|
|
82
|
+
styles: { inline: inlineStyles, external: externalStyles }
|
|
83
|
+
};
|
|
71
84
|
|
|
72
|
-
|
|
85
|
+
this._cache.set(cacheKey, result);
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
logger.wuDebug(
|
|
88
|
+
`[HtmlParser] ${appName}: ${inlineScripts.length} inline scripts, ` +
|
|
89
|
+
`${externalScripts.length} external scripts, ` +
|
|
90
|
+
`${inlineStyles.length + externalStyles.length} styles`
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return result;
|
|
78
94
|
}
|
|
79
95
|
|
|
80
96
|
/**
|
|
81
|
-
*
|
|
82
|
-
* @param {HTMLElement} element - Elemento a parsear
|
|
83
|
-
* @param {Object} context - Contexto de parsing
|
|
97
|
+
* Convenience: fetch + parse in one call.
|
|
84
98
|
*/
|
|
85
|
-
|
|
86
|
-
const
|
|
99
|
+
async fetchAndParse(url, appName) {
|
|
100
|
+
const html = await this.fetchHtml(url, appName);
|
|
101
|
+
return this.parse(html, appName, url);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Recursively walk the DOM, extracting scripts and styles,
|
|
106
|
+
* replacing them with comments to keep the DOM clean.
|
|
107
|
+
*/
|
|
108
|
+
_extractResources(element, ctx) {
|
|
109
|
+
// Iterate over a static copy since we mutate the DOM
|
|
87
110
|
const children = Array.from(element.children);
|
|
88
111
|
|
|
89
112
|
for (const child of children) {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
// 📜 SCRIPT TAGS
|
|
93
|
-
if (tagName === 'script') {
|
|
94
|
-
this.parseScriptTag(child, inlineScripts, externalScripts, baseUrl, appName);
|
|
113
|
+
const tag = child.nodeName.toLowerCase();
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
child.
|
|
115
|
+
if (tag === 'script') {
|
|
116
|
+
this._extractScript(child, ctx);
|
|
117
|
+
child.replaceWith(document.createComment('wu:script'));
|
|
99
118
|
continue;
|
|
100
119
|
}
|
|
101
120
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
inlineStyles.push(styleContent);
|
|
107
|
-
console.log(`[WuHtmlParser] 🎨 Extracted inline style (${styleContent.length} chars)`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Reemplazar style con comentario
|
|
111
|
-
const comment = document.createComment(`Wu: style removed from ${appName}`);
|
|
112
|
-
child.parentElement?.replaceChild(comment, child);
|
|
121
|
+
if (tag === 'style') {
|
|
122
|
+
const text = child.textContent?.trim();
|
|
123
|
+
if (text) ctx.inlineStyles.push(text);
|
|
124
|
+
child.replaceWith(document.createComment('wu:style'));
|
|
113
125
|
continue;
|
|
114
126
|
}
|
|
115
127
|
|
|
116
|
-
|
|
117
|
-
if (tagName === 'link') {
|
|
128
|
+
if (tag === 'link') {
|
|
118
129
|
const rel = child.getAttribute('rel');
|
|
119
130
|
const href = child.getAttribute('href');
|
|
120
|
-
|
|
121
131
|
if (rel === 'stylesheet' && href) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
console.log(`[WuHtmlParser] 🔗 Extracted external style: ${absoluteUrl}`);
|
|
125
|
-
|
|
126
|
-
// Reemplazar link con comentario
|
|
127
|
-
const comment = document.createComment(`Wu: link removed from ${appName}`);
|
|
128
|
-
child.parentElement?.replaceChild(comment, child);
|
|
132
|
+
ctx.externalStyles.push(this._resolveUrl(href, ctx.baseUrl));
|
|
133
|
+
child.replaceWith(document.createComment('wu:link'));
|
|
129
134
|
continue;
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
//
|
|
138
|
+
// Recurse into children
|
|
134
139
|
if (child.children.length > 0) {
|
|
135
|
-
this.
|
|
140
|
+
this._extractResources(child, ctx);
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
/**
|
|
141
|
-
*
|
|
146
|
+
* Extract a <script> tag into inline or external list.
|
|
147
|
+
* Skips type="module" scripts (they can't be eval'd — use module mode for those).
|
|
142
148
|
*/
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
const
|
|
149
|
+
_extractScript(el, ctx) {
|
|
150
|
+
const type = el.getAttribute('type') || '';
|
|
151
|
+
const src = el.getAttribute('src');
|
|
146
152
|
|
|
147
|
-
//
|
|
153
|
+
// Module scripts can't be executed via new Function / eval.
|
|
154
|
+
// If the app uses ES modules, it should use sandbox: 'module' mode.
|
|
148
155
|
if (type === 'module') {
|
|
149
|
-
|
|
156
|
+
logger.wuDebug('[HtmlParser] Skipping type="module" script (use sandbox: "module" for ES modules)');
|
|
150
157
|
return;
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
if (src) {
|
|
154
|
-
|
|
155
|
-
const absoluteUrl = this.resolveUrl(src, baseUrl);
|
|
156
|
-
externalScripts.push(absoluteUrl);
|
|
157
|
-
console.log(`[WuHtmlParser] 📜 Extracted external script: ${absoluteUrl}`);
|
|
158
|
-
} else {
|
|
159
|
-
// Script inline
|
|
160
|
-
const scriptContent = scriptElement.textContent || '';
|
|
161
|
-
if (scriptContent.trim()) {
|
|
162
|
-
inlineScripts.push(scriptContent);
|
|
163
|
-
console.log(`[WuHtmlParser] 📜 Extracted inline script (${scriptContent.length} chars)`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Resolver URL relativa a absoluta
|
|
170
|
-
*/
|
|
171
|
-
resolveUrl(url, baseUrl) {
|
|
172
|
-
// Ya es absoluta
|
|
173
|
-
if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('//')) {
|
|
174
|
-
return url.startsWith('//') ? `https:${url}` : url;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Resolver relativa
|
|
178
|
-
const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
179
|
-
|
|
180
|
-
if (url.startsWith('/')) {
|
|
181
|
-
// Relativa a raíz
|
|
182
|
-
const urlObj = new URL(baseUrl);
|
|
183
|
-
return `${urlObj.protocol}//${urlObj.host}${url}`;
|
|
161
|
+
ctx.externalScripts.push(this._resolveUrl(src, ctx.baseUrl));
|
|
184
162
|
} else {
|
|
185
|
-
|
|
186
|
-
|
|
163
|
+
const text = el.textContent?.trim();
|
|
164
|
+
if (text) ctx.inlineScripts.push(text);
|
|
187
165
|
}
|
|
188
166
|
}
|
|
189
167
|
|
|
190
168
|
/**
|
|
191
|
-
*
|
|
169
|
+
* Resolve a relative URL against a base URL.
|
|
192
170
|
*/
|
|
193
|
-
|
|
194
|
-
|
|
171
|
+
_resolveUrl(url, baseUrl) {
|
|
172
|
+
if (url.startsWith('http://') || url.startsWith('https://')) return url;
|
|
173
|
+
if (url.startsWith('//')) return `https:${url}`;
|
|
195
174
|
|
|
196
175
|
try {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
if (!response.ok) {
|
|
206
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const html = await response.text();
|
|
210
|
-
|
|
211
|
-
if (!html || html.trim().length === 0) {
|
|
212
|
-
throw new Error('Empty HTML response');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
console.log(`[WuHtmlParser] ✅ Fetched HTML (${html.length} chars)`);
|
|
216
|
-
|
|
217
|
-
return html;
|
|
218
|
-
|
|
219
|
-
} catch (error) {
|
|
220
|
-
console.error(`[WuHtmlParser] ❌ Failed to fetch HTML from ${url}:`, error);
|
|
221
|
-
throw error;
|
|
176
|
+
return new URL(url, baseUrl).href;
|
|
177
|
+
} catch {
|
|
178
|
+
// Fallback for environments without URL constructor
|
|
179
|
+
const base = baseUrl.replace(/\/$/, '');
|
|
180
|
+
return url.startsWith('/') ? base + url : `${base}/${url}`;
|
|
222
181
|
}
|
|
223
182
|
}
|
|
224
183
|
|
|
225
184
|
/**
|
|
226
|
-
*
|
|
185
|
+
* Clear the parse cache.
|
|
227
186
|
*/
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return this.parse(html, appName, url);
|
|
187
|
+
clearCache() {
|
|
188
|
+
this._cache.clear();
|
|
231
189
|
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Limpiar cache
|
|
235
|
-
*/
|
|
236
|
-
clearCache(pattern) {
|
|
237
|
-
if (pattern) {
|
|
238
|
-
const regex = new RegExp(pattern);
|
|
239
|
-
for (const [key] of this.cache) {
|
|
240
|
-
if (regex.test(key)) {
|
|
241
|
-
this.cache.delete(key);
|
|
242
|
-
console.log(`[WuHtmlParser] 🗑️ Cleared cache for: ${key}`);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
} else {
|
|
246
|
-
this.cache.clear();
|
|
247
|
-
console.log(`[WuHtmlParser] 🗑️ Cache cleared completely`);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Obtener estadísticas
|
|
253
|
-
*/
|
|
254
|
-
getStats() {
|
|
255
|
-
return {
|
|
256
|
-
cacheSize: this.cache.size,
|
|
257
|
-
cacheKeys: Array.from(this.cache.keys())
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* 🎯 EXPORTS DE CONVENIENCIA
|
|
264
|
-
*/
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Parsear HTML
|
|
268
|
-
*/
|
|
269
|
-
export function parseHtml(html, appName, baseUrl) {
|
|
270
|
-
const parser = new WuHtmlParser();
|
|
271
|
-
return parser.parse(html, appName, baseUrl);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Parsear HTML desde URL
|
|
276
|
-
*/
|
|
277
|
-
export async function parseHtmlFromUrl(url, appName) {
|
|
278
|
-
const parser = new WuHtmlParser();
|
|
279
|
-
return await parser.parseFromUrl(url, appName);
|
|
280
190
|
}
|