import { type KvPair } from './moqt.js';
import { type WireDropConfig, type WireHoldConfig } from './network_simulator.js';
/**
 * MoQ → QUIC object mapping. Values are the on-the-wire identifiers used by the
 * low-level protocol (see MOQ_MAPPING_* in ./moqt.ts) and must stay in sync.
 */
export declare enum MoqMapping {
    ObjectPerDatagram = "ObjPerDatagram",
    SubgroupPerGroup = "SubGroupPerObj"
}
export type ObjStatus = 'queued' | 'sent' | 'aborted' | 'dropped';
export interface ObjInfo {
    objId: number;
    groupId: number;
    status: ObjStatus;
}
/** Options for starting a new group, passed to `Track.sendObject`. */
export interface NewGroupOptions {
    priority: number;
}
/**
 * Caller-assigned (group, object) ids for `Track.sendObject`. Lets several
 * tracks (e.g. the same track published to a main and a backup relay) put the
 * very same object ids on the wire, whatever each one drops.
 */
export interface ObjectIds {
    groupId: number;
    objId: number;
}
/**
 * What one finished wire unit cost: a subgroup stream (its whole group) under
 * the subgroup mapping, or a single datagram object under the datagram one.
 * Counted from the bytes actually written, so it excludes anything the send
 * queue, the open-stream cap or a drop simulator skipped.
 */
export interface SubgroupBytes {
    groupId: number;
    objects: number;
    payloadBytes: number;
    signalingBytes: number;
}
export interface TrackInfo {
    namespace: string[];
    name: string;
    trackAlias: number;
    moqMapping: MoqMapping;
    numSubscribers: number;
    numQueued: number;
    numOpenStreams: number;
    currentGroup: number;
    currentObject: number;
    lastSubgroup: SubgroupBytes | undefined;
}
export interface MoqInitOptions {
    serverCertificateHash?: Uint8Array | null;
    alpnVersion?: string;
}
/**
 * Called for every object received on a subscription. It is handed the raw
 * payload reader (a `ReadableStream` positioned at the object payload), the
 * object extension headers, the payload length (`undefined` means "read to the
 * end of the datagram"), and the MoQ transport-native group/object ids for this
 * object. It returns whether this was the last object (end of stream). Media
 * decoding lives in the caller, keeping `Moq` media-free.
 *
 * `groupId`/`objectId` are the MoQ ordering keys. For subgroup streams `objectId`
 * is the receiver-counted arrival index within the group (the wire object-id
 * delta is always 0 in this mapping); for datagrams it is the wire object id.
 *
 * `isLastInGroup` is true when the object carries the end-of-group signal inline,
 * i.e. datagrams (one object per group, end-of-group bit on the object). Subgroup
 * streams signal end-of-group retroactively instead (see `EndOfGroupCallback`),
 * so this is false for them.
 */
export type ObjectCallback = (reader: ReadableStream<Uint8Array>, extensionHeaders: KvPair[], length?: number, groupId?: number, objectId?: number, isLastInGroup?: boolean) => Promise<boolean> | boolean;
/**
 * Called when the transport learns retroactively that a group is complete,
 * carrying the group id and the object id of its final object. Used for subgroup
 * streams, where end-of-group is a MOQ_OBJ_STATUS_END_OF_GROUP status object that
 * trails the group's last payload object -- so it cannot ride on that object and
 * is delivered out of band. Datagrams carry end-of-group inline on the object
 * instead (see `ObjectCallback`'s `isLastInGroup`).
 */
export type EndOfGroupCallback = (groupId: number, lastObjId: number) => void;
export interface SubscriptionInfo {
    namespace: string[];
    name: string;
    subscribeRequestId: number;
    trackAlias: number;
}
/**
 * Keep-alive loop options. When passed to `Moq.setup`, the session periodically
 * sends a keep-alive PUBLISH while idle (no object sent within `everyMs`).
 * `namespace`/`name` default to 'keepAlive' and a random name.
 */
export interface KeepAliveOptions {
    everyMs: number;
    namespace?: string;
    name?: string;
}
/**
 * A track offered under a published namespace (`Moq.publishNamespace` +
 * `Moq.offerTrack`). Unlike `addTrack` (which proactively PUBLISHes a track),
 * an offered track is served lazily: the `Track` is created only when a peer
 * sends a matching SUBSCRIBE, at which point `onSubscribed` fires with the live
 * `Track` handle. `onUnsubscribed` fires when that subscription ends.
 */
export interface TrackOffer {
    namespace: string[];
    name: string;
    maxQueuedObjects: number;
    maxOpenStreams: number;
    moqMapping: MoqMapping;
    authInfo?: string;
    onSubscribed?: (track: Track) => void;
    onUnsubscribed?: (track: Track) => void;
}
interface Subscriber {
    subscriptionRequestId: number;
    forward: number;
    parameters: KvPair[];
}
/**
 * Handle for one object handed to `Track.sendObject`. Lets the caller observe
 * delivery (`getInfo`) and cancel an object that has not been written yet
 * (`abort`).
 */
export declare class ObjData {
    groupId: number;
    objId: number;
    status: ObjStatus;
    readonly priority: number;
    readonly data: BufferSource | undefined;
    readonly newGroup: boolean;
    readonly extensionHeaders: KvPair[];
    readonly callback?: (obj: ObjData) => void;
    private track;
    constructor(track: Track, groupId: number, objId: number, status: ObjStatus, priority: number, data?: BufferSource, newGroup?: boolean, extensionHeaders?: KvPair[], callback?: (obj: ObjData) => void);
    /** Synchronous snapshot: object id, group id and current status. */
    getInfo(): ObjInfo;
    /** Drop this object from the queue if it has not been written yet. */
    abort(): void;
}
/**
 * A published track. Created via `Moq.addTrack`. Carries the per-track send
 * queue, group/object sequencing, open subgroup stream, and subscriber list.
 */
export declare class Track {
    readonly namespace: string[];
    readonly name: string;
    readonly trackAlias: number;
    readonly publisherRequestId: number;
    readonly authInfo: string | undefined;
    readonly maxQueuedObjects: number;
    readonly maxOpenStreams: number;
    readonly moqMapping: MoqMapping;
    subscribers: Subscriber[];
    private moq;
    private publishStream;
    private queue;
    private draining;
    private closed;
    private forwarding;
    private resumeNeedsNewGroup;
    private firstObjectSent;
    private currentGroupSeq;
    private currentObjectSeq;
    private currentGroupPriority;
    private openStreams;
    private groupLastObj;
    private openStreamCount;
    private skipDeltasUntilNewGroup;
    private groupBytes;
    private lastSubgroupBytes;
    private dropSim;
    private droppedGroupId;
    private holdSim;
    private forcedDropRemaining;
    private forcedHoldRemaining;
    private forcedHoldBuffer;
    onWireDrop?: (obj: ObjData) => void;
    constructor(moq: Moq, namespace: string[], name: string, trackAlias: number, publisherRequestId: number, maxQueuedObjects: number, maxOpenStreams: number, authInfo: string | undefined, moqMapping: MoqMapping, publishStream: WebTransportBidirectionalStream);
    /**
     * Queue an object for delivery. Passing `newGroupOptions` starts a new group
     * (e.g. a video keyframe) with the given publisher priority; omit it to append
     * to the current group. `extensionHeaders` are MoQ object extension headers
     * (e.g. LOC media metadata). `callback` fires once the object is written.
     *
     * Returns an `ObjData` handle. Objects are dropped (status `dropped`) when the
     * subscription is not being forwarded (Forward State 0 / no subscriber), when
     * the pending send queue is already at `maxQueuedObjects`, or (subgroup
     * mapping) when starting a new group would exceed `maxOpenStreams` — in which
     * case the whole group is dropped until a later group finds room.
     *
     * `ids` overrides the track's own sequencing. The track can then not invent a
     * group start, so instead of opening a fresh group (first object, resume after
     * Forward State 0) it drops objects until the caller starts a new group, and it
     * drops the rest of any group whose first object it did not accept.
     */
    sendObject(data: BufferSource | undefined, newGroupOptions?: NewGroupOptions, extensionHeaders?: KvPair[], callback?: (obj: ObjData) => void, ids?: ObjectIds): ObjData;
    /**
     * Enable or disable simulated packet loss on this track's send path. Pass
     * `null` (or an inactive config) to disable. Used only for testing; genuine
     * publication never sets this.
     */
    setWireDropConfig(cfg: WireDropConfig | null): void;
    /**
     * Enable or disable simulated slowness (a stall-then-clump hold) on this
     * track's send path. Pass `null` (or an inactive config) to disable, flushing
     * anything still held. Used only for testing; genuine publication never sets this.
     */
    setWireHoldConfig(cfg: WireHoldConfig | null): void;
    /**
     * Force-drop the next `count` wire units on demand (a manual loss burst), on
     * top of (and independent of) any periodic drop policy. The unit follows the
     * mapping: `count` datagrams, or `count` subgroup streams (groups). Testing only.
     */
    forceDropBurst(count: number): void;
    /**
     * Force-hold the next `count` objects on demand (a manual slowness burst): they
     * are buffered as they arrive (a stall) and released together once the burst is
     * full (a clump), on top of (and independent of) any periodic hold policy.
     * Testing only.
     */
    forceHoldBurst(count: number): void;
    /** Snapshot of the track's identity and live counters. */
    getInfo(): TrackInfo;
    private bytesFor;
    private finishBytes;
    /** Stop the track: drop the queue, close streams, send PUBLISH_DONE. */
    close(): Promise<void>;
    _publishWritable(): WritableStream<Uint8Array>;
    _runResponseLoop(): Promise<void>;
    isForwarding(): boolean;
    _setForwarding(forwarding: boolean): void;
    private resetStreams;
    _addSubscriber(subscriptionRequestId: number, forward: number, parameters: KvPair[]): void;
    _removeSubscribersByRequestId(requestId: number): Subscriber[];
    _lastSent(): {
        group: number | undefined;
        obj: number | undefined;
    };
    _abort(obj: ObjData): void;
    private advanceSequence;
    private adoptSequence;
    private drain;
    private shouldDropOnWire;
    private decideDropUnit;
    private writeObject;
    private closeStream;
}
/**
 * A subscribed track. Created via `Moq.subscribe`. Holds the subscription
 * identity and the per-object callback the receive loops invoke (routed by
 * track alias). Symmetric to `Track` on the publisher side.
 */
export declare class Subscription {
    readonly namespace: string[];
    readonly name: string;
    readonly subscribeRequestId: number;
    readonly trackAlias: number;
    readonly authInfo: string | undefined;
    private onObject;
    private onEndOfGroup;
    private subscribeStream;
    private closed;
    constructor(namespace: string[], name: string, subscribeRequestId: number, trackAlias: number, authInfo: string | undefined, onObject: ObjectCallback, subscribeStream: WebTransportBidirectionalStream, onEndOfGroup?: EndOfGroupCallback);
    /** Snapshot of the subscription's identity. */
    getInfo(): SubscriptionInfo;
    /**
     * Stop the subscription. draft-18 removed the UNSUBSCRIBE message: cancelling
     * the request stream's readable (STOP_SENDING) and closing its writable (FIN)
     * signals the publisher to stop sending objects for this subscription.
     */
    unsubscribe(): Promise<void>;
    _requestWritable(): WritableStream<Uint8Array>;
    _runResponseLoop(): Promise<void>;
    _deliver(reader: ReadableStream<Uint8Array>, extensionHeaders: KvPair[], length?: number, groupId?: number, objectId?: number, isLastInGroup?: boolean): Promise<boolean>;
    _signalEndOfGroup(groupId: number, lastObjId: number): void;
}
export declare enum MoqState {
    Idle = 0,// before init()
    Connecting = 1,// init() called; transport + control stream coming up
    Running = 2,// SETUP handshake done; control loop active
    Closed = 3
}
/**
 * A MoQ publisher session over WebTransport. Owns the transport, the control
 * stream, the inbound control loop (subscriptions), and the set of tracks.
 */
export declare class Moq {
    private moqt;
    private connecting;
    private _state;
    get state(): MoqState;
    private tracks;
    private nextClientReqId;
    private nextAliasValue;
    private keepAliveOpts;
    private keepAliveInterval;
    private lastObjectSentMs;
    private subscriptions;
    private subscriptionsByAlias;
    private incomingLoopsStarted;
    private trackOffers;
    private incomingBidiLoopStarted;
    private peerSetupReceived;
    private resolvePeerSetup;
    /**
     * Open the transport (sync). Connection + control stream creation happen in
     * the background; `setup` and `addTrack` await readiness.
     */
    init(urlHostPort: string, options?: MoqInitOptions): void;
    /** Perform the MoQ SETUP handshake and start the incoming receive loops. */
    setup(keepAliveOpts?: KeepAliveOptions): Promise<void>;
    /**
     * Publish a track. draft-18: open a dedicated bidirectional stream, send
     * PUBLISH on it, and await the peer's REQUEST_OK (or REQUEST_ERROR) read back
     * on that same stream.
     */
    addTrack(namespace: string[], name: string, maxQueuedObjects: number, maxOpenStreams: number, authInfo: string | undefined, moqMapping: MoqMapping): Promise<Track>;
    /**
     * Announce a namespace with a single PUBLISH_NAMESPACE (draft-18 §9.3),
     * instead of one PUBLISH per track. draft-18: open a dedicated bidirectional
     * stream, send PUBLISH_NAMESPACE on it, and await the peer's REQUEST_OK (or
     * REQUEST_ERROR) read back on that same stream.
     *
     * After announcing, register the tracks you are willing to serve with
     * `offerTrack`; each `Track` is then created lazily when a matching SUBSCRIBE
     * arrives from a peer.
     */
    publishNamespace(namespace: string[], authInfo: string | undefined): Promise<void>;
    /**
     * Register a track to serve under a namespace previously announced with
     * `publishNamespace`. The `Track` is created only when a peer SUBSCRIBEs to a
     * matching (namespace, name); `offer.onSubscribed` then fires with the handle.
     */
    offerTrack(offer: TrackOffer): void;
    private drainAnnounceStream;
    /**
     * Subscribe to a track. draft-18: open a dedicated bidirectional stream, send
     * SUBSCRIBE on it, and await SUBSCRIBE_OK read back on the same stream. Objects
     * arrive on separate unidirectional subgroup streams / datagrams, routed to
     * `onObject` by the negotiated track alias. A rejection is retried after
     * `SLEEP_SUBSCRIBE_ERROR_MS` with a fresh request stream. `onEndOfGroup`, if
     * given, fires when each group completes (MoQ end-of-group).
     */
    subscribe(namespace: string[], name: string, authInfo: string | undefined, onObject: ObjectCallback, onEndOfGroup?: EndOfGroupCallback): Promise<Subscription>;
    /** Drop queues, close tracks/subscriptions and the transport (best-effort, async teardown). */
    close(): void;
    private startKeepAlive;
    private stopKeepAlive;
    private maybeSendKeepAlive;
    _wt(): any;
    _markObjectSent(): void;
    private ensureIncomingLoops;
    private ensurePublisherBidiLoop;
    private runPublisherBidiLoop;
    private handlePublisherBidiStream;
    private onIncomingSubscribe;
    private removeTrack;
    private runIncomingUniLoop;
    private handleIncomingUniStream;
    private handlePeerControlStream;
    private receiveSubgroupStream;
    private runDatagramReceiveLoop;
    private controlWriter;
    private allocateClientReqId;
    private allocateTrackAlias;
}
export {};
//# sourceMappingURL=moq.d.ts.map