{"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"]}