import type { HelloFrame, LogEntry } from '../protocol.js'; import { type GetStateHost } from './rpc/get-state.js'; import { type QueryStateHost } from './rpc/query-state.js'; import { type WouldDispatchHost } from './rpc/would-dispatch.js'; import { type SendMessageHost } from './rpc/send-message.js'; import { type ListActionsHost } from './rpc/list-actions.js'; import { type QueryDomHost } from './rpc/query-dom.js'; import { type DescribeVisibleHost } from './rpc/describe-visible-content.js'; import { type DescribeContextHost, type LastDispatchOutcome } from './rpc/describe-context.js'; import { type ObserveHost } from './rpc/observe.js'; export interface WsLike { send(data: string): void; close(): void; addEventListener(event: 'message', h: (e: { data: string | ArrayBuffer; }) => void): void; addEventListener(event: 'open' | 'close', h: () => void): void; } export type RpcHosts = GetStateHost & QueryStateHost & SendMessageHost & ListActionsHost & QueryDomHost & DescribeVisibleHost & DescribeContextHost & ObserveHost & WouldDispatchHost; export type HelloBuilder = () => HelloFrame; export type WsClient = { /** Resolve a pending confirmation; emits confirm-resolved frame to the server. */ resolveConfirm(confirmId: string, outcome: 'confirmed' | 'user-cancelled', stateAfter?: unknown): void; /** * Emit a state-update frame answering a specific server watch (`id`). * The server correlates by `id`, so only an armed `/wait` receives it. * Dropped silently if the socket isn't OPEN (see finding: never let a * send during CONNECTING throw into the host commit cycle). */ emitStateUpdate(id: string, path: string, stateAfter: unknown): void; /** Emit a log-append frame so the server can mirror client-observed actions to the audit sink. */ emitLogAppend(entry: LogEntry): void; /** Whether the underlying socket has fired `open` and not yet `close`. */ isOpen(): boolean; /** Close the socket cleanly. */ close(): void; }; export type WsClientOpts = { /** Called once when the server sends an `{t: 'active'}` frame. Idempotent. */ onActivated?: () => void; /** * Called with every LogEntry emitted by the ws-client (one per rpc * dispatched or errored). Used by the factory to mirror the entries * into the app's local `agent.log` slice so the UI can show activity. * The ws-client still sends the outbound `log-append` frame to the * server regardless. */ onLogEntry?: (entry: LogEntry) => void; /** * Called with the outcome of every `send_message` rpc — `dispatched` * (with optional errors / warnings), `rejected` (with errors), or * `reducer-threw`. The factory uses this to maintain a "last * outcome" snapshot that `describe_context` injects as a synthetic * hint, so apps don't have to maintain their own * `lastDispatchError` state field. */ onDispatchOutcome?: (outcome: LastDispatchOutcome | null) => void; /** * Called when the server sends a `confirm-expire` frame — the server * has told the agent a confirm is terminally rejected, so the browser * must expire the matching pending confirm entry to prevent a late * user Approve from firing a now-dead dispatch. Idempotent. */ onConfirmExpire?: (confirmId: string) => void; /** * Called when the server arms a state watch (`/wait` began). The * factory records a baseline for `path` and, on each subsequent * commit, emits a `state-update` for `id` iff the resolved value * changed. Absent → no state-update traffic is ever produced. */ onWatch?: (id: string, path: string | undefined) => void; /** Called when the server disarms a watch (`/wait` resolved / timed out). */ onUnwatch?: (id: string) => void; /** * Encode a value for the wire at the frame boundary — applied to * every state-bearing OUTBOUND frame (rpc-reply, state-update, * log-append, confirm-resolved). App callbacks and pointer resolution * run on the raw (redacted-but-unencoded) state; codec encoding * (Date → tagged form, etc.) happens ONLY here, once, as the frame * leaves. Defaults to identity when omitted (tests / no codecs). */ encodeWire?: (value: unknown) => unknown; }; /** * Wires up a WebSocket to serve rpc requests from the server. */ export declare function attachWsClient(ws: WsLike, rpc: RpcHosts, hello: HelloBuilder, opts?: WsClientOpts): WsClient; //# sourceMappingURL=ws-client.d.ts.map