/** * Loopback HMAC client for the dashboard process's `/__cli/*` endpoints, used by * `botmux dashboard [current|rotate]` and the post-start/restart hint. * * Two subtleties this module exists to handle correctly: * * 1. **404 is ambiguous.** Only the dashboard's `/__cli/current` returns 404 to * mean "no token minted yet" (`{ error: 'no_active_token' }`). Any *other* * 404 means the request hit a server that doesn't speak the `/__cli` * protocol — most commonly the daemon IPC server, whose unknown-route 404 is * `{ error: 'not_found', path }`. Conflating the two surfaces the infamous * misleading `Rotation failed: no-active-token` when the real problem is that * `.dashboard-port` points at the wrong service. * * 2. **`.dashboard-port` can go stale.** The dashboard (wildcard) and the daemon * IPC servers (loopback) both `listenWithProbe` upward. Their base ports are * now kept disjoint (config.dashboard.port 7891 + probe span vs ipcBasePort * 7950 — see config.ts, guarded by dashboard-ipc-port-range.test.ts), so a * recorded dashboard port should no longer end up owned by an IPC server. The * HMAC self-heal below stays as defense-in-depth: when the recorded port * answers as the *wrong service* (e.g. a foreign squatter pushed the dashboard * onto an unexpected port), we rediscover the real dashboard by HMAC-probing * the probe range (only the genuine dashboard can validate the signature) and * self-heal `.dashboard-port`. */ export type DashboardEndpoint = '/__cli/rotate' | '/__cli/ensure' | '/__cli/current' | '/__cli/reload-binding'; export type DashboardFailReason = 'no-secret' | 'unreachable' | 'auth-failed' | 'http-error' | 'no-active-token' | 'wrong-service'; export type DashboardResult = { ok: true; url: string; localUrl?: string; } | { ok: false; reason: DashboardFailReason; detail?: string; }; type FetchImpl = typeof fetch; /** * Classify a 404 from a `/__cli/*` request. A genuine "no token yet" only comes * from `/__cli/current` carrying `{ error: 'no_active_token' }`; everything else * means the port is answering for some other service (daemon IPC, a stray HTTP * server, …), not one of the dashboard CLI routes. */ export declare function classifyDashboard404(path: DashboardEndpoint, bodyText: string): DashboardResult; /** * A 401 sig_mismatch from the recorded port does NOT prove that we reached the * live dashboard. On macOS a wildcard dashboard bind can coexist with another * process listening on 127.0.0.1:same-port, so the CLI's loopback request may * hit the shadowing process or a stale dashboard. Treat it as rediscoverable. */ export declare function classifyDashboard401(bodyText: string): DashboardResult; /** Issue a single HMAC-authed request to one candidate port. */ export declare function requestDashboardAt(opts: { host: string; port: number; path: DashboardEndpoint; secret: string; fetchImpl?: FetchImpl; }): Promise; /** * Resolve the dashboard URL for `path`, trying the recorded port first and * self-healing the port file when it points at the wrong service or a loopback * shadow returns an HMAC mismatch. */ export declare function callDashboard(opts: { configDir: string; defaultPort: number; host?: string; envPort?: string; probeSpan?: number; persistPort?: boolean; path: DashboardEndpoint; fetchImpl?: FetchImpl; }): Promise; export {}; //# sourceMappingURL=dashboard-endpoint.d.ts.map