import type { ByteSource } from './types.ts';
export declare const MEMORY_LIMIT: number;
export declare const IO_BUFFER_SIZE: number;
export interface SpoolStore {
    write(offset: number, data: Uint8Array): Promise<void>;
    read(offset: number, size: number): Promise<Uint8Array>;
    close(): Promise<void>;
    body?(kind: 'fetch' | 'sdk'): Promise<Blob | AsyncIterable<Uint8Array>>;
}
export type SpoolFactory = () => Promise<SpoolStore>;
/** Install the execution host's private scratch storage. */
export declare function setSpoolFactory(value: SpoolFactory | null): void;
/**
 * Retain replayable bytes, spilling through the host's scratch storage. An
 * append that fails leaves no telling which of its bytes were kept, so every
 * call after it fails too, rather than read bytes from where the append never
 * put them. Bytes count once the spool holds them, before they flush, as in
 * Python, where a cancelled append keeps the spool usable. Bytes waiting for
 * the store go at the offset they end up at, so a flush that failed writes
 * them there again rather than after what it got through. A reader that `hold`s
 * the spool keeps it open: a `close` while it is held takes effect at the last
 * `unhold`.
 */
export declare class ByteSpool {
    readonly memoryLimit: number;
    size: number;
    closed: boolean;
    private memory;
    private store;
    private lost;
    private pendingSize;
    private stored;
    private holders;
    private closing;
    private cache;
    private cacheOffset;
    private turn;
    constructor(memoryLimit?: number);
    /** Run `fn` once every call before it has settled, as Python's lock holds them. */
    private locked;
    append(data: Uint8Array): Promise<void>;
    /** Overwrite an existing window without changing the spool length. */
    write(offset: number, data: Uint8Array): Promise<void>;
    private usable;
    private appendNow;
    private flush;
    fill(source: ByteSource): Promise<void>;
    read(offset: number, size: number): Promise<Uint8Array>;
    private readNow;
    /**
     * The spool's bytes from `offset`, `piece` bytes at a time: a bounded reader
     * keeps `CHUNK_SIZE`, a writer of the whole spool takes `IO_BUFFER_SIZE`,
     * one store read per step.
     */
    stream(offset?: number, size?: number, piece?: number): AsyncGenerator<Uint8Array>;
    output(): Promise<ByteSource>;
    body(kind: 'fetch' | 'sdk'): Promise<Uint8Array | Blob | AsyncIterable<Uint8Array>>;
    /** Keep the spool open until `unhold`, for a reader that took windows of it. */
    hold(): void;
    /** Let go of a `hold`; the last one runs a `close` it held off. */
    unhold(): Promise<void>;
    close(): Promise<void>;
    private closeNow;
}
/**
 * Hold `source` in a spool: its bytes when they fit in memory, a stream that
 * owns the spool past that, null when it is empty. Mirrors Python's spooled.
 */
export declare function spooled(source: ByteSource | null): Promise<ByteSource | null>;
/**
 * `spooled` over both outputs of a run; when one fails, what the other holds
 * is closed. Mirrors Python's spooled_pair.
 */
export declare function spooledPair(stdout: ByteSource | null, stderr: ByteSource | null): Promise<[ByteSource | null, ByteSource | null]>;
/** A window of a spool, sized and sliced as the bytes it stands for. */
export declare class ByteSlice {
    readonly source: ByteSpool;
    readonly offset: number;
    readonly size: number;
    constructor(source: ByteSpool, offset: number, size: number);
    get byteLength(): number;
    /** As `Uint8Array.subarray`, for the nonnegative bounds a buffer slices by. */
    subarray(start?: number, end?: number): ByteSlice;
    stream(): AsyncGenerator<Uint8Array>;
}
//# sourceMappingURL=spool.d.ts.map