/** * Transport contract used by the plugin-side React hooks * (`useMcpResource`, `useMcpTool`) to talk to the host. * * The hooks are deliberately transport-agnostic: the concrete implementation * (postMessage bridge, in-process direct call, fetch-based, …) is injected * via {@link ExtensionRuntimeProvider} or the per-hook `transport` option. * This keeps the React surface stable across Contract A (host-rendered) and * Contract B (worker remote-runtime) execution modes. * * Implementations must honour the supplied {@link AbortSignal} for * cancellation — hooks rely on it to tear down in-flight calls on unmount * or argument changes. */ interface McpTransport { /** * Fetch a resource by URI. Implementations should reject with an `Error` * when the host returns a failure, and should observe `signal` to abort * any in-flight work. */ getResource(uri: string, signal?: AbortSignal): Promise<{ uri: string; data: T; }>; /** * Invoke a tool by name. The request object is opaque to the transport. * Implementations should observe `signal` to abort in-flight work. */ invokeTool(name: string, args: TReq, signal?: AbortSignal): Promise; /** * Upload a binary document to CORE storage via the host shell and resolve * the resulting {@link UploadDocumentResult} (a `StoredDocumentId` plus the * server-validated file metadata). * * **Optional capability.** A transport that does not support binary upload * simply omits this member; {@link "../../plugin-ui" useMcpUpload} throws a * clear runtime error when invoked against such a transport. Keeping it * optional makes adding the upload seam a **non-breaking, additive** change * for existing custom transport implementations (which only provided * `getResource` + `invokeTool`). * * The bytes are handed off as an {@link ArrayBuffer} — the transport is * expected to move it as a **transferable** (zero-copy) across the * worker↔host port. The plugin (worker) never sees the capability token or * the kernel URL: the host shell mints the token, streams the octet-stream * to the kernel document-upload route, and returns only the result. * * When provided, implementations MUST observe `signal` so an unmount / * cancel aborts the in-flight upload rather than streaming bytes to * completion. */ uploadDocument?(meta: UploadDocumentMeta, buffer: ArrayBuffer, signal?: AbortSignal): Promise; } /** * Metadata accompanying an {@link McpTransport.uploadDocument} call. All fields * are advisory hints to the host/kernel: the kernel derives the organisation * from the authenticated capability token (never from this payload), binds the * effective module key to the caller's plugin identity via a kernel allowlist, * and re-validates / sanitises `fileName` + `contentType` server-side. */ interface UploadDocumentMeta { /** Requested storage module key (e.g. "hr"). Validated against the caller's kernel allowlist. */ moduleKey: string; /** Owning entity name (e.g. "Candidates", "CompanyDocuments"). */ entityName: string; /** Optional owning entity id. */ entityId?: string; /** Logical sub-folder / category (e.g. "cvs"). */ category: string; /** Client-supplied file name (server sanitises + caps length). */ fileName: string; /** Client-supplied MIME type (server re-parses; falls back to application/octet-stream). */ contentType: string; /** Byte length of the buffer (advisory; the kernel size cap is authoritative). */ sizeBytes: number; } /** * Result of a successful {@link McpTransport.uploadDocument} call — the id of * the registered `StoredDocument` plus the metadata the kernel actually stored. * The plugin only ever holds the id; it never receives the bytes back. */ interface UploadDocumentResult { storedDocumentId: string; fileName: string; contentType: string; sizeBytes: number; } /** * Wire-shape constants and type guards for host→plugin bridge push messages * (WI 4858 sub-plan 2). These types ride the existing MessagePort channel * alongside the `ethisys:mcp:*` and `ethisys:remotedom` envelopes — the * `type` discriminant keeps them fully separate at the dispatch site. * * The host posts bridge pushes through `WorkerRemoteDomTransport.hostPort`; * the plugin side reads them in `createPortBridgeClient` (plugin-ui package). * In-realm (Tier T) plugins use `InMemoryBridgeTransport` which calls the * subscriber callbacks directly — no serialisation needed. */ declare const BRIDGE_PUSH_THEME: "ethisys:bridge:theme"; declare const BRIDGE_PUSH_LOCALE: "ethisys:bridge:locale"; declare const BRIDGE_PUSH_DENSITY: "ethisys:bridge:density"; declare const BRIDGE_PUSH_A11Y: "ethisys:bridge:a11y"; declare const BRIDGE_NAV_PUSH: "ethisys:bridge:nav"; declare const BRIDGE_SESSION_TOKEN_PUSH: "ethisys:bridge:token"; /** Theme push: host → plugin whenever the host theme changes. */ interface BridgePushThemeEnvelope { readonly type: typeof BRIDGE_PUSH_THEME; /** "light" | "dark" | "high-contrast" */ readonly mode: string; /** Flat design-token map (CSS-variable-name → value). May be empty. */ readonly tokens: Readonly>; } /** Locale push: host → plugin whenever the active locale changes. */ interface BridgePushLocaleEnvelope { readonly type: typeof BRIDGE_PUSH_LOCALE; /** BCP 47 tag, e.g. "en-GB". */ readonly locale: string; /** "ltr" | "rtl" */ readonly dir: "ltr" | "rtl"; } /** Density push: host → plugin when the UI density preference changes. */ interface BridgePushDensityEnvelope { readonly type: typeof BRIDGE_PUSH_DENSITY; /** "comfortable" | "compact" */ readonly density: string; } /** A11y push: host → plugin when accessibility prefs change. */ interface BridgePushA11yEnvelope { readonly type: typeof BRIDGE_PUSH_A11Y; readonly reducedMotion: boolean; readonly highContrast: boolean; } /** Nav push: host → plugin when the SPA location changes. */ interface BridgeNavPushEnvelope { readonly type: typeof BRIDGE_NAV_PUSH; /** Current SPA path (pathname + search). */ readonly path: string; /** `window.history.length` at the time of push. */ readonly historyLength: number; } /** Host → plugin: push a short-lived frontend-session token. */ interface BridgeSessionTokenPushEnvelope { readonly type: typeof BRIDGE_SESSION_TOKEN_PUSH; /** Opaque JWT string — audience-restricted to the plugin's own backend. */ readonly token: string; /** Absolute epoch-ms at which the token expires. Refresh fires 30 s before. */ readonly expiresAtMs: number; } export type { BridgeNavPushEnvelope as B, McpTransport as M, UploadDocumentMeta as U, BridgePushA11yEnvelope as a, BridgePushDensityEnvelope as b, BridgePushLocaleEnvelope as c, BridgePushThemeEnvelope as d, BridgeSessionTokenPushEnvelope as e, UploadDocumentResult as f };