import { EventEmitter } from "node:events"; import type { KeyPair } from "../crypto/keypair.js"; import type { NetworkNode } from "../types/peer.js"; export type TcpRelayPoolOptions = { relays: NetworkNode[]; selfKeyPair: KeyPair; maxConnections?: number; /** Optional debug label inherited by underlying TcpRelayClients. */ label?: string; }; export type TcpRelayPoolEvents = { /** A friend is now online on at least one relay. */ friendOnline: (friendPublicKey: Uint8Array) => void; /** A friend is no longer online on any relay. */ friendOffline: (friendPublicKey: Uint8Array) => void; /** Inbound DATA forwarded by some relay. */ peerData: (friendPublicKey: Uint8Array, payload: Uint8Array) => void; /** Inbound OOB_RECV (used for friend requests via TCP). */ oob: (senderPublicKey: Uint8Array, payload: Uint8Array) => void; /** Inbound onion response routed back through a relay (announce / onion data). */ onionResponse: (packet: Uint8Array) => void; /** Number of currently-connected relays changed (for diagnostics). */ status: (connected: number, total: number) => void; }; export declare class TcpRelayPool extends EventEmitter { #private; constructor(opts: TcpRelayPoolOptions); /** * Initialize the pool. Selects up to `maxConnections` relays from the * supplied list (picks them in order; the operator can prioritize by * sorting). Returns the count of initial connections successfully * opened. */ start(): Promise; /** Tear down all relay connections. */ stop(): Promise; /** * Dynamically add a TCP relay to the pool — used when a friend's * DHT-PK extras advertise a relay address we weren't already on. * Without this, two peers on disjoint relay sets can never establish * a TCP path even if both relays are reachable. Idempotent: skips if * the host:port pair is already in the pool. * * Returns the index of the relay (existing or newly added). */ addRelay(node: NetworkNode): number; /** * Ask every connected relay to route packets for this friend. Idempotent; * subsequent calls for an already-requested key are no-ops on each * underlying client. */ requestRoute(friendPublicKey: Uint8Array): void; /** True if at least one relay reports this friend currently online. */ isFriendOnline(friendPublicKey: Uint8Array): boolean; /** * OOB_SEND — fire-and-forget delivery to any peer connected to any of * our relays, bypassing routing. Used for the initial cookie request * / cookie response / crypto handshake exchange before either side * has issued ROUTING_REQUEST. Mirrors toxcore's tcp_send_oob_packet * which net_crypto.c calls via send_oob_packet for the same purpose. * Returns the count of relays the OOB packet was written to. */ sendOobToFriend(friendPublicKey: Uint8Array, payload: Uint8Array): number; /** * Forward a DATA payload to a friend through any relay where they're * online. Returns the count of relays that accepted the write — 0 if * the friend isn't online on any TCP relay. */ sendToFriend(friendPublicKey: Uint8Array, payload: Uint8Array, droppable?: boolean): number; /** Diagnostics. */ connectedCount(): number; /** * Send an onion request (createOnionRequest0Tcp packet) through up to `fanout` * connected relays. Each relay forwards it to node B over UDP and routes the * onion response back over TCP (surfaced via the pool's "onionResponse" * event). Returns the number of relays the request was handed to (0 = none * connected). Fanning out across a few relays covers the case where one relay * can't reach node B. */ sendOnionRequest(packet: Uint8Array, fanout?: number): number; /** * Snapshot of currently-connected relays for inclusion in DHT-PK * announce extras. Mirrors toxcore's `tcp_copy_connected_relays`. * Returns up to `max` entries, each with the relay's public key and * its host:port — enough for the receiver to add the relay to its * own pool via TcpRelayPool.addRelay and start routing through it. */ connectedRelays(max?: number): Array<{ host: string; port: number; serverPublicKey: Uint8Array; }>; on(event: E, listener: TcpRelayPoolEvents[E]): this; once(event: E, listener: TcpRelayPoolEvents[E]): this; off(event: E, listener: TcpRelayPoolEvents[E]): this; }