// packages/ui-gen/src/validation/ui-compiler.ts // // Standalone UI compiler — validates, classifies, compiles, and hashes // user-authored components. Uses shared validation from @ggui-ai/protocol. // // Two compilation modes: // 1. Transform (default) — transpiles source TSX to ESM, no import resolution. // Used by the server register endpoint (source code in, compiled code out). // 2. Bundle — resolves and inlines all imports from local node_modules. // Used by `ggui ui build` CLI when the component uses external libraries. // Externals (provided by the sandbox runtime at render time): // - react, react/jsx-runtime, react-dom // - @ggui-ai/design/* // // ── Future: Case 2 — LLM-Generated UIs ───────────────────────────── // // The UI generator (Claude Agent SDK + esbuild) creates components from // scratch. Currently those components can only use react + @ggui-ai/design/*. // // When we want generated UIs to use external libraries (chart.js, leaflet, // etc.), the same externals list defined here becomes the set of libraries // available in the generator's esbuild sandbox. The generator's system // prompt would be updated with usage docs for each available library. // // Architecture path: // 1. Define SANDBOX_EXTERNALS here (this file) — single source of truth // 2. Generator sandbox provides these as pre-installed node_modules // 3. System prompt includes library API docs (from a docs registry) // 4. Generated code imports from these libraries → esbuild resolves → works // // This is NOT implemented yet. When we get there, start by extending // SANDBOX_EXTERNALS and updating the generator's esbuild plugin to // resolve from a curated node_modules directory. // ──────────────────────────────────────────────────────────────────── import * as esbuild from 'esbuild'; import { readFileSync } from 'fs'; import { validateComponentDetailed, type ValidationResult } from './component-detailed.js'; import { classifyUi } from '@ggui-ai/protocol'; import { contentHash } from '@ggui-ai/protocol/content-hash'; import type { UiClass } from '@ggui-ai/protocol'; import type { UiManifest } from '@ggui-ai/project-config'; // Re-export shared functions so consumers can import from one place export { classifyUi as classifyUiSource } from '@ggui-ai/protocol'; export { contentHash } from '@ggui-ai/protocol/content-hash'; // ── Externals ─────────────────────────────────────────────────────── // These packages are provided by the ggui sandbox runtime at render time. // They must NOT be bundled into the compiled output. // // For registered UIs (case 1): esbuild excludes these from the bundle. // For generated UIs (case 2, future): these define what's available in // the generator sandbox's node_modules. const SANDBOX_EXTERNALS = [ 'react', 'react/*', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom', 'react-dom/*', '@ggui-ai/design', '@ggui-ai/design/*', '@ggui-ai/wire', '@ggui-ai/wire/*', '@ggui-ai/mcp-apps-react', '@ggui-ai/mcp-apps-react/*', ]; /** Max compiled bundle size (2MB). Prevents accidentally bundling huge deps. */ const MAX_BUNDLE_SIZE = 2 * 1024 * 1024; // ── CSS Inline Plugin ─────────────────────────────────────────────── // Converts `import 'foo.css'` into runtime