UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

135 lines • 5.74 kB
/** * The kit bundle: the app's components, its wrapper, React and ReactDOM as ONE classic script (an * IIFE) that sets `window.Kit`, `window.KitWrapper`, `window.React` and `window.ReactDOM` — what the * sandbox frame inlines, so it needs no network and no module loader. Built with the app's own Vite * (nothing written), its aliases kept, so `@/lib/utils` resolves as it does in the app. */ import { readFileSync } from 'node:fs'; import { runInNewContext } from 'node:vm'; import { contentHash, runKitViteBuild } from './vite-build.js'; function entryCode(files) { const modules = [...files.files, ...files.packages]; return [ 'import * as React from "react";', 'import * as ReactDOMClient from "react-dom/client";', ...modules.map((module, index) => `import * as __kit${index} from ${JSON.stringify(module)};`), ...(files.wrapper !== undefined ? [`import __KitWrapper from ${JSON.stringify(files.wrapper)};`] : []), 'var Kit = {};', // In order, the first module naming a component wins (what `export *` would leave ambiguous). ...modules.map((_, index) => `for (var k in __kit${index}) { if (!(k in Kit) && k !== "default") Kit[k] = __kit${index}[k]; }`), 'window.React = React;', 'window.ReactDOM = ReactDOMClient;', 'window.Kit = Kit;', ...(files.wrapper !== undefined ? ['window.KitWrapper = __KitWrapper;'] : []), ].join('\n'); } /** The names the kit's source files export in PascalCase (read off the text: no TypeScript needed). */ function sourceExportNames(files) { const names = new Set(); for (const file of files) { let text; try { text = readFileSync(file, 'utf8'); } catch { continue; } for (const match of text.matchAll(/export\s+(?:const|function|class|let|var)\s+([A-Z][A-Za-z0-9]*)/g)) names.add(match[1]); for (const match of text.matchAll(/export\s*\{([^}]*)\}/g)) { for (const part of match[1].split(',')) { const name = part .split(/\s+as\s+/) .pop() ?.trim(); if (name !== undefined && /^[A-Z][A-Za-z0-9]*$/.test(name)) names.add(name); } } } return [...names]; } /** Build the kit bundle with the app's Vite. */ export async function buildSandboxKitBundle(options) { const built = await runKitViteBuild({ root: options.root, entry: entryCode(options.files), ...(options.resolve !== undefined ? { resolve: options.resolve } : {}), ...(options.css !== undefined ? { css: options.css } : {}), ...(options.plugins !== undefined ? { plugins: options.plugins } : {}), ...(options.inlineAssetLimit !== undefined ? { inlineAssetLimit: options.inlineAssetLimit } : {}), ...(options.inlineAssetBudget !== undefined ? { inlineAssetBudget: options.inlineAssetBudget } : {}), ...(options.warn !== undefined ? { warn: options.warn } : {}), ...(options.minify !== undefined ? { minify: options.minify } : {}), }); let code = built.code; if (built.css !== '') code = `window.__GENUI_KIT_CSS__=${JSON.stringify(built.css)};\n${code}`; const exports = sourceExportNames(options.files.files); return { code, hash: contentHash(code), exports, modules: built.modules }; } /** * The kit's components as a JavaScript project can document them, without TypeScript: run the * bundle in a bare context (no DOM) and read each PascalCase export's `propTypes` keys and * `defaultProps`. `[]` when the bundle does not run outside a browser. */ export function kitDocsFromBundle(code) { const window = {}; try { runInNewContext(code, { window, self: window, globalThis: window, console: { log() { }, warn() { }, error() { } }, setTimeout, clearTimeout, queueMicrotask, }, { timeout: 2000 }); } catch { if (window.Kit === undefined) return []; } const kit = (window.Kit ?? {}); const docs = []; for (const [name, value] of Object.entries(kit)) { if (!/^[A-Z][A-Za-z0-9]*$/.test(name)) continue; if (typeof value !== 'function' && (typeof value !== 'object' || value === null)) continue; const component = value; const propTypes = (component.propTypes ?? component.render?.propTypes ?? {}); const defaults = (component.defaultProps ?? component.render?.defaultProps ?? {}); const names = [...new Set([...Object.keys(propTypes), ...Object.keys(defaults)])]; docs.push({ name, props: names.slice(0, 40).map((prop) => { const value = defaults[prop]; const shown = value === undefined || typeof value === 'function' ? undefined : (() => { try { return JSON.stringify(value); } catch { return undefined; } })(); return { name: prop, type: value === undefined ? 'unknown' : Array.isArray(value) ? 'array' : typeof value, required: false, ...(shown !== undefined && shown.length <= 80 ? { default: shown } : {}), }; }), }); } return docs; } //# sourceMappingURL=bundle.js.map