/** * Loopback configuration server for the web console. * * Threat model (design decision 10): a page in the user's browser can issue * requests to `localhost` even when it cannot read the responses, so loopback * binding alone is not authentication. Every defence here follows from that: * * - binds `127.0.0.1` only, on a configured stable port — never a wildcard or LAN * interface; * - each command invocation mints a one-time, high-entropy launch token; the * first valid navigation exchanges it for an `HttpOnly; SameSite=Strict` * session cookie and redirects to a clean URL, so the token never lingers in * history, the referrer, or a shared screen; * - every API route requires that cookie; mutating routes additionally require * an exact `Host` and same-origin `Origin`, a JSON content type, and a * bounded body; * - CORS is never enabled, routes and methods are allowlisted, static assets are * served from a precomputed allowlist (no path is ever taken from the request * and resolved against the filesystem), and configuration responses are * `no-store` under a strict CSP. * * The server is lazy, reusable, idle-expiring, and explicitly disposable. It * exposes only the configured entry document and its composed data — never an * arbitrary filesystem path, an import edit target, or a command. * * Core module — no pi imports. The host passes in the entry path, harness facts, * and a notify callback. */ import { type RegisteredHarnessInfo } from "#src/config-editor"; export { DEFAULT_CONFIG_SERVER_PORT } from "#src/config-console"; export interface ConfigServerOptions { /** Absolute path of the sole entry document this console edits. */ entryPath: string; /** Harnesses registered in the running extension. */ harnesses?: readonly RegisteredHarnessInfo[]; /** Packaged browser assets. Defaults to the `web/` directory beside this module. */ assetsDir?: string; /** Inactivity period after which the server closes itself. */ idleTimeoutMs?: number; /** * Loopback port to bind. Defaults to the stable console port; pass 0 only * when an OS-assigned ephemeral port is intentionally required (tests). */ port?: number; /** * Disable launch-token authentication for a disposable local dev server. * Never enable this for the extension's real configuration console. */ development?: boolean; } export interface ConfigServer { readonly port: number; /** Base origin, e.g. `http://127.0.0.1:38217`. */ readonly origin: string; /** Mint a fresh one-time authenticated launch URL. */ issueLaunchUrl(): string; /** True once closed, by disposal or inactivity. */ readonly closed: boolean; close(): Promise; } /** Default packaged asset directory: `/web/`. */ export declare function defaultAssetsDir(): string; /** * Start a configuration server on its configured loopback port. * * Prefer `getOrCreateConfigServer` — a session should reuse one server rather * than accumulate them. */ export declare function startConfigServer(options: ConfigServerOptions): Promise; /** * Return the live server for `entryPath`, starting one on first use. * * A server that has closed itself through inactivity is replaced transparently, * so a later command invocation always yields a usable console. */ export declare function getOrCreateConfigServer(options: ConfigServerOptions): Promise; /** Close the shared server, if one is running. Safe to call repeatedly. */ export declare function disposeConfigServer(): Promise; /** * Try to open `url` in the default browser. * * Resolves false when the platform opener is missing or fails — the caller keeps * the server up and shows a copyable URL instead. */ export declare function openInBrowser(url: string): Promise; //# sourceMappingURL=config-server.d.ts.map