@ethisyscore/extension-runtime 1.71.0 → 1.71.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/host/worker/offscreen.ts","../../src/host/version-skew.ts","../../src/host/worker/bridge-envelopes.ts","../../src/host/worker/transport.ts","../../src/host/worker/component-registry.ts","../../src/mock-host/cli.ts"],"names":["path","fs","KNOWN_PRIMITIVES"],"mappings":"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","file":"cli.cjs","sourcesContent":["/**\n * OffscreenCanvas transfer helpers + pointer/keyboard coalescing for\n * Contract B (worker remote-runtime) extensions.\n *\n * **Architecture.** Hosts that expose a {@link import(\"./component-registry\").SemanticComponentRegistry}'s\n * `CanvasSurface` / `WebGLSurface` primitive create a host-side `<canvas>`,\n * transfer control to the worker via {@link createOffscreenCanvasTransfer}, and\n * the plugin (running inside the worker realm) calls `offscreen.getContext()`\n * to render. The `<canvas>` is owned by the host DOM tree (so layout, theming,\n * and accessibility properties stay on the host side) but every pixel is\n * produced inside the worker — no per-frame `postMessage` cost, no main-thread\n * blocking.\n *\n * **Pointer / keyboard delivery.** Input events still originate on the host\n * `<canvas>`. To avoid spraying the worker port with per-event traffic the\n * host should wrap pointer-move / wheel / scroll callbacks in\n * {@link createInputEventCoalescer}, matching the trailing-edge coalescer\n * already documented in {@link import(\"./transport\").WorkerRemoteDomTransport}\n * (default 16ms ≈ one rAF). Keyboard events MUST use `discrete: true` —\n * coalescing them would drop characters.\n *\n * **Security.** No capability token, no MCP traffic, and no host-only globals\n * cross via the offscreen transfer. The transfer envelope is plain JSON with a\n * single `OffscreenCanvas` handle in the transfer list — the worker side\n * receives an opaque drawing surface and nothing else.\n */\n\n// ─── Public constants ────────────────────────────────────────────────────────\n\n/**\n * Default trailing-edge coalesce window for pointer / wheel / scroll events,\n * in milliseconds. 16ms ≈ one animation frame at 60Hz. Matches the default\n * documented in {@link import(\"./transport\").WorkerRemoteDomTransport}.\n */\nexport const DEFAULT_OFFSCREEN_COALESCE_MS = 16;\n\n// ─── Transfer envelope ───────────────────────────────────────────────────────\n\n/**\n * Host → worker envelope shape for an `OffscreenCanvas` transfer. Stable wire\n * contract — the worker side decodes by `type` and uses `surfaceId` to bind\n * the offscreen to the right host slot when a plugin renders multiple\n * canvases concurrently.\n */\nexport interface OffscreenTransferMessage\n{\n type: \"ethisys:offscreen:transfer\";\n surfaceId: string;\n width: number;\n height: number;\n offscreen: OffscreenCanvas;\n}\n\n/**\n * Construction options for {@link createOffscreenCanvasTransfer}.\n */\nexport interface OffscreenCanvasTransferOptions\n{\n /**\n * The host-owned `<canvas>` element. Its `width` / `height` are captured\n * before transfer so the worker sees the intended pixel dimensions even if\n * the host element resizes later (host should send a separate resize\n * message in that case).\n */\n canvas: HTMLCanvasElement;\n\n /**\n * Stable identifier the worker uses to route the offscreen to the matching\n * surface slot. Typically the SDUI node id of the `CanvasSurface` /\n * `WebGLSurface` primitive that the worker will draw into.\n */\n surfaceId: string;\n\n /**\n * Host-side postMessage function — typically the\n * {@link import(\"./transport\").WorkerRemoteDomTransport}'s port-side\n * `postMessage`. Tests inject a spy.\n */\n postMessage(message: OffscreenTransferMessage, transfer: Transferable[]): void;\n}\n\n/**\n * Successful transfer result. The caller retains a reference to the\n * `OffscreenCanvas` only for observability (e.g., to wire to the worker's\n * reply handshake) — direct rendering from the host side is forbidden because\n * control has already been transferred and any host-side draw call would\n * throw.\n */\nexport interface OffscreenCanvasTransferResult\n{\n offscreen: OffscreenCanvas;\n}\n\n/**\n * Module-scoped WeakSet tracking canvases this SDK has already transferred.\n *\n * Stored OUTSIDE the DOM node deliberately:\n *\n * - Writing an SDK expando (e.g. `__ethisysOffscreenTransferred`) onto a host-\n * owned `<canvas>` mutates state the host doesn't own. A WeakSet keeps the\n * bookkeeping on the SDK side and lets the canvas object stay pristine.\n * - WeakSet entries are collected when the canvas is GC'd, so the guard does\n * not leak memory for plugins that mount and unmount many surfaces.\n * - WeakSet membership is identity-based, so React/concurrent remount paths\n * that re-use the SAME node still see \"already transferred\"; a fresh DOM\n * node (always allocated by React when the key changes) is a fresh entry.\n */\nconst transferredCanvases: WeakSet<HTMLCanvasElement> = new WeakSet<HTMLCanvasElement>();\n\n/**\n * Transfer control of a host-owned `<canvas>` to the worker.\n *\n * Throws if:\n * - the environment lacks `HTMLCanvasElement.prototype.transferControlToOffscreen`\n * (the helper does NOT silently fall back — Contract B clients must require\n * the API and surface a clear error in unsupported browsers);\n * - the same canvas has already had control transferred (idempotency is the\n * caller's responsibility — re-transferring would throw in the browser\n * anyway, but we raise a clearer, diagnosable message ahead of that).\n */\nexport function createOffscreenCanvasTransfer(\n options: OffscreenCanvasTransferOptions,\n): OffscreenCanvasTransferResult\n{\n const { canvas, surfaceId, postMessage } = options;\n const proto = HTMLCanvasElement.prototype as unknown as {\n transferControlToOffscreen?: () => OffscreenCanvas;\n };\n if (typeof proto.transferControlToOffscreen !== \"function\")\n {\n throw new Error(\n \"[offscreen-canvas] OffscreenCanvas is not supported in this environment. \" +\n \"Contract B canvas surfaces require a browser with HTMLCanvasElement.transferControlToOffscreen.\",\n );\n }\n if (transferredCanvases.has(canvas))\n {\n throw new Error(\n `[offscreen-canvas] canvas already transferred (surfaceId='${surfaceId}'). ` +\n \"Create a fresh <canvas> for each surface instead of re-transferring.\",\n );\n }\n\n const offscreen = canvas.transferControlToOffscreen();\n transferredCanvases.add(canvas);\n\n const envelope: OffscreenTransferMessage = {\n type: \"ethisys:offscreen:transfer\",\n surfaceId,\n width: canvas.width,\n height: canvas.height,\n offscreen,\n };\n postMessage(envelope, [offscreen]);\n\n return { offscreen };\n}\n\n// ─── Coalescing ──────────────────────────────────────────────────────────────\n\n/**\n * Construction options for {@link createInputEventCoalescer}.\n */\nexport interface InputEventCoalescerOptions\n{\n /**\n * Coalesce window in milliseconds. Ignored when {@link discrete} is true.\n * Defaults to {@link DEFAULT_OFFSCREEN_COALESCE_MS} (16ms — one rAF).\n */\n coalesceMs?: number;\n\n /**\n * When `true`, forward every payload synchronously without coalescing.\n * Use this for keyboard events — coalescing would drop characters by\n * collapsing multiple key strokes into one trailing delivery.\n */\n discrete?: boolean;\n}\n\n/**\n * Build a trailing-edge input-event coalescer. The pattern matches\n * {@link import(\"./transport\").WorkerRemoteDomTransport.createCoalescer} —\n * factored out here so OffscreenCanvas callers don't need to construct a full\n * transport just to coalesce pointer-move events.\n *\n * Trailing-edge semantics: every burst within a coalesce window collapses to\n * a single delivery carrying the **last** payload seen in the window. A new\n * payload arriving after a window has flushed starts a fresh window.\n */\nexport function createInputEventCoalescer<T>(\n sink: (payload: T) => void,\n options: InputEventCoalescerOptions = {},\n): (payload: T) => void\n{\n if (options.discrete === true)\n {\n // Discrete mode: pass through unchanged. Keyboard input belongs here.\n return (payload: T) =>\n {\n sink(payload);\n };\n }\n const coalesceMs = options.coalesceMs ?? DEFAULT_OFFSCREEN_COALESCE_MS;\n let pending: T | undefined;\n let pendingSet = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const flush = (): void =>\n {\n timer = undefined;\n if (!pendingSet)\n {\n return;\n }\n const value = pending as T;\n pending = undefined;\n pendingSet = false;\n sink(value);\n };\n\n return (payload: T) =>\n {\n pending = payload;\n pendingSet = true;\n if (timer === undefined)\n {\n timer = setTimeout(flush, coalesceMs);\n }\n };\n}\n","/**\n * Version-skew detection for host-side MCP calls.\n *\n * A mounted plugin surface holds a capability token minted against the extension version that\n * was active when the page loaded. When the install is upgraded underneath it, the kernel stops\n * honouring that token: it rejects with `401` and\n * `X-Capability-Token-Rejection-Reason: ExtensionVersionMismatch`. Every other rejection reason is\n * terminal for the surface, but this one is recoverable — remounting against the new version fixes\n * it — which is why it is worth telling apart from an ordinary auth failure.\n *\n * Two signals are handled here, and the difference matters:\n *\n * - **Reactive**, from a rejection: the call already failed. Recovery costs the user a round trip\n * and whatever in-page state the remount discards.\n * - **Proactive**, from the version stamped on a *successful* response: the surface learns the\n * install moved while it is still working, and can remount at a moment of its choosing. Reads\n * keep succeeding until the token's own version check catches up, so this is the path that\n * avoids a visible failure altogether.\n *\n * The interpretation lives here rather than in each host application so that \"which reason means\n * remount\" is decided once, in code that can be tested, instead of being re-derived by every\n * embedder from HTTP trivia.\n */\n\n/** Response header naming the extension version a request was served as. */\nexport const EXTENSION_VERSION_HEADER = \"x-extension-version\";\n\n/** Response header naming the version a rejected surface must remount at. */\nexport const EXTENSION_ACTIVE_VERSION_HEADER = \"x-extension-active-version\";\n\n/** Response header carrying the kernel's structured capability-token rejection reason. */\nexport const CAPABILITY_REJECTION_REASON_HEADER = \"x-capability-token-rejection-reason\";\n\n/** The one rejection reason a surface can resolve by remounting. */\nexport const VERSION_MISMATCH_REASON = \"extensionversionmismatch\";\n\n/**\n * What the host observed about an MCP response, beyond its payload. Both fields are optional\n * because the {@link McpHttpClient} contract predates them: an implementation that does not supply\n * them simply never reports skew, which is the previous behaviour rather than a new failure.\n */\nexport interface McpResponseMetadata\n{\n /** HTTP status code, when the implementation surfaces it. */\n readonly status?: number;\n\n /** Response headers. Looked up case-insensitively, so any casing is fine. */\n readonly headers?: Readonly<Record<string, string>>;\n}\n\n/**\n * How skew came to light.\n *\n * - `\"rejection\"` — a call was refused because the surface's token is stale. Recovery costs a round\n * trip and whatever in-page state the remount discards.\n * - `\"response-stamp\"` — a call succeeded, but the install has moved on. The surface can remount\n * before anything fails, so this is the path worth preferring.\n */\nexport type VersionSkewSource = \"rejection\" | \"response-stamp\";\n\n/**\n * The result of one host-side MCP call: the payload the plugin asked for, plus whatever the host\n * observed about the response itself.\n *\n * Named rather than inlined at the {@link McpHttpClient} declaration so hosts have a type to\n * implement against, and so the skew detector and the transports agree on one shape instead of\n * three structurally-compatible copies drifting apart.\n */\nexport interface McpHttpResponse extends McpResponseMetadata\n{\n /** Whether the call succeeded. */\n readonly ok: boolean;\n\n /** The response payload, shaped by the request kind. */\n readonly data?: unknown;\n\n /** Failure message when {@link ok} is false. */\n readonly error?: string;\n}\n\n/** A detected mismatch between the version a surface is running and the version now installed. */\nexport interface VersionSkew\n{\n /**\n * The version to remount at, when the kernel named it. Undefined means skew is certain but the\n * target is not — the surface should re-read the extension descriptor rather than guess.\n */\n readonly activeVersion?: string;\n\n /** Which signal detected the skew. */\n readonly detectedFrom: VersionSkewSource;\n}\n\n/**\n * Case-insensitive header read. Hosts pass headers through from whatever HTTP client they use, and\n * casing varies by implementation (`fetch` lower-cases, some proxies and Node clients do not), so\n * matching exactly would make detection depend on the embedder's plumbing.\n */\nfunction readHeader(headers: Readonly<Record<string, string>> | undefined, name: string): string | undefined\n{\n if (!headers)\n {\n return undefined;\n }\n const direct = headers[name];\n if (direct !== undefined)\n {\n return direct;\n }\n const lowered = name.toLowerCase();\n for (const key of Object.keys(headers))\n {\n if (key.toLowerCase() === lowered)\n {\n return headers[key];\n }\n }\n return undefined;\n}\n\nfunction trimmedOrUndefined(value: string | undefined): string | undefined\n{\n const trimmed = value?.trim();\n return trimmed !== undefined && trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Decides whether an MCP response means the surface is running against a version that is no longer\n * installed.\n *\n * @param response What the host observed: whether the call succeeded, plus any status and headers.\n * @param mountedExtensionVersion The version this surface mounted at. Required for proactive\n * detection — without it a response stamp cannot be compared to anything, and only rejections are\n * detectable.\n * @returns The skew, or `null` when the response says nothing about versions.\n */\nexport function detectVersionSkew(\n response: McpHttpResponse,\n mountedExtensionVersion?: string): VersionSkew | null\n{\n const reason = trimmedOrUndefined(readHeader(response.headers, CAPABILITY_REJECTION_REASON_HEADER));\n if (reason !== undefined && reason.toLowerCase() === VERSION_MISMATCH_REASON)\n {\n return {\n activeVersion: trimmedOrUndefined(readHeader(response.headers, EXTENSION_ACTIVE_VERSION_HEADER)),\n detectedFrom: \"rejection\",\n };\n }\n\n // Proactive: only meaningful on a call that worked. A failed response's stamp says nothing\n // about the install having moved — the failure has its own cause, and treating it as skew\n // would remount the surface on every unrelated error.\n if (!response.ok)\n {\n return null;\n }\n\n const mounted = trimmedOrUndefined(mountedExtensionVersion);\n const served = trimmedOrUndefined(readHeader(response.headers, EXTENSION_VERSION_HEADER));\n if (mounted === undefined || served === undefined || served === mounted)\n {\n return null;\n }\n\n return { activeVersion: served, detectedFrom: \"response-stamp\" };\n}\n","/**\n * Wire-shape constants and type guards for host→plugin bridge push messages\n * (WI 4858 sub-plan 2). These types ride the existing MessagePort channel\n * alongside the `ethisys:mcp:*` and `ethisys:remotedom` envelopes — the\n * `type` discriminant keeps them fully separate at the dispatch site.\n *\n * The host posts bridge pushes through `WorkerRemoteDomTransport.hostPort`;\n * the plugin side reads them in `createPortBridgeClient` (plugin-ui package).\n * In-realm (Tier T) plugins use `InMemoryBridgeTransport` which calls the\n * subscriber callbacks directly — no serialisation needed.\n */\n\n// ── Type constants ───────────────────────────────────────────────────────────\n\nexport const BRIDGE_PUSH_THEME = \"ethisys:bridge:theme\" as const;\nexport const BRIDGE_PUSH_LOCALE = \"ethisys:bridge:locale\" as const;\nexport const BRIDGE_PUSH_DENSITY = \"ethisys:bridge:density\" as const;\nexport const BRIDGE_PUSH_A11Y = \"ethisys:bridge:a11y\" as const;\nexport const BRIDGE_NAV_PUSH = \"ethisys:bridge:nav\" as const;\nexport const BRIDGE_CHROME_REQUEST = \"ethisys:bridge:chrome:request\" as const;\nexport const BRIDGE_CHROME_RESPONSE = \"ethisys:bridge:chrome:response\" as const;\nexport const BRIDGE_SESSION_TOKEN_PUSH = \"ethisys:bridge:token\" as const;\nexport const BRIDGE_LIFECYCLE_EVENT = \"ethisys:bridge:lifecycle\" as const;\nexport const BRIDGE_A11Y_ANNOUNCE = \"ethisys:bridge:a11y:announce\" as const;\n\n// ── Envelope shapes ──────────────────────────────────────────────────────────\n\n/** Theme push: host → plugin whenever the host theme changes. */\nexport interface BridgePushThemeEnvelope {\n readonly type: typeof BRIDGE_PUSH_THEME;\n /** \"light\" | \"dark\" | \"high-contrast\" */\n readonly mode: string;\n /** Flat design-token map (CSS-variable-name → value). May be empty. */\n readonly tokens: Readonly<Record<string, string>>;\n}\n\n/** Locale push: host → plugin whenever the active locale changes. */\nexport interface BridgePushLocaleEnvelope {\n readonly type: typeof BRIDGE_PUSH_LOCALE;\n /** BCP 47 tag, e.g. \"en-GB\". */\n readonly locale: string;\n /** \"ltr\" | \"rtl\" */\n readonly dir: \"ltr\" | \"rtl\";\n}\n\n/** Density push: host → plugin when the UI density preference changes. */\nexport interface BridgePushDensityEnvelope {\n readonly type: typeof BRIDGE_PUSH_DENSITY;\n /** \"comfortable\" | \"compact\" */\n readonly density: string;\n}\n\n/** A11y push: host → plugin when accessibility prefs change. */\nexport interface BridgePushA11yEnvelope {\n readonly type: typeof BRIDGE_PUSH_A11Y;\n readonly reducedMotion: boolean;\n readonly highContrast: boolean;\n}\n\n/** Nav push: host → plugin when the SPA location changes. */\nexport interface BridgeNavPushEnvelope {\n readonly type: typeof BRIDGE_NAV_PUSH;\n /** Current SPA path (pathname + search). */\n readonly path: string;\n /** `window.history.length` at the time of push. */\n readonly historyLength: number;\n}\n\n/** Plugin → host: request a chrome action (e.g. toast, modal). */\nexport interface BridgeChromeRequestEnvelope {\n readonly type: typeof BRIDGE_CHROME_REQUEST;\n /** Correlation id — matched against the response. */\n readonly id: string;\n /** \"toast\" | \"confirm\" | \"openUrl\" */\n readonly action: string;\n readonly payload: Readonly<Record<string, unknown>>;\n}\n\n/** Host → plugin: response to a chrome request. */\nexport interface BridgeChromeResponseEnvelope {\n readonly type: typeof BRIDGE_CHROME_RESPONSE;\n readonly id: string;\n readonly ok: boolean;\n readonly result?: unknown;\n readonly error?: string;\n}\n\n/** Host → plugin: push a short-lived frontend-session token. */\nexport interface BridgeSessionTokenPushEnvelope {\n readonly type: typeof BRIDGE_SESSION_TOKEN_PUSH;\n /** Opaque JWT string — audience-restricted to the plugin's own backend. */\n readonly token: string;\n /** Absolute epoch-ms at which the token expires. Refresh fires 30 s before. */\n readonly expiresAtMs: number;\n}\n\n/** Host ↔ plugin lifecycle event. */\nexport type BridgeLifecyclePhase = \"load\" | \"ready\" | \"error\" | \"unload\";\n\nexport interface BridgeLifecycleEventEnvelope {\n readonly type: typeof BRIDGE_LIFECYCLE_EVENT;\n readonly phase: BridgeLifecyclePhase;\n /** Present when phase === \"error\". */\n readonly message?: string;\n}\n\n/** Plugin → host: a11y live-region announcement request. */\nexport interface BridgeA11yAnnounceEnvelope {\n readonly type: typeof BRIDGE_A11Y_ANNOUNCE;\n readonly message: string;\n /** \"polite\" | \"assertive\" */\n readonly politeness: \"polite\" | \"assertive\";\n}\n\n// ── Type guards ──────────────────────────────────────────────────────────────\n\nfunction isObj(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === \"object\";\n}\n\nexport function isBridgePushTheme(v: unknown): v is BridgePushThemeEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_THEME && typeof v[\"mode\"] === \"string\";\n}\n\nexport function isBridgePushLocale(v: unknown): v is BridgePushLocaleEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_LOCALE && typeof v[\"locale\"] === \"string\";\n}\n\nexport function isBridgePushDensity(v: unknown): v is BridgePushDensityEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_DENSITY && typeof v[\"density\"] === \"string\";\n}\n\nexport function isBridgePushA11y(v: unknown): v is BridgePushA11yEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_A11Y\n && typeof v[\"reducedMotion\"] === \"boolean\"\n && typeof v[\"highContrast\"] === \"boolean\";\n}\n\nexport function isBridgeNavPush(v: unknown): v is BridgeNavPushEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_NAV_PUSH && typeof v[\"path\"] === \"string\";\n}\n\nexport function isBridgeChromeRequest(v: unknown): v is BridgeChromeRequestEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_CHROME_REQUEST && typeof v[\"id\"] === \"string\";\n}\n\nexport function isBridgeChromeResponse(v: unknown): v is BridgeChromeResponseEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_CHROME_RESPONSE && typeof v[\"id\"] === \"string\";\n}\n\nexport function isBridgeSessionTokenPush(v: unknown): v is BridgeSessionTokenPushEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_SESSION_TOKEN_PUSH\n && typeof v[\"token\"] === \"string\"\n && typeof v[\"expiresAtMs\"] === \"number\";\n}\n\nexport function isBridgeLifecycleEvent(v: unknown): v is BridgeLifecycleEventEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_LIFECYCLE_EVENT && typeof v[\"phase\"] === \"string\";\n}\n\nexport function isBridgeA11yAnnounce(v: unknown): v is BridgeA11yAnnounceEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_A11Y_ANNOUNCE && typeof v[\"message\"] === \"string\";\n}\n","/**\n * Worker-side host transport for `renderMode: remote-runtime` extensions\n * (Contract B). Owns the lifecycle of:\n *\n * 1. A path-pinned module `Worker` spawned from a host-issued bootstrap URL.\n * 2. A `MessagePort`-based RPC channel (handed to the worker on spawn).\n * 3. A Shopify Remote DOM root receiver — wired here so the worker's UI\n * tree mounts into a host React tree.\n * 4. Event coalescing (default ≤16ms, one rAF) for high-frequency input\n * events before they cross the port.\n * 5. MCP tool/resource calls forwarded through the port — but **the\n * capability token never crosses the boundary**. The token is bound\n * to the worker scope on the HOST side: the host transport intercepts\n * the plugin's MCP request, attaches the token to the outbound HTTP\n * call, and forwards ONLY the response payload back through the port.\n *\n * This module is intentionally framework-thin: callers wire `mount(root)`\n * onto a React tree (typically inside a `<WorkerSurfaceMount>`), and the\n * Remote DOM receiver is responsible for translating worker-side\n * RemoteRoot mutations into host-side component renders.\n */\n\nimport { createOffscreenCanvasTransfer } from \"./offscreen\";\nimport type { UploadDocumentMeta } from \"../../plugin/transport\";\nimport {\n detectVersionSkew,\n type McpHttpResponse,\n type VersionSkew,\n} from \"../version-skew\";\nimport {\n BRIDGE_PUSH_THEME,\n BRIDGE_PUSH_LOCALE,\n BRIDGE_PUSH_DENSITY,\n BRIDGE_PUSH_A11Y,\n BRIDGE_NAV_PUSH,\n BRIDGE_CHROME_REQUEST,\n BRIDGE_A11Y_ANNOUNCE,\n BRIDGE_LIFECYCLE_EVENT,\n type BridgePushThemeEnvelope,\n type BridgePushLocaleEnvelope,\n type BridgePushDensityEnvelope,\n type BridgePushA11yEnvelope,\n type BridgeNavPushEnvelope,\n} from \"./bridge-envelopes\";\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/**\n * Structural subset of the DOM `Worker` interface that the transport needs.\n * Tests inject a fake; production callers pass the global `Worker`.\n */\nexport interface WorkerLike\n{\n onmessage: ((ev: MessageEvent) => void) | null;\n onerror: ((ev: ErrorEvent) => void) | null;\n onmessageerror: ((ev: MessageEvent) => void) | null;\n postMessage(message: unknown, transfer?: Transferable[]): void;\n terminate(): void;\n}\n\n/**\n * Constructor signature compatible with the DOM `Worker` constructor. The\n * `workerCtor` option exists exclusively so tests can swap in a fake — in\n * production the caller passes the global `Worker`.\n */\nexport type WorkerCtor = new (url: string | URL, options?: WorkerOptions) => WorkerLike;\n\n/**\n * Discriminated union of MCP fetch shapes the host transport issues. The\n * `capabilityToken` is attached on the host side ONLY — it is never present\n * in any message that crosses the worker port.\n */\nexport type McpHttpRequest =\n | {\n kind: \"invokeTool\";\n name: string;\n args: unknown;\n capabilityToken: string;\n signal?: AbortSignal;\n }\n | {\n kind: \"getResource\";\n uri: string;\n capabilityToken: string;\n signal?: AbortSignal;\n }\n | McpUploadRequest;\n\n/**\n * Host-side document-upload request (a `kind` of {@link McpHttpRequest}).\n * Carries the transferred bytes + advisory metadata plus the host-minted\n * capability token. As with the other request kinds, the token is attached on\n * the HOST side only and never crosses the worker port. Implementations POST\n * the bytes as `application/octet-stream` (metadata in `x-cc-*` headers) to the\n * kernel's capability-token-authed document-upload route; `data` on success is\n * an {@link UploadDocumentResult}.\n */\nexport interface McpUploadRequest\n{\n kind: \"uploadDocument\";\n meta: UploadDocumentMeta;\n buffer: ArrayBuffer;\n capabilityToken: string;\n signal?: AbortSignal;\n}\n\n/**\n * Host-side HTTP client for MCP calls. Implementations are responsible for\n * carrying the supplied `capabilityToken` on the outbound request (typically\n * via `Authorization: Bearer` / `PluginCap`). The `uploadDocument` kind is\n * additive — implementations that predate it fall through to their unknown-kind\n * branch until updated (the FE upload hook is inert until the host handles it).\n */\nexport interface McpHttpClient\n{\n /**\n * Performs the call. The response's `status` and `headers` are optional and additive: supplying\n * them is what enables version-skew detection (see {@link detectVersionSkew}), and an\n * implementation that omits them behaves exactly as before rather than failing.\n */\n fetch(request: McpHttpRequest): Promise<McpHttpResponse>;\n}\n\n/**\n * Construction options for {@link WorkerRemoteDomTransport}.\n */\nexport interface WorkerRemoteDomTransportOptions\n{\n /**\n * Canonical host-origin URL for the worker bootstrap script. This MUST\n * be supplied by the host — never built from user input or extension\n * manifest values — so the worker spawn is path-pinned.\n */\n bootstrapUrl: string;\n\n /**\n * Mints (or fetches a cached) capability token. The host transport\n * resolves this for each outbound MCP HTTP call. The token NEVER leaves\n * host scope — plugin code (the worker side) cannot read it.\n */\n capabilityToken: () => Promise<string>;\n\n /**\n * Host-side MCP HTTP client. The transport bridges port-side plugin\n * MCP requests to this client and returns only the response payload\n * back through the port.\n */\n mcpClient: McpHttpClient;\n\n /**\n * The extension version this surface mounted at. Supplying it enables *proactive* skew\n * detection: a successful response stamped with a different version means the install moved\n * while the surface is still working, so it can remount before anything fails. Without it only\n * outright rejections are detectable, which is a worse experience but not a broken one.\n */\n mountedExtensionVersion?: string;\n\n /**\n * Called at most once, when this surface is found to be running against a version that is no\n * longer installed. The host is expected to remount the surface (which re-mints a capability\n * token against the new version); the transport itself does not retry, because the pending call\n * belongs to a page that is about to be replaced.\n */\n onVersionSkew?: (skew: VersionSkew) => void;\n\n /**\n * Injectable Worker constructor (tests use a fake). Defaults to the\n * global `Worker`.\n */\n workerCtor?: WorkerCtor;\n\n /**\n * Coalescing window in milliseconds for high-frequency events. Defaults\n * to 16ms (~one animation frame). Trailing-edge: the most recent payload\n * within the window is delivered after the window elapses.\n */\n coalesceMs?: number;\n\n /**\n * Maximum number of MCP requests (combined `invokeTool` + `getResource`)\n * the transport will forward to {@link mcpClient} concurrently. Defaults\n * to 8. Requests above the cap are rejected with a deterministic error\n * reply over the port — the worker MUST handle that response shape.\n *\n * Bounded concurrency is a back-pressure boundary, not a quota: it stops\n * a compromised or buggy worker from saturating the host's HTTP / token\n * pool. Production hosts may want to lower this in multi-tenant pools\n * where many extensions share one host process.\n */\n maxConcurrentMcpRequests?: number;\n}\n\n/**\n * Wire shape of a host-sourced input event forwarded to the worker over the\n * port. Pointer / wheel / keyboard payloads share a single envelope type so\n * the worker has one inbound dispatch site. The transport is structurally\n * agnostic to the payload — it forwards verbatim.\n *\n * `kind` discriminates the event family. Coordinates are CSS pixels relative\n * to the host canvas; coalescing happens host-side before the call to\n * {@link WorkerRemoteDomTransport.postInputEvent}.\n */\nexport type InputEventPayload =\n | {\n kind: \"pointermove\" | \"pointerdown\" | \"pointerup\" | \"pointercancel\";\n surfaceId: string;\n x: number;\n y: number;\n buttons: number;\n pointerType: string;\n }\n | {\n kind: \"wheel\";\n surfaceId: string;\n deltaX: number;\n deltaY: number;\n deltaMode: number;\n }\n | {\n kind: \"keydown\" | \"keyup\";\n surfaceId: string;\n key: string;\n code: string;\n ctrlKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n metaKey: boolean;\n };\n\n/**\n * Documented wire protocol identifier embedded in handshake / message\n * envelopes. Bumped when the worker ↔ host message shape changes in a\n * backward-incompatible way.\n */\nexport const WORKER_TRANSPORT_PROTOCOL = \"ethisys.worker.remotedom.v1\";\n\n/**\n * Wire shape of the handshake message the host posts to the worker on\n * {@link WorkerRemoteDomTransport.connect}. Locked here so the SDK side and the\n * API-hosted bootstrap script (`WorkerBootstrapScriptProvider`) read from the\n * same field names — see the API tests pinning `event.data.moduleUrl` and\n * `event.data.importMap`.\n *\n * The handshake is the SOLE message that ever carries `moduleUrl` or\n * `importMap`; subsequent port traffic uses the discriminated message types\n * declared below. The capability token NEVER appears in this payload (or any\n * other postMessage payload) — it is bound on the host side via\n * {@link WorkerRemoteDomTransportOptions.capabilityToken}.\n */\nexport interface WorkerHandshakePayload\n{\n readonly type: \"ethisys:worker:handshake\";\n readonly protocol: string;\n /** Host-origin URL of the plugin's worker bundle entry. */\n readonly moduleUrl: string;\n /**\n * Frozen bare-specifier → host-origin URL map that the bootstrap installs\n * before importing {@link moduleUrl}. Pulled from the plugin's\n * `worker-bundle.import-map.json` at runtime by the host mount.\n */\n readonly importMap: Readonly<Record<string, string>>;\n}\n\n// ─── Implementation ───────────────────────────────────────────────────────────\n\ninterface InvokeToolMessage\n{\n id: string;\n type: \"ethisys:mcp:invokeTool\";\n name: string;\n args: unknown;\n}\n\ninterface GetResourceMessage\n{\n id: string;\n type: \"ethisys:mcp:getResource\";\n uri: string;\n}\n\ninterface UploadDocumentMessage\n{\n id: string;\n type: \"ethisys:mcp:uploadDocument\";\n meta: UploadDocumentMeta;\n buffer: ArrayBuffer;\n}\n\ninterface RemoteDomMessage\n{\n type: \"ethisys:remotedom\";\n payload: unknown;\n}\n\ntype InboundMessage = InvokeToolMessage | GetResourceMessage | UploadDocumentMessage | RemoteDomMessage | { type: string; [k: string]: unknown };\n\n/**\n * Worker-side host transport for Contract B extensions.\n *\n * Construction immediately spawns the worker and transfers one end of a\n * fresh `MessageChannel`; the host retains `port1`, the worker receives\n * `port2`. Both sides exchange messages via their port and the worker port\n * is the *only* channel for plugin ↔ host traffic after handshake.\n */\n/**\n * Default cap for in-flight MCP requests forwarded by the transport. Chosen to\n * cover typical interactive UI traffic (dashboards, list views, detail panels)\n * without letting a runaway worker saturate the host's HTTP / token pool.\n */\nexport const DEFAULT_MAX_CONCURRENT_MCP_REQUESTS = 8;\n\nexport class WorkerRemoteDomTransport\n{\n private readonly worker: WorkerLike;\n private readonly hostPort: MessagePort;\n private readonly workerPort: MessagePort;\n private readonly mcpClient: McpHttpClient;\n private readonly capabilityTokenProvider: () => Promise<string>;\n private readonly mountedExtensionVersion?: string;\n private readonly onVersionSkew?: (skew: VersionSkew) => void;\n private versionSkewReported = false;\n private readonly coalesceMs: number;\n private readonly maxConcurrentMcpRequests: number;\n private readonly abortController: AbortController;\n // Per-request AbortControllers keyed by request id. An inbound\n // `ethisys:mcp:abort` envelope (the worker posts one when a hook's\n // AbortSignal fires on unmount / arg change) aborts just that request;\n // dispose() fans out to every registered controller. Without this a\n // cancelled call — most costly for uploadDocument — keeps streaming to the\n // kernel even though the plugin promise already rejected.\n private readonly inFlightAborts = new Map<string, AbortController>();\n private inFlightMcpRequests = 0;\n private remoteDomConsumer: ((payload: unknown) => void) | undefined;\n private bridgeMessageConsumer: ((msg: unknown) => void) | undefined;\n private disposed = false;\n private connected = false;\n\n public constructor(options: WorkerRemoteDomTransportOptions)\n {\n const WorkerCtor = options.workerCtor ?? (globalThis as unknown as { Worker: WorkerCtor }).Worker;\n if (!WorkerCtor)\n {\n throw new Error(\"WorkerRemoteDomTransport: no Worker constructor available\");\n }\n\n this.mcpClient = options.mcpClient;\n this.capabilityTokenProvider = options.capabilityToken;\n this.mountedExtensionVersion = options.mountedExtensionVersion;\n this.onVersionSkew = options.onVersionSkew;\n this.coalesceMs = options.coalesceMs ?? 16;\n this.maxConcurrentMcpRequests = Math.max(\n 1,\n options.maxConcurrentMcpRequests ?? DEFAULT_MAX_CONCURRENT_MCP_REQUESTS,\n );\n // Aborted from dispose() — propagates into the mcpClient.fetch path so\n // already-in-flight HTTP calls can short-circuit instead of resolving\n // into a closed port.\n this.abortController = new AbortController();\n\n // Spawn the worker FIRST so the constructor's spawn shape is\n // observable to tests even if MessageChannel construction throws.\n this.worker = new WorkerCtor(options.bootstrapUrl, { type: \"module\" });\n\n const channel = new MessageChannel();\n this.hostPort = channel.port1;\n this.workerPort = channel.port2;\n\n // Wire host-side port handling before {@link connect} posts the\n // handshake — this closes a race where the worker could reply faster\n // than we wire up.\n this.hostPort.onmessage = (ev) => this.handlePortMessage(ev.data as InboundMessage);\n this.hostPort.start();\n\n this.worker.onerror = (ev) =>\n {\n // Defensive: do NOT echo worker errors back to the worker — they\n // may carry plugin-side details. Host-side observability is the\n // platform's responsibility.\n void ev;\n };\n }\n\n /**\n * Post the handshake to the worker. Idempotent — only the FIRST call\n * transfers the {@link MessagePort} and posts the handshake payload;\n * subsequent calls are silent no-ops. Splitting this off from the\n * constructor lets the host mount fetch the per-plugin\n * `worker-bundle.import-map.json` (and resolve the bundle's module URL)\n * before the bootstrap script consumes them.\n *\n * Wire shape: {@link WorkerHandshakePayload}. The capability token NEVER\n * appears in the payload — it's bound on the host side via the\n * {@link WorkerRemoteDomTransportOptions.capabilityToken} provider.\n *\n * The `moduleUrl` and `importMap` are forwarded to the worker so the\n * bootstrap script (served from the host-pinned\n * `/extensions/runtime/worker-bootstrap.js`) can:\n * 1. Compose the frozen, same-origin-validated `IMPORT_MAP` from the\n * handshake payload (rejecting any cross-origin entries).\n * 2. `safeImport(moduleUrl)` the plugin's entry module.\n *\n * Same-origin enforcement is the bootstrap's job — this transport is\n * structurally agnostic to the host origin and only forwards what it's\n * handed.\n */\n public connect(moduleUrl: string, importMap: Record<string, string>): void\n {\n if (this.connected)\n {\n return;\n }\n this.connected = true;\n\n // Snapshot the import map into a fresh object so the worker handshake\n // is decoupled from caller-side mutation. `Object.freeze` here is\n // defence-in-depth — the worker rebuilds with `Object.create(null)`\n // anyway, but freezing the host-side payload makes mutation a typed\n // error for any host code that hangs onto the reference.\n const handshake: WorkerHandshakePayload = Object.freeze({\n type: \"ethisys:worker:handshake\",\n protocol: WORKER_TRANSPORT_PROTOCOL,\n moduleUrl,\n importMap: Object.freeze({ ...importMap }),\n });\n this.worker.postMessage(handshake, [this.workerPort]);\n }\n\n /**\n * Bind a consumer for Remote DOM mutation payloads emitted by the worker.\n * The Remote DOM receiver wiring is owned by the caller (typically a host\n * React component); this method exposes the raw stream so the receiver\n * can integrate cleanly without a circular package import.\n */\n public onRemoteDom(consumer: (payload: unknown) => void): void\n {\n this.remoteDomConsumer = consumer;\n }\n\n /**\n * Transfer control of a host-owned `<canvas>` to the worker so plugin code\n * can render via `OffscreenCanvas`. The host retains the `<canvas>` for\n * layout / accessibility purposes only — every pixel is produced inside the\n * worker, so the main thread is never blocked per frame.\n *\n * The transfer rides the established MessagePort (not the worker global\n * `postMessage`) so it is multiplexed with the rest of the host ↔ worker\n * traffic on the same channel. The `OffscreenCanvas` handle is the sole\n * `Transferable` in the envelope; no capability token, MCP context, or\n * other host-only data crosses the boundary.\n *\n * Throws if the environment lacks `transferControlToOffscreen()` or if the\n * canvas has already been transferred — see {@link createOffscreenCanvasTransfer}\n * for the exact diagnostics.\n */\n public transferCanvas(\n canvas: HTMLCanvasElement,\n options: { surfaceId: string },\n ): { offscreen: OffscreenCanvas }\n {\n return createOffscreenCanvasTransfer({\n canvas,\n surfaceId: options.surfaceId,\n postMessage: (message, transfer) =>\n {\n this.hostPort.postMessage(message, transfer);\n },\n });\n }\n\n /**\n * Forward a host-sourced input event to the worker over the port. The\n * payload shape is opaque to the transport — pointer / wheel / keyboard\n * envelopes share the same wire type. Callers are expected to wrap\n * high-frequency (pointer-move, wheel, scroll) events in\n * {@link createCoalescer} or {@link createInputEventCoalescer} BEFORE\n * calling this method so the port never sees the un-coalesced flood.\n *\n * Keyboard / pointer-down / pointer-up events are discrete and should be\n * delivered without coalescing — pass them straight through.\n */\n public postInputEvent(payload: InputEventPayload): void\n {\n this.hostPort.postMessage({\n type: \"ethisys:input:event\",\n payload,\n });\n }\n\n /**\n * Build a trailing-edge coalescer keyed to {@link WorkerRemoteDomTransportOptions.coalesceMs}.\n *\n * Use it to wrap pointer-move / scroll / resize callbacks **before**\n * they cross the port. The last payload in any coalescing window is the\n * one that wins.\n */\n public createCoalescer<T>(consumer: (payload: T) => void): (payload: T) => void\n {\n let pending: T | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () =>\n {\n timer = undefined;\n const value = pending;\n pending = undefined;\n if (value !== undefined)\n {\n consumer(value);\n }\n };\n return (payload: T) =>\n {\n pending = payload;\n if (timer === undefined)\n {\n timer = setTimeout(flush, this.coalesceMs);\n }\n };\n }\n\n // ─── Bridge push methods (WI 4858 sub-plan 2) ─────────────────────────────\n\n /**\n * Register a consumer for inbound plugin→host bridge messages\n * (chrome requests, a11y announce, lifecycle events). Only the most recently\n * registered consumer is kept — the host mount wires exactly one.\n */\n public onBridgeMessage(consumer: (msg: unknown) => void): void\n {\n this.bridgeMessageConsumer = consumer;\n }\n\n /**\n * Push the current host theme to the plugin worker. Safe to call on every\n * host theme-context change — the transport coalesces nothing here; rate\n * limiting at the call site is the host's responsibility.\n */\n public pushTheme(payload: Omit<BridgePushThemeEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_THEME, ...payload });\n }\n\n /** Push the current host locale and text direction to the plugin worker. */\n public pushLocale(payload: Omit<BridgePushLocaleEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_LOCALE, ...payload });\n }\n\n /** Push the current UI density preference to the plugin worker. */\n public pushDensity(payload: Omit<BridgePushDensityEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_DENSITY, ...payload });\n }\n\n /** Push updated accessibility preferences to the plugin worker. */\n public pushA11y(payload: Omit<BridgePushA11yEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_A11Y, ...payload });\n }\n\n /** Push the current SPA navigation state to the plugin worker. */\n public pushNav(payload: Omit<BridgeNavPushEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_NAV_PUSH, ...payload });\n }\n\n /**\n * Tear down the worker and port. Idempotent.\n *\n * Order matters: we abort BEFORE closing the port so any in-flight\n * `mcpClient.fetch` that observes the signal short-circuits and the\n * subsequent attempt to post a reply lands in the disposed-guard branch\n * (which silently drops the post) instead of throwing on a closed port.\n */\n public dispose(): void\n {\n if (this.disposed)\n {\n return;\n }\n this.disposed = true;\n try\n {\n this.abortController.abort();\n // Fan out to every in-flight per-request controller so their\n // `mcpClient.fetch` calls short-circuit too — the dispose-level\n // controller is not the signal those requests were handed.\n for (const controller of this.inFlightAborts.values())\n {\n controller.abort();\n }\n this.inFlightAborts.clear();\n }\n catch\n {\n // AbortController.abort() shouldn't throw, but never let dispose\n // crash the caller — teardown must be best-effort across all\n // resources.\n }\n try\n {\n this.hostPort.close();\n }\n catch\n {\n // ignore — port may already be closed\n }\n try\n {\n this.worker.terminate();\n }\n catch\n {\n // ignore\n }\n }\n\n /**\n * Best-effort wrapper around `hostPort.postMessage` that tolerates posts\n * arriving after {@link dispose}. The browser throws on a closed port and\n * the async handlers below can race dispose, so any post initiated by an\n * awaited continuation must be guarded.\n */\n private safePostMessage(message: unknown): void\n {\n if (this.disposed)\n {\n return;\n }\n try\n {\n this.hostPort.postMessage(message);\n }\n catch\n {\n // Port may have been closed between the disposed check and the\n // post call (browser closes ports asynchronously). Swallowing the\n // throw here is safe because we are already on a teardown path.\n }\n }\n\n // ─── Port message handling ──────────────────────────────────────────────\n\n private handlePortMessage(message: InboundMessage): void\n {\n // Post-dispose port traffic is dropped silently. The browser closes\n // MessagePorts asynchronously; any handler invocation after dispose\n // is a race we observe-and-skip rather than try to service.\n if (this.disposed)\n {\n return;\n }\n switch (message.type)\n {\n case \"ethisys:mcp:invokeTool\":\n this.dispatchMcp(message as InvokeToolMessage, \"ethisys:mcp:invokeTool:result\", (m) => this.handleInvokeTool(m));\n return;\n\n case \"ethisys:mcp:getResource\":\n this.dispatchMcp(message as GetResourceMessage, \"ethisys:mcp:getResource:result\", (m) => this.handleGetResource(m));\n return;\n\n case \"ethisys:mcp:uploadDocument\":\n this.dispatchMcp(message as UploadDocumentMessage, \"ethisys:mcp:uploadDocument:result\", (m) => this.handleUploadDocument(m));\n return;\n\n case \"ethisys:mcp:abort\":\n // Client-side cancel (hook unmount / arg change). Abort just the\n // matching in-flight request so its `mcpClient.fetch` short-circuits\n // instead of streaming to completion. The worker has already dropped\n // its pending resolver, so any late `:result` reply is ignored.\n this.inFlightAborts.get((message as { id?: string }).id ?? \"\")?.abort();\n return;\n\n case \"ethisys:remotedom\":\n this.remoteDomConsumer?.((message as RemoteDomMessage).payload);\n return;\n\n case BRIDGE_CHROME_REQUEST:\n case BRIDGE_A11Y_ANNOUNCE:\n case BRIDGE_LIFECYCLE_EVENT:\n this.bridgeMessageConsumer?.(message);\n return;\n\n default:\n // Unknown messages are ignored. The host MUST NOT echo unknown\n // shapes back to the worker — that would create an attacker-\n // controlled reflection surface.\n return;\n }\n }\n\n /**\n * Gate inbound MCP requests through the bounded concurrency window,\n * reject with a deterministic error reply when the cap is exceeded, and\n * decrement the counter unconditionally when the underlying handler\n * settles (regardless of resolution/rejection shape).\n */\n private dispatchMcp<T extends { id: string }>(\n message: T,\n resultType: string,\n handler: (m: T) => Promise<void>,\n ): void\n {\n if (this.inFlightMcpRequests >= this.maxConcurrentMcpRequests)\n {\n // Back-pressure boundary. The worker MUST surface this to plugin\n // code so it can retry / degrade gracefully rather than silently\n // hang on a never-resolving promise.\n this.safePostMessage({\n id: message.id,\n type: resultType,\n ok: false,\n error: `MCP back-pressure: in-flight cap of ${this.maxConcurrentMcpRequests} reached.`,\n });\n return;\n }\n this.inFlightMcpRequests++;\n this.registerRequestAbort(message.id);\n handler(message).finally(() =>\n {\n this.releaseRequestAbort(message.id);\n this.inFlightMcpRequests = Math.max(0, this.inFlightMcpRequests - 1);\n });\n }\n\n /**\n * Create a per-request AbortController and register it under the request id\n * so an inbound `ethisys:mcp:abort` can cancel just this call. If the\n * transport is already disposed the controller starts aborted so the\n * handler's `mcpClient.fetch` short-circuits immediately.\n */\n private registerRequestAbort(id: string): void\n {\n const controller = new AbortController();\n if (this.abortController.signal.aborted)\n {\n controller.abort();\n }\n this.inFlightAborts.set(id, controller);\n }\n\n /** Drop a settled request's AbortController. */\n private releaseRequestAbort(id: string): void\n {\n this.inFlightAborts.delete(id);\n }\n\n /**\n * The signal to hand to `mcpClient.fetch` for a given request: the\n * per-request controller when registered (client cancel path), falling back\n * to the dispose-level controller.\n */\n private requestSignal(id: string): AbortSignal\n {\n return this.inFlightAborts.get(id)?.signal ?? this.abortController.signal;\n }\n\n /**\n * Raises the skew callback the first time this surface is seen to be running against a version\n * that is no longer installed.\n *\n * Latched deliberately. A page typically has several MCP calls in flight, and after an upgrade\n * every one of them reports the same skew — firing per response would ask the host to remount\n * the same surface repeatedly, and the second remount would tear down the first. One signal per\n * transport is all a remount needs, and the transport is discarded along with the surface.\n *\n * The callback is host code, so it is assumed to be able to throw. Two consequences are guarded\n * here: the throw must not escape into the MCP handler's catch (which would reply `ok: false`\n * for a call that actually succeeded), and it must not consume the latch (which would leave the\n * surface with no response AND no further chance of being told to remount).\n */\n private reportVersionSkew(response: McpHttpResponse): void\n {\n if (this.versionSkewReported || this.onVersionSkew === undefined)\n {\n return;\n }\n const skew = detectVersionSkew(response, this.mountedExtensionVersion);\n if (skew === null)\n {\n return;\n }\n try\n {\n this.onVersionSkew(skew);\n this.versionSkewReported = true;\n }\n catch\n {\n // Swallowed on purpose: a failed remount attempt is the host's problem, and turning it\n // into an MCP failure would corrupt a response the plugin is entitled to. The latch\n // stays open so the next response gets another chance to raise it.\n }\n }\n\n private async handleInvokeTool(message: InvokeToolMessage): Promise<void>\n {\n let token: string;\n try\n {\n token = await this.capabilityTokenProvider();\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:invokeTool:result\", err);\n return;\n }\n // Disposed-before-token: short-circuit. The token mint may have\n // resolved seconds after dispose; posting the reply now would race\n // a closed port.\n if (this.disposed)\n {\n return;\n }\n try\n {\n const result = await this.mcpClient.fetch({\n kind: \"invokeTool\",\n name: message.name,\n args: message.args,\n capabilityToken: token,\n signal: this.requestSignal(message.id),\n });\n this.reportVersionSkew(result);\n // CRITICAL: response payload must never include the token. We\n // forward ONLY the public-facing fields the plugin needs.\n this.safePostMessage({\n id: message.id,\n type: \"ethisys:mcp:invokeTool:result\",\n ok: result.ok,\n data: result.data,\n error: result.error,\n });\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:invokeTool:result\", err);\n }\n }\n\n private async handleGetResource(message: GetResourceMessage): Promise<void>\n {\n let token: string;\n try\n {\n token = await this.capabilityTokenProvider();\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:getResource:result\", err);\n return;\n }\n if (this.disposed)\n {\n return;\n }\n try\n {\n const result = await this.mcpClient.fetch({\n kind: \"getResource\",\n uri: message.uri,\n capabilityToken: token,\n signal: this.requestSignal(message.id),\n });\n this.reportVersionSkew(result);\n this.safePostMessage({\n id: message.id,\n type: \"ethisys:mcp:getResource:result\",\n ok: result.ok,\n data: result.data,\n error: result.error,\n });\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:getResource:result\", err);\n }\n }\n\n private async handleUploadDocument(message: UploadDocumentMessage): Promise<void>\n {\n let token: string;\n try\n {\n token = await this.capabilityTokenProvider();\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:uploadDocument:result\", err);\n return;\n }\n // Disposed-before-token: short-circuit. The token mint may have resolved\n // after dispose; posting the reply now would race a closed port.\n if (this.disposed)\n {\n return;\n }\n try\n {\n // CRITICAL security invariant: the worker transferred ONLY bytes +\n // metadata. The capability token is minted + attached here (host\n // side) and never crosses the port. The abort signal propagates so\n // a client cancel / host dispose aborts the octet-stream upload.\n const result = await this.mcpClient.fetch({\n kind: \"uploadDocument\",\n meta: message.meta,\n buffer: message.buffer,\n capabilityToken: token,\n signal: this.requestSignal(message.id),\n });\n this.reportVersionSkew(result);\n // Response payload must never include the token — forward only the\n // public-facing UploadDocumentResult fields.\n this.safePostMessage({\n id: message.id,\n type: \"ethisys:mcp:uploadDocument:result\",\n ok: result.ok,\n data: result.data,\n error: result.error,\n });\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:uploadDocument:result\", err);\n }\n }\n\n private replyError(id: string, type: string, err: unknown): void\n {\n // Surface a sanitised error string — never the raw error object\n // (which may carry stack traces or token fragments from a misbehaving\n // mcpClient implementation). Routed through safePostMessage so a\n // post-dispose reply does not crash on a closed port.\n const message = err instanceof Error ? err.message : \"MCP request failed\";\n this.safePostMessage({ id, type, ok: false, error: message });\n }\n}\n","/**\n * Semantic component registry for Contract B (worker remote-runtime)\n * extensions.\n *\n * Worker-side plugin code references UI primitives by name — e.g.\n * `<DataTable />`, `<Drawer />`, `<CanvasSurface />`. The host owns rendering:\n * a {@link SemanticComponentRegistry} maps each name to a concrete component\n * type, and the Remote DOM host receiver consults the registry on every\n * worker-emitted mutation. The closed primitive vocabulary {@link CONTRACT_B_PRIMITIVES}\n * is intentionally narrow — adding a primitive is a coordinated host change so\n * plugins cannot extend the contract ad hoc.\n *\n * **Alignment with SDUI:** Where the Contract B name overlaps with the\n * `@ethisyscore/protocol` SDUI primitive vocabulary (`DataTable`, `Form`), the\n * names are identical to avoid synonym drift. SDUI's `Action` is intentionally\n * NOT reused — Contract B's interactive primitive is named `Button` so the\n * worker authoring API stays close to React DOM idioms. The two vocabularies\n * may converge as they evolve, but the host registries (Contract A SDUI vs\n * Contract B Semantic) remain distinct surfaces today.\n *\n * The registry is renderer-agnostic — the generic `TComponent` parameter is\n * whatever component type the host supplies (React `ComponentType` in\n * production; plain objects in tests). This keeps the registry free of a\n * React peer-dep requirement and lets tests assert behaviour without rendering.\n */\n\n// ─── Closed v1 vocabulary ─────────────────────────────────────────────────────\n\n/**\n * The mandatory Contract B (worker remote-runtime) semantic primitive vocabulary.\n *\n * Adding a primitive requires a coordinated host change + protocol bump —\n * plugins cannot extend this set. Each name has a host-supplied concrete\n * component (gogo-ui in production); the registry enforces 1:1 substitution.\n */\nexport const CONTRACT_B_PRIMITIVES = [\n \"Button\",\n \"DataTable\",\n \"Form\",\n \"EntityPicker\",\n \"CommandBar\",\n \"Drawer\",\n \"Modal\",\n \"CanvasSurface\",\n \"WebGLSurface\",\n // Phase 1 additions — mirror the vite-plugin's CONTRACT_B_SEMANTIC_PRIMITIVES\n // list verbatim; drift between the two is caught by the\n // contract-b.test.ts \"import-map-allowlist matches extension-runtime\n // CONTRACT_B_PRIMITIVES\" test.\n \"Card\",\n \"Tabs\",\n \"Select\",\n \"Alert\",\n] as const;\n\n/**\n * Union type of the Contract B semantic primitive names — exported so callers\n * (tests, hosts) get full IntelliSense and compile-time exhaustiveness checks.\n */\nexport type SemanticPrimitiveName = typeof CONTRACT_B_PRIMITIVES[number];\n\nconst KNOWN_PRIMITIVE_SET: ReadonlySet<string> = new Set(CONTRACT_B_PRIMITIVES);\n\n// ─── Registry ─────────────────────────────────────────────────────────────────\n\n/**\n * Map of semantic primitive name → concrete component for Contract B\n * extensions.\n *\n * Construction is open-ended (callers register primitives one at a time) or\n * eager via {@link SemanticComponentRegistry.fromMap} which forces a complete\n * map up front and aborts if any primitive is missing.\n *\n * @typeParam TComponent - The host's concrete component shape. React hosts pass\n * `ComponentType<P>`; tests pass any tagged object.\n */\nexport class SemanticComponentRegistry<TComponent>\n{\n private readonly entries = new Map<SemanticPrimitiveName, TComponent>();\n\n /**\n * Register a primitive → component binding.\n *\n * Throws if `name` is not in {@link CONTRACT_B_PRIMITIVES} (drift prevention)\n * or if `name` is already registered (silent-override prevention).\n */\n public register(name: SemanticPrimitiveName, component: TComponent): void\n {\n if (!KNOWN_PRIMITIVE_SET.has(name))\n {\n throw new Error(\n `[component-registry] unknown semantic primitive '${name}'. ` +\n `Allowed: ${CONTRACT_B_PRIMITIVES.join(\", \")}.`,\n );\n }\n if (this.entries.has(name))\n {\n throw new Error(\n `[component-registry] primitive '${name}' is already registered. ` +\n `Construct a new registry instead of overriding a binding.`,\n );\n }\n this.entries.set(name, component);\n }\n\n /**\n * Resolve a primitive name to its concrete component. Throws if the name is\n * outside the Contract B vocabulary OR if the registry has no binding —\n * silent fallthrough would let typos render blank components, which is\n * worse than a fast failure for plugin authors.\n */\n public resolve(name: SemanticPrimitiveName): TComponent\n {\n if (!KNOWN_PRIMITIVE_SET.has(name))\n {\n throw new Error(\n `[component-registry] unknown semantic primitive '${name}'. ` +\n `Allowed: ${CONTRACT_B_PRIMITIVES.join(\", \")}.`,\n );\n }\n const found = this.entries.get(name);\n if (found === undefined)\n {\n const registered = this.listRegistered().join(\", \") || \"<none>\";\n throw new Error(\n `[component-registry] primitive '${name}' is not registered. ` +\n `Registered primitives: ${registered}.`,\n );\n }\n return found;\n }\n\n /**\n * Cheap presence probe — never throws. Use this when callers want to\n * fall back to a default component instead of erroring.\n */\n public has(name: SemanticPrimitiveName): boolean\n {\n return this.entries.has(name);\n }\n\n /**\n * Sorted list of registered primitive names. Stable output makes registry\n * diagnostics and snapshot tests deterministic.\n */\n public listRegistered(): SemanticPrimitiveName[]\n {\n return [...this.entries.keys()].sort() as SemanticPrimitiveName[];\n }\n\n /**\n * Build a registry from a complete `Record<SemanticPrimitiveName, T>` map.\n *\n * The `Record` type forces TypeScript to refuse incomplete literals at\n * compile time, AND we re-check at runtime so callers who type-erase the\n * record (e.g., via `as any`) still get a fast failure.\n */\n public static fromMap<T>(map: Record<SemanticPrimitiveName, T>): SemanticComponentRegistry<T>\n {\n const registry = new SemanticComponentRegistry<T>();\n const missing: SemanticPrimitiveName[] = [];\n for (const name of CONTRACT_B_PRIMITIVES)\n {\n const component = (map as Partial<Record<SemanticPrimitiveName, T>>)[name];\n if (component === undefined)\n {\n missing.push(name);\n continue;\n }\n registry.register(name, component);\n }\n if (missing.length > 0)\n {\n throw new Error(\n `[component-registry] fromMap is missing semantic primitive(s): ${missing.join(\", \")}.`,\n );\n }\n return registry;\n }\n}\n","/**\n * `npx mock-host <dir>` — standalone declarative-mock-host dev server.\n *\n * Reads SDUI resources from `<dir>/**\\/*.json` (recursive), wires them into the\n * {@link InMemoryMcpTransport}, and serves a Vite dev page that mounts\n * {@link DeclarativeMockHost} so plugin authors can iterate against the same\n * declarative pipeline the real host uses — without standing up the platform.\n *\n * Resource JSON shape (two accepted forms):\n *\n * 1. Tagged: `{ \"uri\": \"books://catalog\", \"tree\": <SduiNode> }`\n * 2. Untagged: a bare SDUI node. The URI defaults to the file's relative\n * path under the resources directory (with `\\\\` normalised to `/` and the\n * `.json` extension stripped).\n *\n * The CLI's pure resource-loading core is exported as {@link loadResources}\n * for unit testing; the Vite-boot side effect is gated behind {@link run}.\n */\n\nimport { promises as fs } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { KNOWN_PRIMITIVES } from \"@ethisyscore/protocol\";\nimport type { SduiNode } from \"../host/declarative/types\";\nimport {\n WorkerRemoteDomTransport,\n type McpHttpClient,\n type WorkerCtor,\n} from \"../host/worker/transport\";\nimport { CONTRACT_B_PRIMITIVES } from \"../host/worker/component-registry\";\n\n/** Map of MCP resource URI -> SDUI tree, as fed into the mock host. */\nexport type ResourceMap = Record<string, SduiNode>;\n\n/**\n * Map of MCP tool name -> canned result, as fed into the mock host. Each\n * value is returned verbatim when the tool is invoked from the rendered tree\n * (Form.submitTool, Action.tool, Field.lookupTool). Plugin authors who need\n * per-call dynamic behaviour can switch from the CLI's tools.json to a\n * hand-rolled Vite app that mounts DeclarativeMockHost with a typed tools\n * object directly.\n */\nexport type ToolResultMap = Record<string, unknown>;\n\n/**\n * Recursively load every `*.json` file under {@link dir} as a SDUI resource.\n *\n * - Tagged form (`{ uri, tree }`) wins when both fields are present.\n * - Untagged form uses the file's relative POSIX-normalised path (minus\n * extension) as the resource URI.\n *\n * Throws a single aggregated error if any file fails to parse — plugin authors\n * see one failure list instead of giving up at the first bad file.\n */\nexport async function loadResources(dir: string): Promise<ResourceMap>\n{\n const absDir = path.resolve(dir);\n const files = await walkJson(absDir);\n const out: ResourceMap = {};\n const errors: string[] = [];\n\n for (const file of files)\n {\n try\n {\n const raw = await fs.readFile(file, \"utf8\");\n const parsed = JSON.parse(raw) as unknown;\n const { uri, tree } = normaliseEntry(parsed, file, absDir);\n if (out[uri] !== undefined)\n {\n errors.push(`Duplicate resource URI '${uri}' (from ${file})`);\n continue;\n }\n out[uri] = tree;\n }\n catch (e)\n {\n errors.push(`${file}: ${(e as Error).message}`);\n }\n }\n\n if (errors.length > 0)\n {\n throw new Error(\n `Failed to load ${errors.length} mock-host resource(s):\\n - ${errors.join(\"\\n - \")}`,\n );\n }\n\n return out;\n}\n\n/**\n * Read `<dir>/tools.json` (if present) and return a `Record<toolName, canned>`\n * map for the mock transport. Missing file → empty map. Malformed file →\n * throws a single descriptive error.\n *\n * Expected shape: `{ \"<tool-name>\": <result-literal>, ... }`. The literal is\n * returned verbatim from `InMemoryMcpTransport.invokeTool(name, args)`.\n */\nexport async function loadTools(dir: string): Promise<ToolResultMap>\n{\n const toolsPath = path.resolve(dir, \"tools.json\");\n try\n {\n const raw = await fs.readFile(toolsPath, \"utf8\");\n const parsed = JSON.parse(raw) as unknown;\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n {\n throw new Error(`Expected an object map, got ${typeof parsed}`);\n }\n return parsed as ToolResultMap;\n }\n catch (e)\n {\n const err = e as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\")\n {\n return {};\n }\n throw new Error(`Failed to load tools.json from ${toolsPath}: ${err.message}`);\n }\n}\n\n/**\n * Convert a parsed JSON value into a `{ uri, tree }` pair.\n * Exported for tests; not part of the public API.\n */\nexport function normaliseEntry(\n parsed: unknown,\n absFile: string,\n absDir: string,\n): { uri: string; tree: SduiNode }\n{\n if (parsed === null || typeof parsed !== \"object\")\n {\n throw new Error(\"Resource JSON must be an object\");\n }\n const obj = parsed as Record<string, unknown>;\n if (typeof obj.uri === \"string\" && obj.tree !== undefined)\n {\n return { uri: obj.uri, tree: obj.tree as SduiNode };\n }\n // Untagged form: derive URI from the file's relative path.\n const rel = path.relative(absDir, absFile).replace(/\\\\/g, \"/\");\n const uri = rel.replace(/\\.json$/i, \"\");\n return { uri, tree: parsed as SduiNode };\n}\n\nasync function walkJson(root: string): Promise<string[]>\n{\n const out: string[] = [];\n\n async function recurse(dir: string): Promise<void>\n {\n let entries;\n try\n {\n entries = await fs.readdir(dir, { withFileTypes: true });\n }\n catch (e)\n {\n const err = e as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\")\n {\n throw new Error(`Resources directory not found: ${root}`);\n }\n throw e;\n }\n for (const entry of entries)\n {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory())\n {\n await recurse(full);\n }\n else if (entry.isFile() && entry.name.toLowerCase().endsWith(\".json\"))\n {\n out.push(full);\n }\n }\n }\n\n await recurse(root);\n out.sort();\n return out;\n}\n\n/**\n * Render a self-contained HTML page that mounts {@link DeclarativeMockHost}\n * with a debug registry (every primitive renders to a labelled `<div>`).\n *\n * Returned as a string so the Vite middleware can serve it from memory without\n * touching the consumer's filesystem.\n */\nexport function renderIndexHtml(resourceUris: string[]): string\n{\n const defaultUri = resourceUris[0] ?? \"\";\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>mock-host (${resourceUris.length} resources)</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1rem; }\n header { border-bottom: 1px solid #ccc; padding-bottom: 0.5rem; margin-bottom: 1rem; }\n select { padding: 0.25rem 0.5rem; }\n [data-mock-primitive] { padding: 0.5rem; margin: 0.25rem 0; border: 1px dashed #aaa; }\n [data-mock-primitive]::before { content: attr(data-mock-primitive); font-size: 0.75rem; color: #666; display: block; }\n </style>\n </head>\n <body>\n <header>\n <strong>mock-host</strong>\n &nbsp;|&nbsp;\n <label>Resource: <select id=\"resource-picker\">\n ${resourceUris.map(u => `<option value=\"${escapeHtml(u)}\">${escapeHtml(u)}</option>`).join(\"\")}\n </select></label>\n </header>\n <main id=\"root\"></main>\n <script type=\"module\" src=\"/@mock-host/entry.tsx\"></script>\n <script>\n window.__MOCK_HOST_DEFAULT_URI__ = ${safeJsonForScript(defaultUri)};\n window.__MOCK_HOST_RESOURCE_URIS__ = ${safeJsonForScript(resourceUris)};\n </script>\n </body>\n</html>`;\n}\n\nfunction escapeHtml(s: string): string\n{\n return s.replace(/[&<>\"']/g, c => ({\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n \"\\\"\": \"&quot;\",\n \"'\": \"&#39;\",\n }[c] as string));\n}\n\n/**\n * Safely serialise a value for embedding inside an inline `<script>` block.\n *\n * Plain `JSON.stringify` leaves `</script>` unescaped, which lets attacker-\n * controlled resource URIs break out of the script context. We replace the\n * dangerous character pairs with their unicode-escaped equivalents — still\n * valid JSON the browser eagerly parses, but inert inside HTML.\n */\nfunction safeJsonForScript(v: unknown): string\n{\n return JSON.stringify(v)\n .replace(/</g, \"\\\\u003c\")\n .replace(/>/g, \"\\\\u003e\")\n .replace(/&/g, \"\\\\u0026\");\n}\n\n/**\n * Build the virtual entry module the browser loads. Embeds the resource map\n * inline so the dev server does not have to serve JSON over a separate\n * endpoint — Vite HMR re-evaluates this module whenever resources change.\n */\nexport function renderEntryModule(\n resources: ResourceMap,\n tools: ToolResultMap = {},\n): string\n{\n const json = JSON.stringify(resources);\n const toolsJson = JSON.stringify(tools);\n // PR #16 review (Medium: mock-host primitive registry hardcoded). Derive the\n // primitive list from the protocol's KNOWN_PRIMITIVES so the mock host can\n // never accept primitives the real protocol rejects, or omit primitives the\n // real protocol added. JSON.stringify ensures the array is emitted as a JS\n // literal in the generated module — identical wire shape to the prior\n // hardcoded list, just sourced from the protocol package.\n const primitives = JSON.stringify([...KNOWN_PRIMITIVES]);\n return `\nimport { createRoot } from \"react-dom/client\";\nimport { createElement, useState } from \"react\";\nimport { DeclarativeMockHost } from \"@ethisyscore/extension-runtime/mock-host\";\n\nconst PRIMITIVES = ${primitives};\n\nconst registry = Object.fromEntries(PRIMITIVES.map(name => [\n name,\n ({ children }) => createElement(\"div\", { \"data-mock-primitive\": name }, children),\n]));\n\nconst resources = ${json};\nconst toolResults = ${toolsJson};\n// Each canned tool result is wrapped in a sync handler. Authors that need\n// per-call behaviour drop tools.json and hand-roll a Vite app that mounts\n// DeclarativeMockHost with a typed tools object directly.\nconst tools = Object.fromEntries(Object.entries(toolResults).map(([name, value]) => [\n name,\n () => value,\n]));\nconst uris = Object.keys(resources);\n\nfunction App() {\n const [uri, setUri] = useState(window.__MOCK_HOST_DEFAULT_URI__ || uris[0] || \"\");\n // Wire the header picker to React state so authors can switch trees live.\n const picker = document.getElementById(\"resource-picker\");\n if (picker && !picker.__wired) {\n picker.__wired = true;\n picker.value = uri;\n picker.addEventListener(\"change\", e => setUri(e.target.value));\n }\n return createElement(DeclarativeMockHost, {\n resources,\n tools,\n registry,\n defaultResourceUri: uri,\n });\n}\n\ncreateRoot(document.getElementById(\"root\")).render(createElement(App));\n`;\n}\n\n// ─── Contract B (Wave 1) CLI augment ──────────────────────────────────────────\n//\n// Wave 0 only supported Contract A (host-rendered) — a directory of SDUI JSON\n// fed into {@link DeclarativeMockHost}. Wave 1 adds Contract B (remote-runtime):\n// plugin authors run `npx mock-host --render-mode remote-runtime ./worker.js`\n// to spawn an in-process Worker via {@link WorkerRemoteDomTransport} against\n// the same Vite dev page workflow. The semantic component registry from E2.S4\n// is referenced by name — each primitive renders to a labelled placeholder so\n// the receiver's substitution behaviour is observable without standing up\n// gogo-ui.\n\n/** Discriminated union of the two render modes the CLI knows about. */\nexport type RenderMode = \"host-rendered\" | \"remote-runtime\";\n\n/**\n * Parsed CLI arguments. `path` is the positional argument — its meaning\n * depends on {@link renderMode}:\n *\n * - `host-rendered`: a directory of SDUI resource JSON files.\n * - `remote-runtime`: a path (or URL) to a built worker bundle.\n */\nexport interface ParsedArgs\n{\n renderMode: RenderMode;\n path: string;\n}\n\nconst RENDER_MODES: ReadonlySet<RenderMode> = new Set<RenderMode>([\n \"host-rendered\",\n \"remote-runtime\",\n]);\n\n/**\n * Parse the CLI's argv-slice. Exported so the test suite can assert flag\n * handling without booting a Vite server.\n *\n * Accepts both `--render-mode <value>` and `--render-mode=<value>`. Defaults\n * to `host-rendered` to preserve Wave 0 behaviour for existing users.\n */\nexport function parseArgs(args: readonly string[]): ParsedArgs\n{\n let renderMode: RenderMode = \"host-rendered\";\n const positional: string[] = [];\n\n for (let i = 0; i < args.length; i++)\n {\n const arg = args[i]!;\n if (arg === \"--render-mode\")\n {\n const next = args[i + 1];\n if (next === undefined)\n {\n throw new Error(\"Usage: mock-host [--render-mode <host-rendered|remote-runtime>] <path>\");\n }\n if (!RENDER_MODES.has(next as RenderMode))\n {\n throw new Error(\n `Invalid --render-mode '${next}'. Allowed: ${[...RENDER_MODES].join(\", \")}.`,\n );\n }\n renderMode = next as RenderMode;\n i++;\n continue;\n }\n if (arg.startsWith(\"--render-mode=\"))\n {\n const value = arg.slice(\"--render-mode=\".length);\n if (!RENDER_MODES.has(value as RenderMode))\n {\n throw new Error(\n `Invalid --render-mode '${value}'. Allowed: ${[...RENDER_MODES].join(\", \")}.`,\n );\n }\n renderMode = value as RenderMode;\n continue;\n }\n positional.push(arg);\n }\n\n if (positional.length === 0)\n {\n throw new Error(\"Usage: mock-host [--render-mode <host-rendered|remote-runtime>] <path>\");\n }\n\n return { renderMode, path: positional[0]! };\n}\n\n/**\n * Render the HTML shell for the Contract B mock host. The page hosts a\n * receiver that mounts the Remote DOM tree produced by the worker — each\n * Contract B primitive renders to a labelled placeholder.\n */\nexport function renderWorkerBundleIndexHtml(bundlePath: string): string\n{\n const safePath = escapeHtml(bundlePath);\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>mock-host (remote-runtime: ${safePath})</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1rem; }\n header { border-bottom: 1px solid #ccc; padding-bottom: 0.5rem; margin-bottom: 1rem; }\n [data-mock-primitive] { padding: 0.5rem; margin: 0.25rem 0; border: 1px dashed #aaa; }\n [data-mock-primitive]::before { content: attr(data-mock-primitive); font-size: 0.75rem; color: #666; display: block; }\n </style>\n </head>\n <body>\n <header><strong>mock-host</strong> &nbsp;|&nbsp; <em>remote-runtime: ${safePath}</em></header>\n <main id=\"root\"></main>\n <script type=\"module\" src=\"/@mock-host/worker-bundle-entry.tsx\"></script>\n </body>\n</html>`;\n}\n\n/**\n * Build the inline entry module the browser loads for Contract B.\n *\n * The module:\n * 1. Constructs a {@link WorkerRemoteDomTransport} pointing at the bundle.\n * 2. Registers a placeholder for every Contract B semantic primitive — the\n * test-injectable seam from E2.S4. Production hosts would substitute\n * gogo-ui components here.\n * 3. Wires the receiver onto the host's `<main id=\"root\">` slot.\n *\n * In-page wiring is deliberately minimal — the goal is observability, not a\n * production receiver implementation. Authors iterate against the same\n * surface their plugins will mount into when the platform host is finished.\n */\nexport function renderWorkerBundleEntryModule(bundleUrl: string): string\n{\n const safePrimitives = JSON.stringify([...CONTRACT_B_PRIMITIVES]);\n const safeUrl = JSON.stringify(bundleUrl);\n return `\nimport { createRoot } from \"react-dom/client\";\nimport { createElement } from \"react\";\nimport {\n WorkerRemoteDomTransport,\n SemanticComponentRegistry,\n} from \"@ethisyscore/extension-runtime/host\";\n\nconst PRIMITIVES = ${safePrimitives};\nconst bundleUrl = ${safeUrl};\n\n// Build the test-injectable component map — every Contract B primitive\n// renders to a labelled placeholder so plugin authors can see what their\n// worker is emitting before plugging in gogo-ui.\nconst componentMap = Object.fromEntries(PRIMITIVES.map(name => [\n name,\n ({ children }) => createElement(\"div\", { \"data-mock-primitive\": name }, children),\n]));\nconst registry = SemanticComponentRegistry.fromMap(componentMap);\n\n// Mock-host MCP client: no platform, so every tool/resource call resolves\n// to a friendly placeholder. Authors who need real MCP traffic should run\n// against the full platform host.\nconst mcpClient = {\n fetch: async (req) => ({\n ok: true,\n data: { mockHost: true, kind: req.kind, name: req.name ?? req.uri },\n }),\n};\n\n// The capability token never crosses the worker boundary — supply a marker\n// here so the host-side fetcher can still attach an Authorization header.\nconst transport = new WorkerRemoteDomTransport({\n bootstrapUrl: bundleUrl,\n capabilityToken: async () => \"mock-host-capability-token\",\n mcpClient,\n});\n\nconst root = createRoot(document.getElementById(\"root\"));\ntransport.onRemoteDom(() => {\n // The full Remote DOM receiver belongs to a separate concern (E3.S2's\n // WorkerSurfaceMount). For mock-host purposes the registry is the\n // observable surface — log the receiver payload for now.\n root.render(createElement(\"div\", { \"data-mock-host-primitives\": PRIMITIVES.join(\",\") }));\n});\n\n// Expose the transport + registry on window so authors can poke at them from\n// devtools (e.g., to terminate the worker between iteration cycles).\nwindow.__MOCK_HOST_TRANSPORT__ = transport;\nwindow.__MOCK_HOST_REGISTRY__ = registry;\n`;\n}\n\n/**\n * Construction options for {@link bootContractBHost}.\n */\nexport interface BootContractBHostOptions\n{\n /**\n * Path or canonical URL to the plugin's worker bundle. The mock host\n * serves it from the configured Vite root — production hosts always use\n * a path-pinned host-origin URL.\n */\n bundleUrl: string;\n /**\n * Injectable Worker constructor. Tests pass a fake; the production CLI\n * path uses the global `Worker`. The transport itself defaults to\n * `globalThis.Worker` when omitted — but the mock-host CLI passes through\n * the caller's choice so test seams compose cleanly.\n */\n workerCtor?: WorkerCtor;\n /**\n * Optional capability token provider. Defaults to a marker string so\n * authors don't need to wire token plumbing into local-dev.\n */\n capabilityToken?: () => Promise<string>;\n /**\n * Optional MCP HTTP client. Defaults to a stub that echoes the request\n * shape — authors who need real MCP traffic compose the platform host.\n */\n mcpClient?: McpHttpClient;\n}\n\nconst defaultMockMcpClient: McpHttpClient = {\n fetch: async (req) =>\n {\n if (req.kind === \"uploadDocument\")\n {\n // Stub upload: echo a synthetic StoredDocument id so a standalone\n // Contract B host can drive the FE upload flow without core storage.\n return {\n ok: true,\n data: {\n storedDocumentId: `mock-${req.meta.entityName}-${req.meta.fileName}`,\n fileName: req.meta.fileName,\n contentType: req.meta.contentType,\n sizeBytes: req.buffer.byteLength,\n },\n };\n }\n const echo = req.kind === \"invokeTool\" ? { tool: req.name, args: req.args } : { resource: req.uri };\n return { ok: true, data: { mockHost: true, ...echo } };\n },\n};\n\n/**\n * Spawn the in-process worker that drives the Contract B mock host.\n *\n * Returns the constructed transport so callers (production CLI: the dev page;\n * tests: assertions) can observe spawn shape, dispose the worker on shutdown,\n * and inspect coalescing behaviour. Reuses\n * {@link WorkerRemoteDomTransport} so the capability-token isolation rules\n * documented in E2.S3 apply without re-implementation.\n */\nexport function bootContractBHost(options: BootContractBHostOptions): WorkerRemoteDomTransport\n{\n return new WorkerRemoteDomTransport({\n bootstrapUrl: options.bundleUrl,\n capabilityToken: options.capabilityToken ?? (async () => \"mock-host-capability-token\"),\n mcpClient: options.mcpClient ?? defaultMockMcpClient,\n workerCtor: options.workerCtor,\n });\n}\n\n/**\n * Wave 1 Contract B dev server. Boots Vite, serves the virtual index page that\n * runs {@link renderWorkerBundleEntryModule} (which spawns the worker), and\n * exposes the bundle on a host-origin URL so the worker handshake can succeed.\n */\nasync function runContractBHost(bundlePathOrUrl: string): Promise<{ url: string; close: () => Promise<void> }>\n{\n // Lazy import so the pure exports stay decoupled from Vite at type-time.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n let viteMod: any;\n try\n {\n viteMod = await import(\"vite\" as any);\n }\n catch\n {\n throw new Error(\n \"vite is required to run `mock-host`. Install with: npm install --save-dev vite\",\n );\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n // Two flavours of bundle reference are accepted: an absolute URL (rare —\n // useful for testing a deployed bundle) and a filesystem path that the\n // dev server exposes as a host-origin URL.\n const isUrl = /^https?:\\/\\//i.test(bundlePathOrUrl);\n const absBundle = isUrl ? bundlePathOrUrl : path.resolve(bundlePathOrUrl);\n\n if (!isUrl)\n {\n try\n {\n await fs.access(absBundle);\n }\n catch\n {\n throw new Error(`mock-host: worker bundle not found at ${absBundle}`);\n }\n }\n\n // The dev page references the bundle via a stable virtual path. The Vite\n // middleware serves the file's bytes directly so the worker spawn URL is\n // host-origin (matching the production CSP path-pinning shape).\n const bundleServePath = \"/@mock-host/worker-bundle.js\";\n const indexHtml = renderWorkerBundleIndexHtml(isUrl ? bundlePathOrUrl : bundleServePath);\n const entryModule = renderWorkerBundleEntryModule(isUrl ? bundlePathOrUrl : bundleServePath);\n\n const server = await viteMod.createServer({\n root: process.cwd(),\n configFile: false,\n server: { port: 0, host: \"127.0.0.1\" },\n plugins: [\n {\n name: \"mock-host-virtual-worker\",\n resolveId(id: string)\n {\n if (id === \"/@mock-host/worker-bundle-entry.tsx\")\n {\n return \"\\0mock-host:worker-bundle-entry\";\n }\n return null;\n },\n load(id: string)\n {\n if (id === \"\\0mock-host:worker-bundle-entry\")\n {\n return entryModule;\n }\n return null;\n },\n /* eslint-disable @typescript-eslint/no-explicit-any */\n configureServer(devServer: any)\n {\n devServer.middlewares.use(async (req: any, res: any, next: () => void) =>\n {\n if (req.url === \"/\" || req.url === \"/index.html\")\n {\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(indexHtml);\n return;\n }\n if (!isUrl && req.url === bundleServePath)\n {\n try\n {\n const bytes = await fs.readFile(absBundle);\n res.setHeader(\"Content-Type\", \"text/javascript; charset=utf-8\");\n res.end(bytes);\n }\n catch (e)\n {\n res.statusCode = 500;\n res.end(`mock-host: failed to read worker bundle: ${(e as Error).message}`);\n }\n return;\n }\n next();\n });\n },\n /* eslint-enable @typescript-eslint/no-explicit-any */\n },\n ],\n });\n\n await server.listen();\n const addr = server.httpServer?.address();\n let port = 5173;\n if (addr && typeof addr === \"object\")\n {\n port = addr.port;\n }\n const url = `http://127.0.0.1:${port}/`;\n process.stdout.write(`mock-host listening on ${url} (remote-runtime: ${absBundle})\\n`);\n\n return { url, close: () => server.close() };\n}\n\n/**\n * Boot the Vite dev server with an in-memory entry + virtual page.\n *\n * Side-effectful: imports `vite` lazily so the pure `loadResources` export\n * stays usable from environments that lack a Vite install (e.g., the unit\n * tests in this package).\n *\n * Dispatches on `--render-mode`:\n * - `host-rendered` (default): Wave 0 declarative-mock-host behaviour.\n * - `remote-runtime`: Wave 1 Contract B — spawns a worker pointing at the\n * supplied bundle path and serves the placeholder dev page.\n */\nexport async function run(args: string[]): Promise<{ url: string; close: () => Promise<void> }>\n{\n const parsed = parseArgs(args);\n\n if (parsed.renderMode === \"remote-runtime\")\n {\n return runContractBHost(parsed.path);\n }\n\n const dir = parsed.path;\n const resources = await loadResources(dir);\n const tools = await loadTools(dir);\n const uris = Object.keys(resources).sort();\n if (uris.length === 0)\n {\n // Allow boot anyway — authors might want to scaffold-then-add resources\n // with HMR-watched edits.\n process.stderr.write(`mock-host: no resources found in ${dir} (HMR will pick up new files)\\n`);\n }\n\n // Lazy import so the pure exports stay decoupled from Vite at type-time.\n // Vite is declared as an OPTIONAL peer dependency — type as `any` here so\n // building the package doesn't require Vite's type surface to be present.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n let viteMod: any;\n try\n {\n viteMod = await import(\"vite\" as any);\n }\n catch\n {\n throw new Error(\n \"vite is required to run `mock-host`. Install with: npm install --save-dev vite\",\n );\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n const indexHtml = renderIndexHtml(uris);\n const entryModule = renderEntryModule(resources, tools);\n const absDir = path.resolve(dir);\n\n const server = await viteMod.createServer({\n root: process.cwd(),\n configFile: false,\n server: { port: 0, host: \"127.0.0.1\" },\n plugins: [\n {\n name: \"mock-host-virtual\",\n resolveId(id: string)\n {\n if (id === \"/@mock-host/entry.tsx\")\n {\n return \"\\0mock-host:entry\";\n }\n return null;\n },\n load(id: string)\n {\n if (id === \"\\0mock-host:entry\")\n {\n return entryModule;\n }\n return null;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n configureServer(devServer: any)\n {\n devServer.watcher.add(absDir);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n devServer.middlewares.use((req: any, res: any, next: () => void) =>\n {\n if (req.url === \"/\" || req.url === \"/index.html\")\n {\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(indexHtml);\n return;\n }\n next();\n });\n },\n },\n ],\n });\n\n await server.listen();\n const addr = server.httpServer?.address();\n let port = 5173;\n if (addr && typeof addr === \"object\")\n {\n port = addr.port;\n }\n const url = `http://127.0.0.1:${port}/`;\n process.stdout.write(`mock-host listening on ${url} (resources: ${uris.length})\\n`);\n\n return { url, close: () => server.close() };\n}\n\n// No top-level bin guard here: the `mock-host` bin entry is a thin\n// CJS wrapper (`bin/mock-host.cjs`, hand-written, kept out of tsup) that\n// requires the compiled `cli.cjs` and calls `run(process.argv.slice(2))`.\n// That keeps this module side-effect free so unit tests can import the pure\n// `loadResources` / `normaliseEntry` / `renderEntryModule` exports without\n// booting Vite.\n"]}
1
+ {"version":3,"sources":["../../src/host/worker/offscreen.ts","../../src/bridge/mcp-error.ts","../../src/host/version-skew.ts","../../src/host/worker/bridge-envelopes.ts","../../src/host/worker/transport.ts","../../src/host/worker/component-registry.ts","../../src/mock-host/cli.ts"],"names":["path","fs","KNOWN_PRIMITIVES"],"mappings":"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","file":"cli.cjs","sourcesContent":["/**\n * OffscreenCanvas transfer helpers + pointer/keyboard coalescing for\n * Contract B (worker remote-runtime) extensions.\n *\n * **Architecture.** Hosts that expose a {@link import(\"./component-registry\").SemanticComponentRegistry}'s\n * `CanvasSurface` / `WebGLSurface` primitive create a host-side `<canvas>`,\n * transfer control to the worker via {@link createOffscreenCanvasTransfer}, and\n * the plugin (running inside the worker realm) calls `offscreen.getContext()`\n * to render. The `<canvas>` is owned by the host DOM tree (so layout, theming,\n * and accessibility properties stay on the host side) but every pixel is\n * produced inside the worker — no per-frame `postMessage` cost, no main-thread\n * blocking.\n *\n * **Pointer / keyboard delivery.** Input events still originate on the host\n * `<canvas>`. To avoid spraying the worker port with per-event traffic the\n * host should wrap pointer-move / wheel / scroll callbacks in\n * {@link createInputEventCoalescer}, matching the trailing-edge coalescer\n * already documented in {@link import(\"./transport\").WorkerRemoteDomTransport}\n * (default 16ms ≈ one rAF). Keyboard events MUST use `discrete: true` —\n * coalescing them would drop characters.\n *\n * **Security.** No capability token, no MCP traffic, and no host-only globals\n * cross via the offscreen transfer. The transfer envelope is plain JSON with a\n * single `OffscreenCanvas` handle in the transfer list — the worker side\n * receives an opaque drawing surface and nothing else.\n */\n\n// ─── Public constants ────────────────────────────────────────────────────────\n\n/**\n * Default trailing-edge coalesce window for pointer / wheel / scroll events,\n * in milliseconds. 16ms ≈ one animation frame at 60Hz. Matches the default\n * documented in {@link import(\"./transport\").WorkerRemoteDomTransport}.\n */\nexport const DEFAULT_OFFSCREEN_COALESCE_MS = 16;\n\n// ─── Transfer envelope ───────────────────────────────────────────────────────\n\n/**\n * Host → worker envelope shape for an `OffscreenCanvas` transfer. Stable wire\n * contract — the worker side decodes by `type` and uses `surfaceId` to bind\n * the offscreen to the right host slot when a plugin renders multiple\n * canvases concurrently.\n */\nexport interface OffscreenTransferMessage\n{\n type: \"ethisys:offscreen:transfer\";\n surfaceId: string;\n width: number;\n height: number;\n offscreen: OffscreenCanvas;\n}\n\n/**\n * Construction options for {@link createOffscreenCanvasTransfer}.\n */\nexport interface OffscreenCanvasTransferOptions\n{\n /**\n * The host-owned `<canvas>` element. Its `width` / `height` are captured\n * before transfer so the worker sees the intended pixel dimensions even if\n * the host element resizes later (host should send a separate resize\n * message in that case).\n */\n canvas: HTMLCanvasElement;\n\n /**\n * Stable identifier the worker uses to route the offscreen to the matching\n * surface slot. Typically the SDUI node id of the `CanvasSurface` /\n * `WebGLSurface` primitive that the worker will draw into.\n */\n surfaceId: string;\n\n /**\n * Host-side postMessage function — typically the\n * {@link import(\"./transport\").WorkerRemoteDomTransport}'s port-side\n * `postMessage`. Tests inject a spy.\n */\n postMessage(message: OffscreenTransferMessage, transfer: Transferable[]): void;\n}\n\n/**\n * Successful transfer result. The caller retains a reference to the\n * `OffscreenCanvas` only for observability (e.g., to wire to the worker's\n * reply handshake) — direct rendering from the host side is forbidden because\n * control has already been transferred and any host-side draw call would\n * throw.\n */\nexport interface OffscreenCanvasTransferResult\n{\n offscreen: OffscreenCanvas;\n}\n\n/**\n * Module-scoped WeakSet tracking canvases this SDK has already transferred.\n *\n * Stored OUTSIDE the DOM node deliberately:\n *\n * - Writing an SDK expando (e.g. `__ethisysOffscreenTransferred`) onto a host-\n * owned `<canvas>` mutates state the host doesn't own. A WeakSet keeps the\n * bookkeeping on the SDK side and lets the canvas object stay pristine.\n * - WeakSet entries are collected when the canvas is GC'd, so the guard does\n * not leak memory for plugins that mount and unmount many surfaces.\n * - WeakSet membership is identity-based, so React/concurrent remount paths\n * that re-use the SAME node still see \"already transferred\"; a fresh DOM\n * node (always allocated by React when the key changes) is a fresh entry.\n */\nconst transferredCanvases: WeakSet<HTMLCanvasElement> = new WeakSet<HTMLCanvasElement>();\n\n/**\n * Transfer control of a host-owned `<canvas>` to the worker.\n *\n * Throws if:\n * - the environment lacks `HTMLCanvasElement.prototype.transferControlToOffscreen`\n * (the helper does NOT silently fall back — Contract B clients must require\n * the API and surface a clear error in unsupported browsers);\n * - the same canvas has already had control transferred (idempotency is the\n * caller's responsibility — re-transferring would throw in the browser\n * anyway, but we raise a clearer, diagnosable message ahead of that).\n */\nexport function createOffscreenCanvasTransfer(\n options: OffscreenCanvasTransferOptions,\n): OffscreenCanvasTransferResult\n{\n const { canvas, surfaceId, postMessage } = options;\n const proto = HTMLCanvasElement.prototype as unknown as {\n transferControlToOffscreen?: () => OffscreenCanvas;\n };\n if (typeof proto.transferControlToOffscreen !== \"function\")\n {\n throw new Error(\n \"[offscreen-canvas] OffscreenCanvas is not supported in this environment. \" +\n \"Contract B canvas surfaces require a browser with HTMLCanvasElement.transferControlToOffscreen.\",\n );\n }\n if (transferredCanvases.has(canvas))\n {\n throw new Error(\n `[offscreen-canvas] canvas already transferred (surfaceId='${surfaceId}'). ` +\n \"Create a fresh <canvas> for each surface instead of re-transferring.\",\n );\n }\n\n const offscreen = canvas.transferControlToOffscreen();\n transferredCanvases.add(canvas);\n\n const envelope: OffscreenTransferMessage = {\n type: \"ethisys:offscreen:transfer\",\n surfaceId,\n width: canvas.width,\n height: canvas.height,\n offscreen,\n };\n postMessage(envelope, [offscreen]);\n\n return { offscreen };\n}\n\n// ─── Coalescing ──────────────────────────────────────────────────────────────\n\n/**\n * Construction options for {@link createInputEventCoalescer}.\n */\nexport interface InputEventCoalescerOptions\n{\n /**\n * Coalesce window in milliseconds. Ignored when {@link discrete} is true.\n * Defaults to {@link DEFAULT_OFFSCREEN_COALESCE_MS} (16ms — one rAF).\n */\n coalesceMs?: number;\n\n /**\n * When `true`, forward every payload synchronously without coalescing.\n * Use this for keyboard events — coalescing would drop characters by\n * collapsing multiple key strokes into one trailing delivery.\n */\n discrete?: boolean;\n}\n\n/**\n * Build a trailing-edge input-event coalescer. The pattern matches\n * {@link import(\"./transport\").WorkerRemoteDomTransport.createCoalescer} —\n * factored out here so OffscreenCanvas callers don't need to construct a full\n * transport just to coalesce pointer-move events.\n *\n * Trailing-edge semantics: every burst within a coalesce window collapses to\n * a single delivery carrying the **last** payload seen in the window. A new\n * payload arriving after a window has flushed starts a fresh window.\n */\nexport function createInputEventCoalescer<T>(\n sink: (payload: T) => void,\n options: InputEventCoalescerOptions = {},\n): (payload: T) => void\n{\n if (options.discrete === true)\n {\n // Discrete mode: pass through unchanged. Keyboard input belongs here.\n return (payload: T) =>\n {\n sink(payload);\n };\n }\n const coalesceMs = options.coalesceMs ?? DEFAULT_OFFSCREEN_COALESCE_MS;\n let pending: T | undefined;\n let pendingSet = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const flush = (): void =>\n {\n timer = undefined;\n if (!pendingSet)\n {\n return;\n }\n const value = pending as T;\n pending = undefined;\n pendingSet = false;\n sink(value);\n };\n\n return (payload: T) =>\n {\n pending = payload;\n pendingSet = true;\n if (timer === undefined)\n {\n timer = setTimeout(flush, coalesceMs);\n }\n };\n}\n","/**\n * A machine-readable classification for an MCP call that failed, carried across the host/plugin\n * bridge alongside the human-readable message.\n *\n * ## Why this exists\n *\n * The bridge used to reduce every failure to `err.message`, a bare string. A plugin therefore could\n * not tell \"you lack permission for this tool\" from \"the host is unreachable\" without matching on\n * host error prose, and the practical consequence was that plugins swallowed *all* failures into a\n * successful empty result to keep a permission denial from looking like a crash. That turns a\n * transient outage into \"you have no connectors\" - a false statement about the user's data, and one\n * that also suppresses the query layer's retry.\n *\n * A closed vocabulary lets the plugin branch on the one case it wants to tolerate and rethrow the\n * rest.\n *\n * ## Deliberately small, and deliberately not HTTP\n *\n * These are the distinctions a *caller* acts on differently, not a mirror of any status enum. Codes\n * that would prompt the same handling are folded together, because a vocabulary nobody can apply is\n * just a wider surface to get wrong. `unavailable` and `timeout` stay separate only because retry\n * policy differs between them.\n */\nexport type McpErrorCode =\n /** The caller is not authenticated, or its token expired. Re-authentication may fix it. */\n | \"unauthorized\"\n /** Authenticated, but not permitted this tool or resource. Retrying will not help. */\n | \"forbidden\"\n /** The tool, resource, or addressed entity does not exist. */\n | \"not_found\"\n /** The arguments were rejected. A caller bug, or stale client-side validation. */\n | \"invalid_request\"\n /** A concurrency or state conflict - a row version, or a duplicate. */\n | \"conflict\"\n /** Throttled. Retry later, with backoff. */\n | \"rate_limited\"\n /** The call did not complete in time. Safe to retry only if the operation is idempotent. */\n | \"timeout\"\n /** The host or an upstream dependency is down. Retryable. */\n | \"unavailable\"\n /** Anything else, including an unclassifiable failure. The default - never a claim. */\n | \"internal\";\n\n/**\n * Every valid {@link McpErrorCode}. Used to validate a code arriving over the wire: an unknown\n * string is downgraded rather than trusted, so a newer host cannot make an older plugin branch on a\n * code it has never heard of.\n */\nexport const MCP_ERROR_CODES: readonly McpErrorCode[] = [\n \"unauthorized\",\n \"forbidden\",\n \"not_found\",\n \"invalid_request\",\n \"conflict\",\n \"rate_limited\",\n \"timeout\",\n \"unavailable\",\n \"internal\",\n];\n\n/** True when `value` is a code this build understands. */\nexport function isMcpErrorCode(value: unknown): value is McpErrorCode\n{\n return typeof value === \"string\"\n && (MCP_ERROR_CODES as readonly string[]).includes(value);\n}\n\n/**\n * Codes a caller can retry without changing anything about the request. Exposed so retry policy is\n * decided once here rather than re-derived, subtly differently, at each call site.\n *\n * `unauthorized` is absent on purpose: a retry only helps once something else has refreshed the\n * token, which is a different action from retrying.\n */\nconst RETRYABLE: readonly McpErrorCode[] = [\"rate_limited\", \"timeout\", \"unavailable\"];\n\n/** True when the failure is worth retrying as-is. */\nexport function isRetryableMcpErrorCode(code: McpErrorCode): boolean\n{\n return RETRYABLE.includes(code);\n}\n\n/**\n * An MCP call rejected by the host, carrying its {@link McpErrorCode}.\n *\n * `name` stays `\"McpHostError\"` - the string the bridge has always set - so code that matches on the\n * name keeps working. Prefer {@link isMcpToolError}, which survives a name change and works across\n * realm boundaries where `instanceof` does not.\n */\nexport class McpToolError extends Error\n{\n /** Machine-readable classification. `internal` when the host sent none. */\n public readonly code: McpErrorCode;\n\n /**\n * Marks the instance for {@link isMcpToolError}. A structural marker rather than a prototype\n * check because the error can be constructed in one bundle and inspected in another, where\n * `instanceof` compares two different class objects and answers false.\n */\n public readonly isMcpToolError = true as const;\n\n public constructor(message: string, code: McpErrorCode = \"internal\")\n {\n super(message);\n this.name = \"McpHostError\";\n this.code = code;\n }\n\n /** True when this failure is worth retrying unchanged. */\n public get retryable(): boolean\n {\n return isRetryableMcpErrorCode(this.code);\n }\n}\n\n/** True when `value` is an {@link McpToolError}, including one from another bundle. */\nexport function isMcpToolError(value: unknown): value is McpToolError\n{\n return value instanceof McpToolError\n || (value !== null\n && typeof value === \"object\"\n && (value as { isMcpToolError?: unknown }).isMcpToolError === true\n && isMcpErrorCode((value as { code?: unknown }).code));\n}\n\n/**\n * Maps an HTTP status onto a code. Split out because host MCP clients are commonly HTTP clients, so\n * a status is the classification most of them already have.\n *\n * Unrecognised statuses (including every 2xx and 3xx, which should not be reaching an error path)\n * yield `internal` rather than a guess.\n */\nexport function mcpErrorCodeFromHttpStatus(status: number): McpErrorCode\n{\n switch (status)\n {\n case 401:\n return \"unauthorized\";\n case 403:\n return \"forbidden\";\n case 404:\n return \"not_found\";\n case 400:\n case 422:\n return \"invalid_request\";\n case 409:\n case 412:\n return \"conflict\";\n case 429:\n return \"rate_limited\";\n case 408:\n case 504:\n return \"timeout\";\n case 502:\n case 503:\n return \"unavailable\";\n default:\n // Everything unmapped, 500 included. `internal` is the honest answer for a status this\n // vocabulary has no distinct handling for - inventing a closer-looking code would tell\n // the caller something the status does not actually say.\n return \"internal\";\n }\n}\n\n/**\n * Derives a code from a host MCP client's RETURNED failure, as opposed to a thrown one.\n *\n * Both paths exist and both have to be covered. A client that throws is handled by\n * {@link classifyHostError}; a client that reports failure as `{ ok: false, error, status }` - the\n * common shape for anything wrapping HTTP - comes through here. Covering only the throw path leaves\n * the majority of real failures arriving as `internal`, which is the same blindness the code was\n * added to remove.\n *\n * Returns `undefined` for a successful response, so a caller can spread it without putting a\n * meaningless code on the happy path.\n */\nexport function classifyHostResponse(response: {\n readonly ok: boolean;\n readonly status?: number;\n readonly mcpErrorCode?: unknown;\n}): McpErrorCode | undefined\n{\n if (response.ok)\n {\n return undefined;\n }\n\n // Same precedence as the thrown path: an explicit code from the client beats the transport's\n // status, and neither is ever inferred from the message.\n if (isMcpErrorCode(response.mcpErrorCode))\n {\n return response.mcpErrorCode;\n }\n\n return typeof response.status === \"number\"\n ? mcpErrorCodeFromHttpStatus(response.status)\n : \"internal\";\n}\n\n/**\n * Derives a code from an arbitrary thrown value, for the host side of the bridge.\n *\n * Precedence, most explicit first:\n *\n * 1. An `mcpErrorCode` property holding a known code. The intended contract: a host MCP client that\n * knows why a call failed says so directly.\n * 2. A numeric `status` / `statusCode`, mapped by {@link mcpErrorCodeFromHttpStatus}. Covers the\n * HTTP clients that already carry one without asking every host to adopt the field above.\n * 3. `name === \"AbortError\"` / `\"TimeoutError\"`, which is how the platform's own aborts surface.\n * 4. `internal`.\n *\n * **Never infers from the message.** Matching prose would make the classification depend on wording\n * nobody treats as a contract, and it would silently reclassify itself the day someone improves an\n * error string. An unclassifiable failure is `internal`, which is honest.\n */\nexport function classifyHostError(err: unknown): McpErrorCode\n{\n if (err === null || typeof err !== \"object\")\n {\n return \"internal\";\n }\n\n const candidate = err as {\n mcpErrorCode?: unknown;\n status?: unknown;\n statusCode?: unknown;\n name?: unknown;\n };\n\n if (isMcpErrorCode(candidate.mcpErrorCode))\n {\n return candidate.mcpErrorCode;\n }\n\n const status = typeof candidate.status === \"number\"\n ? candidate.status\n : typeof candidate.statusCode === \"number\" ? candidate.statusCode : undefined;\n\n if (status !== undefined)\n {\n return mcpErrorCodeFromHttpStatus(status);\n }\n\n if (candidate.name === \"AbortError\" || candidate.name === \"TimeoutError\")\n {\n return \"timeout\";\n }\n\n return \"internal\";\n}\n","/**\n * Version-skew detection for host-side MCP calls.\n *\n * A mounted plugin surface holds a capability token minted against the extension version that\n * was active when the page loaded. When the install is upgraded underneath it, the kernel stops\n * honouring that token: it rejects with `401` and\n * `X-Capability-Token-Rejection-Reason: ExtensionVersionMismatch`. Every other rejection reason is\n * terminal for the surface, but this one is recoverable — remounting against the new version fixes\n * it — which is why it is worth telling apart from an ordinary auth failure.\n *\n * Two signals are handled here, and the difference matters:\n *\n * - **Reactive**, from a rejection: the call already failed. Recovery costs the user a round trip\n * and whatever in-page state the remount discards.\n * - **Proactive**, from the version stamped on a *successful* response: the surface learns the\n * install moved while it is still working, and can remount at a moment of its choosing. Reads\n * keep succeeding until the token's own version check catches up, so this is the path that\n * avoids a visible failure altogether.\n *\n * The interpretation lives here rather than in each host application so that \"which reason means\n * remount\" is decided once, in code that can be tested, instead of being re-derived by every\n * embedder from HTTP trivia.\n */\n\n/** Response header naming the extension version a request was served as. */\nexport const EXTENSION_VERSION_HEADER = \"x-extension-version\";\n\n/** Response header naming the version a rejected surface must remount at. */\nexport const EXTENSION_ACTIVE_VERSION_HEADER = \"x-extension-active-version\";\n\n/** Response header carrying the kernel's structured capability-token rejection reason. */\nexport const CAPABILITY_REJECTION_REASON_HEADER = \"x-capability-token-rejection-reason\";\n\n/** The one rejection reason a surface can resolve by remounting. */\nexport const VERSION_MISMATCH_REASON = \"extensionversionmismatch\";\n\n/**\n * What the host observed about an MCP response, beyond its payload. Both fields are optional\n * because the {@link McpHttpClient} contract predates them: an implementation that does not supply\n * them simply never reports skew, which is the previous behaviour rather than a new failure.\n */\nexport interface McpResponseMetadata\n{\n /** HTTP status code, when the implementation surfaces it. */\n readonly status?: number;\n\n /** Response headers. Looked up case-insensitively, so any casing is fine. */\n readonly headers?: Readonly<Record<string, string>>;\n}\n\n/**\n * How skew came to light.\n *\n * - `\"rejection\"` — a call was refused because the surface's token is stale. Recovery costs a round\n * trip and whatever in-page state the remount discards.\n * - `\"response-stamp\"` — a call succeeded, but the install has moved on. The surface can remount\n * before anything fails, so this is the path worth preferring.\n */\nexport type VersionSkewSource = \"rejection\" | \"response-stamp\";\n\n/**\n * The result of one host-side MCP call: the payload the plugin asked for, plus whatever the host\n * observed about the response itself.\n *\n * Named rather than inlined at the {@link McpHttpClient} declaration so hosts have a type to\n * implement against, and so the skew detector and the transports agree on one shape instead of\n * three structurally-compatible copies drifting apart.\n */\nexport interface McpHttpResponse extends McpResponseMetadata\n{\n /** Whether the call succeeded. */\n readonly ok: boolean;\n\n /** The response payload, shaped by the request kind. */\n readonly data?: unknown;\n\n /** Failure message when {@link ok} is false. */\n readonly error?: string;\n\n /**\n * Optional machine-readable classification for a failure, mirroring the `mcpErrorCode` a client\n * can attach to a thrown error. Set it when the client knows why the call failed more precisely\n * than the status says - it takes precedence over {@link status} when the bridge classifies the\n * reply. Values outside the published vocabulary are ignored rather than forwarded.\n */\n readonly mcpErrorCode?: string;\n}\n\n/** A detected mismatch between the version a surface is running and the version now installed. */\nexport interface VersionSkew\n{\n /**\n * The version to remount at, when the kernel named it. Undefined means skew is certain but the\n * target is not — the surface should re-read the extension descriptor rather than guess.\n */\n readonly activeVersion?: string;\n\n /** Which signal detected the skew. */\n readonly detectedFrom: VersionSkewSource;\n}\n\n/**\n * Case-insensitive header read. Hosts pass headers through from whatever HTTP client they use, and\n * casing varies by implementation (`fetch` lower-cases, some proxies and Node clients do not), so\n * matching exactly would make detection depend on the embedder's plumbing.\n */\nfunction readHeader(headers: Readonly<Record<string, string>> | undefined, name: string): string | undefined\n{\n if (!headers)\n {\n return undefined;\n }\n const direct = headers[name];\n if (direct !== undefined)\n {\n return direct;\n }\n const lowered = name.toLowerCase();\n for (const key of Object.keys(headers))\n {\n if (key.toLowerCase() === lowered)\n {\n return headers[key];\n }\n }\n return undefined;\n}\n\nfunction trimmedOrUndefined(value: string | undefined): string | undefined\n{\n const trimmed = value?.trim();\n return trimmed !== undefined && trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Decides whether an MCP response means the surface is running against a version that is no longer\n * installed.\n *\n * @param response What the host observed: whether the call succeeded, plus any status and headers.\n * @param mountedExtensionVersion The version this surface mounted at. Required for proactive\n * detection — without it a response stamp cannot be compared to anything, and only rejections are\n * detectable.\n * @returns The skew, or `null` when the response says nothing about versions.\n */\nexport function detectVersionSkew(\n response: McpHttpResponse,\n mountedExtensionVersion?: string): VersionSkew | null\n{\n const reason = trimmedOrUndefined(readHeader(response.headers, CAPABILITY_REJECTION_REASON_HEADER));\n if (reason !== undefined && reason.toLowerCase() === VERSION_MISMATCH_REASON)\n {\n return {\n activeVersion: trimmedOrUndefined(readHeader(response.headers, EXTENSION_ACTIVE_VERSION_HEADER)),\n detectedFrom: \"rejection\",\n };\n }\n\n // Proactive: only meaningful on a call that worked. A failed response's stamp says nothing\n // about the install having moved — the failure has its own cause, and treating it as skew\n // would remount the surface on every unrelated error.\n if (!response.ok)\n {\n return null;\n }\n\n const mounted = trimmedOrUndefined(mountedExtensionVersion);\n const served = trimmedOrUndefined(readHeader(response.headers, EXTENSION_VERSION_HEADER));\n if (mounted === undefined || served === undefined || served === mounted)\n {\n return null;\n }\n\n return { activeVersion: served, detectedFrom: \"response-stamp\" };\n}\n","/**\n * Wire-shape constants and type guards for host→plugin bridge push messages\n * (WI 4858 sub-plan 2). These types ride the existing MessagePort channel\n * alongside the `ethisys:mcp:*` and `ethisys:remotedom` envelopes — the\n * `type` discriminant keeps them fully separate at the dispatch site.\n *\n * The host posts bridge pushes through `WorkerRemoteDomTransport.hostPort`;\n * the plugin side reads them in `createPortBridgeClient` (plugin-ui package).\n * In-realm (Tier T) plugins use `InMemoryBridgeTransport` which calls the\n * subscriber callbacks directly — no serialisation needed.\n */\n\n// ── Type constants ───────────────────────────────────────────────────────────\n\nexport const BRIDGE_PUSH_THEME = \"ethisys:bridge:theme\" as const;\nexport const BRIDGE_PUSH_LOCALE = \"ethisys:bridge:locale\" as const;\nexport const BRIDGE_PUSH_DENSITY = \"ethisys:bridge:density\" as const;\nexport const BRIDGE_PUSH_A11Y = \"ethisys:bridge:a11y\" as const;\nexport const BRIDGE_NAV_PUSH = \"ethisys:bridge:nav\" as const;\nexport const BRIDGE_CHROME_REQUEST = \"ethisys:bridge:chrome:request\" as const;\nexport const BRIDGE_CHROME_RESPONSE = \"ethisys:bridge:chrome:response\" as const;\nexport const BRIDGE_SESSION_TOKEN_PUSH = \"ethisys:bridge:token\" as const;\nexport const BRIDGE_LIFECYCLE_EVENT = \"ethisys:bridge:lifecycle\" as const;\nexport const BRIDGE_A11Y_ANNOUNCE = \"ethisys:bridge:a11y:announce\" as const;\n\n// ── Envelope shapes ──────────────────────────────────────────────────────────\n\n/** Theme push: host → plugin whenever the host theme changes. */\nexport interface BridgePushThemeEnvelope {\n readonly type: typeof BRIDGE_PUSH_THEME;\n /** \"light\" | \"dark\" | \"high-contrast\" */\n readonly mode: string;\n /** Flat design-token map (CSS-variable-name → value). May be empty. */\n readonly tokens: Readonly<Record<string, string>>;\n}\n\n/** Locale push: host → plugin whenever the active locale changes. */\nexport interface BridgePushLocaleEnvelope {\n readonly type: typeof BRIDGE_PUSH_LOCALE;\n /** BCP 47 tag, e.g. \"en-GB\". */\n readonly locale: string;\n /** \"ltr\" | \"rtl\" */\n readonly dir: \"ltr\" | \"rtl\";\n}\n\n/** Density push: host → plugin when the UI density preference changes. */\nexport interface BridgePushDensityEnvelope {\n readonly type: typeof BRIDGE_PUSH_DENSITY;\n /** \"comfortable\" | \"compact\" */\n readonly density: string;\n}\n\n/** A11y push: host → plugin when accessibility prefs change. */\nexport interface BridgePushA11yEnvelope {\n readonly type: typeof BRIDGE_PUSH_A11Y;\n readonly reducedMotion: boolean;\n readonly highContrast: boolean;\n}\n\n/** Nav push: host → plugin when the SPA location changes. */\nexport interface BridgeNavPushEnvelope {\n readonly type: typeof BRIDGE_NAV_PUSH;\n /** Current SPA path (pathname + search). */\n readonly path: string;\n /** `window.history.length` at the time of push. */\n readonly historyLength: number;\n}\n\n/** Plugin → host: request a chrome action (e.g. toast, modal). */\nexport interface BridgeChromeRequestEnvelope {\n readonly type: typeof BRIDGE_CHROME_REQUEST;\n /** Correlation id — matched against the response. */\n readonly id: string;\n /** \"toast\" | \"confirm\" | \"openUrl\" */\n readonly action: string;\n readonly payload: Readonly<Record<string, unknown>>;\n}\n\n/** Host → plugin: response to a chrome request. */\nexport interface BridgeChromeResponseEnvelope {\n readonly type: typeof BRIDGE_CHROME_RESPONSE;\n readonly id: string;\n readonly ok: boolean;\n readonly result?: unknown;\n readonly error?: string;\n}\n\n/** Host → plugin: push a short-lived frontend-session token. */\nexport interface BridgeSessionTokenPushEnvelope {\n readonly type: typeof BRIDGE_SESSION_TOKEN_PUSH;\n /** Opaque JWT string — audience-restricted to the plugin's own backend. */\n readonly token: string;\n /** Absolute epoch-ms at which the token expires. Refresh fires 30 s before. */\n readonly expiresAtMs: number;\n}\n\n/** Host ↔ plugin lifecycle event. */\nexport type BridgeLifecyclePhase = \"load\" | \"ready\" | \"error\" | \"unload\";\n\nexport interface BridgeLifecycleEventEnvelope {\n readonly type: typeof BRIDGE_LIFECYCLE_EVENT;\n readonly phase: BridgeLifecyclePhase;\n /** Present when phase === \"error\". */\n readonly message?: string;\n}\n\n/** Plugin → host: a11y live-region announcement request. */\nexport interface BridgeA11yAnnounceEnvelope {\n readonly type: typeof BRIDGE_A11Y_ANNOUNCE;\n readonly message: string;\n /** \"polite\" | \"assertive\" */\n readonly politeness: \"polite\" | \"assertive\";\n}\n\n// ── Type guards ──────────────────────────────────────────────────────────────\n\nfunction isObj(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === \"object\";\n}\n\nexport function isBridgePushTheme(v: unknown): v is BridgePushThemeEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_THEME && typeof v[\"mode\"] === \"string\";\n}\n\nexport function isBridgePushLocale(v: unknown): v is BridgePushLocaleEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_LOCALE && typeof v[\"locale\"] === \"string\";\n}\n\nexport function isBridgePushDensity(v: unknown): v is BridgePushDensityEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_DENSITY && typeof v[\"density\"] === \"string\";\n}\n\nexport function isBridgePushA11y(v: unknown): v is BridgePushA11yEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_PUSH_A11Y\n && typeof v[\"reducedMotion\"] === \"boolean\"\n && typeof v[\"highContrast\"] === \"boolean\";\n}\n\nexport function isBridgeNavPush(v: unknown): v is BridgeNavPushEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_NAV_PUSH && typeof v[\"path\"] === \"string\";\n}\n\nexport function isBridgeChromeRequest(v: unknown): v is BridgeChromeRequestEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_CHROME_REQUEST && typeof v[\"id\"] === \"string\";\n}\n\nexport function isBridgeChromeResponse(v: unknown): v is BridgeChromeResponseEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_CHROME_RESPONSE && typeof v[\"id\"] === \"string\";\n}\n\nexport function isBridgeSessionTokenPush(v: unknown): v is BridgeSessionTokenPushEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_SESSION_TOKEN_PUSH\n && typeof v[\"token\"] === \"string\"\n && typeof v[\"expiresAtMs\"] === \"number\";\n}\n\nexport function isBridgeLifecycleEvent(v: unknown): v is BridgeLifecycleEventEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_LIFECYCLE_EVENT && typeof v[\"phase\"] === \"string\";\n}\n\nexport function isBridgeA11yAnnounce(v: unknown): v is BridgeA11yAnnounceEnvelope {\n return isObj(v) && v[\"type\"] === BRIDGE_A11Y_ANNOUNCE && typeof v[\"message\"] === \"string\";\n}\n","/**\n * Worker-side host transport for `renderMode: remote-runtime` extensions\n * (Contract B). Owns the lifecycle of:\n *\n * 1. A path-pinned module `Worker` spawned from a host-issued bootstrap URL.\n * 2. A `MessagePort`-based RPC channel (handed to the worker on spawn).\n * 3. A Shopify Remote DOM root receiver — wired here so the worker's UI\n * tree mounts into a host React tree.\n * 4. Event coalescing (default ≤16ms, one rAF) for high-frequency input\n * events before they cross the port.\n * 5. MCP tool/resource calls forwarded through the port — but **the\n * capability token never crosses the boundary**. The token is bound\n * to the worker scope on the HOST side: the host transport intercepts\n * the plugin's MCP request, attaches the token to the outbound HTTP\n * call, and forwards ONLY the response payload back through the port.\n *\n * This module is intentionally framework-thin: callers wire `mount(root)`\n * onto a React tree (typically inside a `<WorkerSurfaceMount>`), and the\n * Remote DOM receiver is responsible for translating worker-side\n * RemoteRoot mutations into host-side component renders.\n */\n\nimport { createOffscreenCanvasTransfer } from \"./offscreen\";\nimport { classifyHostError, classifyHostResponse } from \"../../bridge/mcp-error\";\nimport type { UploadDocumentMeta } from \"../../plugin/transport\";\nimport {\n detectVersionSkew,\n type McpHttpResponse,\n type VersionSkew,\n} from \"../version-skew\";\nimport {\n BRIDGE_PUSH_THEME,\n BRIDGE_PUSH_LOCALE,\n BRIDGE_PUSH_DENSITY,\n BRIDGE_PUSH_A11Y,\n BRIDGE_NAV_PUSH,\n BRIDGE_CHROME_REQUEST,\n BRIDGE_A11Y_ANNOUNCE,\n BRIDGE_LIFECYCLE_EVENT,\n type BridgePushThemeEnvelope,\n type BridgePushLocaleEnvelope,\n type BridgePushDensityEnvelope,\n type BridgePushA11yEnvelope,\n type BridgeNavPushEnvelope,\n} from \"./bridge-envelopes\";\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/**\n * Structural subset of the DOM `Worker` interface that the transport needs.\n * Tests inject a fake; production callers pass the global `Worker`.\n */\nexport interface WorkerLike\n{\n onmessage: ((ev: MessageEvent) => void) | null;\n onerror: ((ev: ErrorEvent) => void) | null;\n onmessageerror: ((ev: MessageEvent) => void) | null;\n postMessage(message: unknown, transfer?: Transferable[]): void;\n terminate(): void;\n}\n\n/**\n * Constructor signature compatible with the DOM `Worker` constructor. The\n * `workerCtor` option exists exclusively so tests can swap in a fake — in\n * production the caller passes the global `Worker`.\n */\nexport type WorkerCtor = new (url: string | URL, options?: WorkerOptions) => WorkerLike;\n\n/**\n * Discriminated union of MCP fetch shapes the host transport issues. The\n * `capabilityToken` is attached on the host side ONLY — it is never present\n * in any message that crosses the worker port.\n */\nexport type McpHttpRequest =\n | {\n kind: \"invokeTool\";\n name: string;\n args: unknown;\n capabilityToken: string;\n signal?: AbortSignal;\n }\n | {\n kind: \"getResource\";\n uri: string;\n capabilityToken: string;\n signal?: AbortSignal;\n }\n | McpUploadRequest;\n\n/**\n * Host-side document-upload request (a `kind` of {@link McpHttpRequest}).\n * Carries the transferred bytes + advisory metadata plus the host-minted\n * capability token. As with the other request kinds, the token is attached on\n * the HOST side only and never crosses the worker port. Implementations POST\n * the bytes as `application/octet-stream` (metadata in `x-cc-*` headers) to the\n * kernel's capability-token-authed document-upload route; `data` on success is\n * an {@link UploadDocumentResult}.\n */\nexport interface McpUploadRequest\n{\n kind: \"uploadDocument\";\n meta: UploadDocumentMeta;\n buffer: ArrayBuffer;\n capabilityToken: string;\n signal?: AbortSignal;\n}\n\n/**\n * Host-side HTTP client for MCP calls. Implementations are responsible for\n * carrying the supplied `capabilityToken` on the outbound request (typically\n * via `Authorization: Bearer` / `PluginCap`). The `uploadDocument` kind is\n * additive — implementations that predate it fall through to their unknown-kind\n * branch until updated (the FE upload hook is inert until the host handles it).\n */\nexport interface McpHttpClient\n{\n /**\n * Performs the call. The response's `status` and `headers` are optional and additive: supplying\n * them is what enables version-skew detection (see {@link detectVersionSkew}), and an\n * implementation that omits them behaves exactly as before rather than failing.\n */\n fetch(request: McpHttpRequest): Promise<McpHttpResponse>;\n}\n\n/**\n * Construction options for {@link WorkerRemoteDomTransport}.\n */\nexport interface WorkerRemoteDomTransportOptions\n{\n /**\n * Canonical host-origin URL for the worker bootstrap script. This MUST\n * be supplied by the host — never built from user input or extension\n * manifest values — so the worker spawn is path-pinned.\n */\n bootstrapUrl: string;\n\n /**\n * Mints (or fetches a cached) capability token. The host transport\n * resolves this for each outbound MCP HTTP call. The token NEVER leaves\n * host scope — plugin code (the worker side) cannot read it.\n */\n capabilityToken: () => Promise<string>;\n\n /**\n * Host-side MCP HTTP client. The transport bridges port-side plugin\n * MCP requests to this client and returns only the response payload\n * back through the port.\n */\n mcpClient: McpHttpClient;\n\n /**\n * The extension version this surface mounted at. Supplying it enables *proactive* skew\n * detection: a successful response stamped with a different version means the install moved\n * while the surface is still working, so it can remount before anything fails. Without it only\n * outright rejections are detectable, which is a worse experience but not a broken one.\n */\n mountedExtensionVersion?: string;\n\n /**\n * Called at most once, when this surface is found to be running against a version that is no\n * longer installed. The host is expected to remount the surface (which re-mints a capability\n * token against the new version); the transport itself does not retry, because the pending call\n * belongs to a page that is about to be replaced.\n */\n onVersionSkew?: (skew: VersionSkew) => void;\n\n /**\n * Injectable Worker constructor (tests use a fake). Defaults to the\n * global `Worker`.\n */\n workerCtor?: WorkerCtor;\n\n /**\n * Coalescing window in milliseconds for high-frequency events. Defaults\n * to 16ms (~one animation frame). Trailing-edge: the most recent payload\n * within the window is delivered after the window elapses.\n */\n coalesceMs?: number;\n\n /**\n * Maximum number of MCP requests (combined `invokeTool` + `getResource`)\n * the transport will forward to {@link mcpClient} concurrently. Defaults\n * to 8. Requests above the cap are rejected with a deterministic error\n * reply over the port — the worker MUST handle that response shape.\n *\n * Bounded concurrency is a back-pressure boundary, not a quota: it stops\n * a compromised or buggy worker from saturating the host's HTTP / token\n * pool. Production hosts may want to lower this in multi-tenant pools\n * where many extensions share one host process.\n */\n maxConcurrentMcpRequests?: number;\n}\n\n/**\n * Wire shape of a host-sourced input event forwarded to the worker over the\n * port. Pointer / wheel / keyboard payloads share a single envelope type so\n * the worker has one inbound dispatch site. The transport is structurally\n * agnostic to the payload — it forwards verbatim.\n *\n * `kind` discriminates the event family. Coordinates are CSS pixels relative\n * to the host canvas; coalescing happens host-side before the call to\n * {@link WorkerRemoteDomTransport.postInputEvent}.\n */\nexport type InputEventPayload =\n | {\n kind: \"pointermove\" | \"pointerdown\" | \"pointerup\" | \"pointercancel\";\n surfaceId: string;\n x: number;\n y: number;\n buttons: number;\n pointerType: string;\n }\n | {\n kind: \"wheel\";\n surfaceId: string;\n deltaX: number;\n deltaY: number;\n deltaMode: number;\n }\n | {\n kind: \"keydown\" | \"keyup\";\n surfaceId: string;\n key: string;\n code: string;\n ctrlKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n metaKey: boolean;\n };\n\n/**\n * Documented wire protocol identifier embedded in handshake / message\n * envelopes. Bumped when the worker ↔ host message shape changes in a\n * backward-incompatible way.\n */\nexport const WORKER_TRANSPORT_PROTOCOL = \"ethisys.worker.remotedom.v1\";\n\n/**\n * Wire shape of the handshake message the host posts to the worker on\n * {@link WorkerRemoteDomTransport.connect}. Locked here so the SDK side and the\n * API-hosted bootstrap script (`WorkerBootstrapScriptProvider`) read from the\n * same field names — see the API tests pinning `event.data.moduleUrl` and\n * `event.data.importMap`.\n *\n * The handshake is the SOLE message that ever carries `moduleUrl` or\n * `importMap`; subsequent port traffic uses the discriminated message types\n * declared below. The capability token NEVER appears in this payload (or any\n * other postMessage payload) — it is bound on the host side via\n * {@link WorkerRemoteDomTransportOptions.capabilityToken}.\n */\nexport interface WorkerHandshakePayload\n{\n readonly type: \"ethisys:worker:handshake\";\n readonly protocol: string;\n /** Host-origin URL of the plugin's worker bundle entry. */\n readonly moduleUrl: string;\n /**\n * Frozen bare-specifier → host-origin URL map that the bootstrap installs\n * before importing {@link moduleUrl}. Pulled from the plugin's\n * `worker-bundle.import-map.json` at runtime by the host mount.\n */\n readonly importMap: Readonly<Record<string, string>>;\n}\n\n// ─── Implementation ───────────────────────────────────────────────────────────\n\ninterface InvokeToolMessage\n{\n id: string;\n type: \"ethisys:mcp:invokeTool\";\n name: string;\n args: unknown;\n}\n\ninterface GetResourceMessage\n{\n id: string;\n type: \"ethisys:mcp:getResource\";\n uri: string;\n}\n\ninterface UploadDocumentMessage\n{\n id: string;\n type: \"ethisys:mcp:uploadDocument\";\n meta: UploadDocumentMeta;\n buffer: ArrayBuffer;\n}\n\ninterface RemoteDomMessage\n{\n type: \"ethisys:remotedom\";\n payload: unknown;\n}\n\ntype InboundMessage = InvokeToolMessage | GetResourceMessage | UploadDocumentMessage | RemoteDomMessage | { type: string; [k: string]: unknown };\n\n/**\n * Worker-side host transport for Contract B extensions.\n *\n * Construction immediately spawns the worker and transfers one end of a\n * fresh `MessageChannel`; the host retains `port1`, the worker receives\n * `port2`. Both sides exchange messages via their port and the worker port\n * is the *only* channel for plugin ↔ host traffic after handshake.\n */\n/**\n * Default cap for in-flight MCP requests forwarded by the transport. Chosen to\n * cover typical interactive UI traffic (dashboards, list views, detail panels)\n * without letting a runaway worker saturate the host's HTTP / token pool.\n */\nexport const DEFAULT_MAX_CONCURRENT_MCP_REQUESTS = 8;\n\nexport class WorkerRemoteDomTransport\n{\n private readonly worker: WorkerLike;\n private readonly hostPort: MessagePort;\n private readonly workerPort: MessagePort;\n private readonly mcpClient: McpHttpClient;\n private readonly capabilityTokenProvider: () => Promise<string>;\n private readonly mountedExtensionVersion?: string;\n private readonly onVersionSkew?: (skew: VersionSkew) => void;\n private versionSkewReported = false;\n private readonly coalesceMs: number;\n private readonly maxConcurrentMcpRequests: number;\n private readonly abortController: AbortController;\n // Per-request AbortControllers keyed by request id. An inbound\n // `ethisys:mcp:abort` envelope (the worker posts one when a hook's\n // AbortSignal fires on unmount / arg change) aborts just that request;\n // dispose() fans out to every registered controller. Without this a\n // cancelled call — most costly for uploadDocument — keeps streaming to the\n // kernel even though the plugin promise already rejected.\n private readonly inFlightAborts = new Map<string, AbortController>();\n private inFlightMcpRequests = 0;\n private remoteDomConsumer: ((payload: unknown) => void) | undefined;\n private bridgeMessageConsumer: ((msg: unknown) => void) | undefined;\n private disposed = false;\n private connected = false;\n\n public constructor(options: WorkerRemoteDomTransportOptions)\n {\n const WorkerCtor = options.workerCtor ?? (globalThis as unknown as { Worker: WorkerCtor }).Worker;\n if (!WorkerCtor)\n {\n throw new Error(\"WorkerRemoteDomTransport: no Worker constructor available\");\n }\n\n this.mcpClient = options.mcpClient;\n this.capabilityTokenProvider = options.capabilityToken;\n this.mountedExtensionVersion = options.mountedExtensionVersion;\n this.onVersionSkew = options.onVersionSkew;\n this.coalesceMs = options.coalesceMs ?? 16;\n this.maxConcurrentMcpRequests = Math.max(\n 1,\n options.maxConcurrentMcpRequests ?? DEFAULT_MAX_CONCURRENT_MCP_REQUESTS,\n );\n // Aborted from dispose() — propagates into the mcpClient.fetch path so\n // already-in-flight HTTP calls can short-circuit instead of resolving\n // into a closed port.\n this.abortController = new AbortController();\n\n // Spawn the worker FIRST so the constructor's spawn shape is\n // observable to tests even if MessageChannel construction throws.\n this.worker = new WorkerCtor(options.bootstrapUrl, { type: \"module\" });\n\n const channel = new MessageChannel();\n this.hostPort = channel.port1;\n this.workerPort = channel.port2;\n\n // Wire host-side port handling before {@link connect} posts the\n // handshake — this closes a race where the worker could reply faster\n // than we wire up.\n this.hostPort.onmessage = (ev) => this.handlePortMessage(ev.data as InboundMessage);\n this.hostPort.start();\n\n this.worker.onerror = (ev) =>\n {\n // Defensive: do NOT echo worker errors back to the worker — they\n // may carry plugin-side details. Host-side observability is the\n // platform's responsibility.\n void ev;\n };\n }\n\n /**\n * Post the handshake to the worker. Idempotent — only the FIRST call\n * transfers the {@link MessagePort} and posts the handshake payload;\n * subsequent calls are silent no-ops. Splitting this off from the\n * constructor lets the host mount fetch the per-plugin\n * `worker-bundle.import-map.json` (and resolve the bundle's module URL)\n * before the bootstrap script consumes them.\n *\n * Wire shape: {@link WorkerHandshakePayload}. The capability token NEVER\n * appears in the payload — it's bound on the host side via the\n * {@link WorkerRemoteDomTransportOptions.capabilityToken} provider.\n *\n * The `moduleUrl` and `importMap` are forwarded to the worker so the\n * bootstrap script (served from the host-pinned\n * `/extensions/runtime/worker-bootstrap.js`) can:\n * 1. Compose the frozen, same-origin-validated `IMPORT_MAP` from the\n * handshake payload (rejecting any cross-origin entries).\n * 2. `safeImport(moduleUrl)` the plugin's entry module.\n *\n * Same-origin enforcement is the bootstrap's job — this transport is\n * structurally agnostic to the host origin and only forwards what it's\n * handed.\n */\n public connect(moduleUrl: string, importMap: Record<string, string>): void\n {\n if (this.connected)\n {\n return;\n }\n this.connected = true;\n\n // Snapshot the import map into a fresh object so the worker handshake\n // is decoupled from caller-side mutation. `Object.freeze` here is\n // defence-in-depth — the worker rebuilds with `Object.create(null)`\n // anyway, but freezing the host-side payload makes mutation a typed\n // error for any host code that hangs onto the reference.\n const handshake: WorkerHandshakePayload = Object.freeze({\n type: \"ethisys:worker:handshake\",\n protocol: WORKER_TRANSPORT_PROTOCOL,\n moduleUrl,\n importMap: Object.freeze({ ...importMap }),\n });\n this.worker.postMessage(handshake, [this.workerPort]);\n }\n\n /**\n * Bind a consumer for Remote DOM mutation payloads emitted by the worker.\n * The Remote DOM receiver wiring is owned by the caller (typically a host\n * React component); this method exposes the raw stream so the receiver\n * can integrate cleanly without a circular package import.\n */\n public onRemoteDom(consumer: (payload: unknown) => void): void\n {\n this.remoteDomConsumer = consumer;\n }\n\n /**\n * Transfer control of a host-owned `<canvas>` to the worker so plugin code\n * can render via `OffscreenCanvas`. The host retains the `<canvas>` for\n * layout / accessibility purposes only — every pixel is produced inside the\n * worker, so the main thread is never blocked per frame.\n *\n * The transfer rides the established MessagePort (not the worker global\n * `postMessage`) so it is multiplexed with the rest of the host ↔ worker\n * traffic on the same channel. The `OffscreenCanvas` handle is the sole\n * `Transferable` in the envelope; no capability token, MCP context, or\n * other host-only data crosses the boundary.\n *\n * Throws if the environment lacks `transferControlToOffscreen()` or if the\n * canvas has already been transferred — see {@link createOffscreenCanvasTransfer}\n * for the exact diagnostics.\n */\n public transferCanvas(\n canvas: HTMLCanvasElement,\n options: { surfaceId: string },\n ): { offscreen: OffscreenCanvas }\n {\n return createOffscreenCanvasTransfer({\n canvas,\n surfaceId: options.surfaceId,\n postMessage: (message, transfer) =>\n {\n this.hostPort.postMessage(message, transfer);\n },\n });\n }\n\n /**\n * Forward a host-sourced input event to the worker over the port. The\n * payload shape is opaque to the transport — pointer / wheel / keyboard\n * envelopes share the same wire type. Callers are expected to wrap\n * high-frequency (pointer-move, wheel, scroll) events in\n * {@link createCoalescer} or {@link createInputEventCoalescer} BEFORE\n * calling this method so the port never sees the un-coalesced flood.\n *\n * Keyboard / pointer-down / pointer-up events are discrete and should be\n * delivered without coalescing — pass them straight through.\n */\n public postInputEvent(payload: InputEventPayload): void\n {\n this.hostPort.postMessage({\n type: \"ethisys:input:event\",\n payload,\n });\n }\n\n /**\n * Build a trailing-edge coalescer keyed to {@link WorkerRemoteDomTransportOptions.coalesceMs}.\n *\n * Use it to wrap pointer-move / scroll / resize callbacks **before**\n * they cross the port. The last payload in any coalescing window is the\n * one that wins.\n */\n public createCoalescer<T>(consumer: (payload: T) => void): (payload: T) => void\n {\n let pending: T | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () =>\n {\n timer = undefined;\n const value = pending;\n pending = undefined;\n if (value !== undefined)\n {\n consumer(value);\n }\n };\n return (payload: T) =>\n {\n pending = payload;\n if (timer === undefined)\n {\n timer = setTimeout(flush, this.coalesceMs);\n }\n };\n }\n\n // ─── Bridge push methods (WI 4858 sub-plan 2) ─────────────────────────────\n\n /**\n * Register a consumer for inbound plugin→host bridge messages\n * (chrome requests, a11y announce, lifecycle events). Only the most recently\n * registered consumer is kept — the host mount wires exactly one.\n */\n public onBridgeMessage(consumer: (msg: unknown) => void): void\n {\n this.bridgeMessageConsumer = consumer;\n }\n\n /**\n * Push the current host theme to the plugin worker. Safe to call on every\n * host theme-context change — the transport coalesces nothing here; rate\n * limiting at the call site is the host's responsibility.\n */\n public pushTheme(payload: Omit<BridgePushThemeEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_THEME, ...payload });\n }\n\n /** Push the current host locale and text direction to the plugin worker. */\n public pushLocale(payload: Omit<BridgePushLocaleEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_LOCALE, ...payload });\n }\n\n /** Push the current UI density preference to the plugin worker. */\n public pushDensity(payload: Omit<BridgePushDensityEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_DENSITY, ...payload });\n }\n\n /** Push updated accessibility preferences to the plugin worker. */\n public pushA11y(payload: Omit<BridgePushA11yEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_PUSH_A11Y, ...payload });\n }\n\n /** Push the current SPA navigation state to the plugin worker. */\n public pushNav(payload: Omit<BridgeNavPushEnvelope, \"type\">): void\n {\n this.safePostMessage({ type: BRIDGE_NAV_PUSH, ...payload });\n }\n\n /**\n * Tear down the worker and port. Idempotent.\n *\n * Order matters: we abort BEFORE closing the port so any in-flight\n * `mcpClient.fetch` that observes the signal short-circuits and the\n * subsequent attempt to post a reply lands in the disposed-guard branch\n * (which silently drops the post) instead of throwing on a closed port.\n */\n public dispose(): void\n {\n if (this.disposed)\n {\n return;\n }\n this.disposed = true;\n try\n {\n this.abortController.abort();\n // Fan out to every in-flight per-request controller so their\n // `mcpClient.fetch` calls short-circuit too — the dispose-level\n // controller is not the signal those requests were handed.\n for (const controller of this.inFlightAborts.values())\n {\n controller.abort();\n }\n this.inFlightAborts.clear();\n }\n catch\n {\n // AbortController.abort() shouldn't throw, but never let dispose\n // crash the caller — teardown must be best-effort across all\n // resources.\n }\n try\n {\n this.hostPort.close();\n }\n catch\n {\n // ignore — port may already be closed\n }\n try\n {\n this.worker.terminate();\n }\n catch\n {\n // ignore\n }\n }\n\n /**\n * Best-effort wrapper around `hostPort.postMessage` that tolerates posts\n * arriving after {@link dispose}. The browser throws on a closed port and\n * the async handlers below can race dispose, so any post initiated by an\n * awaited continuation must be guarded.\n */\n private safePostMessage(message: unknown): void\n {\n if (this.disposed)\n {\n return;\n }\n try\n {\n this.hostPort.postMessage(message);\n }\n catch\n {\n // Port may have been closed between the disposed check and the\n // post call (browser closes ports asynchronously). Swallowing the\n // throw here is safe because we are already on a teardown path.\n }\n }\n\n // ─── Port message handling ──────────────────────────────────────────────\n\n private handlePortMessage(message: InboundMessage): void\n {\n // Post-dispose port traffic is dropped silently. The browser closes\n // MessagePorts asynchronously; any handler invocation after dispose\n // is a race we observe-and-skip rather than try to service.\n if (this.disposed)\n {\n return;\n }\n switch (message.type)\n {\n case \"ethisys:mcp:invokeTool\":\n this.dispatchMcp(message as InvokeToolMessage, \"ethisys:mcp:invokeTool:result\", (m) => this.handleInvokeTool(m));\n return;\n\n case \"ethisys:mcp:getResource\":\n this.dispatchMcp(message as GetResourceMessage, \"ethisys:mcp:getResource:result\", (m) => this.handleGetResource(m));\n return;\n\n case \"ethisys:mcp:uploadDocument\":\n this.dispatchMcp(message as UploadDocumentMessage, \"ethisys:mcp:uploadDocument:result\", (m) => this.handleUploadDocument(m));\n return;\n\n case \"ethisys:mcp:abort\":\n // Client-side cancel (hook unmount / arg change). Abort just the\n // matching in-flight request so its `mcpClient.fetch` short-circuits\n // instead of streaming to completion. The worker has already dropped\n // its pending resolver, so any late `:result` reply is ignored.\n this.inFlightAborts.get((message as { id?: string }).id ?? \"\")?.abort();\n return;\n\n case \"ethisys:remotedom\":\n this.remoteDomConsumer?.((message as RemoteDomMessage).payload);\n return;\n\n case BRIDGE_CHROME_REQUEST:\n case BRIDGE_A11Y_ANNOUNCE:\n case BRIDGE_LIFECYCLE_EVENT:\n this.bridgeMessageConsumer?.(message);\n return;\n\n default:\n // Unknown messages are ignored. The host MUST NOT echo unknown\n // shapes back to the worker — that would create an attacker-\n // controlled reflection surface.\n return;\n }\n }\n\n /**\n * Gate inbound MCP requests through the bounded concurrency window,\n * reject with a deterministic error reply when the cap is exceeded, and\n * decrement the counter unconditionally when the underlying handler\n * settles (regardless of resolution/rejection shape).\n */\n private dispatchMcp<T extends { id: string }>(\n message: T,\n resultType: string,\n handler: (m: T) => Promise<void>,\n ): void\n {\n if (this.inFlightMcpRequests >= this.maxConcurrentMcpRequests)\n {\n // Back-pressure boundary. The worker MUST surface this to plugin\n // code so it can retry / degrade gracefully rather than silently\n // hang on a never-resolving promise.\n this.safePostMessage({\n id: message.id,\n type: resultType,\n ok: false,\n error: `MCP back-pressure: in-flight cap of ${this.maxConcurrentMcpRequests} reached.`,\n });\n return;\n }\n this.inFlightMcpRequests++;\n this.registerRequestAbort(message.id);\n handler(message).finally(() =>\n {\n this.releaseRequestAbort(message.id);\n this.inFlightMcpRequests = Math.max(0, this.inFlightMcpRequests - 1);\n });\n }\n\n /**\n * Create a per-request AbortController and register it under the request id\n * so an inbound `ethisys:mcp:abort` can cancel just this call. If the\n * transport is already disposed the controller starts aborted so the\n * handler's `mcpClient.fetch` short-circuits immediately.\n */\n private registerRequestAbort(id: string): void\n {\n const controller = new AbortController();\n if (this.abortController.signal.aborted)\n {\n controller.abort();\n }\n this.inFlightAborts.set(id, controller);\n }\n\n /** Drop a settled request's AbortController. */\n private releaseRequestAbort(id: string): void\n {\n this.inFlightAborts.delete(id);\n }\n\n /**\n * The signal to hand to `mcpClient.fetch` for a given request: the\n * per-request controller when registered (client cancel path), falling back\n * to the dispose-level controller.\n */\n private requestSignal(id: string): AbortSignal\n {\n return this.inFlightAborts.get(id)?.signal ?? this.abortController.signal;\n }\n\n /**\n * Raises the skew callback the first time this surface is seen to be running against a version\n * that is no longer installed.\n *\n * Latched deliberately. A page typically has several MCP calls in flight, and after an upgrade\n * every one of them reports the same skew — firing per response would ask the host to remount\n * the same surface repeatedly, and the second remount would tear down the first. One signal per\n * transport is all a remount needs, and the transport is discarded along with the surface.\n *\n * The callback is host code, so it is assumed to be able to throw. Two consequences are guarded\n * here: the throw must not escape into the MCP handler's catch (which would reply `ok: false`\n * for a call that actually succeeded), and it must not consume the latch (which would leave the\n * surface with no response AND no further chance of being told to remount).\n */\n private reportVersionSkew(response: McpHttpResponse): void\n {\n if (this.versionSkewReported || this.onVersionSkew === undefined)\n {\n return;\n }\n const skew = detectVersionSkew(response, this.mountedExtensionVersion);\n if (skew === null)\n {\n return;\n }\n try\n {\n this.onVersionSkew(skew);\n this.versionSkewReported = true;\n }\n catch\n {\n // Swallowed on purpose: a failed remount attempt is the host's problem, and turning it\n // into an MCP failure would corrupt a response the plugin is entitled to. The latch\n // stays open so the next response gets another chance to raise it.\n }\n }\n\n private async handleInvokeTool(message: InvokeToolMessage): Promise<void>\n {\n let token: string;\n try\n {\n token = await this.capabilityTokenProvider();\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:invokeTool:result\", err);\n return;\n }\n // Disposed-before-token: short-circuit. The token mint may have\n // resolved seconds after dispose; posting the reply now would race\n // a closed port.\n if (this.disposed)\n {\n return;\n }\n try\n {\n const result = await this.mcpClient.fetch({\n kind: \"invokeTool\",\n name: message.name,\n args: message.args,\n capabilityToken: token,\n signal: this.requestSignal(message.id),\n });\n this.reportVersionSkew(result);\n // CRITICAL: response payload must never include the token. We\n // forward ONLY the public-facing fields the plugin needs.\n this.safePostMessage({\n id: message.id,\n type: \"ethisys:mcp:invokeTool:result\",\n ok: result.ok,\n data: result.data,\n error: result.error,\n // A client that REPORTS failure rather than throwing lands here, which is the common\n // shape for anything wrapping HTTP. Classifying only the thrown path left these\n // arriving as `internal`.\n code: classifyHostResponse(result),\n });\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:invokeTool:result\", err);\n }\n }\n\n private async handleGetResource(message: GetResourceMessage): Promise<void>\n {\n let token: string;\n try\n {\n token = await this.capabilityTokenProvider();\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:getResource:result\", err);\n return;\n }\n if (this.disposed)\n {\n return;\n }\n try\n {\n const result = await this.mcpClient.fetch({\n kind: \"getResource\",\n uri: message.uri,\n capabilityToken: token,\n signal: this.requestSignal(message.id),\n });\n this.reportVersionSkew(result);\n this.safePostMessage({\n id: message.id,\n type: \"ethisys:mcp:getResource:result\",\n ok: result.ok,\n data: result.data,\n error: result.error,\n // A client that REPORTS failure rather than throwing lands here, which is the common\n // shape for anything wrapping HTTP. Classifying only the thrown path left these\n // arriving as `internal`.\n code: classifyHostResponse(result),\n });\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:getResource:result\", err);\n }\n }\n\n private async handleUploadDocument(message: UploadDocumentMessage): Promise<void>\n {\n let token: string;\n try\n {\n token = await this.capabilityTokenProvider();\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:uploadDocument:result\", err);\n return;\n }\n // Disposed-before-token: short-circuit. The token mint may have resolved\n // after dispose; posting the reply now would race a closed port.\n if (this.disposed)\n {\n return;\n }\n try\n {\n // CRITICAL security invariant: the worker transferred ONLY bytes +\n // metadata. The capability token is minted + attached here (host\n // side) and never crosses the port. The abort signal propagates so\n // a client cancel / host dispose aborts the octet-stream upload.\n const result = await this.mcpClient.fetch({\n kind: \"uploadDocument\",\n meta: message.meta,\n buffer: message.buffer,\n capabilityToken: token,\n signal: this.requestSignal(message.id),\n });\n this.reportVersionSkew(result);\n // Response payload must never include the token — forward only the\n // public-facing UploadDocumentResult fields.\n this.safePostMessage({\n id: message.id,\n type: \"ethisys:mcp:uploadDocument:result\",\n ok: result.ok,\n data: result.data,\n error: result.error,\n // A client that REPORTS failure rather than throwing lands here, which is the common\n // shape for anything wrapping HTTP. Classifying only the thrown path left these\n // arriving as `internal`.\n code: classifyHostResponse(result),\n });\n }\n catch (err)\n {\n this.replyError(message.id, \"ethisys:mcp:uploadDocument:result\", err);\n }\n }\n\n private replyError(id: string, type: string, err: unknown): void\n {\n // Surface a sanitised error string — never the raw error object\n // (which may carry stack traces or token fragments from a misbehaving\n // mcpClient implementation). Routed through safePostMessage so a\n // post-dispose reply does not crash on a closed port.\n const message = err instanceof Error ? err.message : \"MCP request failed\";\n // `code` is derived from the error's own explicit classification (or an HTTP status), never\n // from its message — see classifyHostError. It is safe to expose where the message may not\n // be: a closed vocabulary carries no host internals.\n this.safePostMessage({ id, type, ok: false, error: message, code: classifyHostError(err) });\n }\n}\n","/**\n * Semantic component registry for Contract B (worker remote-runtime)\n * extensions.\n *\n * Worker-side plugin code references UI primitives by name — e.g.\n * `<DataTable />`, `<Drawer />`, `<CanvasSurface />`. The host owns rendering:\n * a {@link SemanticComponentRegistry} maps each name to a concrete component\n * type, and the Remote DOM host receiver consults the registry on every\n * worker-emitted mutation. The closed primitive vocabulary {@link CONTRACT_B_PRIMITIVES}\n * is intentionally narrow — adding a primitive is a coordinated host change so\n * plugins cannot extend the contract ad hoc.\n *\n * **Alignment with SDUI:** Where the Contract B name overlaps with the\n * `@ethisyscore/protocol` SDUI primitive vocabulary (`DataTable`, `Form`), the\n * names are identical to avoid synonym drift. SDUI's `Action` is intentionally\n * NOT reused — Contract B's interactive primitive is named `Button` so the\n * worker authoring API stays close to React DOM idioms. The two vocabularies\n * may converge as they evolve, but the host registries (Contract A SDUI vs\n * Contract B Semantic) remain distinct surfaces today.\n *\n * The registry is renderer-agnostic — the generic `TComponent` parameter is\n * whatever component type the host supplies (React `ComponentType` in\n * production; plain objects in tests). This keeps the registry free of a\n * React peer-dep requirement and lets tests assert behaviour without rendering.\n */\n\n// ─── Closed v1 vocabulary ─────────────────────────────────────────────────────\n\n/**\n * The mandatory Contract B (worker remote-runtime) semantic primitive vocabulary.\n *\n * Adding a primitive requires a coordinated host change + protocol bump —\n * plugins cannot extend this set. Each name has a host-supplied concrete\n * component (gogo-ui in production); the registry enforces 1:1 substitution.\n */\nexport const CONTRACT_B_PRIMITIVES = [\n \"Button\",\n \"DataTable\",\n \"Form\",\n \"EntityPicker\",\n \"CommandBar\",\n \"Drawer\",\n \"Modal\",\n \"CanvasSurface\",\n \"WebGLSurface\",\n // Phase 1 additions — mirror the vite-plugin's CONTRACT_B_SEMANTIC_PRIMITIVES\n // list verbatim; drift between the two is caught by the\n // contract-b.test.ts \"import-map-allowlist matches extension-runtime\n // CONTRACT_B_PRIMITIVES\" test.\n \"Card\",\n \"Tabs\",\n \"Select\",\n \"Alert\",\n] as const;\n\n/**\n * Union type of the Contract B semantic primitive names — exported so callers\n * (tests, hosts) get full IntelliSense and compile-time exhaustiveness checks.\n */\nexport type SemanticPrimitiveName = typeof CONTRACT_B_PRIMITIVES[number];\n\nconst KNOWN_PRIMITIVE_SET: ReadonlySet<string> = new Set(CONTRACT_B_PRIMITIVES);\n\n// ─── Registry ─────────────────────────────────────────────────────────────────\n\n/**\n * Map of semantic primitive name → concrete component for Contract B\n * extensions.\n *\n * Construction is open-ended (callers register primitives one at a time) or\n * eager via {@link SemanticComponentRegistry.fromMap} which forces a complete\n * map up front and aborts if any primitive is missing.\n *\n * @typeParam TComponent - The host's concrete component shape. React hosts pass\n * `ComponentType<P>`; tests pass any tagged object.\n */\nexport class SemanticComponentRegistry<TComponent>\n{\n private readonly entries = new Map<SemanticPrimitiveName, TComponent>();\n\n /**\n * Register a primitive → component binding.\n *\n * Throws if `name` is not in {@link CONTRACT_B_PRIMITIVES} (drift prevention)\n * or if `name` is already registered (silent-override prevention).\n */\n public register(name: SemanticPrimitiveName, component: TComponent): void\n {\n if (!KNOWN_PRIMITIVE_SET.has(name))\n {\n throw new Error(\n `[component-registry] unknown semantic primitive '${name}'. ` +\n `Allowed: ${CONTRACT_B_PRIMITIVES.join(\", \")}.`,\n );\n }\n if (this.entries.has(name))\n {\n throw new Error(\n `[component-registry] primitive '${name}' is already registered. ` +\n `Construct a new registry instead of overriding a binding.`,\n );\n }\n this.entries.set(name, component);\n }\n\n /**\n * Resolve a primitive name to its concrete component. Throws if the name is\n * outside the Contract B vocabulary OR if the registry has no binding —\n * silent fallthrough would let typos render blank components, which is\n * worse than a fast failure for plugin authors.\n */\n public resolve(name: SemanticPrimitiveName): TComponent\n {\n if (!KNOWN_PRIMITIVE_SET.has(name))\n {\n throw new Error(\n `[component-registry] unknown semantic primitive '${name}'. ` +\n `Allowed: ${CONTRACT_B_PRIMITIVES.join(\", \")}.`,\n );\n }\n const found = this.entries.get(name);\n if (found === undefined)\n {\n const registered = this.listRegistered().join(\", \") || \"<none>\";\n throw new Error(\n `[component-registry] primitive '${name}' is not registered. ` +\n `Registered primitives: ${registered}.`,\n );\n }\n return found;\n }\n\n /**\n * Cheap presence probe — never throws. Use this when callers want to\n * fall back to a default component instead of erroring.\n */\n public has(name: SemanticPrimitiveName): boolean\n {\n return this.entries.has(name);\n }\n\n /**\n * Sorted list of registered primitive names. Stable output makes registry\n * diagnostics and snapshot tests deterministic.\n */\n public listRegistered(): SemanticPrimitiveName[]\n {\n return [...this.entries.keys()].sort() as SemanticPrimitiveName[];\n }\n\n /**\n * Build a registry from a complete `Record<SemanticPrimitiveName, T>` map.\n *\n * The `Record` type forces TypeScript to refuse incomplete literals at\n * compile time, AND we re-check at runtime so callers who type-erase the\n * record (e.g., via `as any`) still get a fast failure.\n */\n public static fromMap<T>(map: Record<SemanticPrimitiveName, T>): SemanticComponentRegistry<T>\n {\n const registry = new SemanticComponentRegistry<T>();\n const missing: SemanticPrimitiveName[] = [];\n for (const name of CONTRACT_B_PRIMITIVES)\n {\n const component = (map as Partial<Record<SemanticPrimitiveName, T>>)[name];\n if (component === undefined)\n {\n missing.push(name);\n continue;\n }\n registry.register(name, component);\n }\n if (missing.length > 0)\n {\n throw new Error(\n `[component-registry] fromMap is missing semantic primitive(s): ${missing.join(\", \")}.`,\n );\n }\n return registry;\n }\n}\n","/**\n * `npx mock-host <dir>` — standalone declarative-mock-host dev server.\n *\n * Reads SDUI resources from `<dir>/**\\/*.json` (recursive), wires them into the\n * {@link InMemoryMcpTransport}, and serves a Vite dev page that mounts\n * {@link DeclarativeMockHost} so plugin authors can iterate against the same\n * declarative pipeline the real host uses — without standing up the platform.\n *\n * Resource JSON shape (two accepted forms):\n *\n * 1. Tagged: `{ \"uri\": \"books://catalog\", \"tree\": <SduiNode> }`\n * 2. Untagged: a bare SDUI node. The URI defaults to the file's relative\n * path under the resources directory (with `\\\\` normalised to `/` and the\n * `.json` extension stripped).\n *\n * The CLI's pure resource-loading core is exported as {@link loadResources}\n * for unit testing; the Vite-boot side effect is gated behind {@link run}.\n */\n\nimport { promises as fs } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { KNOWN_PRIMITIVES } from \"@ethisyscore/protocol\";\nimport type { SduiNode } from \"../host/declarative/types\";\nimport {\n WorkerRemoteDomTransport,\n type McpHttpClient,\n type WorkerCtor,\n} from \"../host/worker/transport\";\nimport { CONTRACT_B_PRIMITIVES } from \"../host/worker/component-registry\";\n\n/** Map of MCP resource URI -> SDUI tree, as fed into the mock host. */\nexport type ResourceMap = Record<string, SduiNode>;\n\n/**\n * Map of MCP tool name -> canned result, as fed into the mock host. Each\n * value is returned verbatim when the tool is invoked from the rendered tree\n * (Form.submitTool, Action.tool, Field.lookupTool). Plugin authors who need\n * per-call dynamic behaviour can switch from the CLI's tools.json to a\n * hand-rolled Vite app that mounts DeclarativeMockHost with a typed tools\n * object directly.\n */\nexport type ToolResultMap = Record<string, unknown>;\n\n/**\n * Recursively load every `*.json` file under {@link dir} as a SDUI resource.\n *\n * - Tagged form (`{ uri, tree }`) wins when both fields are present.\n * - Untagged form uses the file's relative POSIX-normalised path (minus\n * extension) as the resource URI.\n *\n * Throws a single aggregated error if any file fails to parse — plugin authors\n * see one failure list instead of giving up at the first bad file.\n */\nexport async function loadResources(dir: string): Promise<ResourceMap>\n{\n const absDir = path.resolve(dir);\n const files = await walkJson(absDir);\n const out: ResourceMap = {};\n const errors: string[] = [];\n\n for (const file of files)\n {\n try\n {\n const raw = await fs.readFile(file, \"utf8\");\n const parsed = JSON.parse(raw) as unknown;\n const { uri, tree } = normaliseEntry(parsed, file, absDir);\n if (out[uri] !== undefined)\n {\n errors.push(`Duplicate resource URI '${uri}' (from ${file})`);\n continue;\n }\n out[uri] = tree;\n }\n catch (e)\n {\n errors.push(`${file}: ${(e as Error).message}`);\n }\n }\n\n if (errors.length > 0)\n {\n throw new Error(\n `Failed to load ${errors.length} mock-host resource(s):\\n - ${errors.join(\"\\n - \")}`,\n );\n }\n\n return out;\n}\n\n/**\n * Read `<dir>/tools.json` (if present) and return a `Record<toolName, canned>`\n * map for the mock transport. Missing file → empty map. Malformed file →\n * throws a single descriptive error.\n *\n * Expected shape: `{ \"<tool-name>\": <result-literal>, ... }`. The literal is\n * returned verbatim from `InMemoryMcpTransport.invokeTool(name, args)`.\n */\nexport async function loadTools(dir: string): Promise<ToolResultMap>\n{\n const toolsPath = path.resolve(dir, \"tools.json\");\n try\n {\n const raw = await fs.readFile(toolsPath, \"utf8\");\n const parsed = JSON.parse(raw) as unknown;\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n {\n throw new Error(`Expected an object map, got ${typeof parsed}`);\n }\n return parsed as ToolResultMap;\n }\n catch (e)\n {\n const err = e as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\")\n {\n return {};\n }\n throw new Error(`Failed to load tools.json from ${toolsPath}: ${err.message}`);\n }\n}\n\n/**\n * Convert a parsed JSON value into a `{ uri, tree }` pair.\n * Exported for tests; not part of the public API.\n */\nexport function normaliseEntry(\n parsed: unknown,\n absFile: string,\n absDir: string,\n): { uri: string; tree: SduiNode }\n{\n if (parsed === null || typeof parsed !== \"object\")\n {\n throw new Error(\"Resource JSON must be an object\");\n }\n const obj = parsed as Record<string, unknown>;\n if (typeof obj.uri === \"string\" && obj.tree !== undefined)\n {\n return { uri: obj.uri, tree: obj.tree as SduiNode };\n }\n // Untagged form: derive URI from the file's relative path.\n const rel = path.relative(absDir, absFile).replace(/\\\\/g, \"/\");\n const uri = rel.replace(/\\.json$/i, \"\");\n return { uri, tree: parsed as SduiNode };\n}\n\nasync function walkJson(root: string): Promise<string[]>\n{\n const out: string[] = [];\n\n async function recurse(dir: string): Promise<void>\n {\n let entries;\n try\n {\n entries = await fs.readdir(dir, { withFileTypes: true });\n }\n catch (e)\n {\n const err = e as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\")\n {\n throw new Error(`Resources directory not found: ${root}`);\n }\n throw e;\n }\n for (const entry of entries)\n {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory())\n {\n await recurse(full);\n }\n else if (entry.isFile() && entry.name.toLowerCase().endsWith(\".json\"))\n {\n out.push(full);\n }\n }\n }\n\n await recurse(root);\n out.sort();\n return out;\n}\n\n/**\n * Render a self-contained HTML page that mounts {@link DeclarativeMockHost}\n * with a debug registry (every primitive renders to a labelled `<div>`).\n *\n * Returned as a string so the Vite middleware can serve it from memory without\n * touching the consumer's filesystem.\n */\nexport function renderIndexHtml(resourceUris: string[]): string\n{\n const defaultUri = resourceUris[0] ?? \"\";\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>mock-host (${resourceUris.length} resources)</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1rem; }\n header { border-bottom: 1px solid #ccc; padding-bottom: 0.5rem; margin-bottom: 1rem; }\n select { padding: 0.25rem 0.5rem; }\n [data-mock-primitive] { padding: 0.5rem; margin: 0.25rem 0; border: 1px dashed #aaa; }\n [data-mock-primitive]::before { content: attr(data-mock-primitive); font-size: 0.75rem; color: #666; display: block; }\n </style>\n </head>\n <body>\n <header>\n <strong>mock-host</strong>\n &nbsp;|&nbsp;\n <label>Resource: <select id=\"resource-picker\">\n ${resourceUris.map(u => `<option value=\"${escapeHtml(u)}\">${escapeHtml(u)}</option>`).join(\"\")}\n </select></label>\n </header>\n <main id=\"root\"></main>\n <script type=\"module\" src=\"/@mock-host/entry.tsx\"></script>\n <script>\n window.__MOCK_HOST_DEFAULT_URI__ = ${safeJsonForScript(defaultUri)};\n window.__MOCK_HOST_RESOURCE_URIS__ = ${safeJsonForScript(resourceUris)};\n </script>\n </body>\n</html>`;\n}\n\nfunction escapeHtml(s: string): string\n{\n return s.replace(/[&<>\"']/g, c => ({\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n \"\\\"\": \"&quot;\",\n \"'\": \"&#39;\",\n }[c] as string));\n}\n\n/**\n * Safely serialise a value for embedding inside an inline `<script>` block.\n *\n * Plain `JSON.stringify` leaves `</script>` unescaped, which lets attacker-\n * controlled resource URIs break out of the script context. We replace the\n * dangerous character pairs with their unicode-escaped equivalents — still\n * valid JSON the browser eagerly parses, but inert inside HTML.\n */\nfunction safeJsonForScript(v: unknown): string\n{\n return JSON.stringify(v)\n .replace(/</g, \"\\\\u003c\")\n .replace(/>/g, \"\\\\u003e\")\n .replace(/&/g, \"\\\\u0026\");\n}\n\n/**\n * Build the virtual entry module the browser loads. Embeds the resource map\n * inline so the dev server does not have to serve JSON over a separate\n * endpoint — Vite HMR re-evaluates this module whenever resources change.\n */\nexport function renderEntryModule(\n resources: ResourceMap,\n tools: ToolResultMap = {},\n): string\n{\n const json = JSON.stringify(resources);\n const toolsJson = JSON.stringify(tools);\n // PR #16 review (Medium: mock-host primitive registry hardcoded). Derive the\n // primitive list from the protocol's KNOWN_PRIMITIVES so the mock host can\n // never accept primitives the real protocol rejects, or omit primitives the\n // real protocol added. JSON.stringify ensures the array is emitted as a JS\n // literal in the generated module — identical wire shape to the prior\n // hardcoded list, just sourced from the protocol package.\n const primitives = JSON.stringify([...KNOWN_PRIMITIVES]);\n return `\nimport { createRoot } from \"react-dom/client\";\nimport { createElement, useState } from \"react\";\nimport { DeclarativeMockHost } from \"@ethisyscore/extension-runtime/mock-host\";\n\nconst PRIMITIVES = ${primitives};\n\nconst registry = Object.fromEntries(PRIMITIVES.map(name => [\n name,\n ({ children }) => createElement(\"div\", { \"data-mock-primitive\": name }, children),\n]));\n\nconst resources = ${json};\nconst toolResults = ${toolsJson};\n// Each canned tool result is wrapped in a sync handler. Authors that need\n// per-call behaviour drop tools.json and hand-roll a Vite app that mounts\n// DeclarativeMockHost with a typed tools object directly.\nconst tools = Object.fromEntries(Object.entries(toolResults).map(([name, value]) => [\n name,\n () => value,\n]));\nconst uris = Object.keys(resources);\n\nfunction App() {\n const [uri, setUri] = useState(window.__MOCK_HOST_DEFAULT_URI__ || uris[0] || \"\");\n // Wire the header picker to React state so authors can switch trees live.\n const picker = document.getElementById(\"resource-picker\");\n if (picker && !picker.__wired) {\n picker.__wired = true;\n picker.value = uri;\n picker.addEventListener(\"change\", e => setUri(e.target.value));\n }\n return createElement(DeclarativeMockHost, {\n resources,\n tools,\n registry,\n defaultResourceUri: uri,\n });\n}\n\ncreateRoot(document.getElementById(\"root\")).render(createElement(App));\n`;\n}\n\n// ─── Contract B (Wave 1) CLI augment ──────────────────────────────────────────\n//\n// Wave 0 only supported Contract A (host-rendered) — a directory of SDUI JSON\n// fed into {@link DeclarativeMockHost}. Wave 1 adds Contract B (remote-runtime):\n// plugin authors run `npx mock-host --render-mode remote-runtime ./worker.js`\n// to spawn an in-process Worker via {@link WorkerRemoteDomTransport} against\n// the same Vite dev page workflow. The semantic component registry from E2.S4\n// is referenced by name — each primitive renders to a labelled placeholder so\n// the receiver's substitution behaviour is observable without standing up\n// gogo-ui.\n\n/** Discriminated union of the two render modes the CLI knows about. */\nexport type RenderMode = \"host-rendered\" | \"remote-runtime\";\n\n/**\n * Parsed CLI arguments. `path` is the positional argument — its meaning\n * depends on {@link renderMode}:\n *\n * - `host-rendered`: a directory of SDUI resource JSON files.\n * - `remote-runtime`: a path (or URL) to a built worker bundle.\n */\nexport interface ParsedArgs\n{\n renderMode: RenderMode;\n path: string;\n}\n\nconst RENDER_MODES: ReadonlySet<RenderMode> = new Set<RenderMode>([\n \"host-rendered\",\n \"remote-runtime\",\n]);\n\n/**\n * Parse the CLI's argv-slice. Exported so the test suite can assert flag\n * handling without booting a Vite server.\n *\n * Accepts both `--render-mode <value>` and `--render-mode=<value>`. Defaults\n * to `host-rendered` to preserve Wave 0 behaviour for existing users.\n */\nexport function parseArgs(args: readonly string[]): ParsedArgs\n{\n let renderMode: RenderMode = \"host-rendered\";\n const positional: string[] = [];\n\n for (let i = 0; i < args.length; i++)\n {\n const arg = args[i]!;\n if (arg === \"--render-mode\")\n {\n const next = args[i + 1];\n if (next === undefined)\n {\n throw new Error(\"Usage: mock-host [--render-mode <host-rendered|remote-runtime>] <path>\");\n }\n if (!RENDER_MODES.has(next as RenderMode))\n {\n throw new Error(\n `Invalid --render-mode '${next}'. Allowed: ${[...RENDER_MODES].join(\", \")}.`,\n );\n }\n renderMode = next as RenderMode;\n i++;\n continue;\n }\n if (arg.startsWith(\"--render-mode=\"))\n {\n const value = arg.slice(\"--render-mode=\".length);\n if (!RENDER_MODES.has(value as RenderMode))\n {\n throw new Error(\n `Invalid --render-mode '${value}'. Allowed: ${[...RENDER_MODES].join(\", \")}.`,\n );\n }\n renderMode = value as RenderMode;\n continue;\n }\n positional.push(arg);\n }\n\n if (positional.length === 0)\n {\n throw new Error(\"Usage: mock-host [--render-mode <host-rendered|remote-runtime>] <path>\");\n }\n\n return { renderMode, path: positional[0]! };\n}\n\n/**\n * Render the HTML shell for the Contract B mock host. The page hosts a\n * receiver that mounts the Remote DOM tree produced by the worker — each\n * Contract B primitive renders to a labelled placeholder.\n */\nexport function renderWorkerBundleIndexHtml(bundlePath: string): string\n{\n const safePath = escapeHtml(bundlePath);\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>mock-host (remote-runtime: ${safePath})</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1rem; }\n header { border-bottom: 1px solid #ccc; padding-bottom: 0.5rem; margin-bottom: 1rem; }\n [data-mock-primitive] { padding: 0.5rem; margin: 0.25rem 0; border: 1px dashed #aaa; }\n [data-mock-primitive]::before { content: attr(data-mock-primitive); font-size: 0.75rem; color: #666; display: block; }\n </style>\n </head>\n <body>\n <header><strong>mock-host</strong> &nbsp;|&nbsp; <em>remote-runtime: ${safePath}</em></header>\n <main id=\"root\"></main>\n <script type=\"module\" src=\"/@mock-host/worker-bundle-entry.tsx\"></script>\n </body>\n</html>`;\n}\n\n/**\n * Build the inline entry module the browser loads for Contract B.\n *\n * The module:\n * 1. Constructs a {@link WorkerRemoteDomTransport} pointing at the bundle.\n * 2. Registers a placeholder for every Contract B semantic primitive — the\n * test-injectable seam from E2.S4. Production hosts would substitute\n * gogo-ui components here.\n * 3. Wires the receiver onto the host's `<main id=\"root\">` slot.\n *\n * In-page wiring is deliberately minimal — the goal is observability, not a\n * production receiver implementation. Authors iterate against the same\n * surface their plugins will mount into when the platform host is finished.\n */\nexport function renderWorkerBundleEntryModule(bundleUrl: string): string\n{\n const safePrimitives = JSON.stringify([...CONTRACT_B_PRIMITIVES]);\n const safeUrl = JSON.stringify(bundleUrl);\n return `\nimport { createRoot } from \"react-dom/client\";\nimport { createElement } from \"react\";\nimport {\n WorkerRemoteDomTransport,\n SemanticComponentRegistry,\n} from \"@ethisyscore/extension-runtime/host\";\n\nconst PRIMITIVES = ${safePrimitives};\nconst bundleUrl = ${safeUrl};\n\n// Build the test-injectable component map — every Contract B primitive\n// renders to a labelled placeholder so plugin authors can see what their\n// worker is emitting before plugging in gogo-ui.\nconst componentMap = Object.fromEntries(PRIMITIVES.map(name => [\n name,\n ({ children }) => createElement(\"div\", { \"data-mock-primitive\": name }, children),\n]));\nconst registry = SemanticComponentRegistry.fromMap(componentMap);\n\n// Mock-host MCP client: no platform, so every tool/resource call resolves\n// to a friendly placeholder. Authors who need real MCP traffic should run\n// against the full platform host.\nconst mcpClient = {\n fetch: async (req) => ({\n ok: true,\n data: { mockHost: true, kind: req.kind, name: req.name ?? req.uri },\n }),\n};\n\n// The capability token never crosses the worker boundary — supply a marker\n// here so the host-side fetcher can still attach an Authorization header.\nconst transport = new WorkerRemoteDomTransport({\n bootstrapUrl: bundleUrl,\n capabilityToken: async () => \"mock-host-capability-token\",\n mcpClient,\n});\n\nconst root = createRoot(document.getElementById(\"root\"));\ntransport.onRemoteDom(() => {\n // The full Remote DOM receiver belongs to a separate concern (E3.S2's\n // WorkerSurfaceMount). For mock-host purposes the registry is the\n // observable surface — log the receiver payload for now.\n root.render(createElement(\"div\", { \"data-mock-host-primitives\": PRIMITIVES.join(\",\") }));\n});\n\n// Expose the transport + registry on window so authors can poke at them from\n// devtools (e.g., to terminate the worker between iteration cycles).\nwindow.__MOCK_HOST_TRANSPORT__ = transport;\nwindow.__MOCK_HOST_REGISTRY__ = registry;\n`;\n}\n\n/**\n * Construction options for {@link bootContractBHost}.\n */\nexport interface BootContractBHostOptions\n{\n /**\n * Path or canonical URL to the plugin's worker bundle. The mock host\n * serves it from the configured Vite root — production hosts always use\n * a path-pinned host-origin URL.\n */\n bundleUrl: string;\n /**\n * Injectable Worker constructor. Tests pass a fake; the production CLI\n * path uses the global `Worker`. The transport itself defaults to\n * `globalThis.Worker` when omitted — but the mock-host CLI passes through\n * the caller's choice so test seams compose cleanly.\n */\n workerCtor?: WorkerCtor;\n /**\n * Optional capability token provider. Defaults to a marker string so\n * authors don't need to wire token plumbing into local-dev.\n */\n capabilityToken?: () => Promise<string>;\n /**\n * Optional MCP HTTP client. Defaults to a stub that echoes the request\n * shape — authors who need real MCP traffic compose the platform host.\n */\n mcpClient?: McpHttpClient;\n}\n\nconst defaultMockMcpClient: McpHttpClient = {\n fetch: async (req) =>\n {\n if (req.kind === \"uploadDocument\")\n {\n // Stub upload: echo a synthetic StoredDocument id so a standalone\n // Contract B host can drive the FE upload flow without core storage.\n return {\n ok: true,\n data: {\n storedDocumentId: `mock-${req.meta.entityName}-${req.meta.fileName}`,\n fileName: req.meta.fileName,\n contentType: req.meta.contentType,\n sizeBytes: req.buffer.byteLength,\n },\n };\n }\n const echo = req.kind === \"invokeTool\" ? { tool: req.name, args: req.args } : { resource: req.uri };\n return { ok: true, data: { mockHost: true, ...echo } };\n },\n};\n\n/**\n * Spawn the in-process worker that drives the Contract B mock host.\n *\n * Returns the constructed transport so callers (production CLI: the dev page;\n * tests: assertions) can observe spawn shape, dispose the worker on shutdown,\n * and inspect coalescing behaviour. Reuses\n * {@link WorkerRemoteDomTransport} so the capability-token isolation rules\n * documented in E2.S3 apply without re-implementation.\n */\nexport function bootContractBHost(options: BootContractBHostOptions): WorkerRemoteDomTransport\n{\n return new WorkerRemoteDomTransport({\n bootstrapUrl: options.bundleUrl,\n capabilityToken: options.capabilityToken ?? (async () => \"mock-host-capability-token\"),\n mcpClient: options.mcpClient ?? defaultMockMcpClient,\n workerCtor: options.workerCtor,\n });\n}\n\n/**\n * Wave 1 Contract B dev server. Boots Vite, serves the virtual index page that\n * runs {@link renderWorkerBundleEntryModule} (which spawns the worker), and\n * exposes the bundle on a host-origin URL so the worker handshake can succeed.\n */\nasync function runContractBHost(bundlePathOrUrl: string): Promise<{ url: string; close: () => Promise<void> }>\n{\n // Lazy import so the pure exports stay decoupled from Vite at type-time.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n let viteMod: any;\n try\n {\n viteMod = await import(\"vite\" as any);\n }\n catch\n {\n throw new Error(\n \"vite is required to run `mock-host`. Install with: npm install --save-dev vite\",\n );\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n // Two flavours of bundle reference are accepted: an absolute URL (rare —\n // useful for testing a deployed bundle) and a filesystem path that the\n // dev server exposes as a host-origin URL.\n const isUrl = /^https?:\\/\\//i.test(bundlePathOrUrl);\n const absBundle = isUrl ? bundlePathOrUrl : path.resolve(bundlePathOrUrl);\n\n if (!isUrl)\n {\n try\n {\n await fs.access(absBundle);\n }\n catch\n {\n throw new Error(`mock-host: worker bundle not found at ${absBundle}`);\n }\n }\n\n // The dev page references the bundle via a stable virtual path. The Vite\n // middleware serves the file's bytes directly so the worker spawn URL is\n // host-origin (matching the production CSP path-pinning shape).\n const bundleServePath = \"/@mock-host/worker-bundle.js\";\n const indexHtml = renderWorkerBundleIndexHtml(isUrl ? bundlePathOrUrl : bundleServePath);\n const entryModule = renderWorkerBundleEntryModule(isUrl ? bundlePathOrUrl : bundleServePath);\n\n const server = await viteMod.createServer({\n root: process.cwd(),\n configFile: false,\n server: { port: 0, host: \"127.0.0.1\" },\n plugins: [\n {\n name: \"mock-host-virtual-worker\",\n resolveId(id: string)\n {\n if (id === \"/@mock-host/worker-bundle-entry.tsx\")\n {\n return \"\\0mock-host:worker-bundle-entry\";\n }\n return null;\n },\n load(id: string)\n {\n if (id === \"\\0mock-host:worker-bundle-entry\")\n {\n return entryModule;\n }\n return null;\n },\n /* eslint-disable @typescript-eslint/no-explicit-any */\n configureServer(devServer: any)\n {\n devServer.middlewares.use(async (req: any, res: any, next: () => void) =>\n {\n if (req.url === \"/\" || req.url === \"/index.html\")\n {\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(indexHtml);\n return;\n }\n if (!isUrl && req.url === bundleServePath)\n {\n try\n {\n const bytes = await fs.readFile(absBundle);\n res.setHeader(\"Content-Type\", \"text/javascript; charset=utf-8\");\n res.end(bytes);\n }\n catch (e)\n {\n res.statusCode = 500;\n res.end(`mock-host: failed to read worker bundle: ${(e as Error).message}`);\n }\n return;\n }\n next();\n });\n },\n /* eslint-enable @typescript-eslint/no-explicit-any */\n },\n ],\n });\n\n await server.listen();\n const addr = server.httpServer?.address();\n let port = 5173;\n if (addr && typeof addr === \"object\")\n {\n port = addr.port;\n }\n const url = `http://127.0.0.1:${port}/`;\n process.stdout.write(`mock-host listening on ${url} (remote-runtime: ${absBundle})\\n`);\n\n return { url, close: () => server.close() };\n}\n\n/**\n * Boot the Vite dev server with an in-memory entry + virtual page.\n *\n * Side-effectful: imports `vite` lazily so the pure `loadResources` export\n * stays usable from environments that lack a Vite install (e.g., the unit\n * tests in this package).\n *\n * Dispatches on `--render-mode`:\n * - `host-rendered` (default): Wave 0 declarative-mock-host behaviour.\n * - `remote-runtime`: Wave 1 Contract B — spawns a worker pointing at the\n * supplied bundle path and serves the placeholder dev page.\n */\nexport async function run(args: string[]): Promise<{ url: string; close: () => Promise<void> }>\n{\n const parsed = parseArgs(args);\n\n if (parsed.renderMode === \"remote-runtime\")\n {\n return runContractBHost(parsed.path);\n }\n\n const dir = parsed.path;\n const resources = await loadResources(dir);\n const tools = await loadTools(dir);\n const uris = Object.keys(resources).sort();\n if (uris.length === 0)\n {\n // Allow boot anyway — authors might want to scaffold-then-add resources\n // with HMR-watched edits.\n process.stderr.write(`mock-host: no resources found in ${dir} (HMR will pick up new files)\\n`);\n }\n\n // Lazy import so the pure exports stay decoupled from Vite at type-time.\n // Vite is declared as an OPTIONAL peer dependency — type as `any` here so\n // building the package doesn't require Vite's type surface to be present.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n let viteMod: any;\n try\n {\n viteMod = await import(\"vite\" as any);\n }\n catch\n {\n throw new Error(\n \"vite is required to run `mock-host`. Install with: npm install --save-dev vite\",\n );\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n\n const indexHtml = renderIndexHtml(uris);\n const entryModule = renderEntryModule(resources, tools);\n const absDir = path.resolve(dir);\n\n const server = await viteMod.createServer({\n root: process.cwd(),\n configFile: false,\n server: { port: 0, host: \"127.0.0.1\" },\n plugins: [\n {\n name: \"mock-host-virtual\",\n resolveId(id: string)\n {\n if (id === \"/@mock-host/entry.tsx\")\n {\n return \"\\0mock-host:entry\";\n }\n return null;\n },\n load(id: string)\n {\n if (id === \"\\0mock-host:entry\")\n {\n return entryModule;\n }\n return null;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n configureServer(devServer: any)\n {\n devServer.watcher.add(absDir);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n devServer.middlewares.use((req: any, res: any, next: () => void) =>\n {\n if (req.url === \"/\" || req.url === \"/index.html\")\n {\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(indexHtml);\n return;\n }\n next();\n });\n },\n },\n ],\n });\n\n await server.listen();\n const addr = server.httpServer?.address();\n let port = 5173;\n if (addr && typeof addr === \"object\")\n {\n port = addr.port;\n }\n const url = `http://127.0.0.1:${port}/`;\n process.stdout.write(`mock-host listening on ${url} (resources: ${uris.length})\\n`);\n\n return { url, close: () => server.close() };\n}\n\n// No top-level bin guard here: the `mock-host` bin entry is a thin\n// CJS wrapper (`bin/mock-host.cjs`, hand-written, kept out of tsup) that\n// requires the compiled `cli.cjs` and calls `run(process.argv.slice(2))`.\n// That keeps this module side-effect free so unit tests can import the pure\n// `loadResources` / `normaliseEntry` / `renderEntryModule` exports without\n// booting Vite.\n"]}