import type { Broker, RemoteRouter, PeerInfo } from "./broker.js"; import { type Envelope } from "./envelope.js"; import type { PiForwardClient } from "../transport/pi_forward_client.js"; /** A sibling peer as carried on the wire in `peers_update.peers_detailed`: * the sibling's LOCAL `(cwd, name, address)` — no `pc`/prefix (the receiver * fills `pc` from the verified sibling label). */ export interface WirePeerInfo { cwd: string; name: string; address: string; } export interface RemotePeerEntry { /** The sibling's local peers (unprefixed `(cwd, name, address)`). */ infos: WirePeerInfo[]; pcPubkey: string; ts: number; } interface SiblingInfo { pcLabel: string; pcPubkey: string; } export interface BrokerRemoteOptions { broker: Broker; pi: PiForwardClient; selfPcLabel: string; selfPcPubkey: string; /** Initial siblings (Pis-irmãos of the same Owner). May be extended later. */ siblings?: SiblingInfo[]; /** TTL override (testing). */ cacheTtlMs?: number; /** Logger (defaults to console.error). */ log?: (msg: string) => void; } export declare class BrokerRemote implements RemoteRouter { private readonly broker; private readonly pi; private readonly selfPcLabel; private readonly selfPcPubkey; private readonly cacheTtlMs; private readonly log; /** Siblings: pc_label → pc_pubkey. Authoritative for anti-spoof. */ private readonly siblingByLabel; /** Reverse index built from siblings: pc_pubkey → pc_label. */ private readonly siblingByPubkey; /** Cache of peers per remote pc_label. */ private readonly remotePeers; /** In-flight `peers_request` calls, keyed by pc_label. */ private readonly pendingFills; private readonly onIncoming; private detached; constructor(opts: BrokerRemoteOptions); /** Bootstrap: announce ourselves AND ask every sibling for their peers. * Single helper so `_addSibling` can reuse half of it when a new * sibling appears via `setSiblings`. */ private _bootstrapWithSiblings; /** Fresh local inventory for a `peers_update` push, read straight from the * broker (authoritative + sync — no stale cache, drive-letter-safe: the * broker knows its real local peers, no `:`-heuristic). Always carries BOTH * `peers` (addresses, back-compat for Fase-1-only siblings) and the * structured `peers_detailed` (plan/38 Fase 2). */ private _localPeersBody; detach(): void; /** Replace or extend the sibling set. Idempotent on identical input. * Removes any sibling missing from `next`. Plan/25 Wave B bootstrap: * fires `peers_request` at any sibling that wasn't in the previous * set so the cache warms up without waiting for their next push. */ setSiblings(next: SiblingInfo[]): void; private _addSibling; /** Structured cached peers for a remote pc_label (the sibling's local * `(cwd,name,address)`), or [] when unknown / expired. */ private _remoteInfos; /** Returns the cached peer ADDRESSES for a remote pc_label (the sibling's * local, unprefixed addresses), or [] when unknown / expired. */ getRemotePeers(pcLabel: string): string[]; /** Returns the full cross-PC inventory: pc_label → addresses (TTL-respected). */ getAllRemote(): Record; /** Aggregated remote peer addresses (`:@`) for the broker's * `list_peers` `peers` field. Skips siblings with no cache entry. */ listRemotePeers(): string[]; /** Structured remote roster (plan/38 Fase 2): one `PeerInfo` per cross-PC * peer with `pc` = sibling label, `cwd`/`name` from the sibling's inventory, * and `address` prefixed `:@`. Powers `peers_detailed`. */ listRemotePeerInfos(): PeerInfo[]; /** * Called whenever the local UDS broker's peer set changes * (peer_joined/peer_left). We push a `peers_update` envelope to every * sibling so their caches stay fresh without polling. */ onLocalPeersChanged(_peers: string[]): void; /** * Broker hook (plan/25 Wave C). Inspect `env.to` for a `:` prefix: * * - no prefix or prefix == selfPcLabel → return false (broker delivers * locally; if same-self prefix is present we DON'T strip it here — * the local resolver will treat it as a literal name, which works * because local names don't carry colons in practice) * - prefix === known sibling label → rewrite `env.from`, pack onto the * relay, return true. May trigger a lazy `peers_request` when the * cache is empty (returns false on hard cache miss so the broker * surfaces a transport_error path; we always optimistically send, * and ACK timeout in the sender ends up reporting the failure). * - prefix is not a known sibling label → return false (backward-compat * for hypothetical local names containing `:`) */ tryRouteOutbound(env: Envelope): boolean; /** * Entry point for envelopes the relay forwards to us. Receives the * envelope verbatim plus the verified `from_pc` (Pi-pubkey of the * sender, authoritative — relay-checked). */ handleIncoming(env: Envelope, fromPc: string): void; private _setRemoteCache; private _awaitPeersFill; private _propagateTransportError; private _sendControlEnvelope; private _labelForPubkey; } /** * Parse a `:` address. Returns null when the input doesn't * carry a `:`. Note: callers are responsible for deciding whether the * parsed `pcLabel` is meaningful (i.e., matches selfPcLabel or a known * sibling); a non-null return here does NOT imply the address is remote. * The broker's prefix routing uses this — local names containing literal * `:` continue working as long as no sibling carries the same prefix. */ export declare function parseAddress(to: string): { pcLabel: string; peerName: string; } | null; export {};