/** * Node status client. * * `createNodeStatusClient(opts)` produces a small subscribe/current/stop client * that surfaces a {@link NodeStatusSetView} in one of two modes: * * - **remote**: connect to a node's `/ws/status` WebSocket feed, decode the * size-prefixed `$NST` binary frames, and re-emit on every update. * Auto-reconnects with capped exponential backoff + jitter. * - **helia**: given an SDN Helia node ({@link HeliaSDNNode} from * `createHeliaSDNNode`), assemble the same view client-side from the local * libp2p peer id, connection state to the two SDN bootstrap peers, EPM/vCard * resolution, and opportunistic geo coordinates from any reachable remote * `/ws/status` feed. * * Both modes are fail-open: transient errors never throw out of the client; * they are reported through `opts.onError` (when provided) and the client keeps * running. */ import type { HeliaSDNNode } from '../helia'; import { type NodeStatusSetView } from './view-model'; /** Minimal structural WebSocket used by the client (browser / `ws` / mocks). */ export interface WebSocketLike { binaryType: string; readonly readyState: number; send(data: string | ArrayBufferLike | ArrayBufferView): void; close(code?: number, reason?: string): void; onopen: ((event: unknown) => void) | null; onclose: ((event: unknown) => void) | null; onerror: ((event: unknown) => void) | null; onmessage: ((event: { data?: unknown; }) => void) | null; } /** Constructor shape for a {@link WebSocketLike}. */ export type WebSocketCtor = new (url: string) => WebSocketLike; /** A subscriber for status set updates. */ export type NodeStatusListener = (view: NodeStatusSetView) => void; /** The shared client interface exposed by both modes. */ export interface NodeStatusClient { /** * Subscribe to status updates. The current view (if any) is delivered * synchronously on subscribe. Returns an unsubscribe function. */ subscribe(cb: NodeStatusListener): () => void; /** The most recently emitted view, or `null` before the first update. */ current(): NodeStatusSetView | null; /** Stop the client, closing sockets/timers. Idempotent. */ stop(): void; } /** Options for {@link createNodeStatusClient}. */ export interface NodeStatusClientOptions { /** * Remote mode: URL of the node's status feed. Accepts `wss://`, `ws://`, * `https://`, `http://`, or a bare host. When no explicit `/ws/...` path is * present, `/ws/status` is appended (https → wss, http → ws). */ url?: string; /** Helia mode: an SDN Helia node from `createHeliaSDNNode`. */ helia?: HeliaSDNNode; /** Helia mode: reassembly interval in ms (default 5000). */ refreshIntervalMs?: number; /** Remote mode: reconnect backoff base in ms (default 500). */ backoffBaseMs?: number; /** Remote mode: reconnect backoff cap in ms (default 30000). */ backoffCapMs?: number; /** * WebSocket implementation. Defaults to `globalThis.WebSocket`. Provide for * Node without a global WebSocket, or a mock for tests. */ WebSocket?: WebSocketCtor; /** * Helia mode: enable opportunistic geo enrichment (one short-lived fetch of a * reachable remote `/ws/status` per bootstrap node). Default `true`. */ geo?: boolean; /** Called with non-fatal errors (fail-open). */ onError?: (error: unknown) => void; } /** Backoff tuning for reconnect delay computation. */ export interface BackoffOptions { baseMs: number; capMs: number; /** Jitter as a fraction (0..1) of the delay, added randomly. Default 0.3. */ jitter?: number; } /** * Compute a capped exponential backoff delay with jitter. Pure and * deterministic for a given `rng`, so reconnect timing is unit-testable. * * @param attempt zero-based reconnect attempt count */ export declare function computeBackoffDelay(attempt: number, options: BackoffOptions, rng?: () => number): number; /** * Normalize a status feed URL to a `ws`/`wss` URL ending in a `/ws/...` path. * * - `wss://host` / `ws://host` → adds `/ws/status` when no path is present * - `https://host` → `wss://host/ws/status` * - `http://host` → `ws://host/ws/status` * - `host` → `wss://host/ws/status` */ export declare function deriveStatusWsUrl(input: string): string; /** * Open a status feed, resolve the first decoded frame, then close. Rejects on * timeout, socket error, or close-before-frame. Exported for reuse and testing. */ export declare function fetchNodeStatusOnce(url: string, webSocketCtor?: WebSocketCtor, timeoutMs?: number): Promise; /** * Create a node status client. Supply `url` for remote mode (a node's * `/ws/status` feed) or `helia` for local client-side assembly. When both are * given, remote mode wins. */ export declare function createNodeStatusClient(options: NodeStatusClientOptions): NodeStatusClient; //# sourceMappingURL=client.d.ts.map