/** * Minimal ICE-lite agent: gather candidates, exchange via an external * signaling channel (Carrier friend-message), connectivity-check each * (local, remote) pair, pick the highest-priority working pair as the * data path, keepalive, re-run on failure. * * This is NOT full ICE: * - No controlling/controlled negotiation (both sides probe equally). * - No aggressive nomination, no Trickle phases. * - No TCP candidates. * * Just enough to upgrade a Carrier friend session from "tcp-relay only" * to "UDP-direct or TURN-relayed", whichever works. */ import { type Socket as DgramSocket } from "dgram"; import { AddressValue } from "./stun.js"; export type CandidateKind = "host" | "srflx" | "relay"; export interface Candidate { kind: CandidateKind; address: string; port: number; /** Higher beats lower. Convention: host=10000, srflx=5000, relay=1000. */ priority: number; } export interface CandidateOffer { candidates: Candidate[]; ufrag: string; password: string; generation: number; } interface BootnodeRef { host: string; publicKey: Uint8Array; } interface SignalingHandle { send(offer: CandidateOffer): void; onOffer(cb: (offer: CandidateOffer) => void): void; } export interface IceAgentOpts { /** * The peer's UDP socket. ICE shares it so that once a pair wins, the * caller can use the same socket for data traffic — bypassing any * extra demultiplexing. */ sock: DgramSocket; /** Bootnodes we can use as STUN servers. ≥2 → can detect symmetric NAT. */ stunBootnodes: BootnodeRef[]; /** Bootnodes we can use as TURN servers (usually the same list). */ turnBootnodes: BootnodeRef[]; /** Our Carrier identity, used for TURN credential derivation. */ ourUserid: string; ourSecretKey: Uint8Array; /** How we tell the remote peer our candidates. */ signaling: SignalingHandle; /** Called when ICE picks a winning pair. May be called again on re-run. */ onSelected: (pair: { local: Candidate; remote: Candidate; }) => void; /** Called for raw data received via the TURN relay (DATA-INDICATION). */ onRelayedData?: (peer: AddressValue, data: Uint8Array) => void; } export declare class IceLiteAgent { #private; constructor(opts: IceAgentOpts); /** Gather local candidates and ship them via signaling. Idempotent-ish. */ start(): Promise; close(): void; } export {};