You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@mcp-apps-kit/ui-react-builder

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mcp-apps-kit/ui-react-builder - npm Package Compare versions

Comparing version
0.3.0
to
0.4.0
+2
dist/build-GBFL3B7J.js
export{b as buildReactUI,a as buildReactUIs}from'./chunk-3YHDRPOV.js';import'./chunk-R7RJYHEX.js';//# sourceMappingURL=build-GBFL3B7J.js.map
//# sourceMappingURL=build-GBFL3B7J.js.map
{"version":3,"sources":[],"names":[],"mappings":"","file":"build-GBFL3B7J.js"}
import {b as b$1,a}from'./chunk-R7RJYHEX.js';import*as w from'esbuild';import*as u from'fs/promises';import*as p from'path';async function C(s,t={}){let e=Date.now(),n=new Map,o=new Map,i=[],l=[],r=t.cwd??process.cwd();t.outDir&&await u.mkdir(p.resolve(r,t.outDir),{recursive:true});let m;if(t.globalCss)try{m=await u.readFile(p.resolve(r,t.globalCss),"utf-8");}catch(a){i.push(`Could not load global CSS from ${t.globalCss}: ${a instanceof Error?a.message:String(a)}`);}for(let[a,d]of Object.entries(s))try{let c=await b(a,d,{...t,cwd:r,globalCss:m});if(n.set(a,c),t.outDir){let f=p.resolve(r,t.outDir,`${a}.html`);await u.writeFile(f,c,"utf-8"),o.set(a,f);}}catch(c){let f={key:a,message:c instanceof Error?c.message:String(c),stack:c instanceof Error?c.stack:void 0};l.push(f);}return {outputs:n,files:o,duration:Date.now()-e,warnings:i,errors:l}}async function b(s,t,e){let n=t.__component,o=n.name||"Component",i=t.__defaultProps,l=t.__autoResize,r=b$1({componentPath:"__COMPONENT_PLACEHOLDER__",defaultProps:i,autoResize:l}),m=[_(n,o),y()],a$1=await w.build({stdin:{contents:r,loader:"tsx",resolveDir:e.cwd,sourcefile:`${s}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:e.minify??true,sourcemap:e.sourcemap?"inline":false,jsx:"automatic",jsxImportSource:"react",logLevel:"warning",external:e.external,plugins:m,define:{"process.env.NODE_ENV":e.minify?'"production"':'"development"'}}),d=a$1.outputFiles?.[0];if(!d)throw new Error(`No output generated for UI: ${s}`);let c=d.text;return a$1.warnings,a({key:s,name:t.name??s,script:c,css:e.globalCss})}function _(s,t){return {name:"mcp-component-resolver",setup(e){e.onResolve({filter:/__COMPONENT_PLACEHOLDER__/},()=>({path:"__COMPONENT__",namespace:"mcp-component"})),e.onLoad({filter:/.*/,namespace:"mcp-component"},()=>{let n=s.toString(),o=/^\s*class\b/.test(n),i=/^\s*function\b/.test(n),l=!o&&!i,r;return l?r=`
import React from "react";
const ${t} = ${n};
export default ${t};
`:r=`
import React from "react";
${n}
export default ${t};
`,{contents:r,loader:"tsx"}});}}}function y(){return {name:"mcp-css-handler",setup(s){s.onLoad({filter:/\.css$/},async t=>{if(t.path.endsWith(".module.css"))return null;let e=await u.readFile(t.path,"utf-8");return {contents:`
const style = document.createElement("style");
style.textContent = ${JSON.stringify(e)};
document.head.appendChild(style);
`,loader:"js"}}),s.onLoad({filter:/\.module\.css$/},async t=>{let e=await u.readFile(t.path,"utf-8"),n=E(e),o=Object.fromEntries(n.map(r=>[r,`${r}_${x(t.path)}`])),i=e;for(let[r,m]of Object.entries(o))i=i.replace(new RegExp(`\\.${r}\\b`,"g"),`.${m}`);return {contents:`
const style = document.createElement("style");
style.textContent = ${JSON.stringify(i)};
document.head.appendChild(style);
export default ${JSON.stringify(o)};
`,loader:"js"}});}}}function E(s){let t=/\.([a-zA-Z_][a-zA-Z0-9_-]*)/g,e=new Set,n;for(;(n=t.exec(s))!==null;)n[1]&&e.add(n[1]);return Array.from(e)}function x(s){let t=0;for(let e=0;e<s.length;e++){let n=s.charCodeAt(e);t=(t<<5)-t+n,t=t&t;}return Math.abs(t).toString(36).substring(0,5)}async function O(s,t,e={}){let n=await C({[s]:t},e),o=n.outputs.get(s);if(!o){let i=n.errors.find(l=>l.key===s);throw new Error(i?.message??`Failed to build UI: ${s}`)}return o}export{C as a,O as b};//# sourceMappingURL=chunk-3YHDRPOV.js.map
//# sourceMappingURL=chunk-3YHDRPOV.js.map
{"version":3,"sources":["../src/build.ts"],"names":["buildReactUIs","uis","options","startTime","outputs","files","warnings","errors","cwd","globalCss","error","key","def","html","compileComponent","outPath","buildError","component","componentName","defaultProps","autoResize","entryPoint","generateEntryPoint","plugins","createComponentPlugin","createCSSPlugin","result","outputFile","script","generateHTML","build","componentSource","isClassComponent","isFunctionComponent","isArrowFunction","contents","args","css","classNames","extractClassNames","mapping","name","hashString","transformedCss","original","hashed","classRegex","classes","match","str","hash","i","char","buildReactUI","e"],"mappings":"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","file":"chunk-3YHDRPOV.js","sourcesContent":["/**\n * React UI build system using esbuild\n *\n * Compiles React components into self-contained HTML files that can be\n * served as MCP UI resources.\n */\n\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { ReactUIDef, BuildOptions, BuildResult, BuildError } from \"./types\";\nimport { generateHTML, generateEntryPoint } from \"./html\";\n\n/**\n * Build multiple React UIs into self-contained HTML files.\n *\n * This function takes a record of React UI definitions and compiles each one\n * into a complete HTML file that includes React, ReactDOM, @mcp-apps-kit/ui-react,\n * and the user's component code.\n *\n * **IMPORTANT: Limitations**\n *\n * This programmatic build function serializes components using `.toString()`, which has\n * significant limitations:\n *\n * - **No external imports**: Components cannot import other modules, hooks, or utilities\n * - **No closures**: Components that capture external variables will not work\n * - **Simple components only**: Best for self-contained components without dependencies\n *\n * For production use, prefer the **Vite plugin** (`mcpReactUI`) which uses file paths\n * for proper import resolution and supports:\n * - Full import/export resolution\n * - CSS imports and CSS modules\n * - All React hooks and utilities\n * - External component dependencies\n *\n * This function is primarily intended for:\n * - **Testing**: Unit and integration tests for the build pipeline\n * - **Simple widgets**: Self-contained components with no external imports\n * - **Prototyping**: Quick experimentation before setting up Vite\n *\n * @param uis - Record of UI keys to React UI definitions\n * @param options - Build configuration options\n * @returns Build result with compiled HTML and metadata\n *\n * @example\n * ```typescript\n * // For production, use the Vite plugin instead:\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [mcpReactUI({ serverEntry: \"./src/index.ts\" })],\n * });\n *\n * // This programmatic API is for simple/test cases:\n * import { buildReactUIs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * // Only works with simple, self-contained components\n * const SimpleWidget = () => <div>Hello World</div>;\n *\n * const result = await buildReactUIs({\n * \"simple\": defineReactUI({\n * component: SimpleWidget,\n * name: \"Simple Widget\",\n * }),\n * });\n * ```\n */\nexport async function buildReactUIs(\n uis: Record<string, ReactUIDef>,\n options: BuildOptions = {}\n): Promise<BuildResult> {\n const startTime = Date.now();\n const outputs = new Map<string, string>();\n const files = new Map<string, string>();\n const warnings: string[] = [];\n const errors: BuildError[] = [];\n\n const cwd = options.cwd ?? process.cwd();\n\n // Create output directory if specified\n if (options.outDir) {\n await fs.mkdir(path.resolve(cwd, options.outDir), { recursive: true });\n }\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n try {\n globalCss = await fs.readFile(path.resolve(cwd, options.globalCss), \"utf-8\");\n } catch (error) {\n warnings.push(\n `Could not load global CSS from ${options.globalCss}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n // Build each UI\n for (const [key, def] of Object.entries(uis)) {\n try {\n const html = await compileComponent(key, def, {\n ...options,\n cwd,\n globalCss,\n });\n\n outputs.set(key, html);\n\n // Write to file if outDir specified\n if (options.outDir) {\n const outPath = path.resolve(cwd, options.outDir, `${key}.html`);\n await fs.writeFile(outPath, html, \"utf-8\");\n files.set(key, outPath);\n }\n } catch (error) {\n const buildError: BuildError = {\n key,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n errors.push(buildError);\n }\n }\n\n return {\n outputs,\n files,\n duration: Date.now() - startTime,\n warnings,\n errors,\n };\n}\n\n/**\n * Compile a single React component to self-contained HTML.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns Complete HTML document as a string\n */\nasync function compileComponent(\n key: string,\n def: ReactUIDef,\n options: BuildOptions & { cwd: string; globalCss?: string }\n): Promise<string> {\n // Get component from internal properties\n const component = def.__component;\n const componentName = component.name || \"Component\";\n const defaultProps = def.__defaultProps;\n const autoResize = def.__autoResize;\n\n // Create the entry point using function serialization\n // Note: The Vite plugin uses file paths for proper import resolution\n // This build function falls back to function serialization (limited - doesn't capture imports)\n const entryPoint = generateEntryPoint({\n componentPath: `__COMPONENT_PLACEHOLDER__`,\n defaultProps,\n autoResize,\n });\n\n // Configure plugins\n const plugins: esbuild.Plugin[] = [\n createComponentPlugin(component, componentName),\n createCSSPlugin(),\n ];\n\n // Use esbuild to bundle everything\n const result = await esbuild.build({\n stdin: {\n contents: entryPoint,\n loader: \"tsx\",\n resolveDir: options.cwd,\n sourcefile: `${key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ? \"inline\" : false,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n logLevel: \"warning\",\n external: options.external,\n plugins,\n define: {\n \"process.env.NODE_ENV\": options.minify ? '\"production\"' : '\"development\"',\n },\n });\n\n // Get the bundled JavaScript\n const outputFile = result.outputFiles?.[0];\n if (!outputFile) {\n throw new Error(`No output generated for UI: ${key}`);\n }\n\n const script = outputFile.text;\n\n // Collect any warnings from esbuild (currently silent, could add a logger later)\n // Warnings are typically about missing exports, unused imports, etc.\n // For now we don't surface these to users\n void result.warnings;\n\n // Generate the final HTML\n const html = generateHTML({\n key,\n name: def.name ?? key,\n script,\n css: options.globalCss,\n });\n\n return html;\n}\n\n/**\n * Create an esbuild plugin that resolves the component placeholder.\n *\n * This plugin intercepts imports of the placeholder module and replaces\n * it with the actual component code. This is necessary because we receive\n * a function reference, not a file path.\n */\nfunction createComponentPlugin(\n component: { toString: () => string },\n componentName: string\n): esbuild.Plugin {\n return {\n name: \"mcp-component-resolver\",\n setup(build) {\n // Intercept the placeholder import\n build.onResolve({ filter: /__COMPONENT_PLACEHOLDER__/ }, () => {\n return {\n path: \"__COMPONENT__\",\n namespace: \"mcp-component\",\n };\n });\n\n // Provide the component code\n build.onLoad({ filter: /.*/, namespace: \"mcp-component\" }, () => {\n // Serialize the component to a module\n // For now, we export a placeholder that requires runtime injection\n // In a real implementation, we'd need the component's source path\n const componentSource = component.toString();\n\n // Detect component type: class, function, or arrow function\n const isClassComponent = /^\\s*class\\b/.test(componentSource);\n const isFunctionComponent = /^\\s*function\\b/.test(componentSource);\n const isArrowFunction = !isClassComponent && !isFunctionComponent;\n\n let contents: string;\n if (isArrowFunction) {\n contents = `\n import React from \"react\";\n const ${componentName} = ${componentSource};\n export default ${componentName};\n `;\n } else {\n contents = `\n import React from \"react\";\n ${componentSource}\n export default ${componentName};\n `;\n }\n\n return {\n contents,\n loader: \"tsx\",\n };\n });\n },\n };\n}\n\n/**\n * Create an esbuild plugin that handles CSS imports.\n *\n * This plugin transforms CSS imports into JavaScript that injects\n * the styles into the document head at runtime.\n */\nfunction createCSSPlugin(): esbuild.Plugin {\n return {\n name: \"mcp-css-handler\",\n setup(build) {\n // Handle .css imports (excluding .module.css which has its own handler)\n build.onLoad({ filter: /\\.css$/ }, async (args) => {\n // Skip .module.css files - they're handled by the CSS modules loader\n if (args.path.endsWith(\".module.css\")) {\n return null;\n }\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Create JavaScript that injects the CSS\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(css)};\n document.head.appendChild(style);\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n\n // Handle CSS modules (.module.css)\n build.onLoad({ filter: /\\.module\\.css$/ }, async (args) => {\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Generate a simple class name mapping\n // In a real implementation, we'd use a proper CSS modules processor\n const classNames = extractClassNames(css);\n const mapping = Object.fromEntries(\n classNames.map((name) => [name, `${name}_${hashString(args.path)}`])\n );\n\n // Transform the CSS with new class names\n let transformedCss = css;\n for (const [original, hashed] of Object.entries(mapping)) {\n transformedCss = transformedCss.replace(\n new RegExp(`\\\\.${original}\\\\b`, \"g\"),\n `.${hashed}`\n );\n }\n\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(transformedCss)};\n document.head.appendChild(style);\n export default ${JSON.stringify(mapping)};\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n },\n };\n}\n\n/**\n * Extract class names from CSS content.\n */\nfunction extractClassNames(css: string): string[] {\n const classRegex = /\\.([a-zA-Z_][a-zA-Z0-9_-]*)/g;\n const classes = new Set<string>();\n let match;\n while ((match = classRegex.exec(css)) !== null) {\n if (match[1]) {\n classes.add(match[1]);\n }\n }\n return Array.from(classes);\n}\n\n/**\n * Simple string hash for generating unique class names.\n */\nfunction hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36).substring(0, 5);\n}\n\n/**\n * Build a single React UI.\n *\n * Convenience function for building just one UI.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns The compiled HTML string\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }));\n * ```\n */\nexport async function buildReactUI(\n key: string,\n def: ReactUIDef,\n options: BuildOptions = {}\n): Promise<string> {\n const result = await buildReactUIs({ [key]: def }, options);\n\n const html = result.outputs.get(key);\n if (!html) {\n const error = result.errors.find((e) => e.key === key);\n throw new Error(error?.message ?? `Failed to build UI: ${key}`);\n }\n\n return html;\n}\n"]}
var a=`
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
line-height: 1.5;
color: #1a1a1a;
background-color: transparent;
}
@media (prefers-color-scheme: dark) {
body {
color: #f5f5f5;
}
}
#root {
min-height: 100%;
}
`;function d(t){let{key:o,name:e,script:r,css:n}=t,i=n?`${a}
${n}`:a;return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="mcp-ui-key" content="${c(o)}">
<title>${c(e)}</title>
<style>${i}</style>
</head>
<body>
<div id="root"></div>
<script type="module">${r.replace(/<\/script>/gi,"</script>")}</script>
</body>
</html>`}function g(t,o){let e=typeof t=="string"?{componentPath:t,defaultProps:o}:t,{componentPath:r,componentExport:n="default",defaultProps:i,autoResize:s}=e,p=i?JSON.stringify(i):"{}",m=n==="default"?`import Component from "${r}";`:`import { ${n} as Component } from "${r}";`,l=s===void 0?"":` autoResize={${s}}`;return `
import React from "react";
import { createRoot } from "react-dom/client";
import { AppsProvider } from "@mcp-apps-kit/ui-react";
${m}
const rootElement = document.getElementById("root");
if (rootElement) {
const root = createRoot(rootElement);
root.render(
<React.StrictMode>
<AppsProvider${l}>
<Component {...${p}} />
</AppsProvider>
</React.StrictMode>
);
}
`}function c(t){let o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return t.replace(/[&<>"']/g,e=>o[e]??e)}export{d as a,g as b};//# sourceMappingURL=chunk-R7RJYHEX.js.map
//# sourceMappingURL=chunk-R7RJYHEX.js.map
{"version":3,"sources":["../src/html.ts"],"names":["DEFAULT_BASE_CSS","generateHTML","options","key","name","script","css","combinedCss","escapeHtml","generateEntryPoint","componentPathOrOptions","defaultProps","componentPath","componentExport","props","autoResize","propsJson","importStatement","providerProps","text","htmlEntities","char"],"mappings":"AAUA,IAAMA,CAAAA,CAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA,CA0DlB,SAASC,CAAAA,CAAaC,CAAAA,CAAkC,CAC7D,GAAM,CAAE,IAAAC,CAAAA,CAAK,IAAA,CAAAC,EAAM,MAAA,CAAAC,CAAAA,CAAQ,IAAAC,CAAI,CAAA,CAAIJ,EAG7BK,CAAAA,CAAcD,CAAAA,CAAM,GAAGN,CAAgB;AAAA,EAAKM,CAAG,CAAA,CAAA,CAAKN,CAAAA,CAE1D,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAAA,EAK4BQ,CAAAA,CAAWL,CAAG,CAAC,CAAA;AAAA,SAAA,EACzCK,CAAAA,CAAWJ,CAAI,CAAC,CAAA;AAAA,SAAA,EAChBG,CAAW,CAAA;AAAA;AAAA;AAAA;AAAA,wBAAA,EAIIF,CAAAA,CAAO,OAAA,CAAQ,cAAA,CAAgB,WAAgB,CAAC,CAAA;AAAA;AAAA,OAAA,CAG1E,CA8DO,SAASI,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACQ,CAER,IAAMT,CAAAA,CACJ,OAAOQ,CAAAA,EAA2B,QAAA,CAC9B,CAAE,cAAeA,CAAAA,CAAwB,YAAA,CAAAC,CAAa,CAAA,CACtDD,CAAAA,CAEA,CAAE,aAAA,CAAAE,CAAAA,CAAe,eAAA,CAAAC,CAAAA,CAAkB,SAAA,CAAW,YAAA,CAAcC,CAAAA,CAAO,UAAA,CAAAC,CAAW,CAAA,CAAIb,CAAAA,CAClFc,CAAAA,CAAYF,CAAAA,CAAQ,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAA,CAAI,IAAA,CAG5CG,CAAAA,CACJJ,CAAAA,GAAoB,SAAA,CAChB,CAAA,uBAAA,EAA0BD,CAAa,KACvC,CAAA,SAAA,EAAYC,CAAe,CAAA,sBAAA,EAAyBD,CAAa,CAAA,EAAA,CAAA,CAGjEM,CAAAA,CAAgBH,CAAAA,GAAe,MAAA,CAAY,EAAA,CAAK,CAAA,aAAA,EAAgBA,CAAU,CAAA,CAAA,CAAA,CAEhF,OAAO;AAAA;AAAA;AAAA;AAAA,EAIPE,CAAe;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAA,EAOIC,CAAa,CAAA;AAAA,uBAAA,EACTF,CAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAMlC,CAQA,SAASR,CAAAA,CAAWW,CAAAA,CAAsB,CACxC,IAAMC,CAAAA,CAAuC,CAC3C,GAAA,CAAK,OAAA,CACL,GAAA,CAAK,MAAA,CACL,GAAA,CAAK,MAAA,CACL,GAAA,CAAK,QAAA,CACL,GAAA,CAAK,OACP,CAAA,CAEA,OAAOD,CAAAA,CAAK,OAAA,CAAQ,UAAA,CAAaE,CAAAA,EAASD,CAAAA,CAAaC,CAAI,CAAA,EAAKA,CAAI,CACtE","file":"chunk-R7RJYHEX.js","sourcesContent":["/**\n * HTML template generation for React UIs\n */\n\nimport type { TemplateOptions } from \"./types\";\n\n/**\n * Default base CSS reset for all UIs.\n * Provides a consistent starting point across platforms.\n */\nconst DEFAULT_BASE_CSS = `\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html {\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n line-height: 1.5;\n color: #1a1a1a;\n background-color: transparent;\n }\n\n @media (prefers-color-scheme: dark) {\n body {\n color: #f5f5f5;\n }\n }\n\n #root {\n min-height: 100%;\n }\n`;\n\n/**\n * Generate a self-contained HTML document for a React UI.\n *\n * The generated HTML includes:\n * - DOCTYPE and valid HTML5 structure\n * - Meta tags for responsive design\n * - Inlined CSS (base reset + optional custom CSS)\n * - Inlined JavaScript bundle with React app\n *\n * @param options - Template options with key, name, script, and optional CSS\n * @returns Complete HTML document as a string\n *\n * @example\n * ```typescript\n * const html = generateHTML({\n * key: \"restaurant-list\",\n * name: \"Restaurant List Widget\",\n * script: bundledJavaScript,\n * css: customStyles,\n * });\n * ```\n *\n * @internal\n */\nexport function generateHTML(options: TemplateOptions): string {\n const { key, name, script, css } = options;\n\n // Combine base CSS with any custom CSS\n const combinedCss = css ? `${DEFAULT_BASE_CSS}\\n${css}` : DEFAULT_BASE_CSS;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"mcp-ui-key\" content=\"${escapeHtml(key)}\">\n <title>${escapeHtml(name)}</title>\n <style>${combinedCss}</style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\">${script.replace(/<\\/script>/gi, \"</scr\" + \"ipt>\")}</script>\n</body>\n</html>`;\n}\n\n/**\n * Options for generating the React entry point.\n *\n * @internal\n */\nexport interface EntryPointOptions {\n /**\n * Path to the component file.\n */\n componentPath: string;\n\n /**\n * Name of the export to use.\n * Use \"default\" for default exports, or the actual name for named exports.\n * @default \"default\"\n */\n componentExport?: string;\n\n /**\n * Default props to pass to the component.\n */\n defaultProps?: Record<string, unknown>;\n\n /**\n * Whether to enable automatic size change notifications.\n * When undefined, uses the default (true).\n */\n autoResize?: boolean;\n}\n\n/**\n * Generate the React entry point code that will be bundled.\n *\n * This creates a small JavaScript module that:\n * 1. Imports React and ReactDOM\n * 2. Imports the user's component\n * 3. Imports AppsProvider from @mcp-apps-kit/ui-react\n * 4. Renders the component wrapped in providers\n *\n * @param componentPath - Path to the React component file (for backward compatibility)\n * @param defaultProps - Optional default props to pass to the component\n * @returns JavaScript/TypeScript source code for the entry point\n *\n * @example\n * ```typescript\n * // Default export\n * const entryCode = generateEntryPoint(\n * \"./src/widgets/MyWidget.tsx\",\n * { theme: \"dark\" }\n * );\n *\n * // Named export\n * const entryCode = generateEntryPoint({\n * componentPath: \"./src/widgets/MyWidget.tsx\",\n * componentExport: \"MyWidget\",\n * });\n * ```\n *\n * @internal\n */\nexport function generateEntryPoint(\n componentPathOrOptions: string | EntryPointOptions,\n defaultProps?: Record<string, unknown>\n): string {\n // Handle backward compatibility with string-only signature\n const options: EntryPointOptions =\n typeof componentPathOrOptions === \"string\"\n ? { componentPath: componentPathOrOptions, defaultProps }\n : componentPathOrOptions;\n\n const { componentPath, componentExport = \"default\", defaultProps: props, autoResize } = options;\n const propsJson = props ? JSON.stringify(props) : \"{}\";\n\n // Generate appropriate import statement based on export type\n const importStatement =\n componentExport === \"default\"\n ? `import Component from \"${componentPath}\";`\n : `import { ${componentExport} as Component } from \"${componentPath}\";`;\n\n // Generate AppsProvider props\n const providerProps = autoResize === undefined ? \"\" : ` autoResize={${autoResize}}`;\n\n return `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\n${importStatement}\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider${providerProps}>\n <Component {...${propsJson}} />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n *\n * @param text - Text to escape\n * @returns Escaped text safe for HTML insertion\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] ?? char);\n}\n\n/**\n * Extract CSS from a string that may contain both JS and CSS.\n * Used when esbuild bundles CSS as JavaScript that injects styles.\n *\n * @param code - Bundled code that may contain CSS injection\n * @returns Extracted CSS string or undefined\n */\nexport function extractInlineCSS(code: string): string | undefined {\n // esbuild injects CSS as: document.head.appendChild(...).textContent = \"css content\"\n const cssMatch = code.match(/\\.textContent\\s*=\\s*[\"'`]([\\s\\S]*?)[\"'`]\\s*[;,)]/);\n if (cssMatch?.[1]) {\n // Unescape the CSS string\n return cssMatch[1].replace(/\\\\n/g, \"\\n\").replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n return undefined;\n}\n"]}
+16
-16

@@ -1,3 +0,3 @@

'use strict';var x=require('esbuild'),f=require('fs/promises'),d=require('path');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var x__namespace=/*#__PURE__*/_interopNamespace(x);var f__namespace=/*#__PURE__*/_interopNamespace(f);var d__namespace=/*#__PURE__*/_interopNamespace(d);var S=Object.defineProperty;var D=(e,t)=>()=>(e&&(t=e(e=0)),t);var _=(e,t)=>{for(var r in t)S(e,r,{get:t[r],enumerable:true});};function h(e){let{key:t,name:r,script:n,css:o}=e,s=o?`${b}
${o}`:b;return `<!DOCTYPE html>
'use strict';var x=require('esbuild'),u=require('fs/promises'),g=require('path');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var x__namespace=/*#__PURE__*/_interopNamespace(x);var u__namespace=/*#__PURE__*/_interopNamespace(u);var g__namespace=/*#__PURE__*/_interopNamespace(g);var _=Object.defineProperty;var b=(e,t)=>()=>(e&&(t=e(e=0)),t);var S=(e,t)=>{for(var r in t)_(e,r,{get:t[r],enumerable:true});};function R(e){let{key:t,name:r,script:o,css:n}=e,s=n?`${D}
${n}`:D;return `<!DOCTYPE html>
<html lang="en">

@@ -13,9 +13,9 @@ <head>

<div id="root"></div>
<script type="module">${n.replace(/<\/script>/gi,"</script>")}</script>
<script type="module">${o.replace(/<\/script>/gi,"</script>")}</script>
</body>
</html>`}function R(e,t){let r=typeof e=="string"?{componentPath:e,defaultProps:t}:e,{componentPath:n,componentExport:o="default",defaultProps:s}=r,c=s?JSON.stringify(s):"{}";return `
</html>`}function h(e,t){let r=typeof e=="string"?{componentPath:e,defaultProps:t}:e,{componentPath:o,componentExport:n="default",defaultProps:s,autoResize:a}=r,i=s?JSON.stringify(s):"{}",p=n==="default"?`import Component from "${o}";`:`import { ${n} as Component } from "${o}";`,c=a===void 0?"":` autoResize={${a}}`;return `
import React from "react";
import { createRoot } from "react-dom/client";
import { AppsProvider } from "@mcp-apps-kit/ui-react";
${o==="default"?`import Component from "${n}";`:`import { ${o} as Component } from "${n}";`}
${p}

@@ -27,4 +27,4 @@ const rootElement = document.getElementById("root");

<React.StrictMode>
<AppsProvider>
<Component {...${c}} />
<AppsProvider${c}>
<Component {...${i}} />
</AppsProvider>

@@ -34,3 +34,3 @@ </React.StrictMode>

}
`}function w(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return e.replace(/[&<>"']/g,r=>t[r]??r)}var b,y=D(()=>{b=`
`}function w(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return e.replace(/[&<>"']/g,r=>t[r]??r)}var D,y=b(()=>{D=`
*,

@@ -67,22 +67,22 @@ *::before,

}
`;});var C={};_(C,{buildReactUI:()=>E,buildReactUIs:()=>I});async function I(e,t={}){let r=Date.now(),n=new Map,o=new Map,s=[],c=[],i=t.cwd??process.cwd();t.outDir&&await f__namespace.mkdir(d__namespace.resolve(i,t.outDir),{recursive:true});let l;if(t.globalCss)try{l=await f__namespace.readFile(d__namespace.resolve(i,t.globalCss),"utf-8");}catch(a){s.push(`Could not load global CSS from ${t.globalCss}: ${a instanceof Error?a.message:String(a)}`);}for(let[a,g]of Object.entries(e))try{let p=await v(a,g,{...t,cwd:i,globalCss:l});if(n.set(a,p),t.outDir){let m=d__namespace.resolve(i,t.outDir,`${a}.html`);await f__namespace.writeFile(m,p,"utf-8"),o.set(a,m);}}catch(p){let m={key:a,message:p instanceof Error?p.message:String(p),stack:p instanceof Error?p.stack:void 0};c.push(m);}return {outputs:n,files:o,duration:Date.now()-r,warnings:s,errors:c}}async function v(e,t,r){let n=t.__component,o=n.name||"Component",s=t.__defaultProps,c=R("__COMPONENT_PLACEHOLDER__",s),i=[T(n,o),N()],l=await x__namespace.build({stdin:{contents:c,loader:"tsx",resolveDir:r.cwd,sourcefile:`${e}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:r.minify??true,sourcemap:r.sourcemap?"inline":false,jsx:"automatic",jsxImportSource:"react",logLevel:"warning",external:r.external,plugins:i,define:{"process.env.NODE_ENV":r.minify?'"production"':'"development"'}}),a=l.outputFiles?.[0];if(!a)throw new Error(`No output generated for UI: ${e}`);let g=a.text;return l.warnings,h({key:e,name:t.name??e,script:g,css:r.globalCss})}function T(e,t){return {name:"mcp-component-resolver",setup(r){r.onResolve({filter:/__COMPONENT_PLACEHOLDER__/},()=>({path:"__COMPONENT__",namespace:"mcp-component"})),r.onLoad({filter:/.*/,namespace:"mcp-component"},()=>{let n=e.toString(),o=/^\s*class\b/.test(n),s=/^\s*function\b/.test(n),c=!o&&!s,i;return c?i=`
`;});var $={};S($,{buildReactUI:()=>E,buildReactUIs:()=>I});async function I(e,t={}){let r=Date.now(),o=new Map,n=new Map,s=[],a=[],i=t.cwd??process.cwd();t.outDir&&await u__namespace.mkdir(g__namespace.resolve(i,t.outDir),{recursive:true});let p;if(t.globalCss)try{p=await u__namespace.readFile(g__namespace.resolve(i,t.globalCss),"utf-8");}catch(c){s.push(`Could not load global CSS from ${t.globalCss}: ${c instanceof Error?c.message:String(c)}`);}for(let[c,m]of Object.entries(e))try{let l=await v(c,m,{...t,cwd:i,globalCss:p});if(o.set(c,l),t.outDir){let f=g__namespace.resolve(i,t.outDir,`${c}.html`);await u__namespace.writeFile(f,l,"utf-8"),n.set(c,f);}}catch(l){let f={key:c,message:l instanceof Error?l.message:String(l),stack:l instanceof Error?l.stack:void 0};a.push(f);}return {outputs:o,files:n,duration:Date.now()-r,warnings:s,errors:a}}async function v(e,t,r){let o=t.__component,n=o.name||"Component",s=t.__defaultProps,a=t.__autoResize,i=h({componentPath:"__COMPONENT_PLACEHOLDER__",defaultProps:s,autoResize:a}),p=[T(o,n),N()],c=await x__namespace.build({stdin:{contents:i,loader:"tsx",resolveDir:r.cwd,sourcefile:`${e}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:r.minify??true,sourcemap:r.sourcemap?"inline":false,jsx:"automatic",jsxImportSource:"react",logLevel:"warning",external:r.external,plugins:p,define:{"process.env.NODE_ENV":r.minify?'"production"':'"development"'}}),m=c.outputFiles?.[0];if(!m)throw new Error(`No output generated for UI: ${e}`);let l=m.text;return c.warnings,R({key:e,name:t.name??e,script:l,css:r.globalCss})}function T(e,t){return {name:"mcp-component-resolver",setup(r){r.onResolve({filter:/__COMPONENT_PLACEHOLDER__/},()=>({path:"__COMPONENT__",namespace:"mcp-component"})),r.onLoad({filter:/.*/,namespace:"mcp-component"},()=>{let o=e.toString(),n=/^\s*class\b/.test(o),s=/^\s*function\b/.test(o),a=!n&&!s,i;return a?i=`
import React from "react";
const ${t} = ${n};
const ${t} = ${o};
export default ${t};
`:i=`
import React from "react";
${n}
${o}
export default ${t};
`,{contents:i,loader:"tsx"}});}}}function N(){return {name:"mcp-css-handler",setup(e){e.onLoad({filter:/\.css$/},async t=>{if(t.path.endsWith(".module.css"))return null;let r=await f__namespace.readFile(t.path,"utf-8");return {contents:`
`,{contents:i,loader:"tsx"}});}}}function N(){return {name:"mcp-css-handler",setup(e){e.onLoad({filter:/\.css$/},async t=>{if(t.path.endsWith(".module.css"))return null;let r=await u__namespace.readFile(t.path,"utf-8");return {contents:`
const style = document.createElement("style");
style.textContent = ${JSON.stringify(r)};
document.head.appendChild(style);
`,loader:"js"}}),e.onLoad({filter:/\.module\.css$/},async t=>{let r=await f__namespace.readFile(t.path,"utf-8"),n=k(r),o=Object.fromEntries(n.map(i=>[i,`${i}_${A(t.path)}`])),s=r;for(let[i,l]of Object.entries(o))s=s.replace(new RegExp(`\\.${i}\\b`,"g"),`.${l}`);return {contents:`
`,loader:"js"}}),e.onLoad({filter:/\.module\.css$/},async t=>{let r=await u__namespace.readFile(t.path,"utf-8"),o=k(r),n=Object.fromEntries(o.map(i=>[i,`${i}_${A(t.path)}`])),s=r;for(let[i,p]of Object.entries(n))s=s.replace(new RegExp(`\\.${i}\\b`,"g"),`.${p}`);return {contents:`
const style = document.createElement("style");
style.textContent = ${JSON.stringify(s)};
document.head.appendChild(style);
export default ${JSON.stringify(o)};
`,loader:"js"}});}}}function k(e){let t=/\.([a-zA-Z_][a-zA-Z0-9_-]*)/g,r=new Set,n;for(;(n=t.exec(e))!==null;)n[1]&&r.add(n[1]);return Array.from(r)}function A(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);t=(t<<5)-t+n,t=t&t;}return Math.abs(t).toString(36).substring(0,5)}async function E(e,t,r={}){let n=await I({[e]:t},r),o=n.outputs.get(e);if(!o){let s=n.errors.find(c=>c.key===e);throw new Error(s?.message??`Failed to build UI: ${e}`)}return o}var U=D(()=>{y();});function O(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function B(e){let{component:t,defaultProps:r,outDir:n,...o}=e,s=t.name??"component",c=O(s),l=`${n??"./src/ui/dist"}/${c}.html`;return {...o,html:l,__reactUI:true,__component:t,__defaultProps:r}}function u(e){return typeof e=="object"&&e!==null&&"__reactUI"in e&&e.__reactUI}U();function $(e,t){let r={};for(let[n,o]of Object.entries(e))if(u(o)){let s=t.outputs.get(n);if(!s){let c=t.errors.find(i=>i.key===n);throw c?new Error(`Build failed for React UI "${n}": ${c.message}`):new Error(`No build output found for React UI "${n}". Did you forget to include it in buildReactUIs()?`)}r[n]={html:s,name:o.name,description:o.description,widgetDescription:o.widgetDescription,csp:o.csp,prefersBorder:o.prefersBorder,domain:o.domain};}else r[n]=o;return r}function F(e,t){return {html:t,name:e.name,description:e.description,widgetDescription:e.widgetDescription,csp:e.csp,prefersBorder:e.prefersBorder,domain:e.domain}}function P(e){let t={},r={};for(let[n,o]of Object.entries(e))u(o)?t[n]=o:r[n]=o;return {reactUIs:t,standardUIs:r}}async function M(e,t){let{buildReactUIs:r}=await Promise.resolve().then(()=>(U(),C)),{reactUIs:n,standardUIs:o}=P(e);if(Object.keys(n).length===0)return o;let s=await r(n,t);if(s.errors.length>0){let c=s.errors.map(i=>` - ${i.key}: ${i.message}`).join(`
export default ${JSON.stringify(n)};
`,loader:"js"}});}}}function k(e){let t=/\.([a-zA-Z_][a-zA-Z0-9_-]*)/g,r=new Set,o;for(;(o=t.exec(e))!==null;)o[1]&&r.add(o[1]);return Array.from(r)}function A(e){let t=0;for(let r=0;r<e.length;r++){let o=e.charCodeAt(r);t=(t<<5)-t+o,t=t&t;}return Math.abs(t).toString(36).substring(0,5)}async function E(e,t,r={}){let o=await I({[e]:t},r),n=o.outputs.get(e);if(!n){let s=o.errors.find(a=>a.key===e);throw new Error(s?.message??`Failed to build UI: ${e}`)}return n}var U=b(()=>{y();});function O(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function B(e){let{component:t,defaultProps:r,outDir:o,autoResize:n,...s}=e,a=t.name??"component",i=O(a),c=`${o??"./src/ui/dist"}/${i}.html`;return {...s,html:c,__reactUI:true,__component:t,__defaultProps:r,__autoResize:n??true}}function d(e){return typeof e=="object"&&e!==null&&"__reactUI"in e&&e.__reactUI}U();function C(e,t){let r={};for(let[o,n]of Object.entries(e))if(d(n)){let s=t.outputs.get(o);if(!s){let a=t.errors.find(i=>i.key===o);throw a?new Error(`Build failed for React UI "${o}": ${a.message}`):new Error(`No build output found for React UI "${o}". Did you forget to include it in buildReactUIs()?`)}r[o]={html:s,name:n.name,description:n.description,widgetDescription:n.widgetDescription,csp:n.csp,prefersBorder:n.prefersBorder,domain:n.domain};}else r[o]=n;return r}function F(e,t){return {html:t,name:e.name,description:e.description,widgetDescription:e.widgetDescription,csp:e.csp,prefersBorder:e.prefersBorder,domain:e.domain}}function P(e){let t={},r={};for(let[o,n]of Object.entries(e))d(n)?t[o]=n:r[o]=n;return {reactUIs:t,standardUIs:r}}async function M(e,t){let{buildReactUIs:r}=await Promise.resolve().then(()=>(U(),$)),{reactUIs:o,standardUIs:n}=P(e);if(Object.keys(o).length===0)return n;let s=await r(o,t);if(s.errors.length>0){let a=s.errors.map(i=>` - ${i.key}: ${i.message}`).join(`
`);throw new Error(`Failed to build some React UIs:
${c}`)}return {...o,...$(n,s)}}y();exports.buildAndTransform=M;exports.buildReactUI=E;exports.buildReactUIs=I;exports.defineReactUI=B;exports.extractReactUIs=P;exports.generateEntryPoint=R;exports.generateHTML=h;exports.isReactUIDef=u;exports.transformSingleToCoreDef=F;exports.transformToCoreDefs=$;//# sourceMappingURL=index.cjs.map
${a}`)}return {...n,...C(o,s)}}y();exports.buildAndTransform=M;exports.buildReactUI=E;exports.buildReactUIs=I;exports.defineReactUI=B;exports.extractReactUIs=P;exports.generateEntryPoint=h;exports.generateHTML=R;exports.isReactUIDef=d;exports.transformSingleToCoreDef=F;exports.transformToCoreDefs=C;//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/html.ts","../src/build.ts","../src/define.ts","../src/index.ts","../src/transform.ts"],"names":["generateHTML","options","key","name","script","css","combinedCss","DEFAULT_BASE_CSS","escapeHtml","generateEntryPoint","componentPathOrOptions","defaultProps","componentPath","componentExport","props","propsJson","text","htmlEntities","char","init_html","__esmMin","build_exports","__export","buildReactUI","buildReactUIs","uis","startTime","outputs","files","warnings","errors","cwd","f","d","globalCss","error","def","html","compileComponent","outPath","buildError","component","componentName","entryPoint","plugins","createComponentPlugin","createCSSPlugin","result","x","outputFile","build","componentSource","isClassComponent","isFunctionComponent","isArrowFunction","contents","args","classNames","extractClassNames","mapping","hashString","transformedCss","original","hashed","classRegex","classes","match","str","hash","i","e","init_build","toKebabCase","defineReactUI","definition","outDir","rest","htmlPath","isReactUIDef","value","transformToCoreDefs","defs","buildResult","transformSingleToCoreDef","extractReactUIs","reactUIs","standardUIs","buildAndTransform","errorMessages"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * HTML template generation for React UIs\n */\n\nimport type { TemplateOptions } from \"./types\";\n\n/**\n * Default base CSS reset for all UIs.\n * Provides a consistent starting point across platforms.\n */\nconst DEFAULT_BASE_CSS = `\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html {\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n line-height: 1.5;\n color: #1a1a1a;\n background-color: transparent;\n }\n\n @media (prefers-color-scheme: dark) {\n body {\n color: #f5f5f5;\n }\n }\n\n #root {\n min-height: 100%;\n }\n`;\n\n/**\n * Generate a self-contained HTML document for a React UI.\n *\n * The generated HTML includes:\n * - DOCTYPE and valid HTML5 structure\n * - Meta tags for responsive design\n * - Inlined CSS (base reset + optional custom CSS)\n * - Inlined JavaScript bundle with React app\n *\n * @param options - Template options with key, name, script, and optional CSS\n * @returns Complete HTML document as a string\n *\n * @example\n * ```typescript\n * const html = generateHTML({\n * key: \"restaurant-list\",\n * name: \"Restaurant List Widget\",\n * script: bundledJavaScript,\n * css: customStyles,\n * });\n * ```\n *\n * @internal\n */\nexport function generateHTML(options: TemplateOptions): string {\n const { key, name, script, css } = options;\n\n // Combine base CSS with any custom CSS\n const combinedCss = css ? `${DEFAULT_BASE_CSS}\\n${css}` : DEFAULT_BASE_CSS;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"mcp-ui-key\" content=\"${escapeHtml(key)}\">\n <title>${escapeHtml(name)}</title>\n <style>${combinedCss}</style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\">${script.replace(/<\\/script>/gi, \"</scr\" + \"ipt>\")}</script>\n</body>\n</html>`;\n}\n\n/**\n * Options for generating the React entry point.\n *\n * @internal\n */\nexport interface EntryPointOptions {\n /**\n * Path to the component file.\n */\n componentPath: string;\n\n /**\n * Name of the export to use.\n * Use \"default\" for default exports, or the actual name for named exports.\n * @default \"default\"\n */\n componentExport?: string;\n\n /**\n * Default props to pass to the component.\n */\n defaultProps?: Record<string, unknown>;\n}\n\n/**\n * Generate the React entry point code that will be bundled.\n *\n * This creates a small JavaScript module that:\n * 1. Imports React and ReactDOM\n * 2. Imports the user's component\n * 3. Imports AppsProvider from @mcp-apps-kit/ui-react\n * 4. Renders the component wrapped in providers\n *\n * @param componentPath - Path to the React component file (for backward compatibility)\n * @param defaultProps - Optional default props to pass to the component\n * @returns JavaScript/TypeScript source code for the entry point\n *\n * @example\n * ```typescript\n * // Default export\n * const entryCode = generateEntryPoint(\n * \"./src/widgets/MyWidget.tsx\",\n * { theme: \"dark\" }\n * );\n *\n * // Named export\n * const entryCode = generateEntryPoint({\n * componentPath: \"./src/widgets/MyWidget.tsx\",\n * componentExport: \"MyWidget\",\n * });\n * ```\n *\n * @internal\n */\nexport function generateEntryPoint(\n componentPathOrOptions: string | EntryPointOptions,\n defaultProps?: Record<string, unknown>\n): string {\n // Handle backward compatibility with string-only signature\n const options: EntryPointOptions =\n typeof componentPathOrOptions === \"string\"\n ? { componentPath: componentPathOrOptions, defaultProps }\n : componentPathOrOptions;\n\n const { componentPath, componentExport = \"default\", defaultProps: props } = options;\n const propsJson = props ? JSON.stringify(props) : \"{}\";\n\n // Generate appropriate import statement based on export type\n const importStatement =\n componentExport === \"default\"\n ? `import Component from \"${componentPath}\";`\n : `import { ${componentExport} as Component } from \"${componentPath}\";`;\n\n return `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\n${importStatement}\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider>\n <Component {...${propsJson}} />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n *\n * @param text - Text to escape\n * @returns Escaped text safe for HTML insertion\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] ?? char);\n}\n\n/**\n * Extract CSS from a string that may contain both JS and CSS.\n * Used when esbuild bundles CSS as JavaScript that injects styles.\n *\n * @param code - Bundled code that may contain CSS injection\n * @returns Extracted CSS string or undefined\n */\nexport function extractInlineCSS(code: string): string | undefined {\n // esbuild injects CSS as: document.head.appendChild(...).textContent = \"css content\"\n const cssMatch = code.match(/\\.textContent\\s*=\\s*[\"'`]([\\s\\S]*?)[\"'`]\\s*[;,)]/);\n if (cssMatch?.[1]) {\n // Unescape the CSS string\n return cssMatch[1].replace(/\\\\n/g, \"\\n\").replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n return undefined;\n}\n","/**\n * React UI build system using esbuild\n *\n * Compiles React components into self-contained HTML files that can be\n * served as MCP UI resources.\n */\n\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { ReactUIDef, BuildOptions, BuildResult, BuildError } from \"./types\";\nimport { generateHTML, generateEntryPoint } from \"./html\";\n\n/**\n * Build multiple React UIs into self-contained HTML files.\n *\n * This function takes a record of React UI definitions and compiles each one\n * into a complete HTML file that includes React, ReactDOM, @mcp-apps-kit/ui-react,\n * and the user's component code.\n *\n * **IMPORTANT: Limitations**\n *\n * This programmatic build function serializes components using `.toString()`, which has\n * significant limitations:\n *\n * - **No external imports**: Components cannot import other modules, hooks, or utilities\n * - **No closures**: Components that capture external variables will not work\n * - **Simple components only**: Best for self-contained components without dependencies\n *\n * For production use, prefer the **Vite plugin** (`mcpReactUI`) which uses file paths\n * for proper import resolution and supports:\n * - Full import/export resolution\n * - CSS imports and CSS modules\n * - All React hooks and utilities\n * - External component dependencies\n *\n * This function is primarily intended for:\n * - **Testing**: Unit and integration tests for the build pipeline\n * - **Simple widgets**: Self-contained components with no external imports\n * - **Prototyping**: Quick experimentation before setting up Vite\n *\n * @param uis - Record of UI keys to React UI definitions\n * @param options - Build configuration options\n * @returns Build result with compiled HTML and metadata\n *\n * @example\n * ```typescript\n * // For production, use the Vite plugin instead:\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [mcpReactUI({ serverEntry: \"./src/index.ts\" })],\n * });\n *\n * // This programmatic API is for simple/test cases:\n * import { buildReactUIs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * // Only works with simple, self-contained components\n * const SimpleWidget = () => <div>Hello World</div>;\n *\n * const result = await buildReactUIs({\n * \"simple\": defineReactUI({\n * component: SimpleWidget,\n * name: \"Simple Widget\",\n * }),\n * });\n * ```\n */\nexport async function buildReactUIs(\n uis: Record<string, ReactUIDef>,\n options: BuildOptions = {}\n): Promise<BuildResult> {\n const startTime = Date.now();\n const outputs = new Map<string, string>();\n const files = new Map<string, string>();\n const warnings: string[] = [];\n const errors: BuildError[] = [];\n\n const cwd = options.cwd ?? process.cwd();\n\n // Create output directory if specified\n if (options.outDir) {\n await fs.mkdir(path.resolve(cwd, options.outDir), { recursive: true });\n }\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n try {\n globalCss = await fs.readFile(path.resolve(cwd, options.globalCss), \"utf-8\");\n } catch (error) {\n warnings.push(\n `Could not load global CSS from ${options.globalCss}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n // Build each UI\n for (const [key, def] of Object.entries(uis)) {\n try {\n const html = await compileComponent(key, def, {\n ...options,\n cwd,\n globalCss,\n });\n\n outputs.set(key, html);\n\n // Write to file if outDir specified\n if (options.outDir) {\n const outPath = path.resolve(cwd, options.outDir, `${key}.html`);\n await fs.writeFile(outPath, html, \"utf-8\");\n files.set(key, outPath);\n }\n } catch (error) {\n const buildError: BuildError = {\n key,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n errors.push(buildError);\n }\n }\n\n return {\n outputs,\n files,\n duration: Date.now() - startTime,\n warnings,\n errors,\n };\n}\n\n/**\n * Compile a single React component to self-contained HTML.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns Complete HTML document as a string\n */\nasync function compileComponent(\n key: string,\n def: ReactUIDef,\n options: BuildOptions & { cwd: string; globalCss?: string }\n): Promise<string> {\n // Get component from internal properties\n const component = def.__component;\n const componentName = component.name || \"Component\";\n const defaultProps = def.__defaultProps;\n\n // Create the entry point using function serialization\n // Note: The Vite plugin uses file paths for proper import resolution\n // This build function falls back to function serialization (limited - doesn't capture imports)\n const entryPoint = generateEntryPoint(`__COMPONENT_PLACEHOLDER__`, defaultProps);\n\n // Configure plugins\n const plugins: esbuild.Plugin[] = [\n createComponentPlugin(component, componentName),\n createCSSPlugin(),\n ];\n\n // Use esbuild to bundle everything\n const result = await esbuild.build({\n stdin: {\n contents: entryPoint,\n loader: \"tsx\",\n resolveDir: options.cwd,\n sourcefile: `${key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ? \"inline\" : false,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n logLevel: \"warning\",\n external: options.external,\n plugins,\n define: {\n \"process.env.NODE_ENV\": options.minify ? '\"production\"' : '\"development\"',\n },\n });\n\n // Get the bundled JavaScript\n const outputFile = result.outputFiles?.[0];\n if (!outputFile) {\n throw new Error(`No output generated for UI: ${key}`);\n }\n\n const script = outputFile.text;\n\n // Collect any warnings from esbuild (currently silent, could add a logger later)\n // Warnings are typically about missing exports, unused imports, etc.\n // For now we don't surface these to users\n void result.warnings;\n\n // Generate the final HTML\n const html = generateHTML({\n key,\n name: def.name ?? key,\n script,\n css: options.globalCss,\n });\n\n return html;\n}\n\n/**\n * Create an esbuild plugin that resolves the component placeholder.\n *\n * This plugin intercepts imports of the placeholder module and replaces\n * it with the actual component code. This is necessary because we receive\n * a function reference, not a file path.\n */\nfunction createComponentPlugin(\n component: { toString: () => string },\n componentName: string\n): esbuild.Plugin {\n return {\n name: \"mcp-component-resolver\",\n setup(build) {\n // Intercept the placeholder import\n build.onResolve({ filter: /__COMPONENT_PLACEHOLDER__/ }, () => {\n return {\n path: \"__COMPONENT__\",\n namespace: \"mcp-component\",\n };\n });\n\n // Provide the component code\n build.onLoad({ filter: /.*/, namespace: \"mcp-component\" }, () => {\n // Serialize the component to a module\n // For now, we export a placeholder that requires runtime injection\n // In a real implementation, we'd need the component's source path\n const componentSource = component.toString();\n\n // Detect component type: class, function, or arrow function\n const isClassComponent = /^\\s*class\\b/.test(componentSource);\n const isFunctionComponent = /^\\s*function\\b/.test(componentSource);\n const isArrowFunction = !isClassComponent && !isFunctionComponent;\n\n let contents: string;\n if (isArrowFunction) {\n contents = `\n import React from \"react\";\n const ${componentName} = ${componentSource};\n export default ${componentName};\n `;\n } else {\n contents = `\n import React from \"react\";\n ${componentSource}\n export default ${componentName};\n `;\n }\n\n return {\n contents,\n loader: \"tsx\",\n };\n });\n },\n };\n}\n\n/**\n * Create an esbuild plugin that handles CSS imports.\n *\n * This plugin transforms CSS imports into JavaScript that injects\n * the styles into the document head at runtime.\n */\nfunction createCSSPlugin(): esbuild.Plugin {\n return {\n name: \"mcp-css-handler\",\n setup(build) {\n // Handle .css imports (excluding .module.css which has its own handler)\n build.onLoad({ filter: /\\.css$/ }, async (args) => {\n // Skip .module.css files - they're handled by the CSS modules loader\n if (args.path.endsWith(\".module.css\")) {\n return null;\n }\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Create JavaScript that injects the CSS\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(css)};\n document.head.appendChild(style);\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n\n // Handle CSS modules (.module.css)\n build.onLoad({ filter: /\\.module\\.css$/ }, async (args) => {\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Generate a simple class name mapping\n // In a real implementation, we'd use a proper CSS modules processor\n const classNames = extractClassNames(css);\n const mapping = Object.fromEntries(\n classNames.map((name) => [name, `${name}_${hashString(args.path)}`])\n );\n\n // Transform the CSS with new class names\n let transformedCss = css;\n for (const [original, hashed] of Object.entries(mapping)) {\n transformedCss = transformedCss.replace(\n new RegExp(`\\\\.${original}\\\\b`, \"g\"),\n `.${hashed}`\n );\n }\n\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(transformedCss)};\n document.head.appendChild(style);\n export default ${JSON.stringify(mapping)};\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n },\n };\n}\n\n/**\n * Extract class names from CSS content.\n */\nfunction extractClassNames(css: string): string[] {\n const classRegex = /\\.([a-zA-Z_][a-zA-Z0-9_-]*)/g;\n const classes = new Set<string>();\n let match;\n while ((match = classRegex.exec(css)) !== null) {\n if (match[1]) {\n classes.add(match[1]);\n }\n }\n return Array.from(classes);\n}\n\n/**\n * Simple string hash for generating unique class names.\n */\nfunction hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36).substring(0, 5);\n}\n\n/**\n * Build a single React UI.\n *\n * Convenience function for building just one UI.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns The compiled HTML string\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }));\n * ```\n */\nexport async function buildReactUI(\n key: string,\n def: ReactUIDef,\n options: BuildOptions = {}\n): Promise<string> {\n const result = await buildReactUIs({ [key]: def }, options);\n\n const html = result.outputs.get(key);\n if (!html) {\n const error = result.errors.find((e) => e.key === key);\n throw new Error(error?.message ?? `Failed to build UI: ${key}`);\n }\n\n return html;\n}\n","/**\n * Helper functions for defining React-based UIs\n */\n\nimport type { ReactUIInput, ReactUIDef } from \"./types\";\n\n/**\n * Convert component name to kebab-case for filename.\n * @internal\n */\nfunction toKebabCase(name: string): string {\n return name.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n\n/**\n * Define a UI using a React component.\n *\n * This helper creates a UIDef with an auto-generated HTML path based on\n * the component name. The Vite plugin discovers these definitions and\n * builds the React components into self-contained HTML files.\n *\n * @param definition - React UI input with component and metadata\n * @returns A UIDef with auto-generated html path and React metadata\n *\n * @example Basic usage\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * const widgetUI = defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * prefersBorder: true,\n * });\n * // Returns: { html: \"./src/ui/dist/my-widget.html\", name: \"My Widget\", ... }\n * ```\n *\n * @example With tool definition\n * ```typescript\n * import { createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { RestaurantList } from \"./widgets/RestaurantList\";\n *\n * const app = createApp({\n * name: \"restaurant-finder\",\n * version: \"1.0.0\",\n * tools: {\n * search: defineTool({\n * description: \"Search for restaurants\",\n * input: z.object({ query: z.string() }),\n * output: z.object({ restaurants: z.array(RestaurantSchema) }),\n * ui: defineReactUI({\n * component: RestaurantList,\n * name: \"Restaurant List\",\n * }),\n * handler: async (input) => {\n * // ... search logic\n * },\n * }),\n * },\n * });\n * ```\n *\n * @example Custom output directory\n * ```typescript\n * const widgetUI = defineReactUI({\n * component: ConfigurableWidget,\n * name: \"Configurable Widget\",\n * outDir: \"./dist/ui\",\n * });\n * // Returns: { html: \"./dist/ui/configurable-widget.html\", ... }\n * ```\n */\nexport function defineReactUI(definition: ReactUIInput): ReactUIDef {\n const { component, defaultProps, outDir, ...rest } = definition;\n\n // Generate the output path from component name\n const componentName = component.name ?? \"component\";\n const key = toKebabCase(componentName);\n const outputDir = outDir ?? \"./src/ui/dist\";\n const htmlPath = `${outputDir}/${key}.html`;\n\n return {\n ...rest,\n html: htmlPath,\n __reactUI: true,\n __component: component,\n __defaultProps: defaultProps,\n };\n}\n\n/**\n * Check if a value is a React UI definition.\n *\n * This type guard is used by the build system to identify\n * React UIs that need to be compiled to HTML.\n *\n * @param value - Value to check\n * @returns True if the value is a ReactUIDef\n *\n * @example\n * ```typescript\n * import { isReactUIDef } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * const ui = someUnknownUI;\n * if (isReactUIDef(ui)) {\n * // ui.__component is available here\n * console.log(\"React UI:\", ui.__component.name);\n * }\n * ```\n *\n * @internal\n */\nexport function isReactUIDef(value: unknown): value is ReactUIDef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__reactUI\" in value &&\n (value as ReactUIDef).__reactUI\n );\n}\n","/**\n * @mcp-apps-kit/ui-react-builder\n *\n * Build tool for React-based MCP application UIs.\n *\n * This package allows you to define UI resources using React components\n * instead of pre-built HTML files. The framework handles bundling React,\n * ReactDOM, and @mcp-apps-kit/ui-react into self-contained HTML that works\n * with both MCP Apps (Claude Desktop) and ChatGPT.\n *\n * @example Basic usage\n * ```typescript\n * import { defineReactUI, buildReactUIs } from \"@mcp-apps-kit/ui-react-builder\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * // Define your UI with a React component\n * const widgetUI = defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * prefersBorder: true,\n * });\n *\n * // Build to HTML\n * const result = await buildReactUIs({\n * \"my-widget\": widgetUI,\n * }, {\n * outDir: \"./dist/ui\",\n * });\n *\n * console.log(`Built ${result.outputs.size} UIs in ${result.duration}ms`);\n * ```\n *\n * @example With tool definition\n * ```typescript\n * import { createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { defineReactUI, buildAndTransform } from \"@mcp-apps-kit/ui-react-builder\";\n * import { RestaurantList } from \"./widgets/RestaurantList\";\n * import { z } from \"zod\";\n *\n * // Build and transform in one step\n * const uis = await buildAndTransform({\n * \"restaurant-list\": defineReactUI({\n * component: RestaurantList,\n * name: \"Restaurant List\",\n * }),\n * });\n *\n * const app = createApp({\n * name: \"restaurant-finder\",\n * version: \"1.0.0\",\n * tools: {\n * search: defineTool({\n * description: \"Search for restaurants\",\n * input: z.object({ query: z.string() }),\n * output: z.object({ restaurants: z.array(z.unknown()) }),\n * ui: uis[\"restaurant-list\"],\n * handler: async (input) => {\n * // ... search logic\n * return { restaurants: [] };\n * },\n * }),\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\n// =============================================================================\n// TYPE EXPORTS\n// =============================================================================\n\nexport type {\n ReactUIInput,\n ReactUIDef,\n BuildOptions,\n BuildResult,\n BuildError,\n TemplateOptions,\n DevServerOptions,\n} from \"./types\";\n\n// =============================================================================\n// DEFINITION HELPERS\n// =============================================================================\n\nexport { defineReactUI, isReactUIDef } from \"./define\";\n\n// =============================================================================\n// BUILD FUNCTIONS\n// =============================================================================\n\nexport { buildReactUIs, buildReactUI } from \"./build\";\n\n// =============================================================================\n// TRANSFORM UTILITIES\n// =============================================================================\n\nexport {\n transformToCoreDefs,\n transformSingleToCoreDef,\n extractReactUIs,\n buildAndTransform,\n} from \"./transform\";\n\n// =============================================================================\n// HTML UTILITIES\n// =============================================================================\n\nexport type { EntryPointOptions } from \"./html\";\nexport { generateHTML, generateEntryPoint } from \"./html\";\n","/**\n * Transform utilities for converting ReactUIDef to standard UIDef\n *\n * After building React UIs, this module helps convert them to the\n * standard UIDef format that @mcp-apps-kit/core understands.\n */\n\nimport type { UIDef } from \"@mcp-apps-kit/core\";\nimport type { ReactUIDef, BuildResult } from \"./types\";\nimport { isReactUIDef } from \"./define\";\n\n/**\n * Transform React UI definitions to standard core UIDefs.\n *\n * This function takes a mix of React UIs and standard UIs, and converts\n * all React UIs to standard UIDefs using the build result. Standard UIDefs\n * pass through unchanged.\n *\n * Use this after calling `buildReactUIs` to get definitions that can be\n * passed directly to `createApp`.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param buildResult - Result from buildReactUIs containing compiled HTML\n * @returns Record of UI keys to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildReactUIs, transformToCoreDefs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * // Define a mix of React and standard UIs\n * const uis = {\n * \"react-widget\": defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }),\n * \"html-widget\": defineUI({\n * html: \"./widget.html\",\n * name: \"HTML Widget\",\n * }),\n * };\n *\n * // Build React UIs\n * const buildResult = await buildReactUIs({\n * \"react-widget\": uis[\"react-widget\"] as ReactUIDef,\n * });\n *\n * // Transform all to core format\n * const coreDefs = transformToCoreDefs(uis, buildResult);\n *\n * // Now use with createApp\n * const app = createApp({\n * name: \"my-app\",\n * version: \"1.0.0\",\n * tools: {\n * myTool: defineTool({\n * // ... tool definition\n * ui: coreDefs[\"react-widget\"],\n * }),\n * },\n * });\n * ```\n */\nexport function transformToCoreDefs(\n defs: Record<string, ReactUIDef | UIDef>,\n buildResult: BuildResult\n): Record<string, UIDef> {\n const result: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n // Get compiled HTML from build result\n const html = buildResult.outputs.get(key);\n if (!html) {\n // Check if there was a build error\n const error = buildResult.errors.find((e) => e.key === key);\n if (error) {\n throw new Error(`Build failed for React UI \"${key}\": ${error.message}`);\n }\n throw new Error(\n `No build output found for React UI \"${key}\". Did you forget to include it in buildReactUIs()?`\n );\n }\n\n // Transform ReactUIDef to UIDef with inline HTML\n result[key] = {\n html, // Inline the compiled HTML\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n } else {\n // Pass through standard UIDef unchanged\n result[key] = def;\n }\n }\n\n return result;\n}\n\n/**\n * Transform a single React UI definition to a standard UIDef.\n *\n * @param def - React UI definition\n * @param html - Compiled HTML string from build\n * @returns Standard UIDef with inline HTML\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", reactDef);\n * const coreDef = transformSingleToCoreDef(reactDef, html);\n * ```\n *\n * @internal\n */\nexport function transformSingleToCoreDef(def: ReactUIDef, html: string): UIDef {\n return {\n html,\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n}\n\n/**\n * Extract React UI definitions from a mixed record.\n *\n * Use this to separate React UIs (that need building) from standard UIs\n * (that are already HTML).\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @returns Object with separated React and standard UIs\n *\n * @example\n * ```typescript\n * const { reactUIs, standardUIs } = extractReactUIs(allUIs);\n *\n * // Build only the React UIs\n * const buildResult = await buildReactUIs(reactUIs);\n *\n * // Combine back together\n * const allCoreDefs = {\n * ...standardUIs,\n * ...transformToCoreDefs(reactUIs, buildResult),\n * };\n * ```\n *\n * @internal\n */\nexport function extractReactUIs(defs: Record<string, ReactUIDef | UIDef>): {\n reactUIs: Record<string, ReactUIDef>;\n standardUIs: Record<string, UIDef>;\n} {\n const reactUIs: Record<string, ReactUIDef> = {};\n const standardUIs: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n reactUIs[key] = def;\n } else {\n standardUIs[key] = def;\n }\n }\n\n return { reactUIs, standardUIs };\n}\n\n/**\n * Convenience function to build and transform React UIs in one step.\n *\n * This combines `buildReactUIs` and `transformToCoreDefs` for simpler usage.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param options - Build options (passed to buildReactUIs)\n * @returns Promise resolving to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildAndTransform, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp } from \"@mcp-apps-kit/core\";\n *\n * const uis = await buildAndTransform({\n * \"react-widget\": defineReactUI({ component: MyWidget }),\n * \"html-widget\": defineUI({ html: \"./widget.html\" }),\n * });\n *\n * // All are now standard UIDefs\n * console.log(uis[\"react-widget\"].html.startsWith(\"<!DOCTYPE html>\")); // true\n * console.log(uis[\"html-widget\"].html); // \"./widget.html\"\n * ```\n */\nexport async function buildAndTransform(\n defs: Record<string, ReactUIDef | UIDef>,\n options?: Parameters<typeof import(\"./build\").buildReactUIs>[1]\n): Promise<Record<string, UIDef>> {\n // Dynamically import build to avoid circular dependencies\n const { buildReactUIs } = await import(\"./build\");\n\n // Separate React UIs from standard UIs\n const { reactUIs, standardUIs } = extractReactUIs(defs);\n\n // If no React UIs, just return standard UIs\n if (Object.keys(reactUIs).length === 0) {\n return standardUIs;\n }\n\n // Build React UIs\n const buildResult = await buildReactUIs(reactUIs, options);\n\n // Check for errors\n if (buildResult.errors.length > 0) {\n const errorMessages = buildResult.errors.map((e) => ` - ${e.key}: ${e.message}`).join(\"\\n\");\n throw new Error(`Failed to build some React UIs:\\n${errorMessages}`);\n }\n\n // Transform and combine\n return {\n ...standardUIs,\n ...transformToCoreDefs(reactUIs, buildResult),\n };\n}\n"]}
{"version":3,"sources":["../src/html.ts","../src/build.ts","../src/define.ts","../src/index.ts","../src/transform.ts"],"names":["generateHTML","options","key","name","script","css","combinedCss","DEFAULT_BASE_CSS","escapeHtml","generateEntryPoint","componentPathOrOptions","defaultProps","componentPath","componentExport","props","autoResize","propsJson","importStatement","providerProps","text","htmlEntities","char","init_html","__esmMin","build_exports","__export","buildReactUI","buildReactUIs","uis","startTime","outputs","files","warnings","errors","cwd","u","g","globalCss","error","def","html","compileComponent","outPath","buildError","component","componentName","entryPoint","plugins","createComponentPlugin","createCSSPlugin","result","x","outputFile","build","componentSource","isClassComponent","isFunctionComponent","isArrowFunction","contents","args","classNames","extractClassNames","mapping","hashString","transformedCss","original","hashed","classRegex","classes","match","str","hash","i","e","init_build","toKebabCase","defineReactUI","definition","outDir","rest","htmlPath","isReactUIDef","value","transformToCoreDefs","defs","buildResult","transformSingleToCoreDef","extractReactUIs","reactUIs","standardUIs","buildAndTransform","errorMessages"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * HTML template generation for React UIs\n */\n\nimport type { TemplateOptions } from \"./types\";\n\n/**\n * Default base CSS reset for all UIs.\n * Provides a consistent starting point across platforms.\n */\nconst DEFAULT_BASE_CSS = `\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html {\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n line-height: 1.5;\n color: #1a1a1a;\n background-color: transparent;\n }\n\n @media (prefers-color-scheme: dark) {\n body {\n color: #f5f5f5;\n }\n }\n\n #root {\n min-height: 100%;\n }\n`;\n\n/**\n * Generate a self-contained HTML document for a React UI.\n *\n * The generated HTML includes:\n * - DOCTYPE and valid HTML5 structure\n * - Meta tags for responsive design\n * - Inlined CSS (base reset + optional custom CSS)\n * - Inlined JavaScript bundle with React app\n *\n * @param options - Template options with key, name, script, and optional CSS\n * @returns Complete HTML document as a string\n *\n * @example\n * ```typescript\n * const html = generateHTML({\n * key: \"restaurant-list\",\n * name: \"Restaurant List Widget\",\n * script: bundledJavaScript,\n * css: customStyles,\n * });\n * ```\n *\n * @internal\n */\nexport function generateHTML(options: TemplateOptions): string {\n const { key, name, script, css } = options;\n\n // Combine base CSS with any custom CSS\n const combinedCss = css ? `${DEFAULT_BASE_CSS}\\n${css}` : DEFAULT_BASE_CSS;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"mcp-ui-key\" content=\"${escapeHtml(key)}\">\n <title>${escapeHtml(name)}</title>\n <style>${combinedCss}</style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\">${script.replace(/<\\/script>/gi, \"</scr\" + \"ipt>\")}</script>\n</body>\n</html>`;\n}\n\n/**\n * Options for generating the React entry point.\n *\n * @internal\n */\nexport interface EntryPointOptions {\n /**\n * Path to the component file.\n */\n componentPath: string;\n\n /**\n * Name of the export to use.\n * Use \"default\" for default exports, or the actual name for named exports.\n * @default \"default\"\n */\n componentExport?: string;\n\n /**\n * Default props to pass to the component.\n */\n defaultProps?: Record<string, unknown>;\n\n /**\n * Whether to enable automatic size change notifications.\n * When undefined, uses the default (true).\n */\n autoResize?: boolean;\n}\n\n/**\n * Generate the React entry point code that will be bundled.\n *\n * This creates a small JavaScript module that:\n * 1. Imports React and ReactDOM\n * 2. Imports the user's component\n * 3. Imports AppsProvider from @mcp-apps-kit/ui-react\n * 4. Renders the component wrapped in providers\n *\n * @param componentPath - Path to the React component file (for backward compatibility)\n * @param defaultProps - Optional default props to pass to the component\n * @returns JavaScript/TypeScript source code for the entry point\n *\n * @example\n * ```typescript\n * // Default export\n * const entryCode = generateEntryPoint(\n * \"./src/widgets/MyWidget.tsx\",\n * { theme: \"dark\" }\n * );\n *\n * // Named export\n * const entryCode = generateEntryPoint({\n * componentPath: \"./src/widgets/MyWidget.tsx\",\n * componentExport: \"MyWidget\",\n * });\n * ```\n *\n * @internal\n */\nexport function generateEntryPoint(\n componentPathOrOptions: string | EntryPointOptions,\n defaultProps?: Record<string, unknown>\n): string {\n // Handle backward compatibility with string-only signature\n const options: EntryPointOptions =\n typeof componentPathOrOptions === \"string\"\n ? { componentPath: componentPathOrOptions, defaultProps }\n : componentPathOrOptions;\n\n const { componentPath, componentExport = \"default\", defaultProps: props, autoResize } = options;\n const propsJson = props ? JSON.stringify(props) : \"{}\";\n\n // Generate appropriate import statement based on export type\n const importStatement =\n componentExport === \"default\"\n ? `import Component from \"${componentPath}\";`\n : `import { ${componentExport} as Component } from \"${componentPath}\";`;\n\n // Generate AppsProvider props\n const providerProps = autoResize === undefined ? \"\" : ` autoResize={${autoResize}}`;\n\n return `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\n${importStatement}\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider${providerProps}>\n <Component {...${propsJson}} />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n *\n * @param text - Text to escape\n * @returns Escaped text safe for HTML insertion\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] ?? char);\n}\n\n/**\n * Extract CSS from a string that may contain both JS and CSS.\n * Used when esbuild bundles CSS as JavaScript that injects styles.\n *\n * @param code - Bundled code that may contain CSS injection\n * @returns Extracted CSS string or undefined\n */\nexport function extractInlineCSS(code: string): string | undefined {\n // esbuild injects CSS as: document.head.appendChild(...).textContent = \"css content\"\n const cssMatch = code.match(/\\.textContent\\s*=\\s*[\"'`]([\\s\\S]*?)[\"'`]\\s*[;,)]/);\n if (cssMatch?.[1]) {\n // Unescape the CSS string\n return cssMatch[1].replace(/\\\\n/g, \"\\n\").replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n return undefined;\n}\n","/**\n * React UI build system using esbuild\n *\n * Compiles React components into self-contained HTML files that can be\n * served as MCP UI resources.\n */\n\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { ReactUIDef, BuildOptions, BuildResult, BuildError } from \"./types\";\nimport { generateHTML, generateEntryPoint } from \"./html\";\n\n/**\n * Build multiple React UIs into self-contained HTML files.\n *\n * This function takes a record of React UI definitions and compiles each one\n * into a complete HTML file that includes React, ReactDOM, @mcp-apps-kit/ui-react,\n * and the user's component code.\n *\n * **IMPORTANT: Limitations**\n *\n * This programmatic build function serializes components using `.toString()`, which has\n * significant limitations:\n *\n * - **No external imports**: Components cannot import other modules, hooks, or utilities\n * - **No closures**: Components that capture external variables will not work\n * - **Simple components only**: Best for self-contained components without dependencies\n *\n * For production use, prefer the **Vite plugin** (`mcpReactUI`) which uses file paths\n * for proper import resolution and supports:\n * - Full import/export resolution\n * - CSS imports and CSS modules\n * - All React hooks and utilities\n * - External component dependencies\n *\n * This function is primarily intended for:\n * - **Testing**: Unit and integration tests for the build pipeline\n * - **Simple widgets**: Self-contained components with no external imports\n * - **Prototyping**: Quick experimentation before setting up Vite\n *\n * @param uis - Record of UI keys to React UI definitions\n * @param options - Build configuration options\n * @returns Build result with compiled HTML and metadata\n *\n * @example\n * ```typescript\n * // For production, use the Vite plugin instead:\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [mcpReactUI({ serverEntry: \"./src/index.ts\" })],\n * });\n *\n * // This programmatic API is for simple/test cases:\n * import { buildReactUIs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * // Only works with simple, self-contained components\n * const SimpleWidget = () => <div>Hello World</div>;\n *\n * const result = await buildReactUIs({\n * \"simple\": defineReactUI({\n * component: SimpleWidget,\n * name: \"Simple Widget\",\n * }),\n * });\n * ```\n */\nexport async function buildReactUIs(\n uis: Record<string, ReactUIDef>,\n options: BuildOptions = {}\n): Promise<BuildResult> {\n const startTime = Date.now();\n const outputs = new Map<string, string>();\n const files = new Map<string, string>();\n const warnings: string[] = [];\n const errors: BuildError[] = [];\n\n const cwd = options.cwd ?? process.cwd();\n\n // Create output directory if specified\n if (options.outDir) {\n await fs.mkdir(path.resolve(cwd, options.outDir), { recursive: true });\n }\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n try {\n globalCss = await fs.readFile(path.resolve(cwd, options.globalCss), \"utf-8\");\n } catch (error) {\n warnings.push(\n `Could not load global CSS from ${options.globalCss}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n // Build each UI\n for (const [key, def] of Object.entries(uis)) {\n try {\n const html = await compileComponent(key, def, {\n ...options,\n cwd,\n globalCss,\n });\n\n outputs.set(key, html);\n\n // Write to file if outDir specified\n if (options.outDir) {\n const outPath = path.resolve(cwd, options.outDir, `${key}.html`);\n await fs.writeFile(outPath, html, \"utf-8\");\n files.set(key, outPath);\n }\n } catch (error) {\n const buildError: BuildError = {\n key,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n errors.push(buildError);\n }\n }\n\n return {\n outputs,\n files,\n duration: Date.now() - startTime,\n warnings,\n errors,\n };\n}\n\n/**\n * Compile a single React component to self-contained HTML.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns Complete HTML document as a string\n */\nasync function compileComponent(\n key: string,\n def: ReactUIDef,\n options: BuildOptions & { cwd: string; globalCss?: string }\n): Promise<string> {\n // Get component from internal properties\n const component = def.__component;\n const componentName = component.name || \"Component\";\n const defaultProps = def.__defaultProps;\n const autoResize = def.__autoResize;\n\n // Create the entry point using function serialization\n // Note: The Vite plugin uses file paths for proper import resolution\n // This build function falls back to function serialization (limited - doesn't capture imports)\n const entryPoint = generateEntryPoint({\n componentPath: `__COMPONENT_PLACEHOLDER__`,\n defaultProps,\n autoResize,\n });\n\n // Configure plugins\n const plugins: esbuild.Plugin[] = [\n createComponentPlugin(component, componentName),\n createCSSPlugin(),\n ];\n\n // Use esbuild to bundle everything\n const result = await esbuild.build({\n stdin: {\n contents: entryPoint,\n loader: \"tsx\",\n resolveDir: options.cwd,\n sourcefile: `${key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ? \"inline\" : false,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n logLevel: \"warning\",\n external: options.external,\n plugins,\n define: {\n \"process.env.NODE_ENV\": options.minify ? '\"production\"' : '\"development\"',\n },\n });\n\n // Get the bundled JavaScript\n const outputFile = result.outputFiles?.[0];\n if (!outputFile) {\n throw new Error(`No output generated for UI: ${key}`);\n }\n\n const script = outputFile.text;\n\n // Collect any warnings from esbuild (currently silent, could add a logger later)\n // Warnings are typically about missing exports, unused imports, etc.\n // For now we don't surface these to users\n void result.warnings;\n\n // Generate the final HTML\n const html = generateHTML({\n key,\n name: def.name ?? key,\n script,\n css: options.globalCss,\n });\n\n return html;\n}\n\n/**\n * Create an esbuild plugin that resolves the component placeholder.\n *\n * This plugin intercepts imports of the placeholder module and replaces\n * it with the actual component code. This is necessary because we receive\n * a function reference, not a file path.\n */\nfunction createComponentPlugin(\n component: { toString: () => string },\n componentName: string\n): esbuild.Plugin {\n return {\n name: \"mcp-component-resolver\",\n setup(build) {\n // Intercept the placeholder import\n build.onResolve({ filter: /__COMPONENT_PLACEHOLDER__/ }, () => {\n return {\n path: \"__COMPONENT__\",\n namespace: \"mcp-component\",\n };\n });\n\n // Provide the component code\n build.onLoad({ filter: /.*/, namespace: \"mcp-component\" }, () => {\n // Serialize the component to a module\n // For now, we export a placeholder that requires runtime injection\n // In a real implementation, we'd need the component's source path\n const componentSource = component.toString();\n\n // Detect component type: class, function, or arrow function\n const isClassComponent = /^\\s*class\\b/.test(componentSource);\n const isFunctionComponent = /^\\s*function\\b/.test(componentSource);\n const isArrowFunction = !isClassComponent && !isFunctionComponent;\n\n let contents: string;\n if (isArrowFunction) {\n contents = `\n import React from \"react\";\n const ${componentName} = ${componentSource};\n export default ${componentName};\n `;\n } else {\n contents = `\n import React from \"react\";\n ${componentSource}\n export default ${componentName};\n `;\n }\n\n return {\n contents,\n loader: \"tsx\",\n };\n });\n },\n };\n}\n\n/**\n * Create an esbuild plugin that handles CSS imports.\n *\n * This plugin transforms CSS imports into JavaScript that injects\n * the styles into the document head at runtime.\n */\nfunction createCSSPlugin(): esbuild.Plugin {\n return {\n name: \"mcp-css-handler\",\n setup(build) {\n // Handle .css imports (excluding .module.css which has its own handler)\n build.onLoad({ filter: /\\.css$/ }, async (args) => {\n // Skip .module.css files - they're handled by the CSS modules loader\n if (args.path.endsWith(\".module.css\")) {\n return null;\n }\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Create JavaScript that injects the CSS\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(css)};\n document.head.appendChild(style);\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n\n // Handle CSS modules (.module.css)\n build.onLoad({ filter: /\\.module\\.css$/ }, async (args) => {\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Generate a simple class name mapping\n // In a real implementation, we'd use a proper CSS modules processor\n const classNames = extractClassNames(css);\n const mapping = Object.fromEntries(\n classNames.map((name) => [name, `${name}_${hashString(args.path)}`])\n );\n\n // Transform the CSS with new class names\n let transformedCss = css;\n for (const [original, hashed] of Object.entries(mapping)) {\n transformedCss = transformedCss.replace(\n new RegExp(`\\\\.${original}\\\\b`, \"g\"),\n `.${hashed}`\n );\n }\n\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(transformedCss)};\n document.head.appendChild(style);\n export default ${JSON.stringify(mapping)};\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n },\n };\n}\n\n/**\n * Extract class names from CSS content.\n */\nfunction extractClassNames(css: string): string[] {\n const classRegex = /\\.([a-zA-Z_][a-zA-Z0-9_-]*)/g;\n const classes = new Set<string>();\n let match;\n while ((match = classRegex.exec(css)) !== null) {\n if (match[1]) {\n classes.add(match[1]);\n }\n }\n return Array.from(classes);\n}\n\n/**\n * Simple string hash for generating unique class names.\n */\nfunction hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36).substring(0, 5);\n}\n\n/**\n * Build a single React UI.\n *\n * Convenience function for building just one UI.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns The compiled HTML string\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }));\n * ```\n */\nexport async function buildReactUI(\n key: string,\n def: ReactUIDef,\n options: BuildOptions = {}\n): Promise<string> {\n const result = await buildReactUIs({ [key]: def }, options);\n\n const html = result.outputs.get(key);\n if (!html) {\n const error = result.errors.find((e) => e.key === key);\n throw new Error(error?.message ?? `Failed to build UI: ${key}`);\n }\n\n return html;\n}\n","/**\n * Helper functions for defining React-based UIs\n */\n\nimport type { ReactUIInput, ReactUIDef } from \"./types\";\n\n/**\n * Convert component name to kebab-case for filename.\n * @internal\n */\nfunction toKebabCase(name: string): string {\n return name.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n\n/**\n * Define a UI using a React component.\n *\n * This helper creates a UIDef with an auto-generated HTML path based on\n * the component name. The Vite plugin discovers these definitions and\n * builds the React components into self-contained HTML files.\n *\n * @param definition - React UI input with component and metadata\n * @returns A UIDef with auto-generated html path and React metadata\n *\n * @example Basic usage\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * const widgetUI = defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * prefersBorder: true,\n * });\n * // Returns: { html: \"./src/ui/dist/my-widget.html\", name: \"My Widget\", ... }\n * ```\n *\n * @example With tool definition\n * ```typescript\n * import { createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { RestaurantList } from \"./widgets/RestaurantList\";\n *\n * const app = createApp({\n * name: \"restaurant-finder\",\n * version: \"1.0.0\",\n * tools: {\n * search: defineTool({\n * description: \"Search for restaurants\",\n * input: z.object({ query: z.string() }),\n * output: z.object({ restaurants: z.array(RestaurantSchema) }),\n * ui: defineReactUI({\n * component: RestaurantList,\n * name: \"Restaurant List\",\n * }),\n * handler: async (input) => {\n * // ... search logic\n * },\n * }),\n * },\n * });\n * ```\n *\n * @example Custom output directory\n * ```typescript\n * const widgetUI = defineReactUI({\n * component: ConfigurableWidget,\n * name: \"Configurable Widget\",\n * outDir: \"./dist/ui\",\n * });\n * // Returns: { html: \"./dist/ui/configurable-widget.html\", ... }\n * ```\n */\nexport function defineReactUI(definition: ReactUIInput): ReactUIDef {\n const { component, defaultProps, outDir, autoResize, ...rest } = definition;\n\n // Generate the output path from component name\n const componentName = component.name ?? \"component\";\n const key = toKebabCase(componentName);\n const outputDir = outDir ?? \"./src/ui/dist\";\n const htmlPath = `${outputDir}/${key}.html`;\n\n return {\n ...rest,\n html: htmlPath,\n __reactUI: true,\n __component: component,\n __defaultProps: defaultProps,\n __autoResize: autoResize ?? true,\n };\n}\n\n/**\n * Check if a value is a React UI definition.\n *\n * This type guard is used by the build system to identify\n * React UIs that need to be compiled to HTML.\n *\n * @param value - Value to check\n * @returns True if the value is a ReactUIDef\n *\n * @example\n * ```typescript\n * import { isReactUIDef } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * const ui = someUnknownUI;\n * if (isReactUIDef(ui)) {\n * // ui.__component is available here\n * console.log(\"React UI:\", ui.__component.name);\n * }\n * ```\n *\n * @internal\n */\nexport function isReactUIDef(value: unknown): value is ReactUIDef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__reactUI\" in value &&\n (value as ReactUIDef).__reactUI\n );\n}\n","/**\n * @mcp-apps-kit/ui-react-builder\n *\n * Build tool for React-based MCP application UIs.\n *\n * This package allows you to define UI resources using React components\n * instead of pre-built HTML files. The framework handles bundling React,\n * ReactDOM, and @mcp-apps-kit/ui-react into self-contained HTML that works\n * with both MCP Apps and ChatGPT.\n *\n * @example Basic usage\n * ```typescript\n * import { defineReactUI, buildReactUIs } from \"@mcp-apps-kit/ui-react-builder\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * // Define your UI with a React component\n * const widgetUI = defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * prefersBorder: true,\n * });\n *\n * // Build to HTML\n * const result = await buildReactUIs({\n * \"my-widget\": widgetUI,\n * }, {\n * outDir: \"./dist/ui\",\n * });\n *\n * console.log(`Built ${result.outputs.size} UIs in ${result.duration}ms`);\n * ```\n *\n * @example With tool definition\n * ```typescript\n * import { createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { defineReactUI, buildAndTransform } from \"@mcp-apps-kit/ui-react-builder\";\n * import { RestaurantList } from \"./widgets/RestaurantList\";\n * import { z } from \"zod\";\n *\n * // Build and transform in one step\n * const uis = await buildAndTransform({\n * \"restaurant-list\": defineReactUI({\n * component: RestaurantList,\n * name: \"Restaurant List\",\n * }),\n * });\n *\n * const app = createApp({\n * name: \"restaurant-finder\",\n * version: \"1.0.0\",\n * tools: {\n * search: defineTool({\n * description: \"Search for restaurants\",\n * input: z.object({ query: z.string() }),\n * output: z.object({ restaurants: z.array(z.unknown()) }),\n * ui: uis[\"restaurant-list\"],\n * handler: async (input) => {\n * // ... search logic\n * return { restaurants: [] };\n * },\n * }),\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\n// =============================================================================\n// TYPE EXPORTS\n// =============================================================================\n\nexport type {\n ReactUIInput,\n ReactUIDef,\n BuildOptions,\n BuildResult,\n BuildError,\n TemplateOptions,\n DevServerOptions,\n} from \"./types\";\n\n// =============================================================================\n// DEFINITION HELPERS\n// =============================================================================\n\nexport { defineReactUI, isReactUIDef } from \"./define\";\n\n// =============================================================================\n// BUILD FUNCTIONS\n// =============================================================================\n\nexport { buildReactUIs, buildReactUI } from \"./build\";\n\n// =============================================================================\n// TRANSFORM UTILITIES\n// =============================================================================\n\nexport {\n transformToCoreDefs,\n transformSingleToCoreDef,\n extractReactUIs,\n buildAndTransform,\n} from \"./transform\";\n\n// =============================================================================\n// HTML UTILITIES\n// =============================================================================\n\nexport type { EntryPointOptions } from \"./html\";\nexport { generateHTML, generateEntryPoint } from \"./html\";\n","/**\n * Transform utilities for converting ReactUIDef to standard UIDef\n *\n * After building React UIs, this module helps convert them to the\n * standard UIDef format that @mcp-apps-kit/core understands.\n */\n\nimport type { UIDef } from \"@mcp-apps-kit/core\";\nimport type { ReactUIDef, BuildResult } from \"./types\";\nimport { isReactUIDef } from \"./define\";\n\n/**\n * Transform React UI definitions to standard core UIDefs.\n *\n * This function takes a mix of React UIs and standard UIs, and converts\n * all React UIs to standard UIDefs using the build result. Standard UIDefs\n * pass through unchanged.\n *\n * Use this after calling `buildReactUIs` to get definitions that can be\n * passed directly to `createApp`.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param buildResult - Result from buildReactUIs containing compiled HTML\n * @returns Record of UI keys to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildReactUIs, transformToCoreDefs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * // Define a mix of React and standard UIs\n * const uis = {\n * \"react-widget\": defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }),\n * \"html-widget\": defineUI({\n * html: \"./widget.html\",\n * name: \"HTML Widget\",\n * }),\n * };\n *\n * // Build React UIs\n * const buildResult = await buildReactUIs({\n * \"react-widget\": uis[\"react-widget\"] as ReactUIDef,\n * });\n *\n * // Transform all to core format\n * const coreDefs = transformToCoreDefs(uis, buildResult);\n *\n * // Now use with createApp\n * const app = createApp({\n * name: \"my-app\",\n * version: \"1.0.0\",\n * tools: {\n * myTool: defineTool({\n * // ... tool definition\n * ui: coreDefs[\"react-widget\"],\n * }),\n * },\n * });\n * ```\n */\nexport function transformToCoreDefs(\n defs: Record<string, ReactUIDef | UIDef>,\n buildResult: BuildResult\n): Record<string, UIDef> {\n const result: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n // Get compiled HTML from build result\n const html = buildResult.outputs.get(key);\n if (!html) {\n // Check if there was a build error\n const error = buildResult.errors.find((e) => e.key === key);\n if (error) {\n throw new Error(`Build failed for React UI \"${key}\": ${error.message}`);\n }\n throw new Error(\n `No build output found for React UI \"${key}\". Did you forget to include it in buildReactUIs()?`\n );\n }\n\n // Transform ReactUIDef to UIDef with inline HTML\n result[key] = {\n html, // Inline the compiled HTML\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n } else {\n // Pass through standard UIDef unchanged\n result[key] = def;\n }\n }\n\n return result;\n}\n\n/**\n * Transform a single React UI definition to a standard UIDef.\n *\n * @param def - React UI definition\n * @param html - Compiled HTML string from build\n * @returns Standard UIDef with inline HTML\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", reactDef);\n * const coreDef = transformSingleToCoreDef(reactDef, html);\n * ```\n *\n * @internal\n */\nexport function transformSingleToCoreDef(def: ReactUIDef, html: string): UIDef {\n return {\n html,\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n}\n\n/**\n * Extract React UI definitions from a mixed record.\n *\n * Use this to separate React UIs (that need building) from standard UIs\n * (that are already HTML).\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @returns Object with separated React and standard UIs\n *\n * @example\n * ```typescript\n * const { reactUIs, standardUIs } = extractReactUIs(allUIs);\n *\n * // Build only the React UIs\n * const buildResult = await buildReactUIs(reactUIs);\n *\n * // Combine back together\n * const allCoreDefs = {\n * ...standardUIs,\n * ...transformToCoreDefs(reactUIs, buildResult),\n * };\n * ```\n *\n * @internal\n */\nexport function extractReactUIs(defs: Record<string, ReactUIDef | UIDef>): {\n reactUIs: Record<string, ReactUIDef>;\n standardUIs: Record<string, UIDef>;\n} {\n const reactUIs: Record<string, ReactUIDef> = {};\n const standardUIs: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n reactUIs[key] = def;\n } else {\n standardUIs[key] = def;\n }\n }\n\n return { reactUIs, standardUIs };\n}\n\n/**\n * Convenience function to build and transform React UIs in one step.\n *\n * This combines `buildReactUIs` and `transformToCoreDefs` for simpler usage.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param options - Build options (passed to buildReactUIs)\n * @returns Promise resolving to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildAndTransform, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp } from \"@mcp-apps-kit/core\";\n *\n * const uis = await buildAndTransform({\n * \"react-widget\": defineReactUI({ component: MyWidget }),\n * \"html-widget\": defineUI({ html: \"./widget.html\" }),\n * });\n *\n * // All are now standard UIDefs\n * console.log(uis[\"react-widget\"].html.startsWith(\"<!DOCTYPE html>\")); // true\n * console.log(uis[\"html-widget\"].html); // \"./widget.html\"\n * ```\n */\nexport async function buildAndTransform(\n defs: Record<string, ReactUIDef | UIDef>,\n options?: Parameters<typeof import(\"./build\").buildReactUIs>[1]\n): Promise<Record<string, UIDef>> {\n // Dynamically import build to avoid circular dependencies\n const { buildReactUIs } = await import(\"./build\");\n\n // Separate React UIs from standard UIs\n const { reactUIs, standardUIs } = extractReactUIs(defs);\n\n // If no React UIs, just return standard UIs\n if (Object.keys(reactUIs).length === 0) {\n return standardUIs;\n }\n\n // Build React UIs\n const buildResult = await buildReactUIs(reactUIs, options);\n\n // Check for errors\n if (buildResult.errors.length > 0) {\n const errorMessages = buildResult.errors.map((e) => ` - ${e.key}: ${e.message}`).join(\"\\n\");\n throw new Error(`Failed to build some React UIs:\\n${errorMessages}`);\n }\n\n // Transform and combine\n return {\n ...standardUIs,\n ...transformToCoreDefs(reactUIs, buildResult),\n };\n}\n"]}

@@ -56,2 +56,12 @@ import { ComponentType } from 'react';

outDir?: string;
/**
* Enable automatic size change notifications (MCP adapter only).
*
* When enabled, the UI automatically reports its size changes to the host
* using a ResizeObserver on document.body and document.documentElement.
* The host can then resize the UI container accordingly.
*
* @default true
*/
autoResize?: boolean;
}

@@ -82,2 +92,7 @@ /**

__defaultProps?: Record<string, unknown>;
/**
* Whether to enable automatic size change notifications.
* @internal
*/
__autoResize?: boolean;
}

@@ -576,2 +591,7 @@ /**

defaultProps?: Record<string, unknown>;
/**
* Whether to enable automatic size change notifications.
* When undefined, uses the default (true).
*/
autoResize?: boolean;
}

@@ -578,0 +598,0 @@ /**

@@ -56,2 +56,12 @@ import { ComponentType } from 'react';

outDir?: string;
/**
* Enable automatic size change notifications (MCP adapter only).
*
* When enabled, the UI automatically reports its size changes to the host
* using a ResizeObserver on document.body and document.documentElement.
* The host can then resize the UI container accordingly.
*
* @default true
*/
autoResize?: boolean;
}

@@ -82,2 +92,7 @@ /**

__defaultProps?: Record<string, unknown>;
/**
* Whether to enable automatic size change notifications.
* @internal
*/
__autoResize?: boolean;
}

@@ -576,2 +591,7 @@ /**

defaultProps?: Record<string, unknown>;
/**
* Whether to enable automatic size change notifications.
* When undefined, uses the default (true).
*/
autoResize?: boolean;
}

@@ -578,0 +598,0 @@ /**

@@ -1,4 +0,4 @@

export{b as buildReactUI,a as buildReactUIs}from'./chunk-5WFQIJJW.js';export{b as generateEntryPoint,a as generateHTML}from'./chunk-6JS3KVIH.js';function R(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function l(e){let{component:o,defaultProps:n,outDir:r,...t}=e,s=o.name??"component",i=R(s),d=`${r??"./src/ui/dist"}/${i}.html`;return {...t,html:d,__reactUI:true,__component:o,__defaultProps:n}}function a(e){return typeof e=="object"&&e!==null&&"__reactUI"in e&&e.__reactUI}function f(e,o){let n={};for(let[r,t]of Object.entries(e))if(a(t)){let s=o.outputs.get(r);if(!s){let i=o.errors.find(c=>c.key===r);throw i?new Error(`Build failed for React UI "${r}": ${i.message}`):new Error(`No build output found for React UI "${r}". Did you forget to include it in buildReactUIs()?`)}n[r]={html:s,name:t.name,description:t.description,widgetDescription:t.widgetDescription,csp:t.csp,prefersBorder:t.prefersBorder,domain:t.domain};}else n[r]=t;return n}function D(e,o){return {html:o,name:e.name,description:e.description,widgetDescription:e.widgetDescription,csp:e.csp,prefersBorder:e.prefersBorder,domain:e.domain}}function p(e){let o={},n={};for(let[r,t]of Object.entries(e))a(t)?o[r]=t:n[r]=t;return {reactUIs:o,standardUIs:n}}async function g(e,o){let{buildReactUIs:n}=await import('./build-ZF3MI5NJ.js'),{reactUIs:r,standardUIs:t}=p(e);if(Object.keys(r).length===0)return t;let s=await n(r,o);if(s.errors.length>0){let i=s.errors.map(c=>` - ${c.key}: ${c.message}`).join(`
export{b as buildReactUI,a as buildReactUIs}from'./chunk-3YHDRPOV.js';export{b as generateEntryPoint,a as generateHTML}from'./chunk-R7RJYHEX.js';function R(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function l(e){let{component:o,defaultProps:n,outDir:r,autoResize:t,...s}=e,i=o.name??"component",c=R(i),d=`${r??"./src/ui/dist"}/${c}.html`;return {...s,html:d,__reactUI:true,__component:o,__defaultProps:n,__autoResize:t??true}}function a(e){return typeof e=="object"&&e!==null&&"__reactUI"in e&&e.__reactUI}function f(e,o){let n={};for(let[r,t]of Object.entries(e))if(a(t)){let s=o.outputs.get(r);if(!s){let i=o.errors.find(c=>c.key===r);throw i?new Error(`Build failed for React UI "${r}": ${i.message}`):new Error(`No build output found for React UI "${r}". Did you forget to include it in buildReactUIs()?`)}n[r]={html:s,name:t.name,description:t.description,widgetDescription:t.widgetDescription,csp:t.csp,prefersBorder:t.prefersBorder,domain:t.domain};}else n[r]=t;return n}function D(e,o){return {html:o,name:e.name,description:e.description,widgetDescription:e.widgetDescription,csp:e.csp,prefersBorder:e.prefersBorder,domain:e.domain}}function p(e){let o={},n={};for(let[r,t]of Object.entries(e))a(t)?o[r]=t:n[r]=t;return {reactUIs:o,standardUIs:n}}async function g(e,o){let{buildReactUIs:n}=await import('./build-GBFL3B7J.js'),{reactUIs:r,standardUIs:t}=p(e);if(Object.keys(r).length===0)return t;let s=await n(r,o);if(s.errors.length>0){let i=s.errors.map(c=>` - ${c.key}: ${c.message}`).join(`
`);throw new Error(`Failed to build some React UIs:
${i}`)}return {...t,...f(r,s)}}export{g as buildAndTransform,l as defineReactUI,p as extractReactUIs,a as isReactUIDef,D as transformSingleToCoreDef,f as transformToCoreDefs};//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/define.ts","../src/transform.ts"],"names":["toKebabCase","name","defineReactUI","definition","component","defaultProps","outDir","rest","componentName","key","htmlPath","isReactUIDef","value","transformToCoreDefs","defs","buildResult","result","def","html","error","e","transformSingleToCoreDef","extractReactUIs","reactUIs","standardUIs","buildAndTransform","options","buildReactUIs","errorMessages"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Helper functions for defining React-based UIs\n */\n\nimport type { ReactUIInput, ReactUIDef } from \"./types\";\n\n/**\n * Convert component name to kebab-case for filename.\n * @internal\n */\nfunction toKebabCase(name: string): string {\n return name.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n\n/**\n * Define a UI using a React component.\n *\n * This helper creates a UIDef with an auto-generated HTML path based on\n * the component name. The Vite plugin discovers these definitions and\n * builds the React components into self-contained HTML files.\n *\n * @param definition - React UI input with component and metadata\n * @returns A UIDef with auto-generated html path and React metadata\n *\n * @example Basic usage\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * const widgetUI = defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * prefersBorder: true,\n * });\n * // Returns: { html: \"./src/ui/dist/my-widget.html\", name: \"My Widget\", ... }\n * ```\n *\n * @example With tool definition\n * ```typescript\n * import { createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { RestaurantList } from \"./widgets/RestaurantList\";\n *\n * const app = createApp({\n * name: \"restaurant-finder\",\n * version: \"1.0.0\",\n * tools: {\n * search: defineTool({\n * description: \"Search for restaurants\",\n * input: z.object({ query: z.string() }),\n * output: z.object({ restaurants: z.array(RestaurantSchema) }),\n * ui: defineReactUI({\n * component: RestaurantList,\n * name: \"Restaurant List\",\n * }),\n * handler: async (input) => {\n * // ... search logic\n * },\n * }),\n * },\n * });\n * ```\n *\n * @example Custom output directory\n * ```typescript\n * const widgetUI = defineReactUI({\n * component: ConfigurableWidget,\n * name: \"Configurable Widget\",\n * outDir: \"./dist/ui\",\n * });\n * // Returns: { html: \"./dist/ui/configurable-widget.html\", ... }\n * ```\n */\nexport function defineReactUI(definition: ReactUIInput): ReactUIDef {\n const { component, defaultProps, outDir, ...rest } = definition;\n\n // Generate the output path from component name\n const componentName = component.name ?? \"component\";\n const key = toKebabCase(componentName);\n const outputDir = outDir ?? \"./src/ui/dist\";\n const htmlPath = `${outputDir}/${key}.html`;\n\n return {\n ...rest,\n html: htmlPath,\n __reactUI: true,\n __component: component,\n __defaultProps: defaultProps,\n };\n}\n\n/**\n * Check if a value is a React UI definition.\n *\n * This type guard is used by the build system to identify\n * React UIs that need to be compiled to HTML.\n *\n * @param value - Value to check\n * @returns True if the value is a ReactUIDef\n *\n * @example\n * ```typescript\n * import { isReactUIDef } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * const ui = someUnknownUI;\n * if (isReactUIDef(ui)) {\n * // ui.__component is available here\n * console.log(\"React UI:\", ui.__component.name);\n * }\n * ```\n *\n * @internal\n */\nexport function isReactUIDef(value: unknown): value is ReactUIDef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__reactUI\" in value &&\n (value as ReactUIDef).__reactUI\n );\n}\n","/**\n * Transform utilities for converting ReactUIDef to standard UIDef\n *\n * After building React UIs, this module helps convert them to the\n * standard UIDef format that @mcp-apps-kit/core understands.\n */\n\nimport type { UIDef } from \"@mcp-apps-kit/core\";\nimport type { ReactUIDef, BuildResult } from \"./types\";\nimport { isReactUIDef } from \"./define\";\n\n/**\n * Transform React UI definitions to standard core UIDefs.\n *\n * This function takes a mix of React UIs and standard UIs, and converts\n * all React UIs to standard UIDefs using the build result. Standard UIDefs\n * pass through unchanged.\n *\n * Use this after calling `buildReactUIs` to get definitions that can be\n * passed directly to `createApp`.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param buildResult - Result from buildReactUIs containing compiled HTML\n * @returns Record of UI keys to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildReactUIs, transformToCoreDefs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * // Define a mix of React and standard UIs\n * const uis = {\n * \"react-widget\": defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }),\n * \"html-widget\": defineUI({\n * html: \"./widget.html\",\n * name: \"HTML Widget\",\n * }),\n * };\n *\n * // Build React UIs\n * const buildResult = await buildReactUIs({\n * \"react-widget\": uis[\"react-widget\"] as ReactUIDef,\n * });\n *\n * // Transform all to core format\n * const coreDefs = transformToCoreDefs(uis, buildResult);\n *\n * // Now use with createApp\n * const app = createApp({\n * name: \"my-app\",\n * version: \"1.0.0\",\n * tools: {\n * myTool: defineTool({\n * // ... tool definition\n * ui: coreDefs[\"react-widget\"],\n * }),\n * },\n * });\n * ```\n */\nexport function transformToCoreDefs(\n defs: Record<string, ReactUIDef | UIDef>,\n buildResult: BuildResult\n): Record<string, UIDef> {\n const result: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n // Get compiled HTML from build result\n const html = buildResult.outputs.get(key);\n if (!html) {\n // Check if there was a build error\n const error = buildResult.errors.find((e) => e.key === key);\n if (error) {\n throw new Error(`Build failed for React UI \"${key}\": ${error.message}`);\n }\n throw new Error(\n `No build output found for React UI \"${key}\". Did you forget to include it in buildReactUIs()?`\n );\n }\n\n // Transform ReactUIDef to UIDef with inline HTML\n result[key] = {\n html, // Inline the compiled HTML\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n } else {\n // Pass through standard UIDef unchanged\n result[key] = def;\n }\n }\n\n return result;\n}\n\n/**\n * Transform a single React UI definition to a standard UIDef.\n *\n * @param def - React UI definition\n * @param html - Compiled HTML string from build\n * @returns Standard UIDef with inline HTML\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", reactDef);\n * const coreDef = transformSingleToCoreDef(reactDef, html);\n * ```\n *\n * @internal\n */\nexport function transformSingleToCoreDef(def: ReactUIDef, html: string): UIDef {\n return {\n html,\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n}\n\n/**\n * Extract React UI definitions from a mixed record.\n *\n * Use this to separate React UIs (that need building) from standard UIs\n * (that are already HTML).\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @returns Object with separated React and standard UIs\n *\n * @example\n * ```typescript\n * const { reactUIs, standardUIs } = extractReactUIs(allUIs);\n *\n * // Build only the React UIs\n * const buildResult = await buildReactUIs(reactUIs);\n *\n * // Combine back together\n * const allCoreDefs = {\n * ...standardUIs,\n * ...transformToCoreDefs(reactUIs, buildResult),\n * };\n * ```\n *\n * @internal\n */\nexport function extractReactUIs(defs: Record<string, ReactUIDef | UIDef>): {\n reactUIs: Record<string, ReactUIDef>;\n standardUIs: Record<string, UIDef>;\n} {\n const reactUIs: Record<string, ReactUIDef> = {};\n const standardUIs: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n reactUIs[key] = def;\n } else {\n standardUIs[key] = def;\n }\n }\n\n return { reactUIs, standardUIs };\n}\n\n/**\n * Convenience function to build and transform React UIs in one step.\n *\n * This combines `buildReactUIs` and `transformToCoreDefs` for simpler usage.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param options - Build options (passed to buildReactUIs)\n * @returns Promise resolving to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildAndTransform, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp } from \"@mcp-apps-kit/core\";\n *\n * const uis = await buildAndTransform({\n * \"react-widget\": defineReactUI({ component: MyWidget }),\n * \"html-widget\": defineUI({ html: \"./widget.html\" }),\n * });\n *\n * // All are now standard UIDefs\n * console.log(uis[\"react-widget\"].html.startsWith(\"<!DOCTYPE html>\")); // true\n * console.log(uis[\"html-widget\"].html); // \"./widget.html\"\n * ```\n */\nexport async function buildAndTransform(\n defs: Record<string, ReactUIDef | UIDef>,\n options?: Parameters<typeof import(\"./build\").buildReactUIs>[1]\n): Promise<Record<string, UIDef>> {\n // Dynamically import build to avoid circular dependencies\n const { buildReactUIs } = await import(\"./build\");\n\n // Separate React UIs from standard UIs\n const { reactUIs, standardUIs } = extractReactUIs(defs);\n\n // If no React UIs, just return standard UIs\n if (Object.keys(reactUIs).length === 0) {\n return standardUIs;\n }\n\n // Build React UIs\n const buildResult = await buildReactUIs(reactUIs, options);\n\n // Check for errors\n if (buildResult.errors.length > 0) {\n const errorMessages = buildResult.errors.map((e) => ` - ${e.key}: ${e.message}`).join(\"\\n\");\n throw new Error(`Failed to build some React UIs:\\n${errorMessages}`);\n }\n\n // Transform and combine\n return {\n ...standardUIs,\n ...transformToCoreDefs(reactUIs, buildResult),\n };\n}\n"]}
{"version":3,"sources":["../src/define.ts","../src/transform.ts"],"names":["toKebabCase","name","defineReactUI","definition","component","defaultProps","outDir","autoResize","rest","componentName","key","htmlPath","isReactUIDef","value","transformToCoreDefs","defs","buildResult","result","def","html","error","e","transformSingleToCoreDef","extractReactUIs","reactUIs","standardUIs","buildAndTransform","options","buildReactUIs","errorMessages"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Helper functions for defining React-based UIs\n */\n\nimport type { ReactUIInput, ReactUIDef } from \"./types\";\n\n/**\n * Convert component name to kebab-case for filename.\n * @internal\n */\nfunction toKebabCase(name: string): string {\n return name.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n\n/**\n * Define a UI using a React component.\n *\n * This helper creates a UIDef with an auto-generated HTML path based on\n * the component name. The Vite plugin discovers these definitions and\n * builds the React components into self-contained HTML files.\n *\n * @param definition - React UI input with component and metadata\n * @returns A UIDef with auto-generated html path and React metadata\n *\n * @example Basic usage\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * const widgetUI = defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * prefersBorder: true,\n * });\n * // Returns: { html: \"./src/ui/dist/my-widget.html\", name: \"My Widget\", ... }\n * ```\n *\n * @example With tool definition\n * ```typescript\n * import { createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { RestaurantList } from \"./widgets/RestaurantList\";\n *\n * const app = createApp({\n * name: \"restaurant-finder\",\n * version: \"1.0.0\",\n * tools: {\n * search: defineTool({\n * description: \"Search for restaurants\",\n * input: z.object({ query: z.string() }),\n * output: z.object({ restaurants: z.array(RestaurantSchema) }),\n * ui: defineReactUI({\n * component: RestaurantList,\n * name: \"Restaurant List\",\n * }),\n * handler: async (input) => {\n * // ... search logic\n * },\n * }),\n * },\n * });\n * ```\n *\n * @example Custom output directory\n * ```typescript\n * const widgetUI = defineReactUI({\n * component: ConfigurableWidget,\n * name: \"Configurable Widget\",\n * outDir: \"./dist/ui\",\n * });\n * // Returns: { html: \"./dist/ui/configurable-widget.html\", ... }\n * ```\n */\nexport function defineReactUI(definition: ReactUIInput): ReactUIDef {\n const { component, defaultProps, outDir, autoResize, ...rest } = definition;\n\n // Generate the output path from component name\n const componentName = component.name ?? \"component\";\n const key = toKebabCase(componentName);\n const outputDir = outDir ?? \"./src/ui/dist\";\n const htmlPath = `${outputDir}/${key}.html`;\n\n return {\n ...rest,\n html: htmlPath,\n __reactUI: true,\n __component: component,\n __defaultProps: defaultProps,\n __autoResize: autoResize ?? true,\n };\n}\n\n/**\n * Check if a value is a React UI definition.\n *\n * This type guard is used by the build system to identify\n * React UIs that need to be compiled to HTML.\n *\n * @param value - Value to check\n * @returns True if the value is a ReactUIDef\n *\n * @example\n * ```typescript\n * import { isReactUIDef } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * const ui = someUnknownUI;\n * if (isReactUIDef(ui)) {\n * // ui.__component is available here\n * console.log(\"React UI:\", ui.__component.name);\n * }\n * ```\n *\n * @internal\n */\nexport function isReactUIDef(value: unknown): value is ReactUIDef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__reactUI\" in value &&\n (value as ReactUIDef).__reactUI\n );\n}\n","/**\n * Transform utilities for converting ReactUIDef to standard UIDef\n *\n * After building React UIs, this module helps convert them to the\n * standard UIDef format that @mcp-apps-kit/core understands.\n */\n\nimport type { UIDef } from \"@mcp-apps-kit/core\";\nimport type { ReactUIDef, BuildResult } from \"./types\";\nimport { isReactUIDef } from \"./define\";\n\n/**\n * Transform React UI definitions to standard core UIDefs.\n *\n * This function takes a mix of React UIs and standard UIs, and converts\n * all React UIs to standard UIDefs using the build result. Standard UIDefs\n * pass through unchanged.\n *\n * Use this after calling `buildReactUIs` to get definitions that can be\n * passed directly to `createApp`.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param buildResult - Result from buildReactUIs containing compiled HTML\n * @returns Record of UI keys to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildReactUIs, transformToCoreDefs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp, defineTool } from \"@mcp-apps-kit/core\";\n * import { MyWidget } from \"./widgets/MyWidget\";\n *\n * // Define a mix of React and standard UIs\n * const uis = {\n * \"react-widget\": defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }),\n * \"html-widget\": defineUI({\n * html: \"./widget.html\",\n * name: \"HTML Widget\",\n * }),\n * };\n *\n * // Build React UIs\n * const buildResult = await buildReactUIs({\n * \"react-widget\": uis[\"react-widget\"] as ReactUIDef,\n * });\n *\n * // Transform all to core format\n * const coreDefs = transformToCoreDefs(uis, buildResult);\n *\n * // Now use with createApp\n * const app = createApp({\n * name: \"my-app\",\n * version: \"1.0.0\",\n * tools: {\n * myTool: defineTool({\n * // ... tool definition\n * ui: coreDefs[\"react-widget\"],\n * }),\n * },\n * });\n * ```\n */\nexport function transformToCoreDefs(\n defs: Record<string, ReactUIDef | UIDef>,\n buildResult: BuildResult\n): Record<string, UIDef> {\n const result: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n // Get compiled HTML from build result\n const html = buildResult.outputs.get(key);\n if (!html) {\n // Check if there was a build error\n const error = buildResult.errors.find((e) => e.key === key);\n if (error) {\n throw new Error(`Build failed for React UI \"${key}\": ${error.message}`);\n }\n throw new Error(\n `No build output found for React UI \"${key}\". Did you forget to include it in buildReactUIs()?`\n );\n }\n\n // Transform ReactUIDef to UIDef with inline HTML\n result[key] = {\n html, // Inline the compiled HTML\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n } else {\n // Pass through standard UIDef unchanged\n result[key] = def;\n }\n }\n\n return result;\n}\n\n/**\n * Transform a single React UI definition to a standard UIDef.\n *\n * @param def - React UI definition\n * @param html - Compiled HTML string from build\n * @returns Standard UIDef with inline HTML\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", reactDef);\n * const coreDef = transformSingleToCoreDef(reactDef, html);\n * ```\n *\n * @internal\n */\nexport function transformSingleToCoreDef(def: ReactUIDef, html: string): UIDef {\n return {\n html,\n name: def.name,\n description: def.description,\n widgetDescription: def.widgetDescription,\n csp: def.csp,\n prefersBorder: def.prefersBorder,\n domain: def.domain,\n };\n}\n\n/**\n * Extract React UI definitions from a mixed record.\n *\n * Use this to separate React UIs (that need building) from standard UIs\n * (that are already HTML).\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @returns Object with separated React and standard UIs\n *\n * @example\n * ```typescript\n * const { reactUIs, standardUIs } = extractReactUIs(allUIs);\n *\n * // Build only the React UIs\n * const buildResult = await buildReactUIs(reactUIs);\n *\n * // Combine back together\n * const allCoreDefs = {\n * ...standardUIs,\n * ...transformToCoreDefs(reactUIs, buildResult),\n * };\n * ```\n *\n * @internal\n */\nexport function extractReactUIs(defs: Record<string, ReactUIDef | UIDef>): {\n reactUIs: Record<string, ReactUIDef>;\n standardUIs: Record<string, UIDef>;\n} {\n const reactUIs: Record<string, ReactUIDef> = {};\n const standardUIs: Record<string, UIDef> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n if (isReactUIDef(def)) {\n reactUIs[key] = def;\n } else {\n standardUIs[key] = def;\n }\n }\n\n return { reactUIs, standardUIs };\n}\n\n/**\n * Convenience function to build and transform React UIs in one step.\n *\n * This combines `buildReactUIs` and `transformToCoreDefs` for simpler usage.\n *\n * @param defs - Record of UI keys to ReactUIDef or UIDef\n * @param options - Build options (passed to buildReactUIs)\n * @returns Promise resolving to standard UIDefs\n *\n * @example\n * ```typescript\n * import { buildAndTransform, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { defineUI, createApp } from \"@mcp-apps-kit/core\";\n *\n * const uis = await buildAndTransform({\n * \"react-widget\": defineReactUI({ component: MyWidget }),\n * \"html-widget\": defineUI({ html: \"./widget.html\" }),\n * });\n *\n * // All are now standard UIDefs\n * console.log(uis[\"react-widget\"].html.startsWith(\"<!DOCTYPE html>\")); // true\n * console.log(uis[\"html-widget\"].html); // \"./widget.html\"\n * ```\n */\nexport async function buildAndTransform(\n defs: Record<string, ReactUIDef | UIDef>,\n options?: Parameters<typeof import(\"./build\").buildReactUIs>[1]\n): Promise<Record<string, UIDef>> {\n // Dynamically import build to avoid circular dependencies\n const { buildReactUIs } = await import(\"./build\");\n\n // Separate React UIs from standard UIs\n const { reactUIs, standardUIs } = extractReactUIs(defs);\n\n // If no React UIs, just return standard UIs\n if (Object.keys(reactUIs).length === 0) {\n return standardUIs;\n }\n\n // Build React UIs\n const buildResult = await buildReactUIs(reactUIs, options);\n\n // Check for errors\n if (buildResult.errors.length > 0) {\n const errorMessages = buildResult.errors.map((e) => ` - ${e.key}: ${e.message}`).join(\"\\n\");\n throw new Error(`Failed to build some React UIs:\\n${errorMessages}`);\n }\n\n // Transform and combine\n return {\n ...standardUIs,\n ...transformToCoreDefs(reactUIs, buildResult),\n };\n}\n"]}

@@ -1,2 +0,2 @@

'use strict';Object.defineProperty(exports,'__esModule',{value:true});var S=require('esbuild'),f=require('fs/promises'),a=require('path'),typescriptEstree=require('@typescript-eslint/typescript-estree');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var S__namespace=/*#__PURE__*/_interopNamespace(S);var f__namespace=/*#__PURE__*/_interopNamespace(f);var a__namespace=/*#__PURE__*/_interopNamespace(a);var h=`
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var b=require('esbuild'),u=require('fs/promises'),l=require('path'),typescriptEstree=require('@typescript-eslint/typescript-estree');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var b__namespace=/*#__PURE__*/_interopNamespace(b);var u__namespace=/*#__PURE__*/_interopNamespace(u);var l__namespace=/*#__PURE__*/_interopNamespace(l);var v=`
*,

@@ -33,4 +33,4 @@ *::before,

}
`;function P(t){let{key:r,name:n,script:o,css:e}=t,i=e?`${h}
${e}`:h;return `<!DOCTYPE html>
`;function P(t){let{key:o,name:n,script:r,css:e}=t,i=e?`${v}
${e}`:v;return `<!DOCTYPE html>
<html lang="en">

@@ -40,4 +40,4 @@ <head>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="mcp-ui-key" content="${v(r)}">
<title>${v(n)}</title>
<meta name="mcp-ui-key" content="${h(o)}">
<title>${h(n)}</title>
<style>${i}</style>

@@ -47,9 +47,9 @@ </head>

<div id="root"></div>
<script type="module">${o.replace(/<\/script>/gi,"</script>")}</script>
<script type="module">${r.replace(/<\/script>/gi,"</script>")}</script>
</body>
</html>`}function v(t){let r={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return t.replace(/[&<>"']/g,n=>r[n]??n)}async function b(t){let r=typescriptEstree.parse(t,{loc:true,range:true,jsx:true}),n=[],o=new Map;for(let e of r.body)if(e.type===typescriptEstree.AST_NODE_TYPES.ImportDeclaration){let i=e.source.value;for(let s of e.specifiers)if(s.type===typescriptEstree.AST_NODE_TYPES.ImportSpecifier){let c=s.local.name;o.set(c,i);}else if(s.type===typescriptEstree.AST_NODE_TYPES.ImportDefaultSpecifier){let c=s.local.name;o.set(c,i);}}return g(r,e=>{if(e.type===typescriptEstree.AST_NODE_TYPES.CallExpression&&e.callee.type===typescriptEstree.AST_NODE_TYPES.Identifier&&e.callee.name==="defineReactUI"){let i=w(e,o);i&&n.push(i);}}),n}function w(t,r){let n=t.arguments[0];if(n?.type!==typescriptEstree.AST_NODE_TYPES.ObjectExpression)return null;let o=null,e=null;for(let s of n.properties){if(s.type!==typescriptEstree.AST_NODE_TYPES.Property)continue;let c=s.key,l=c.type===typescriptEstree.AST_NODE_TYPES.Identifier?c.name:null;l&&(l==="component"?s.value.type===typescriptEstree.AST_NODE_TYPES.Identifier&&(o=s.value.name):l==="name"&&s.value.type===typescriptEstree.AST_NODE_TYPES.Literal&&typeof s.value.value=="string"&&(e=s.value.value));}if(!o||!e)return null;let i=r.get(o);return i?{componentName:o,importPath:i,name:e}:null}function g(t,r){if(Array.isArray(t)){for(let o of t)g(o,r);return}r(t);let n=t;for(let o of Object.keys(n)){let e=n[o];if(e&&typeof e=="object")if(Array.isArray(e))for(let i of e)i&&typeof i=="object"&&"type"in i&&g(i,r);else "type"in e&&g(e,r);}}var I={info:t=>{console.log(t);},warn:t=>{console.warn(t);},error:t=>{console.error(t);}},C={info:()=>{},warn:()=>{},error:()=>{}};function k(t){let r=t.replace(/\\/g,"/"),n=/^[a-zA-Z]:\//.test(r),o=r.startsWith("//");return r.startsWith(".")||r.startsWith("/")||n||o?r:`./${r}`}function $(t,r){let n=a__namespace.resolve(t),o=a__namespace.resolve(r),e=a__namespace.relative(n,o);return e===""?true:e===".."?false:!e.startsWith(`..${a__namespace.sep}`)&&!a__namespace.isAbsolute(e)}async function U(t,r,n,o,e){if(!t.startsWith("."))return null;let i=await f__namespace.realpath(n),s=a__namespace.resolve(r,t),c=a__namespace.extname(s)?[s]:[".tsx",".ts",".jsx",".js"].map(l=>s+l);for(let l of c){try{await f__namespace.access(l);}catch{continue}let p=await f__namespace.realpath(l);return $(i,p)?p:(e.warn(`[mcp-react-ui] Refusing to build UI component outside project root. component="${o}", import="${t}", resolved="${p}"`),null)}return e.warn(`[mcp-react-ui] Could not resolve component file for "${o}" from import "${t}". Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`),null}async function T(t,r,n){let o=a__namespace.resolve(r,t),e=await f__namespace.readFile(o,"utf-8"),i=a__namespace.dirname(o),s=await b(e),c=[];for(let l of s){let p=await U(l.importPath,i,r,l.componentName,n);if(!p)continue;let u=l.componentName.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();c.push({componentName:l.componentName,componentPath:p,name:l.name,key:u});}return c}async function N(t,r,n,o,e){let i=r.minify??o,s=r.outDir??"./dist/ui",c=r.serverConfig??{},l;if(r.globalCss){let p=a__namespace.resolve(n,r.globalCss);try{l=await f__namespace.readFile(p,"utf-8");}catch(u){e.warn(`[mcp-react-ui] globalCss file not found or unreadable: ${p} - ${u instanceof Error?u.message:u}`);}}for(let p of t){let R=`
</html>`}function h(t){let o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return t.replace(/[&<>"']/g,n=>o[n]??n)}async function R(t){let o=typescriptEstree.parse(t,{loc:true,range:true,jsx:true}),n=[],r=new Map;for(let e of o.body)if(e.type===typescriptEstree.AST_NODE_TYPES.ImportDeclaration){let i=e.source.value;for(let c of e.specifiers)if(c.type===typescriptEstree.AST_NODE_TYPES.ImportSpecifier){let s=c.local.name;r.set(s,i);}else if(c.type===typescriptEstree.AST_NODE_TYPES.ImportDefaultSpecifier){let s=c.local.name;r.set(s,i);}}return d(o,e=>{if(e.type===typescriptEstree.AST_NODE_TYPES.CallExpression&&e.callee.type===typescriptEstree.AST_NODE_TYPES.Identifier&&e.callee.name==="defineReactUI"){let i=I(e,r);i&&n.push(i);}}),n}function I(t,o){let n=t.arguments[0];if(n?.type!==typescriptEstree.AST_NODE_TYPES.ObjectExpression)return null;let r=null,e=null,i;for(let s of n.properties){if(s.type!==typescriptEstree.AST_NODE_TYPES.Property)continue;let p=s.key,a=p.type===typescriptEstree.AST_NODE_TYPES.Identifier?p.name:null;a&&(a==="component"?s.value.type===typescriptEstree.AST_NODE_TYPES.Identifier&&(r=s.value.name):a==="name"?s.value.type===typescriptEstree.AST_NODE_TYPES.Literal&&typeof s.value.value=="string"&&(e=s.value.value):a==="autoResize"&&s.value.type===typescriptEstree.AST_NODE_TYPES.Literal&&typeof s.value.value=="boolean"&&(i=s.value.value));}if(!r||!e)return null;let c=o.get(r);return c?{componentName:r,importPath:c,name:e,autoResize:i}:null}function d(t,o){if(Array.isArray(t)){for(let r of t)d(r,o);return}o(t);let n=t;for(let r of Object.keys(n)){let e=n[r];if(e&&typeof e=="object")if(Array.isArray(e))for(let i of e)i&&typeof i=="object"&&"type"in i&&d(i,o);else "type"in e&&d(e,o);}}var C={info:t=>{console.log(t);},warn:t=>{console.warn(t);},error:t=>{console.error(t);}},k={info:()=>{},warn:()=>{},error:()=>{}};function $(t){let o=t.replace(/\\/g,"/"),n=/^[a-zA-Z]:\//.test(o),r=o.startsWith("//");return o.startsWith(".")||o.startsWith("/")||n||r?o:`./${o}`}function U(t,o){let n=l__namespace.resolve(t),r=l__namespace.resolve(o),e=l__namespace.relative(n,r);return e===""?true:e===".."?false:!e.startsWith(`..${l__namespace.sep}`)&&!l__namespace.isAbsolute(e)}async function T(t,o,n,r,e){if(!t.startsWith("."))return null;let i=await u__namespace.realpath(n),c=l__namespace.resolve(o,t),s=l__namespace.extname(c)?[c]:[".tsx",".ts",".jsx",".js"].map(p=>c+p);for(let p of s){try{await u__namespace.access(p);}catch{continue}let a=await u__namespace.realpath(p);return U(i,a)?a:(e.warn(`[mcp-react-ui] Refusing to build UI component outside project root. component="${r}", import="${t}", resolved="${a}"`),null)}return e.warn(`[mcp-react-ui] Could not resolve component file for "${r}" from import "${t}". Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`),null}async function N(t,o,n){let r=l__namespace.resolve(o,t),e=await u__namespace.readFile(r,"utf-8"),i=l__namespace.dirname(r),c=await R(e),s=[];for(let p of c){let a=await T(p.importPath,i,o,p.componentName,n);if(!a)continue;let m=p.componentName.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();s.push({componentName:p.componentName,componentPath:a,name:p.name,key:m,autoResize:p.autoResize});}return s}async function D(t,o,n,r,e){let i=o.minify??r,c=o.outDir??"./dist/ui",s=o.serverConfig??{},p;if(o.globalCss){let a=l__namespace.resolve(n,o.globalCss);try{p=await u__namespace.readFile(a,"utf-8");}catch(m){e.warn(`[mcp-react-ui] globalCss file not found or unreadable: ${a} - ${m instanceof Error?m.message:m}`);}}for(let a of t){let m=$(a.componentPath),S=a.autoResize===void 0?"":` autoResize={${a.autoResize}}`,x=`
import React from "react";
import { createRoot } from "react-dom/client";
import { AppsProvider } from "@mcp-apps-kit/ui-react";
import Component from "${k(p.componentPath)}";
import Component from "${m}";

@@ -61,3 +61,3 @@ const rootElement = document.getElementById("root");

<React.StrictMode>
<AppsProvider>
<AppsProvider${S}>
<Component />

@@ -68,3 +68,3 @@ </AppsProvider>

}
`,d=(await S__namespace.build({stdin:{contents:R,loader:"tsx",resolveDir:n,sourcefile:`${p.key}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:i,jsx:"automatic",jsxImportSource:"react",define:{"process.env.NODE_ENV":i?'"production"':'"development"',__MCP_SERVER_CONFIG__:JSON.stringify(c)}})).outputFiles?.[0]?.text;if(!d)throw new Error(`Failed to build UI: ${p.key}`);let x=P({key:p.key,name:p.name,script:d,css:l}),y=a__namespace.resolve(n,s,`${p.key}.html`);await f__namespace.mkdir(a__namespace.dirname(y),{recursive:true}),await f__namespace.writeFile(y,x,"utf-8"),e.info(`[mcp-react-ui] Built: ${p.key}.html`);}}function D(t){let r,n=t.standalone??false,o=t.logger===false?C:t.logger??I;return {name:"mcp-react-ui",configResolved(e){r=e;},async buildStart(){let e=r.root,i=r.mode==="production",s=await T(t.serverEntry,e,o);if(s.length===0){o.info("[mcp-react-ui] No defineReactUI calls found");return}o.info(`[mcp-react-ui] Found ${s.length} React UI(s): ${s.map(c=>c.componentName).join(", ")}`),await N(s,t,e,i,o);},resolveId(e){return n&&e==="virtual:mcp-react-ui-entry"?e:null},load(e){return n&&e==="virtual:mcp-react-ui-entry"?"export default {}":null},config(){if(n)return {build:{rollupOptions:{input:"virtual:mcp-react-ui-entry"}}}},generateBundle(e,i){if(!n)return;let s=Object.keys(i);for(let c of s)delete i[c];}}}var F=D;exports.default=F;exports.isPathWithinRoot=$;exports.mcpReactUI=D;exports.toEsbuildImportSpecifier=k;//# sourceMappingURL=vite-plugin.cjs.map
`,g=(await b__namespace.build({stdin:{contents:x,loader:"tsx",resolveDir:n,sourcefile:`${a.key}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:i,jsx:"automatic",jsxImportSource:"react",define:{"process.env.NODE_ENV":i?'"production"':'"development"',__MCP_SERVER_CONFIG__:JSON.stringify(s)}})).outputFiles?.[0]?.text;if(!g)throw new Error(`Failed to build UI: ${a.key}`);let E=P({key:a.key,name:a.name,script:g,css:p}),y=l__namespace.resolve(n,c,`${a.key}.html`);await u__namespace.mkdir(l__namespace.dirname(y),{recursive:true}),await u__namespace.writeFile(y,E,"utf-8"),e.info(`[mcp-react-ui] Built: ${a.key}.html`);}}function A(t){let o,n=t.standalone??false,r=t.logger===false?k:t.logger??C;return {name:"mcp-react-ui",configResolved(e){o=e;},async buildStart(){let e=o.root,i=o.mode==="production",c=await N(t.serverEntry,e,r);if(c.length===0){r.info("[mcp-react-ui] No defineReactUI calls found");return}r.info(`[mcp-react-ui] Found ${c.length} React UI(s): ${c.map(s=>s.componentName).join(", ")}`),await D(c,t,e,i,r);},resolveId(e){return n&&e==="virtual:mcp-react-ui-entry"?e:null},load(e){return n&&e==="virtual:mcp-react-ui-entry"?"export default {}":null},config(){if(n)return {build:{rollupOptions:{input:"virtual:mcp-react-ui-entry"}}}},generateBundle(e,i){if(!n)return;let c=Object.keys(i);for(let s of c)delete i[s];}}}var F=A;exports.default=F;exports.isPathWithinRoot=U;exports.mcpReactUI=A;exports.toEsbuildImportSpecifier=$;//# sourceMappingURL=vite-plugin.cjs.map
//# sourceMappingURL=vite-plugin.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/html.ts","../src/ast-parser.ts","../src/vite-plugin.ts"],"names":["DEFAULT_BASE_CSS","generateHTML","options","key","name","script","css","combinedCss","escapeHtml","text","htmlEntities","char","parseReactUIDefinitions","content","ast","parse","results","importMap","node","AST_NODE_TYPES","importPath","specifier","localName","walkAST","parsed","parseDefineReactUICall","arg","componentName","uiName","prop","keyName","visitor","child","nodeRecord","value","item","defaultLogger","message","silentLogger","toEsbuildImportSpecifier","componentPath","normalized","isWindowsDriveAbsolute","isUncAbsolute","isPathWithinRoot","rootPath","candidatePath","resolvedRoot","a","resolvedCandidate","relative","resolveComponentPath","entryDir","rootDir","logger","rootRealPath","f","basePath","candidatePaths","ext","candidateRealPath","discoverReactUIs","serverEntry","root","entryPath","discovered","ui","buildDiscoveredUIs","isProduction","minify","outDir","serverConfig","globalCss","globalCssPath","error","entryCode","S","html","outputPath","mcpReactUI","config","standalone","resolvedConfig","d","id","_","bundle","keys","vite_plugin_default"],"mappings":"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","file":"vite-plugin.cjs","sourcesContent":["/**\n * HTML template generation for React UIs\n */\n\nimport type { TemplateOptions } from \"./types\";\n\n/**\n * Default base CSS reset for all UIs.\n * Provides a consistent starting point across platforms.\n */\nconst DEFAULT_BASE_CSS = `\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html {\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n line-height: 1.5;\n color: #1a1a1a;\n background-color: transparent;\n }\n\n @media (prefers-color-scheme: dark) {\n body {\n color: #f5f5f5;\n }\n }\n\n #root {\n min-height: 100%;\n }\n`;\n\n/**\n * Generate a self-contained HTML document for a React UI.\n *\n * The generated HTML includes:\n * - DOCTYPE and valid HTML5 structure\n * - Meta tags for responsive design\n * - Inlined CSS (base reset + optional custom CSS)\n * - Inlined JavaScript bundle with React app\n *\n * @param options - Template options with key, name, script, and optional CSS\n * @returns Complete HTML document as a string\n *\n * @example\n * ```typescript\n * const html = generateHTML({\n * key: \"restaurant-list\",\n * name: \"Restaurant List Widget\",\n * script: bundledJavaScript,\n * css: customStyles,\n * });\n * ```\n *\n * @internal\n */\nexport function generateHTML(options: TemplateOptions): string {\n const { key, name, script, css } = options;\n\n // Combine base CSS with any custom CSS\n const combinedCss = css ? `${DEFAULT_BASE_CSS}\\n${css}` : DEFAULT_BASE_CSS;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"mcp-ui-key\" content=\"${escapeHtml(key)}\">\n <title>${escapeHtml(name)}</title>\n <style>${combinedCss}</style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\">${script.replace(/<\\/script>/gi, \"</scr\" + \"ipt>\")}</script>\n</body>\n</html>`;\n}\n\n/**\n * Options for generating the React entry point.\n *\n * @internal\n */\nexport interface EntryPointOptions {\n /**\n * Path to the component file.\n */\n componentPath: string;\n\n /**\n * Name of the export to use.\n * Use \"default\" for default exports, or the actual name for named exports.\n * @default \"default\"\n */\n componentExport?: string;\n\n /**\n * Default props to pass to the component.\n */\n defaultProps?: Record<string, unknown>;\n}\n\n/**\n * Generate the React entry point code that will be bundled.\n *\n * This creates a small JavaScript module that:\n * 1. Imports React and ReactDOM\n * 2. Imports the user's component\n * 3. Imports AppsProvider from @mcp-apps-kit/ui-react\n * 4. Renders the component wrapped in providers\n *\n * @param componentPath - Path to the React component file (for backward compatibility)\n * @param defaultProps - Optional default props to pass to the component\n * @returns JavaScript/TypeScript source code for the entry point\n *\n * @example\n * ```typescript\n * // Default export\n * const entryCode = generateEntryPoint(\n * \"./src/widgets/MyWidget.tsx\",\n * { theme: \"dark\" }\n * );\n *\n * // Named export\n * const entryCode = generateEntryPoint({\n * componentPath: \"./src/widgets/MyWidget.tsx\",\n * componentExport: \"MyWidget\",\n * });\n * ```\n *\n * @internal\n */\nexport function generateEntryPoint(\n componentPathOrOptions: string | EntryPointOptions,\n defaultProps?: Record<string, unknown>\n): string {\n // Handle backward compatibility with string-only signature\n const options: EntryPointOptions =\n typeof componentPathOrOptions === \"string\"\n ? { componentPath: componentPathOrOptions, defaultProps }\n : componentPathOrOptions;\n\n const { componentPath, componentExport = \"default\", defaultProps: props } = options;\n const propsJson = props ? JSON.stringify(props) : \"{}\";\n\n // Generate appropriate import statement based on export type\n const importStatement =\n componentExport === \"default\"\n ? `import Component from \"${componentPath}\";`\n : `import { ${componentExport} as Component } from \"${componentPath}\";`;\n\n return `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\n${importStatement}\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider>\n <Component {...${propsJson}} />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n *\n * @param text - Text to escape\n * @returns Escaped text safe for HTML insertion\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] ?? char);\n}\n\n/**\n * Extract CSS from a string that may contain both JS and CSS.\n * Used when esbuild bundles CSS as JavaScript that injects styles.\n *\n * @param code - Bundled code that may contain CSS injection\n * @returns Extracted CSS string or undefined\n */\nexport function extractInlineCSS(code: string): string | undefined {\n // esbuild injects CSS as: document.head.appendChild(...).textContent = \"css content\"\n const cssMatch = code.match(/\\.textContent\\s*=\\s*[\"'`]([\\s\\S]*?)[\"'`]\\s*[;,)]/);\n if (cssMatch?.[1]) {\n // Unescape the CSS string\n return cssMatch[1].replace(/\\\\n/g, \"\\n\").replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n return undefined;\n}\n","/**\n * AST-based parser for discovering defineReactUI calls\n *\n * Uses @typescript-eslint/typescript-estree for reliable TypeScript/TSX parsing.\n * This replaces the regex-based approach for more accurate import resolution.\n */\n\nimport { AST_NODE_TYPES, parse, type TSESTree } from \"@typescript-eslint/typescript-estree\";\n\n/**\n * Result of parsing a defineReactUI call\n */\nexport interface ParsedReactUI {\n /** Variable name used for the component */\n componentName: string;\n /** Import path for the component */\n importPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n}\n\n/**\n * Parse a TypeScript/TSX file and extract defineReactUI calls.\n *\n * @param content - File content to parse\n * @returns Array of parsed React UI definitions\n */\nexport async function parseReactUIDefinitions(content: string): Promise<ParsedReactUI[]> {\n const ast = parse(content, {\n loc: true,\n range: true,\n jsx: true,\n // Don't require a project - we just need syntax parsing\n });\n\n const results: ParsedReactUI[] = [];\n\n // Build import map: identifier -> import path\n const importMap = new Map<string, string>();\n\n for (const node of ast.body) {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n const importPath = node.source.value;\n\n for (const specifier of node.specifiers) {\n if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {\n // Named import: import { Foo } from \"./path\" or import { Foo as Bar } from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n } else if (specifier.type === AST_NODE_TYPES.ImportDefaultSpecifier) {\n // Default import: import Foo from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n }\n }\n }\n }\n\n // Walk the AST to find defineReactUI calls\n walkAST(ast, (node) => {\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier &&\n node.callee.name === \"defineReactUI\"\n ) {\n const parsed = parseDefineReactUICall(node, importMap);\n if (parsed) {\n results.push(parsed);\n }\n }\n });\n\n return results;\n}\n\n/**\n * Parse a defineReactUI call expression\n */\nfunction parseDefineReactUICall(\n node: TSESTree.CallExpression,\n importMap: Map<string, string>\n): ParsedReactUI | null {\n // First argument should be an object expression\n const arg = node.arguments[0];\n if (arg?.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n\n let componentName: string | null = null;\n let uiName: string | null = null;\n\n for (const prop of arg.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) continue;\n\n const key = prop.key;\n const keyName = key.type === AST_NODE_TYPES.Identifier ? key.name : null;\n if (!keyName) continue;\n\n if (keyName === \"component\") {\n // Extract component identifier\n if (prop.value.type === AST_NODE_TYPES.Identifier) {\n componentName = prop.value.name;\n }\n } else if (keyName === \"name\") {\n // Extract name string\n if (prop.value.type === AST_NODE_TYPES.Literal && typeof prop.value.value === \"string\") {\n uiName = prop.value.value;\n }\n }\n }\n\n if (!componentName || !uiName) {\n return null;\n }\n\n const importPath = importMap.get(componentName);\n if (!importPath) {\n return null;\n }\n\n return {\n componentName,\n importPath,\n name: uiName,\n };\n}\n\n/**\n * Simple AST walker\n */\nfunction walkAST(\n node: TSESTree.Node | TSESTree.Node[],\n visitor: (node: TSESTree.Node) => void\n): void {\n if (Array.isArray(node)) {\n for (const child of node) {\n walkAST(child, visitor);\n }\n return;\n }\n\n visitor(node);\n\n // Walk child nodes - cast to unknown first to avoid strict type checking\n const nodeRecord = node as unknown as Record<string, unknown>;\n for (const key of Object.keys(nodeRecord)) {\n const value = nodeRecord[key];\n if (value && typeof value === \"object\") {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n walkAST(item as TSESTree.Node, visitor);\n }\n }\n } else if (\"type\" in value) {\n walkAST(value as TSESTree.Node, visitor);\n }\n }\n }\n}\n","/**\n * Vite plugin for building React UI components\n *\n * This plugin automatically discovers `defineReactUI` calls in your source code,\n * resolves the component imports, and builds them into self-contained HTML files.\n *\n * Usage in vite.config.ts:\n * ```typescript\n * import { defineConfig } from \"vite\";\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * // Server entry point to scan for defineReactUI calls\n * serverEntry: \"./src/index.ts\",\n * // Output directory for built HTML files\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n *\n * Then in your server code:\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { GreetingWidget } from \"./ui/GreetingWidget\";\n *\n * const greetTool = defineTool({\n * ui: defineReactUI({\n * component: GreetingWidget,\n * name: \"Greeting Widget\",\n * }),\n * // ...\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig } from \"vite\";\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { generateHTML } from \"./html\";\nimport { parseReactUIDefinitions } from \"./ast-parser\";\n\n/**\n * Logger interface for the MCP React UI plugin.\n */\nexport interface PluginLogger {\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\n\n/**\n * Default logger that uses console methods with a prefix.\n */\nconst defaultLogger: PluginLogger = {\n info: (message: string) => {\n console.log(message); // eslint-disable-line no-console\n },\n warn: (message: string) => {\n console.warn(message); // eslint-disable-line no-console\n },\n error: (message: string) => {\n console.error(message); // eslint-disable-line no-console\n },\n};\n\n/**\n * Silent logger that does nothing.\n */\nconst silentLogger: PluginLogger = {\n info: () => {\n // Intentionally empty - silent logger\n },\n warn: () => {\n // Intentionally empty - silent logger\n },\n error: () => {\n // Intentionally empty - silent logger\n },\n};\n\n/**\n * Server configuration injected into UIs at build time.\n *\n * These values are available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n */\nexport type McpServerConfig = {\n /**\n * Base URL of the MCP server.\n *\n * Used by UIs to make API calls (e.g., debug logging via HTTP).\n * Should include protocol and port (e.g., \"http://localhost:3000\").\n *\n * @example \"http://localhost:3000\"\n * @example \"https://api.myapp.com\"\n */\n baseUrl?: string;\n\n /**\n * Additional custom configuration.\n *\n * Any extra values your UI needs at runtime.\n */\n [key: string]: unknown;\n};\n\n/**\n * Options for the MCP React UI Vite plugin.\n */\nexport interface McpReactUIOptions {\n /**\n * Server entry point file to scan for defineReactUI calls.\n * The plugin will parse this file and find all defineReactUI usages,\n * then resolve the component imports to their source files.\n *\n * @example \"./src/index.ts\"\n */\n serverEntry: string;\n\n /**\n * Output directory for built HTML files.\n * @default \"./dist/ui\"\n */\n outDir?: string;\n\n /**\n * Whether to minify the output.\n * Defaults to true in production, false in development.\n */\n minify?: boolean;\n\n /**\n * Path to global CSS file to include in all UIs.\n */\n globalCss?: string;\n\n /**\n * Custom logger for plugin output.\n * Set to `false` to disable all logging, or provide a custom logger.\n * @default console\n */\n logger?: PluginLogger | false;\n\n /**\n * Standalone mode takes over the Vite build.\n *\n * - When `true`, the plugin overrides the build input and removes all Vite outputs,\n * producing only the generated UI HTML files.\n * - When `false` (default), the plugin is additive: it generates UI HTML files\n * without modifying the main Vite build inputs/outputs.\n *\n * Use `true` when your Vite config exists solely to build MCP UI HTML.\n */\n standalone?: boolean;\n\n /**\n * Server configuration to inject into UIs at build time.\n *\n * These values become available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n * Useful for injecting the server base URL, API endpoints, or other runtime config.\n *\n * @example\n * ```typescript\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * serverConfig: {\n * baseUrl: \"http://localhost:3000\",\n * },\n * })\n * ```\n */\n serverConfig?: McpServerConfig;\n}\n\n/**\n * Information about a discovered React UI definition.\n */\ninterface DiscoveredUI {\n /** Variable name used for the component */\n componentName: string;\n /** Resolved file path to the component */\n componentPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n /** Generated key for output file */\n key: string;\n}\n\n/**\n * Convert a filesystem path to an import specifier suitable for esbuild.\n *\n * esbuild accepts absolute paths as specifiers (e.g. \"/abs/file.tsx\", \"C:/abs/file.tsx\").\n * For relative-like paths, we prefix with \"./\".\n *\n * @internal\n */\nexport function toEsbuildImportSpecifier(componentPath: string): string {\n // Normalize path for ESM imports (Windows backslashes -> forward slashes)\n const normalized = componentPath.replace(/\\\\/g, \"/\");\n\n // Absolute path forms we must not prefix with \"./\":\n // - POSIX absolute: /...\n // - Windows drive absolute: C:/...\n // - UNC absolute: //server/share/...\n const isWindowsDriveAbsolute = /^[a-zA-Z]:\\//.test(normalized);\n const isUncAbsolute = normalized.startsWith(\"//\");\n\n if (\n normalized.startsWith(\".\") ||\n normalized.startsWith(\"/\") ||\n isWindowsDriveAbsolute ||\n isUncAbsolute\n ) {\n return normalized;\n }\n\n return `./${normalized}`;\n}\n\n/**\n * Checks whether `candidatePath` is within `rootPath`.\n *\n * Both inputs may be relative; they will be resolved before comparison.\n *\n * @internal\n */\nexport function isPathWithinRoot(rootPath: string, candidatePath: string): boolean {\n const resolvedRoot = path.resolve(rootPath);\n const resolvedCandidate = path.resolve(candidatePath);\n\n const relative = path.relative(resolvedRoot, resolvedCandidate);\n if (relative === \"\") return true;\n if (relative === \"..\") return false;\n\n return !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * Resolve import path to actual file path with extension.\n */\nasync function resolveComponentPath(\n importPath: string,\n entryDir: string,\n rootDir: string,\n componentName: string,\n logger: PluginLogger\n): Promise<string | null> {\n if (!importPath.startsWith(\".\")) {\n // Package import - skip\n return null;\n }\n\n const rootRealPath = await fs.realpath(rootDir);\n const basePath = path.resolve(entryDir, importPath);\n\n const candidatePaths = path.extname(basePath)\n ? [basePath]\n : [\".tsx\", \".ts\", \".jsx\", \".js\"].map((ext) => basePath + ext);\n\n for (const candidatePath of candidatePaths) {\n try {\n await fs.access(candidatePath);\n } catch {\n continue;\n }\n\n // Resolve symlinks before boundary check.\n const candidateRealPath = await fs.realpath(candidatePath);\n if (!isPathWithinRoot(rootRealPath, candidateRealPath)) {\n logger.warn(\n `[mcp-react-ui] Refusing to build UI component outside project root. ` +\n `component=\"${componentName}\", import=\"${importPath}\", resolved=\"${candidateRealPath}\"`\n );\n return null;\n }\n\n return candidateRealPath;\n }\n\n logger.warn(\n `[mcp-react-ui] Could not resolve component file for \"${componentName}\" from import \"${importPath}\". ` +\n `Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`\n );\n return null;\n}\n\n/**\n * Scan source file for defineReactUI calls and extract component information.\n * Uses AST parsing for reliable detection of imports and defineReactUI calls.\n */\nasync function discoverReactUIs(\n serverEntry: string,\n root: string,\n logger: PluginLogger\n): Promise<DiscoveredUI[]> {\n const entryPath = path.resolve(root, serverEntry);\n const content = await fs.readFile(entryPath, \"utf-8\");\n const entryDir = path.dirname(entryPath);\n\n const parsed = await parseReactUIDefinitions(content);\n const discovered: DiscoveredUI[] = [];\n\n for (const ui of parsed) {\n const componentPath = await resolveComponentPath(\n ui.importPath,\n entryDir,\n root,\n ui.componentName,\n logger\n );\n if (!componentPath) continue;\n\n const key = ui.componentName.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n discovered.push({\n componentName: ui.componentName,\n componentPath,\n name: ui.name,\n key,\n });\n }\n\n return discovered;\n}\n\n/**\n * Build discovered React UI components.\n */\nasync function buildDiscoveredUIs(\n discovered: DiscoveredUI[],\n options: McpReactUIOptions,\n root: string,\n isProduction: boolean,\n logger: PluginLogger\n): Promise<void> {\n const minify = options.minify ?? isProduction;\n const outDir = options.outDir ?? \"./dist/ui\";\n const serverConfig = options.serverConfig ?? {};\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n const globalCssPath = path.resolve(root, options.globalCss);\n try {\n globalCss = await fs.readFile(globalCssPath, \"utf-8\");\n } catch (error) {\n logger.warn(\n `[mcp-react-ui] globalCss file not found or unreadable: ${globalCssPath} - ${\n error instanceof Error ? error.message : error\n }`\n );\n }\n }\n\n // Build each discovered UI\n for (const ui of discovered) {\n const importPath = toEsbuildImportSpecifier(ui.componentPath);\n\n // Generate entry point code\n const entryCode = `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\nimport Component from \"${importPath}\";\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider>\n <Component />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n\n // Bundle with esbuild\n const result = await esbuild.build({\n stdin: {\n contents: entryCode,\n loader: \"tsx\",\n resolveDir: root,\n sourcefile: `${ui.key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n define: {\n \"process.env.NODE_ENV\": minify ? '\"production\"' : '\"development\"',\n __MCP_SERVER_CONFIG__: JSON.stringify(serverConfig),\n },\n });\n\n const script = result.outputFiles?.[0]?.text;\n if (!script) {\n throw new Error(`Failed to build UI: ${ui.key}`);\n }\n\n // Generate HTML\n const html = generateHTML({\n key: ui.key,\n name: ui.name,\n script,\n css: globalCss,\n });\n\n // Write output file\n const outputPath = path.resolve(root, outDir, `${ui.key}.html`);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, html, \"utf-8\");\n\n logger.info(`[mcp-react-ui] Built: ${ui.key}.html`);\n }\n}\n\n/**\n * Vite plugin that automatically discovers and builds React UI components.\n *\n * This plugin scans your server entry point for `defineReactUI` calls,\n * resolves the component imports, and builds them into self-contained HTML.\n *\n * @param options - Plugin configuration\n * @returns Vite plugin\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n */\nexport function mcpReactUI(options: McpReactUIOptions): Plugin {\n let config: ResolvedConfig;\n\n const standalone = options.standalone ?? false;\n\n // Resolve logger: false = silent, undefined = default, custom = use provided\n const logger: PluginLogger =\n options.logger === false ? silentLogger : (options.logger ?? defaultLogger);\n\n return {\n name: \"mcp-react-ui\",\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n\n // Run build at the start of the build process\n async buildStart() {\n const root = config.root;\n const isProduction = config.mode === \"production\";\n\n // Discover React UIs from server entry\n const discovered = await discoverReactUIs(options.serverEntry, root, logger);\n\n if (discovered.length === 0) {\n logger.info(\"[mcp-react-ui] No defineReactUI calls found\");\n return;\n }\n\n logger.info(\n `[mcp-react-ui] Found ${discovered.length} React UI(s): ${discovered.map((d) => d.componentName).join(\", \")}`\n );\n\n // Build discovered UIs\n await buildDiscoveredUIs(discovered, options, root, isProduction, logger);\n },\n\n // Provide a virtual empty module so Vite doesn't complain about missing entry\n resolveId(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return id;\n }\n return null;\n },\n\n load(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return \"export default {}\";\n }\n return null;\n },\n\n // Override the config to use our virtual entry\n config() {\n if (!standalone) {\n return undefined;\n }\n\n return {\n build: {\n rollupOptions: {\n input: \"virtual:mcp-react-ui-entry\",\n },\n },\n };\n },\n\n // Standalone mode: prevent Vite from generating output files (we already wrote our HTML)\n generateBundle(_, bundle) {\n if (!standalone) {\n return;\n }\n\n // Remove all generated chunks since we don't need them\n const keys = Object.keys(bundle);\n for (const key of keys) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete bundle[key];\n }\n },\n };\n}\n\nexport default mcpReactUI;\n"]}
{"version":3,"sources":["../src/html.ts","../src/ast-parser.ts","../src/vite-plugin.ts"],"names":["DEFAULT_BASE_CSS","generateHTML","options","key","name","script","css","combinedCss","escapeHtml","text","htmlEntities","char","parseReactUIDefinitions","content","ast","parse","results","importMap","node","AST_NODE_TYPES","importPath","specifier","localName","walkAST","parsed","parseDefineReactUICall","arg","componentName","uiName","autoResize","prop","keyName","visitor","child","nodeRecord","value","item","defaultLogger","message","silentLogger","toEsbuildImportSpecifier","componentPath","normalized","isWindowsDriveAbsolute","isUncAbsolute","isPathWithinRoot","rootPath","candidatePath","resolvedRoot","l","resolvedCandidate","relative","resolveComponentPath","entryDir","rootDir","logger","rootRealPath","u","basePath","candidatePaths","ext","candidateRealPath","discoverReactUIs","serverEntry","root","entryPath","discovered","ui","buildDiscoveredUIs","isProduction","minify","outDir","serverConfig","globalCss","globalCssPath","error","providerProps","entryCode","b","html","outputPath","mcpReactUI","config","standalone","resolvedConfig","d","id","_","bundle","keys","vite_plugin_default"],"mappings":"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","file":"vite-plugin.cjs","sourcesContent":["/**\n * HTML template generation for React UIs\n */\n\nimport type { TemplateOptions } from \"./types\";\n\n/**\n * Default base CSS reset for all UIs.\n * Provides a consistent starting point across platforms.\n */\nconst DEFAULT_BASE_CSS = `\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html {\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n line-height: 1.5;\n color: #1a1a1a;\n background-color: transparent;\n }\n\n @media (prefers-color-scheme: dark) {\n body {\n color: #f5f5f5;\n }\n }\n\n #root {\n min-height: 100%;\n }\n`;\n\n/**\n * Generate a self-contained HTML document for a React UI.\n *\n * The generated HTML includes:\n * - DOCTYPE and valid HTML5 structure\n * - Meta tags for responsive design\n * - Inlined CSS (base reset + optional custom CSS)\n * - Inlined JavaScript bundle with React app\n *\n * @param options - Template options with key, name, script, and optional CSS\n * @returns Complete HTML document as a string\n *\n * @example\n * ```typescript\n * const html = generateHTML({\n * key: \"restaurant-list\",\n * name: \"Restaurant List Widget\",\n * script: bundledJavaScript,\n * css: customStyles,\n * });\n * ```\n *\n * @internal\n */\nexport function generateHTML(options: TemplateOptions): string {\n const { key, name, script, css } = options;\n\n // Combine base CSS with any custom CSS\n const combinedCss = css ? `${DEFAULT_BASE_CSS}\\n${css}` : DEFAULT_BASE_CSS;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"mcp-ui-key\" content=\"${escapeHtml(key)}\">\n <title>${escapeHtml(name)}</title>\n <style>${combinedCss}</style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\">${script.replace(/<\\/script>/gi, \"</scr\" + \"ipt>\")}</script>\n</body>\n</html>`;\n}\n\n/**\n * Options for generating the React entry point.\n *\n * @internal\n */\nexport interface EntryPointOptions {\n /**\n * Path to the component file.\n */\n componentPath: string;\n\n /**\n * Name of the export to use.\n * Use \"default\" for default exports, or the actual name for named exports.\n * @default \"default\"\n */\n componentExport?: string;\n\n /**\n * Default props to pass to the component.\n */\n defaultProps?: Record<string, unknown>;\n\n /**\n * Whether to enable automatic size change notifications.\n * When undefined, uses the default (true).\n */\n autoResize?: boolean;\n}\n\n/**\n * Generate the React entry point code that will be bundled.\n *\n * This creates a small JavaScript module that:\n * 1. Imports React and ReactDOM\n * 2. Imports the user's component\n * 3. Imports AppsProvider from @mcp-apps-kit/ui-react\n * 4. Renders the component wrapped in providers\n *\n * @param componentPath - Path to the React component file (for backward compatibility)\n * @param defaultProps - Optional default props to pass to the component\n * @returns JavaScript/TypeScript source code for the entry point\n *\n * @example\n * ```typescript\n * // Default export\n * const entryCode = generateEntryPoint(\n * \"./src/widgets/MyWidget.tsx\",\n * { theme: \"dark\" }\n * );\n *\n * // Named export\n * const entryCode = generateEntryPoint({\n * componentPath: \"./src/widgets/MyWidget.tsx\",\n * componentExport: \"MyWidget\",\n * });\n * ```\n *\n * @internal\n */\nexport function generateEntryPoint(\n componentPathOrOptions: string | EntryPointOptions,\n defaultProps?: Record<string, unknown>\n): string {\n // Handle backward compatibility with string-only signature\n const options: EntryPointOptions =\n typeof componentPathOrOptions === \"string\"\n ? { componentPath: componentPathOrOptions, defaultProps }\n : componentPathOrOptions;\n\n const { componentPath, componentExport = \"default\", defaultProps: props, autoResize } = options;\n const propsJson = props ? JSON.stringify(props) : \"{}\";\n\n // Generate appropriate import statement based on export type\n const importStatement =\n componentExport === \"default\"\n ? `import Component from \"${componentPath}\";`\n : `import { ${componentExport} as Component } from \"${componentPath}\";`;\n\n // Generate AppsProvider props\n const providerProps = autoResize === undefined ? \"\" : ` autoResize={${autoResize}}`;\n\n return `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\n${importStatement}\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider${providerProps}>\n <Component {...${propsJson}} />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n *\n * @param text - Text to escape\n * @returns Escaped text safe for HTML insertion\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] ?? char);\n}\n\n/**\n * Extract CSS from a string that may contain both JS and CSS.\n * Used when esbuild bundles CSS as JavaScript that injects styles.\n *\n * @param code - Bundled code that may contain CSS injection\n * @returns Extracted CSS string or undefined\n */\nexport function extractInlineCSS(code: string): string | undefined {\n // esbuild injects CSS as: document.head.appendChild(...).textContent = \"css content\"\n const cssMatch = code.match(/\\.textContent\\s*=\\s*[\"'`]([\\s\\S]*?)[\"'`]\\s*[;,)]/);\n if (cssMatch?.[1]) {\n // Unescape the CSS string\n return cssMatch[1].replace(/\\\\n/g, \"\\n\").replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n return undefined;\n}\n","/**\n * AST-based parser for discovering defineReactUI calls\n *\n * Uses @typescript-eslint/typescript-estree for reliable TypeScript/TSX parsing.\n * This replaces the regex-based approach for more accurate import resolution.\n */\n\nimport { AST_NODE_TYPES, parse, type TSESTree } from \"@typescript-eslint/typescript-estree\";\n\n/**\n * Result of parsing a defineReactUI call\n */\nexport interface ParsedReactUI {\n /** Variable name used for the component */\n componentName: string;\n /** Import path for the component */\n importPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n /** Whether auto-resize is enabled (undefined means default/true) */\n autoResize?: boolean;\n}\n\n/**\n * Parse a TypeScript/TSX file and extract defineReactUI calls.\n *\n * @param content - File content to parse\n * @returns Array of parsed React UI definitions\n */\nexport async function parseReactUIDefinitions(content: string): Promise<ParsedReactUI[]> {\n const ast = parse(content, {\n loc: true,\n range: true,\n jsx: true,\n // Don't require a project - we just need syntax parsing\n });\n\n const results: ParsedReactUI[] = [];\n\n // Build import map: identifier -> import path\n const importMap = new Map<string, string>();\n\n for (const node of ast.body) {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n const importPath = node.source.value;\n\n for (const specifier of node.specifiers) {\n if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {\n // Named import: import { Foo } from \"./path\" or import { Foo as Bar } from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n } else if (specifier.type === AST_NODE_TYPES.ImportDefaultSpecifier) {\n // Default import: import Foo from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n }\n }\n }\n }\n\n // Walk the AST to find defineReactUI calls\n walkAST(ast, (node) => {\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier &&\n node.callee.name === \"defineReactUI\"\n ) {\n const parsed = parseDefineReactUICall(node, importMap);\n if (parsed) {\n results.push(parsed);\n }\n }\n });\n\n return results;\n}\n\n/**\n * Parse a defineReactUI call expression\n */\nfunction parseDefineReactUICall(\n node: TSESTree.CallExpression,\n importMap: Map<string, string>\n): ParsedReactUI | null {\n // First argument should be an object expression\n const arg = node.arguments[0];\n if (arg?.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n\n let componentName: string | null = null;\n let uiName: string | null = null;\n let autoResize: boolean | undefined = undefined;\n\n for (const prop of arg.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) continue;\n\n const key = prop.key;\n const keyName = key.type === AST_NODE_TYPES.Identifier ? key.name : null;\n if (!keyName) continue;\n\n if (keyName === \"component\") {\n // Extract component identifier\n if (prop.value.type === AST_NODE_TYPES.Identifier) {\n componentName = prop.value.name;\n }\n } else if (keyName === \"name\") {\n // Extract name string\n if (prop.value.type === AST_NODE_TYPES.Literal && typeof prop.value.value === \"string\") {\n uiName = prop.value.value;\n }\n } else if (keyName === \"autoResize\") {\n // Extract autoResize boolean\n if (prop.value.type === AST_NODE_TYPES.Literal && typeof prop.value.value === \"boolean\") {\n autoResize = prop.value.value;\n }\n }\n }\n\n if (!componentName || !uiName) {\n return null;\n }\n\n const importPath = importMap.get(componentName);\n if (!importPath) {\n return null;\n }\n\n return {\n componentName,\n importPath,\n name: uiName,\n autoResize,\n };\n}\n\n/**\n * Simple AST walker\n */\nfunction walkAST(\n node: TSESTree.Node | TSESTree.Node[],\n visitor: (node: TSESTree.Node) => void\n): void {\n if (Array.isArray(node)) {\n for (const child of node) {\n walkAST(child, visitor);\n }\n return;\n }\n\n visitor(node);\n\n // Walk child nodes - cast to unknown first to avoid strict type checking\n const nodeRecord = node as unknown as Record<string, unknown>;\n for (const key of Object.keys(nodeRecord)) {\n const value = nodeRecord[key];\n if (value && typeof value === \"object\") {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n walkAST(item as TSESTree.Node, visitor);\n }\n }\n } else if (\"type\" in value) {\n walkAST(value as TSESTree.Node, visitor);\n }\n }\n }\n}\n","/**\n * Vite plugin for building React UI components\n *\n * This plugin automatically discovers `defineReactUI` calls in your source code,\n * resolves the component imports, and builds them into self-contained HTML files.\n *\n * Usage in vite.config.ts:\n * ```typescript\n * import { defineConfig } from \"vite\";\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * // Server entry point to scan for defineReactUI calls\n * serverEntry: \"./src/index.ts\",\n * // Output directory for built HTML files\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n *\n * Then in your server code:\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { GreetingWidget } from \"./ui/GreetingWidget\";\n *\n * const greetTool = defineTool({\n * ui: defineReactUI({\n * component: GreetingWidget,\n * name: \"Greeting Widget\",\n * }),\n * // ...\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig } from \"vite\";\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { generateHTML } from \"./html\";\nimport { parseReactUIDefinitions } from \"./ast-parser\";\n\n/**\n * Logger interface for the MCP React UI plugin.\n */\nexport interface PluginLogger {\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\n\n/**\n * Default logger that uses console methods with a prefix.\n */\nconst defaultLogger: PluginLogger = {\n info: (message: string) => {\n console.log(message); // eslint-disable-line no-console\n },\n warn: (message: string) => {\n console.warn(message); // eslint-disable-line no-console\n },\n error: (message: string) => {\n console.error(message); // eslint-disable-line no-console\n },\n};\n\n/**\n * Silent logger that does nothing.\n */\nconst silentLogger: PluginLogger = {\n info: () => {\n // Intentionally empty - silent logger\n },\n warn: () => {\n // Intentionally empty - silent logger\n },\n error: () => {\n // Intentionally empty - silent logger\n },\n};\n\n/**\n * Server configuration injected into UIs at build time.\n *\n * These values are available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n */\nexport type McpServerConfig = {\n /**\n * Base URL of the MCP server.\n *\n * Used by UIs to make API calls (e.g., debug logging via HTTP).\n * Should include protocol and port (e.g., \"http://localhost:3000\").\n *\n * @example \"http://localhost:3000\"\n * @example \"https://api.myapp.com\"\n */\n baseUrl?: string;\n\n /**\n * Additional custom configuration.\n *\n * Any extra values your UI needs at runtime.\n */\n [key: string]: unknown;\n};\n\n/**\n * Options for the MCP React UI Vite plugin.\n */\nexport interface McpReactUIOptions {\n /**\n * Server entry point file to scan for defineReactUI calls.\n * The plugin will parse this file and find all defineReactUI usages,\n * then resolve the component imports to their source files.\n *\n * @example \"./src/index.ts\"\n */\n serverEntry: string;\n\n /**\n * Output directory for built HTML files.\n * @default \"./dist/ui\"\n */\n outDir?: string;\n\n /**\n * Whether to minify the output.\n * Defaults to true in production, false in development.\n */\n minify?: boolean;\n\n /**\n * Path to global CSS file to include in all UIs.\n */\n globalCss?: string;\n\n /**\n * Custom logger for plugin output.\n * Set to `false` to disable all logging, or provide a custom logger.\n * @default console\n */\n logger?: PluginLogger | false;\n\n /**\n * Standalone mode takes over the Vite build.\n *\n * - When `true`, the plugin overrides the build input and removes all Vite outputs,\n * producing only the generated UI HTML files.\n * - When `false` (default), the plugin is additive: it generates UI HTML files\n * without modifying the main Vite build inputs/outputs.\n *\n * Use `true` when your Vite config exists solely to build MCP UI HTML.\n */\n standalone?: boolean;\n\n /**\n * Server configuration to inject into UIs at build time.\n *\n * These values become available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n * Useful for injecting the server base URL, API endpoints, or other runtime config.\n *\n * @example\n * ```typescript\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * serverConfig: {\n * baseUrl: \"http://localhost:3000\",\n * },\n * })\n * ```\n */\n serverConfig?: McpServerConfig;\n}\n\n/**\n * Information about a discovered React UI definition.\n */\ninterface DiscoveredUI {\n /** Variable name used for the component */\n componentName: string;\n /** Resolved file path to the component */\n componentPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n /** Generated key for output file */\n key: string;\n /** Whether auto-resize is enabled (undefined means default/true) */\n autoResize?: boolean;\n}\n\n/**\n * Convert a filesystem path to an import specifier suitable for esbuild.\n *\n * esbuild accepts absolute paths as specifiers (e.g. \"/abs/file.tsx\", \"C:/abs/file.tsx\").\n * For relative-like paths, we prefix with \"./\".\n *\n * @internal\n */\nexport function toEsbuildImportSpecifier(componentPath: string): string {\n // Normalize path for ESM imports (Windows backslashes -> forward slashes)\n const normalized = componentPath.replace(/\\\\/g, \"/\");\n\n // Absolute path forms we must not prefix with \"./\":\n // - POSIX absolute: /...\n // - Windows drive absolute: C:/...\n // - UNC absolute: //server/share/...\n const isWindowsDriveAbsolute = /^[a-zA-Z]:\\//.test(normalized);\n const isUncAbsolute = normalized.startsWith(\"//\");\n\n if (\n normalized.startsWith(\".\") ||\n normalized.startsWith(\"/\") ||\n isWindowsDriveAbsolute ||\n isUncAbsolute\n ) {\n return normalized;\n }\n\n return `./${normalized}`;\n}\n\n/**\n * Checks whether `candidatePath` is within `rootPath`.\n *\n * Both inputs may be relative; they will be resolved before comparison.\n *\n * @internal\n */\nexport function isPathWithinRoot(rootPath: string, candidatePath: string): boolean {\n const resolvedRoot = path.resolve(rootPath);\n const resolvedCandidate = path.resolve(candidatePath);\n\n const relative = path.relative(resolvedRoot, resolvedCandidate);\n if (relative === \"\") return true;\n if (relative === \"..\") return false;\n\n return !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * Resolve import path to actual file path with extension.\n */\nasync function resolveComponentPath(\n importPath: string,\n entryDir: string,\n rootDir: string,\n componentName: string,\n logger: PluginLogger\n): Promise<string | null> {\n if (!importPath.startsWith(\".\")) {\n // Package import - skip\n return null;\n }\n\n const rootRealPath = await fs.realpath(rootDir);\n const basePath = path.resolve(entryDir, importPath);\n\n const candidatePaths = path.extname(basePath)\n ? [basePath]\n : [\".tsx\", \".ts\", \".jsx\", \".js\"].map((ext) => basePath + ext);\n\n for (const candidatePath of candidatePaths) {\n try {\n await fs.access(candidatePath);\n } catch {\n continue;\n }\n\n // Resolve symlinks before boundary check.\n const candidateRealPath = await fs.realpath(candidatePath);\n if (!isPathWithinRoot(rootRealPath, candidateRealPath)) {\n logger.warn(\n `[mcp-react-ui] Refusing to build UI component outside project root. ` +\n `component=\"${componentName}\", import=\"${importPath}\", resolved=\"${candidateRealPath}\"`\n );\n return null;\n }\n\n return candidateRealPath;\n }\n\n logger.warn(\n `[mcp-react-ui] Could not resolve component file for \"${componentName}\" from import \"${importPath}\". ` +\n `Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`\n );\n return null;\n}\n\n/**\n * Scan source file for defineReactUI calls and extract component information.\n * Uses AST parsing for reliable detection of imports and defineReactUI calls.\n */\nasync function discoverReactUIs(\n serverEntry: string,\n root: string,\n logger: PluginLogger\n): Promise<DiscoveredUI[]> {\n const entryPath = path.resolve(root, serverEntry);\n const content = await fs.readFile(entryPath, \"utf-8\");\n const entryDir = path.dirname(entryPath);\n\n const parsed = await parseReactUIDefinitions(content);\n const discovered: DiscoveredUI[] = [];\n\n for (const ui of parsed) {\n const componentPath = await resolveComponentPath(\n ui.importPath,\n entryDir,\n root,\n ui.componentName,\n logger\n );\n if (!componentPath) continue;\n\n const key = ui.componentName.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n discovered.push({\n componentName: ui.componentName,\n componentPath,\n name: ui.name,\n key,\n autoResize: ui.autoResize,\n });\n }\n\n return discovered;\n}\n\n/**\n * Build discovered React UI components.\n */\nasync function buildDiscoveredUIs(\n discovered: DiscoveredUI[],\n options: McpReactUIOptions,\n root: string,\n isProduction: boolean,\n logger: PluginLogger\n): Promise<void> {\n const minify = options.minify ?? isProduction;\n const outDir = options.outDir ?? \"./dist/ui\";\n const serverConfig = options.serverConfig ?? {};\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n const globalCssPath = path.resolve(root, options.globalCss);\n try {\n globalCss = await fs.readFile(globalCssPath, \"utf-8\");\n } catch (error) {\n logger.warn(\n `[mcp-react-ui] globalCss file not found or unreadable: ${globalCssPath} - ${\n error instanceof Error ? error.message : error\n }`\n );\n }\n }\n\n // Build each discovered UI\n for (const ui of discovered) {\n const importPath = toEsbuildImportSpecifier(ui.componentPath);\n\n // Generate AppsProvider props based on autoResize setting\n const providerProps = ui.autoResize === undefined ? \"\" : ` autoResize={${ui.autoResize}}`;\n\n // Generate entry point code\n const entryCode = `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\nimport Component from \"${importPath}\";\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider${providerProps}>\n <Component />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n\n // Bundle with esbuild\n const result = await esbuild.build({\n stdin: {\n contents: entryCode,\n loader: \"tsx\",\n resolveDir: root,\n sourcefile: `${ui.key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n define: {\n \"process.env.NODE_ENV\": minify ? '\"production\"' : '\"development\"',\n __MCP_SERVER_CONFIG__: JSON.stringify(serverConfig),\n },\n });\n\n const script = result.outputFiles?.[0]?.text;\n if (!script) {\n throw new Error(`Failed to build UI: ${ui.key}`);\n }\n\n // Generate HTML\n const html = generateHTML({\n key: ui.key,\n name: ui.name,\n script,\n css: globalCss,\n });\n\n // Write output file\n const outputPath = path.resolve(root, outDir, `${ui.key}.html`);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, html, \"utf-8\");\n\n logger.info(`[mcp-react-ui] Built: ${ui.key}.html`);\n }\n}\n\n/**\n * Vite plugin that automatically discovers and builds React UI components.\n *\n * This plugin scans your server entry point for `defineReactUI` calls,\n * resolves the component imports, and builds them into self-contained HTML.\n *\n * @param options - Plugin configuration\n * @returns Vite plugin\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n */\nexport function mcpReactUI(options: McpReactUIOptions): Plugin {\n let config: ResolvedConfig;\n\n const standalone = options.standalone ?? false;\n\n // Resolve logger: false = silent, undefined = default, custom = use provided\n const logger: PluginLogger =\n options.logger === false ? silentLogger : (options.logger ?? defaultLogger);\n\n return {\n name: \"mcp-react-ui\",\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n\n // Run build at the start of the build process\n async buildStart() {\n const root = config.root;\n const isProduction = config.mode === \"production\";\n\n // Discover React UIs from server entry\n const discovered = await discoverReactUIs(options.serverEntry, root, logger);\n\n if (discovered.length === 0) {\n logger.info(\"[mcp-react-ui] No defineReactUI calls found\");\n return;\n }\n\n logger.info(\n `[mcp-react-ui] Found ${discovered.length} React UI(s): ${discovered.map((d) => d.componentName).join(\", \")}`\n );\n\n // Build discovered UIs\n await buildDiscoveredUIs(discovered, options, root, isProduction, logger);\n },\n\n // Provide a virtual empty module so Vite doesn't complain about missing entry\n resolveId(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return id;\n }\n return null;\n },\n\n load(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return \"export default {}\";\n }\n return null;\n },\n\n // Override the config to use our virtual entry\n config() {\n if (!standalone) {\n return undefined;\n }\n\n return {\n build: {\n rollupOptions: {\n input: \"virtual:mcp-react-ui-entry\",\n },\n },\n };\n },\n\n // Standalone mode: prevent Vite from generating output files (we already wrote our HTML)\n generateBundle(_, bundle) {\n if (!standalone) {\n return;\n }\n\n // Remove all generated chunks since we don't need them\n const keys = Object.keys(bundle);\n for (const key of keys) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete bundle[key];\n }\n },\n };\n}\n\nexport default mcpReactUI;\n"]}

@@ -1,6 +0,6 @@

import {a as a$1}from'./chunk-6JS3KVIH.js';import*as P from'esbuild';import*as f from'fs/promises';import*as a from'path';import {parse,AST_NODE_TYPES}from'@typescript-eslint/typescript-estree';async function h(t){let r=parse(t,{loc:true,range:true,jsx:true}),i=[],o=new Map;for(let e of r.body)if(e.type===AST_NODE_TYPES.ImportDeclaration){let s=e.source.value;for(let n of e.specifiers)if(n.type===AST_NODE_TYPES.ImportSpecifier){let c=n.local.name;o.set(c,s);}else if(n.type===AST_NODE_TYPES.ImportDefaultSpecifier){let c=n.local.name;o.set(c,s);}}return g(r,e=>{if(e.type===AST_NODE_TYPES.CallExpression&&e.callee.type===AST_NODE_TYPES.Identifier&&e.callee.name==="defineReactUI"){let s=w(e,o);s&&i.push(s);}}),i}function w(t,r){let i=t.arguments[0];if(i?.type!==AST_NODE_TYPES.ObjectExpression)return null;let o=null,e=null;for(let n of i.properties){if(n.type!==AST_NODE_TYPES.Property)continue;let c=n.key,l=c.type===AST_NODE_TYPES.Identifier?c.name:null;l&&(l==="component"?n.value.type===AST_NODE_TYPES.Identifier&&(o=n.value.name):l==="name"&&n.value.type===AST_NODE_TYPES.Literal&&typeof n.value.value=="string"&&(e=n.value.value));}if(!o||!e)return null;let s=r.get(o);return s?{componentName:o,importPath:s,name:e}:null}function g(t,r){if(Array.isArray(t)){for(let o of t)g(o,r);return}r(t);let i=t;for(let o of Object.keys(i)){let e=i[o];if(e&&typeof e=="object")if(Array.isArray(e))for(let s of e)s&&typeof s=="object"&&"type"in s&&g(s,r);else "type"in e&&g(e,r);}}var S={info:t=>{console.log(t);},warn:t=>{console.warn(t);},error:t=>{console.error(t);}},x={info:()=>{},warn:()=>{},error:()=>{}};function C(t){let r=t.replace(/\\/g,"/"),i=/^[a-zA-Z]:\//.test(r),o=r.startsWith("//");return r.startsWith(".")||r.startsWith("/")||i||o?r:`./${r}`}function E(t,r){let i=a.resolve(t),o=a.resolve(r),e=a.relative(i,o);return e===""?true:e===".."?false:!e.startsWith(`..${a.sep}`)&&!a.isAbsolute(e)}async function k(t,r,i,o,e){if(!t.startsWith("."))return null;let s=await f.realpath(i),n=a.resolve(r,t),c=a.extname(n)?[n]:[".tsx",".ts",".jsx",".js"].map(l=>n+l);for(let l of c){try{await f.access(l);}catch{continue}let u=await f.realpath(l);return E(s,u)?u:(e.warn(`[mcp-react-ui] Refusing to build UI component outside project root. component="${o}", import="${t}", resolved="${u}"`),null)}return e.warn(`[mcp-react-ui] Could not resolve component file for "${o}" from import "${t}". Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`),null}async function U(t,r,i){let o=a.resolve(r,t),e=await f.readFile(o,"utf-8"),s=a.dirname(o),n=await h(e),c=[];for(let l of n){let u=await k(l.importPath,s,r,l.componentName,i);if(!u)continue;let m=l.componentName.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();c.push({componentName:l.componentName,componentPath:u,name:l.name,key:m});}return c}async function N(t,r,i,o,e){let s=r.minify??o,n=r.outDir??"./dist/ui",c=r.serverConfig??{},l;if(r.globalCss){let u=a.resolve(i,r.globalCss);try{l=await f.readFile(u,"utf-8");}catch(m){e.warn(`[mcp-react-ui] globalCss file not found or unreadable: ${u} - ${m instanceof Error?m.message:m}`);}}for(let u of t){let I=`
import {a}from'./chunk-R7RJYHEX.js';import*as P from'esbuild';import*as f from'fs/promises';import*as l from'path';import {parse,AST_NODE_TYPES}from'@typescript-eslint/typescript-estree';async function h(t){let r=parse(t,{loc:true,range:true,jsx:true}),n=[],o=new Map;for(let e of r.body)if(e.type===AST_NODE_TYPES.ImportDeclaration){let i=e.source.value;for(let c of e.specifiers)if(c.type===AST_NODE_TYPES.ImportSpecifier){let s=c.local.name;o.set(s,i);}else if(c.type===AST_NODE_TYPES.ImportDefaultSpecifier){let s=c.local.name;o.set(s,i);}}return d(r,e=>{if(e.type===AST_NODE_TYPES.CallExpression&&e.callee.type===AST_NODE_TYPES.Identifier&&e.callee.name==="defineReactUI"){let i=S(e,o);i&&n.push(i);}}),n}function S(t,r){let n=t.arguments[0];if(n?.type!==AST_NODE_TYPES.ObjectExpression)return null;let o=null,e=null,i;for(let s of n.properties){if(s.type!==AST_NODE_TYPES.Property)continue;let u=s.key,a=u.type===AST_NODE_TYPES.Identifier?u.name:null;a&&(a==="component"?s.value.type===AST_NODE_TYPES.Identifier&&(o=s.value.name):a==="name"?s.value.type===AST_NODE_TYPES.Literal&&typeof s.value.value=="string"&&(e=s.value.value):a==="autoResize"&&s.value.type===AST_NODE_TYPES.Literal&&typeof s.value.value=="boolean"&&(i=s.value.value));}if(!o||!e)return null;let c=r.get(o);return c?{componentName:o,importPath:c,name:e,autoResize:i}:null}function d(t,r){if(Array.isArray(t)){for(let o of t)d(o,r);return}r(t);let n=t;for(let o of Object.keys(n)){let e=n[o];if(e&&typeof e=="object")if(Array.isArray(e))for(let i of e)i&&typeof i=="object"&&"type"in i&&d(i,r);else "type"in e&&d(e,r);}}var x={info:t=>{console.log(t);},warn:t=>{console.warn(t);},error:t=>{console.error(t);}},C={info:()=>{},warn:()=>{},error:()=>{}};function E(t){let r=t.replace(/\\/g,"/"),n=/^[a-zA-Z]:\//.test(r),o=r.startsWith("//");return r.startsWith(".")||r.startsWith("/")||n||o?r:`./${r}`}function k(t,r){let n=l.resolve(t),o=l.resolve(r),e=l.relative(n,o);return e===""?true:e===".."?false:!e.startsWith(`..${l.sep}`)&&!l.isAbsolute(e)}async function U(t,r,n,o,e){if(!t.startsWith("."))return null;let i=await f.realpath(n),c=l.resolve(r,t),s=l.extname(c)?[c]:[".tsx",".ts",".jsx",".js"].map(u=>c+u);for(let u of s){try{await f.access(u);}catch{continue}let a=await f.realpath(u);return k(i,a)?a:(e.warn(`[mcp-react-ui] Refusing to build UI component outside project root. component="${o}", import="${t}", resolved="${a}"`),null)}return e.warn(`[mcp-react-ui] Could not resolve component file for "${o}" from import "${t}". Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`),null}async function N(t,r,n){let o=l.resolve(r,t),e=await f.readFile(o,"utf-8"),i=l.dirname(o),c=await h(e),s=[];for(let u of c){let a=await U(u.importPath,i,r,u.componentName,n);if(!a)continue;let m=u.componentName.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();s.push({componentName:u.componentName,componentPath:a,name:u.name,key:m,autoResize:u.autoResize});}return s}async function $(t,r,n,o,e){let i=r.minify??o,c=r.outDir??"./dist/ui",s=r.serverConfig??{},u;if(r.globalCss){let a=l.resolve(n,r.globalCss);try{u=await f.readFile(a,"utf-8");}catch(m){e.warn(`[mcp-react-ui] globalCss file not found or unreadable: ${a} - ${m instanceof Error?m.message:m}`);}}for(let a$1 of t){let m=E(a$1.componentPath),R=a$1.autoResize===void 0?"":` autoResize={${a$1.autoResize}}`,b=`
import React from "react";
import { createRoot } from "react-dom/client";
import { AppsProvider } from "@mcp-apps-kit/ui-react";
import Component from "${C(u.componentPath)}";
import Component from "${m}";

@@ -12,3 +12,3 @@ const rootElement = document.getElementById("root");

<React.StrictMode>
<AppsProvider>
<AppsProvider${R}>
<Component />

@@ -19,3 +19,3 @@ </AppsProvider>

}
`,d=(await P.build({stdin:{contents:I,loader:"tsx",resolveDir:i,sourcefile:`${u.key}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:s,jsx:"automatic",jsxImportSource:"react",define:{"process.env.NODE_ENV":s?'"production"':'"development"',__MCP_SERVER_CONFIG__:JSON.stringify(c)}})).outputFiles?.[0]?.text;if(!d)throw new Error(`Failed to build UI: ${u.key}`);let b=a$1({key:u.key,name:u.name,script:d,css:l}),y=a.resolve(i,n,`${u.key}.html`);await f.mkdir(a.dirname(y),{recursive:true}),await f.writeFile(y,b,"utf-8"),e.info(`[mcp-react-ui] Built: ${u.key}.html`);}}function T(t){let r,i=t.standalone??false,o=t.logger===false?x:t.logger??S;return {name:"mcp-react-ui",configResolved(e){r=e;},async buildStart(){let e=r.root,s=r.mode==="production",n=await U(t.serverEntry,e,o);if(n.length===0){o.info("[mcp-react-ui] No defineReactUI calls found");return}o.info(`[mcp-react-ui] Found ${n.length} React UI(s): ${n.map(c=>c.componentName).join(", ")}`),await N(n,t,e,s,o);},resolveId(e){return i&&e==="virtual:mcp-react-ui-entry"?e:null},load(e){return i&&e==="virtual:mcp-react-ui-entry"?"export default {}":null},config(){if(i)return {build:{rollupOptions:{input:"virtual:mcp-react-ui-entry"}}}},generateBundle(e,s){if(!i)return;let n=Object.keys(s);for(let c of n)delete s[c];}}}var M=T;export{M as default,E as isPathWithinRoot,T as mcpReactUI,C as toEsbuildImportSpecifier};//# sourceMappingURL=vite-plugin.js.map
`,g=(await P.build({stdin:{contents:b,loader:"tsx",resolveDir:n,sourcefile:`${a$1.key}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:i,jsx:"automatic",jsxImportSource:"react",define:{"process.env.NODE_ENV":i?'"production"':'"development"',__MCP_SERVER_CONFIG__:JSON.stringify(s)}})).outputFiles?.[0]?.text;if(!g)throw new Error(`Failed to build UI: ${a$1.key}`);let I=a({key:a$1.key,name:a$1.name,script:g,css:u}),y=l.resolve(n,c,`${a$1.key}.html`);await f.mkdir(l.dirname(y),{recursive:true}),await f.writeFile(y,I,"utf-8"),e.info(`[mcp-react-ui] Built: ${a$1.key}.html`);}}function T(t){let r,n=t.standalone??false,o=t.logger===false?C:t.logger??x;return {name:"mcp-react-ui",configResolved(e){r=e;},async buildStart(){let e=r.root,i=r.mode==="production",c=await N(t.serverEntry,e,o);if(c.length===0){o.info("[mcp-react-ui] No defineReactUI calls found");return}o.info(`[mcp-react-ui] Found ${c.length} React UI(s): ${c.map(s=>s.componentName).join(", ")}`),await $(c,t,e,i,o);},resolveId(e){return n&&e==="virtual:mcp-react-ui-entry"?e:null},load(e){return n&&e==="virtual:mcp-react-ui-entry"?"export default {}":null},config(){if(n)return {build:{rollupOptions:{input:"virtual:mcp-react-ui-entry"}}}},generateBundle(e,i){if(!n)return;let c=Object.keys(i);for(let s of c)delete i[s];}}}var M=T;export{M as default,k as isPathWithinRoot,T as mcpReactUI,E as toEsbuildImportSpecifier};//# sourceMappingURL=vite-plugin.js.map
//# sourceMappingURL=vite-plugin.js.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/ast-parser.ts","../src/vite-plugin.ts"],"names":["parseReactUIDefinitions","content","ast","parse","results","importMap","node","AST_NODE_TYPES","importPath","specifier","localName","walkAST","parsed","parseDefineReactUICall","arg","componentName","uiName","prop","key","keyName","visitor","child","nodeRecord","value","item","defaultLogger","message","silentLogger","toEsbuildImportSpecifier","componentPath","normalized","isWindowsDriveAbsolute","isUncAbsolute","isPathWithinRoot","rootPath","candidatePath","resolvedRoot","resolvedCandidate","relative","resolveComponentPath","entryDir","rootDir","logger","rootRealPath","basePath","candidatePaths","ext","candidateRealPath","discoverReactUIs","serverEntry","root","entryPath","discovered","ui","buildDiscoveredUIs","options","isProduction","minify","outDir","serverConfig","globalCss","globalCssPath","error","entryCode","script","html","generateHTML","outputPath","mcpReactUI","config","standalone","resolvedConfig","d","id","_","bundle","keys","vite_plugin_default"],"mappings":"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","file":"vite-plugin.js","sourcesContent":["/**\n * AST-based parser for discovering defineReactUI calls\n *\n * Uses @typescript-eslint/typescript-estree for reliable TypeScript/TSX parsing.\n * This replaces the regex-based approach for more accurate import resolution.\n */\n\nimport { AST_NODE_TYPES, parse, type TSESTree } from \"@typescript-eslint/typescript-estree\";\n\n/**\n * Result of parsing a defineReactUI call\n */\nexport interface ParsedReactUI {\n /** Variable name used for the component */\n componentName: string;\n /** Import path for the component */\n importPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n}\n\n/**\n * Parse a TypeScript/TSX file and extract defineReactUI calls.\n *\n * @param content - File content to parse\n * @returns Array of parsed React UI definitions\n */\nexport async function parseReactUIDefinitions(content: string): Promise<ParsedReactUI[]> {\n const ast = parse(content, {\n loc: true,\n range: true,\n jsx: true,\n // Don't require a project - we just need syntax parsing\n });\n\n const results: ParsedReactUI[] = [];\n\n // Build import map: identifier -> import path\n const importMap = new Map<string, string>();\n\n for (const node of ast.body) {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n const importPath = node.source.value;\n\n for (const specifier of node.specifiers) {\n if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {\n // Named import: import { Foo } from \"./path\" or import { Foo as Bar } from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n } else if (specifier.type === AST_NODE_TYPES.ImportDefaultSpecifier) {\n // Default import: import Foo from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n }\n }\n }\n }\n\n // Walk the AST to find defineReactUI calls\n walkAST(ast, (node) => {\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier &&\n node.callee.name === \"defineReactUI\"\n ) {\n const parsed = parseDefineReactUICall(node, importMap);\n if (parsed) {\n results.push(parsed);\n }\n }\n });\n\n return results;\n}\n\n/**\n * Parse a defineReactUI call expression\n */\nfunction parseDefineReactUICall(\n node: TSESTree.CallExpression,\n importMap: Map<string, string>\n): ParsedReactUI | null {\n // First argument should be an object expression\n const arg = node.arguments[0];\n if (arg?.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n\n let componentName: string | null = null;\n let uiName: string | null = null;\n\n for (const prop of arg.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) continue;\n\n const key = prop.key;\n const keyName = key.type === AST_NODE_TYPES.Identifier ? key.name : null;\n if (!keyName) continue;\n\n if (keyName === \"component\") {\n // Extract component identifier\n if (prop.value.type === AST_NODE_TYPES.Identifier) {\n componentName = prop.value.name;\n }\n } else if (keyName === \"name\") {\n // Extract name string\n if (prop.value.type === AST_NODE_TYPES.Literal && typeof prop.value.value === \"string\") {\n uiName = prop.value.value;\n }\n }\n }\n\n if (!componentName || !uiName) {\n return null;\n }\n\n const importPath = importMap.get(componentName);\n if (!importPath) {\n return null;\n }\n\n return {\n componentName,\n importPath,\n name: uiName,\n };\n}\n\n/**\n * Simple AST walker\n */\nfunction walkAST(\n node: TSESTree.Node | TSESTree.Node[],\n visitor: (node: TSESTree.Node) => void\n): void {\n if (Array.isArray(node)) {\n for (const child of node) {\n walkAST(child, visitor);\n }\n return;\n }\n\n visitor(node);\n\n // Walk child nodes - cast to unknown first to avoid strict type checking\n const nodeRecord = node as unknown as Record<string, unknown>;\n for (const key of Object.keys(nodeRecord)) {\n const value = nodeRecord[key];\n if (value && typeof value === \"object\") {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n walkAST(item as TSESTree.Node, visitor);\n }\n }\n } else if (\"type\" in value) {\n walkAST(value as TSESTree.Node, visitor);\n }\n }\n }\n}\n","/**\n * Vite plugin for building React UI components\n *\n * This plugin automatically discovers `defineReactUI` calls in your source code,\n * resolves the component imports, and builds them into self-contained HTML files.\n *\n * Usage in vite.config.ts:\n * ```typescript\n * import { defineConfig } from \"vite\";\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * // Server entry point to scan for defineReactUI calls\n * serverEntry: \"./src/index.ts\",\n * // Output directory for built HTML files\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n *\n * Then in your server code:\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { GreetingWidget } from \"./ui/GreetingWidget\";\n *\n * const greetTool = defineTool({\n * ui: defineReactUI({\n * component: GreetingWidget,\n * name: \"Greeting Widget\",\n * }),\n * // ...\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig } from \"vite\";\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { generateHTML } from \"./html\";\nimport { parseReactUIDefinitions } from \"./ast-parser\";\n\n/**\n * Logger interface for the MCP React UI plugin.\n */\nexport interface PluginLogger {\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\n\n/**\n * Default logger that uses console methods with a prefix.\n */\nconst defaultLogger: PluginLogger = {\n info: (message: string) => {\n console.log(message); // eslint-disable-line no-console\n },\n warn: (message: string) => {\n console.warn(message); // eslint-disable-line no-console\n },\n error: (message: string) => {\n console.error(message); // eslint-disable-line no-console\n },\n};\n\n/**\n * Silent logger that does nothing.\n */\nconst silentLogger: PluginLogger = {\n info: () => {\n // Intentionally empty - silent logger\n },\n warn: () => {\n // Intentionally empty - silent logger\n },\n error: () => {\n // Intentionally empty - silent logger\n },\n};\n\n/**\n * Server configuration injected into UIs at build time.\n *\n * These values are available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n */\nexport type McpServerConfig = {\n /**\n * Base URL of the MCP server.\n *\n * Used by UIs to make API calls (e.g., debug logging via HTTP).\n * Should include protocol and port (e.g., \"http://localhost:3000\").\n *\n * @example \"http://localhost:3000\"\n * @example \"https://api.myapp.com\"\n */\n baseUrl?: string;\n\n /**\n * Additional custom configuration.\n *\n * Any extra values your UI needs at runtime.\n */\n [key: string]: unknown;\n};\n\n/**\n * Options for the MCP React UI Vite plugin.\n */\nexport interface McpReactUIOptions {\n /**\n * Server entry point file to scan for defineReactUI calls.\n * The plugin will parse this file and find all defineReactUI usages,\n * then resolve the component imports to their source files.\n *\n * @example \"./src/index.ts\"\n */\n serverEntry: string;\n\n /**\n * Output directory for built HTML files.\n * @default \"./dist/ui\"\n */\n outDir?: string;\n\n /**\n * Whether to minify the output.\n * Defaults to true in production, false in development.\n */\n minify?: boolean;\n\n /**\n * Path to global CSS file to include in all UIs.\n */\n globalCss?: string;\n\n /**\n * Custom logger for plugin output.\n * Set to `false` to disable all logging, or provide a custom logger.\n * @default console\n */\n logger?: PluginLogger | false;\n\n /**\n * Standalone mode takes over the Vite build.\n *\n * - When `true`, the plugin overrides the build input and removes all Vite outputs,\n * producing only the generated UI HTML files.\n * - When `false` (default), the plugin is additive: it generates UI HTML files\n * without modifying the main Vite build inputs/outputs.\n *\n * Use `true` when your Vite config exists solely to build MCP UI HTML.\n */\n standalone?: boolean;\n\n /**\n * Server configuration to inject into UIs at build time.\n *\n * These values become available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n * Useful for injecting the server base URL, API endpoints, or other runtime config.\n *\n * @example\n * ```typescript\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * serverConfig: {\n * baseUrl: \"http://localhost:3000\",\n * },\n * })\n * ```\n */\n serverConfig?: McpServerConfig;\n}\n\n/**\n * Information about a discovered React UI definition.\n */\ninterface DiscoveredUI {\n /** Variable name used for the component */\n componentName: string;\n /** Resolved file path to the component */\n componentPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n /** Generated key for output file */\n key: string;\n}\n\n/**\n * Convert a filesystem path to an import specifier suitable for esbuild.\n *\n * esbuild accepts absolute paths as specifiers (e.g. \"/abs/file.tsx\", \"C:/abs/file.tsx\").\n * For relative-like paths, we prefix with \"./\".\n *\n * @internal\n */\nexport function toEsbuildImportSpecifier(componentPath: string): string {\n // Normalize path for ESM imports (Windows backslashes -> forward slashes)\n const normalized = componentPath.replace(/\\\\/g, \"/\");\n\n // Absolute path forms we must not prefix with \"./\":\n // - POSIX absolute: /...\n // - Windows drive absolute: C:/...\n // - UNC absolute: //server/share/...\n const isWindowsDriveAbsolute = /^[a-zA-Z]:\\//.test(normalized);\n const isUncAbsolute = normalized.startsWith(\"//\");\n\n if (\n normalized.startsWith(\".\") ||\n normalized.startsWith(\"/\") ||\n isWindowsDriveAbsolute ||\n isUncAbsolute\n ) {\n return normalized;\n }\n\n return `./${normalized}`;\n}\n\n/**\n * Checks whether `candidatePath` is within `rootPath`.\n *\n * Both inputs may be relative; they will be resolved before comparison.\n *\n * @internal\n */\nexport function isPathWithinRoot(rootPath: string, candidatePath: string): boolean {\n const resolvedRoot = path.resolve(rootPath);\n const resolvedCandidate = path.resolve(candidatePath);\n\n const relative = path.relative(resolvedRoot, resolvedCandidate);\n if (relative === \"\") return true;\n if (relative === \"..\") return false;\n\n return !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * Resolve import path to actual file path with extension.\n */\nasync function resolveComponentPath(\n importPath: string,\n entryDir: string,\n rootDir: string,\n componentName: string,\n logger: PluginLogger\n): Promise<string | null> {\n if (!importPath.startsWith(\".\")) {\n // Package import - skip\n return null;\n }\n\n const rootRealPath = await fs.realpath(rootDir);\n const basePath = path.resolve(entryDir, importPath);\n\n const candidatePaths = path.extname(basePath)\n ? [basePath]\n : [\".tsx\", \".ts\", \".jsx\", \".js\"].map((ext) => basePath + ext);\n\n for (const candidatePath of candidatePaths) {\n try {\n await fs.access(candidatePath);\n } catch {\n continue;\n }\n\n // Resolve symlinks before boundary check.\n const candidateRealPath = await fs.realpath(candidatePath);\n if (!isPathWithinRoot(rootRealPath, candidateRealPath)) {\n logger.warn(\n `[mcp-react-ui] Refusing to build UI component outside project root. ` +\n `component=\"${componentName}\", import=\"${importPath}\", resolved=\"${candidateRealPath}\"`\n );\n return null;\n }\n\n return candidateRealPath;\n }\n\n logger.warn(\n `[mcp-react-ui] Could not resolve component file for \"${componentName}\" from import \"${importPath}\". ` +\n `Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`\n );\n return null;\n}\n\n/**\n * Scan source file for defineReactUI calls and extract component information.\n * Uses AST parsing for reliable detection of imports and defineReactUI calls.\n */\nasync function discoverReactUIs(\n serverEntry: string,\n root: string,\n logger: PluginLogger\n): Promise<DiscoveredUI[]> {\n const entryPath = path.resolve(root, serverEntry);\n const content = await fs.readFile(entryPath, \"utf-8\");\n const entryDir = path.dirname(entryPath);\n\n const parsed = await parseReactUIDefinitions(content);\n const discovered: DiscoveredUI[] = [];\n\n for (const ui of parsed) {\n const componentPath = await resolveComponentPath(\n ui.importPath,\n entryDir,\n root,\n ui.componentName,\n logger\n );\n if (!componentPath) continue;\n\n const key = ui.componentName.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n discovered.push({\n componentName: ui.componentName,\n componentPath,\n name: ui.name,\n key,\n });\n }\n\n return discovered;\n}\n\n/**\n * Build discovered React UI components.\n */\nasync function buildDiscoveredUIs(\n discovered: DiscoveredUI[],\n options: McpReactUIOptions,\n root: string,\n isProduction: boolean,\n logger: PluginLogger\n): Promise<void> {\n const minify = options.minify ?? isProduction;\n const outDir = options.outDir ?? \"./dist/ui\";\n const serverConfig = options.serverConfig ?? {};\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n const globalCssPath = path.resolve(root, options.globalCss);\n try {\n globalCss = await fs.readFile(globalCssPath, \"utf-8\");\n } catch (error) {\n logger.warn(\n `[mcp-react-ui] globalCss file not found or unreadable: ${globalCssPath} - ${\n error instanceof Error ? error.message : error\n }`\n );\n }\n }\n\n // Build each discovered UI\n for (const ui of discovered) {\n const importPath = toEsbuildImportSpecifier(ui.componentPath);\n\n // Generate entry point code\n const entryCode = `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\nimport Component from \"${importPath}\";\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider>\n <Component />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n\n // Bundle with esbuild\n const result = await esbuild.build({\n stdin: {\n contents: entryCode,\n loader: \"tsx\",\n resolveDir: root,\n sourcefile: `${ui.key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n define: {\n \"process.env.NODE_ENV\": minify ? '\"production\"' : '\"development\"',\n __MCP_SERVER_CONFIG__: JSON.stringify(serverConfig),\n },\n });\n\n const script = result.outputFiles?.[0]?.text;\n if (!script) {\n throw new Error(`Failed to build UI: ${ui.key}`);\n }\n\n // Generate HTML\n const html = generateHTML({\n key: ui.key,\n name: ui.name,\n script,\n css: globalCss,\n });\n\n // Write output file\n const outputPath = path.resolve(root, outDir, `${ui.key}.html`);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, html, \"utf-8\");\n\n logger.info(`[mcp-react-ui] Built: ${ui.key}.html`);\n }\n}\n\n/**\n * Vite plugin that automatically discovers and builds React UI components.\n *\n * This plugin scans your server entry point for `defineReactUI` calls,\n * resolves the component imports, and builds them into self-contained HTML.\n *\n * @param options - Plugin configuration\n * @returns Vite plugin\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n */\nexport function mcpReactUI(options: McpReactUIOptions): Plugin {\n let config: ResolvedConfig;\n\n const standalone = options.standalone ?? false;\n\n // Resolve logger: false = silent, undefined = default, custom = use provided\n const logger: PluginLogger =\n options.logger === false ? silentLogger : (options.logger ?? defaultLogger);\n\n return {\n name: \"mcp-react-ui\",\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n\n // Run build at the start of the build process\n async buildStart() {\n const root = config.root;\n const isProduction = config.mode === \"production\";\n\n // Discover React UIs from server entry\n const discovered = await discoverReactUIs(options.serverEntry, root, logger);\n\n if (discovered.length === 0) {\n logger.info(\"[mcp-react-ui] No defineReactUI calls found\");\n return;\n }\n\n logger.info(\n `[mcp-react-ui] Found ${discovered.length} React UI(s): ${discovered.map((d) => d.componentName).join(\", \")}`\n );\n\n // Build discovered UIs\n await buildDiscoveredUIs(discovered, options, root, isProduction, logger);\n },\n\n // Provide a virtual empty module so Vite doesn't complain about missing entry\n resolveId(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return id;\n }\n return null;\n },\n\n load(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return \"export default {}\";\n }\n return null;\n },\n\n // Override the config to use our virtual entry\n config() {\n if (!standalone) {\n return undefined;\n }\n\n return {\n build: {\n rollupOptions: {\n input: \"virtual:mcp-react-ui-entry\",\n },\n },\n };\n },\n\n // Standalone mode: prevent Vite from generating output files (we already wrote our HTML)\n generateBundle(_, bundle) {\n if (!standalone) {\n return;\n }\n\n // Remove all generated chunks since we don't need them\n const keys = Object.keys(bundle);\n for (const key of keys) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete bundle[key];\n }\n },\n };\n}\n\nexport default mcpReactUI;\n"]}
{"version":3,"sources":["../src/ast-parser.ts","../src/vite-plugin.ts"],"names":["parseReactUIDefinitions","content","ast","parse","results","importMap","node","AST_NODE_TYPES","importPath","specifier","localName","walkAST","parsed","parseDefineReactUICall","arg","componentName","uiName","autoResize","prop","key","keyName","visitor","child","nodeRecord","value","item","defaultLogger","message","silentLogger","toEsbuildImportSpecifier","componentPath","normalized","isWindowsDriveAbsolute","isUncAbsolute","isPathWithinRoot","rootPath","candidatePath","resolvedRoot","resolvedCandidate","relative","resolveComponentPath","entryDir","rootDir","logger","rootRealPath","basePath","candidatePaths","ext","candidateRealPath","discoverReactUIs","serverEntry","root","entryPath","discovered","ui","buildDiscoveredUIs","options","isProduction","minify","outDir","serverConfig","globalCss","globalCssPath","error","providerProps","entryCode","script","html","generateHTML","outputPath","mcpReactUI","config","standalone","resolvedConfig","d","id","_","bundle","keys","vite_plugin_default"],"mappings":"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","file":"vite-plugin.js","sourcesContent":["/**\n * AST-based parser for discovering defineReactUI calls\n *\n * Uses @typescript-eslint/typescript-estree for reliable TypeScript/TSX parsing.\n * This replaces the regex-based approach for more accurate import resolution.\n */\n\nimport { AST_NODE_TYPES, parse, type TSESTree } from \"@typescript-eslint/typescript-estree\";\n\n/**\n * Result of parsing a defineReactUI call\n */\nexport interface ParsedReactUI {\n /** Variable name used for the component */\n componentName: string;\n /** Import path for the component */\n importPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n /** Whether auto-resize is enabled (undefined means default/true) */\n autoResize?: boolean;\n}\n\n/**\n * Parse a TypeScript/TSX file and extract defineReactUI calls.\n *\n * @param content - File content to parse\n * @returns Array of parsed React UI definitions\n */\nexport async function parseReactUIDefinitions(content: string): Promise<ParsedReactUI[]> {\n const ast = parse(content, {\n loc: true,\n range: true,\n jsx: true,\n // Don't require a project - we just need syntax parsing\n });\n\n const results: ParsedReactUI[] = [];\n\n // Build import map: identifier -> import path\n const importMap = new Map<string, string>();\n\n for (const node of ast.body) {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n const importPath = node.source.value;\n\n for (const specifier of node.specifiers) {\n if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {\n // Named import: import { Foo } from \"./path\" or import { Foo as Bar } from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n } else if (specifier.type === AST_NODE_TYPES.ImportDefaultSpecifier) {\n // Default import: import Foo from \"./path\"\n const localName = specifier.local.name;\n importMap.set(localName, importPath);\n }\n }\n }\n }\n\n // Walk the AST to find defineReactUI calls\n walkAST(ast, (node) => {\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier &&\n node.callee.name === \"defineReactUI\"\n ) {\n const parsed = parseDefineReactUICall(node, importMap);\n if (parsed) {\n results.push(parsed);\n }\n }\n });\n\n return results;\n}\n\n/**\n * Parse a defineReactUI call expression\n */\nfunction parseDefineReactUICall(\n node: TSESTree.CallExpression,\n importMap: Map<string, string>\n): ParsedReactUI | null {\n // First argument should be an object expression\n const arg = node.arguments[0];\n if (arg?.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n\n let componentName: string | null = null;\n let uiName: string | null = null;\n let autoResize: boolean | undefined = undefined;\n\n for (const prop of arg.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) continue;\n\n const key = prop.key;\n const keyName = key.type === AST_NODE_TYPES.Identifier ? key.name : null;\n if (!keyName) continue;\n\n if (keyName === \"component\") {\n // Extract component identifier\n if (prop.value.type === AST_NODE_TYPES.Identifier) {\n componentName = prop.value.name;\n }\n } else if (keyName === \"name\") {\n // Extract name string\n if (prop.value.type === AST_NODE_TYPES.Literal && typeof prop.value.value === \"string\") {\n uiName = prop.value.value;\n }\n } else if (keyName === \"autoResize\") {\n // Extract autoResize boolean\n if (prop.value.type === AST_NODE_TYPES.Literal && typeof prop.value.value === \"boolean\") {\n autoResize = prop.value.value;\n }\n }\n }\n\n if (!componentName || !uiName) {\n return null;\n }\n\n const importPath = importMap.get(componentName);\n if (!importPath) {\n return null;\n }\n\n return {\n componentName,\n importPath,\n name: uiName,\n autoResize,\n };\n}\n\n/**\n * Simple AST walker\n */\nfunction walkAST(\n node: TSESTree.Node | TSESTree.Node[],\n visitor: (node: TSESTree.Node) => void\n): void {\n if (Array.isArray(node)) {\n for (const child of node) {\n walkAST(child, visitor);\n }\n return;\n }\n\n visitor(node);\n\n // Walk child nodes - cast to unknown first to avoid strict type checking\n const nodeRecord = node as unknown as Record<string, unknown>;\n for (const key of Object.keys(nodeRecord)) {\n const value = nodeRecord[key];\n if (value && typeof value === \"object\") {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n walkAST(item as TSESTree.Node, visitor);\n }\n }\n } else if (\"type\" in value) {\n walkAST(value as TSESTree.Node, visitor);\n }\n }\n }\n}\n","/**\n * Vite plugin for building React UI components\n *\n * This plugin automatically discovers `defineReactUI` calls in your source code,\n * resolves the component imports, and builds them into self-contained HTML files.\n *\n * Usage in vite.config.ts:\n * ```typescript\n * import { defineConfig } from \"vite\";\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * // Server entry point to scan for defineReactUI calls\n * serverEntry: \"./src/index.ts\",\n * // Output directory for built HTML files\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n *\n * Then in your server code:\n * ```typescript\n * import { defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n * import { GreetingWidget } from \"./ui/GreetingWidget\";\n *\n * const greetTool = defineTool({\n * ui: defineReactUI({\n * component: GreetingWidget,\n * name: \"Greeting Widget\",\n * }),\n * // ...\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig } from \"vite\";\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { generateHTML } from \"./html\";\nimport { parseReactUIDefinitions } from \"./ast-parser\";\n\n/**\n * Logger interface for the MCP React UI plugin.\n */\nexport interface PluginLogger {\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\n\n/**\n * Default logger that uses console methods with a prefix.\n */\nconst defaultLogger: PluginLogger = {\n info: (message: string) => {\n console.log(message); // eslint-disable-line no-console\n },\n warn: (message: string) => {\n console.warn(message); // eslint-disable-line no-console\n },\n error: (message: string) => {\n console.error(message); // eslint-disable-line no-console\n },\n};\n\n/**\n * Silent logger that does nothing.\n */\nconst silentLogger: PluginLogger = {\n info: () => {\n // Intentionally empty - silent logger\n },\n warn: () => {\n // Intentionally empty - silent logger\n },\n error: () => {\n // Intentionally empty - silent logger\n },\n};\n\n/**\n * Server configuration injected into UIs at build time.\n *\n * These values are available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n */\nexport type McpServerConfig = {\n /**\n * Base URL of the MCP server.\n *\n * Used by UIs to make API calls (e.g., debug logging via HTTP).\n * Should include protocol and port (e.g., \"http://localhost:3000\").\n *\n * @example \"http://localhost:3000\"\n * @example \"https://api.myapp.com\"\n */\n baseUrl?: string;\n\n /**\n * Additional custom configuration.\n *\n * Any extra values your UI needs at runtime.\n */\n [key: string]: unknown;\n};\n\n/**\n * Options for the MCP React UI Vite plugin.\n */\nexport interface McpReactUIOptions {\n /**\n * Server entry point file to scan for defineReactUI calls.\n * The plugin will parse this file and find all defineReactUI usages,\n * then resolve the component imports to their source files.\n *\n * @example \"./src/index.ts\"\n */\n serverEntry: string;\n\n /**\n * Output directory for built HTML files.\n * @default \"./dist/ui\"\n */\n outDir?: string;\n\n /**\n * Whether to minify the output.\n * Defaults to true in production, false in development.\n */\n minify?: boolean;\n\n /**\n * Path to global CSS file to include in all UIs.\n */\n globalCss?: string;\n\n /**\n * Custom logger for plugin output.\n * Set to `false` to disable all logging, or provide a custom logger.\n * @default console\n */\n logger?: PluginLogger | false;\n\n /**\n * Standalone mode takes over the Vite build.\n *\n * - When `true`, the plugin overrides the build input and removes all Vite outputs,\n * producing only the generated UI HTML files.\n * - When `false` (default), the plugin is additive: it generates UI HTML files\n * without modifying the main Vite build inputs/outputs.\n *\n * Use `true` when your Vite config exists solely to build MCP UI HTML.\n */\n standalone?: boolean;\n\n /**\n * Server configuration to inject into UIs at build time.\n *\n * These values become available in the UI via `getMcpServerConfig()` from @mcp-apps-kit/ui.\n * Useful for injecting the server base URL, API endpoints, or other runtime config.\n *\n * @example\n * ```typescript\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * serverConfig: {\n * baseUrl: \"http://localhost:3000\",\n * },\n * })\n * ```\n */\n serverConfig?: McpServerConfig;\n}\n\n/**\n * Information about a discovered React UI definition.\n */\ninterface DiscoveredUI {\n /** Variable name used for the component */\n componentName: string;\n /** Resolved file path to the component */\n componentPath: string;\n /** UI name from the defineReactUI call */\n name: string;\n /** Generated key for output file */\n key: string;\n /** Whether auto-resize is enabled (undefined means default/true) */\n autoResize?: boolean;\n}\n\n/**\n * Convert a filesystem path to an import specifier suitable for esbuild.\n *\n * esbuild accepts absolute paths as specifiers (e.g. \"/abs/file.tsx\", \"C:/abs/file.tsx\").\n * For relative-like paths, we prefix with \"./\".\n *\n * @internal\n */\nexport function toEsbuildImportSpecifier(componentPath: string): string {\n // Normalize path for ESM imports (Windows backslashes -> forward slashes)\n const normalized = componentPath.replace(/\\\\/g, \"/\");\n\n // Absolute path forms we must not prefix with \"./\":\n // - POSIX absolute: /...\n // - Windows drive absolute: C:/...\n // - UNC absolute: //server/share/...\n const isWindowsDriveAbsolute = /^[a-zA-Z]:\\//.test(normalized);\n const isUncAbsolute = normalized.startsWith(\"//\");\n\n if (\n normalized.startsWith(\".\") ||\n normalized.startsWith(\"/\") ||\n isWindowsDriveAbsolute ||\n isUncAbsolute\n ) {\n return normalized;\n }\n\n return `./${normalized}`;\n}\n\n/**\n * Checks whether `candidatePath` is within `rootPath`.\n *\n * Both inputs may be relative; they will be resolved before comparison.\n *\n * @internal\n */\nexport function isPathWithinRoot(rootPath: string, candidatePath: string): boolean {\n const resolvedRoot = path.resolve(rootPath);\n const resolvedCandidate = path.resolve(candidatePath);\n\n const relative = path.relative(resolvedRoot, resolvedCandidate);\n if (relative === \"\") return true;\n if (relative === \"..\") return false;\n\n return !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\n/**\n * Resolve import path to actual file path with extension.\n */\nasync function resolveComponentPath(\n importPath: string,\n entryDir: string,\n rootDir: string,\n componentName: string,\n logger: PluginLogger\n): Promise<string | null> {\n if (!importPath.startsWith(\".\")) {\n // Package import - skip\n return null;\n }\n\n const rootRealPath = await fs.realpath(rootDir);\n const basePath = path.resolve(entryDir, importPath);\n\n const candidatePaths = path.extname(basePath)\n ? [basePath]\n : [\".tsx\", \".ts\", \".jsx\", \".js\"].map((ext) => basePath + ext);\n\n for (const candidatePath of candidatePaths) {\n try {\n await fs.access(candidatePath);\n } catch {\n continue;\n }\n\n // Resolve symlinks before boundary check.\n const candidateRealPath = await fs.realpath(candidatePath);\n if (!isPathWithinRoot(rootRealPath, candidateRealPath)) {\n logger.warn(\n `[mcp-react-ui] Refusing to build UI component outside project root. ` +\n `component=\"${componentName}\", import=\"${importPath}\", resolved=\"${candidateRealPath}\"`\n );\n return null;\n }\n\n return candidateRealPath;\n }\n\n logger.warn(\n `[mcp-react-ui] Could not resolve component file for \"${componentName}\" from import \"${importPath}\". ` +\n `Tried extensions: .tsx, .ts, .jsx, .js. Skipping this component.`\n );\n return null;\n}\n\n/**\n * Scan source file for defineReactUI calls and extract component information.\n * Uses AST parsing for reliable detection of imports and defineReactUI calls.\n */\nasync function discoverReactUIs(\n serverEntry: string,\n root: string,\n logger: PluginLogger\n): Promise<DiscoveredUI[]> {\n const entryPath = path.resolve(root, serverEntry);\n const content = await fs.readFile(entryPath, \"utf-8\");\n const entryDir = path.dirname(entryPath);\n\n const parsed = await parseReactUIDefinitions(content);\n const discovered: DiscoveredUI[] = [];\n\n for (const ui of parsed) {\n const componentPath = await resolveComponentPath(\n ui.importPath,\n entryDir,\n root,\n ui.componentName,\n logger\n );\n if (!componentPath) continue;\n\n const key = ui.componentName.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n discovered.push({\n componentName: ui.componentName,\n componentPath,\n name: ui.name,\n key,\n autoResize: ui.autoResize,\n });\n }\n\n return discovered;\n}\n\n/**\n * Build discovered React UI components.\n */\nasync function buildDiscoveredUIs(\n discovered: DiscoveredUI[],\n options: McpReactUIOptions,\n root: string,\n isProduction: boolean,\n logger: PluginLogger\n): Promise<void> {\n const minify = options.minify ?? isProduction;\n const outDir = options.outDir ?? \"./dist/ui\";\n const serverConfig = options.serverConfig ?? {};\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n const globalCssPath = path.resolve(root, options.globalCss);\n try {\n globalCss = await fs.readFile(globalCssPath, \"utf-8\");\n } catch (error) {\n logger.warn(\n `[mcp-react-ui] globalCss file not found or unreadable: ${globalCssPath} - ${\n error instanceof Error ? error.message : error\n }`\n );\n }\n }\n\n // Build each discovered UI\n for (const ui of discovered) {\n const importPath = toEsbuildImportSpecifier(ui.componentPath);\n\n // Generate AppsProvider props based on autoResize setting\n const providerProps = ui.autoResize === undefined ? \"\" : ` autoResize={${ui.autoResize}}`;\n\n // Generate entry point code\n const entryCode = `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\nimport Component from \"${importPath}\";\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider${providerProps}>\n <Component />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n\n // Bundle with esbuild\n const result = await esbuild.build({\n stdin: {\n contents: entryCode,\n loader: \"tsx\",\n resolveDir: root,\n sourcefile: `${ui.key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n define: {\n \"process.env.NODE_ENV\": minify ? '\"production\"' : '\"development\"',\n __MCP_SERVER_CONFIG__: JSON.stringify(serverConfig),\n },\n });\n\n const script = result.outputFiles?.[0]?.text;\n if (!script) {\n throw new Error(`Failed to build UI: ${ui.key}`);\n }\n\n // Generate HTML\n const html = generateHTML({\n key: ui.key,\n name: ui.name,\n script,\n css: globalCss,\n });\n\n // Write output file\n const outputPath = path.resolve(root, outDir, `${ui.key}.html`);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, html, \"utf-8\");\n\n logger.info(`[mcp-react-ui] Built: ${ui.key}.html`);\n }\n}\n\n/**\n * Vite plugin that automatically discovers and builds React UI components.\n *\n * This plugin scans your server entry point for `defineReactUI` calls,\n * resolves the component imports, and builds them into self-contained HTML.\n *\n * @param options - Plugin configuration\n * @returns Vite plugin\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [\n * mcpReactUI({\n * serverEntry: \"./src/index.ts\",\n * outDir: \"./src/ui/dist\",\n * }),\n * ],\n * });\n * ```\n */\nexport function mcpReactUI(options: McpReactUIOptions): Plugin {\n let config: ResolvedConfig;\n\n const standalone = options.standalone ?? false;\n\n // Resolve logger: false = silent, undefined = default, custom = use provided\n const logger: PluginLogger =\n options.logger === false ? silentLogger : (options.logger ?? defaultLogger);\n\n return {\n name: \"mcp-react-ui\",\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n },\n\n // Run build at the start of the build process\n async buildStart() {\n const root = config.root;\n const isProduction = config.mode === \"production\";\n\n // Discover React UIs from server entry\n const discovered = await discoverReactUIs(options.serverEntry, root, logger);\n\n if (discovered.length === 0) {\n logger.info(\"[mcp-react-ui] No defineReactUI calls found\");\n return;\n }\n\n logger.info(\n `[mcp-react-ui] Found ${discovered.length} React UI(s): ${discovered.map((d) => d.componentName).join(\", \")}`\n );\n\n // Build discovered UIs\n await buildDiscoveredUIs(discovered, options, root, isProduction, logger);\n },\n\n // Provide a virtual empty module so Vite doesn't complain about missing entry\n resolveId(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return id;\n }\n return null;\n },\n\n load(id) {\n if (standalone && id === \"virtual:mcp-react-ui-entry\") {\n return \"export default {}\";\n }\n return null;\n },\n\n // Override the config to use our virtual entry\n config() {\n if (!standalone) {\n return undefined;\n }\n\n return {\n build: {\n rollupOptions: {\n input: \"virtual:mcp-react-ui-entry\",\n },\n },\n };\n },\n\n // Standalone mode: prevent Vite from generating output files (we already wrote our HTML)\n generateBundle(_, bundle) {\n if (!standalone) {\n return;\n }\n\n // Remove all generated chunks since we don't need them\n const keys = Object.keys(bundle);\n for (const key of keys) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete bundle[key];\n }\n },\n };\n}\n\nexport default mcpReactUI;\n"]}
{
"name": "@mcp-apps-kit/ui-react-builder",
"version": "0.3.0",
"version": "0.4.0",
"description": "Build tool for React-based MCP application UIs",

@@ -62,4 +62,4 @@ "type": "module",

"peerDependencies": {
"@mcp-apps-kit/core": "^0.3.0",
"@mcp-apps-kit/ui-react": "^0.3.0",
"@mcp-apps-kit/core": "^0.4.0",
"@mcp-apps-kit/ui-react": "^0.4.0",
"react": "^18.0.0 || ^19.0.0",

@@ -66,0 +66,0 @@ "react-dom": "^18.0.0 || ^19.0.0",

@@ -7,3 +7,3 @@ # @mcp-apps-kit/ui-react-builder

`@mcp-apps-kit/ui-react-builder` allows you to define UI resources using React components instead of pre-built HTML files. The framework handles bundling React, ReactDOM, and `@mcp-apps-kit/ui-react` into self-contained HTML that works with both MCP Apps (Claude Desktop) and ChatGPT.
`@mcp-apps-kit/ui-react-builder` allows you to define UI resources using React components instead of pre-built HTML files. The framework handles bundling React, ReactDOM, and `@mcp-apps-kit/ui-react` into self-contained HTML that works with both MCP Apps and ChatGPT.

@@ -96,2 +96,4 @@ ## Table of Contents

prefersBorder: true,
// Optional: Disable automatic size notifications (default: true)
// autoResize: false,
}),

@@ -194,2 +196,13 @@ handler: async ({ name }) => ({

#### `defineReactUI` Options
| Option | Type | Default | Description |
| --------------- | --------------- | ---------- | ------------------------------------------------------------------------------------------- |
| `component` | `ComponentType` | (required) | React component to render |
| `name` | `string` | (required) | Display name for the UI |
| `description` | `string` | - | Description of the UI widget |
| `prefersBorder` | `boolean` | - | Hint to the host whether a border should be drawn |
| `autoResize` | `boolean` | `true` | Enable automatic size change notifications. Only supported in MCP Apps; ignored in ChatGPT. |
| `csp` | `CSPConfig` | - | Content Security Policy configuration (ChatGPT only) |
### Types

@@ -196,0 +209,0 @@

export{b as buildReactUI,a as buildReactUIs}from'./chunk-5WFQIJJW.js';import'./chunk-6JS3KVIH.js';//# sourceMappingURL=build-ZF3MI5NJ.js.map
//# sourceMappingURL=build-ZF3MI5NJ.js.map
{"version":3,"sources":[],"names":[],"mappings":"","file":"build-ZF3MI5NJ.js"}
import {b as b$1,a}from'./chunk-6JS3KVIH.js';import*as w from'esbuild';import*as u from'fs/promises';import*as d from'path';async function C(s,t={}){let e=Date.now(),n=new Map,o=new Map,i=[],c=[],r=t.cwd??process.cwd();t.outDir&&await u.mkdir(d.resolve(r,t.outDir),{recursive:true});let f;if(t.globalCss)try{f=await u.readFile(d.resolve(r,t.globalCss),"utf-8");}catch(a){i.push(`Could not load global CSS from ${t.globalCss}: ${a instanceof Error?a.message:String(a)}`);}for(let[a,p]of Object.entries(s))try{let l=await b(a,p,{...t,cwd:r,globalCss:f});if(n.set(a,l),t.outDir){let m=d.resolve(r,t.outDir,`${a}.html`);await u.writeFile(m,l,"utf-8"),o.set(a,m);}}catch(l){let m={key:a,message:l instanceof Error?l.message:String(l),stack:l instanceof Error?l.stack:void 0};c.push(m);}return {outputs:n,files:o,duration:Date.now()-e,warnings:i,errors:c}}async function b(s,t,e){let n=t.__component,o=n.name||"Component",i=t.__defaultProps,c=b$1("__COMPONENT_PLACEHOLDER__",i),r=[y(n,o),E()],f=await w.build({stdin:{contents:c,loader:"tsx",resolveDir:e.cwd,sourcefile:`${s}-entry.tsx`},bundle:true,write:false,format:"esm",platform:"browser",target:["es2020","chrome90","firefox90","safari14"],minify:e.minify??true,sourcemap:e.sourcemap?"inline":false,jsx:"automatic",jsxImportSource:"react",logLevel:"warning",external:e.external,plugins:r,define:{"process.env.NODE_ENV":e.minify?'"production"':'"development"'}}),a$1=f.outputFiles?.[0];if(!a$1)throw new Error(`No output generated for UI: ${s}`);let p=a$1.text;return f.warnings,a({key:s,name:t.name??s,script:p,css:e.globalCss})}function y(s,t){return {name:"mcp-component-resolver",setup(e){e.onResolve({filter:/__COMPONENT_PLACEHOLDER__/},()=>({path:"__COMPONENT__",namespace:"mcp-component"})),e.onLoad({filter:/.*/,namespace:"mcp-component"},()=>{let n=s.toString(),o=/^\s*class\b/.test(n),i=/^\s*function\b/.test(n),c=!o&&!i,r;return c?r=`
import React from "react";
const ${t} = ${n};
export default ${t};
`:r=`
import React from "react";
${n}
export default ${t};
`,{contents:r,loader:"tsx"}});}}}function E(){return {name:"mcp-css-handler",setup(s){s.onLoad({filter:/\.css$/},async t=>{if(t.path.endsWith(".module.css"))return null;let e=await u.readFile(t.path,"utf-8");return {contents:`
const style = document.createElement("style");
style.textContent = ${JSON.stringify(e)};
document.head.appendChild(style);
`,loader:"js"}}),s.onLoad({filter:/\.module\.css$/},async t=>{let e=await u.readFile(t.path,"utf-8"),n=_(e),o=Object.fromEntries(n.map(r=>[r,`${r}_${x(t.path)}`])),i=e;for(let[r,f]of Object.entries(o))i=i.replace(new RegExp(`\\.${r}\\b`,"g"),`.${f}`);return {contents:`
const style = document.createElement("style");
style.textContent = ${JSON.stringify(i)};
document.head.appendChild(style);
export default ${JSON.stringify(o)};
`,loader:"js"}});}}}function _(s){let t=/\.([a-zA-Z_][a-zA-Z0-9_-]*)/g,e=new Set,n;for(;(n=t.exec(s))!==null;)n[1]&&e.add(n[1]);return Array.from(e)}function x(s){let t=0;for(let e=0;e<s.length;e++){let n=s.charCodeAt(e);t=(t<<5)-t+n,t=t&t;}return Math.abs(t).toString(36).substring(0,5)}async function O(s,t,e={}){let n=await C({[s]:t},e),o=n.outputs.get(s);if(!o){let i=n.errors.find(c=>c.key===s);throw new Error(i?.message??`Failed to build UI: ${s}`)}return o}export{C as a,O as b};//# sourceMappingURL=chunk-5WFQIJJW.js.map
//# sourceMappingURL=chunk-5WFQIJJW.js.map
{"version":3,"sources":["../src/build.ts"],"names":["buildReactUIs","uis","options","startTime","outputs","files","warnings","errors","cwd","globalCss","error","key","def","html","compileComponent","outPath","buildError","component","componentName","defaultProps","entryPoint","generateEntryPoint","plugins","createComponentPlugin","createCSSPlugin","result","outputFile","script","generateHTML","build","componentSource","isClassComponent","isFunctionComponent","isArrowFunction","contents","args","css","classNames","extractClassNames","mapping","name","hashString","transformedCss","original","hashed","classRegex","classes","match","str","hash","i","char","buildReactUI","e"],"mappings":"4HAqEA,eAAsBA,CAAAA,CACpBC,EACAC,CAAAA,CAAwB,GACF,CACtB,IAAMC,EAAY,IAAA,CAAK,GAAA,GACjBC,CAAAA,CAAU,IAAI,IACdC,CAAAA,CAAQ,IAAI,IACZC,CAAAA,CAAqB,GACrBC,CAAAA,CAAuB,GAEvBC,CAAAA,CAAMN,CAAAA,CAAQ,KAAO,OAAA,CAAQ,GAAA,GAG/BA,CAAAA,CAAQ,MAAA,EACV,MAAS,CAAA,CAAA,KAAA,CAAW,CAAA,CAAA,OAAA,CAAQM,EAAKN,CAAAA,CAAQ,MAAM,EAAG,CAAE,SAAA,CAAW,IAAK,CAAC,CAAA,CAIvE,IAAIO,CAAAA,CACJ,GAAIP,EAAQ,SAAA,CACV,GAAI,CACFO,CAAAA,CAAY,MAAS,WAAc,CAAA,CAAA,OAAA,CAAQD,CAAAA,CAAKN,EAAQ,SAAS,CAAA,CAAG,OAAO,EAC7E,CAAA,MAASQ,EAAO,CACdJ,CAAAA,CAAS,KACP,CAAA,+BAAA,EAAkCJ,CAAAA,CAAQ,SAAS,CAAA,EAAA,EACjDQ,CAAAA,YAAiB,MAAQA,CAAAA,CAAM,OAAA,CAAU,OAAOA,CAAK,CACvD,EACF,EACF,CAIF,OAAW,CAACC,CAAAA,CAAKC,CAAG,CAAA,GAAK,MAAA,CAAO,QAAQX,CAAG,CAAA,CACzC,GAAI,CACF,IAAMY,EAAO,MAAMC,CAAAA,CAAiBH,EAAKC,CAAAA,CAAK,CAC5C,GAAGV,CAAAA,CACH,GAAA,CAAAM,EACA,SAAA,CAAAC,CACF,CAAC,CAAA,CAKD,GAHAL,EAAQ,GAAA,CAAIO,CAAAA,CAAKE,CAAI,CAAA,CAGjBX,CAAAA,CAAQ,OAAQ,CAClB,IAAMa,EAAe,CAAA,CAAA,OAAA,CAAQP,CAAAA,CAAKN,EAAQ,MAAA,CAAQ,CAAA,EAAGS,CAAG,CAAA,KAAA,CAAO,CAAA,CAC/D,MAAS,CAAA,CAAA,SAAA,CAAUI,CAAAA,CAASF,EAAM,OAAO,CAAA,CACzCR,EAAM,GAAA,CAAIM,CAAAA,CAAKI,CAAO,EACxB,CACF,OAASL,CAAAA,CAAO,CACd,IAAMM,CAAAA,CAAyB,CAC7B,IAAAL,CAAAA,CACA,OAAA,CAASD,aAAiB,KAAA,CAAQA,CAAAA,CAAM,QAAU,MAAA,CAAOA,CAAK,EAC9D,KAAA,CAAOA,CAAAA,YAAiB,MAAQA,CAAAA,CAAM,KAAA,CAAQ,MAChD,CAAA,CACAH,CAAAA,CAAO,KAAKS,CAAU,EACxB,CAGF,OAAO,CACL,QAAAZ,CAAAA,CACA,KAAA,CAAAC,EACA,QAAA,CAAU,IAAA,CAAK,KAAI,CAAIF,CAAAA,CACvB,SAAAG,CAAAA,CACA,MAAA,CAAAC,CACF,CACF,CAUA,eAAeO,CAAAA,CACbH,CAAAA,CACAC,EACAV,CAAAA,CACiB,CAEjB,IAAMe,CAAAA,CAAYL,CAAAA,CAAI,YAChBM,CAAAA,CAAgBD,CAAAA,CAAU,MAAQ,WAAA,CAClCE,CAAAA,CAAeP,EAAI,cAAA,CAKnBQ,CAAAA,CAAaC,IAAmB,2BAAA,CAA6BF,CAAY,EAGzEG,CAAAA,CAA4B,CAChCC,EAAsBN,CAAAA,CAAWC,CAAa,EAC9CM,CAAAA,EACF,EAGMC,CAAAA,CAAS,MAAc,QAAM,CACjC,KAAA,CAAO,CACL,QAAA,CAAUL,CAAAA,CACV,OAAQ,KAAA,CACR,UAAA,CAAYlB,EAAQ,GAAA,CACpB,UAAA,CAAY,GAAGS,CAAG,CAAA,UAAA,CACpB,EACA,MAAA,CAAQ,IAAA,CACR,MAAO,KAAA,CACP,MAAA,CAAQ,MACR,QAAA,CAAU,SAAA,CACV,OAAQ,CAAC,QAAA,CAAU,WAAY,WAAA,CAAa,UAAU,EACtD,MAAA,CAAQT,CAAAA,CAAQ,QAAU,IAAA,CAC1B,SAAA,CAAWA,EAAQ,SAAA,CAAY,QAAA,CAAW,MAC1C,GAAA,CAAK,WAAA,CACL,gBAAiB,OAAA,CACjB,QAAA,CAAU,UACV,QAAA,CAAUA,CAAAA,CAAQ,SAClB,OAAA,CAAAoB,CAAAA,CACA,OAAQ,CACN,sBAAA,CAAwBpB,EAAQ,MAAA,CAAS,cAAA,CAAiB,eAC5D,CACF,CAAC,EAGKwB,GAAAA,CAAaD,CAAAA,CAAO,cAAc,CAAC,CAAA,CACzC,GAAI,CAACC,GAAAA,CACH,MAAM,IAAI,KAAA,CAAM,+BAA+Bf,CAAG,CAAA,CAAE,EAGtD,IAAMgB,CAAAA,CAASD,IAAW,IAAA,CAK1B,OAAKD,EAAO,QAAA,CAGCG,CAAAA,CAAa,CACxB,GAAA,CAAAjB,CAAAA,CACA,KAAMC,CAAAA,CAAI,IAAA,EAAQD,EAClB,MAAA,CAAAgB,CAAAA,CACA,IAAKzB,CAAAA,CAAQ,SACf,CAAC,CAGH,CASA,SAASqB,CAAAA,CACPN,CAAAA,CACAC,EACgB,CAChB,OAAO,CACL,IAAA,CAAM,wBAAA,CACN,MAAMW,CAAAA,CAAO,CAEXA,EAAM,SAAA,CAAU,CAAE,OAAQ,2BAA4B,CAAA,CAAG,KAChD,CACL,IAAA,CAAM,gBACN,SAAA,CAAW,eACb,EACD,CAAA,CAGDA,CAAAA,CAAM,OAAO,CAAE,MAAA,CAAQ,KAAM,SAAA,CAAW,eAAgB,EAAG,IAAM,CAI/D,IAAMC,CAAAA,CAAkBb,CAAAA,CAAU,UAAS,CAGrCc,CAAAA,CAAmB,cAAc,IAAA,CAAKD,CAAe,EACrDE,CAAAA,CAAsB,gBAAA,CAAiB,KAAKF,CAAe,CAAA,CAC3DG,EAAkB,CAACF,CAAAA,EAAoB,CAACC,CAAAA,CAE1CE,CAAAA,CACJ,OAAID,CAAAA,CACFC,CAAAA,CAAW;AAAA;AAAA,oBAAA,EAEChB,CAAa,MAAMY,CAAe,CAAA;AAAA,6BAAA,EACzBZ,CAAa,CAAA;AAAA,YAAA,CAAA,CAGlCgB,CAAAA,CAAW;AAAA;AAAA,cAAA,EAELJ,CAAe;AAAA,6BAAA,EACAZ,CAAa,CAAA;AAAA,YAAA,CAAA,CAI7B,CACL,SAAAgB,CAAAA,CACA,MAAA,CAAQ,KACV,CACF,CAAC,EACH,CACF,CACF,CAQA,SAASV,CAAAA,EAAkC,CACzC,OAAO,CACL,IAAA,CAAM,kBACN,KAAA,CAAMK,CAAAA,CAAO,CAEXA,CAAAA,CAAM,MAAA,CAAO,CAAE,OAAQ,QAAS,CAAA,CAAG,MAAOM,CAAAA,EAAS,CAEjD,GAAIA,CAAAA,CAAK,IAAA,CAAK,QAAA,CAAS,aAAa,CAAA,CAClC,OAAO,KAET,IAAMC,CAAAA,CAAM,MAAS,CAAA,CAAA,QAAA,CAASD,CAAAA,CAAK,KAAM,OAAO,CAAA,CAShD,OAAO,CACL,QAAA,CAPe;AAAA;AAAA,8BAAA,EAEO,IAAA,CAAK,SAAA,CAAUC,CAAG,CAAC,CAAA;AAAA;AAAA,QAAA,CAAA,CAMzC,MAAA,CAAQ,IACV,CACF,CAAC,EAGDP,CAAAA,CAAM,MAAA,CAAO,CAAE,MAAA,CAAQ,gBAAiB,CAAA,CAAG,MAAOM,CAAAA,EAAS,CACzD,IAAMC,CAAAA,CAAM,MAAS,CAAA,CAAA,QAAA,CAASD,CAAAA,CAAK,IAAA,CAAM,OAAO,CAAA,CAI1CE,CAAAA,CAAaC,EAAkBF,CAAG,CAAA,CAClCG,CAAAA,CAAU,MAAA,CAAO,YACrBF,CAAAA,CAAW,GAAA,CAAKG,CAAAA,EAAS,CAACA,EAAM,CAAA,EAAGA,CAAI,CAAA,CAAA,EAAIC,CAAAA,CAAWN,CAAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAC,CACrE,CAAA,CAGIO,CAAAA,CAAiBN,CAAAA,CACrB,OAAW,CAACO,CAAAA,CAAUC,CAAM,CAAA,GAAK,OAAO,OAAA,CAAQL,CAAO,CAAA,CACrDG,CAAAA,CAAiBA,CAAAA,CAAe,OAAA,CAC9B,IAAI,MAAA,CAAO,MAAMC,CAAQ,CAAA,GAAA,CAAA,CAAO,GAAG,CAAA,CACnC,IAAIC,CAAM,CAAA,CACZ,CAAA,CAUF,OAAO,CACL,QAAA,CARe;AAAA;AAAA,8BAAA,EAEO,IAAA,CAAK,SAAA,CAAUF,CAAc,CAAC,CAAA;AAAA;AAAA,yBAAA,EAEnC,IAAA,CAAK,SAAA,CAAUH,CAAO,CAAC,CAAA;AAAA,QAAA,CAAA,CAKxC,MAAA,CAAQ,IACV,CACF,CAAC,EACH,CACF,CACF,CAKA,SAASD,CAAAA,CAAkBF,CAAAA,CAAuB,CAChD,IAAMS,CAAAA,CAAa,8BAAA,CACbC,CAAAA,CAAU,IAAI,GAAA,CAChBC,CAAAA,CACJ,KAAA,CAAQA,CAAAA,CAAQF,CAAAA,CAAW,IAAA,CAAKT,CAAG,CAAA,IAAO,IAAA,EACpCW,CAAAA,CAAM,CAAC,CAAA,EACTD,EAAQ,GAAA,CAAIC,CAAAA,CAAM,CAAC,CAAC,CAAA,CAGxB,OAAO,KAAA,CAAM,IAAA,CAAKD,CAAO,CAC3B,CAKA,SAASL,CAAAA,CAAWO,CAAAA,CAAqB,CACvC,IAAIC,EAAO,CAAA,CACX,IAAA,IAASC,CAAAA,CAAI,CAAA,CAAGA,CAAAA,CAAIF,CAAAA,CAAI,MAAA,CAAQE,CAAAA,EAAAA,CAAK,CACnC,IAAMC,CAAAA,CAAOH,CAAAA,CAAI,UAAA,CAAWE,CAAC,CAAA,CAC7BD,CAAAA,CAAAA,CAAQA,CAAAA,EAAQ,GAAKA,CAAAA,CAAOE,CAAAA,CAC5BF,CAAAA,CAAOA,CAAAA,CAAOA,EAChB,CACA,OAAO,IAAA,CAAK,GAAA,CAAIA,CAAI,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,CAAA,CAAG,CAAC,CACnD,CAoBA,eAAsBG,CAAAA,CACpBzC,CAAAA,CACAC,CAAAA,CACAV,CAAAA,CAAwB,GACP,CACjB,IAAMuB,CAAAA,CAAS,MAAMzB,CAAAA,CAAc,CAAE,CAACW,CAAG,EAAGC,CAAI,CAAA,CAAGV,CAAO,CAAA,CAEpDW,CAAAA,CAAOY,CAAAA,CAAO,OAAA,CAAQ,GAAA,CAAId,CAAG,CAAA,CACnC,GAAI,CAACE,CAAAA,CAAM,CACT,IAAMH,CAAAA,CAAQe,EAAO,MAAA,CAAO,IAAA,CAAM4B,CAAAA,EAAMA,CAAAA,CAAE,GAAA,GAAQ1C,CAAG,CAAA,CACrD,MAAM,IAAI,KAAA,CAAMD,CAAAA,EAAO,OAAA,EAAW,CAAA,oBAAA,EAAuBC,CAAG,CAAA,CAAE,CAChE,CAEA,OAAOE,CACT","file":"chunk-5WFQIJJW.js","sourcesContent":["/**\n * React UI build system using esbuild\n *\n * Compiles React components into self-contained HTML files that can be\n * served as MCP UI resources.\n */\n\nimport * as esbuild from \"esbuild\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { ReactUIDef, BuildOptions, BuildResult, BuildError } from \"./types\";\nimport { generateHTML, generateEntryPoint } from \"./html\";\n\n/**\n * Build multiple React UIs into self-contained HTML files.\n *\n * This function takes a record of React UI definitions and compiles each one\n * into a complete HTML file that includes React, ReactDOM, @mcp-apps-kit/ui-react,\n * and the user's component code.\n *\n * **IMPORTANT: Limitations**\n *\n * This programmatic build function serializes components using `.toString()`, which has\n * significant limitations:\n *\n * - **No external imports**: Components cannot import other modules, hooks, or utilities\n * - **No closures**: Components that capture external variables will not work\n * - **Simple components only**: Best for self-contained components without dependencies\n *\n * For production use, prefer the **Vite plugin** (`mcpReactUI`) which uses file paths\n * for proper import resolution and supports:\n * - Full import/export resolution\n * - CSS imports and CSS modules\n * - All React hooks and utilities\n * - External component dependencies\n *\n * This function is primarily intended for:\n * - **Testing**: Unit and integration tests for the build pipeline\n * - **Simple widgets**: Self-contained components with no external imports\n * - **Prototyping**: Quick experimentation before setting up Vite\n *\n * @param uis - Record of UI keys to React UI definitions\n * @param options - Build configuration options\n * @returns Build result with compiled HTML and metadata\n *\n * @example\n * ```typescript\n * // For production, use the Vite plugin instead:\n * // vite.config.ts\n * import { mcpReactUI } from \"@mcp-apps-kit/ui-react-builder/vite\";\n *\n * export default defineConfig({\n * plugins: [mcpReactUI({ serverEntry: \"./src/index.ts\" })],\n * });\n *\n * // This programmatic API is for simple/test cases:\n * import { buildReactUIs, defineReactUI } from \"@mcp-apps-kit/ui-react-builder\";\n *\n * // Only works with simple, self-contained components\n * const SimpleWidget = () => <div>Hello World</div>;\n *\n * const result = await buildReactUIs({\n * \"simple\": defineReactUI({\n * component: SimpleWidget,\n * name: \"Simple Widget\",\n * }),\n * });\n * ```\n */\nexport async function buildReactUIs(\n uis: Record<string, ReactUIDef>,\n options: BuildOptions = {}\n): Promise<BuildResult> {\n const startTime = Date.now();\n const outputs = new Map<string, string>();\n const files = new Map<string, string>();\n const warnings: string[] = [];\n const errors: BuildError[] = [];\n\n const cwd = options.cwd ?? process.cwd();\n\n // Create output directory if specified\n if (options.outDir) {\n await fs.mkdir(path.resolve(cwd, options.outDir), { recursive: true });\n }\n\n // Load global CSS if specified\n let globalCss: string | undefined;\n if (options.globalCss) {\n try {\n globalCss = await fs.readFile(path.resolve(cwd, options.globalCss), \"utf-8\");\n } catch (error) {\n warnings.push(\n `Could not load global CSS from ${options.globalCss}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n // Build each UI\n for (const [key, def] of Object.entries(uis)) {\n try {\n const html = await compileComponent(key, def, {\n ...options,\n cwd,\n globalCss,\n });\n\n outputs.set(key, html);\n\n // Write to file if outDir specified\n if (options.outDir) {\n const outPath = path.resolve(cwd, options.outDir, `${key}.html`);\n await fs.writeFile(outPath, html, \"utf-8\");\n files.set(key, outPath);\n }\n } catch (error) {\n const buildError: BuildError = {\n key,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n errors.push(buildError);\n }\n }\n\n return {\n outputs,\n files,\n duration: Date.now() - startTime,\n warnings,\n errors,\n };\n}\n\n/**\n * Compile a single React component to self-contained HTML.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns Complete HTML document as a string\n */\nasync function compileComponent(\n key: string,\n def: ReactUIDef,\n options: BuildOptions & { cwd: string; globalCss?: string }\n): Promise<string> {\n // Get component from internal properties\n const component = def.__component;\n const componentName = component.name || \"Component\";\n const defaultProps = def.__defaultProps;\n\n // Create the entry point using function serialization\n // Note: The Vite plugin uses file paths for proper import resolution\n // This build function falls back to function serialization (limited - doesn't capture imports)\n const entryPoint = generateEntryPoint(`__COMPONENT_PLACEHOLDER__`, defaultProps);\n\n // Configure plugins\n const plugins: esbuild.Plugin[] = [\n createComponentPlugin(component, componentName),\n createCSSPlugin(),\n ];\n\n // Use esbuild to bundle everything\n const result = await esbuild.build({\n stdin: {\n contents: entryPoint,\n loader: \"tsx\",\n resolveDir: options.cwd,\n sourcefile: `${key}-entry.tsx`,\n },\n bundle: true,\n write: false,\n format: \"esm\",\n platform: \"browser\",\n target: [\"es2020\", \"chrome90\", \"firefox90\", \"safari14\"],\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ? \"inline\" : false,\n jsx: \"automatic\",\n jsxImportSource: \"react\",\n logLevel: \"warning\",\n external: options.external,\n plugins,\n define: {\n \"process.env.NODE_ENV\": options.minify ? '\"production\"' : '\"development\"',\n },\n });\n\n // Get the bundled JavaScript\n const outputFile = result.outputFiles?.[0];\n if (!outputFile) {\n throw new Error(`No output generated for UI: ${key}`);\n }\n\n const script = outputFile.text;\n\n // Collect any warnings from esbuild (currently silent, could add a logger later)\n // Warnings are typically about missing exports, unused imports, etc.\n // For now we don't surface these to users\n void result.warnings;\n\n // Generate the final HTML\n const html = generateHTML({\n key,\n name: def.name ?? key,\n script,\n css: options.globalCss,\n });\n\n return html;\n}\n\n/**\n * Create an esbuild plugin that resolves the component placeholder.\n *\n * This plugin intercepts imports of the placeholder module and replaces\n * it with the actual component code. This is necessary because we receive\n * a function reference, not a file path.\n */\nfunction createComponentPlugin(\n component: { toString: () => string },\n componentName: string\n): esbuild.Plugin {\n return {\n name: \"mcp-component-resolver\",\n setup(build) {\n // Intercept the placeholder import\n build.onResolve({ filter: /__COMPONENT_PLACEHOLDER__/ }, () => {\n return {\n path: \"__COMPONENT__\",\n namespace: \"mcp-component\",\n };\n });\n\n // Provide the component code\n build.onLoad({ filter: /.*/, namespace: \"mcp-component\" }, () => {\n // Serialize the component to a module\n // For now, we export a placeholder that requires runtime injection\n // In a real implementation, we'd need the component's source path\n const componentSource = component.toString();\n\n // Detect component type: class, function, or arrow function\n const isClassComponent = /^\\s*class\\b/.test(componentSource);\n const isFunctionComponent = /^\\s*function\\b/.test(componentSource);\n const isArrowFunction = !isClassComponent && !isFunctionComponent;\n\n let contents: string;\n if (isArrowFunction) {\n contents = `\n import React from \"react\";\n const ${componentName} = ${componentSource};\n export default ${componentName};\n `;\n } else {\n contents = `\n import React from \"react\";\n ${componentSource}\n export default ${componentName};\n `;\n }\n\n return {\n contents,\n loader: \"tsx\",\n };\n });\n },\n };\n}\n\n/**\n * Create an esbuild plugin that handles CSS imports.\n *\n * This plugin transforms CSS imports into JavaScript that injects\n * the styles into the document head at runtime.\n */\nfunction createCSSPlugin(): esbuild.Plugin {\n return {\n name: \"mcp-css-handler\",\n setup(build) {\n // Handle .css imports (excluding .module.css which has its own handler)\n build.onLoad({ filter: /\\.css$/ }, async (args) => {\n // Skip .module.css files - they're handled by the CSS modules loader\n if (args.path.endsWith(\".module.css\")) {\n return null;\n }\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Create JavaScript that injects the CSS\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(css)};\n document.head.appendChild(style);\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n\n // Handle CSS modules (.module.css)\n build.onLoad({ filter: /\\.module\\.css$/ }, async (args) => {\n const css = await fs.readFile(args.path, \"utf-8\");\n\n // Generate a simple class name mapping\n // In a real implementation, we'd use a proper CSS modules processor\n const classNames = extractClassNames(css);\n const mapping = Object.fromEntries(\n classNames.map((name) => [name, `${name}_${hashString(args.path)}`])\n );\n\n // Transform the CSS with new class names\n let transformedCss = css;\n for (const [original, hashed] of Object.entries(mapping)) {\n transformedCss = transformedCss.replace(\n new RegExp(`\\\\.${original}\\\\b`, \"g\"),\n `.${hashed}`\n );\n }\n\n const contents = `\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(transformedCss)};\n document.head.appendChild(style);\n export default ${JSON.stringify(mapping)};\n `;\n\n return {\n contents,\n loader: \"js\",\n };\n });\n },\n };\n}\n\n/**\n * Extract class names from CSS content.\n */\nfunction extractClassNames(css: string): string[] {\n const classRegex = /\\.([a-zA-Z_][a-zA-Z0-9_-]*)/g;\n const classes = new Set<string>();\n let match;\n while ((match = classRegex.exec(css)) !== null) {\n if (match[1]) {\n classes.add(match[1]);\n }\n }\n return Array.from(classes);\n}\n\n/**\n * Simple string hash for generating unique class names.\n */\nfunction hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36).substring(0, 5);\n}\n\n/**\n * Build a single React UI.\n *\n * Convenience function for building just one UI.\n *\n * @param key - Unique key for this UI\n * @param def - React UI definition\n * @param options - Build options\n * @returns The compiled HTML string\n *\n * @example\n * ```typescript\n * const html = await buildReactUI(\"my-widget\", defineReactUI({\n * component: MyWidget,\n * name: \"My Widget\",\n * }));\n * ```\n */\nexport async function buildReactUI(\n key: string,\n def: ReactUIDef,\n options: BuildOptions = {}\n): Promise<string> {\n const result = await buildReactUIs({ [key]: def }, options);\n\n const html = result.outputs.get(key);\n if (!html) {\n const error = result.errors.find((e) => e.key === key);\n throw new Error(error?.message ?? `Failed to build UI: ${key}`);\n }\n\n return html;\n}\n"]}
var s=`
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
line-height: 1.5;
color: #1a1a1a;
background-color: transparent;
}
@media (prefers-color-scheme: dark) {
body {
color: #f5f5f5;
}
}
#root {
min-height: 100%;
}
`;function m(t){let{key:o,name:e,script:r,css:n}=t,i=n?`${s}
${n}`:s;return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="mcp-ui-key" content="${a(o)}">
<title>${a(e)}</title>
<style>${i}</style>
</head>
<body>
<div id="root"></div>
<script type="module">${r.replace(/<\/script>/gi,"</script>")}</script>
</body>
</html>`}function l(t,o){let e=typeof t=="string"?{componentPath:t,defaultProps:o}:t,{componentPath:r,componentExport:n="default",defaultProps:i}=e,c=i?JSON.stringify(i):"{}";return `
import React from "react";
import { createRoot } from "react-dom/client";
import { AppsProvider } from "@mcp-apps-kit/ui-react";
${n==="default"?`import Component from "${r}";`:`import { ${n} as Component } from "${r}";`}
const rootElement = document.getElementById("root");
if (rootElement) {
const root = createRoot(rootElement);
root.render(
<React.StrictMode>
<AppsProvider>
<Component {...${c}} />
</AppsProvider>
</React.StrictMode>
);
}
`}function a(t){let o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return t.replace(/[&<>"']/g,e=>o[e]??e)}export{m as a,l as b};//# sourceMappingURL=chunk-6JS3KVIH.js.map
//# sourceMappingURL=chunk-6JS3KVIH.js.map
{"version":3,"sources":["../src/html.ts"],"names":["DEFAULT_BASE_CSS","generateHTML","options","key","name","script","css","combinedCss","escapeHtml","generateEntryPoint","componentPathOrOptions","defaultProps","componentPath","componentExport","props","propsJson","text","htmlEntities","char"],"mappings":"AAUA,IAAMA,CAAAA,CAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA,CA0DlB,SAASC,CAAAA,CAAaC,CAAAA,CAAkC,CAC7D,GAAM,CAAE,IAAAC,CAAAA,CAAK,IAAA,CAAAC,EAAM,MAAA,CAAAC,CAAAA,CAAQ,IAAAC,CAAI,CAAA,CAAIJ,EAG7BK,CAAAA,CAAcD,CAAAA,CAAM,GAAGN,CAAgB;AAAA,EAAKM,CAAG,CAAA,CAAA,CAAKN,CAAAA,CAE1D,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAAA,EAK4BQ,CAAAA,CAAWL,CAAG,CAAC,CAAA;AAAA,SAAA,EACzCK,CAAAA,CAAWJ,CAAI,CAAC,CAAA;AAAA,SAAA,EAChBG,CAAW,CAAA;AAAA;AAAA;AAAA;AAAA,wBAAA,EAIIF,CAAAA,CAAO,OAAA,CAAQ,cAAA,CAAgB,WAAgB,CAAC,CAAA;AAAA;AAAA,OAAA,CAG1E,CAwDO,SAASI,CAAAA,CACdC,CAAAA,CACAC,EACQ,CAER,IAAMT,CAAAA,CACJ,OAAOQ,GAA2B,QAAA,CAC9B,CAAE,aAAA,CAAeA,CAAAA,CAAwB,aAAAC,CAAa,CAAA,CACtDD,CAAAA,CAEA,CAAE,cAAAE,CAAAA,CAAe,eAAA,CAAAC,CAAAA,CAAkB,SAAA,CAAW,aAAcC,CAAM,CAAA,CAAIZ,CAAAA,CACtEa,CAAAA,CAAYD,EAAQ,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAA,CAAI,KAQlD,OAAO;AAAA;AAAA;AAAA;AAAA,EAJLD,CAAAA,GAAoB,UAChB,CAAA,uBAAA,EAA0BD,CAAa,KACvC,CAAA,SAAA,EAAYC,CAAe,CAAA,sBAAA,EAAyBD,CAAa,CAAA,EAAA,CAMxD;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAA,EAQQG,CAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAMlC,CAQA,SAASP,CAAAA,CAAWQ,CAAAA,CAAsB,CACxC,IAAMC,CAAAA,CAAuC,CAC3C,GAAA,CAAK,OAAA,CACL,GAAA,CAAK,MAAA,CACL,GAAA,CAAK,MAAA,CACL,GAAA,CAAK,QAAA,CACL,GAAA,CAAK,OACP,CAAA,CAEA,OAAOD,CAAAA,CAAK,OAAA,CAAQ,UAAA,CAAaE,CAAAA,EAASD,CAAAA,CAAaC,CAAI,CAAA,EAAKA,CAAI,CACtE","file":"chunk-6JS3KVIH.js","sourcesContent":["/**\n * HTML template generation for React UIs\n */\n\nimport type { TemplateOptions } from \"./types\";\n\n/**\n * Default base CSS reset for all UIs.\n * Provides a consistent starting point across platforms.\n */\nconst DEFAULT_BASE_CSS = `\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html {\n font-size: 16px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif;\n line-height: 1.5;\n color: #1a1a1a;\n background-color: transparent;\n }\n\n @media (prefers-color-scheme: dark) {\n body {\n color: #f5f5f5;\n }\n }\n\n #root {\n min-height: 100%;\n }\n`;\n\n/**\n * Generate a self-contained HTML document for a React UI.\n *\n * The generated HTML includes:\n * - DOCTYPE and valid HTML5 structure\n * - Meta tags for responsive design\n * - Inlined CSS (base reset + optional custom CSS)\n * - Inlined JavaScript bundle with React app\n *\n * @param options - Template options with key, name, script, and optional CSS\n * @returns Complete HTML document as a string\n *\n * @example\n * ```typescript\n * const html = generateHTML({\n * key: \"restaurant-list\",\n * name: \"Restaurant List Widget\",\n * script: bundledJavaScript,\n * css: customStyles,\n * });\n * ```\n *\n * @internal\n */\nexport function generateHTML(options: TemplateOptions): string {\n const { key, name, script, css } = options;\n\n // Combine base CSS with any custom CSS\n const combinedCss = css ? `${DEFAULT_BASE_CSS}\\n${css}` : DEFAULT_BASE_CSS;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"mcp-ui-key\" content=\"${escapeHtml(key)}\">\n <title>${escapeHtml(name)}</title>\n <style>${combinedCss}</style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script type=\"module\">${script.replace(/<\\/script>/gi, \"</scr\" + \"ipt>\")}</script>\n</body>\n</html>`;\n}\n\n/**\n * Options for generating the React entry point.\n *\n * @internal\n */\nexport interface EntryPointOptions {\n /**\n * Path to the component file.\n */\n componentPath: string;\n\n /**\n * Name of the export to use.\n * Use \"default\" for default exports, or the actual name for named exports.\n * @default \"default\"\n */\n componentExport?: string;\n\n /**\n * Default props to pass to the component.\n */\n defaultProps?: Record<string, unknown>;\n}\n\n/**\n * Generate the React entry point code that will be bundled.\n *\n * This creates a small JavaScript module that:\n * 1. Imports React and ReactDOM\n * 2. Imports the user's component\n * 3. Imports AppsProvider from @mcp-apps-kit/ui-react\n * 4. Renders the component wrapped in providers\n *\n * @param componentPath - Path to the React component file (for backward compatibility)\n * @param defaultProps - Optional default props to pass to the component\n * @returns JavaScript/TypeScript source code for the entry point\n *\n * @example\n * ```typescript\n * // Default export\n * const entryCode = generateEntryPoint(\n * \"./src/widgets/MyWidget.tsx\",\n * { theme: \"dark\" }\n * );\n *\n * // Named export\n * const entryCode = generateEntryPoint({\n * componentPath: \"./src/widgets/MyWidget.tsx\",\n * componentExport: \"MyWidget\",\n * });\n * ```\n *\n * @internal\n */\nexport function generateEntryPoint(\n componentPathOrOptions: string | EntryPointOptions,\n defaultProps?: Record<string, unknown>\n): string {\n // Handle backward compatibility with string-only signature\n const options: EntryPointOptions =\n typeof componentPathOrOptions === \"string\"\n ? { componentPath: componentPathOrOptions, defaultProps }\n : componentPathOrOptions;\n\n const { componentPath, componentExport = \"default\", defaultProps: props } = options;\n const propsJson = props ? JSON.stringify(props) : \"{}\";\n\n // Generate appropriate import statement based on export type\n const importStatement =\n componentExport === \"default\"\n ? `import Component from \"${componentPath}\";`\n : `import { ${componentExport} as Component } from \"${componentPath}\";`;\n\n return `\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { AppsProvider } from \"@mcp-apps-kit/ui-react\";\n${importStatement}\n\nconst rootElement = document.getElementById(\"root\");\nif (rootElement) {\n const root = createRoot(rootElement);\n root.render(\n <React.StrictMode>\n <AppsProvider>\n <Component {...${propsJson}} />\n </AppsProvider>\n </React.StrictMode>\n );\n}\n`;\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n *\n * @param text - Text to escape\n * @returns Escaped text safe for HTML insertion\n */\nfunction escapeHtml(text: string): string {\n const htmlEntities: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n };\n\n return text.replace(/[&<>\"']/g, (char) => htmlEntities[char] ?? char);\n}\n\n/**\n * Extract CSS from a string that may contain both JS and CSS.\n * Used when esbuild bundles CSS as JavaScript that injects styles.\n *\n * @param code - Bundled code that may contain CSS injection\n * @returns Extracted CSS string or undefined\n */\nexport function extractInlineCSS(code: string): string | undefined {\n // esbuild injects CSS as: document.head.appendChild(...).textContent = \"css content\"\n const cssMatch = code.match(/\\.textContent\\s*=\\s*[\"'`]([\\s\\S]*?)[\"'`]\\s*[;,)]/);\n if (cssMatch?.[1]) {\n // Unescape the CSS string\n return cssMatch[1].replace(/\\\\n/g, \"\\n\").replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n return undefined;\n}\n"]}