/**
 * PresenceClient — the signalling channel.
 *
 * A single WebSocket to the Audin presence endpoint over which the operator:
 *   - announces availability on a set of phone numbers (`set_available`),
 *   - keeps the connection alive (`ping` heartbeat),
 *   - answers / declines inbound offers (`accept` / `reject`),
 *   - starts outbound calls (`start_outbound`).
 *
 * and over which the server pushes: `connected`, `available_set`,
 * `incoming_call`, `call_taken`, `call_assigned`, `outbound_started`, `pong`,
 * `error`.
 *
 * Resilience built in here so the higher-level `AudinOperator` doesn't have to:
 *   - HEARTBEAT: a `ping` every `heartbeatIntervalMs`; the server reaps idle
 *     connections at ~90s.
 *   - RECONNECT: on unexpected close, walk a backoff schedule, fetch a FRESH
 *     token via `getToken` (the old one may have expired), reconnect, and
 *     re-send the last `set_available` so the operator comes back online
 *     automatically.
 *
 * This class is transport-only: it parses/dispatches messages and owns the
 * socket lifecycle. It holds NO call state and names NO providers.
 */
import type { OperatorLogger } from "./types.js";
/** A server→client message. Loosely typed; the handler narrows on `type`. */
export interface PresenceServerMessage {
    type: string;
    [key: string]: unknown;
}
export interface PresenceClientOptions {
    /** Base WS URL WITHOUT query, e.g. `wss://host/operator-presence/ws`. */
    presenceWsUrl: string;
    /**
     * Resolve a valid session token (cached & shared with REST/audio). Returns
     * the raw JWT string. Should re-mint internally once expired.
     */
    ensureToken: () => Promise<string>;
    /**
     * Drop the cached token so the next {@link ensureToken} re-mints. Invoked on
     * an auth-related socket close so a reconnect uses a fresh token.
     */
    invalidateToken: () => void;
    heartbeatIntervalMs: number;
    reconnectBackoffMs: number[];
    logger: OperatorLogger;
    /** Invoked for every parsed server message. */
    onMessage: (msg: PresenceServerMessage) => void;
    /** Connection lifecycle for the higher layer (state, errors). */
    onOpen: () => void;
    onReconnecting: () => void;
    onError: (code: string, message: string, cause?: unknown) => void;
}
export declare class PresenceClient {
    private readonly opts;
    private ws;
    private heartbeatTimer;
    private reconnectTimer;
    private reconnectAttempt;
    /** True between `connect()` and `disconnect()` — gates auto-reconnect. */
    private desiredOnline;
    /** Last availability we announced, replayed after a reconnect. */
    private lastAvailability;
    constructor(opts: PresenceClientOptions);
    /** Open the presence socket and keep it open (auto-reconnecting). */
    connect(): Promise<void>;
    /**
     * Close the socket and stop reconnecting. Best-effort `set_unavailable`
     * first so the server drops presence immediately rather than waiting for the
     * reaper.
     */
    disconnect(): void;
    /** Announce availability on `phoneNumberIds`; remembered for reconnects. */
    setAvailable(phoneNumberIds: string[]): void;
    /** Drop availability (stays connected). */
    setUnavailable(): void;
    /** Answer an inbound offer. */
    accept(callSid: string): void;
    /** Decline an inbound offer. */
    reject(callSid: string): void;
    /** Request an outbound call. The server replies with `outbound_started`. */
    startOutbound(to: string, callerId: string): void;
    /** Whether the socket is currently open. */
    get isOpen(): boolean;
    private openOnce;
    private scheduleReconnect;
    private startHeartbeat;
    private stopHeartbeat;
    private clearTimers;
    private sendRaw;
}
