wu-framework 1.1.15 → 1.1.17

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.
Files changed (88) hide show
  1. package/README.md +52 -20
  2. package/dist/wu-framework.cjs.js +1 -1
  3. package/dist/wu-framework.cjs.js.map +1 -1
  4. package/dist/wu-framework.dev.js +15511 -15146
  5. package/dist/wu-framework.dev.js.map +1 -1
  6. package/dist/wu-framework.esm.js +1 -1
  7. package/dist/wu-framework.esm.js.map +1 -1
  8. package/dist/wu-framework.umd.js +1 -1
  9. package/dist/wu-framework.umd.js.map +1 -1
  10. package/package.json +166 -161
  11. package/src/adapters/angular/ai.js +30 -30
  12. package/src/adapters/angular/index.d.ts +154 -154
  13. package/src/adapters/angular/index.js +932 -932
  14. package/src/adapters/angular.d.ts +3 -3
  15. package/src/adapters/angular.js +3 -3
  16. package/src/adapters/index.js +168 -168
  17. package/src/adapters/lit/ai.js +20 -20
  18. package/src/adapters/lit/index.d.ts +120 -120
  19. package/src/adapters/lit/index.js +721 -721
  20. package/src/adapters/lit.d.ts +3 -3
  21. package/src/adapters/lit.js +3 -3
  22. package/src/adapters/preact/ai.js +33 -33
  23. package/src/adapters/preact/index.d.ts +108 -108
  24. package/src/adapters/preact/index.js +661 -661
  25. package/src/adapters/preact.d.ts +3 -3
  26. package/src/adapters/preact.js +3 -3
  27. package/src/adapters/react/index.js +48 -54
  28. package/src/adapters/react.d.ts +3 -3
  29. package/src/adapters/react.js +3 -3
  30. package/src/adapters/shared.js +64 -64
  31. package/src/adapters/solid/ai.js +32 -32
  32. package/src/adapters/solid/index.d.ts +101 -101
  33. package/src/adapters/solid/index.js +586 -586
  34. package/src/adapters/solid.d.ts +3 -3
  35. package/src/adapters/solid.js +3 -3
  36. package/src/adapters/svelte/ai.js +31 -31
  37. package/src/adapters/svelte/index.d.ts +166 -166
  38. package/src/adapters/svelte/index.js +798 -798
  39. package/src/adapters/svelte.d.ts +3 -3
  40. package/src/adapters/svelte.js +3 -3
  41. package/src/adapters/vanilla/ai.js +30 -30
  42. package/src/adapters/vanilla/index.d.ts +179 -179
  43. package/src/adapters/vanilla/index.js +785 -785
  44. package/src/adapters/vanilla.d.ts +3 -3
  45. package/src/adapters/vanilla.js +3 -3
  46. package/src/adapters/vue/ai.js +52 -52
  47. package/src/adapters/vue/index.d.ts +299 -299
  48. package/src/adapters/vue/index.js +610 -610
  49. package/src/adapters/vue.d.ts +3 -3
  50. package/src/adapters/vue.js +3 -3
  51. package/src/ai/wu-ai-actions.js +261 -261
  52. package/src/ai/wu-ai-agent.js +546 -546
  53. package/src/ai/wu-ai-browser-primitives.js +354 -354
  54. package/src/ai/wu-ai-browser.js +380 -380
  55. package/src/ai/wu-ai-context.js +332 -332
  56. package/src/ai/wu-ai-conversation.js +613 -613
  57. package/src/ai/wu-ai-orchestrate.js +1021 -1021
  58. package/src/ai/wu-ai-permissions.js +381 -381
  59. package/src/ai/wu-ai-provider.js +700 -700
  60. package/src/ai/wu-ai-schema.js +225 -225
  61. package/src/ai/wu-ai-triggers.js +396 -396
  62. package/src/ai/wu-ai.js +804 -804
  63. package/src/core/wu-app.js +236 -236
  64. package/src/core/wu-cache.js +498 -477
  65. package/src/core/wu-core.js +1412 -1398
  66. package/src/core/wu-error-boundary.js +396 -382
  67. package/src/core/wu-event-bus.js +390 -348
  68. package/src/core/wu-hooks.js +350 -350
  69. package/src/core/wu-html-parser.js +199 -190
  70. package/src/core/wu-iframe-sandbox.js +328 -328
  71. package/src/core/wu-loader.js +385 -273
  72. package/src/core/wu-logger.js +142 -134
  73. package/src/core/wu-manifest.js +532 -509
  74. package/src/core/wu-mcp-bridge.js +432 -432
  75. package/src/core/wu-overrides.js +510 -510
  76. package/src/core/wu-performance.js +228 -228
  77. package/src/core/wu-plugin.js +401 -348
  78. package/src/core/wu-prefetch.js +414 -414
  79. package/src/core/wu-proxy-sandbox.js +477 -476
  80. package/src/core/wu-sandbox.js +779 -779
  81. package/src/core/wu-script-executor.js +161 -113
  82. package/src/core/wu-snapshot-sandbox.js +227 -227
  83. package/src/core/wu-store.js +13 -3
  84. package/src/core/wu-strategies.js +256 -256
  85. package/src/core/wu-style-bridge.js +477 -477
  86. package/src/index.d.ts +317 -0
  87. package/src/index.js +234 -224
  88. package/src/utils/dependency-resolver.js +327 -327
@@ -1,113 +1,161 @@
1
- /**
2
- * WU-SCRIPT-EXECUTOR: Execute scripts inside a Proxy sandbox.
3
- *
4
- * Two isolation levels:
5
- * - strictGlobal: true → with(proxy) { code } — all global access goes through proxy
6
- * - strictGlobal: false → (function(window){ code })(proxy) — only explicit window.xxx
7
- *
8
- * This is what makes the sandbox REAL instead of decorative.
9
- * Without this, import() runs code in global scope and the proxy is just a cleanup tracker.
10
- * With this, code receives the proxy as "window" and every setTimeout, addEventListener,
11
- * document.querySelector, localStorage access goes through the proxy's traps.
12
- */
13
-
14
- import { logger } from './wu-logger.js';
15
-
16
- export class WuScriptExecutor {
17
-
18
- /**
19
- * Execute a script string inside the proxy sandbox.
20
- *
21
- * @param {string} scriptText - JavaScript code to execute
22
- * @param {string} appName - App identifier (for logging)
23
- * @param {Proxy} proxy - The activated proxy sandbox
24
- * @param {Object} [options]
25
- * @param {boolean} [options.strictGlobal=true] - Use with(proxy) for maximum isolation
26
- * @param {string} [options.sourceUrl=''] - Source URL for devtools (//# sourceURL)
27
- * @returns {*} Return value of the executed code
28
- */
29
- execute(scriptText, appName, proxy, options = {}) {
30
- const { strictGlobal = true, sourceUrl = '' } = options;
31
-
32
- if (!scriptText || !scriptText.trim()) return;
33
-
34
- const sourceComment = sourceUrl ? `\n//# sourceURL=wu-sandbox:///${appName}/${sourceUrl}\n` : '';
35
-
36
- let wrappedCode;
37
-
38
- if (strictGlobal) {
39
- // MAXIMUM ISOLATION
40
- // with(window) makes ALL unqualified identifiers (setTimeout, fetch, document, etc.)
41
- // resolve through the proxy's has/get traps, not the real window.
42
- // Note: 'use strict' inside the with block becomes a no-op string expression,
43
- // so bundled code with strict mode still works.
44
- wrappedCode = `;(function(window, self, globalThis, top, parent) {
45
- with(window) {
46
- ;${scriptText}${sourceComment}
47
- }
48
- }).call(proxy, proxy, proxy, proxy, proxy, proxy);`;
49
- } else {
50
- // IIFE ONLY only explicit window.xxx goes through proxy
51
- wrappedCode = `;(function(window, self, globalThis, top, parent) {
52
- ;${scriptText}${sourceComment}
53
- }).call(proxy, proxy, proxy, proxy, proxy, proxy);`;
54
- }
55
-
56
- try {
57
- // new Function('proxy', code) creates a function with 'proxy' as the single param.
58
- // This avoids polluting scope — the only bridge to the sandbox is the proxy argument.
59
- const fn = new Function('proxy', wrappedCode);
60
- return fn(proxy);
61
- } catch (error) {
62
- // If strictGlobal failed (rare edge case with with-statement), retry without it
63
- if (strictGlobal) {
64
- logger.wuWarn(`[ScriptExecutor] strictGlobal failed for ${appName}, retrying without with(): ${error.message}`);
65
- return this.execute(scriptText, appName, proxy, { ...options, strictGlobal: false });
66
- }
67
- logger.wuError(`[ScriptExecutor] Execution failed for ${appName}:`, error);
68
- throw error;
69
- }
70
- }
71
-
72
- /**
73
- * Fetch script content from a URL.
74
- * @param {string} url - Script URL
75
- * @returns {Promise<string>} Script text
76
- */
77
- async fetchScript(url) {
78
- const response = await fetch(url);
79
- if (!response.ok) {
80
- throw new Error(`Failed to fetch script ${url}: HTTP ${response.status}`);
81
- }
82
- return response.text();
83
- }
84
-
85
- /**
86
- * Execute an array of scripts in sequence inside the proxy.
87
- * External scripts (with src) are fetched first.
88
- *
89
- * @param {Array<{content?: string, src?: string}>} scripts
90
- * @param {string} appName
91
- * @param {Proxy} proxy
92
- * @param {Object} [options]
93
- */
94
- async executeAll(scripts, appName, proxy, options = {}) {
95
- for (const script of scripts) {
96
- let text = script.content;
97
-
98
- if (!text && script.src) {
99
- logger.wuDebug(`[ScriptExecutor] Fetching external script: ${script.src}`);
100
- text = await this.fetchScript(script.src);
101
- }
102
-
103
- if (text && text.trim()) {
104
- this.execute(text, appName, proxy, {
105
- ...options,
106
- sourceUrl: script.src || options.sourceUrl || ''
107
- });
108
- }
109
- }
110
-
111
- logger.wuDebug(`[ScriptExecutor] Executed ${scripts.length} scripts for ${appName}`);
112
- }
113
- }
1
+ /**
2
+ * WU-SCRIPT-EXECUTOR: Execute scripts inside a Proxy sandbox.
3
+ *
4
+ * Two isolation levels:
5
+ * - strictGlobal: true → with(proxy) { code } — all global access goes through proxy
6
+ * - strictGlobal: false → (function(window){ code })(proxy) — only explicit window.xxx
7
+ *
8
+ * This is what makes the sandbox REAL instead of decorative.
9
+ * Without this, import() runs code in global scope and the proxy is just a cleanup tracker.
10
+ * With this, code receives the proxy as "window" and every setTimeout, addEventListener,
11
+ * document.querySelector, localStorage access goes through the proxy's traps.
12
+ */
13
+
14
+ import { logger } from './wu-logger.js';
15
+
16
+ export class WuScriptExecutor {
17
+
18
+ /**
19
+ * Dangerous patterns that indicate prototype pollution, sandbox escape,
20
+ * or direct access to sensitive APIs. Each entry is a regex paired with
21
+ * a human-readable label used in error messages.
22
+ *
23
+ * This is a tripwire, not a full parser. It catches the most common
24
+ * attack vectors without the overhead of AST analysis.
25
+ */
26
+ static DANGEROUS_PATTERNS = [
27
+ // Prototype pollution vectors
28
+ { pattern: /constructor\s*\[\s*['"`]constructor['"`]\s*\]/, label: 'constructor chain access (sandbox escape)' },
29
+ { pattern: /__proto__/, label: '__proto__ access (prototype pollution)' },
30
+
31
+ // Sandbox escape via proxy introspection
32
+ { pattern: /Object\s*\.\s*getPrototypeOf\s*\(\s*proxy\s*\)/, label: 'Object.getPrototypeOf(proxy) (sandbox escape)' },
33
+
34
+ // Dynamic code generation that bypasses the sandbox
35
+ { pattern: /Function\s*\(\s*['"`]/, label: 'Function() constructor (dynamic code generation)' },
36
+ { pattern: /\beval\s*\(/, label: 'eval() (dynamic code execution)' },
37
+
38
+ // Dynamic import escapes the sandbox entirely (runs in global scope)
39
+ { pattern: /\bimport\s*\(/, label: 'import() (dynamic import escapes sandbox)' },
40
+
41
+ // Direct cookie access (should go through proxy traps, not raw document)
42
+ { pattern: /document\s*\.\s*cookie/, label: 'document.cookie (direct cookie access)' },
43
+ ];
44
+
45
+ /**
46
+ * Validate script text against known dangerous patterns before execution.
47
+ * Throws if any pattern matches. This is intentionally lightweight --
48
+ * pattern detection only, not a full parse.
49
+ *
50
+ * @param {string} scriptText - The raw script to validate
51
+ * @param {string} appName - App identifier (for error context)
52
+ * @throws {Error} If a dangerous pattern is detected
53
+ */
54
+ _validateScript(scriptText, appName) {
55
+ for (const { pattern, label } of WuScriptExecutor.DANGEROUS_PATTERNS) {
56
+ if (pattern.test(scriptText)) {
57
+ const msg = `[ScriptExecutor] Blocked dangerous pattern in "${appName}": ${label}`;
58
+ logger.wuError(msg);
59
+ throw new Error(msg);
60
+ }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Execute a script string inside the proxy sandbox.
66
+ *
67
+ * @param {string} scriptText - JavaScript code to execute
68
+ * @param {string} appName - App identifier (for logging)
69
+ * @param {Proxy} proxy - The activated proxy sandbox
70
+ * @param {Object} [options]
71
+ * @param {boolean} [options.strictGlobal=true] - Use with(proxy) for maximum isolation
72
+ * @param {string} [options.sourceUrl=''] - Source URL for devtools (//# sourceURL)
73
+ * @returns {*} Return value of the executed code
74
+ */
75
+ execute(scriptText, appName, proxy, options = {}) {
76
+ const { strictGlobal = true, sourceUrl = '' } = options;
77
+
78
+ if (!scriptText || !scriptText.trim()) return;
79
+
80
+ this._validateScript(scriptText, appName);
81
+
82
+ const sourceComment = sourceUrl ? `\n//# sourceURL=wu-sandbox:///${appName}/${sourceUrl}\n` : '';
83
+
84
+ let wrappedCode;
85
+
86
+ if (strictGlobal) {
87
+ // MAXIMUM ISOLATION
88
+ // with(window) makes ALL unqualified identifiers (setTimeout, fetch, document, etc.)
89
+ // resolve through the proxy's has/get traps, not the real window.
90
+ // Note: 'use strict' inside the with block becomes a no-op string expression,
91
+ // so bundled code with strict mode still works.
92
+ wrappedCode = `;(function(window, self, globalThis, top, parent) {
93
+ with(window) {
94
+ ;${scriptText}${sourceComment}
95
+ }
96
+ }).call(proxy, proxy, proxy, proxy, proxy, proxy);`;
97
+ } else {
98
+ // IIFE ONLY — only explicit window.xxx goes through proxy
99
+ wrappedCode = `;(function(window, self, globalThis, top, parent) {
100
+ ;${scriptText}${sourceComment}
101
+ }).call(proxy, proxy, proxy, proxy, proxy, proxy);`;
102
+ }
103
+
104
+ try {
105
+ // new Function('proxy', code) creates a function with 'proxy' as the single param.
106
+ // This avoids polluting scope — the only bridge to the sandbox is the proxy argument.
107
+ const fn = new Function('proxy', wrappedCode);
108
+ return fn(proxy);
109
+ } catch (error) {
110
+ // If strictGlobal failed (rare edge case with with-statement), retry without it
111
+ if (strictGlobal) {
112
+ logger.wuWarn(`[ScriptExecutor] strictGlobal failed for ${appName}, retrying without with(): ${error.message}`);
113
+ return this.execute(scriptText, appName, proxy, { ...options, strictGlobal: false });
114
+ }
115
+ logger.wuError(`[ScriptExecutor] Execution failed for ${appName}:`, error);
116
+ throw error;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Fetch script content from a URL.
122
+ * @param {string} url - Script URL
123
+ * @returns {Promise<string>} Script text
124
+ */
125
+ async fetchScript(url) {
126
+ const response = await fetch(url);
127
+ if (!response.ok) {
128
+ throw new Error(`Failed to fetch script ${url}: HTTP ${response.status}`);
129
+ }
130
+ return response.text();
131
+ }
132
+
133
+ /**
134
+ * Execute an array of scripts in sequence inside the proxy.
135
+ * External scripts (with src) are fetched first.
136
+ *
137
+ * @param {Array<{content?: string, src?: string}>} scripts
138
+ * @param {string} appName
139
+ * @param {Proxy} proxy
140
+ * @param {Object} [options]
141
+ */
142
+ async executeAll(scripts, appName, proxy, options = {}) {
143
+ for (const script of scripts) {
144
+ let text = script.content;
145
+
146
+ if (!text && script.src) {
147
+ logger.wuDebug(`[ScriptExecutor] Fetching external script: ${script.src}`);
148
+ text = await this.fetchScript(script.src);
149
+ }
150
+
151
+ if (text && text.trim()) {
152
+ this.execute(text, appName, proxy, {
153
+ ...options,
154
+ sourceUrl: script.src || options.sourceUrl || ''
155
+ });
156
+ }
157
+ }
158
+
159
+ logger.wuDebug(`[ScriptExecutor] Executed ${scripts.length} scripts for ${appName}`);
160
+ }
161
+ }