/** * The socket the page holds open, and what gets written down it. * * The page used to ask `/api/status` every 1.5 seconds, which is a poor fit for * what it is watching: a `check` says nothing for a minute at a time and then * files a finding, so the poll was both too slow to be live and too frequent to * be idle. This is the other way round. The page opens one socket, the server * writes to it when something actually moves, and a board nobody is running * anything against costs no traffic at all. * * One direction only. Every write the page makes is already a POST, and it * should stay one: those are actions with answers, and an action whose outcome * arrives on a different channel than the request is harder to reason about * than one that simply returns it. * * Frames carry a kind, because there are two things to say. A `status` frame is * the whole payload `/api/status` answers with rather than a delta: the page * already redraws only the regions whose signature moved, so a delta would buy * bytes on a loopback socket and cost a second implementation of the fold that * `summarise` already is. A `narration` frame IS a delta, for the opposite * reason: a judge writing a verdict says something several times a second, and * re-sending its whole transcript each time would put the same thousand lines * on the wire over and over. */ import type { Server, ServerWebSocket } from "bun"; /** Upgrade a request into a live socket. False when it was not a websocket request. */ export declare function openLive(req: Request, server: Server): boolean; /** * Send the current status to every open socket. * * Called by the watcher when the run log or the backlog moves, by the few * transitions no file records (a run starting, a child dying), and by a socket * opening, which forces a send because a page that has just connected has * nothing on it yet. * * Forcing goes through here rather than being a send of its own so that both * kinds of push are ordered against each other. A greeting built beside this * could be delivered after a newer payload and leave that tab stale until * something else happened to move. */ export declare function pushNow(force?: boolean): Promise; /** * Push whatever the judges have said since the last time. * * Separate from the board's push, and not folded into it, because the two move * at completely different rates: a verdict being written says something several * times a second while the board it will land on does not change at all. A push * that carried both would either rebuild the board per token or hold the * narration back until a finding landed. */ export declare function pushNarration(): void; export declare const live: { open(ws: ServerWebSocket): void; close(ws: ServerWebSocket): void; /** * The page never sends anything. Its writes are POSTs, deliberately, so this * exists only because a websocket handler must have one. */ message(): void; }; /** How many pages are listening. Exported for the watcher, which sleeps when nobody is. */ export declare function liveCount(): number;