import { Duplex } from 'node:stream';
declare const ByteStreamInfo: unique symbol;
interface IByteStreamInfo {
    receivers: Map<number, SrpcByteStream>;
    senders: Map<number, SrpcByteStream>;
    nextId: number;
    step: number;
    pendingReceivers?: Map<number, IPendingReceiver>;
    pendingReceiverBytes: number;
    pendingReceiverChunkBytes: number;
    terminalSenders: Map<number, number>;
}
interface IPendingReceiver {
    chunks: Buffer[];
    bytes: number;
    errorBytes: number;
    finished: boolean;
    destroyed: boolean;
    destroyedError?: Error;
    timeout?: ReturnType<typeof setTimeout>;
}
export interface IByteStream {
    [ByteStreamInfo]?: IByteStreamInfo;
    write(streamId: number, data: unknown): boolean | void | Promise<boolean | void>;
    finish(streamId: number): boolean | void | Promise<boolean | void>;
    destroy(streamId: number, err?: unknown): boolean | void | Promise<boolean | void>;
    attachDisconnectHandler(handler: () => void): void;
    detachDisconnectHandler(handler: () => void): void;
    getBufferedAmount(): number;
    parentStreamId: string;
    allocateSenderId?(): number;
    attachReceiver?(streamId: number): void | Promise<void>;
    announceSender?(streamId: number): void;
    receiverBufferChanged?(streamId: number, bufferedBytes: number): void;
    /** Emits transport-owned byte-stream diagnostics when enabled by the owner. */
    logDebug?(message: string, data?: Record<string, unknown>): void;
    /** Parity owned by senders on the remote endpoint. */
    remoteSenderIdParity?: 0 | 1;
}
export interface IByteStreamable {
    byteStream: IByteStream;
    /** Resolve a context-pinned transport, or reject a stale async context. */
    resolveByteStream?(): IByteStream;
}
export declare function byteStreamDestroyReason(error: unknown): string | undefined;
export declare class SrpcByteStream extends Duplex {
    private readonly _id;
    /** The transport generation this substream was created against. */
    private readonly transport;
    private readonly isSender;
    private cleaned;
    private remotelyDestroyed;
    private remoteFinished;
    private localFinished;
    get id(): number;
    constructor(stream: IByteStreamable, id?: number);
    static init(stream: IByteStreamable, options: {
        startId: number;
        step: number;
    }): void;
    static createReceiver(stream: IByteStreamable, id: number): SrpcByteStream;
    static createSender(stream: IByteStreamable): SrpcByteStream;
    static reserveSenderIds(stream: IByteStreamable, count: number): number[];
    static hasReceiver(stream: IByteStreamable, id: number): boolean;
    static hasSender(stream: IByteStreamable, id: number): boolean;
    static hasTerminalSender(stream: IByteStreamable, id: number): boolean;
    static consumeTerminalSender(stream: IByteStreamable, id: number): boolean;
    static getReceiverBufferedBytes(stream: IByteStreamable, id: number): number;
    static writeReceiver(stream: IByteStreamable, id: number, data: unknown): boolean;
    static abortReceiver(stream: IByteStreamable, id: number, error?: unknown): void;
    static finishReceiver(stream: IByteStreamable, id: number): void;
    static destroySubstream(stream: IByteStreamable, id: number, err?: string): void;
    _read(): void;
    read(size?: number): any;
    _write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
    _final(callback: (error?: Error | null) => void): void;
    _destroy(error: Error | null, callback: (error?: Error | null) => void): void;
    private flushPendingReceiver;
    private readonly handleDisconnect;
    private cleanup;
    private notifyReceiverBufferChanged;
    private static ensureInfo;
    private static ensureTransportInfo;
}
export {};
//# sourceMappingURL=SrpcByteStream.d.ts.map