/** * OpenKernel — Peer Mesh * * Tracks peers, keeps them alive with heartbeats, and (for peers we manage) * holds an open SSE stream to receive their activity + telemetry. On heartbeat * failure a peer is marked down and its stream reconnected — the self-healing * that replaces a hand-rolled session scheduler. * * Connection direction honours the security model: WE open streams to peers we * manage (satellites are accept-only). A satellite never dials us. */ import type { Logger } from '../types.js'; import type { FederationEnvelope, NodeIdentity, PeerInfo, StreamFrame, UpdateAnnounce } from './types.js'; import { MeshClient } from './transport-http.js'; export interface PeerMeshOptions { self: NodeIdentity; client: MeshClient; logger: Logger; heartbeatMs?: number; /** Frames streamed from a managed peer (activity, telemetry, heartbeat). */ onFrame: (peerId: string, frame: StreamFrame) => void; /** Called whenever the peer set or a peer's connected state changes. */ onPeerChange?: () => void; /** Current local load 0–100, sent with heartbeats. */ getLoad: () => number; /** Our own mesh port — advertised in heartbeats so hubs can dial us back. */ selfPort?: number; } export declare class PeerMesh { private opts; private peers; private streams; private timer?; private readonly hbMs; constructor(opts: PeerMeshOptions); list(): PeerInfo[]; get(nodeId: string): PeerInfo | undefined; connected(): PeerInfo[]; /** Discover + attach a peer at a base URL (manifest probe + open its stream). */ connect(url: string): Promise; /** Send a hub/relay version announcement to every currently connected peer. */ announceUpdate(announce: UpdateAnnounce): Promise; private openStream; start(): void; private tick; /** Upsert a peer we learned about via handshake (e.g. inbound hello). */ note(env: FederationEnvelope, url?: string): void; remove(nodeId: string): void; stop(): void; }