import type { IncomingMessage, Server as HttpServer } from "http"; /** * v2.2.0 Codex audit H4: broadcasts are metadata-only. * * Pre-audit shape included `data: Record` carrying raw * webhook payloads + plaintext message.sent content. The dashboard client * treats every push as a "something changed — refetch /api/snapshot" * signal and ignores the payload entirely; sending the full shape * needlessly expanded the blast radius (any log aggregator, any * unauthenticated network capture during the WebSocket handshake, or a * future WS-surface-broadening bug would have leaked message content). * * Trimmed to {event, entity_id, ts, kind?}. `kind` is an optional * one-word tag ("send_message", "task.accepted", etc.) for clients that * want to display "X happened" without looking up details — still free * of body content. If we ever need to ship payload-bound broadcasts, * introduce a new `DashboardPayloadEvent` shape alongside this one so * the metadata-only contract never regresses silently. */ export interface DashboardEvent { /** High-level event name broadcast to dashboard clients. Stable wire format. */ event: "agent.state_changed" | "message.sent" | "task.transitioned" | "channel.posted" | "dashboard.theme_changed" | "agent.status_changed"; /** Primary entity id used for the rate-limit coalesce key. */ entity_id: string; /** ISO timestamp of the event — always stamped server-side so clients can order. */ ts: string; /** Optional one-word sub-tag (e.g. `"send_message"` or `"task.accepted"`). No body content. */ kind?: string; } /** * Gate: is this incoming upgrade allowed to open a dashboard WS session? * Exported for testability. */ export declare function dashboardWsAuthOk(req: IncomingMessage): { ok: boolean; reason?: string; }; /** * Attach a WebSocket server to the running http.Server. Hijacks only the * /dashboard/ws upgrade path; every other upgrade is left for future * transports to handle (currently none). */ export declare function attachDashboardWs(server: HttpServer): void; /** * Broadcast an event to every connected dashboard client. Rate-limited: at * most one broadcast per 500ms per (event, entity_id) tuple. Exceeding that * drops the broadcast silently — the next state transition will emit its * own fresh broadcast and clients poll-refresh via /api/snapshot if they * want canonical state. * * NEVER throws. Event sources are callbacks from hot paths (send_message, * update_task, etc.); a broadcast failure must not escape to the caller. */ export declare function broadcastDashboardEvent(evt: DashboardEvent): void; /** Testing-only: clear module-scope state between runs. */ export declare function _resetDashboardWsForTests(): void; /** Testing-only: read-only view of client + rate-limit counts. */ export declare function _dashboardWsStateForTests(): { clients: number; rateKeys: number; }; //# sourceMappingURL=websocket.d.ts.map