import { Cell, type JSONSchema, type Runtime } from "@commontools/runner"; import { getRecipeIdFromCharm } from "../manager.ts"; export type IFrameRecipe = { src: string; argumentSchema: JSONSchema; resultSchema: JSONSchema; spec: string; plan?: string; goal?: string; name: string; }; export const buildFullRecipe = (iframe: IFrameRecipe) => { const properties = typeof iframe.resultSchema === "boolean" ? undefined : iframe.resultSchema.properties; const result = Object.keys(properties ?? {}).map((key) => ` ${key}: data.${key},\n` ).join("\n"); return `import { h, recipe, type JSONSchema, UI, NAME } from "commontools"; type IFrameRecipe = { src: string, argumentSchema: JSONSchema, resultSchema: JSONSchema, spec: string, plan?: string, goal?: string, name: string, } const inst: IFrameRecipe = /* IFRAME-V0 */ ${ JSON.stringify(iframe, null, 2) } /* IFRAME-V0 */ const runIframeRecipe = ({ argumentSchema, resultSchema, src, name }: IFrameRecipe) => recipe(argumentSchema, resultSchema, (data) => ({ [NAME]: name, [UI]: ( ), ${result} })); export default runIframeRecipe(inst); `; }; function parseIframeRecipe(source: string): IFrameRecipe { // Extract content between IFRAME-V0 comments const match = source.match( /\/\* IFRAME-V0 \*\/([\s\S]*?)\/\* IFRAME-V0 \*\//, ); if (!match || !match[1]) { throw new Error("Could not find IFRAME-V0 recipe content in source"); } return JSON.parse(match[1]) as IFrameRecipe; } export const getIframeRecipe = ( charm: Cell, runtime: Runtime, ): { recipeId: string; // `src` is either a single file string source, or the entry // file source code in a recipe. src?: string; iframe?: IFrameRecipe; } => { const recipeId = getRecipeIdFromCharm(charm); if (!recipeId) { console.warn("No recipeId found for charm", charm.entityId); return { recipeId, src: "", iframe: undefined }; } const meta = runtime.recipeManager.getRecipeMeta({ recipeId }); const src = meta ? (meta.src ?? meta.program?.files.find((file) => file.name === meta.program?.main) ?.contents) : undefined; if (!src) { return { recipeId }; } try { return { recipeId, src, iframe: parseIframeRecipe(src) }; } catch (_) { return { recipeId, src }; } };