{"version":3,"sources":["../src/generative-ui.ts"],"names":["isRecord","value","assert","condition","message","validateArtifact","raw","type","validateChildren","c","validateElement","i","validateUIMessage","parseUIMessage","input","body","start","end","detectCodeArtifacts","pattern","out","match"],"mappings":"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","file":"generative-ui.cjs","sourcesContent":["/**\n * Generative UI — typed JSON the agent emits that downstream\n * renderers turn into real components. The schema is intentionally\n * framework-agnostic (React, Vue, Svelte, RN all render the same\n * tree) and keeps the element set small so model outputs stay\n * predictable.\n *\n * Paired with artifacts (code blocks, charts, markdown, HTML) so a\n * single `UIMessage` can mix declarative UI + rich content.\n */\n\nexport interface UIElementText {\n  kind: 'text'\n  text: string\n  weight?: 'normal' | 'bold'\n}\n\nexport interface UIElementHeading {\n  kind: 'heading'\n  level: 1 | 2 | 3\n  text: string\n}\n\nexport interface UIElementList {\n  kind: 'list'\n  ordered?: boolean\n  items: string[]\n}\n\nexport interface UIElementButton {\n  kind: 'button'\n  label: string\n  action: string\n  payload?: Record<string, unknown>\n  variant?: 'primary' | 'secondary' | 'danger'\n}\n\nexport interface UIElementImage {\n  kind: 'image'\n  src: string\n  alt?: string\n}\n\nexport interface UIElementCard {\n  kind: 'card'\n  title?: string\n  children: UIElement[]\n}\n\nexport interface UIElementStack {\n  kind: 'stack'\n  direction?: 'row' | 'column'\n  children: UIElement[]\n}\n\nexport interface UIElementArtifact {\n  kind: 'artifact'\n  artifact: Artifact\n}\n\nexport type UIElement =\n  | UIElementText\n  | UIElementHeading\n  | UIElementList\n  | UIElementButton\n  | UIElementImage\n  | UIElementCard\n  | UIElementStack\n  | UIElementArtifact\n\n// ---------------------------------------------------------------------------\n// Artifacts — rich content blocks\n// ---------------------------------------------------------------------------\n\nexport interface ArtifactCode {\n  type: 'code'\n  language: string\n  source: string\n  filename?: string\n}\n\nexport interface ArtifactMarkdown {\n  type: 'markdown'\n  source: string\n}\n\nexport interface ArtifactHtml {\n  type: 'html'\n  source: string\n  /** Sandbox policy hint for the renderer (iframe sandbox attrs). */\n  sandbox?: string\n}\n\nexport interface ArtifactChart {\n  type: 'chart'\n  chartType: 'line' | 'bar' | 'pie' | 'scatter' | 'area'\n  data: Array<Record<string, number | string>>\n  x?: string\n  y?: string | string[]\n  title?: string\n}\n\nexport type Artifact = ArtifactCode | ArtifactMarkdown | ArtifactHtml | ArtifactChart\n\n// ---------------------------------------------------------------------------\n// UI message wrapper + validators\n// ---------------------------------------------------------------------------\n\nexport interface UIMessage {\n  version: 1\n  root: UIElement\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction assert(condition: unknown, message: string): asserts condition {\n  if (!condition) throw new Error(`Invalid UIMessage: ${message}`)\n}\n\nexport function validateArtifact(raw: unknown): Artifact {\n  assert(isRecord(raw), 'artifact must be an object')\n  const type = raw.type\n  if (type === 'code') {\n    assert(typeof raw.language === 'string', 'artifact.language must be string')\n    assert(typeof raw.source === 'string', 'artifact.source must be string')\n    return raw as unknown as ArtifactCode\n  }\n  if (type === 'markdown' || type === 'html') {\n    assert(typeof raw.source === 'string', 'artifact.source must be string')\n    return raw as unknown as ArtifactMarkdown | ArtifactHtml\n  }\n  if (type === 'chart') {\n    assert(typeof raw.chartType === 'string', 'artifact.chartType must be string')\n    assert(Array.isArray(raw.data), 'artifact.data must be an array')\n    return raw as unknown as ArtifactChart\n  }\n  throw new Error(`Invalid UIMessage: unknown artifact.type \"${String(type)}\"`)\n}\n\nfunction validateChildren(raw: unknown): UIElement[] {\n  assert(Array.isArray(raw), 'children must be an array')\n  return raw.map(c => validateElement(c))\n}\n\nexport function validateElement(raw: unknown): UIElement {\n  assert(isRecord(raw), 'element must be an object')\n  switch (raw.kind) {\n    case 'text':\n      assert(typeof raw.text === 'string', 'text.text must be string')\n      return raw as unknown as UIElementText\n    case 'heading':\n      assert([1, 2, 3].includes(Number(raw.level)), 'heading.level must be 1, 2, or 3')\n      assert(typeof raw.text === 'string', 'heading.text must be string')\n      return raw as unknown as UIElementHeading\n    case 'list':\n      assert(Array.isArray(raw.items), 'list.items must be an array')\n      assert(raw.items.every((i: unknown) => typeof i === 'string'), 'list.items must be strings')\n      return raw as unknown as UIElementList\n    case 'button':\n      assert(typeof raw.label === 'string' && typeof raw.action === 'string', 'button.label/action required')\n      return raw as unknown as UIElementButton\n    case 'image':\n      assert(typeof raw.src === 'string', 'image.src must be string')\n      return raw as unknown as UIElementImage\n    case 'card':\n      return { ...raw, children: validateChildren(raw.children) } as UIElementCard\n    case 'stack':\n      return { ...raw, children: validateChildren(raw.children) } as UIElementStack\n    case 'artifact':\n      return { kind: 'artifact', artifact: validateArtifact(raw.artifact) }\n    default:\n      throw new Error(`Invalid UIMessage: unknown element.kind \"${String(raw.kind)}\"`)\n  }\n}\n\nexport function validateUIMessage(raw: unknown): UIMessage {\n  assert(isRecord(raw), 'root must be an object')\n  assert(raw.version === 1, `unsupported version: ${String(raw.version)}`)\n  return { version: 1, root: validateElement(raw.root) }\n}\n\n/**\n * Parse text that may contain a fenced JSON block (```json ... ```),\n * or a raw JSON object, into a `UIMessage`. Useful when agents emit\n * prose + UI side-by-side.\n */\nexport function parseUIMessage(input: string): UIMessage {\n  const fenced = input.match(/```(?:json)?\\n?([\\s\\S]*?)```/)\n  const body = (fenced?.[1] ?? input).trim()\n  const start = body.indexOf('{')\n  const end = body.lastIndexOf('}')\n  if (start < 0 || end <= start) throw new Error('parseUIMessage: no JSON object found')\n  return validateUIMessage(JSON.parse(body.slice(start, end + 1)))\n}\n\n// ---------------------------------------------------------------------------\n// Artifact detection — pull artifacts out of a plain text stream\n// ---------------------------------------------------------------------------\n\nexport interface DetectedArtifact {\n  artifact: Artifact\n  /** Offsets in the source where the fence started / ended. */\n  start: number\n  end: number\n}\n\n/**\n * Scan a string for fenced code blocks and return them as `code`\n * artifacts. HTML / markdown / chart artifacts are left to the\n * agent to emit explicitly via `UIMessage`.\n */\nexport function detectCodeArtifacts(input: string): DetectedArtifact[] {\n  const pattern = /```(\\w+)?\\n([\\s\\S]*?)```/g\n  const out: DetectedArtifact[] = []\n  for (const match of input.matchAll(pattern)) {\n    const start = match.index ?? 0\n    out.push({\n      artifact: {\n        type: 'code',\n        language: match[1] ?? 'plaintext',\n        source: match[2] ?? '',\n      },\n      start,\n      end: start + match[0].length,\n    })\n  }\n  return out\n}\n"]}