import type { AppEndpoint } from "@telorun/debug-ui"; import { LruBlobStore } from "./blob-store.js"; export interface DebugServerOptions { /** Preferred bind host. Default `127.0.0.1` (loopback). */ host?: string; /** Preferred port; falls back to an ephemeral port if taken. Default 9230. */ port?: number; /** Path to the JSONL file, served at `/events.jsonl` for download. */ jsonlPath?: string; /** Absolute path to the single-file debug UI (`resolveUiBundle`). When absent, * the endpoint runs headless and `/` returns a "UI not available" notice. */ uiHtmlPath?: string; /** Single-file debug UI bytes to serve from memory — set when the bundle was * fetched under `--no-cache-write` and never written to disk (e.g. the k8s * runner's read-only cache). Preferred over {@link uiHtmlPath} when both set. */ uiHtml?: Buffer; /** Why the UI bundle is absent — rendered verbatim in the `/` 503 (e.g. the * exact fetch URL that failed) so the failure is explicit, not generic. */ uiUnavailableReason?: string; /** Replay ring-buffer size. Default 5000. */ bufferSize?: number; } /** * Localhost-only HTTP server that serves the debug-watcher UI and streams events * to it over SSE. Bound to `127.0.0.1` because events can carry secrets. The * caller pushes already-serialized wire lines via {@link push}; the server keeps * a bounded replay buffer so a browser opened (or reconnected) mid-run sees * history, then live events. * * Producer-side and Node-specific by design — a Rust/Go kernel reimplements this; * the cross-runtime contract is the wire format and these endpoints, not the code. */ export declare class DebugServer { private readonly options; private readonly server; private readonly clients; private readonly heartbeats; private readonly buffer; private readonly bufferSize; private readonly host; private _url; private _endpoints; /** Binary payloads are offloaded here and served at `/blobs/:id`; the serializer * emits pointers into the event log. */ readonly blobStore: LruBlobStore; constructor(options?: DebugServerOptions); get url(): string; /** Advertise where the running app is reachable; the UI fetches these from the * `/json/version` handshake and renders them as links. Hosts are left blank — * the producer can't know which hostname the viewer used, so the UI fills them * from its own origin. Updatable across watch reloads. */ setEndpoints(endpoints: AppEndpoint[]): void; /** Start listening on the configured host (loopback by default). Resolves once * the URL is known. */ start(): Promise; private listen; /** Fan one serialized wire line to the replay buffer and every live client. */ push(line: string): void; /** * Tear down so nothing keeps the process alive. `unref` alone is unreliable * across runtimes (bun ignores `socket.unref()`), so we *actively* clear every * heartbeat timer and destroy every live SSE socket, then close the listener. * Synchronous and idempotent — safe to call from a signal handler. */ stop(): void; private handle; /** Discovery handshake: protocol identity + version + endpoint paths, so a * consumer can confirm it speaks this server's wire format before connecting. */ private handleVersion; private handleSse; private handleBlob; private handleJsonl; /** Serve the single-file UI for every non-API path. The bundle is fully * self-contained (JS + CSS inlined), so there are no asset routes to resolve * and no path-traversal surface. Absent bundle → a 503 notice; the endpoint * itself (SSE / JSONL / blobs / version) keeps working headless. */ private handleUi; } //# sourceMappingURL=debug-server.d.ts.map