@nimblebrain/synapse 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -4
- package/dist/{chunk-JVKQNMAP.js → chunk-5AR3IROW.js} +11 -6
- package/dist/chunk-5AR3IROW.js.map +1 -0
- package/dist/{chunk-XGJAADVV.js → chunk-AGN3NDOK.js} +25 -36
- package/dist/chunk-AGN3NDOK.js.map +1 -0
- package/dist/chunk-DOKVNVTI.js +162 -0
- package/dist/chunk-DOKVNVTI.js.map +1 -0
- package/dist/chunk-IA2M4GTK.cjs +170 -0
- package/dist/chunk-IA2M4GTK.cjs.map +1 -0
- package/dist/{chunk-A4ENX6XW.cjs → chunk-QHS7BJLI.cjs} +28 -39
- package/dist/chunk-QHS7BJLI.cjs.map +1 -0
- package/dist/{chunk-ANUZ7WFQ.cjs → chunk-VMUZMVKW.cjs} +11 -6
- package/dist/chunk-VMUZMVKW.cjs.map +1 -0
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/connect.iife.global.js +25 -25
- package/dist/{detect-DSnLT-_m.d.ts → detect-C_qmYsh9.d.cts} +6 -0
- package/dist/{detect-DSnLT-_m.d.cts → detect-Dfd0upoz.d.ts} +6 -0
- package/dist/host/index.cjs +14 -14
- package/dist/host/index.d.cts +10 -3
- package/dist/host/index.d.ts +10 -3
- package/dist/host/index.js +2 -2
- package/dist/index.cjs +13 -9
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +3 -3
- package/dist/react/index.cjs +5 -5
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +3 -3
- package/dist/react/index.js.map +1 -1
- package/dist/synapse-runtime.iife.global.js +25 -25
- package/dist/synapse-ui.iife.global.js +1 -1
- package/dist/{types-C9utGXv_.d.cts → types-BSZasM8q.d.cts} +39 -1
- package/dist/{types-C9utGXv_.d.ts → types-BSZasM8q.d.ts} +39 -1
- package/dist/ui/index.cjs +34 -1
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +34 -1
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -6
- package/dist/chunk-A4ENX6XW.cjs.map +0 -1
- package/dist/chunk-ANUZ7WFQ.cjs.map +0 -1
- package/dist/chunk-JVKQNMAP.js.map +0 -1
- package/dist/chunk-KTXASIFJ.cjs +0 -75
- package/dist/chunk-KTXASIFJ.cjs.map +0 -1
- package/dist/chunk-VXTMI266.js +0 -73
- package/dist/chunk-VXTMI266.js.map +0 -1
- package/dist/chunk-XGJAADVV.js.map +0 -1
- package/dist/ui/fonts.cjs +0 -19
- package/dist/ui/fonts.cjs.map +0 -1
- package/dist/ui/fonts.d.cts +0 -30
- package/dist/ui/fonts.d.ts +0 -30
- package/dist/ui/fonts.js +0 -17
- package/dist/ui/fonts.js.map +0 -1
package/README.md
CHANGED
|
@@ -48,7 +48,6 @@ component rendered across ChatGPT, Claude, and NimbleBrain — ships as the
|
|
|
48
48
|
| `@nimblebrain/synapse` | Vanilla JS core — `connect()`, `createSynapse()`, `createStore()` |
|
|
49
49
|
| `@nimblebrain/synapse/react` | React hooks and providers (`AppProvider`, `SynapseProvider`) |
|
|
50
50
|
| `@nimblebrain/synapse/ui` | Component library — tokens, primitives, components, layouts |
|
|
51
|
-
| `@nimblebrain/synapse/ui/fonts` | Side-effect import that loads the brand fonts into the iframe |
|
|
52
51
|
| `@nimblebrain/synapse/ui/base` | Side-effect import that establishes the root-height chain (`html, body, #root`) the app shell fills. `AppFrame` does this automatically on render; import it in your entry to apply it before first paint |
|
|
53
52
|
| `@nimblebrain/synapse/vite` | Vite plugin for dev mode |
|
|
54
53
|
| `@nimblebrain/synapse/codegen` | CLI + programmatic code generation |
|
|
@@ -67,9 +66,14 @@ every token and component in light/dark across several themes.
|
|
|
67
66
|
These are the durable decisions behind the library; they rarely change.
|
|
68
67
|
|
|
69
68
|
- **The library holds no brand.** Tokens are `var(--token, neutral-fallback)`
|
|
70
|
-
references, not hex values. The host injects the real palette
|
|
69
|
+
references, not hex values. The host injects the real palette at runtime
|
|
71
70
|
(the MCP ext-apps `hostContext.styles.variables`), so the same app adopts
|
|
72
71
|
whatever host it runs in. Standalone, it renders in neutral fallbacks.
|
|
72
|
+
- **That includes typography — the SDK ships no fonts.** Font fallbacks are
|
|
73
|
+
web-safe system stacks, so an app renders correctly with no host, no network,
|
|
74
|
+
and no font files. A host that wants its own typeface sends `@font-face`
|
|
75
|
+
descriptors on the theme; the library fetches nothing on its own. See
|
|
76
|
+
[Host fonts](#host-fonts).
|
|
73
77
|
- **Theme via CSS, not React.** Components style with token-driven inline-style
|
|
74
78
|
objects whose values are those `var()` refs, so theming — including light/dark —
|
|
75
79
|
resolves in CSS with no re-render. `ensureStyle` injects keyframes and
|
|
@@ -82,8 +86,58 @@ These are the durable decisions behind the library; they rarely change.
|
|
|
82
86
|
- **Responsive to the pane, not the device.** Layouts observe their own width
|
|
83
87
|
(`ResizeObserver` via `useBreakpoint`), because an app's iframe may be
|
|
84
88
|
fullscreen, split, or a narrow rail regardless of screen size.
|
|
85
|
-
- **
|
|
86
|
-
|
|
89
|
+
- **Sandbox-safe overlays.** `Drawer` is a plain `<div>` overlay, not a native
|
|
90
|
+
`<dialog>`: the app iframe withholds `allow-modals`, so `<dialog>.showModal()`
|
|
91
|
+
throws there. The scrim, Tab focus trap, focus-in/restore, scroll-lock, and
|
|
92
|
+
Escape are hand-rolled.
|
|
93
|
+
|
|
94
|
+
### Host fonts
|
|
95
|
+
|
|
96
|
+
A CSS custom property can *name* a font family but cannot *load* one, and an app
|
|
97
|
+
iframe is its own document — it inherits no `@font-face` from the host page. So a
|
|
98
|
+
host that sends only tokens is naming a typeface the app has no way to render.
|
|
99
|
+
`SynapseTheme.fontFaces` closes that gap: the host sends the faces alongside the
|
|
100
|
+
tokens, and the SDK loads them into the app document.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// Host side — sent as the `synapse/fontFaces` host-context extension.
|
|
104
|
+
{
|
|
105
|
+
mode: "dark",
|
|
106
|
+
tokens: { "--font-sans": "'Your Sans', system-ui, sans-serif" },
|
|
107
|
+
fontFaces: [
|
|
108
|
+
{ family: "Your Sans", src: "url('/fonts/your-sans.woff2') format('woff2')", weight: "400 700" },
|
|
109
|
+
],
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Field | Notes |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `family` | Must match the family named in the host's `--font-*` token value. |
|
|
116
|
+
| `src` | Any CSS `src` descriptor — relative (`url('/fonts/x.woff2')`), absolute (`url('https://cdn.example/x.woff2')`), or `data:`. |
|
|
117
|
+
| `weight` | Single weight (`400`) or a variable range (`400 700`). Optional. |
|
|
118
|
+
| `style` | `normal`, `italic`, … Optional. |
|
|
119
|
+
| `display` | Defaults to `swap`, so text paints in the fallback rather than blocking. Optional. |
|
|
120
|
+
|
|
121
|
+
Three things worth knowing:
|
|
122
|
+
|
|
123
|
+
- **Sending no fonts is a supported configuration, not a degraded one.** Omit
|
|
124
|
+
`fontFaces` and the app renders in the web-safe fallbacks (`system-ui`,
|
|
125
|
+
`ui-monospace`, `Georgia`).
|
|
126
|
+
- **Give every `--font-*` token value a web-safe tail.** A bare family name with
|
|
127
|
+
no matching face falls through to the browser default, not to your intended
|
|
128
|
+
stack. `"'Your Sans', system-ui, sans-serif"`, never `"'Your Sans'"`.
|
|
129
|
+
- **The URL must satisfy the app iframe's CSP — and `'self'` may not mean what
|
|
130
|
+
you expect.** A host that mounts apps in a `srcdoc` iframe *without*
|
|
131
|
+
`allow-same-origin` (the usual choice, since granting it to third-party app
|
|
132
|
+
HTML is a sandbox escape) gives the frame an **opaque origin**, and CSP
|
|
133
|
+
`'self'` then matches nothing. Under a typical `font-src 'self' data:`, a
|
|
134
|
+
`data:` URI is the only form that works unconditionally; any http(s) URL —
|
|
135
|
+
self-hosted or CDN — needs the host to add that origin to the frame's CSP.
|
|
136
|
+
Check the host's policy before choosing between them.
|
|
137
|
+
|
|
138
|
+
Faces are applied through the same funnel as the token variables
|
|
139
|
+
(`applyTheme`), so a theme change can never leave an app with the host's palette
|
|
140
|
+
under the wrong typeface.
|
|
87
141
|
|
|
88
142
|
## Quick Start
|
|
89
143
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { applyTheme, foldFontFaces, fontFacesKey } from './chunk-DOKVNVTI.js';
|
|
2
2
|
|
|
3
3
|
// src/host/theme.ts
|
|
4
4
|
function applyHostTheme(theme) {
|
|
5
5
|
if (typeof document !== "undefined") {
|
|
6
6
|
document.documentElement.setAttribute("data-theme", theme.mode);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
applyTheme(theme.mode, theme.tokens, theme.fontFaces);
|
|
9
9
|
}
|
|
10
10
|
function preferredMode(win) {
|
|
11
11
|
try {
|
|
@@ -248,7 +248,7 @@ function createMcpAppsAdapter(win, options) {
|
|
|
248
248
|
}
|
|
249
249
|
function applyHostContext(ctx) {
|
|
250
250
|
if (!ctx || typeof ctx !== "object") return;
|
|
251
|
-
let { mode, tokens } = currentTheme;
|
|
251
|
+
let { mode, tokens, fontFaces } = currentTheme;
|
|
252
252
|
let changed = false;
|
|
253
253
|
if (ctx.theme != null) {
|
|
254
254
|
const next = coerceMode(ctx.theme, mode);
|
|
@@ -262,8 +262,13 @@ function createMcpAppsAdapter(win, options) {
|
|
|
262
262
|
tokens = { ...tokens, ...styles.variables };
|
|
263
263
|
changed = true;
|
|
264
264
|
}
|
|
265
|
+
const nextFaces = foldFontFaces(fontFaces, ctx);
|
|
266
|
+
if (fontFacesKey(nextFaces) !== fontFacesKey(fontFaces)) {
|
|
267
|
+
fontFaces = nextFaces;
|
|
268
|
+
changed = true;
|
|
269
|
+
}
|
|
265
270
|
if (changed) {
|
|
266
|
-
currentTheme = { mode, tokens };
|
|
271
|
+
currentTheme = { mode, tokens, ...fontFaces ? { fontFaces } : {} };
|
|
267
272
|
for (const cb of themeCbs) cb(currentTheme);
|
|
268
273
|
}
|
|
269
274
|
}
|
|
@@ -459,5 +464,5 @@ function connectUI(options = {}) {
|
|
|
459
464
|
}
|
|
460
465
|
|
|
461
466
|
export { HostUnsupportedError, SYNAPSE_DATA_ELEMENT_ID, adapterForKind, applyHostTheme, coerceMode, connectUI, createChatGPTAdapter, createInlineAdapter, createMcpAppsAdapter, detectHostKind, preferredMode, selectAdapter };
|
|
462
|
-
//# sourceMappingURL=chunk-
|
|
463
|
-
//# sourceMappingURL=chunk-
|
|
467
|
+
//# sourceMappingURL=chunk-5AR3IROW.js.map
|
|
468
|
+
//# sourceMappingURL=chunk-5AR3IROW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/host/theme.ts","../src/host/types.ts","../src/host/adapters/chatgpt.ts","../src/host/data.ts","../src/host/adapters/inline.ts","../src/host/adapters/mcpapps.ts","../src/host/detect.ts","../src/host/connect.ts"],"names":[],"mappings":"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","file":"chunk-5AR3IROW.js","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 (or a host that supplies\n * only a mode string, like the OpenAI Apps SDK, still themes correctly). SSR-safe.\n *\n * Any `fontFaces` the host supplies are loaded here too — a token can name a\n * family but not load it, so the two travel together. A host that sends none\n * leaves the web-safe fallbacks in force.\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, theme.fontFaces);\n}\n\n/** Read the OS-level color scheme as a sane default for hosts that don't push a\n * theme until later (mcp-ui) 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 * hosts that each speak a different bridge: ChatGPT (OpenAI Apps SDK), Claude\n * (mcp-ui), and plain/standalone. Apps code against `synapse.*` and never touch\n * a host protocol. 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 * ChatGPT / mcp-ui / inline bridges are pure `window.openai` + `postMessage`, so\n * the IIFE that apps inline stays tiny (no Zod, no ext-apps schemas).\n */\n\n/**\n * The host the client resolved to, as reported by `synapse.host()`. An escape\n * hatch — apps should rarely branch on it; `capabilities()` is the supported way\n * to feature-detect. `\"nimblebrain\"` is reserved for the runtime adapter (P3).\n */\nimport type { FontFaceDescriptor } from \"../types.js\";\n\nexport type HostKind = \"chatgpt\" | \"claude\" | \"nimblebrain\" | \"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 /** Font faces the host wants loaded. Absent where the host sends none, which\n * leaves the SDK's web-safe fallbacks in force. See `FontFaceDescriptor`. */\n fontFaces?: FontFaceDescriptor[];\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\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 * `\"claude\"` → MCP Apps standard adapter, `\"chatgpt\"` → OpenAI Apps adapter,\n * `\"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 mcp-ui / SSR 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-ui 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. Rejects with {@link HostUnsupportedError} where the\n * host advertises no pull (`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 each host speaks. 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/** mcp-ui iframe-lifecycle messages (child → host, host → child). */\nexport const MCPUI_READY = \"ui-lifecycle-iframe-ready\";\nexport const MCPUI_RENDER_DATA = \"ui-lifecycle-iframe-render-data\";\nexport const MCPUI_SIZE_CHANGE = \"ui-size-change\";\n/** mcp-ui action messages (child → host). */\nexport const MCPUI_LINK = \"link\";\nexport const MCPUI_PROMPT = \"prompt\";\n\n/** OpenAI Apps SDK globals-broadcast event (host → child). */\nexport const OPENAI_SET_GLOBALS = \"openai:set_globals\";\n\n// ---------------------------------------------------------------------------\n// MCP Apps standard (SEP-1865) — the convergence bridge, primary for Claude\n// Desktop and the NimbleBrain runtime. 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","import { coerceMode } from \"../theme.js\";\nimport {\n type ConnectUIOptions,\n type HostAdapter,\n type HostCapabilities,\n HostUnsupportedError,\n OPENAI_SET_GLOBALS,\n type SynapseUITheme,\n} from \"../types.js\";\n\n/**\n * The subset of the OpenAI Apps SDK `window.openai` surface this adapter uses.\n * All members are optional — the SDK version a host ships may not carry every\n * one, so each call is guarded and degraded.\n */\ninterface OpenAiHost {\n toolOutput?: unknown;\n theme?: unknown;\n callTool?: (name: string, args?: Record<string, unknown>) => Promise<unknown>;\n sendFollowUpMessage?: (arg: { prompt: string }) => void;\n /** Older casing seen in the wild — tried as a fallback. */\n sendFollowupMessage?: (arg: { prompt: string }) => void;\n openExternal?: (arg: { href: string }) => void;\n}\n\ninterface SetGlobalsDetail {\n globals?: { toolOutput?: unknown; theme?: unknown };\n}\n\n/**\n * ChatGPT (OpenAI Apps SDK) adapter.\n *\n * Data arrives on `window.openai.toolOutput` (available synchronously before the\n * widget script runs) and updates via the `openai:set_globals` event. Theme is a\n * mode string on the same surface. The host auto-sizes the iframe, so `resize()`\n * is a no-op. `callTool` is available when the host exposes `window.openai.callTool`.\n */\nexport function createChatGPTAdapter(\n win: Window & typeof globalThis,\n _options: ConnectUIOptions,\n): HostAdapter {\n const openai = () => (win as unknown as { openai?: OpenAiHost }).openai;\n\n let currentData: unknown = openai()?.toolOutput ?? null;\n let currentTheme: SynapseUITheme = {\n mode: coerceMode(openai()?.theme, \"light\"),\n tokens: {},\n };\n\n const dataCbs = new Set<(d: unknown) => void>();\n const themeCbs = new Set<(t: SynapseUITheme) => void>();\n let destroyed = false;\n\n const onSetGlobals = (event: Event) => {\n if (destroyed) return;\n const globals = (event as CustomEvent<SetGlobalsDetail>).detail?.globals;\n if (!globals) return;\n if (\"toolOutput\" in globals && globals.toolOutput != null) {\n currentData = globals.toolOutput;\n for (const cb of dataCbs) cb(currentData);\n }\n if (\"theme\" in globals && globals.theme != null) {\n const mode = coerceMode(globals.theme, currentTheme.mode);\n if (mode !== currentTheme.mode) {\n currentTheme = { mode, tokens: {} };\n for (const cb of themeCbs) cb(currentTheme);\n }\n }\n };\n\n return {\n host: \"chatgpt\",\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 const call = openai()?.callTool;\n if (!call) throw new HostUnsupportedError(\"callTool\", \"chatgpt\");\n return (await call(name, args ?? {})) as O;\n },\n sendPrompt(text: string) {\n const o = openai();\n const send = o?.sendFollowUpMessage ?? o?.sendFollowupMessage;\n send?.({ prompt: text });\n },\n openLink(url: string) {\n const open = openai()?.openExternal;\n if (open) open({ href: url });\n else win.open(url, \"_blank\", \"noopener,noreferrer\");\n },\n resize() {\n // ChatGPT auto-sizes the widget iframe — nothing to report.\n },\n capabilities(): HostCapabilities {\n const o = openai();\n return {\n pull: typeof o?.callTool === \"function\",\n sendPrompt:\n typeof o?.sendFollowUpMessage === \"function\" ||\n typeof o?.sendFollowupMessage === \"function\",\n openLink: true,\n };\n },\n start() {\n win.addEventListener(OPENAI_SET_GLOBALS, onSetGlobals as EventListener, { passive: true });\n // Re-read in case the host mutated globals between construction and start.\n currentData = openai()?.toolOutput ?? currentData;\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n win.removeEventListener(OPENAI_SET_GLOBALS, onSetGlobals as EventListener);\n dataCbs.clear();\n themeCbs.clear();\n },\n };\n}\n","/**\n * Read data baked into the HTML as `<script type=\"application/json\" id=…>`.\n *\n * This is how the mcp-ui embedded-resource path and SSR/standalone deliver the\n * pushed tool output with no round-trip: 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\n/**\n * Pull the app payload out of an arbitrary render-data envelope. Hosts wrap the\n * tool output differently (`renderData`, `toolOutput`, `structuredContent`, or\n * the bare object), so unwrap the known envelope keys, else pass the object\n * through. Kept framework-generic — no app-specific keys.\n */\nexport function unwrapRenderData<T = unknown>(payload: unknown): T | null {\n if (payload == null || typeof payload !== \"object\") return null;\n const rec = payload as Record<string, unknown>;\n const nested = rec.renderData;\n const source =\n nested != null && typeof nested === \"object\" ? (nested as Record<string, unknown>) : rec;\n if (source.toolOutput != null) return source.toolOutput as T;\n if (source.structuredContent != null) return source.structuredContent as T;\n // No bare `data` envelope key — too ambiguous with an app's own `data` field.\n return source as T;\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` and `theme-defaults` are type-only against `@modelcontextprotocol/*`,\n// so importing them keeps this adapter free of the ext-apps runtime (and Zod)\n// that the lean `window.SynapseUI` IIFE deliberately excludes.\nimport { foldFontFaces } from \"../../detection.js\";\nimport { fontFacesKey } from \"../../theme-defaults.js\";\nimport { readInlineData, unwrapRenderData } from \"../data.js\";\nimport { coerceMode, 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 MCPUI_LINK,\n MCPUI_PROMPT,\n MCPUI_READY,\n MCPUI_RENDER_DATA,\n MCPUI_SIZE_CHANGE,\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 convergence bridge for Claude\n * Desktop and other MCP Apps hosts.\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). The legacy mcp-ui `ui-lifecycle-*` messages are sent and\n * accepted alongside so a pre-standard host still renders — a standard host drops\n * the non-JSON-RPC frames, and a legacy host ignores the JSON-RPC ones.\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 `ui/initialize` resolves — proof we're on an MCP Apps standard host,\n // which lets us stop mirroring actions to the legacy shim.\n let standardConfirmed = 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 // The legacy mcp-ui frames (render-data in, size/link/prompt out) are a\n // transitional shim for the one host that still speaks it — the NimbleBrain\n // runtime, which shares this adapter via the `nimblebrain` kind until the P3\n // `nimblebrain` adapter lands and this shim is removed. Once the handshake\n // confirms a standard host we stop mirroring, so a host that understood both\n // dialects never acts on an action twice.\n function postLegacy(message: Record<string, unknown>): void {\n if (standardConfirmed) return;\n post(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 * font faces). Fonts ride the `synapse/fontFaces` extension: absent means\n * unchanged, an explicit (possibly empty) list replaces. ChatGPT supplies\n * only a mode string, so this is the adapter where host typography arrives. */\n function applyHostContext(ctx: Record<string, unknown> | null | undefined): void {\n if (!ctx || typeof ctx !== \"object\") return;\n let { mode, tokens, fontFaces } = 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 const nextFaces = foldFontFaces(fontFaces, ctx);\n if (fontFacesKey(nextFaces) !== fontFacesKey(fontFaces)) {\n fontFaces = nextFaces;\n changed = true;\n }\n if (changed) {\n currentTheme = { mode, tokens, ...(fontFaces ? { fontFaces } : {}) };\n for (const cb of themeCbs) cb(currentTheme);\n }\n }\n\n function reportSize(height?: number): void {\n if (destroyed) 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 postLegacy({ type: MCPUI_SIZE_CHANGE, payload: { 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 : unwrapRenderData(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 /** Legacy mcp-ui render-data (non-JSON-RPC) — a pre-standard host's data path. */\n function handleLegacy(d: Record<string, unknown>): void {\n if (d.type === MCPUI_RENDER_DATA || d.type === \"renderData\") {\n const { theme, ...rest } = (d.payload ?? {}) as Record<string, unknown>;\n if (theme != null) applyHostContext({ theme });\n if (Object.keys(rest).length > 0) emitData(unwrapRenderData(rest));\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\") return;\n if (d.jsonrpc !== \"2.0\") {\n handleLegacy(d);\n return;\n }\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: \"claude\",\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 // Standard follow-up (ack ignored); legacy mirror for a pre-standard host.\n void request(MCPAPP_MESSAGE, { role: \"user\", content: [{ type: \"text\", text }] }).catch(\n () => {},\n );\n postLegacy({ type: MCPUI_PROMPT, payload: { prompt: text } });\n },\n openLink(url: string) {\n void request(MCPAPP_OPEN_LINK, { url }).catch(() => {});\n postLegacy({ type: MCPUI_LINK, payload: { url } });\n },\n resize(height?: number) {\n reportSize(height);\n },\n capabilities(): HostCapabilities {\n // The MCP Apps standard host answers `tools/call` over this bridge, so pull\n // is advertised. A legacy-only host that shares this adapter (nimblebrain,\n // pre-P3) does not, so there callTool rejects only after REQUEST_TIMEOUT_MS\n // rather than failing fast.\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 // Legacy mcp-ui ready (a standard host drops this non-JSON-RPC frame).\n post({ type: MCPUI_READY });\n\n // MCP Apps standard handshake. A legacy-only host never answers, so the\n // legacy render-data path (handleLegacy) still feeds the widget.\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 standardConfirmed = true;\n applyHostContext(result?.hostContext);\n notify(MCPAPP_INITIALIZED, {});\n // A host keeps the frame hidden until it gets a size after init — force one.\n lastReportedHeight = -1;\n reportSize();\n })\n .catch(() => {\n // Not an MCP Apps host (or it was slow) — the legacy path covers data.\n });\n\n reportSize();\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 { createChatGPTAdapter } from \"./adapters/chatgpt.js\";\nimport { 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 openai?: unknown;\n parent?: unknown;\n self?: unknown;\n}\n\n/**\n * Feature-detect the host from the browsing context.\n *\n * - `window.openai` present → **chatgpt** (OpenAI Apps SDK).\n * - otherwise, a nested browsing context (`parent !== self`, or a cross-origin\n * access that throws) → **claude** (MCP Apps standard postMessage host).\n * - top-level document → **generic** (inline / standalone).\n *\n * Returns the host *kind*; `chooseAdapter` maps it to a concrete adapter and\n * honors an explicit `options.host` override for previews/SSR/tests.\n */\nexport function detectHostKind(win: DetectableWindow): HostKind {\n if (win.openai != null) return \"chatgpt\";\n try {\n if (win.parent != null && win.parent !== win) return \"claude\";\n } catch {\n // Cross-origin parent access throws → we are framed by another origin.\n return \"claude\";\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 switch (kind) {\n case \"chatgpt\":\n return createChatGPTAdapter(win, options);\n case \"claude\":\n case \"nimblebrain\":\n // Both speak the MCP Apps standard (SEP-1865). `nimblebrain` shares it for\n // now; a dedicated adapter over the `synapse/*` extension lands in P3.\n return createMcpAppsAdapter(win, options);\n default:\n return createInlineAdapter(win, options);\n }\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 type { ConnectUIOptions, SynapseUIClient } from \"./types.js\";\n\n/**\n * Connect a Synapse-authored component to whatever host it renders in — ChatGPT\n * (OpenAI Apps SDK), Claude (MCP Apps standard), or a plain/standalone page — behind one\n * push-first API. Feature-detects the host, 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 callTool: <O>(name: string, args?: Record<string, unknown>) => adapter.callTool<O>(name, args),\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"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { extractFontFaces, applyTheme, foldFontFaces, detectHost, extractTheme, fontFacesKey } from './chunk-DOKVNVTI.js';
|
|
2
2
|
import { INITIALIZE_METHOD, LATEST_PROTOCOL_VERSION, HOST_CONTEXT_CHANGED_METHOD, INITIALIZED_METHOD, MESSAGE_METHOD, OPEN_LINK_METHOD, TOOL_RESULT_METHOD, RESOURCE_TEARDOWN_METHOD, TOOL_CANCELLED_METHOD, TOOL_INPUT_PARTIAL_METHOD, TOOL_INPUT_METHOD } from '@modelcontextprotocol/ext-apps';
|
|
3
3
|
|
|
4
4
|
// src/content-parser.ts
|
|
@@ -252,9 +252,11 @@ async function connect(options) {
|
|
|
252
252
|
};
|
|
253
253
|
const ctx = result.hostContext;
|
|
254
254
|
if (ctx) {
|
|
255
|
+
const initialFontFaces = extractFontFaces(ctx);
|
|
255
256
|
currentTheme = {
|
|
256
257
|
mode: ctx.theme === "dark" ? "dark" : "light",
|
|
257
|
-
tokens: ctx.styles?.variables && typeof ctx.styles.variables === "object" ? ctx.styles.variables : {}
|
|
258
|
+
tokens: ctx.styles?.variables && typeof ctx.styles.variables === "object" ? ctx.styles.variables : {},
|
|
259
|
+
...initialFontFaces ? { fontFaces: initialFontFaces } : {}
|
|
258
260
|
};
|
|
259
261
|
if (ctx.toolInfo && typeof ctx.toolInfo === "object") {
|
|
260
262
|
toolInfo = { tool: ctx.toolInfo.tool ?? {} };
|
|
@@ -262,7 +264,7 @@ async function connect(options) {
|
|
|
262
264
|
if (ctx.containerDimensions && typeof ctx.containerDimensions === "object") {
|
|
263
265
|
containerDimensions = ctx.containerDimensions;
|
|
264
266
|
}
|
|
265
|
-
|
|
267
|
+
applyTheme(currentTheme.mode, currentTheme.tokens, currentTheme.fontFaces);
|
|
266
268
|
}
|
|
267
269
|
}
|
|
268
270
|
transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {
|
|
@@ -271,8 +273,9 @@ async function connect(options) {
|
|
|
271
273
|
const mode = ctx.theme === "dark" ? "dark" : "light";
|
|
272
274
|
const variables = ctx.styles?.variables;
|
|
273
275
|
const tokens = variables && typeof variables === "object" ? variables : currentTheme.tokens;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
+
const fontFaces = foldFontFaces(currentTheme.fontFaces, ctx);
|
|
277
|
+
currentTheme = { mode, tokens, ...fontFaces ? { fontFaces } : {} };
|
|
278
|
+
applyTheme(mode, tokens, fontFaces);
|
|
276
279
|
const set = handlers.get(HOST_CONTEXT_CHANGED_METHOD);
|
|
277
280
|
if (set) {
|
|
278
281
|
for (const handler of set) handler(currentTheme);
|
|
@@ -396,30 +399,6 @@ async function connect(options) {
|
|
|
396
399
|
return app;
|
|
397
400
|
}
|
|
398
401
|
|
|
399
|
-
// src/detection.ts
|
|
400
|
-
var DEFAULT_THEME = {
|
|
401
|
-
mode: "light",
|
|
402
|
-
primaryColor: "#6366f1",
|
|
403
|
-
tokens: {}
|
|
404
|
-
};
|
|
405
|
-
function detectHost(initResponse) {
|
|
406
|
-
const resp = initResponse;
|
|
407
|
-
const hostName = resp?.hostInfo?.name ?? "unknown";
|
|
408
|
-
const protocolVersion = resp?.protocolVersion ?? "unknown";
|
|
409
|
-
return {
|
|
410
|
-
isNimbleBrain: hostName === "nimblebrain",
|
|
411
|
-
serverName: hostName,
|
|
412
|
-
protocolVersion
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
function extractTheme(ctx) {
|
|
416
|
-
if (!ctx) return { ...DEFAULT_THEME };
|
|
417
|
-
const mode = ctx.theme === "light" || ctx.theme === "dark" ? ctx.theme : DEFAULT_THEME.mode;
|
|
418
|
-
const variables = ctx.styles?.variables;
|
|
419
|
-
const tokens = variables && typeof variables === "object" && !Array.isArray(variables) ? variables : {};
|
|
420
|
-
return { mode, primaryColor: DEFAULT_THEME.primaryColor, tokens };
|
|
421
|
-
}
|
|
422
|
-
|
|
423
402
|
// src/keyboard.ts
|
|
424
403
|
var KeyboardForwarder = class {
|
|
425
404
|
listener;
|
|
@@ -608,6 +587,15 @@ function createSynapse(options) {
|
|
|
608
587
|
const transport = new SynapseTransport();
|
|
609
588
|
let hostInfo = null;
|
|
610
589
|
let currentHostContext = {};
|
|
590
|
+
let currentFontFaces;
|
|
591
|
+
function syncFontFaces(ctx) {
|
|
592
|
+
currentFontFaces = foldFontFaces(currentFontFaces, ctx);
|
|
593
|
+
return currentFontFaces;
|
|
594
|
+
}
|
|
595
|
+
function resolveTheme(ctx) {
|
|
596
|
+
const theme = extractTheme(ctx);
|
|
597
|
+
return currentFontFaces ? { ...theme, fontFaces: currentFontFaces } : theme;
|
|
598
|
+
}
|
|
611
599
|
let hostTasksCapability = null;
|
|
612
600
|
let destroyed = false;
|
|
613
601
|
const taskStatusRouter = createTaskStatusRouter(transport);
|
|
@@ -632,7 +620,7 @@ function createSynapse(options) {
|
|
|
632
620
|
hostTasksCapability = rawTasks && typeof rawTasks === "object" && !Array.isArray(rawTasks) ? rawTasks : void 0;
|
|
633
621
|
{
|
|
634
622
|
const theme = extractTheme(currentHostContext);
|
|
635
|
-
|
|
623
|
+
applyTheme(theme.mode, theme.tokens, syncFontFaces(currentHostContext));
|
|
636
624
|
}
|
|
637
625
|
for (const cb of hostContextCallbacks) cb(currentHostContext);
|
|
638
626
|
transport.send(INITIALIZED_METHOD, {});
|
|
@@ -641,7 +629,7 @@ function createSynapse(options) {
|
|
|
641
629
|
const unsubHostContext = transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {
|
|
642
630
|
currentHostContext = params ?? {};
|
|
643
631
|
const theme = extractTheme(currentHostContext);
|
|
644
|
-
|
|
632
|
+
applyTheme(theme.mode, theme.tokens, syncFontFaces(currentHostContext));
|
|
645
633
|
for (const cb of hostContextCallbacks) cb(currentHostContext);
|
|
646
634
|
});
|
|
647
635
|
const hostContextCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -732,7 +720,7 @@ function createSynapse(options) {
|
|
|
732
720
|
};
|
|
733
721
|
},
|
|
734
722
|
getTheme() {
|
|
735
|
-
return
|
|
723
|
+
return resolveTheme(currentHostContext);
|
|
736
724
|
},
|
|
737
725
|
// Selector over `onHostContextChanged`: only fires when the *derived*
|
|
738
726
|
// theme actually changes, so theme subscribers don't see spurious
|
|
@@ -748,9 +736,9 @@ function createSynapse(options) {
|
|
|
748
736
|
// current derived theme, so a workspace-only `host-context-changed`
|
|
749
737
|
// notification correctly filters as a no-op.
|
|
750
738
|
onThemeChanged(callback) {
|
|
751
|
-
let prev = hostInfo !== null ?
|
|
739
|
+
let prev = hostInfo !== null ? resolveTheme(currentHostContext) : null;
|
|
752
740
|
const wrapped = (ctx) => {
|
|
753
|
-
const next =
|
|
741
|
+
const next = resolveTheme(ctx);
|
|
754
742
|
if (prev !== null && themesEqual(prev, next)) return;
|
|
755
743
|
prev = next;
|
|
756
744
|
callback(next);
|
|
@@ -868,6 +856,7 @@ function validateFileResult(value) {
|
|
|
868
856
|
}
|
|
869
857
|
function themesEqual(a, b) {
|
|
870
858
|
if (a.mode !== b.mode || a.primaryColor !== b.primaryColor) return false;
|
|
859
|
+
if (fontFacesKey(a.fontFaces) !== fontFacesKey(b.fontFaces)) return false;
|
|
871
860
|
const aKeys = Object.keys(a.tokens);
|
|
872
861
|
const bKeys = Object.keys(b.tokens);
|
|
873
862
|
if (aKeys.length !== bKeys.length) return false;
|
|
@@ -878,5 +867,5 @@ function themesEqual(a, b) {
|
|
|
878
867
|
}
|
|
879
868
|
|
|
880
869
|
export { connect, createSynapse };
|
|
881
|
-
//# sourceMappingURL=chunk-
|
|
882
|
-
//# sourceMappingURL=chunk-
|
|
870
|
+
//# sourceMappingURL=chunk-AGN3NDOK.js.map
|
|
871
|
+
//# sourceMappingURL=chunk-AGN3NDOK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/content-parser.ts","../src/event-map.ts","../src/resize.ts","../src/result-parser.ts","../src/transport.ts","../src/connect.ts","../src/keyboard.ts","../src/task-handle.ts","../src/core.ts"],"names":["HOST_CONTEXT_CHANGED_METHOD","TOOL_RESULT_METHOD","raw","READ_RESOURCE_METHOD","LATEST_PROTOCOL_VERSION","INITIALIZE_METHOD","INITIALIZED_METHOD","options","MESSAGE_METHOD","OPEN_LINK_METHOD"],"mappings":"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","file":"chunk-AGN3NDOK.js","sourcesContent":["import type { ToolResultData } from \"./types.js\";\n\nexport type { ToolResultData };\n\n/**\n * Parse inbound `ui/notifications/tool-result` notification params into\n * a consistent `ToolResultData` shape.\n *\n * Implements the 5-step parsing algorithm from the RFC:\n * 1. If `params.structuredContent` exists → use it as content.\n * 2. Else if `params.content` is an array of `{type:\"text\", text}` blocks →\n * join the text values and try JSON.parse.\n * 3. Else if `params.content` is a string → try JSON.parse.\n * 4. If JSON.parse fails in steps 2 or 3 → deliver the raw string.\n * 5. Return `{ content, structuredContent, raw }`.\n */\nexport function parseToolResultParams(params: Record<string, unknown> | undefined): ToolResultData {\n const raw = params ?? {};\n const structuredContent = raw.structuredContent ?? null;\n\n // Step 1: If structuredContent exists, use it as content\n if (structuredContent != null) {\n return { content: structuredContent, structuredContent, raw };\n }\n\n const rawContent = raw.content;\n\n // Step 2: If content is array of {type:\"text\", text} blocks, join texts and try JSON.parse\n if (Array.isArray(rawContent)) {\n const texts = rawContent\n .filter(\n (block: unknown) =>\n block != null &&\n typeof block === \"object\" &&\n (block as Record<string, unknown>).type === \"text\" &&\n typeof (block as Record<string, unknown>).text === \"string\",\n )\n .map((block: unknown) => (block as Record<string, unknown>).text as string);\n\n if (texts.length > 0) {\n const joined = texts.join(\"\");\n try {\n return { content: JSON.parse(joined), structuredContent: null, raw };\n } catch {\n return { content: joined, structuredContent: null, raw };\n }\n }\n\n // No text blocks — return raw content array\n return { content: rawContent, structuredContent: null, raw };\n }\n\n // Step 3: If content is string, try JSON.parse\n if (typeof rawContent === \"string\") {\n try {\n return { content: JSON.parse(rawContent), structuredContent: null, raw };\n } catch {\n return { content: rawContent, structuredContent: null, raw };\n }\n }\n\n // Fallback: return content as-is (could be null, object, etc.)\n return { content: rawContent ?? null, structuredContent: null, raw };\n}\n","import {\n HOST_CONTEXT_CHANGED_METHOD,\n RESOURCE_TEARDOWN_METHOD,\n TOOL_CANCELLED_METHOD,\n TOOL_INPUT_METHOD,\n TOOL_INPUT_PARTIAL_METHOD,\n TOOL_RESULT_METHOD,\n} from \"@modelcontextprotocol/ext-apps\";\n\n/**\n * Maps short event names used in App.on() to full MCP method names.\n * Uses canonical constants from @modelcontextprotocol/ext-apps to stay\n * in sync with the spec — if the spec changes a method name, this breaks\n * at compile time, not silently at runtime.\n */\nconst EVENT_MAP: Record<string, string> = {\n \"tool-result\": TOOL_RESULT_METHOD,\n \"tool-input\": TOOL_INPUT_METHOD,\n \"tool-input-partial\": TOOL_INPUT_PARTIAL_METHOD,\n \"tool-cancelled\": TOOL_CANCELLED_METHOD,\n \"theme-changed\": HOST_CONTEXT_CHANGED_METHOD,\n teardown: RESOURCE_TEARDOWN_METHOD,\n};\n\n/**\n * Resolve a short event name to a full MCP method name.\n * Returns the mapped method if found, otherwise passes through as-is.\n */\nexport function resolveEventMethod(name: string): string {\n return EVENT_MAP[name] ?? name;\n}\n","type SendFn = (method: string, params: Record<string, unknown>) => void;\n\ninterface Resizer {\n resize(width?: number, height?: number): void;\n measureAndSend(): void;\n destroy(): void;\n}\n\nexport function createResizer(send: SendFn, autoResize: boolean): Resizer {\n let destroyed = false;\n let observer: ResizeObserver | null = null;\n let rafId: number | null = null;\n\n function measureAndSend(): void {\n if (destroyed) return;\n const width = document.body.scrollWidth;\n const height = document.body.scrollHeight;\n send(\"ui/notifications/size-changed\", { width, height });\n }\n\n function resize(width?: number, height?: number): void {\n if (destroyed) return;\n if (width !== undefined && height !== undefined) {\n send(\"ui/notifications/size-changed\", { width, height });\n } else {\n measureAndSend();\n }\n }\n\n // Auto mode: attach ResizeObserver, debounced at 16ms via requestAnimationFrame\n if (autoResize && typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(() => {\n if (destroyed) return;\n if (rafId !== null) cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n rafId = null;\n measureAndSend();\n });\n });\n observer.observe(document.body);\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n if (rafId !== null) cancelAnimationFrame(rafId);\n observer?.disconnect();\n observer = null;\n }\n\n return { resize, measureAndSend, destroy };\n}\n","import type { ToolCallResult } from \"./types.js\";\n\n/**\n * Normalize a raw tool call response into a consistent `ToolCallResult`.\n *\n * Handles three shapes:\n * 1. MCP `CallToolResult` — has a `content` array with typed blocks.\n * 2. Raw JSON object (NimbleBrain bridge) — used as-is.\n * 3. Null / undefined — returns `{ data: null, isError: false }`.\n *\n * `_meta` on a `CallToolResult` is preserved on the parsed output as a\n * whole-object passthrough — notably `io.modelcontextprotocol/related-task`\n * (`{ taskId }`) for MCP 2025-11-25 task-augmented results, but any other\n * namespaced `_meta` keys propagate for free.\n */\nexport function parseToolResult(raw: unknown): ToolCallResult {\n if (raw == null) {\n return { data: null, isError: false };\n }\n\n if (isCallToolResult(raw)) {\n return parseCallToolResult(raw);\n }\n\n // Raw JSON object — pass through.\n return { data: raw, isError: false };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ninterface McpTextBlock {\n type: \"text\";\n text: string;\n}\n\ninterface McpCallToolResult {\n content: unknown[];\n isError?: boolean;\n _meta?: { [key: string]: unknown };\n}\n\nfunction isCallToolResult(value: unknown): value is McpCallToolResult {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n return Array.isArray((value as Record<string, unknown>).content);\n}\n\nfunction isTextBlock(block: unknown): block is McpTextBlock {\n if (block === null || typeof block !== \"object\" || Array.isArray(block)) {\n return false;\n }\n const obj = block as Record<string, unknown>;\n return obj.type === \"text\" && typeof obj.text === \"string\";\n}\n\n/**\n * Extract `_meta` as a shallow-copied object if present and object-shaped.\n *\n * Key-preserving by design: every `_meta` entry propagates without\n * selective copying, so future spec additions flow through without code\n * changes. Returns `undefined` when the input has no meaningful `_meta`.\n */\nfunction extractMeta(result: McpCallToolResult): { [key: string]: unknown } | undefined {\n const meta = result._meta;\n if (!meta || typeof meta !== \"object\" || Array.isArray(meta)) return undefined;\n // Shallow spread so mutations on either side don't leak. Preserves the\n // full key set including `io.modelcontextprotocol/related-task`.\n return { ...meta };\n}\n\nfunction parseCallToolResult(result: McpCallToolResult): ToolCallResult {\n const isError = result.isError === true;\n const content = result.content;\n const meta = extractMeta(result);\n\n if (content.length === 0) {\n return { data: null, isError, content, ...(meta && { _meta: meta }) };\n }\n\n const firstText = content.find(isTextBlock);\n\n if (!firstText) {\n // No text blocks — return the full content array so callers can inspect it.\n return { data: content, isError, content, ...(meta && { _meta: meta }) };\n }\n\n // Try to parse JSON from the text block.\n try {\n return { data: JSON.parse(firstText.text), isError, content, ...(meta && { _meta: meta }) };\n } catch {\n // Invalid JSON — return the raw string.\n return { data: firstText.text, isError, content, ...(meta && { _meta: meta }) };\n }\n}\n","import type {\n JsonRpcMessage,\n JsonRpcNotification,\n JsonRpcRequest,\n JsonRpcResponse,\n} from \"./types.js\";\n\ntype PendingEntry = {\n resolve: (value: unknown) => void;\n reject: (reason: unknown) => void;\n};\n\ntype MessageHandler = (params: Record<string, unknown> | undefined) => void;\n\nexport class SynapseTransport {\n private counter = 0;\n private destroyed = false;\n private pending = new Map<string, PendingEntry>();\n private handlers = new Map<string, Set<MessageHandler>>();\n private listener: (event: MessageEvent) => void;\n\n constructor() {\n this.listener = (event: MessageEvent) => this.handleMessage(event);\n window.addEventListener(\"message\", this.listener);\n }\n\n send(method: string, params?: Record<string, unknown>): void {\n if (this.destroyed) return;\n\n const msg: JsonRpcNotification = {\n jsonrpc: \"2.0\",\n method,\n ...(params !== undefined && { params }),\n };\n window.parent.postMessage(msg, \"*\");\n }\n\n request(method: string, params?: Record<string, unknown>): Promise<unknown> {\n if (this.destroyed) {\n return Promise.reject(new Error(\"Transport destroyed\"));\n }\n\n const id = `syn-${++this.counter}`;\n const msg: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n method,\n id,\n ...(params !== undefined && { params }),\n };\n\n return new Promise<unknown>((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n window.parent.postMessage(msg, \"*\");\n });\n }\n\n onMessage(method: string, callback: MessageHandler): () => void {\n if (!this.handlers.has(method)) {\n this.handlers.set(method, new Set());\n }\n this.handlers.get(method)?.add(callback);\n\n return () => {\n const set = this.handlers.get(method);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.handlers.delete(method);\n }\n }\n };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n window.removeEventListener(\"message\", this.listener);\n\n const error = new Error(\"Transport destroyed\");\n for (const entry of this.pending.values()) {\n entry.reject(error);\n }\n this.pending.clear();\n this.handlers.clear();\n }\n\n private handleMessage(event: MessageEvent): void {\n if (this.destroyed) return;\n\n const data = event.data as JsonRpcMessage;\n if (!data || data.jsonrpc !== \"2.0\") return;\n\n // Response to a pending request\n if (\"id\" in data && data.id && !(\"method\" in data)) {\n const response = data as JsonRpcResponse;\n const entry = this.pending.get(response.id);\n if (!entry) return;\n this.pending.delete(response.id);\n\n if (response.error) {\n const err = new Error(response.error.message);\n (err as any).code = response.error.code;\n (err as any).data = response.error.data;\n entry.reject(err);\n } else {\n entry.resolve(response.result);\n }\n return;\n }\n\n // Incoming notification\n if (\"method\" in data && !(\"id\" in data && data.id)) {\n const notification = data as JsonRpcNotification;\n const set = this.handlers.get(notification.method);\n if (set) {\n for (const handler of set) {\n handler(notification.params);\n }\n }\n }\n }\n}\n","import type {\n McpUiHostContext,\n McpUiHostContextChangedNotification,\n McpUiInitializeRequest,\n McpUiInitializeResult,\n McpUiMessageRequest,\n McpUiOpenLinkRequest,\n McpUiUpdateModelContextRequest,\n} from \"@modelcontextprotocol/ext-apps\";\nimport {\n HOST_CONTEXT_CHANGED_METHOD,\n INITIALIZE_METHOD,\n INITIALIZED_METHOD,\n LATEST_PROTOCOL_VERSION,\n MESSAGE_METHOD,\n OPEN_LINK_METHOD,\n TOOL_RESULT_METHOD,\n} from \"@modelcontextprotocol/ext-apps\";\nimport type {\n CallToolRequest,\n ReadResourceRequest,\n ReadResourceResult,\n TextContent,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { parseToolResultParams } from \"./content-parser.js\";\nimport { extractFontFaces, foldFontFaces } from \"./detection.js\";\nimport { resolveEventMethod } from \"./event-map.js\";\nimport { createResizer } from \"./resize.js\";\nimport { parseToolResult } from \"./result-parser.js\";\nimport { applyTheme } from \"./theme-defaults.js\";\nimport { SynapseTransport } from \"./transport.js\";\nimport type { App, ConnectOptions, Dimensions, Theme, ToolCallResult } from \"./types.js\";\n\n// Derived locally because `@modelcontextprotocol/ext-apps` only exports\n// METHOD constants for ext-apps specific ui/* methods. Typing the literal\n// with the spec's request `method` field still produces a compile error if\n// upstream renames it.\nconst READ_RESOURCE_METHOD: ReadResourceRequest[\"method\"] = \"resources/read\";\n\n/**\n * Connect to a MCP Apps host.\n *\n * Owns the full ext-apps handshake, content parsing, resize management,\n * and event routing. Returns a ready-to-use `App` object.\n */\nexport async function connect(options: ConnectOptions): Promise<App> {\n const { name, version, autoResize = false } = options;\n\n const transport = new SynapseTransport();\n let destroyed = false;\n\n // --- Mutable state ---\n let currentTheme: Theme = { mode: \"light\", tokens: {} };\n let hostInfo: { name: string; version: string } = { name: \"unknown\", version: \"unknown\" };\n let toolInfo: { tool: Record<string, unknown> } | null = null;\n let containerDimensions: Dimensions | null = null;\n\n // --- Event handlers ---\n const handlers = new Map<string, Set<(params: unknown) => void>>();\n\n // --- Step 1: Set up message listener (handled by SynapseTransport constructor) ---\n\n // --- Step 2: Send initial size ---\n const resizer = createResizer((method, params) => transport.send(method, params), autoResize);\n resizer.measureAndSend();\n\n // --- Steps 3-4: Send ui/initialize and wait for response ---\n //\n // `connect()` returns an `App` with no task-augmented call surface, so\n // we don't advertise the `tasks` capability here. Per MCP 2025-11-25,\n // requestors MUST NOT advertise capabilities they can't use — and\n // doing so confuses hosts that allocate state on the strength of the\n // advertisement. If `App` ever grows `callToolAsTask`, re-add the\n // capability here at the same time.\n const initParams: McpUiInitializeRequest[\"params\"] = {\n protocolVersion: LATEST_PROTOCOL_VERSION,\n appInfo: { name, version },\n appCapabilities: {},\n };\n\n const result = (await transport.request(\n INITIALIZE_METHOD,\n initParams as unknown as Record<string, unknown>,\n )) as McpUiInitializeResult | null;\n\n // --- Step 5: Extract theme, hostInfo, toolInfo, containerDimensions ---\n if (result) {\n hostInfo = {\n name: result.hostInfo?.name ?? \"unknown\",\n version: result.hostInfo?.version ?? \"unknown\",\n };\n\n const ctx: McpUiHostContext | undefined = result.hostContext;\n if (ctx) {\n const initialFontFaces = extractFontFaces(ctx);\n currentTheme = {\n mode: ctx.theme === \"dark\" ? \"dark\" : \"light\",\n tokens:\n ctx.styles?.variables && typeof ctx.styles.variables === \"object\"\n ? (ctx.styles.variables as Record<string, string>)\n : {},\n ...(initialFontFaces ? { fontFaces: initialFontFaces } : {}),\n };\n\n if (ctx.toolInfo && typeof ctx.toolInfo === \"object\") {\n toolInfo = { tool: (ctx.toolInfo.tool as unknown as Record<string, unknown>) ?? {} };\n }\n if (ctx.containerDimensions && typeof ctx.containerDimensions === \"object\") {\n containerDimensions = ctx.containerDimensions as Dimensions;\n }\n\n // Inject the theme into the DOM: neutral defaults for the mode back any\n // var the host omits, then host values win. Any host-supplied font faces\n // load alongside — a token names a family, it cannot load one.\n applyTheme(currentTheme.mode, currentTheme.tokens, currentTheme.fontFaces);\n }\n }\n\n // --- Route incoming notifications to registered handlers ---\n\n // Special handling for host-context-changed: update internal theme state\n transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {\n if (destroyed || !params) return;\n const ctx = params as Partial<McpUiHostContextChangedNotification[\"params\"]>;\n const mode = ctx.theme === \"dark\" ? \"dark\" : \"light\";\n const variables = ctx.styles?.variables;\n const tokens =\n variables && typeof variables === \"object\"\n ? (variables as Record<string, string>)\n : currentTheme.tokens;\n // A host-context-changed carries only the fields that changed; `foldFontFaces`\n // owns what an absent or unusable list means (see its doc).\n const fontFaces = foldFontFaces(currentTheme.fontFaces, ctx);\n currentTheme = { mode, tokens, ...(fontFaces ? { fontFaces } : {}) };\n applyTheme(mode, tokens, fontFaces);\n const set = handlers.get(HOST_CONTEXT_CHANGED_METHOD);\n if (set) {\n for (const handler of set) handler(currentTheme);\n }\n });\n\n // Helper to ensure transport subscription exists for a method\n const subscribedMethods = new Set<string>([HOST_CONTEXT_CHANGED_METHOD]);\n\n function ensureTransportSub(method: string): void {\n if (subscribedMethods.has(method)) return;\n subscribedMethods.add(method);\n\n const isToolResult = method === TOOL_RESULT_METHOD;\n\n transport.onMessage(method, (params) => {\n if (destroyed) return;\n const set = handlers.get(method);\n if (!set) return;\n for (const handler of set) {\n if (isToolResult) {\n handler(parseToolResultParams(params));\n } else {\n handler(params);\n }\n }\n });\n }\n\n // --- Step 6: Pre-register handlers from options.on, then send initialized ---\n if (options.on) {\n for (const [event, handler] of Object.entries(options.on)) {\n if (typeof handler === \"function\") {\n const method = resolveEventMethod(event);\n if (!handlers.has(method)) handlers.set(method, new Set());\n handlers.get(method)?.add(handler);\n ensureTransportSub(method);\n }\n }\n }\n transport.send(INITIALIZED_METHOD, {});\n\n // --- Step 7: Build and return the App object ---\n const app: App = {\n get theme() {\n return { ...currentTheme };\n },\n get hostInfo() {\n return { ...hostInfo };\n },\n get toolInfo() {\n return toolInfo;\n },\n get containerDimensions() {\n return containerDimensions;\n },\n\n on(event: string, handler: (params: any) => void): () => void {\n const method = resolveEventMethod(event);\n\n if (!handlers.has(method)) {\n handlers.set(method, new Set());\n }\n handlers.get(method)?.add(handler);\n ensureTransportSub(method);\n\n return () => {\n const set = handlers.get(method);\n if (set) {\n set.delete(handler);\n if (set.size === 0) handlers.delete(method);\n }\n };\n },\n\n resize(width?: number, height?: number): void {\n resizer.resize(width, height);\n },\n\n openLink(url: string): void {\n if (destroyed) return;\n const params: McpUiOpenLinkRequest[\"params\"] = { url };\n // Spec: ui/open-link is a request (expects a response), not a notification\n transport\n .request(OPEN_LINK_METHOD, params as unknown as Record<string, unknown>)\n .catch(() => {});\n },\n\n updateModelContext(state: Record<string, unknown>, summary?: string): void {\n if (destroyed) return;\n const params: McpUiUpdateModelContextRequest[\"params\"] = {\n structuredContent: state,\n ...(summary !== undefined && {\n content: [{ type: \"text\", text: summary } satisfies TextContent],\n }),\n };\n transport.send(\"ui/update-model-context\", params as unknown as Record<string, unknown>);\n },\n\n async callTool(toolName: string, args?: Record<string, unknown>): Promise<ToolCallResult> {\n const params: CallToolRequest[\"params\"] = {\n name: toolName,\n arguments: args ?? {},\n };\n const raw = await transport.request(\n \"tools/call\",\n params as unknown as Record<string, unknown>,\n );\n return parseToolResult(raw);\n },\n\n async readServerResource(params: ReadResourceRequest[\"params\"]): Promise<ReadResourceResult> {\n const raw = await transport.request(\n READ_RESOURCE_METHOD,\n params as unknown as Record<string, unknown>,\n );\n return raw as ReadResourceResult;\n },\n\n sendMessage(text: string, context?: { action?: string; entity?: string }): void {\n if (destroyed) return;\n const textBlock: TextContent = {\n type: \"text\",\n text,\n ...(context && { _meta: { context } }),\n };\n const params: McpUiMessageRequest[\"params\"] = {\n role: \"user\",\n content: [textBlock],\n };\n transport.send(MESSAGE_METHOD, params as unknown as Record<string, unknown>);\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n resizer.destroy();\n handlers.clear();\n transport.destroy();\n },\n };\n\n return app;\n}\n","import type { SynapseTransport } from \"./transport.js\";\nimport type { KeyForwardConfig } from \"./types.js\";\n\n/**\n * Forward keyboard shortcuts from the iframe document to the host.\n *\n * By default, forwards all Ctrl/Cmd+key combos and Escape.\n * Apps can customize via `forwardKeys` config.\n */\nexport class KeyboardForwarder {\n private listener: (event: KeyboardEvent) => void;\n private destroyed = false;\n\n constructor(transport: SynapseTransport, customKeys?: KeyForwardConfig[]) {\n const config = customKeys ?? null; // null = default behavior\n\n this.listener = (event: KeyboardEvent) => {\n if (this.destroyed) return;\n if (this.shouldForward(event, config)) {\n event.preventDefault();\n transport.send(\"synapse/keydown\", {\n key: event.key,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n });\n }\n };\n\n document.addEventListener(\"keydown\", this.listener);\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n document.removeEventListener(\"keydown\", this.listener);\n }\n\n private shouldForward(event: KeyboardEvent, config: KeyForwardConfig[] | null): boolean {\n // Empty array = forwarding disabled\n if (config && config.length === 0) return false;\n\n // Custom config: match exactly\n if (config) {\n return config.some(\n (k) =>\n event.key.toLowerCase() === k.key.toLowerCase() &&\n (k.ctrl === undefined || event.ctrlKey === k.ctrl) &&\n (k.meta === undefined || event.metaKey === k.meta) &&\n (k.shift === undefined || event.shiftKey === k.shift) &&\n (k.alt === undefined || event.altKey === k.alt),\n );\n }\n\n // Default: forward all Ctrl/Cmd combos + Escape,\n // EXCEPT clipboard shortcuts (c, v, x, a) which the browser must handle natively.\n if (event.key === \"Escape\") return true;\n if (event.ctrlKey || event.metaKey) {\n const key = event.key.toLowerCase();\n if (key === \"c\" || key === \"v\" || key === \"x\" || key === \"a\") return false;\n return true;\n }\n return false;\n }\n}\n","import type {\n CallToolRequest,\n CancelTaskRequest,\n CancelTaskResult,\n CreateTaskResult,\n GetTaskPayloadRequest,\n GetTaskPayloadResult,\n GetTaskRequest,\n GetTaskResult,\n Task,\n TaskStatus,\n TaskStatusNotification,\n TaskStatusNotificationParams,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { parseToolResult } from \"./result-parser.js\";\nimport type { SynapseTransport } from \"./transport.js\";\nimport type { CallToolAsTaskOptions, TaskHandle, ToolCallResult } from \"./types.js\";\n\n// -----------------------------------------------------------------------------\n// Spec method constants\n// -----------------------------------------------------------------------------\n//\n// The MCP SDK publishes task-method strings only inside Zod `z.literal(...)`s,\n// not as top-level `*_METHOD` constants. Derive each from its request's\n// `method` type so an upstream rename surfaces here as a compile error\n// (same pattern as `READ_RESOURCE_METHOD` in core.ts / connect.ts).\n//\n// When adding a new method here, also mirror it in `src/_shims/ext-apps.ts`\n// per the IIFE build instructions in CLAUDE.md — the shim must export the\n// same string constants any source file consumes.\n\nexport const TOOLS_CALL_METHOD: CallToolRequest[\"method\"] = \"tools/call\";\nexport const TASKS_GET_METHOD: GetTaskRequest[\"method\"] = \"tasks/get\";\nexport const TASKS_RESULT_METHOD: GetTaskPayloadRequest[\"method\"] = \"tasks/result\";\nexport const TASKS_CANCEL_METHOD: CancelTaskRequest[\"method\"] = \"tasks/cancel\";\nexport const TASKS_STATUS_NOTIFICATION_METHOD: TaskStatusNotification[\"method\"] =\n \"notifications/tasks/status\";\n\n// -----------------------------------------------------------------------------\n// Status router\n// -----------------------------------------------------------------------------\n\n/**\n * Notification fields the spec guarantees on `notifications/tasks/status`.\n * Deliberately narrower than `Task` — the wire notification omits\n * `createdAt`, `lastUpdatedAt`, `ttl`, `pollInterval`. Consumers receive\n * a merged full `Task` via `TaskHandle.onStatus`; the handle is the only\n * party with access to the initial `CreateTaskResult.task` needed to fill\n * the missing fields.\n */\nexport interface TaskStatusUpdate {\n taskId: string;\n status: TaskStatus;\n statusMessage?: string;\n}\n\n/**\n * Per-taskId callback registry. One registry is shared across all\n * `TaskHandle` instances on a given transport so the transport-level\n * `notifications/tasks/status` handler registers exactly once — multiple\n * handles route in-memory by taskId, not by wire subscription.\n */\nexport interface TaskStatusRouter {\n subscribe(taskId: string, cb: (update: TaskStatusUpdate) => void): () => void;\n dispose(): void;\n}\n\nexport function createTaskStatusRouter(transport: SynapseTransport): TaskStatusRouter {\n const listeners = new Map<string, Set<(update: TaskStatusUpdate) => void>>();\n\n // Single transport-level subscription. All per-handle listeners filter\n // in-memory by taskId off this one wire handler.\n const unsub = transport.onMessage(TASKS_STATUS_NOTIFICATION_METHOD, (rawParams) => {\n if (!rawParams) return;\n const params = rawParams as unknown as TaskStatusNotificationParams;\n const taskId = params.taskId;\n if (typeof taskId !== \"string\") return;\n\n const set = listeners.get(taskId);\n if (!set || set.size === 0) return;\n\n // Forward the spec-guaranteed fields verbatim. We deliberately don't\n // fabricate `createdAt`/`lastUpdatedAt`/`ttl` here — the handle merges\n // these from its initial `CreateTaskResult.task` so consumers always\n // see a real Task with no placeholder strings.\n const update: TaskStatusUpdate = {\n taskId: params.taskId,\n status: params.status,\n ...(params.statusMessage !== undefined && { statusMessage: params.statusMessage }),\n };\n\n for (const cb of set) cb(update);\n });\n\n return {\n subscribe(taskId, cb) {\n let set = listeners.get(taskId);\n if (!set) {\n set = new Set();\n listeners.set(taskId, set);\n }\n set.add(cb);\n return () => {\n const s = listeners.get(taskId);\n if (!s) return;\n s.delete(cb);\n if (s.size === 0) listeners.delete(taskId);\n };\n },\n dispose() {\n listeners.clear();\n unsub();\n },\n };\n}\n\n// -----------------------------------------------------------------------------\n// Caller-facing factory\n// -----------------------------------------------------------------------------\n\n/**\n * Dependencies injected into `callToolAsTask`. The call site (in\n * `core.ts`) provides the transport, the shared status router, a factory\n * for the `tools/call` params (so `internal` / `name` handling stays in\n * one place), and the current `_hostTasksCapability` value.\n */\nexport interface CallToolAsTaskDeps {\n transport: SynapseTransport;\n router: TaskStatusRouter;\n /**\n * `null` before the `ui/initialize` handshake resolves, `undefined`\n * afterward if the host did not advertise `tasks`, or the captured\n * capability shape if it did. `callToolAsTask` throws when the nested\n * `requests.tools.call` is not present.\n */\n getHostTasksCapability: () =>\n | { requests?: { tools?: { call?: Record<string, never> } } }\n | undefined\n | null;\n /** App name for `params.server` when `internal: true`. */\n appName: string;\n /** Whether the enclosing Synapse is running in internal-apps mode. */\n internalApp: boolean;\n}\n\nexport async function callToolAsTask<TOutput = unknown>(\n deps: CallToolAsTaskDeps,\n toolName: string,\n args?: unknown,\n options?: CallToolAsTaskOptions,\n): Promise<TaskHandle<TOutput>> {\n const hostTasks = deps.getHostTasksCapability();\n if (!hostTasks?.requests?.tools?.call) {\n throw new Error(\n \"callToolAsTask: host did not advertise tasks.requests.tools.call in its capabilities. \" +\n \"Per MCP 2025-11-25 §, requestors MUST NOT task-augment a tools/call without \" +\n \"matching receiver capability. Fall back to `synapse.callTool`.\",\n );\n }\n\n // Per spec, `task` is an object even when the caller provides no hints —\n // its presence is the signal to the receiver that augmentation is\n // requested. An empty `{}` is valid.\n const taskParam: { ttl?: number } = {};\n if (options?.ttl !== undefined) taskParam.ttl = options.ttl;\n\n // `internal` resolution:\n // - explicit `options.internal === true` → cross-server, add `server`\n // - explicit `options.internal === false` → never add `server`\n // - omitted → inherit from app-level\n // `internal` flag (same\n // semantics as `callTool`)\n const crossServer = options?.internal ?? deps.internalApp;\n\n // Build `tools/call` params. We layer our own shape on the SDK's\n // `CallToolRequest[\"params\"]` via `satisfies` so any rename upstream\n // (`name` → `toolName`, `arguments` → `args`, etc.) trips tsc. The\n // `server` extension is a NimbleBrain bridge convention, not an MCP\n // spec field.\n const callParams = {\n name: toolName,\n arguments: (args as Record<string, unknown> | undefined) ?? {},\n task: taskParam,\n ...(crossServer ? { server: deps.appName } : {}),\n } satisfies CallToolRequest[\"params\"] & { server?: string };\n\n const raw = await deps.transport.request(\n TOOLS_CALL_METHOD,\n callParams as unknown as Record<string, unknown>,\n );\n\n // Spec: task-augmented `tools/call` returns a `CreateTaskResult`. If a\n // receiver that advertised the capability returns a bare\n // `CallToolResult` instead, that's a protocol violation — surface it.\n const createResult = raw as CreateTaskResult | null | undefined;\n const initialTask = createResult?.task;\n if (!initialTask || typeof initialTask !== \"object\" || typeof initialTask.taskId !== \"string\") {\n throw new Error(\n \"callToolAsTask: receiver returned a response without `task` per CreateTaskResult \" +\n \"(expected shape: `{ task: { taskId, status, ... } }`). Receiver may not honor \" +\n \"the advertised tasks capability.\",\n );\n }\n\n const taskId = initialTask.taskId;\n\n // Preserve the Set-semantic dedup contract on `onStatus` (matches\n // `SynapseTransport.onMessage`): registering the same callback twice\n // collapses to one wire subscription, and either returned unsub\n // releases it. Without this, every `onStatus(cb)` would create a\n // fresh wrapper that the router treats as distinct.\n const localCallbacks = new Map<(task: Task) => void, () => void>();\n\n const handle: TaskHandle<TOutput> = {\n task: initialTask,\n\n async result(): Promise<ToolCallResult<TOutput>> {\n const params = { taskId } satisfies GetTaskPayloadRequest[\"params\"];\n const rawResult = await deps.transport.request(\n TASKS_RESULT_METHOD,\n params as unknown as Record<string, unknown>,\n );\n // Per spec §: `tasks/result` returns exactly what the non-task\n // response would return. Parse through the shared tool-result\n // parser so `_meta[\"io.modelcontextprotocol/related-task\"]`\n // propagates unchanged (key-preserving spread).\n //\n // Type note: `GetTaskPayloadResult` is a union of result shapes\n // (one per augmentable request type). For `tools/call` tasks,\n // the runtime shape is `CallToolResult`, which `parseToolResult`\n // already handles.\n const typed = rawResult as GetTaskPayloadResult;\n return parseToolResult(typed) as ToolCallResult<TOutput>;\n },\n\n async refresh(): Promise<Task> {\n const params = { taskId } satisfies GetTaskRequest[\"params\"];\n const raw = await deps.transport.request(\n TASKS_GET_METHOD,\n params as unknown as Record<string, unknown>,\n );\n // Per spec, `tasks/get` returns the task shape FLAT (taskId, status,\n // ttl, createdAt, lastUpdatedAt, ... at the top level) — NOT\n // wrapped in a `{ task }` field (unlike `CreateTaskResult`).\n return projectTask(raw as GetTaskResult);\n },\n\n async cancel(): Promise<Task> {\n const params = { taskId } satisfies CancelTaskRequest[\"params\"];\n const raw = await deps.transport.request(\n TASKS_CANCEL_METHOD,\n params as unknown as Record<string, unknown>,\n );\n // `CancelTaskResult` is flat like `GetTaskResult`.\n return projectTask(raw as CancelTaskResult);\n },\n\n onStatus(cb) {\n // Idempotent-in-callback: if the same `cb` is already subscribed,\n // return the existing unsub.\n const existing = localCallbacks.get(cb);\n if (existing) return existing;\n\n // Merge the notification's spec-guaranteed fields (taskId, status,\n // statusMessage) with the handle's initial `CreateTaskResult.task`\n // so the consumer always sees a full valid `Task`. `lastUpdatedAt`\n // is stamped at SDK-receive time (an approximation of the host's\n // update time — the spec doesn't wire the host's timestamp through\n // the notification, so this is the closest signal we have).\n // `createdAt`, `ttl`, `pollInterval` come from the initial task\n // because they don't change over a task's lifetime.\n const wireUnsub = deps.router.subscribe(taskId, (update) => {\n const merged: Task = {\n taskId: update.taskId,\n status: update.status,\n ttl: initialTask.ttl,\n createdAt: initialTask.createdAt,\n lastUpdatedAt: new Date().toISOString(),\n ...(initialTask.pollInterval !== undefined && {\n pollInterval: initialTask.pollInterval,\n }),\n ...(update.statusMessage !== undefined && { statusMessage: update.statusMessage }),\n };\n cb(merged);\n });\n\n const unsub = () => {\n localCallbacks.delete(cb);\n wireUnsub();\n };\n localCallbacks.set(cb, unsub);\n return unsub;\n },\n };\n\n return handle;\n}\n\n// -----------------------------------------------------------------------------\n// Internal helpers\n// -----------------------------------------------------------------------------\n\n/**\n * Project a `GetTaskResult` / `CancelTaskResult` down to the canonical\n * `Task` shape. Both result types are structurally `Task` with an\n * optional `_meta` field on top; we project explicitly so consumers\n * don't see protocol-level `_meta` leaking onto the task state they\n * get back from `refresh()` / `cancel()`.\n *\n * Asymmetry note: `parseToolResult` (for `tools/call` / `tasks/result`\n * payloads) is key-preserving — `_meta` flows through end-to-end, which\n * matters for `io.modelcontextprotocol/related-task` correlation. Here\n * we drop `_meta` because no downstream consumer reads it on `Task` state\n * today. If a host starts stamping useful keys on `tasks/get`/`tasks/cancel`\n * responses, switch to a key-preserving projection.\n */\nfunction projectTask(raw: GetTaskResult | CancelTaskResult): Task {\n return {\n taskId: raw.taskId,\n status: raw.status,\n ttl: raw.ttl,\n createdAt: raw.createdAt,\n lastUpdatedAt: raw.lastUpdatedAt,\n ...(raw.pollInterval !== undefined && { pollInterval: raw.pollInterval }),\n ...(raw.statusMessage !== undefined && { statusMessage: raw.statusMessage }),\n };\n}\n","import type {\n McpUiHostContext,\n McpUiInitializeRequest,\n McpUiInitializeResult,\n McpUiMessageRequest,\n McpUiOpenLinkRequest,\n McpUiUpdateModelContextRequest,\n} from \"@modelcontextprotocol/ext-apps\";\nimport {\n HOST_CONTEXT_CHANGED_METHOD,\n INITIALIZE_METHOD,\n INITIALIZED_METHOD,\n LATEST_PROTOCOL_VERSION,\n MESSAGE_METHOD,\n OPEN_LINK_METHOD,\n} from \"@modelcontextprotocol/ext-apps\";\nimport type {\n ReadResourceRequest,\n ReadResourceResult,\n TextContent,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { detectHost, extractTheme, foldFontFaces } from \"./detection.js\";\nimport { KeyboardForwarder } from \"./keyboard.js\";\nimport { parseToolResult } from \"./result-parser.js\";\nimport { callToolAsTask as callToolAsTaskImpl, createTaskStatusRouter } from \"./task-handle.js\";\nimport { applyTheme, fontFacesKey } from \"./theme-defaults.js\";\nimport { SynapseTransport } from \"./transport.js\";\nimport type {\n AgentAction,\n CallToolAsTaskOptions,\n DataChangedEvent,\n FileResult,\n FontFaceDescriptor,\n HostInfo,\n RequestFileOptions,\n Synapse,\n SynapseOptions,\n SynapseTheme,\n TaskHandle,\n TasksCapability,\n ToolCallResult,\n} from \"./types.js\";\n\n// `@modelcontextprotocol/ext-apps` only exports METHOD constants for ext-apps\n// specific ui/* methods, not standard MCP methods. Deriving the constant\n// locally with the spec request's `method` type still fails compilation if\n// upstream renames it.\nconst READ_RESOURCE_METHOD: ReadResourceRequest[\"method\"] = \"resources/read\";\n\n/**\n * Create a Synapse instance.\n *\n * Wraps the ext-apps protocol handshake via `SynapseTransport` and provides\n * a typed, framework-agnostic API for calling tools, reacting to data changes,\n * dispatching actions, and pushing LLM-visible state.\n *\n * In non-NimbleBrain hosts, NB-specific methods degrade to no-ops.\n */\nexport function createSynapse(options: SynapseOptions): Synapse {\n const { name, version, internal = false, forwardKeys } = options;\n\n const transport = new SynapseTransport();\n let hostInfo: HostInfo | null = null;\n // Single source of truth for ext-apps host context. `theme`, `styles`,\n // `displayMode`, `toolInfo` are spec-standardized fields; the open\n // `[key: string]: unknown` lets hosts publish extensions (e.g. NimbleBrain\n // populates a `workspace` field). `getTheme()` and any other typed view\n // is derived from this object — no parallel state.\n let currentHostContext: McpUiHostContext = {};\n // Font faces are the one derived value that must NOT be recomputed from a\n // replaced context. A `host-context-changed` carries only the fields that\n // changed (per the ext-apps `McpUiHostContextChangedNotification` params\n // doc), so a bare `{ theme: \"dark\" }` toggle would otherwise re-derive\n // \"no fonts\" and unload the host's typeface mid-session — far more visible\n // than the equivalent for a colour token. Sticky here, cleared only by an\n // explicit empty list from the host.\n let currentFontFaces: FontFaceDescriptor[] | undefined;\n\n /** Fold a (possibly partial) context's faces into the sticky set. */\n function syncFontFaces(ctx: McpUiHostContext): FontFaceDescriptor[] | undefined {\n currentFontFaces = foldFontFaces(currentFontFaces, ctx);\n return currentFontFaces;\n }\n\n /**\n * The theme as reported to consumers: derived from the context, with the\n * sticky faces folded back in. Every public view goes through here —\n * `getTheme()`, the `onThemeChanged` payload, and its equality filter — so\n * they cannot disagree with each other or with what is actually loaded.\n */\n function resolveTheme(ctx: McpUiHostContext): SynapseTheme {\n const theme = extractTheme(ctx);\n return currentFontFaces ? { ...theme, fontFaces: currentFontFaces } : theme;\n }\n // Module-private store for the host's declared `tasks` capability. Kept\n // in the closure (not on Synapse) so `callToolAsTask` reads it without\n // expanding the public surface. `null` before the handshake completes;\n // `undefined` after a handshake where the host did not advertise `tasks`.\n let hostTasksCapability: TasksCapability | undefined | null = null;\n let destroyed = false;\n\n // Shared router for `notifications/tasks/status`. Created eagerly so\n // the transport-level listener registers exactly once — every\n // `TaskHandle.onStatus` subscriber filters off this single wire\n // subscription by taskId. Disposed in `destroy()`.\n const taskStatusRouter = createTaskStatusRouter(transport);\n\n // --- Debounce for setVisibleState ---\n let stateTimer: ReturnType<typeof setTimeout> | null = null;\n\n // --- Keyboard forwarding ---\n let keyboard: KeyboardForwarder | null = null;\n\n // --- ext-apps handshake ---\n //\n // `appCapabilities` is typed as `McpUiAppCapabilities` by the ext-apps\n // spec package, which does not yet model the MCP 2025-11-25 tasks\n // utility. We extend structurally via `TasksCapability` (re-exported\n // from the SDK's `ClientCapabilities.tasks` / `ServerTasksCapability`\n // shape) and `satisfies` the extension so the nested objects match the\n // spec literally — empty objects `{}` as presence flags, NOT booleans.\n const appCapabilities = {\n tasks: {\n cancel: {},\n requests: { tools: { call: {} } },\n } satisfies TasksCapability,\n };\n const initParams: McpUiInitializeRequest[\"params\"] = {\n protocolVersion: LATEST_PROTOCOL_VERSION,\n appInfo: { name, version },\n appCapabilities:\n appCapabilities as unknown as McpUiInitializeRequest[\"params\"][\"appCapabilities\"],\n };\n\n const ready = transport\n .request(INITIALIZE_METHOD, initParams as unknown as Record<string, unknown>)\n .then((result) => {\n hostInfo = detectHost(result);\n currentHostContext = ((result as McpUiInitializeResult | null)?.hostContext ??\n {}) as McpUiHostContext;\n\n // Capture the host's declared `tasks` capability from the init\n // response. The ext-apps `McpUiHostCapabilities` type lacks a\n // `tasks` field (the SDK extension post-dates it), so we read via\n // the result's index signature. `undefined` when absent.\n const initResult = result as McpUiInitializeResult | null;\n const rawTasks = (initResult?.hostCapabilities as Record<string, unknown> | undefined)?.tasks;\n hostTasksCapability =\n rawTasks && typeof rawTasks === \"object\" && !Array.isArray(rawTasks)\n ? (rawTasks as TasksCapability)\n : undefined;\n\n // Inject the theme into :root so plain-CSS styles consume it via\n // `var(--…)` without reading theme.tokens imperatively. Neutral defaults\n // back any var the host omits (theme-correct), then host values win.\n {\n const theme = extractTheme(currentHostContext);\n applyTheme(theme.mode, theme.tokens, syncFontFaces(currentHostContext));\n }\n\n // Notify subscribers so React hooks (useTheme, useHostContext) and\n // custom listeners reflect the handshake-provided context (not just\n // subsequent host-context-changed notifications).\n for (const cb of hostContextCallbacks) cb(currentHostContext);\n\n transport.send(INITIALIZED_METHOD, {});\n\n keyboard = new KeyboardForwarder(transport, forwardKeys);\n });\n\n // Listen for host context changes (ext-apps spec). The notification's params\n // are a PARTIAL update — only the fields that changed — so `currentHostContext`\n // being replaced wholesale here means any field the host omits is re-derived as\n // absent. That is long-standing behaviour for the spec fields (a subscriber\n // reads the notification as sent); fonts opt out via `syncFontFaces` because\n // unloading a typeface on an unrelated toggle is a visible break, not a\n // no-op. Making the whole context merge is a wider change than this one\n // concerns: it also wipes the host's tokens, and fixing it changes what every\n // subscriber observes. Tracked in #46.\n const unsubHostContext = transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {\n currentHostContext = (params ?? {}) as McpUiHostContext;\n const theme = extractTheme(currentHostContext);\n applyTheme(theme.mode, theme.tokens, syncFontFaces(currentHostContext));\n for (const cb of hostContextCallbacks) cb(currentHostContext);\n });\n\n const hostContextCallbacks = new Set<(ctx: McpUiHostContext) => void>();\n const dataCallbacks = new Set<(event: DataChangedEvent) => void>();\n const actionCallbacks = new Set<(action: AgentAction) => void>();\n\n // Listen for data change events\n const unsubData = transport.onMessage(\"synapse/data-changed\", (params) => {\n if (!params) return;\n const event: DataChangedEvent = {\n source: \"agent\",\n server: (params.server as string) ?? \"\",\n tool: (params.tool as string) ?? \"\",\n };\n for (const cb of dataCallbacks) cb(event);\n });\n\n // Listen for agent actions (typed, declarative commands from the server)\n const unsubAction = transport.onMessage(\"synapse/action\", (params) => {\n if (!params || typeof params.type !== \"string\") return;\n const action: AgentAction = {\n type: params.type as string,\n payload: (params.payload as Record<string, unknown>) ?? {},\n requiresConfirmation: params.requiresConfirmation === true,\n label: typeof params.label === \"string\" ? params.label : undefined,\n };\n for (const cb of actionCallbacks) cb(action);\n });\n\n const isNB = () => hostInfo?.isNimbleBrain === true;\n\n const synapse: Synapse = {\n get ready() {\n return ready;\n },\n\n get isNimbleBrainHost() {\n return isNB();\n },\n\n get destroyed() {\n return destroyed;\n },\n\n async callTool<TInput = Record<string, unknown>, TOutput = unknown>(\n toolName: string,\n args?: TInput,\n ): Promise<ToolCallResult<TOutput>> {\n const params: Record<string, unknown> = {\n name: toolName,\n arguments: args ?? {},\n };\n // Internal apps can cross-call\n if (internal) {\n params.server = name;\n }\n const raw = await transport.request(\"tools/call\", params);\n return parseToolResult(raw) as ToolCallResult<TOutput>;\n },\n\n async callToolAsTask<TInput = Record<string, unknown>, TOutput = unknown>(\n toolName: string,\n args?: TInput,\n options?: CallToolAsTaskOptions,\n ): Promise<TaskHandle<TOutput>> {\n return callToolAsTaskImpl<TOutput>(\n {\n transport,\n router: taskStatusRouter,\n getHostTasksCapability: () => hostTasksCapability,\n appName: name,\n internalApp: internal,\n },\n toolName,\n args,\n options,\n );\n },\n\n async readResource(uri: string): Promise<ReadResourceResult> {\n const params: ReadResourceRequest[\"params\"] = { uri };\n const raw = await transport.request(\n READ_RESOURCE_METHOD,\n params as unknown as Record<string, unknown>,\n );\n return raw as ReadResourceResult;\n },\n\n onDataChanged(callback: (event: DataChangedEvent) => void): () => void {\n dataCallbacks.add(callback);\n return () => {\n dataCallbacks.delete(callback);\n };\n },\n\n onAction(callback: (action: AgentAction) => void): () => void {\n actionCallbacks.add(callback);\n return () => {\n actionCallbacks.delete(callback);\n };\n },\n\n getHostContext(): McpUiHostContext {\n return currentHostContext;\n },\n\n onHostContextChanged(callback: (ctx: McpUiHostContext) => void): () => void {\n hostContextCallbacks.add(callback);\n return () => {\n hostContextCallbacks.delete(callback);\n };\n },\n\n getTheme(): SynapseTheme {\n return resolveTheme(currentHostContext);\n },\n\n // Selector over `onHostContextChanged`: only fires when the *derived*\n // theme actually changes, so theme subscribers don't see spurious\n // updates when other host-context fields (e.g. workspace) change.\n //\n // Subscriber timing matters:\n // - Subscribed BEFORE handshake: `prev = null` sentinel. The first\n // fire (the handshake dispatch) always invokes the callback,\n // even if the host's theme happens to derive to the default.\n // Otherwise consumers using `onThemeChanged` as their init\n // signal would silently miss it.\n // - Subscribed AFTER handshake: `prev` is pre-seeded with the\n // current derived theme, so a workspace-only `host-context-changed`\n // notification correctly filters as a no-op.\n onThemeChanged(callback: (theme: SynapseTheme) => void): () => void {\n let prev: SynapseTheme | null = hostInfo !== null ? resolveTheme(currentHostContext) : null;\n const wrapped = (ctx: McpUiHostContext) => {\n const next = resolveTheme(ctx);\n if (prev !== null && themesEqual(prev, next)) return;\n prev = next;\n callback(next);\n };\n hostContextCallbacks.add(wrapped);\n return () => {\n hostContextCallbacks.delete(wrapped);\n };\n },\n\n action(action: string, params?: Record<string, unknown>): void {\n if (!isNB()) return;\n transport.send(\"synapse/action\", { action, ...params });\n },\n\n chat(message: string, context?: { action?: string; entity?: string }): void {\n const textBlock: TextContent = {\n type: \"text\",\n text: message,\n ...(isNB() && context && { _meta: { context } }),\n };\n const params: McpUiMessageRequest[\"params\"] = {\n role: \"user\",\n content: [textBlock],\n };\n transport.send(MESSAGE_METHOD, params as unknown as Record<string, unknown>);\n },\n\n setVisibleState(state: Record<string, unknown>, summary?: string): void {\n // Debounce: 250ms\n if (stateTimer) clearTimeout(stateTimer);\n stateTimer = setTimeout(() => {\n const params: McpUiUpdateModelContextRequest[\"params\"] = {\n structuredContent: state,\n ...(summary !== undefined && {\n content: [{ type: \"text\", text: summary } satisfies TextContent],\n }),\n };\n transport.send(\"ui/update-model-context\", params as unknown as Record<string, unknown>);\n stateTimer = null;\n }, 250);\n },\n\n downloadFile(filename: string, content: string | Blob, mimeType?: string): void {\n // Precedence: explicit mimeType arg > Blob's intrinsic type > octet-stream fallback.\n // Empty-string mimeType falls through (a \"\" MIME is effectively \"no type\").\n const resolvedMime =\n mimeType || (content instanceof Blob ? content.type : \"\") || \"application/octet-stream\";\n const blob = content instanceof Blob ? content : new Blob([content], { type: resolvedMime });\n transport.send(\"synapse/download-file\", {\n data: blob,\n filename,\n mimeType: resolvedMime,\n });\n },\n\n openLink(url: string): void {\n const params: McpUiOpenLinkRequest[\"params\"] = { url };\n // Spec: ui/open-link is a request (expects a response), not a notification\n transport\n .request(OPEN_LINK_METHOD, params as unknown as Record<string, unknown>)\n .catch(() => {\n // Fallback: if host doesn't respond, open directly\n window.open(url, \"_blank\", \"noopener\");\n });\n },\n\n async pickFile(options?: RequestFileOptions): Promise<FileResult | null> {\n if (!isNB()) {\n throw new Error(\"pickFile is not supported in this host\");\n }\n const result = await requestFile(transport, options, false);\n if (result === null) return null;\n // Server may have returned an array even for single-pick — take the\n // first entry to preserve the documented `FileResult | null` shape.\n return Array.isArray(result) ? (result[0] ?? null) : result;\n },\n\n async pickFiles(options?: RequestFileOptions): Promise<FileResult[]> {\n if (!isNB()) {\n throw new Error(\"pickFiles is not supported in this host\");\n }\n const result = await requestFile(transport, options, true);\n if (result === null) return [];\n return Array.isArray(result) ? result : [result];\n },\n\n _onMessage(\n method: string,\n callback: (params: Record<string, unknown> | undefined) => void,\n ): () => void {\n return transport.onMessage(method, callback);\n },\n\n _request(method: string, params?: Record<string, unknown>): Promise<unknown> {\n return transport.request(method, params);\n },\n\n get _hostTasksCapability(): TasksCapability | undefined | null {\n return hostTasksCapability;\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n if (stateTimer) clearTimeout(stateTimer);\n keyboard?.destroy();\n unsubHostContext();\n unsubData();\n unsubAction();\n taskStatusRouter.dispose();\n hostContextCallbacks.clear();\n dataCallbacks.clear();\n actionCallbacks.clear();\n transport.destroy();\n },\n };\n\n return synapse;\n}\n\n/**\n * Shared request path for `pickFile` / `pickFiles`. Centralizes:\n *\n * - The wire method name `synapse/request-file` (which is what the\n * NimbleBrain bridge actually handles — earlier SDK versions sent\n * `synapse/pick-file` and the call would silently time out).\n * - Runtime shape validation. Older hosts (pre-`POST /v1/resources`)\n * still respond to `synapse/request-file` but return the legacy\n * `{ base64Data, … }` shape. The TS type promises a string `id`;\n * without this guard, consumers would silently get `undefined.id`\n * and fail downstream in confusing ways. Failing loud at the\n * boundary tells the developer exactly which side is mismatched.\n */\nasync function requestFile(\n transport: SynapseTransport,\n options: RequestFileOptions | undefined,\n multiple: boolean,\n): Promise<FileResult | FileResult[] | null> {\n const result = await transport.request(\"synapse/request-file\", {\n accept: options?.accept,\n maxSize: options?.maxSize ?? 26_214_400,\n multiple,\n });\n if (result == null) return null;\n if (Array.isArray(result)) {\n return result.map(validateFileResult);\n }\n return validateFileResult(result);\n}\n\nfunction validateFileResult(value: unknown): FileResult {\n if (\n typeof value !== \"object\" ||\n value === null ||\n typeof (value as { id?: unknown }).id !== \"string\"\n ) {\n throw new Error(\n \"synapse/request-file returned a result without a string `id`. \" +\n \"The host appears to be on a version older than this SDK targets — \" +\n \"@nimblebrain/synapse 0.8.0+ requires a host with POST /v1/resources \" +\n \"(NimbleBrain ≥ the version that ships PR #93).\",\n );\n }\n return value as FileResult;\n}\n\n/** Shallow equality for `SynapseTheme` — used by `onThemeChanged` to filter\n * host-context changes that don't actually move the theme (e.g. a workspace\n * switch that leaves theme/styles untouched). Cheap; tokens are ~40 entries.\n * Typography counts: a host can swap typeface without touching mode or tokens,\n * and that must still reach subscribers. */\nfunction themesEqual(a: SynapseTheme, b: SynapseTheme): boolean {\n if (a.mode !== b.mode || a.primaryColor !== b.primaryColor) return false;\n if (fontFacesKey(a.fontFaces) !== fontFacesKey(b.fontFaces)) return false;\n const aKeys = Object.keys(a.tokens);\n const bKeys = Object.keys(b.tokens);\n if (aKeys.length !== bKeys.length) return false;\n // Iterating only over `a`'s keys is sufficient: under equal length, any\n // key in `a` missing from `b` reads `b[k] === undefined`, which fails the\n // strict-inequality check. Symmetric difference is covered.\n for (const k of aKeys) {\n if (a.tokens[k] !== b.tokens[k]) return false;\n }\n return true;\n}\n"]}
|