import { ReactNode, ReactElement } from 'react'; import { C as ComponentRegistry } from '../registry-DpCx_LxF.cjs'; import { SduiNode } from '@ethisyscore/protocol'; import { M as McpTransport, U as UploadDocumentMeta, f as UploadDocumentResult } from '../bridge-envelopes-DA6vxbyb.cjs'; import { P as PortBridgeClient, T as ThemePayload, L as LocalePayload, D as DensityPayload, A as A11yPayload, N as NavPayload, S as SessionTokenPayload } from '../bridge-client-DzRcKIJT.cjs'; /** * Handler for a mocked tool invocation. The handler receives the request * payload supplied by the caller and may return synchronously or * asynchronously. The result is forwarded verbatim through * {@link InMemoryMcpTransport.invokeTool}. */ type MockToolHandler = (args: unknown) => Promise | unknown; /** * Handler for a mocked document upload. Receives the {@link UploadDocumentMeta} * and the transferred bytes; returns the {@link UploadDocumentResult} the FE * hook resolves. Optional — when omitted, the transport returns a synthetic * result echoing the metadata so a standalone plugin can exercise the flow. */ type MockUploadHandler = (meta: UploadDocumentMeta, buffer: ArrayBuffer, signal?: AbortSignal) => Promise | UploadDocumentResult; /** * An in-memory {@link McpTransport} backed by a `{ resources, tools }` map. * * Used by {@link DeclarativeMockHost} so plugin authors can run their app * standalone for local development without a real host. The transport mirrors * the runtime contract exactly: * * - `getResource(uri)` resolves a `SduiNode` keyed by URI, or rejects with a * descriptive error if the URI is not registered. * - `invokeTool(name, args)` dispatches to a synchronous or async handler, * or rejects if the tool name is unknown. * * `getResource` / `invokeTool` intentionally do NOT honour the supplied * `AbortSignal` — mock handlers are synchronous from the caller's perspective * and there is no in-flight network call to abort. Hooks still work correctly * because they treat the `AbortSignal` as a one-way notification, not a * contract. `uploadDocument` DOES observe the signal (rejecting with an * `AbortError`): its contract mandates it, a mock upload handler may be * genuinely async, and dev-host flows need to simulate upload cancellation. */ declare class InMemoryMcpTransport implements McpTransport { private readonly resources; private readonly tools; private readonly uploadHandler?; constructor(resources: Record, tools?: Record, uploadHandler?: MockUploadHandler); getResource(uri: string): Promise<{ uri: string; data: T; }>; invokeTool(name: string, args: TReq): Promise; uploadDocument(meta: UploadDocumentMeta, buffer: ArrayBuffer, signal?: AbortSignal): Promise; } /** * Props for {@link DeclarativeMockHost}. * * Plugin authors `npm link` the runtime and render `` in * their local dev app to exercise the same declarative pipeline the real host * uses, but backed by in-memory fakes instead of the platform. */ interface DeclarativeMockHostProps { /** * In-memory resource map. Keys are MCP resource URIs; values are SDUI trees * that {@link interpret} will render against the supplied registry. */ resources: Record; /** * In-memory tool map. Keys are MCP tool names; values are handlers invoked * when a child component calls `useMcpTool(name).invoke(args)`. * * Handlers may be sync or async — the transport awaits the result before * forwarding it to the caller. */ tools?: Record; /** * URI of the resource rendered as the host's default tree. If the URI is * not present in `resources` the host renders the supplied `children` * instead — useful for stubs that exercise only tool invocations. */ defaultResourceUri: string; /** * The same primitive → component registry the real host uses. Passed * verbatim to {@link interpret}; the mock host owns no UI of its own. */ registry: ComponentRegistry; /** * Optional fallback content rendered when `defaultResourceUri` does not * resolve to a registered resource. Children also have access to the wired * transport via {@link ExtensionRuntimeProvider}, so they can invoke * mocked tools and resources directly through the React hooks. */ children?: ReactNode; } /** * In-memory host for declarative (Contract A) plugin local-dev. * * Renders a plugin's SDUI resource against the supplied registry and wires an * {@link InMemoryMcpTransport} into context so descendant components that use * `useMcpResource` / `useMcpTool` resolve against the same fakes. * * The host is intentionally minimal: it does not simulate permissions, theme * propagation, or capability tokens. Its purpose is to exercise the * declarative pipeline end-to-end against deterministic in-memory data so * plugin authors can iterate without standing up the real platform. */ declare function DeclarativeMockHost(props: DeclarativeMockHostProps): ReactElement; /** * In-realm bridge transport for plugin local-dev and contract testing. * * Calling `pushTheme(...)`, `pushLocale(...)`, etc. invokes the registered * subscriber callbacks **synchronously** — no serialisation, no port. This * lets Vitest + React Testing Library drive bridge state changes with `act()` * without a real MessageChannel. * * In production, the bridge client is `createPortBridgeClient` backed by a * real MessagePort. `InMemoryBridgeTransport` is the dev/test equivalent: * both expose the same `PortBridgeClient`-compatible subscriber API on the * consumer side, but `InMemoryBridgeTransport` also exposes the push-side * and the `onChromeRequest` handler for test assertions. */ type ChromeRequestHandler = (action: string, payload: Record) => Promise | unknown; declare class InMemoryBridgeTransport implements PortBridgeClient { private _themeCb; private _localeCb; private _densityCb; private _a11yCb; private _navCb; private _tokenCb; private _chromeHandler; onTheme(cb: (p: ThemePayload) => void): void; onLocale(cb: (p: LocalePayload) => void): void; onDensity(cb: (p: DensityPayload) => void): void; onA11y(cb: (p: A11yPayload) => void): void; onNav(cb: (p: NavPayload) => void): void; onSessionToken(cb: (p: SessionTokenPayload) => void): void; requestChrome(action: string, payload: Record): Promise; announceA11y(_message: string, _politeness: "polite" | "assertive"): void; /** Push a theme update to the registered subscriber (synchronous). */ pushTheme(payload: ThemePayload): void; /** Push a locale update to the registered subscriber. */ pushLocale(payload: LocalePayload): void; /** Push a density update. */ pushDensity(payload: DensityPayload): void; /** Push a11y preference changes. */ pushA11y(payload: A11yPayload): void; /** Push a nav state update. */ pushNav(payload: NavPayload): void; /** Push a frontend-session token. */ pushSessionToken(payload: SessionTokenPayload): void; /** * Register a handler for plugin→host chrome requests (toast, confirm, etc). * Called by `requestChrome` and by `simulateChromeRequest`. */ onChromeRequest(handler: ChromeRequestHandler): void; /** * Programmatically send a chrome request as if a plugin component called * `PortBridgeClient.requestChrome(...)`. Useful for test assertions. */ simulateChromeRequest(action: string, payload: Record): Promise; } /** * Mock host for plugins that use bridge hooks (`useBridgeTheme`, * `useBridgeLocale`, `useBridgeA11y`, etc.) during local-dev or contract * testing. * * Wraps {@link DeclarativeMockHost} and wires a {@link BridgeClientContext} * provider so any descendant bridge hook resolves against the supplied * `bridgeTransport` instead of throwing "no bridge client available". * * For tests where bridge state must be driven externally (push a new theme, * assert that a component re-renders), pass an {@link InMemoryBridgeTransport} * instance and call `transport.pushTheme(...)` wrapped in `act()`. */ interface WorkerMockHostProps extends DeclarativeMockHostProps { /** * The bridge transport to wire into context. Pass an * {@link InMemoryBridgeTransport} for tests; pass a * `createPortBridgeClient(port)` instance for postMessage integration tests. */ bridgeTransport: PortBridgeClient; } /** * Mock host that combines the SDUI declarative pipeline with bridge context. * * Rendering contract (same as DeclarativeMockHost): * - `defaultResourceUri` present in `resources` → renders the SDUI tree. * - URI absent → renders `children` instead (tool-invocation stubs, etc). * * Bridge contract: * - All `useBridgeTheme`, `useBridgeLocale`, etc. hooks in the subtree resolve * against `bridgeTransport`. */ declare function WorkerMockHost(props: WorkerMockHostProps): ReactElement; export { DeclarativeMockHost, type DeclarativeMockHostProps, InMemoryBridgeTransport, InMemoryMcpTransport, type MockToolHandler, WorkerMockHost, type WorkerMockHostProps };