/**
 * Per-peer sender-side retention buffer for fragmented message bytes,
 * used to satisfy NACK retransmits from the peer's {@link FragmentAssembler}.
 *
 * Lifecycle:
 *   1. {@link retain} — called on each fragmented send; copies the source
 *      bytes into the retention so they're available to retransmit. If
 *      the per-peer slot cap is hit, the oldest retained entry is FIFO-
 *      evicted.
 *   2. {@link consume_nack} — looks up retained bytes for a NACK target
 *      and bumps the retry counter. Returns `null` if the entry is gone
 *      (aged out, evicted, or out of retry budget — in which case the
 *      entry is dropped here too).
 *   3. {@link service} — call once per tick to age out entries older
 *      than `max_age_ms`.
 *   4. {@link clear} — drop everything; call on peer disconnect.
 *
 * Memory cost: each retained entry holds a fresh copy of its source
 * payload (the upstream send buffer is a reused scratch). With the
 * default 16 slots × up-to-64 KiB cap on the receiver, worst case is
 * 1 MiB per peer; steady-state is empty because steady traffic fits in
 * one packet and bypasses fragmentation.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2025
 */
export class FragmentRetention {
    /**
     * @param {{
     *   max_messages?: number,
     *   max_age_ms?: number,
     *   max_retries?: number,
     * }} [options]
     *   `max_messages` caps simultaneously-retained messages; oldest is
     *   FIFO-evicted on overflow. `max_age_ms` is the per-entry TTL.
     *   `max_retries` caps how many NACK retransmit rounds a single
     *   retained message can satisfy before being dropped.
     */
    constructor({ max_messages, max_age_ms, max_retries, }?: {
        max_messages?: number;
        max_age_ms?: number;
        max_retries?: number;
    });
    /** @type {number} @readonly */
    readonly max_messages: number;
    /** @type {number} @readonly */
    readonly max_age_ms: number;
    /** @type {number} @readonly */
    readonly max_retries: number;
    /**
     * Copy `payload[0..length)` into retention under `message_id`.
     * Evicts the oldest retained entry if `max_messages` is exceeded.
     *
     * If a retained entry already exists for `message_id` (only legitimate
     * cause: uint16 wrap), the old entry is dropped first so the FIFO
     * position and retry budget restart from the new send.
     *
     * @param {number} message_id
     * @param {Uint8Array} payload  source bytes (caller may overwrite after return)
     * @param {number} length       number of bytes from `payload[0]` to copy
     * @param {number} now_ms       monotonic timestamp for age-out
     */
    retain(message_id: number, payload: Uint8Array, length: number, now_ms: number): void;
    /**
     * Mark a NACK round for `message_id` and return the retained entry
     * so the caller can re-emit the missing chunks. Returns `null` if
     * no entry exists, or if the per-message retry budget is now
     * exhausted (in which case the entry is dropped).
     *
     * @param {number} message_id
     * @returns {{payload: Uint8Array, length: number}|null}
     */
    consume_nack(message_id: number): {
        payload: Uint8Array;
        length: number;
    } | null;
    /**
     * Per-tick maintenance: evict any entry older than `max_age_ms`.
     *
     * The FIFO is in strict insertion order, so we can stop at the first
     * still-fresh entry rather than scanning the whole map.
     *
     * @param {number} now_ms
     */
    service(now_ms: number): void;
    /**
     * Number of currently-retained messages.
     * @returns {number}
     */
    size(): number;
    /**
     * Whether `message_id` is currently retained.
     * @param {number} message_id
     * @returns {boolean}
     */
    has(message_id: number): boolean;
    /**
     * Drop every retained entry. Use on peer disconnect.
     */
    clear(): void;
    #private;
}
//# sourceMappingURL=FragmentRetention.d.ts.map