{"version":3,"sources":["../src/host/theme.ts","../src/host/types.ts","../src/host/data.ts","../src/host/adapters/inline.ts","../src/host/adapters/mcpapps.ts","../src/host/detect.ts","../src/host/connect.ts"],"names":["applyTheme","extractHostFontCss"],"mappings":"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","file":"chunk-BNF352SA.cjs","sourcesContent":["import { applyTheme } from \"../theme-defaults.js\";\nimport type { SynapseUITheme } from \"./types.js\";\n\n/**\n * Apply a resolved theme to the DOM for the cross-host client.\n *\n * Two conventions coexist across Synapse components, so the client drives both:\n *\n *  - `document.documentElement[data-theme=\"light\"|\"dark\"]` — how self-contained\n *    HTML components (Bassethound's report) gate their `--var` palettes, and the\n *    lever a host's light/dark signal actually flips.\n *  - CSS custom properties via {@link applyTheme} — how the\n *    `@nimblebrain/synapse/ui` token components consume theme, backed by the\n *    SDK's neutral defaults so every referenced var resolves in both modes.\n *\n * Setting both means an app can use either convention (and a host that supplies\n * only a mode string still themes correctly). SSR-safe.\n *\n * Fonts travel separately, as the host's `@font-face` CSS: see\n * {@link injectHostFonts}.\n */\nexport function applyHostTheme(theme: SynapseUITheme): void {\n  if (typeof document !== \"undefined\") {\n    document.documentElement.setAttribute(\"data-theme\", theme.mode);\n  }\n  applyTheme(theme.mode, theme.tokens);\n}\n\n/** The style element the host's font CSS goes in — the same id the spec's\n *  `applyHostFonts` uses, so both clients agree on one element. */\nexport const HOST_FONTS_STYLE_ID = \"__mcp-host-fonts\";\n\n/**\n * Load the host's `@font-face` CSS (the spec's `hostContext.styles.css.fonts`)\n * into the document.\n *\n * Mirrors ext-apps `applyHostFonts`, which this client cannot import without\n * pulling the ext-apps runtime into its IIFE: the CSS is injected once and left\n * in place, so a later host-context change without `css` keeps the typeface\n * loaded. A host that sends none leaves the web-safe fallbacks in force.\n * SSR-safe.\n */\nexport function injectHostFonts(css: string): void {\n  if (typeof document === \"undefined\") return;\n  if (document.getElementById(HOST_FONTS_STYLE_ID)) return;\n  const style = document.createElement(\"style\");\n  style.id = HOST_FONTS_STYLE_ID;\n  style.textContent = css;\n  document.head.appendChild(style);\n}\n\n/** Read the OS-level color scheme as a sane default for hosts that don't push a\n *  theme until the handshake completes, or ever (standalone). */\nexport function preferredMode(win: Window | undefined): \"light\" | \"dark\" {\n  try {\n    if (win?.matchMedia?.(\"(prefers-color-scheme: dark)\").matches) return \"dark\";\n  } catch {\n    // matchMedia unavailable (older test envs) — fall through to light.\n  }\n  return \"light\";\n}\n\n/** Coerce an arbitrary host-supplied theme signal to a mode. Accepts the string\n *  form (`\"dark\"`) both hosts use; anything else falls back. */\nexport function coerceMode(value: unknown, fallback: \"light\" | \"dark\"): \"light\" | \"dark\" {\n  return value === \"light\" || value === \"dark\" ? value : fallback;\n}\n","/**\n * Cross-host UI client — types and wire constants.\n *\n * The cross-host client (`connectUI`) renders one Synapse-authored component in\n * any MCP Apps host (ChatGPT, Claude, NimbleBrain) and standalone. Apps code\n * against `synapse.*` and never touch the bridge. This is a **push-first** surface: the tool output that spawned\n * the widget is delivered at render (`data()` / `onData()`); `callTool()` is the\n * pull escape hatch, advertised per host via `capabilities()`.\n *\n * This layer intentionally has ZERO dependency on `@modelcontextprotocol/*` — the\n * bridge is JSON-RPC over `postMessage`, spoken by hand, so the IIFE that apps\n * inline stays tiny (no Zod, no ext-apps schemas).\n */\n\n/**\n * The bridge the client resolved to, as reported by `synapse.host()`:\n * `\"mcp-apps\"` in a frame, `\"generic\"` standalone. It names the bridge, not the\n * product — every framing host speaks the same one. Apps should rarely branch on\n * it; `capabilities()` is the supported way to feature-detect.\n */\nexport type HostKind = \"mcp-apps\" | \"generic\";\n\n/** Resolved theme. `mode` always resolves to light or dark. `tokens` are CSS\n *  custom properties the host publishes — the MCP Apps adapter reads them from\n *  `hostContext.styles.variables`; where a host sends none they stay empty and the\n *  SDK's neutral defaults back them. */\nexport interface SynapseUITheme {\n  mode: \"light\" | \"dark\";\n  tokens: Record<string, string>;\n}\n\n/** What the active host actually supports. `data()`/`onData()`/`theme()`/\n *  `resize()` work everywhere; these three vary. */\nexport interface HostCapabilities {\n  /** `callTool()` can reach the server (widget→server fetch). */\n  pull: boolean;\n  /** `sendPrompt()` reaches the agent conversation. */\n  sendPrompt: boolean;\n  /** `openLink()` opens an external URL through the host. */\n  openLink: boolean;\n}\n\n/** Thrown by `callTool()` when the active host offers no widget→server call. */\nexport class HostUnsupportedError extends Error {\n  constructor(feature: string, host: HostKind) {\n    super(`\"${feature}\" is not supported by the \"${host}\" host`);\n    this.name = \"HostUnsupportedError\";\n  }\n}\n\n/**\n * Thrown by `callTool()` when the tool result says the call failed\n * (`isError: true`). MCP reports a tool failure inside the result rather than as\n * a JSON-RPC error, and a host reports a refusal the same way — ChatGPT answers a\n * call to a tool the app may not see with an `isError` result — so without this a\n * failure would resolve as if it were data. The message is the result's first\n * text block; the whole result is on `result`.\n */\nexport class ToolCallError extends Error {\n  readonly result: unknown;\n  constructor(name: string, result: unknown) {\n    super(toolErrorText(result) ?? `tool \"${name}\" returned an error`);\n    this.name = \"ToolCallError\";\n    this.result = result;\n  }\n}\n\nfunction toolErrorText(result: unknown): string | undefined {\n  const content = (result as { content?: unknown } | null)?.content;\n  if (!Array.isArray(content)) return undefined;\n  for (const block of content) {\n    const b = block as { type?: unknown; text?: unknown } | null;\n    if (b?.type === \"text\" && typeof b.text === \"string\" && b.text !== \"\") return b.text;\n  }\n  return undefined;\n}\n\n/** True when a tool result reports failure, as MCP defines it. */\nexport function isToolError(result: unknown): boolean {\n  return (\n    result != null &&\n    typeof result === \"object\" &&\n    (result as { isError?: unknown }).isError === true\n  );\n}\n\nexport interface ConnectUIOptions {\n  /** App name — informational; forwarded to hosts that accept an appInfo. */\n  name?: string;\n  /** App semver — informational. */\n  version?: string;\n  /**\n   * Force a host adapter instead of auto-detecting. Used by preview harnesses,\n   * SSR, and tests; production apps omit it and let the SDK feature-detect.\n   * `\"mcp-apps\"` → MCP Apps standard adapter, `\"generic\"` → inline adapter.\n   */\n  host?: HostKind;\n  /**\n   * `id` of the `<script type=\"application/json\">` element carrying pushed data\n   * baked into the HTML (the SSR / standalone path). Defaults to\n   * {@link SYNAPSE_DATA_ELEMENT_ID}.\n   */\n  dataElementId?: string;\n  /**\n   * Auto-report content height to the host on layout changes (MCP Apps only).\n   * Defaults to `true`. Set `false` to size manually via `resize()`.\n   */\n  autoResize?: boolean;\n  /** Window to bind to. Defaults to the global `window`. Injectable for tests. */\n  window?: Window & typeof globalThis;\n}\n\n/**\n * The public cross-host client. Bound to `synapse` by convention.\n *\n * ```ts\n * const synapse = connectUI();\n * synapse.onData(render);          // future pushes/updates\n * render(synapse.data());          // current value (may be null → empty state)\n * ```\n */\nexport interface SynapseUIClient {\n  /** The current pushed data, or `null` before anything has been delivered. */\n  data<T = unknown>(): T | null;\n  /** Subscribe to data updates (NOT replayed — read `data()` for the current\n   *  value). Returns an unsubscribe. */\n  onData<T = unknown>(cb: (data: T) => void): () => void;\n\n  /** The current resolved theme. */\n  theme(): SynapseUITheme;\n  /** Subscribe to theme changes. The client already applies the theme to the DOM\n   *  (`data-theme` attribute + CSS variables) before this fires. */\n  onTheme(cb: (theme: SynapseUITheme) => void): () => void;\n\n  /** Widget→server tool call. Resolves with the tool result. Rejects with\n   *  {@link ToolCallError} when the result reports failure (`isError: true`), and\n   *  with {@link HostUnsupportedError} where the host advertises no pull\n   *  (`capabilities().pull === false`). */\n  callTool<O = unknown>(name: string, args?: Record<string, unknown>): Promise<O>;\n  /** Send a follow-up message to the agent conversation. No-op where unsupported. */\n  sendPrompt(text: string): void;\n  /** Open an external URL through the host (falls back to `window.open`). */\n  openLink(url: string): void;\n  /** Report content height to the host. Omit `height` to measure `document.body`. */\n  resize(height?: number): void;\n\n  /** What the active host supports. */\n  capabilities(): HostCapabilities;\n  /** The resolved host — an escape hatch; prefer `capabilities()`. */\n  host(): HostKind;\n  /** Tear down listeners/observers. */\n  destroy(): void;\n}\n\n/**\n * Internal adapter contract. One per host bridge; the client is a thin façade\n * over the selected adapter.\n */\nexport interface HostAdapter {\n  readonly host: HostKind;\n  getData<T = unknown>(): T | null;\n  onData<T = unknown>(cb: (data: T) => void): () => void;\n  getTheme(): SynapseUITheme;\n  onTheme(cb: (theme: SynapseUITheme) => void): () => void;\n  callTool<O = unknown>(name: string, args?: Record<string, unknown>): Promise<O>;\n  sendPrompt(text: string): void;\n  openLink(url: string): void;\n  resize(height?: number): void;\n  capabilities(): HostCapabilities;\n  /** Begin listening / send the ready handshake / read baked-in data. Called once\n   *  by `connectUI` synchronously so `getData()` is populated on return. */\n  start(): void;\n  destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Wire constants — the bridge message shapes. Centralized so a\n// host protocol tweak is a one-line change, not a grep-and-pray.\n// ---------------------------------------------------------------------------\n\n/** Default `id` of the baked-in data `<script type=\"application/json\">`. */\nexport const SYNAPSE_DATA_ELEMENT_ID = \"synapse-ui-data\";\n\n// ---------------------------------------------------------------------------\n// MCP Apps standard (SEP-1865) — the bridge every framing host speaks. The View iframe is an MCP client and the\n// host an MCP server; they exchange raw JSON-RPC 2.0 objects over `postMessage`\n// (no wrapper envelope). Method names are canonical to the ext-apps spec.\n// ---------------------------------------------------------------------------\n\n/** Protocol version exchanged in the `ui/initialize` handshake. */\nexport const MCPAPP_PROTOCOL_VERSION = \"2026-01-26\";\n/** View → host handshake request; the result carries the host context. */\nexport const MCPAPP_INITIALIZE = \"ui/initialize\";\n/** View → host notification sent once after the init result — the host holds all\n *  pushes until it arrives. */\nexport const MCPAPP_INITIALIZED = \"ui/notifications/initialized\";\n/** Host → view notification carrying the tool output. `params` IS the\n *  `CallToolResult` (data at `params.structuredContent`) — no `result` wrapper. */\nexport const MCPAPP_TOOL_RESULT = \"ui/notifications/tool-result\";\n/** Host → view notification carrying a partial host context (theme, styles, …). */\nexport const MCPAPP_HOST_CONTEXT_CHANGED = \"ui/notifications/host-context-changed\";\n/** View → host notification reporting intrinsic size (`{ width?, height? }`). A\n *  host may keep the frame hidden until it receives one, so it is sent promptly. */\nexport const MCPAPP_SIZE_CHANGED = \"ui/notifications/size-changed\";\n/** View → host request: open an external URL (`{ url }`). */\nexport const MCPAPP_OPEN_LINK = \"ui/open-link\";\n/** View → host request: send a follow-up to the conversation\n *  (`{ role: \"user\", content: ContentBlock[] }`). */\nexport const MCPAPP_MESSAGE = \"ui/message\";\n/** Host → view request: graceful teardown; the view replies `{}`. */\nexport const MCPAPP_TEARDOWN = \"ui/resource-teardown\";\n/** Standard MCP method the View may call over the same channel (pull). */\nexport const MCP_TOOLS_CALL = \"tools/call\";\n","/**\n * Read data baked into the HTML as `<script type=\"application/json\" id=…>`.\n *\n * This is how a server delivers tool output with no round-trip, for first paint\n * and for a standalone render: the server helper escapes the payload\n * and substitutes it into the element (see the Python `SynapseUI.render_html`).\n * A data-free template leaves the marker comment in place, which fails\n * `JSON.parse` and reads back as `null` — exactly the \"no data yet\" state.\n */\nexport function readInlineData<T = unknown>(\n  doc: Document | undefined,\n  elementId: string,\n): T | null {\n  if (!doc) return null;\n  const el = doc.getElementById(elementId);\n  const text = el?.textContent;\n  if (!text) return null;\n  try {\n    const parsed = JSON.parse(text);\n    return (parsed ?? null) as T | null;\n  } catch {\n    // Unreplaced marker or malformed blob — treat as no data.\n    return null;\n  }\n}\n","import { readInlineData } from \"../data.js\";\nimport { coerceMode, preferredMode } from \"../theme.js\";\nimport {\n  type ConnectUIOptions,\n  type HostAdapter,\n  type HostCapabilities,\n  HostUnsupportedError,\n  SYNAPSE_DATA_ELEMENT_ID,\n  type SynapseUITheme,\n} from \"../types.js\";\n\n/**\n * Inline / standalone fallback adapter.\n *\n * No live host bridge — used for SSR, previews, and a plain browser render. Data\n * comes only from the baked-in `<script type=\"application/json\">` blob; there is\n * nothing to push, so `onData` never fires after `start()`. Theme follows the OS\n * color scheme and tracks `prefers-color-scheme` changes. `openLink` opens a new\n * tab; `sendPrompt`/`callTool` have no destination.\n */\nexport function createInlineAdapter(\n  win: Window & typeof globalThis,\n  options: ConnectUIOptions,\n): HostAdapter {\n  const dataElementId = options.dataElementId ?? SYNAPSE_DATA_ELEMENT_ID;\n\n  let currentData: unknown = null;\n  let currentTheme: SynapseUITheme = { mode: preferredMode(win), tokens: {} };\n\n  const themeCbs = new Set<(t: SynapseUITheme) => void>();\n  let destroyed = false;\n  let media: MediaQueryList | null = null;\n\n  const onSchemeChange = (event: MediaQueryListEvent) => {\n    if (destroyed) return;\n    const mode = coerceMode(event.matches ? \"dark\" : \"light\", currentTheme.mode);\n    if (mode === currentTheme.mode) return;\n    currentTheme = { mode, tokens: {} };\n    for (const cb of themeCbs) cb(currentTheme);\n  };\n\n  return {\n    host: \"generic\",\n    getData: <T>() => currentData as T | null,\n    onData() {\n      // Static render — no updates after the initial baked-in read.\n      return () => {};\n    },\n    getTheme: () => currentTheme,\n    onTheme(cb) {\n      themeCbs.add(cb);\n      return () => themeCbs.delete(cb);\n    },\n    async callTool<O>(_name: string): Promise<O> {\n      throw new HostUnsupportedError(\"callTool\", \"generic\");\n    },\n    sendPrompt() {\n      // No agent to reach in a standalone render.\n    },\n    openLink(url: string) {\n      win.open(url, \"_blank\", \"noopener,noreferrer\");\n    },\n    resize() {\n      // No host to size for.\n    },\n    capabilities(): HostCapabilities {\n      return { pull: false, sendPrompt: false, openLink: true };\n    },\n    start() {\n      currentData = readInlineData(win.document, dataElementId);\n      try {\n        media = win.matchMedia?.(\"(prefers-color-scheme: dark)\") ?? null;\n        media?.addEventListener?.(\"change\", onSchemeChange);\n      } catch {\n        media = null;\n      }\n    },\n    destroy() {\n      if (destroyed) return;\n      destroyed = true;\n      media?.removeEventListener?.(\"change\", onSchemeChange);\n      media = null;\n      themeCbs.clear();\n    },\n  };\n}\n","// `detection` is type-only against `@modelcontextprotocol/*`, so importing it\n// keeps this adapter free of the ext-apps runtime (and Zod) that the lean\n// `window.SynapseUI` IIFE deliberately excludes.\nimport { extractHostFontCss } from \"../../detection.js\";\nimport { readInlineData } from \"../data.js\";\nimport { coerceMode, injectHostFonts, preferredMode } from \"../theme.js\";\nimport {\n  type ConnectUIOptions,\n  type HostAdapter,\n  type HostCapabilities,\n  MCP_TOOLS_CALL,\n  MCPAPP_HOST_CONTEXT_CHANGED,\n  MCPAPP_INITIALIZE,\n  MCPAPP_INITIALIZED,\n  MCPAPP_MESSAGE,\n  MCPAPP_OPEN_LINK,\n  MCPAPP_PROTOCOL_VERSION,\n  MCPAPP_SIZE_CHANGED,\n  MCPAPP_TEARDOWN,\n  MCPAPP_TOOL_RESULT,\n  SYNAPSE_DATA_ELEMENT_ID,\n  type SynapseUITheme,\n} from \"../types.js\";\n\n/** How long a widget→host request (`callTool`, `openLink`, `sendPrompt`) waits\n *  for its response before rejecting, so a silent host never hangs a promise. */\nconst REQUEST_TIMEOUT_MS = 30_000;\n\ninterface PendingRequest {\n  resolve: (value: unknown) => void;\n  reject: (reason: unknown) => void;\n  timer: ReturnType<typeof setTimeout>;\n}\n\n/**\n * MCP Apps standard (SEP-1865) adapter — the bridge for every framed host.\n * ChatGPT, Claude and NimbleBrain all implement the standard, so there is one.\n *\n * The View iframe is an MCP client speaking JSON-RPC 2.0 to `window.parent`:\n *\n *  1. posts `ui/initialize` and awaits the host context (theme, style variables);\n *  2. posts `ui/notifications/initialized`, then a `size-changed` — a host keeps\n *     the frame hidden until it has both the handshake and a size;\n *  3. receives data via `ui/notifications/tool-result` (`params` IS the\n *     `CallToolResult`, so data is at `params.structuredContent`) and theme via\n *     `ui/notifications/host-context-changed`.\n *\n * Actions go up as requests: `ui/open-link`, `ui/message` (follow-up), and\n * `tools/call` (pull).\n */\nexport function createMcpAppsAdapter(\n  win: Window & typeof globalThis,\n  options: ConnectUIOptions,\n): HostAdapter {\n  const dataElementId = options.dataElementId ?? SYNAPSE_DATA_ELEMENT_ID;\n  const autoResize = options.autoResize !== false;\n\n  let currentData: unknown = null;\n  let currentTheme: SynapseUITheme = { mode: preferredMode(win), tokens: {} };\n\n  const dataCbs = new Set<(d: unknown) => void>();\n  const themeCbs = new Set<(t: SynapseUITheme) => void>();\n  let destroyed = false;\n  // Set once the host has answered `ui/initialize` and been told `initialized`.\n  let initialized = false;\n  let nextId = 1;\n  const pending = new Map<number, PendingRequest>();\n  let lastReportedHeight = -1;\n  let resizeObserver: ResizeObserver | null = null;\n  let onWindowResize: (() => void) | null = null;\n\n  const parent = () => win.parent ?? win;\n\n  function post(message: Record<string, unknown>): void {\n    parent().postMessage(message, \"*\");\n  }\n\n  function notify(method: string, params?: Record<string, unknown>): void {\n    post({ jsonrpc: \"2.0\", method, params: params ?? {} });\n  }\n\n  function request<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T> {\n    const id = nextId++;\n    return new Promise<T>((resolve, reject) => {\n      const timer = setTimeout(() => {\n        pending.delete(id);\n        reject(new Error(`\"${method}\" timed out`));\n      }, REQUEST_TIMEOUT_MS);\n      pending.set(id, { resolve: resolve as (v: unknown) => void, reject, timer });\n      post({ jsonrpc: \"2.0\", id, method, params: params ?? {} });\n    });\n  }\n\n  function emitData(next: unknown): void {\n    if (next == null) return;\n    currentData = next;\n    for (const cb of dataCbs) cb(next);\n  }\n\n  /** Merge a full or partial host context into the resolved theme (mode, tokens),\n   *  and load the host's `@font-face` CSS from the spec's `styles.css.fonts`. */\n  function applyHostContext(ctx: Record<string, unknown> | null | undefined): void {\n    if (!ctx || typeof ctx !== \"object\") return;\n    const fontCss = extractHostFontCss(ctx);\n    if (fontCss !== undefined) injectHostFonts(fontCss);\n    let { mode, tokens } = currentTheme;\n    let changed = false;\n    if (ctx.theme != null) {\n      const next = coerceMode(ctx.theme, mode);\n      if (next !== mode) {\n        mode = next;\n        changed = true;\n      }\n    }\n    const styles = ctx.styles as { variables?: Record<string, string> } | undefined;\n    if (styles?.variables && typeof styles.variables === \"object\") {\n      tokens = { ...tokens, ...styles.variables };\n      changed = true;\n    }\n    if (changed) {\n      currentTheme = { mode, tokens };\n      for (const cb of themeCbs) cb(currentTheme);\n    }\n  }\n\n  function reportSize(height?: number): void {\n    // `ui/initialize` is the app's first word on this bridge, and a strict host\n    // drops anything that arrives before it — leaving the frame hidden. The\n    // handshake reports a size as soon as it completes, so nothing is lost.\n    if (destroyed || !initialized) return;\n    const h = typeof height === \"number\" ? height : Math.ceil(win.document.body.scrollHeight);\n    if (h === lastReportedHeight) return;\n    lastReportedHeight = h;\n    notify(MCPAPP_SIZE_CHANGED, { height: h });\n  }\n\n  function handleResponse(d: Record<string, unknown>): void {\n    // Normalize the echoed id: JSON-RPC requires a same-type echo, but a lax host\n    // that returned \"1\" for 1 would otherwise miss the numeric-keyed pending map.\n    const id = Number(d.id);\n    const p = pending.get(id);\n    if (!p) return;\n    pending.delete(id);\n    clearTimeout(p.timer);\n    if (d.error != null) {\n      const err = d.error as { message?: string };\n      p.reject(new Error(err.message ?? \"request failed\"));\n    } else {\n      p.resolve(d.result);\n    }\n  }\n\n  function handleNotification(method: string, params: Record<string, unknown>): void {\n    if (method === MCPAPP_TOOL_RESULT) {\n      // `params` is the CallToolResult: the render data lives at structuredContent.\n      const structured = params.structuredContent;\n      emitData(structured != null ? structured : params);\n    } else if (method === MCPAPP_HOST_CONTEXT_CHANGED) {\n      applyHostContext(params);\n    }\n  }\n\n  function handleRequest(d: Record<string, unknown>): void {\n    // The one host→view request we honor: acknowledge teardown so the host can\n    // dispose the frame cleanly.\n    if (d.method === MCPAPP_TEARDOWN) {\n      post({ jsonrpc: \"2.0\", id: d.id, result: {} });\n    }\n  }\n\n  const onMessage = (event: MessageEvent) => {\n    if (destroyed) return;\n    // Accept only frames from the host window when the browser sets a source.\n    if (event.source && event.source !== parent()) return;\n    const d = event.data as Record<string, unknown> | null | undefined;\n    if (!d || typeof d !== \"object\" || d.jsonrpc !== \"2.0\") return;\n    if (d.id != null && (\"result\" in d || \"error\" in d)) {\n      handleResponse(d);\n    } else if (typeof d.method === \"string\") {\n      if (d.id != null) handleRequest(d);\n      else handleNotification(d.method, (d.params ?? {}) as Record<string, unknown>);\n    }\n  };\n\n  function setupResize(): void {\n    onWindowResize = () => reportSize();\n    win.addEventListener(\"resize\", onWindowResize);\n    if (typeof win.ResizeObserver !== \"undefined\") {\n      resizeObserver = new win.ResizeObserver(() => reportSize());\n      resizeObserver.observe(win.document.body);\n    }\n  }\n\n  return {\n    host: \"mcp-apps\",\n    getData: <T>() => currentData as T | null,\n    onData(cb) {\n      dataCbs.add(cb as (d: unknown) => void);\n      return () => dataCbs.delete(cb as (d: unknown) => void);\n    },\n    getTheme: () => currentTheme,\n    onTheme(cb) {\n      themeCbs.add(cb);\n      return () => themeCbs.delete(cb);\n    },\n    async callTool<O>(name: string, args?: Record<string, unknown>): Promise<O> {\n      return (await request(MCP_TOOLS_CALL, { name, arguments: args ?? {} })) as O;\n    },\n    sendPrompt(text: string) {\n      void request(MCPAPP_MESSAGE, { role: \"user\", content: [{ type: \"text\", text }] }).catch(\n        () => {},\n      );\n    },\n    openLink(url: string) {\n      void request(MCPAPP_OPEN_LINK, { url }).catch(() => {});\n    },\n    resize(height?: number) {\n      reportSize(height);\n    },\n    capabilities(): HostCapabilities {\n      // An MCP Apps host answers `tools/call`, `ui/message` and `ui/open-link`\n      // over this bridge.\n      return { pull: true, sendPrompt: true, openLink: true };\n    },\n    start() {\n      win.addEventListener(\"message\", onMessage as EventListener);\n\n      // Baked-in data → available on first paint, before the handshake resolves.\n      currentData = readInlineData(win.document, dataElementId);\n\n      if (autoResize) setupResize();\n\n      request<{ hostContext?: Record<string, unknown> }>(MCPAPP_INITIALIZE, {\n        appInfo: { name: options.name ?? \"synapse-ui\", version: options.version ?? \"0.0.0\" },\n        appCapabilities: { availableDisplayModes: [\"inline\"] },\n        protocolVersion: MCPAPP_PROTOCOL_VERSION,\n      })\n        .then((result) => {\n          if (destroyed) return;\n          applyHostContext(result?.hostContext);\n          notify(MCPAPP_INITIALIZED, {});\n          initialized = true;\n          // A host keeps the frame hidden until it gets a size after init, and\n          // this is the first point at which sending one is allowed.\n          reportSize();\n        })\n        .catch(() => {\n          // The parent never answered: it is not an MCP Apps host, and nothing\n          // reaches the component over this bridge. Baked-in data still renders.\n        });\n    },\n    destroy() {\n      if (destroyed) return;\n      destroyed = true;\n      win.removeEventListener(\"message\", onMessage as EventListener);\n      if (onWindowResize) win.removeEventListener(\"resize\", onWindowResize);\n      onWindowResize = null;\n      resizeObserver?.disconnect();\n      resizeObserver = null;\n      for (const p of pending.values()) {\n        clearTimeout(p.timer);\n        p.reject(new Error(\"adapter destroyed\"));\n      }\n      pending.clear();\n      dataCbs.clear();\n      themeCbs.clear();\n    },\n  };\n}\n","import { createInlineAdapter } from \"./adapters/inline.js\";\nimport { createMcpAppsAdapter } from \"./adapters/mcpapps.js\";\nimport type { ConnectUIOptions, HostAdapter, HostKind } from \"./types.js\";\n\n/**\n * Minimal window shape the detector inspects. Kept structural so detection is\n * unit-testable with a plain object — no full `Window` fake required.\n */\ninterface DetectableWindow {\n  parent?: unknown;\n}\n\n/**\n * Detect the bridge from the browsing context.\n *\n *  - a nested browsing context (`parent !== self`, or a cross-origin access that\n *    throws) → **mcp-apps**: every host that frames a component speaks the MCP\n *    Apps standard.\n *  - top-level document → **generic** (inline / standalone).\n *\n * Nothing on the window names the host. `window.openai` in particular does not:\n * ChatGPT injects it into every frame it serves, whatever the component is.\n * Which host answered is in the handshake, not here.\n */\nexport function detectHostKind(win: DetectableWindow): HostKind {\n  try {\n    if (win.parent != null && win.parent !== win) return \"mcp-apps\";\n  } catch {\n    // Cross-origin parent access throws → we are framed by another origin.\n    return \"mcp-apps\";\n  }\n  return \"generic\";\n}\n\n/** Build the adapter for an explicit host kind (`options.host` or a detected one). */\nexport function adapterForKind(\n  kind: HostKind,\n  win: Window & typeof globalThis,\n  options: ConnectUIOptions,\n): HostAdapter {\n  if (kind === \"mcp-apps\") return createMcpAppsAdapter(win, options);\n  if (kind === \"generic\") return createInlineAdapter(win, options);\n  // A script-tag caller has no compiler to reject a value outside `HostKind`, and\n  // treating one as standalone inside a frame sends no handshake: the host keeps\n  // the frame hidden and the component is blank with nothing to say why.\n  throw new TypeError(`unknown host \"${String(kind)}\": expected \"mcp-apps\" or \"generic\"`);\n}\n\n/** Select and construct the host adapter, honoring `options.host` when set. */\nexport function selectAdapter(\n  win: Window & typeof globalThis,\n  options: ConnectUIOptions,\n): HostAdapter {\n  const kind = options.host ?? detectHostKind(win as unknown as DetectableWindow);\n  return adapterForKind(kind, win, options);\n}\n","import { selectAdapter } from \"./detect.js\";\nimport { applyHostTheme } from \"./theme.js\";\nimport {\n  type ConnectUIOptions,\n  isToolError,\n  type SynapseUIClient,\n  ToolCallError,\n} from \"./types.js\";\n\n/**\n * Connect a Synapse-authored component to whatever host it renders in — any MCP\n * Apps host, or a plain/standalone page — behind one push-first API. Detects\n * whether it is framed, selects an adapter, and applies the\n * host theme to the DOM before returning.\n *\n * Synchronous: `data()` is populated from baked-in data (where present) on\n * return, and pushed updates arrive via `onData`. Bind the result to `synapse`:\n *\n * ```ts\n * const synapse = connectUI({ name: \"my-widget\", version: \"1.0.0\" });\n * synapse.onData(render);        // future pushes/updates\n * render(synapse.data());        // current value (null → empty state)\n * ```\n */\nexport function connectUI(options: ConnectUIOptions = {}): SynapseUIClient {\n  const win = options.window ?? (globalThis as unknown as Window & typeof globalThis);\n  const adapter = selectAdapter(win, options);\n\n  // The client owns theme application: adapters resolve mode/tokens; this puts\n  // them on the DOM (data-theme + CSS vars) so apps never wire theme by hand.\n  applyHostTheme(adapter.getTheme());\n  const unsubTheme = adapter.onTheme(applyHostTheme);\n\n  adapter.start();\n\n  let destroyed = false;\n\n  return {\n    data: <T>() => adapter.getData<T>(),\n    onData: <T>(cb: (data: T) => void) => adapter.onData<T>(cb),\n    theme: () => adapter.getTheme(),\n    onTheme: (cb) => adapter.onTheme(cb),\n    // Decided here rather than per adapter: every host reports a failed or\n    // refused call inside the result, because that is how MCP defines one.\n    async callTool<O>(name: string, args?: Record<string, unknown>): Promise<O> {\n      const result = await adapter.callTool<O>(name, args);\n      if (isToolError(result)) throw new ToolCallError(name, result);\n      return result;\n    },\n    sendPrompt: (text: string) => adapter.sendPrompt(text),\n    openLink: (url: string) => adapter.openLink(url),\n    resize: (height?: number) => adapter.resize(height),\n    capabilities: () => adapter.capabilities(),\n    host: () => adapter.host,\n    destroy() {\n      if (destroyed) return;\n      destroyed = true;\n      unsubTheme();\n      adapter.destroy();\n    },\n  };\n}\n"]}