/** * Minimal TURN client (RFC 5766 subset) for the Carrier bootnode TURN * servers running on UDP/3478. Covers: * * - ALLOCATE (with the long-term cred dance: 401 → echo realm/nonce → success) * - REFRESH (keeps the allocation alive past `lifetime`) * - CREATE-PERMISSION (one per peer address we want to send to) * - SEND-INDICATION (wraps app data going out via the relay) * - DATA-INDICATION (unwraps app data coming in via the relay) * * Deliberately skipped to keep this small: * - ChannelBind / ChannelData framing — minor bandwidth win, more state * - TCP TURN, TURN-over-TLS * - DontFragment, Even-port, reservation tokens * * Owns its UDP socket exclusively while a request is in flight. The * caller can multiplex by using a separate TurnClient per allocation * (one per bootnode), which is what ICE will do. */ import type { Socket as DgramSocket } from "dgram"; import { AddressValue, buildBindingRequest } from "./stun.js"; import type { CarrierTurnCreds } from "./turn-creds.js"; export interface TurnAllocation { relayedAddress: AddressValue; mappedAddress?: AddressValue; lifetime: number; } type DataHandler = (peer: AddressValue, data: Uint8Array) => void; export declare class TurnClient { #private; readonly creds: CarrierTurnCreds; constructor(opts: { sock: DgramSocket; creds: CarrierTurnCreds; }); /** * Perform the long-term-credential ALLOCATE dance. Returns the * server-reflexive (mapped) and relay-allocated addresses, plus the * allocation lifetime. */ allocate(): Promise; /** * Tell the TURN server we want to send to / receive from `peer`. * Required before SEND-INDICATION will actually relay. */ createPermission(peer: AddressValue): Promise; /** * Wrap `data` in a SEND-INDICATION and ship it to the TURN server. * Fire-and-forget — TURN indications never get a response. */ sendTo(peer: AddressValue, data: Uint8Array): void; onData(cb: DataHandler): void; refresh(): Promise; close(): void; } export { buildBindingRequest };