wu-framework 1.2.0 → 2.1.0
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 +99 -18
- package/dist/adapters/alpine/index.js +2 -0
- package/dist/adapters/alpine/index.js.map +1 -0
- package/dist/adapters/angular/index.js +2 -0
- package/dist/adapters/angular/index.js.map +1 -0
- package/dist/adapters/htmx/index.js +2 -0
- package/dist/adapters/htmx/index.js.map +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/lit/index.js +44 -0
- package/dist/adapters/lit/index.js.map +1 -0
- package/dist/adapters/preact/index.js +2 -0
- package/dist/adapters/preact/index.js.map +1 -0
- package/dist/adapters/qwik/index.js +2 -0
- package/dist/adapters/qwik/index.js.map +1 -0
- package/dist/adapters/react/index.js +2 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/shared.js +2 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/adapters/solid/index.js +2 -0
- package/dist/adapters/solid/index.js.map +1 -0
- package/dist/adapters/stencil/index.js +2 -0
- package/dist/adapters/stencil/index.js.map +1 -0
- package/dist/adapters/stimulus/index.js +2 -0
- package/dist/adapters/stimulus/index.js.map +1 -0
- package/dist/adapters/svelte/index.js +2 -0
- package/dist/adapters/svelte/index.js.map +1 -0
- package/dist/adapters/vanilla/index.js +2 -0
- package/dist/adapters/vanilla/index.js.map +1 -0
- package/dist/adapters/vue/index.js +2 -0
- package/dist/adapters/vue/index.js.map +1 -0
- package/dist/ai/wu-ai.js +2 -0
- package/dist/ai/wu-ai.js.map +1 -0
- package/dist/core/wu-mcp-bridge.js +2 -0
- package/dist/core/wu-mcp-bridge.js.map +1 -0
- package/{src → dist}/index.d.ts +445 -317
- package/dist/wu-ai-browser-primitives-BDKXJlwc.js +2 -0
- package/dist/wu-ai-browser-primitives-BDKXJlwc.js.map +1 -0
- package/dist/wu-framework.cjs.js +3 -0
- package/dist/wu-framework.cjs.js.map +1 -0
- package/dist/wu-framework.dev.js +9175 -0
- package/dist/wu-framework.dev.js.map +1 -0
- package/dist/wu-framework.esm.js +3 -0
- package/dist/wu-framework.esm.js.map +1 -0
- package/dist/wu-framework.umd.js +3 -0
- package/dist/wu-framework.umd.js.map +1 -0
- package/dist/wu-html-parser.js +2 -0
- package/dist/wu-html-parser.js.map +1 -0
- package/dist/wu-iframe-sandbox.js +2 -0
- package/dist/wu-iframe-sandbox.js.map +1 -0
- package/dist/wu-logger-fJfUHBGA.js +2 -0
- package/dist/wu-logger-fJfUHBGA.js.map +1 -0
- package/dist/wu-script-executor.js +2 -0
- package/dist/wu-script-executor.js.map +1 -0
- package/package.json +43 -34
- package/src/adapters/alpine/index.js +0 -231
- package/src/adapters/alpine.js +0 -3
- package/src/adapters/angular/ai.js +0 -30
- package/src/adapters/angular/index.js +0 -932
- package/src/adapters/angular.js +0 -3
- package/src/adapters/htmx/index.js +0 -242
- package/src/adapters/htmx.js +0 -3
- package/src/adapters/index.js +0 -225
- package/src/adapters/lit/ai.js +0 -20
- package/src/adapters/lit/index.js +0 -721
- package/src/adapters/lit.js +0 -3
- package/src/adapters/preact/ai.js +0 -33
- package/src/adapters/preact/index.js +0 -661
- package/src/adapters/preact.js +0 -3
- package/src/adapters/qwik/index.js +0 -108
- package/src/adapters/qwik.js +0 -3
- package/src/adapters/react/ai.js +0 -135
- package/src/adapters/react/index.js +0 -695
- package/src/adapters/react.js +0 -3
- package/src/adapters/shared.js +0 -64
- package/src/adapters/solid/ai.js +0 -32
- package/src/adapters/solid/index.js +0 -586
- package/src/adapters/solid.js +0 -3
- package/src/adapters/stencil/index.js +0 -228
- package/src/adapters/stencil.js +0 -3
- package/src/adapters/stimulus/index.js +0 -255
- package/src/adapters/stimulus.js +0 -3
- package/src/adapters/svelte/ai.js +0 -31
- package/src/adapters/svelte/index.js +0 -798
- package/src/adapters/svelte.js +0 -3
- package/src/adapters/vanilla/ai.js +0 -30
- package/src/adapters/vanilla/index.js +0 -785
- package/src/adapters/vanilla.js +0 -3
- package/src/adapters/vue/ai.js +0 -52
- package/src/adapters/vue/index.js +0 -618
- package/src/adapters/vue.js +0 -3
- package/src/ai/wu-ai-actions.js +0 -261
- package/src/ai/wu-ai-agent.js +0 -546
- package/src/ai/wu-ai-browser-primitives.js +0 -354
- package/src/ai/wu-ai-browser.js +0 -380
- package/src/ai/wu-ai-context.js +0 -332
- package/src/ai/wu-ai-conversation.js +0 -613
- package/src/ai/wu-ai-orchestrate.js +0 -1021
- package/src/ai/wu-ai-permissions.js +0 -381
- package/src/ai/wu-ai-provider.js +0 -700
- package/src/ai/wu-ai-schema.js +0 -225
- package/src/ai/wu-ai-triggers.js +0 -396
- package/src/ai/wu-ai.js +0 -804
- package/src/core/wu-app.js +0 -236
- package/src/core/wu-cache.js +0 -498
- package/src/core/wu-core.js +0 -1412
- package/src/core/wu-error-boundary.js +0 -396
- package/src/core/wu-event-bus.js +0 -390
- package/src/core/wu-hooks.js +0 -350
- package/src/core/wu-html-parser.js +0 -199
- package/src/core/wu-iframe-sandbox.js +0 -328
- package/src/core/wu-loader.js +0 -385
- package/src/core/wu-logger.js +0 -143
- package/src/core/wu-manifest.js +0 -533
- package/src/core/wu-mcp-bridge.js +0 -432
- package/src/core/wu-overrides.js +0 -510
- package/src/core/wu-performance.js +0 -228
- package/src/core/wu-plugin.js +0 -401
- package/src/core/wu-prefetch.js +0 -414
- package/src/core/wu-proxy-sandbox.js +0 -477
- package/src/core/wu-sandbox.js +0 -779
- package/src/core/wu-script-executor.js +0 -161
- package/src/core/wu-snapshot-sandbox.js +0 -227
- package/src/core/wu-store.js +0 -307
- package/src/core/wu-strategies.js +0 -256
- package/src/core/wu-style-bridge.js +0 -477
- package/src/index.js +0 -234
- package/src/utils/dependency-resolver.js +0 -328
- /package/{src → dist}/adapters/alpine/index.d.ts +0 -0
- /package/{src → dist}/adapters/alpine.d.ts +0 -0
- /package/{src → dist}/adapters/angular/index.d.ts +0 -0
- /package/{src → dist}/adapters/angular.d.ts +0 -0
- /package/{src → dist}/adapters/htmx/index.d.ts +0 -0
- /package/{src → dist}/adapters/htmx.d.ts +0 -0
- /package/{src → dist}/adapters/lit/index.d.ts +0 -0
- /package/{src → dist}/adapters/lit.d.ts +0 -0
- /package/{src → dist}/adapters/preact/index.d.ts +0 -0
- /package/{src → dist}/adapters/preact.d.ts +0 -0
- /package/{src → dist}/adapters/qwik/index.d.ts +0 -0
- /package/{src → dist}/adapters/qwik.d.ts +0 -0
- /package/{src → dist}/adapters/react/index.d.ts +0 -0
- /package/{src → dist}/adapters/react.d.ts +0 -0
- /package/{src → dist}/adapters/solid/index.d.ts +0 -0
- /package/{src → dist}/adapters/solid.d.ts +0 -0
- /package/{src → dist}/adapters/stencil/index.d.ts +0 -0
- /package/{src → dist}/adapters/stencil.d.ts +0 -0
- /package/{src → dist}/adapters/stimulus/index.d.ts +0 -0
- /package/{src → dist}/adapters/stimulus.d.ts +0 -0
- /package/{src → dist}/adapters/svelte/index.d.ts +0 -0
- /package/{src → dist}/adapters/svelte.d.ts +0 -0
- /package/{src → dist}/adapters/vanilla/index.d.ts +0 -0
- /package/{src → dist}/adapters/vanilla.d.ts +0 -0
- /package/{src → dist}/adapters/vue/index.d.ts +0 -0
- /package/{src → dist}/adapters/vue.d.ts +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{l as t}from"./wu-logger-fJfUHBGA.js";class e{constructor(){this._cache=new Map}async fetchHtml(e,r){t.wuDebug(`[HtmlParser] Fetching HTML for ${r} from ${e}`);const s=await fetch(e,{method:"GET",headers:{Accept:"text/html,application/xhtml+xml,*/*"}});if(!s.ok)throw new Error(`[HtmlParser] Failed to fetch ${e}: HTTP ${s.status}`);const n=await s.text();if(!n||!n.trim())throw new Error(`[HtmlParser] Empty HTML response from ${e}`);return t.wuDebug(`[HtmlParser] Fetched ${n.length} chars for ${r}`),n}parse(e,r,s){const n=`${r}:${e.length}`;if(this._cache.has(n))return this._cache.get(n);const c=(new DOMParser).parseFromString(e,"text/html"),i=[],l=[],a=[],o=[],h={inlineScripts:i,externalScripts:l,inlineStyles:a,externalStyles:o,baseUrl:s};c.head&&this._extractResources(c.head,h);const u=c.body||c.documentElement;this._extractResources(u,h);const m={dom:u.innerHTML,scripts:{inline:i,external:l},styles:{inline:a,external:o}};return this._cache.set(n,m),t.wuDebug(`[HtmlParser] ${r}: ${i.length} inline scripts, ${l.length} external scripts, ${a.length+o.length} styles`),m}async fetchAndParse(t,e){const r=await this.fetchHtml(t,e);return this.parse(r,e,t)}_extractResources(t,e){const r=Array.from(t.children);for(const t of r){const r=t.nodeName.toLowerCase();if("script"!==r){if("style"===r){const r=t.textContent?.trim();r&&e.inlineStyles.push(r),t.replaceWith(document.createComment("wu:style"));continue}if("link"===r){const r=t.getAttribute("rel"),s=t.getAttribute("href");if("stylesheet"===r&&s){e.externalStyles.push(this._resolveUrl(s,e.baseUrl)),t.replaceWith(document.createComment("wu:link"));continue}}t.children.length>0&&this._extractResources(t,e)}else this._extractScript(t,e),t.replaceWith(document.createComment("wu:script"))}}_extractScript(e,r){const s=e.getAttribute("type")||"",n=e.getAttribute("src");if("module"!==s)if(n)r.externalScripts.push(this._resolveUrl(n,r.baseUrl));else{const t=e.textContent?.trim();t&&r.inlineScripts.push(t)}else t.wuDebug('[HtmlParser] Skipping type="module" script (use sandbox: "module" for ES modules)')}_resolveUrl(t,e){if(t.startsWith("http://")||t.startsWith("https://"))return t;if(t.startsWith("//"))return`https:${t}`;try{return new URL(t,e).href}catch{const r=e.replace(/\/$/,"");return t.startsWith("/")?r+t:`${r}/${t}`}}clearCache(){this._cache.clear()}}export{e as WuHtmlParser};
|
|
2
|
+
//# sourceMappingURL=wu-html-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wu-html-parser.js","sources":["../src/core/wu-html-parser.js"],"sourcesContent":["/**\r\n * WU-HTML-PARSER: Fetch and parse HTML entries from micro-apps.\r\n *\r\n * Used in \"strict\" sandbox mode. The flow:\r\n * 1. Fetch the HTML page at the app's URL\r\n * 2. Parse it: extract inline/external scripts, inline/external styles, and clean DOM\r\n * 3. Return structured result so wu-core can inject DOM + styles into Shadow DOM\r\n * and execute scripts inside the proxy sandbox via WuScriptExecutor.\r\n *\r\n * This is the qiankun-style \"HTML entry\" approach that enables real JS isolation.\r\n */\r\n\r\nimport { logger } from './wu-logger.js';\r\n\r\nexport class WuHtmlParser {\r\n constructor() {\r\n this._cache = new Map();\r\n }\r\n\r\n /**\r\n * Fetch HTML content from a URL.\r\n * @param {string} url - App URL (e.g. http://localhost:3001)\r\n * @param {string} appName - For logging\r\n * @returns {Promise<string>} Raw HTML string\r\n */\r\n async fetchHtml(url, appName) {\r\n logger.wuDebug(`[HtmlParser] Fetching HTML for ${appName} from ${url}`);\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n headers: { 'Accept': 'text/html,application/xhtml+xml,*/*' }\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`[HtmlParser] Failed to fetch ${url}: HTTP ${response.status}`);\r\n }\r\n\r\n const html = await response.text();\r\n if (!html || !html.trim()) {\r\n throw new Error(`[HtmlParser] Empty HTML response from ${url}`);\r\n }\r\n\r\n logger.wuDebug(`[HtmlParser] Fetched ${html.length} chars for ${appName}`);\r\n return html;\r\n }\r\n\r\n /**\r\n * Parse HTML string into structured parts.\r\n *\r\n * @param {string} html - Raw HTML\r\n * @param {string} appName - App identifier\r\n * @param {string} baseUrl - Base URL for resolving relative paths\r\n * @returns {{\r\n * dom: string,\r\n * scripts: { inline: string[], external: string[] },\r\n * styles: { inline: string[], external: string[] }\r\n * }}\r\n */\r\n parse(html, appName, baseUrl) {\r\n const cacheKey = `${appName}:${html.length}`;\r\n if (this._cache.has(cacheKey)) {\r\n return this._cache.get(cacheKey);\r\n }\r\n\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(html, 'text/html');\r\n\r\n const inlineScripts = [];\r\n const externalScripts = [];\r\n const inlineStyles = [];\r\n const externalStyles = [];\r\n\r\n const ctx = {\r\n inlineScripts, externalScripts,\r\n inlineStyles, externalStyles,\r\n baseUrl\r\n };\r\n\r\n // DOMParser moves <style>, <link>, and some <script> tags to <head>.\r\n // Extract resources from both head and body to capture everything.\r\n if (doc.head) {\r\n this._extractResources(doc.head, ctx);\r\n }\r\n\r\n const temp = doc.body || doc.documentElement;\r\n this._extractResources(temp, ctx);\r\n\r\n const result = {\r\n dom: temp.innerHTML,\r\n scripts: { inline: inlineScripts, external: externalScripts },\r\n styles: { inline: inlineStyles, external: externalStyles }\r\n };\r\n\r\n this._cache.set(cacheKey, result);\r\n\r\n logger.wuDebug(\r\n `[HtmlParser] ${appName}: ${inlineScripts.length} inline scripts, ` +\r\n `${externalScripts.length} external scripts, ` +\r\n `${inlineStyles.length + externalStyles.length} styles`\r\n );\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Convenience: fetch + parse in one call.\r\n */\r\n async fetchAndParse(url, appName) {\r\n const html = await this.fetchHtml(url, appName);\r\n return this.parse(html, appName, url);\r\n }\r\n\r\n /**\r\n * Recursively walk the DOM, extracting scripts and styles,\r\n * replacing them with comments to keep the DOM clean.\r\n */\r\n _extractResources(element, ctx) {\r\n // Iterate over a static copy since we mutate the DOM\r\n const children = Array.from(element.children);\r\n\r\n for (const child of children) {\r\n const tag = child.nodeName.toLowerCase();\r\n\r\n if (tag === 'script') {\r\n this._extractScript(child, ctx);\r\n child.replaceWith(document.createComment('wu:script'));\r\n continue;\r\n }\r\n\r\n if (tag === 'style') {\r\n const text = child.textContent?.trim();\r\n if (text) ctx.inlineStyles.push(text);\r\n child.replaceWith(document.createComment('wu:style'));\r\n continue;\r\n }\r\n\r\n if (tag === 'link') {\r\n const rel = child.getAttribute('rel');\r\n const href = child.getAttribute('href');\r\n if (rel === 'stylesheet' && href) {\r\n ctx.externalStyles.push(this._resolveUrl(href, ctx.baseUrl));\r\n child.replaceWith(document.createComment('wu:link'));\r\n continue;\r\n }\r\n }\r\n\r\n // Recurse into children\r\n if (child.children.length > 0) {\r\n this._extractResources(child, ctx);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Extract a <script> tag into inline or external list.\r\n * Skips type=\"module\" scripts (they can't be eval'd — use module mode for those).\r\n */\r\n _extractScript(el, ctx) {\r\n const type = el.getAttribute('type') || '';\r\n const src = el.getAttribute('src');\r\n\r\n // Module scripts can't be executed via new Function / eval.\r\n // If the app uses ES modules, it should use sandbox: 'module' mode.\r\n if (type === 'module') {\r\n logger.wuDebug('[HtmlParser] Skipping type=\"module\" script (use sandbox: \"module\" for ES modules)');\r\n return;\r\n }\r\n\r\n if (src) {\r\n ctx.externalScripts.push(this._resolveUrl(src, ctx.baseUrl));\r\n } else {\r\n const text = el.textContent?.trim();\r\n if (text) ctx.inlineScripts.push(text);\r\n }\r\n }\r\n\r\n /**\r\n * Resolve a relative URL against a base URL.\r\n */\r\n _resolveUrl(url, baseUrl) {\r\n if (url.startsWith('http://') || url.startsWith('https://')) return url;\r\n if (url.startsWith('//')) return `https:${url}`;\r\n\r\n try {\r\n return new URL(url, baseUrl).href;\r\n } catch {\r\n // Fallback for environments without URL constructor\r\n const base = baseUrl.replace(/\\/$/, '');\r\n return url.startsWith('/') ? base + url : `${base}/${url}`;\r\n }\r\n }\r\n\r\n /**\r\n * Clear the parse cache.\r\n */\r\n clearCache() {\r\n this._cache.clear();\r\n }\r\n}\r\n"],"names":["WuHtmlParser","constructor","this","_cache","Map","fetchHtml","url","appName","logger","wuDebug","response","fetch","method","headers","Accept","ok","Error","status","html","text","trim","length","parse","baseUrl","cacheKey","has","get","doc","DOMParser","parseFromString","inlineScripts","externalScripts","inlineStyles","externalStyles","ctx","head","_extractResources","temp","body","documentElement","result","dom","innerHTML","scripts","inline","external","styles","set","fetchAndParse","element","children","Array","from","child","tag","nodeName","toLowerCase","textContent","push","replaceWith","document","createComment","rel","getAttribute","href","_resolveUrl","_extractScript","el","type","src","startsWith","URL","base","replace","clearCache","clear"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{l as e}from"./wu-logger-fJfUHBGA.js";class t{constructor(e){this.appName=e,this.iframe=null,this._active=!1,this._timers=new Set,this._intervals=new Set,this._rafs=new Set,this._listeners=[]}activate(t,r,n){if(this._active)return this.iframe.contentWindow;const i=document.createElement("iframe");i.setAttribute("data-wu-sandbox",this.appName),i.style.cssText="display:none !important;position:absolute;width:0;height:0;border:0;",document.body.appendChild(i),this.iframe=i;const a=t.replace(/\/$/,""),s=i.contentWindow,o=s.document;return o.open(),o.write(`<!DOCTYPE html><html><head><base href="${a}/"></head><body></body></html>`),o.close(),s.wu=this._buildRestrictedWu(window.wu),this._patchDocument(s,r,n),this._patchTimers(s),this._active=!0,e.wuDebug(`[IframeSandbox] Activated for ${this.appName} (base: ${a})`),s}_buildRestrictedWu(e){if(!e)return;const t=t=>"function"==typeof t?t.bind(e):t,r=e.store?Object.freeze({get:t(e.store.get),set:t(e.store.set),on:t(e.store.on),batch:t(e.store.batch)}):null,n=e.eventBus?Object.freeze({emit:t(e.eventBus.emit),on:t(e.eventBus.on),off:t(e.eventBus.off),once:t(e.eventBus.once),registerApp:t(e.eventBus.registerApp),unregisterApp:t(e.eventBus.unregisterApp)}):null,i={version:e.version,info:e.info,_isWuFramework:!0,define:t(e.define),mount:t(e.mount),unmount:t(e.unmount),app:t(e.app),hide:t(e.hide),show:t(e.show),isHidden:t(e.isHidden),store:r,eventBus:n,emit:t(e.emit),on:t(e.on),off:t(e.off),once:t(e.once),getState:t(e.getState),setState:t(e.setState),onStateChange:t(e.onStateChange),ai:e.ai,aiReady:t(e.aiReady),getStats:t(e.getStats),getSandboxInfo:t(e.getSandboxInfo),silence:t(e.silence),verbose:t(e.verbose)};return Object.freeze(i)}importModule(t,r=3e4){if(!this._active)throw new Error(`[IframeSandbox] Not active for ${this.appName}`);return new Promise((n,i)=>{const a=`wu_${this.appName}_${Date.now()}`,s=e=>{e.data?.channelId===a&&(c(),e.data.error?i(new Error(e.data.error)):n())},o=setTimeout(()=>{c(),i(new Error(`[IframeSandbox] import() timed out for ${this.appName}: ${t}`))},r),c=()=>{window.removeEventListener("message",s),clearTimeout(o)};window.addEventListener("message",s);const m=this.iframe.contentWindow.document,d=m.createElement("script");d.type="module",d.textContent=`import("${t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}").then(() => parent.postMessage({ channelId: "${a}", success: true }, '*')).catch(e => parent.postMessage({ channelId: "${a}", error: e.message || String(e) }, '*'));`,m.head.appendChild(d),e.wuDebug(`[IframeSandbox] Importing module: ${t}`)})}_patchDocument(t,r,n){const i=t.document,a=n||r,s=document;i.createElement=(e,t)=>s.createElement(e,t),i.createElementNS=(e,t,r)=>s.createElementNS(e,t,r),i.createTextNode=e=>s.createTextNode(e),i.createComment=e=>s.createComment(e),i.createDocumentFragment=()=>s.createDocumentFragment(),i.querySelector=e=>a.querySelector(e),i.querySelectorAll=e=>a.querySelectorAll(e),i.getElementById=e=>a.querySelector(`#${e}`),i.getElementsByClassName=e=>a.querySelectorAll(`.${e}`),i.getElementsByTagName=e=>a.querySelectorAll(e);try{Object.defineProperty(i,"body",{get:()=>r,configurable:!0})}catch{e.wuDebug("[IframeSandbox] Could not redefine document.body")}const o=i.addEventListener.bind(i),c=i.removeEventListener.bind(i);i.addEventListener=(e,t,r)=>{this._listeners.push({target:i,event:e,handler:t,options:r}),o(e,t,r)},i.removeEventListener=(e,t,r)=>{this._listeners=this._listeners.filter(r=>!(r.target===i&&r.event===e&&r.handler===t)),c(e,t,r)},e.wuDebug(`[IframeSandbox] Document patched for ${this.appName}`)}_patchTimers(t){const r=t.setTimeout.bind(t),n=t.clearTimeout.bind(t),i=t.setInterval.bind(t),a=t.clearInterval.bind(t);if(t.setTimeout=(e,t,...n)=>{const i=r((...t)=>{this._timers.delete(i),"function"==typeof e&&e(...t)},t,...n);return this._timers.add(i),i},t.clearTimeout=e=>{this._timers.delete(e),n(e)},t.setInterval=(e,t,...r)=>{const n=i(e,t,...r);return this._intervals.add(n),n},t.clearInterval=e=>{this._intervals.delete(e),a(e)},t.requestAnimationFrame){const e=t.requestAnimationFrame.bind(t),r=t.cancelAnimationFrame.bind(t);t.requestAnimationFrame=t=>{const r=e((...e)=>{this._rafs.delete(r),t(...e)});return this._rafs.add(r),r},t.cancelAnimationFrame=e=>{this._rafs.delete(e),r(e)}}e.wuDebug(`[IframeSandbox] Timer tracking active for ${this.appName}`)}destroy(){if(this._active){this._active=!1;for(const e of this._timers)try{clearTimeout(e)}catch{}for(const e of this._intervals)try{clearInterval(e)}catch{}for(const e of this._rafs)try{cancelAnimationFrame(e)}catch{}this._timers.clear(),this._intervals.clear(),this._rafs.clear();for(const{target:e,event:t,handler:r,options:n}of this._listeners)try{e.removeEventListener(t,r,n)}catch{}if(this._listeners=[],this.iframe){try{const e=this.iframe.contentDocument;e&&(e.open(),e.write(""),e.close())}catch{}this.iframe.parentNode&&this.iframe.parentNode.removeChild(this.iframe),this.iframe=null}e.wuDebug(`[IframeSandbox] Destroyed for ${this.appName}`)}}isActive(){return this._active}}export{t as WuIframeSandbox};
|
|
2
|
+
//# sourceMappingURL=wu-iframe-sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wu-iframe-sandbox.js","sources":["../src/core/wu-iframe-sandbox.js"],"sourcesContent":["/**\r\n * WU-IFRAME-SANDBOX: Real JS isolation using hidden iframes.\r\n *\r\n * Architecture:\r\n * ┌── Main Window ────────────────────────────────┐\r\n * │ ┌── Shadow DOM Container ──────────────────┐ │\r\n * │ │ App renders here (CSS isolated) │ │\r\n * │ └──────────────────────────────────────────┘ │\r\n * │ ┌── Hidden iframe ────────────────────────┐ │\r\n * │ │ import() runs here (REAL modules) │ │\r\n * │ │ window = iframe.contentWindow (ISOLATED)│ │\r\n * │ │ document patched → Shadow DOM │ │\r\n * │ └────────────────────────────────────────-─┘ │\r\n * └───────────────────────────────────────────────┘\r\n *\r\n * Why iframe?\r\n * - import() is REAL → tree shaking, source maps, HMR all work\r\n * - iframe has its own window → globals are isolated\r\n * - Destroying iframe kills all timers/listeners at once\r\n *\r\n * How it works:\r\n * 1. Create hidden iframe with <base href=\"appUrl\"> for URL resolution\r\n * 2. Patch iframe's document: createElement → main document (no ownerDocument issues),\r\n * querySelector/body → Shadow DOM container\r\n * 3. Track timers for guaranteed cleanup (some browsers don't kill iframe timers)\r\n * 4. import() the app module inside iframe → runs in isolated context\r\n * 5. App calls wu.define() → lifecycle registered on parent's WuCore\r\n * 6. On unmount: destroy iframe = nuclear cleanup\r\n *\r\n * Fallback:\r\n * If import() fails (CORS, module errors), wu-core falls back to eval mode\r\n * (fetch HTML + parse + execute with(proxy)).\r\n */\r\n\r\nimport { logger } from './wu-logger.js';\r\n\r\nexport class WuIframeSandbox {\r\n constructor(appName) {\r\n this.appName = appName;\r\n this.iframe = null;\r\n this._active = false;\r\n\r\n // Side-effect tracking for guaranteed cleanup\r\n this._timers = new Set();\r\n this._intervals = new Set();\r\n this._rafs = new Set();\r\n this._listeners = [];\r\n }\r\n\r\n /**\r\n * Create and activate the iframe sandbox.\r\n *\r\n * @param {string} appUrl - App's base URL (for <base href> and relative imports)\r\n * @param {HTMLElement} shadowContainer - Shadow DOM container for DOM redirection\r\n * @param {ShadowRoot|null} shadowRoot - Shadow root for query scoping\r\n * @returns {Window} The iframe's contentWindow (isolated execution context)\r\n */\r\n activate(appUrl, shadowContainer, shadowRoot) {\r\n if (this._active) return this.iframe.contentWindow;\r\n\r\n // 1. Create hidden iframe\r\n const iframe = document.createElement('iframe');\r\n iframe.setAttribute('data-wu-sandbox', this.appName);\r\n iframe.style.cssText = 'display:none !important;position:absolute;width:0;height:0;border:0;';\r\n\r\n // Must be in DOM before accessing contentWindow\r\n document.body.appendChild(iframe);\r\n this.iframe = iframe;\r\n\r\n // 2. Write base HTML with <base href> pointing to app URL.\r\n // This makes relative URL resolution work for fetch(), CSS url(), etc.\r\n // import() of full URLs works regardless of base.\r\n const baseUrl = appUrl.replace(/\\/$/, '');\r\n const iframeWin = iframe.contentWindow;\r\n const iframeDoc = iframeWin.document;\r\n\r\n iframeDoc.open();\r\n iframeDoc.write(\r\n `<!DOCTYPE html><html><head><base href=\"${baseUrl}/\"></head><body></body></html>`\r\n );\r\n iframeDoc.close();\r\n\r\n // 3. Expose a RESTRICTED wu inside the iframe.\r\n //\r\n // Pre-v2.1 we leaked the full `window.wu` — meaning sandboxed app code\r\n // could touch internals like wu.core, wu.cache, wu.errorBoundary,\r\n // wu.pluginSystem, etc. That defeats much of the iframe isolation.\r\n //\r\n // Now we expose only the public surface an app legitimately needs:\r\n // - lifecycle: define, mount, unmount, app, hide, show, isHidden\r\n // - communication: emit, on, off, once\r\n // - state: store (get/set/on), getState/setState/onStateChange\r\n // - AI: ai (lazy proxy, already locked down)\r\n // - meta: version, info, getStats, getSandboxInfo\r\n // - logger: silence, verbose\r\n iframeWin.wu = this._buildRestrictedWu(window.wu);\r\n\r\n // 4. Patch document: redirect DOM operations to Shadow DOM\r\n this._patchDocument(iframeWin, shadowContainer, shadowRoot);\r\n\r\n // 5. Track timers for guaranteed cleanup\r\n this._patchTimers(iframeWin);\r\n\r\n this._active = true;\r\n logger.wuDebug(`[IframeSandbox] Activated for ${this.appName} (base: ${baseUrl})`);\r\n return iframeWin;\r\n }\r\n\r\n /**\r\n * Build a Object.freeze'd, restricted view of `window.wu` for exposing\r\n * inside the iframe. Methods are bound so the app can call them naturally\r\n * (no need to `wu.emit.bind(wu)`); internals are hidden.\r\n *\r\n * @param {object} fullWu - The full framework instance (window.wu)\r\n * @returns {Readonly<object>} Frozen restricted facade\r\n * @private\r\n */\r\n _buildRestrictedWu(fullWu) {\r\n // Tests and SSR-like setups may have no global wu — keep the surface\r\n // optional rather than crashing during activate().\r\n if (!fullWu) return undefined;\r\n\r\n const bind = (fn) => (typeof fn === 'function' ? fn.bind(fullWu) : fn);\r\n\r\n // Wrap nested store so we don't expose its internals (ringbuffer, listeners Map)\r\n const storeFacade = fullWu.store ? Object.freeze({\r\n get: bind(fullWu.store.get),\r\n set: bind(fullWu.store.set),\r\n on: bind(fullWu.store.on),\r\n batch: bind(fullWu.store.batch),\r\n }) : null;\r\n\r\n // EventBus facade: expose pub/sub but not internals (authorizedApps, history, _internalTokens)\r\n const eventBusFacade = fullWu.eventBus ? Object.freeze({\r\n emit: bind(fullWu.eventBus.emit),\r\n on: bind(fullWu.eventBus.on),\r\n off: bind(fullWu.eventBus.off),\r\n once: bind(fullWu.eventBus.once),\r\n registerApp: bind(fullWu.eventBus.registerApp),\r\n unregisterApp: bind(fullWu.eventBus.unregisterApp),\r\n }) : null;\r\n\r\n const facade = {\r\n // Identity\r\n version: fullWu.version,\r\n info: fullWu.info,\r\n _isWuFramework: true,\r\n // Lifecycle the app needs to register itself\r\n define: bind(fullWu.define),\r\n mount: bind(fullWu.mount),\r\n unmount: bind(fullWu.unmount),\r\n app: bind(fullWu.app),\r\n hide: bind(fullWu.hide),\r\n show: bind(fullWu.show),\r\n isHidden: bind(fullWu.isHidden),\r\n // Sub-objects (restricted facades, not raw refs)\r\n store: storeFacade,\r\n eventBus: eventBusFacade,\r\n // Top-level pub/sub shortcuts\r\n emit: bind(fullWu.emit),\r\n on: bind(fullWu.on),\r\n off: bind(fullWu.off),\r\n once: bind(fullWu.once),\r\n // Store shortcuts (read/write only)\r\n getState: bind(fullWu.getState),\r\n setState: bind(fullWu.setState),\r\n onStateChange: bind(fullWu.onStateChange),\r\n // AI proxy is already lazy-loaded + restricted by setupLazyAi\r\n ai: fullWu.ai,\r\n aiReady: bind(fullWu.aiReady),\r\n // Meta\r\n getStats: bind(fullWu.getStats),\r\n getSandboxInfo: bind(fullWu.getSandboxInfo),\r\n // Logging control\r\n silence: bind(fullWu.silence),\r\n verbose: bind(fullWu.verbose),\r\n };\r\n\r\n return Object.freeze(facade);\r\n }\r\n\r\n /**\r\n * Import an ES module inside the iframe via real import().\r\n * Preserves tree shaking, source maps, and Vite HMR.\r\n *\r\n * @param {string} url - Full module URL to import\r\n * @param {number} [timeout=30000] - Max wait time in ms\r\n * @returns {Promise<void>}\r\n */\r\n importModule(url, timeout = 30000) {\r\n if (!this._active) {\r\n throw new Error(`[IframeSandbox] Not active for ${this.appName}`);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const channelId = `wu_${this.appName}_${Date.now()}`;\r\n\r\n // Listen for import completion via postMessage\r\n const onMessage = (event) => {\r\n if (event.data?.channelId !== channelId) return;\r\n cleanup();\r\n if (event.data.error) {\r\n reject(new Error(event.data.error));\r\n } else {\r\n resolve();\r\n }\r\n };\r\n\r\n const timer = setTimeout(() => {\r\n cleanup();\r\n reject(new Error(\r\n `[IframeSandbox] import() timed out for ${this.appName}: ${url}`\r\n ));\r\n }, timeout);\r\n\r\n const cleanup = () => {\r\n window.removeEventListener('message', onMessage);\r\n clearTimeout(timer);\r\n };\r\n\r\n window.addEventListener('message', onMessage);\r\n\r\n // Inject module script into iframe\r\n const iframeDoc = this.iframe.contentWindow.document;\r\n const script = iframeDoc.createElement('script');\r\n script.type = 'module';\r\n script.textContent =\r\n `import(\"${url.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\")` +\r\n `.then(() => parent.postMessage({ channelId: \"${channelId}\", success: true }, '*'))` +\r\n `.catch(e => parent.postMessage({ channelId: \"${channelId}\", error: e.message || String(e) }, '*'));`;\r\n\r\n iframeDoc.head.appendChild(script);\r\n logger.wuDebug(`[IframeSandbox] Importing module: ${url}`);\r\n });\r\n }\r\n\r\n /**\r\n * Patch the iframe's document to redirect DOM operations.\r\n *\r\n * Critical patches:\r\n * - createElement/createTextNode → main document (avoids ownerDocument mismatch)\r\n * React/Vue create nodes and append to Shadow DOM container.\r\n * Nodes must belong to the main document to avoid cross-document adoption issues.\r\n *\r\n * - querySelector/body → Shadow DOM container\r\n * Libraries that query the document will find app elements in the Shadow DOM.\r\n *\r\n * - addEventListener → tracked for cleanup\r\n */\r\n _patchDocument(iframeWin, shadowContainer, shadowRoot) {\r\n const iframeDoc = iframeWin.document;\r\n const queryTarget = shadowRoot || shadowContainer;\r\n const mainDoc = document; // parent document\r\n\r\n // --- Node creation: use main document to avoid ownerDocument mismatch ---\r\n // React uses container.ownerDocument.createElement() internally,\r\n // but other code might use document.createElement() directly.\r\n // By redirecting to main document, all nodes belong to the same document tree.\r\n iframeDoc.createElement = (tag, options) => mainDoc.createElement(tag, options);\r\n iframeDoc.createElementNS = (ns, tag, options) => mainDoc.createElementNS(ns, tag, options);\r\n iframeDoc.createTextNode = (text) => mainDoc.createTextNode(text);\r\n iframeDoc.createComment = (text) => mainDoc.createComment(text);\r\n iframeDoc.createDocumentFragment = () => mainDoc.createDocumentFragment();\r\n\r\n // --- DOM queries: redirect to Shadow DOM ---\r\n iframeDoc.querySelector = (sel) => queryTarget.querySelector(sel);\r\n iframeDoc.querySelectorAll = (sel) => queryTarget.querySelectorAll(sel);\r\n iframeDoc.getElementById = (id) => queryTarget.querySelector(`#${id}`);\r\n iframeDoc.getElementsByClassName = (cls) => queryTarget.querySelectorAll(`.${cls}`);\r\n iframeDoc.getElementsByTagName = (tag) => queryTarget.querySelectorAll(tag);\r\n\r\n // --- document.body → shadow container ---\r\n // Frameworks that append to document.body (portals, modals) will target the Shadow DOM.\r\n try {\r\n Object.defineProperty(iframeDoc, 'body', {\r\n get: () => shadowContainer,\r\n configurable: true\r\n });\r\n } catch {\r\n // Some environments don't allow redefining body — not critical\r\n logger.wuDebug('[IframeSandbox] Could not redefine document.body');\r\n }\r\n\r\n // --- document.addEventListener: track for cleanup ---\r\n const origDocAdd = iframeDoc.addEventListener.bind(iframeDoc);\r\n const origDocRemove = iframeDoc.removeEventListener.bind(iframeDoc);\r\n\r\n iframeDoc.addEventListener = (event, handler, options) => {\r\n this._listeners.push({ target: iframeDoc, event, handler, options });\r\n origDocAdd(event, handler, options);\r\n };\r\n\r\n iframeDoc.removeEventListener = (event, handler, options) => {\r\n this._listeners = this._listeners.filter(\r\n l => !(l.target === iframeDoc && l.event === event && l.handler === handler)\r\n );\r\n origDocRemove(event, handler, options);\r\n };\r\n\r\n logger.wuDebug(`[IframeSandbox] Document patched for ${this.appName}`);\r\n }\r\n\r\n /**\r\n * Patch timers in the iframe for guaranteed cleanup.\r\n * Some browsers don't fully kill timers when an iframe is removed.\r\n * We track all IDs and clear them explicitly on destroy.\r\n */\r\n _patchTimers(iframeWin) {\r\n const origSetTimeout = iframeWin.setTimeout.bind(iframeWin);\r\n const origClearTimeout = iframeWin.clearTimeout.bind(iframeWin);\r\n const origSetInterval = iframeWin.setInterval.bind(iframeWin);\r\n const origClearInterval = iframeWin.clearInterval.bind(iframeWin);\r\n\r\n iframeWin.setTimeout = (fn, ms, ...args) => {\r\n const id = origSetTimeout((...a) => {\r\n this._timers.delete(id);\r\n if (typeof fn === 'function') fn(...a);\r\n }, ms, ...args);\r\n this._timers.add(id);\r\n return id;\r\n };\r\n\r\n iframeWin.clearTimeout = (id) => {\r\n this._timers.delete(id);\r\n origClearTimeout(id);\r\n };\r\n\r\n iframeWin.setInterval = (fn, ms, ...args) => {\r\n const id = origSetInterval(fn, ms, ...args);\r\n this._intervals.add(id);\r\n return id;\r\n };\r\n\r\n iframeWin.clearInterval = (id) => {\r\n this._intervals.delete(id);\r\n origClearInterval(id);\r\n };\r\n\r\n // requestAnimationFrame may not exist in all iframe contexts\r\n if (iframeWin.requestAnimationFrame) {\r\n const origRAF = iframeWin.requestAnimationFrame.bind(iframeWin);\r\n const origCancelRAF = iframeWin.cancelAnimationFrame.bind(iframeWin);\r\n\r\n iframeWin.requestAnimationFrame = (fn) => {\r\n const id = origRAF((...a) => {\r\n this._rafs.delete(id);\r\n fn(...a);\r\n });\r\n this._rafs.add(id);\r\n return id;\r\n };\r\n\r\n iframeWin.cancelAnimationFrame = (id) => {\r\n this._rafs.delete(id);\r\n origCancelRAF(id);\r\n };\r\n }\r\n\r\n logger.wuDebug(`[IframeSandbox] Timer tracking active for ${this.appName}`);\r\n }\r\n\r\n /**\r\n * Destroy the iframe and all side effects.\r\n * Nuclear cleanup: kills everything at once.\r\n */\r\n destroy() {\r\n if (!this._active) return;\r\n this._active = false;\r\n\r\n // 1. Clear all tracked timers\r\n for (const id of this._timers) { try { clearTimeout(id); } catch {} }\r\n for (const id of this._intervals) { try { clearInterval(id); } catch {} }\r\n for (const id of this._rafs) { try { cancelAnimationFrame(id); } catch {} }\r\n this._timers.clear();\r\n this._intervals.clear();\r\n this._rafs.clear();\r\n\r\n // 2. Remove all tracked event listeners\r\n for (const { target, event, handler, options } of this._listeners) {\r\n try { target.removeEventListener(event, handler, options); } catch {}\r\n }\r\n this._listeners = [];\r\n\r\n // 3. Wipe and remove iframe\r\n if (this.iframe) {\r\n try {\r\n const doc = this.iframe.contentDocument;\r\n if (doc) {\r\n doc.open();\r\n doc.write('');\r\n doc.close();\r\n }\r\n } catch {\r\n // Cross-origin or already detached — ignore\r\n }\r\n\r\n if (this.iframe.parentNode) {\r\n this.iframe.parentNode.removeChild(this.iframe);\r\n }\r\n this.iframe = null;\r\n }\r\n\r\n logger.wuDebug(`[IframeSandbox] Destroyed for ${this.appName}`);\r\n }\r\n\r\n /**\r\n * Check if this sandbox is active.\r\n * @returns {boolean}\r\n */\r\n isActive() {\r\n return this._active;\r\n }\r\n}\r\n"],"names":["WuIframeSandbox","constructor","appName","this","iframe","_active","_timers","Set","_intervals","_rafs","_listeners","activate","appUrl","shadowContainer","shadowRoot","contentWindow","document","createElement","setAttribute","style","cssText","body","appendChild","baseUrl","replace","iframeWin","iframeDoc","open","write","close","wu","_buildRestrictedWu","window","_patchDocument","_patchTimers","logger","wuDebug","fullWu","bind","fn","storeFacade","store","Object","freeze","get","set","on","batch","eventBusFacade","eventBus","emit","off","once","registerApp","unregisterApp","facade","version","info","_isWuFramework","define","mount","unmount","app","hide","show","isHidden","getState","setState","onStateChange","ai","aiReady","getStats","getSandboxInfo","silence","verbose","importModule","url","timeout","Error","Promise","resolve","reject","channelId","Date","now","onMessage","event","data","cleanup","error","timer","setTimeout","removeEventListener","clearTimeout","addEventListener","script","type","textContent","head","queryTarget","mainDoc","tag","options","createElementNS","ns","createTextNode","text","createComment","createDocumentFragment","querySelector","sel","querySelectorAll","getElementById","id","getElementsByClassName","cls","getElementsByTagName","defineProperty","configurable","origDocAdd","origDocRemove","handler","push","target","filter","l","origSetTimeout","origClearTimeout","origSetInterval","setInterval","origClearInterval","clearInterval","ms","args","a","delete","add","requestAnimationFrame","origRAF","origCancelRAF","cancelAnimationFrame","destroy","clear","doc","contentDocument","parentNode","removeChild","isActive"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=new class{constructor(){this.isDevelopment=this.detectEnvironment(),this.logLevel=this.isDevelopment?"warn":"error",this.levels={debug:0,info:1,warn:2,error:3,silent:4}}detectEnvironment(){if("undefined"!=typeof window&&!0===window.WU_DEBUG)return!0;if("undefined"!=typeof window&&!1===window.WU_DEBUG)return!1;if("undefined"!=typeof process&&"production"===process.env?.NODE_ENV)return!1;if("undefined"!=typeof process&&"development"===process.env?.NODE_ENV)return!0;if("undefined"!=typeof window&&window.location){const e=window.location.hostname;if("localhost"===e||"127.0.0.1"===e||"[::1]"===e)return!0;try{if(new URLSearchParams(window.location.search).has("wu-debug"))return!0}catch{}}return!1}setLevel(e){return this.logLevel=e,this}setDevelopment(e){return this.isDevelopment=e,this.logLevel=e?"debug":"error",this}shouldLog(e){return this.levels[e]>=this.levels[this.logLevel]}debug(...e){this.shouldLog("debug")&&console.log(...e)}info(...e){this.shouldLog("info")&&console.info(...e)}warn(...e){this.shouldLog("warn")&&console.warn(...e)}error(...e){this.shouldLog("error")&&console.error(...e)}wu(e,...o){if(this.shouldLog(e)){console["debug"===e?"log":e]("[Wu]",...o)}}wuDebug(...e){this.wu("debug",...e)}wuInfo(...e){this.wu("info",...e)}wuWarn(...e){this.wu("warn",...e)}wuError(...e){this.wu("error",...e)}};export{e as l};
|
|
2
|
+
//# sourceMappingURL=wu-logger-fJfUHBGA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wu-logger-fJfUHBGA.js","sources":["../src/core/wu-logger.js"],"sourcesContent":["/**\r\n * 📝 WU-LOGGER: Sistema de logging inteligente para entornos\r\n * Controla los logs automáticamente según el entorno\r\n */\r\n\r\nexport class WuLogger {\r\n constructor() {\r\n // Detectar entorno automáticamente\r\n this.isDevelopment = this.detectEnvironment();\r\n // En desarrollo: warn (menos ruido), en producción: error\r\n this.logLevel = this.isDevelopment ? 'warn' : 'error';\r\n\r\n this.levels = {\r\n debug: 0,\r\n info: 1,\r\n warn: 2,\r\n error: 3,\r\n silent: 4\r\n };\r\n }\r\n\r\n /**\r\n * Detectar si estamos en desarrollo\r\n */\r\n detectEnvironment() {\r\n // 1. Explicit flag takes priority\r\n if (typeof window !== 'undefined' && window.WU_DEBUG === true) return true;\r\n if (typeof window !== 'undefined' && window.WU_DEBUG === false) return false;\r\n\r\n // 2. NODE_ENV check (works in bundlers and Node)\r\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return false;\r\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') return true;\r\n\r\n // 3. Browser heuristics (only if window exists)\r\n if (typeof window !== 'undefined' && window.location) {\r\n const hostname = window.location.hostname;\r\n if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]') return true;\r\n\r\n // URL param override\r\n try {\r\n if (new URLSearchParams(window.location.search).has('wu-debug')) return true;\r\n } catch {}\r\n }\r\n\r\n // 4. Default: assume production\r\n return false;\r\n }\r\n\r\n /**\r\n * Configurar nivel de logging\r\n */\r\n setLevel(level) {\r\n this.logLevel = level;\r\n return this;\r\n }\r\n\r\n /**\r\n * Habilitar/deshabilitar development mode\r\n */\r\n setDevelopment(isDev) {\r\n this.isDevelopment = isDev;\r\n this.logLevel = isDev ? 'debug' : 'error';\r\n return this;\r\n }\r\n\r\n /**\r\n * Verificar si debemos mostrar el log\r\n */\r\n shouldLog(level) {\r\n return this.levels[level] >= this.levels[this.logLevel];\r\n }\r\n\r\n /**\r\n * Logging methods\r\n */\r\n debug(...args) {\r\n if (this.shouldLog('debug')) {\r\n console.log(...args);\r\n }\r\n }\r\n\r\n info(...args) {\r\n if (this.shouldLog('info')) {\r\n console.info(...args);\r\n }\r\n }\r\n\r\n warn(...args) {\r\n if (this.shouldLog('warn')) {\r\n console.warn(...args);\r\n }\r\n }\r\n\r\n error(...args) {\r\n if (this.shouldLog('error')) {\r\n console.error(...args);\r\n }\r\n }\r\n\r\n /**\r\n * Logging con contexto Wu\r\n */\r\n wu(level, ...args) {\r\n if (this.shouldLog(level)) {\r\n const method = level === 'debug' ? 'log' : level;\r\n console[method]('[Wu]', ...args);\r\n }\r\n }\r\n\r\n /**\r\n * Helper methods específicos para Wu\r\n */\r\n wuDebug(...args) { this.wu('debug', ...args); }\r\n wuInfo(...args) { this.wu('info', ...args); }\r\n wuWarn(...args) { this.wu('warn', ...args); }\r\n wuError(...args) { this.wu('error', ...args); }\r\n}\r\n\r\n// Singleton instance\r\nexport const logger = new WuLogger();\r\n\r\n// Helper para compatibilidad con logs existentes\r\nexport const wuLog = {\r\n debug: (...args) => logger.wuDebug(...args),\r\n info: (...args) => logger.wuInfo(...args),\r\n warn: (...args) => logger.wuWarn(...args),\r\n error: (...args) => logger.wuError(...args)\r\n};\r\n\r\n/**\r\n * 🔇 Silenciar todos los logs de Wu Framework\r\n * Útil en producción para eliminar todo el ruido\r\n */\r\nexport function silenceAllLogs() {\r\n logger.setLevel('silent');\r\n}\r\n\r\n/**\r\n * 🔊 Restaurar logs (nivel debug)\r\n */\r\nexport function enableAllLogs() {\r\n logger.setLevel('debug');\r\n}"],"names":["logger","constructor","this","isDevelopment","detectEnvironment","logLevel","levels","debug","info","warn","error","silent","window","WU_DEBUG","process","env","NODE_ENV","location","hostname","URLSearchParams","search","has","setLevel","level","setDevelopment","isDev","shouldLog","args","console","log","wu","wuDebug","wuInfo","wuWarn","wuError"],"mappings":"AAuHY,MAACA,EAAS,IAlHf,MACL,WAAAC,GAEEC,KAAKC,cAAgBD,KAAKE,oBAE1BF,KAAKG,SAAWH,KAAKC,cAAgB,OAAS,QAE9CD,KAAKI,OAAS,CACZC,MAAO,EACPC,KAAM,EACNC,KAAM,EACNC,MAAO,EACPC,OAAQ,EAEZ,CAKA,iBAAAP,GAEE,GAAsB,oBAAXQ,SAA8C,IAApBA,OAAOC,SAAmB,OAAO,EACtE,GAAsB,oBAAXD,SAA8C,IAApBA,OAAOC,SAAoB,OAAO,EAGvE,GAAuB,oBAAZC,SAAqD,eAA1BA,QAAQC,KAAKC,SAA2B,OAAO,EACrF,GAAuB,oBAAZF,SAAqD,gBAA1BA,QAAQC,KAAKC,SAA4B,OAAO,EAGtF,GAAsB,oBAAXJ,QAA0BA,OAAOK,SAAU,CACpD,MAAMC,EAAWN,OAAOK,SAASC,SACjC,GAAiB,cAAbA,GAAyC,cAAbA,GAAyC,UAAbA,EAAsB,OAAO,EAGzF,IACE,GAAI,IAAIC,gBAAgBP,OAAOK,SAASG,QAAQC,IAAI,YAAa,OAAO,CAC1E,CAAE,MAAO,CACX,CAGA,OAAO,CACT,CAKA,QAAAC,CAASC,GAEP,OADArB,KAAKG,SAAWkB,EACTrB,IACT,CAKA,cAAAsB,CAAeC,GAGb,OAFAvB,KAAKC,cAAgBsB,EACrBvB,KAAKG,SAAWoB,EAAQ,QAAU,QAC3BvB,IACT,CAKA,SAAAwB,CAAUH,GACR,OAAOrB,KAAKI,OAAOiB,IAAUrB,KAAKI,OAAOJ,KAAKG,SAChD,CAKA,KAAAE,IAASoB,GACHzB,KAAKwB,UAAU,UACjBE,QAAQC,OAAOF,EAEnB,CAEA,IAAAnB,IAAQmB,GACFzB,KAAKwB,UAAU,SACjBE,QAAQpB,QAAQmB,EAEpB,CAEA,IAAAlB,IAAQkB,GACFzB,KAAKwB,UAAU,SACjBE,QAAQnB,QAAQkB,EAEpB,CAEA,KAAAjB,IAASiB,GACHzB,KAAKwB,UAAU,UACjBE,QAAQlB,SAASiB,EAErB,CAKA,EAAAG,CAAGP,KAAUI,GACX,GAAIzB,KAAKwB,UAAUH,GAAQ,CAEzBK,QADyB,UAAVL,EAAoB,MAAQA,GAC3B,UAAWI,EAC7B,CACF,CAKA,OAAAI,IAAWJ,GAAQzB,KAAK4B,GAAG,WAAYH,EAAO,CAC9C,MAAAK,IAAUL,GAAQzB,KAAK4B,GAAG,UAAWH,EAAO,CAC5C,MAAAM,IAAUN,GAAQzB,KAAK4B,GAAG,UAAWH,EAAO,CAC5C,OAAAO,IAAWP,GAAQzB,KAAK4B,GAAG,WAAYH,EAAO"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{l as t}from"./wu-logger-fJfUHBGA.js";class r{static DANGEROUS_PATTERNS=[{pattern:/constructor\s*\[\s*['"`]constructor['"`]\s*\]/,label:"constructor chain access (sandbox escape)"},{pattern:/__proto__/,label:"__proto__ access (prototype pollution)"},{pattern:/Object\s*\.\s*getPrototypeOf\s*\(\s*proxy\s*\)/,label:"Object.getPrototypeOf(proxy) (sandbox escape)"},{pattern:/Function\s*\(\s*['"`]/,label:"Function() constructor (dynamic code generation)"},{pattern:/\beval\s*\(/,label:"eval() (dynamic code execution)"},{pattern:/\bimport\s*\(/,label:"import() (dynamic import escapes sandbox)"},{pattern:/document\s*\.\s*cookie/,label:"document.cookie (direct cookie access)"}];_validateScript(e,o){for(const{pattern:c,label:n}of r.DANGEROUS_PATTERNS)if(c.test(e)){const r=`[ScriptExecutor] Blocked dangerous pattern in "${o}": ${n}`;throw t.wuError(r),new Error(r)}}execute(r,e,o,c={}){const{strictGlobal:n=!0,sourceUrl:s=""}=c;if(!r||!r.trim())return;this._validateScript(r,e);const a=s?`\n//# sourceURL=wu-sandbox:///${e}/${s}\n`:"";let i;i=n?`;(function(window, self, globalThis, top, parent) {\n with(window) {\n ;${r}${a}\n }\n}).call(proxy, proxy, proxy, proxy, proxy, proxy);`:`;(function(window, self, globalThis, top, parent) {\n ;${r}${a}\n}).call(proxy, proxy, proxy, proxy, proxy, proxy);`;try{return new Function("proxy",i)(o)}catch(s){if(n)return t.wuWarn(`[ScriptExecutor] strictGlobal failed for ${e}, retrying without with(): ${s.message}`),this.execute(r,e,o,{...c,strictGlobal:!1});throw t.wuError(`[ScriptExecutor] Execution failed for ${e}:`,s),s}}async fetchScript(t){const r=await fetch(t);if(!r.ok)throw new Error(`Failed to fetch script ${t}: HTTP ${r.status}`);return r.text()}async executeAll(r,e,o,c={}){for(const n of r){let r=n.content;!r&&n.src&&(t.wuDebug(`[ScriptExecutor] Fetching external script: ${n.src}`),r=await this.fetchScript(n.src)),r&&r.trim()&&this.execute(r,e,o,{...c,sourceUrl:n.src||c.sourceUrl||""})}t.wuDebug(`[ScriptExecutor] Executed ${r.length} scripts for ${e}`)}}export{r as WuScriptExecutor};
|
|
2
|
+
//# sourceMappingURL=wu-script-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wu-script-executor.js","sources":["../src/core/wu-script-executor.js"],"sourcesContent":["/**\r\n * WU-SCRIPT-EXECUTOR: Execute scripts inside a Proxy sandbox.\r\n *\r\n * Two isolation levels:\r\n * - strictGlobal: true → with(proxy) { code } — all global access goes through proxy\r\n * - strictGlobal: false → (function(window){ code })(proxy) — only explicit window.xxx\r\n *\r\n * This is what makes the sandbox REAL instead of decorative.\r\n * Without this, import() runs code in global scope and the proxy is just a cleanup tracker.\r\n * With this, code receives the proxy as \"window\" and every setTimeout, addEventListener,\r\n * document.querySelector, localStorage access goes through the proxy's traps.\r\n */\r\n\r\nimport { logger } from './wu-logger.js';\r\n\r\nexport class WuScriptExecutor {\r\n\r\n /**\r\n * Dangerous patterns that indicate prototype pollution, sandbox escape,\r\n * or direct access to sensitive APIs. Each entry is a regex paired with\r\n * a human-readable label used in error messages.\r\n *\r\n * This is a tripwire, not a full parser. It catches the most common\r\n * attack vectors without the overhead of AST analysis.\r\n */\r\n static DANGEROUS_PATTERNS = [\r\n // Prototype pollution vectors\r\n { pattern: /constructor\\s*\\[\\s*['\"`]constructor['\"`]\\s*\\]/, label: 'constructor chain access (sandbox escape)' },\r\n { pattern: /__proto__/, label: '__proto__ access (prototype pollution)' },\r\n\r\n // Sandbox escape via proxy introspection\r\n { pattern: /Object\\s*\\.\\s*getPrototypeOf\\s*\\(\\s*proxy\\s*\\)/, label: 'Object.getPrototypeOf(proxy) (sandbox escape)' },\r\n\r\n // Dynamic code generation that bypasses the sandbox\r\n { pattern: /Function\\s*\\(\\s*['\"`]/, label: 'Function() constructor (dynamic code generation)' },\r\n { pattern: /\\beval\\s*\\(/, label: 'eval() (dynamic code execution)' },\r\n\r\n // Dynamic import escapes the sandbox entirely (runs in global scope)\r\n { pattern: /\\bimport\\s*\\(/, label: 'import() (dynamic import escapes sandbox)' },\r\n\r\n // Direct cookie access (should go through proxy traps, not raw document)\r\n { pattern: /document\\s*\\.\\s*cookie/, label: 'document.cookie (direct cookie access)' },\r\n ];\r\n\r\n /**\r\n * Validate script text against known dangerous patterns before execution.\r\n * Throws if any pattern matches. This is intentionally lightweight --\r\n * pattern detection only, not a full parse.\r\n *\r\n * @param {string} scriptText - The raw script to validate\r\n * @param {string} appName - App identifier (for error context)\r\n * @throws {Error} If a dangerous pattern is detected\r\n */\r\n _validateScript(scriptText, appName) {\r\n for (const { pattern, label } of WuScriptExecutor.DANGEROUS_PATTERNS) {\r\n if (pattern.test(scriptText)) {\r\n const msg = `[ScriptExecutor] Blocked dangerous pattern in \"${appName}\": ${label}`;\r\n logger.wuError(msg);\r\n throw new Error(msg);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Execute a script string inside the proxy sandbox.\r\n *\r\n * @param {string} scriptText - JavaScript code to execute\r\n * @param {string} appName - App identifier (for logging)\r\n * @param {Proxy} proxy - The activated proxy sandbox\r\n * @param {Object} [options]\r\n * @param {boolean} [options.strictGlobal=true] - Use with(proxy) for maximum isolation\r\n * @param {string} [options.sourceUrl=''] - Source URL for devtools (//# sourceURL)\r\n * @returns {*} Return value of the executed code\r\n */\r\n execute(scriptText, appName, proxy, options = {}) {\r\n const { strictGlobal = true, sourceUrl = '' } = options;\r\n\r\n if (!scriptText || !scriptText.trim()) return;\r\n\r\n this._validateScript(scriptText, appName);\r\n\r\n const sourceComment = sourceUrl ? `\\n//# sourceURL=wu-sandbox:///${appName}/${sourceUrl}\\n` : '';\r\n\r\n let wrappedCode;\r\n\r\n if (strictGlobal) {\r\n // MAXIMUM ISOLATION\r\n // with(window) makes ALL unqualified identifiers (setTimeout, fetch, document, etc.)\r\n // resolve through the proxy's has/get traps, not the real window.\r\n // Note: 'use strict' inside the with block becomes a no-op string expression,\r\n // so bundled code with strict mode still works.\r\n wrappedCode = `;(function(window, self, globalThis, top, parent) {\r\n with(window) {\r\n ;${scriptText}${sourceComment}\r\n }\r\n}).call(proxy, proxy, proxy, proxy, proxy, proxy);`;\r\n } else {\r\n // IIFE ONLY — only explicit window.xxx goes through proxy\r\n wrappedCode = `;(function(window, self, globalThis, top, parent) {\r\n ;${scriptText}${sourceComment}\r\n}).call(proxy, proxy, proxy, proxy, proxy, proxy);`;\r\n }\r\n\r\n try {\r\n // new Function('proxy', code) creates a function with 'proxy' as the single param.\r\n // This avoids polluting scope — the only bridge to the sandbox is the proxy argument.\r\n const fn = new Function('proxy', wrappedCode);\r\n return fn(proxy);\r\n } catch (error) {\r\n // If strictGlobal failed (rare edge case with with-statement), retry without it\r\n if (strictGlobal) {\r\n logger.wuWarn(`[ScriptExecutor] strictGlobal failed for ${appName}, retrying without with(): ${error.message}`);\r\n return this.execute(scriptText, appName, proxy, { ...options, strictGlobal: false });\r\n }\r\n logger.wuError(`[ScriptExecutor] Execution failed for ${appName}:`, error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Fetch script content from a URL.\r\n * @param {string} url - Script URL\r\n * @returns {Promise<string>} Script text\r\n */\r\n async fetchScript(url) {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch script ${url}: HTTP ${response.status}`);\r\n }\r\n return response.text();\r\n }\r\n\r\n /**\r\n * Execute an array of scripts in sequence inside the proxy.\r\n * External scripts (with src) are fetched first.\r\n *\r\n * @param {Array<{content?: string, src?: string}>} scripts\r\n * @param {string} appName\r\n * @param {Proxy} proxy\r\n * @param {Object} [options]\r\n */\r\n async executeAll(scripts, appName, proxy, options = {}) {\r\n for (const script of scripts) {\r\n let text = script.content;\r\n\r\n if (!text && script.src) {\r\n logger.wuDebug(`[ScriptExecutor] Fetching external script: ${script.src}`);\r\n text = await this.fetchScript(script.src);\r\n }\r\n\r\n if (text && text.trim()) {\r\n this.execute(text, appName, proxy, {\r\n ...options,\r\n sourceUrl: script.src || options.sourceUrl || ''\r\n });\r\n }\r\n }\r\n\r\n logger.wuDebug(`[ScriptExecutor] Executed ${scripts.length} scripts for ${appName}`);\r\n }\r\n}\r\n"],"names":["WuScriptExecutor","static","pattern","label","_validateScript","scriptText","appName","DANGEROUS_PATTERNS","test","msg","logger","wuError","Error","execute","proxy","options","strictGlobal","sourceUrl","trim","this","sourceComment","wrappedCode","Function","fn","error","wuWarn","message","fetchScript","url","response","fetch","ok","status","text","executeAll","scripts","script","content","src","wuDebug","length"],"mappings":"4CAeO,MAAMA,EAUXC,0BAA4B,CAE1B,CAAEC,QAAS,gDAAiDC,MAAO,6CACnE,CAAED,QAAS,YAAaC,MAAO,0CAG/B,CAAED,QAAS,iDAAkDC,MAAO,iDAGpE,CAAED,QAAS,wBAAyBC,MAAO,oDAC3C,CAAED,QAAS,cAAeC,MAAO,mCAGjC,CAAED,QAAS,gBAAiBC,MAAO,6CAGnC,CAAED,QAAS,yBAA0BC,MAAO,2CAY9C,eAAAC,CAAgBC,EAAYC,GAC1B,IAAK,MAAMJ,QAAEA,EAAOC,MAAEA,KAAWH,EAAiBO,mBAChD,GAAIL,EAAQM,KAAKH,GAAa,CAC5B,MAAMI,EAAM,kDAAkDH,OAAaH,IAE3E,MADAO,EAAOC,QAAQF,GACT,IAAIG,MAAMH,EAClB,CAEJ,CAaA,OAAAI,CAAQR,EAAYC,EAASQ,EAAOC,EAAU,CAAA,GAC5C,MAAMC,aAAEA,GAAe,EAAIC,UAAEA,EAAY,IAAOF,EAEhD,IAAKV,IAAeA,EAAWa,OAAQ,OAEvCC,KAAKf,gBAAgBC,EAAYC,GAEjC,MAAMc,EAAgBH,EAAY,iCAAiCX,KAAWW,MAAgB,GAE9F,IAAII,EAQFA,EANEL,EAMY,+EAEbX,IAAae,6DAKA,2DACff,IAAae,wDAId,IAIE,OADW,IAAIE,SAAS,QAASD,EAC1BE,CAAGT,EACZ,CAAE,MAAOU,GAEP,GAAIR,EAEF,OADAN,EAAOe,OAAO,4CAA4CnB,+BAAqCkB,EAAME,WAC9FP,KAAKN,QAAQR,EAAYC,EAASQ,EAAO,IAAKC,EAASC,cAAc,IAG9E,MADAN,EAAOC,QAAQ,yCAAyCL,KAAYkB,GAC9DA,CACR,CACF,CAOA,iBAAMG,CAAYC,GAChB,MAAMC,QAAiBC,MAAMF,GAC7B,IAAKC,EAASE,GACZ,MAAM,IAAInB,MAAM,0BAA0BgB,WAAaC,EAASG,UAElE,OAAOH,EAASI,MAClB,CAWA,gBAAMC,CAAWC,EAAS7B,EAASQ,EAAOC,EAAU,CAAA,GAClD,IAAK,MAAMqB,KAAUD,EAAS,CAC5B,IAAIF,EAAOG,EAAOC,SAEbJ,GAAQG,EAAOE,MAClB5B,EAAO6B,QAAQ,8CAA8CH,EAAOE,OACpEL,QAAad,KAAKQ,YAAYS,EAAOE,MAGnCL,GAAQA,EAAKf,QACfC,KAAKN,QAAQoB,EAAM3B,EAASQ,EAAO,IAC9BC,EACHE,UAAWmB,EAAOE,KAAOvB,EAAQE,WAAa,IAGpD,CAEAP,EAAO6B,QAAQ,6BAA6BJ,EAAQK,sBAAsBlC,IAC5E"}
|
package/package.json
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wu-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Universal Microfrontends Framework - 13 frameworks, zero config, Shadow DOM isolation",
|
|
5
5
|
"main": "dist/wu-framework.cjs.js",
|
|
6
|
-
"module": "
|
|
6
|
+
"module": "dist/wu-framework.esm.js",
|
|
7
7
|
"browser": "dist/wu-framework.umd.js",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"import": "./
|
|
11
|
+
"import": "./dist/wu-framework.esm.js",
|
|
12
12
|
"require": "./dist/wu-framework.cjs.js",
|
|
13
13
|
"browser": "./dist/wu-framework.umd.js"
|
|
14
14
|
},
|
|
15
|
-
"./
|
|
16
|
-
"./adapters": "./
|
|
17
|
-
"./adapters/
|
|
18
|
-
"./adapters/
|
|
19
|
-
"./adapters/
|
|
20
|
-
"./adapters/
|
|
21
|
-
"./adapters/
|
|
22
|
-
"./adapters/
|
|
23
|
-
"./adapters/
|
|
24
|
-
"./adapters/
|
|
25
|
-
"./adapters/
|
|
26
|
-
"./adapters/
|
|
27
|
-
"./adapters/
|
|
28
|
-
"./adapters/
|
|
29
|
-
"./adapters/stimulus": "./src/adapters/stimulus/index.js",
|
|
15
|
+
"./adapters": "./dist/adapters/index.js",
|
|
16
|
+
"./adapters/react": "./dist/adapters/react/index.js",
|
|
17
|
+
"./adapters/vue": "./dist/adapters/vue/index.js",
|
|
18
|
+
"./adapters/angular": "./dist/adapters/angular/index.js",
|
|
19
|
+
"./adapters/svelte": "./dist/adapters/svelte/index.js",
|
|
20
|
+
"./adapters/preact": "./dist/adapters/preact/index.js",
|
|
21
|
+
"./adapters/solid": "./dist/adapters/solid/index.js",
|
|
22
|
+
"./adapters/lit": "./dist/adapters/lit/index.js",
|
|
23
|
+
"./adapters/vanilla": "./dist/adapters/vanilla/index.js",
|
|
24
|
+
"./adapters/alpine": "./dist/adapters/alpine/index.js",
|
|
25
|
+
"./adapters/qwik": "./dist/adapters/qwik/index.js",
|
|
26
|
+
"./adapters/stencil": "./dist/adapters/stencil/index.js",
|
|
27
|
+
"./adapters/htmx": "./dist/adapters/htmx/index.js",
|
|
28
|
+
"./adapters/stimulus": "./dist/adapters/stimulus/index.js",
|
|
30
29
|
"./integrations/astro": "./integrations/astro/index.js",
|
|
31
30
|
"./integrations/astro/WuApp.astro": "./integrations/astro/WuApp.astro",
|
|
32
|
-
"./integrations/astro/WuShell.astro": "./integrations/astro/WuShell.astro"
|
|
31
|
+
"./integrations/astro/WuShell.astro": "./integrations/astro/WuShell.astro",
|
|
32
|
+
"./sandbox/iframe": "./dist/wu-iframe-sandbox.js",
|
|
33
|
+
"./sandbox/html-parser": "./dist/wu-html-parser.js",
|
|
34
|
+
"./sandbox/script-executor": "./dist/wu-script-executor.js",
|
|
35
|
+
"./ai": "./dist/ai/wu-ai.js"
|
|
33
36
|
},
|
|
34
37
|
"scripts": {
|
|
35
38
|
"dev": "rollup -c --watch",
|
|
@@ -43,7 +46,8 @@
|
|
|
43
46
|
"test:coverage": "vitest run --coverage",
|
|
44
47
|
"lint": "eslint src/",
|
|
45
48
|
"format": "prettier --write src/",
|
|
46
|
-
"format:check": "prettier --check src/"
|
|
49
|
+
"format:check": "prettier --check src/",
|
|
50
|
+
"prepublishOnly": "npm run build"
|
|
47
51
|
},
|
|
48
52
|
"keywords": [
|
|
49
53
|
"microfrontends",
|
|
@@ -86,52 +90,57 @@
|
|
|
86
90
|
"supports es6-module"
|
|
87
91
|
],
|
|
88
92
|
"files": [
|
|
89
|
-
"src/",
|
|
90
93
|
"dist/",
|
|
91
94
|
"integrations/",
|
|
92
95
|
"README.md",
|
|
93
96
|
"LICENSE"
|
|
94
97
|
],
|
|
98
|
+
"sideEffects": [
|
|
99
|
+
"./dist/wu-framework.esm.js",
|
|
100
|
+
"./dist/wu-framework.cjs.js",
|
|
101
|
+
"./dist/wu-framework.umd.js",
|
|
102
|
+
"./dist/wu-framework.dev.js"
|
|
103
|
+
],
|
|
95
104
|
"typesVersions": {
|
|
96
105
|
"*": {
|
|
97
106
|
"adapters/react": [
|
|
98
|
-
"
|
|
107
|
+
"dist/adapters/react/index.d.ts"
|
|
99
108
|
],
|
|
100
109
|
"adapters/vue": [
|
|
101
|
-
"
|
|
110
|
+
"dist/adapters/vue/index.d.ts"
|
|
102
111
|
],
|
|
103
112
|
"adapters/angular": [
|
|
104
|
-
"
|
|
113
|
+
"dist/adapters/angular/index.d.ts"
|
|
105
114
|
],
|
|
106
115
|
"adapters/svelte": [
|
|
107
|
-
"
|
|
116
|
+
"dist/adapters/svelte/index.d.ts"
|
|
108
117
|
],
|
|
109
118
|
"adapters/preact": [
|
|
110
|
-
"
|
|
119
|
+
"dist/adapters/preact/index.d.ts"
|
|
111
120
|
],
|
|
112
121
|
"adapters/solid": [
|
|
113
|
-
"
|
|
122
|
+
"dist/adapters/solid/index.d.ts"
|
|
114
123
|
],
|
|
115
124
|
"adapters/lit": [
|
|
116
|
-
"
|
|
125
|
+
"dist/adapters/lit/index.d.ts"
|
|
117
126
|
],
|
|
118
127
|
"adapters/vanilla": [
|
|
119
|
-
"
|
|
128
|
+
"dist/adapters/vanilla/index.d.ts"
|
|
120
129
|
],
|
|
121
130
|
"adapters/alpine": [
|
|
122
|
-
"
|
|
131
|
+
"dist/adapters/alpine/index.d.ts"
|
|
123
132
|
],
|
|
124
133
|
"adapters/qwik": [
|
|
125
|
-
"
|
|
134
|
+
"dist/adapters/qwik/index.d.ts"
|
|
126
135
|
],
|
|
127
136
|
"adapters/stencil": [
|
|
128
|
-
"
|
|
137
|
+
"dist/adapters/stencil/index.d.ts"
|
|
129
138
|
],
|
|
130
139
|
"adapters/htmx": [
|
|
131
|
-
"
|
|
140
|
+
"dist/adapters/htmx/index.d.ts"
|
|
132
141
|
],
|
|
133
142
|
"adapters/stimulus": [
|
|
134
|
-
"
|
|
143
|
+
"dist/adapters/stimulus/index.d.ts"
|
|
135
144
|
]
|
|
136
145
|
}
|
|
137
146
|
},
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WU-FRAMEWORK ALPINE.JS ADAPTER
|
|
3
|
-
*
|
|
4
|
-
* Bridges Alpine.js reactive components into Wu Framework's
|
|
5
|
-
* microfrontend orchestration layer. Alpine's declarative
|
|
6
|
-
* x-data / x-bind paradigm maps naturally to a template + data
|
|
7
|
-
* registration model.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* import { wuAlpine } from 'wu-framework/adapters/alpine';
|
|
11
|
-
*
|
|
12
|
-
* wuAlpine.register('my-app', {
|
|
13
|
-
* template: '<div x-data="app"><span x-text="message"></span></div>',
|
|
14
|
-
* data: () => ({ message: 'Hello from Alpine' })
|
|
15
|
-
* });
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // With lifecycle hooks
|
|
19
|
-
* wuAlpine.register('counter', {
|
|
20
|
-
* template: `
|
|
21
|
-
* <div x-data="app">
|
|
22
|
-
* <span x-text="count"></span>
|
|
23
|
-
* <button @click="count++">+</button>
|
|
24
|
-
* </div>
|
|
25
|
-
* `,
|
|
26
|
-
* data: () => ({ count: 0 })
|
|
27
|
-
* }, {
|
|
28
|
-
* onMount: (container) => console.log('Mounted'),
|
|
29
|
-
* onUnmount: (container) => console.log('Unmounted')
|
|
30
|
-
* });
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
// Adapter-scoped state
|
|
34
|
-
const adapterState = {
|
|
35
|
-
apps: new Map()
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Obtiene la instancia de Wu Framework
|
|
40
|
-
*/
|
|
41
|
-
function getWuInstance() {
|
|
42
|
-
if (typeof window === 'undefined') return null;
|
|
43
|
-
|
|
44
|
-
return window.wu
|
|
45
|
-
|| window.parent?.wu
|
|
46
|
-
|| window.top?.wu
|
|
47
|
-
|| null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Espera a que Wu Framework este disponible
|
|
52
|
-
*/
|
|
53
|
-
function waitForWu(timeout = 5000) {
|
|
54
|
-
return new Promise((resolve, reject) => {
|
|
55
|
-
const wu = getWuInstance();
|
|
56
|
-
if (wu) {
|
|
57
|
-
resolve(wu);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const startTime = Date.now();
|
|
62
|
-
|
|
63
|
-
const handleWuReady = () => {
|
|
64
|
-
cleanup();
|
|
65
|
-
resolve(getWuInstance());
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
window.addEventListener('wu:ready', handleWuReady);
|
|
69
|
-
window.addEventListener('wu:app:ready', handleWuReady);
|
|
70
|
-
|
|
71
|
-
const checkInterval = setInterval(() => {
|
|
72
|
-
const wu = getWuInstance();
|
|
73
|
-
if (wu) {
|
|
74
|
-
cleanup();
|
|
75
|
-
resolve(wu);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (Date.now() - startTime > timeout) {
|
|
80
|
-
cleanup();
|
|
81
|
-
reject(new Error(`Wu Framework not found after ${timeout}ms`));
|
|
82
|
-
}
|
|
83
|
-
}, 200);
|
|
84
|
-
|
|
85
|
-
function cleanup() {
|
|
86
|
-
clearInterval(checkInterval);
|
|
87
|
-
window.removeEventListener('wu:ready', handleWuReady);
|
|
88
|
-
window.removeEventListener('wu:app:ready', handleWuReady);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Registra una app Alpine.js como microfrontend
|
|
95
|
-
*
|
|
96
|
-
* @param {string} appName - Nombre unico del microfrontend
|
|
97
|
-
* @param {Object} appConfig - Configuracion de la app Alpine
|
|
98
|
-
* @param {string} appConfig.template - HTML string con directivas Alpine (x-data, x-bind, etc.)
|
|
99
|
-
* @param {Function} appConfig.data - Funcion que retorna el objeto de datos Alpine
|
|
100
|
-
* @param {Object} [options] - Opciones adicionales
|
|
101
|
-
* @param {Function} [options.onMount] - Callback despues de montar
|
|
102
|
-
* @param {Function} [options.onUnmount] - Callback antes de desmontar
|
|
103
|
-
* @param {boolean} [options.standalone=true] - Permitir ejecucion standalone
|
|
104
|
-
* @param {string} [options.standaloneContainer='#app'] - Selector para modo standalone
|
|
105
|
-
* @returns {Promise<boolean>} true si el registro fue exitoso
|
|
106
|
-
*/
|
|
107
|
-
async function register(appName, appConfig, options = {}) {
|
|
108
|
-
const { template, data } = appConfig;
|
|
109
|
-
|
|
110
|
-
const {
|
|
111
|
-
onMount = null,
|
|
112
|
-
onUnmount = null,
|
|
113
|
-
standalone = true,
|
|
114
|
-
standaloneContainer = '#app'
|
|
115
|
-
} = options;
|
|
116
|
-
|
|
117
|
-
if (!template || typeof template !== 'string') {
|
|
118
|
-
throw new Error(`[WuAlpine] template (HTML string) is required for ${appName}`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Mount function
|
|
122
|
-
const mountApp = (container) => {
|
|
123
|
-
if (!container) {
|
|
124
|
-
console.error(`[WuAlpine] Mount failed for ${appName}: container is null`);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Prevent double-mount
|
|
129
|
-
if (adapterState.apps.has(appName)) {
|
|
130
|
-
console.warn(`[WuAlpine] ${appName} already mounted, unmounting first`);
|
|
131
|
-
unmountApp();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
container.innerHTML = '';
|
|
136
|
-
|
|
137
|
-
// Inject template HTML
|
|
138
|
-
container.innerHTML = template;
|
|
139
|
-
|
|
140
|
-
// Initialize Alpine on this subtree
|
|
141
|
-
const Alpine = window.Alpine;
|
|
142
|
-
if (Alpine) {
|
|
143
|
-
if (data && typeof data === 'function') {
|
|
144
|
-
Alpine.data('app', data);
|
|
145
|
-
}
|
|
146
|
-
Alpine.initTree(container);
|
|
147
|
-
} else {
|
|
148
|
-
console.warn(`[WuAlpine] window.Alpine not found - template inserted but not initialized`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
adapterState.apps.set(appName, { container, config: appConfig });
|
|
152
|
-
|
|
153
|
-
console.log(`[WuAlpine] ${appName} mounted successfully`);
|
|
154
|
-
|
|
155
|
-
if (onMount) {
|
|
156
|
-
onMount(container);
|
|
157
|
-
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error(`[WuAlpine] Mount error for ${appName}:`, error);
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// Unmount function
|
|
165
|
-
const unmountApp = (container) => {
|
|
166
|
-
const appData = adapterState.apps.get(appName);
|
|
167
|
-
|
|
168
|
-
if (appData) {
|
|
169
|
-
try {
|
|
170
|
-
if (onUnmount) {
|
|
171
|
-
onUnmount(appData.container);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Tear down Alpine reactivity on this subtree
|
|
175
|
-
const Alpine = window.Alpine;
|
|
176
|
-
if (Alpine && typeof Alpine.destroyTree === 'function') {
|
|
177
|
-
Alpine.destroyTree(appData.container);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
appData.container.innerHTML = '';
|
|
181
|
-
adapterState.apps.delete(appName);
|
|
182
|
-
|
|
183
|
-
console.log(`[WuAlpine] ${appName} unmounted successfully`);
|
|
184
|
-
} catch (error) {
|
|
185
|
-
console.error(`[WuAlpine] Unmount error for ${appName}:`, error);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (container) {
|
|
190
|
-
container.innerHTML = '';
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// Register with Wu Framework or fall back to standalone
|
|
195
|
-
try {
|
|
196
|
-
const wu = await waitForWu(3000);
|
|
197
|
-
|
|
198
|
-
wu.define(appName, {
|
|
199
|
-
mount: mountApp,
|
|
200
|
-
unmount: unmountApp
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
console.log(`[WuAlpine] ${appName} registered with Wu Framework`);
|
|
204
|
-
return true;
|
|
205
|
-
|
|
206
|
-
} catch (error) {
|
|
207
|
-
console.warn(`[WuAlpine] Wu Framework not available for ${appName}`);
|
|
208
|
-
|
|
209
|
-
if (standalone) {
|
|
210
|
-
const containerElement = document.querySelector(standaloneContainer);
|
|
211
|
-
|
|
212
|
-
if (containerElement) {
|
|
213
|
-
console.log(`[WuAlpine] Running ${appName} in standalone mode`);
|
|
214
|
-
mountApp(containerElement);
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Public API
|
|
224
|
-
export const wuAlpine = {
|
|
225
|
-
register,
|
|
226
|
-
getWuInstance,
|
|
227
|
-
waitForWu
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
export { register, getWuInstance, waitForWu };
|
|
231
|
-
export default wuAlpine;
|
package/src/adapters/alpine.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WU-FRAMEWORK ANGULAR AI INTEGRATION
|
|
3
|
-
*/
|
|
4
|
-
function getWuInstance() {
|
|
5
|
-
if (typeof window === 'undefined') return null;
|
|
6
|
-
return window.wu || window.parent?.wu || window.top?.wu || null;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function createWuAIService(options = {}) {
|
|
10
|
-
const { namespace = 'default' } = options;
|
|
11
|
-
const state = { messages: [], isStreaming: false, error: null };
|
|
12
|
-
return {
|
|
13
|
-
get messages() { return [...state.messages]; },
|
|
14
|
-
get isStreaming() { return state.isStreaming; },
|
|
15
|
-
get error() { return state.error; },
|
|
16
|
-
async send(text) {
|
|
17
|
-
if (!text?.trim()) return null;
|
|
18
|
-
const wu = getWuInstance();
|
|
19
|
-
if (!wu?.ai) { state.error = 'Wu AI not available'; return null; }
|
|
20
|
-
state.messages.push({ id: `user-${Date.now()}`, role: 'user', content: text, timestamp: Date.now() });
|
|
21
|
-
state.isStreaming = true; state.error = null;
|
|
22
|
-
try {
|
|
23
|
-
const res = await wu.ai.send(text, { namespace });
|
|
24
|
-
state.messages.push({ id: `assistant-${Date.now()}`, role: 'assistant', content: res.content, timestamp: Date.now() });
|
|
25
|
-
state.isStreaming = false; return res;
|
|
26
|
-
} catch (err) { state.error = err.message; state.isStreaming = false; return null; }
|
|
27
|
-
},
|
|
28
|
-
clear() { state.messages.length = 0; state.error = null; },
|
|
29
|
-
};
|
|
30
|
-
}
|