import type { Accessor } from '../../accessor/base.ts';
import type { FileStat, PathSpec } from '../../types.ts';
import { type DetectFn, type ScopeMatch } from './scope.ts';
export type Reader<A extends Accessor> = (accessor: A, match: ScopeMatch, path: PathSpec, entry: FileStat | null, parent: FileStat | null) => Promise<Uint8Array>;
export interface ReadWindow {
    limit?: number | null;
    offset?: number | null;
}
export type WindowedReader<A extends Accessor> = (accessor: A, match: ScopeMatch, path: PathSpec, entry: FileStat | null, parent: FileStat | null, window: ReadWindow) => Promise<Uint8Array>;
export interface HierarchyReadOptions<A extends Accessor> {
    /**
     * Readers for kinds whose content is windowed at the source (postgres rows
     * take a row limit/offset the backend pushes into the query); they receive
     * the caller's window, which every plain reader ignores, matching a
     * filesystem read that has no row notion.
     */
    windowed?: Readonly<Record<string, WindowedReader<A>>>;
    /**
     * Every read first proves the file's parent directory exists, by the row
     * its listing names, so a container the listing refuses reads as absent
     * exactly as `ls` and `stat` report it. A backend whose readers address the
     * API by the ids in the path asks for it: without it, `cat` of a board
     * outside `boardIds` fetched that board by its id. The file itself stays
     * the reader's to prove, since a bounded listing need not name every file
     * that exists.
     */
    parented?: boolean;
}
/** Proves the matched entity exists before its answer runs. */
export type Guard<A extends Accessor> = (accessor: A, match: ScopeMatch, virtual: string) => Promise<void>;
/**
 * Build a call only some file kinds answer: classify, guard, dispatch, null
 * for the rest.
 *
 * The line calls (`firstLines`, `lastLines`, `lineCount`, `follow`) are
 * answered for a backend's data files (a table's rows, a collection's
 * documents) and not for its metadata files (a schema, a database.json),
 * which the caller reads the usual way. The table names the data kinds once,
 * so no answer repeats the check. Each answer is called as
 * `answer(accessor, match, path, ...args)`, after `guard`. Mirrors
 * `per_kind` in `mirage/core/hierarchy/read.py`.
 */
export declare function perKind<A extends Accessor, Args extends unknown[], T>(detect: DetectFn, answers: Readonly<Record<string, (accessor: A, match: ScopeMatch, path: PathSpec, ...args: Args) => Promise<T>>>, options?: {
    guard?: Guard<A>;
}): (accessor: A, path: PathSpec, ...args: Args) => Promise<T | null>;
/**
 * Build a hierarchy read: classify, dispatch, refuse the rest.
 *
 * Readers own their fetches, guards and rendering, handed what is at the path
 * (`entry`) and at its parent (`parent`) as the listings name them; the kit
 * owns the classification and the ENOENT funnel for every non-file shape.
 * `readers` holds one reader per leaf kind. Mirrors `make_read` in
 * `mirage/core/hierarchy/read.py`.
 */
export declare function makeRead<A extends Accessor>(detect: DetectFn, readers: Readonly<Record<string, Reader<A>>>, options?: HierarchyReadOptions<A>): (accessor: A, path: PathSpec, entry?: FileStat | null, parent?: FileStat | null, window?: ReadWindow) => Promise<Uint8Array>;
export type RangedReader<A extends Accessor> = (accessor: A, match: ScopeMatch, path: PathSpec, entry: FileStat | null, parent: FileStat | null, offset: number, size: number | null) => Promise<Uint8Array>;
export type ReadFn<A extends Accessor> = (accessor: A, path: PathSpec, entry?: FileStat | null, parent?: FileStat | null) => Promise<Uint8Array>;
/**
 * Build a byte-ranged read over a hierarchy read.
 *
 * A rendered file has no remote range to ask for — its bytes do not exist
 * until the read renders them — so the window is sliced after the fact. A
 * stored blob does (discord and slack attachments serve HTTP range
 * requests), and downloading the whole file to keep a slice would defeat the
 * ranged read; those kinds name a ranged reader in `ranged` and push the
 * byte window to the source.
 */
export declare function makeReadRange<A extends Accessor>(detect: DetectFn, read: ReadFn<A>, ranged: Readonly<Record<string, RangedReader<A>>>): (accessor: A, path: PathSpec, entry?: FileStat | null, parent?: FileStat | null, options?: {
    offset?: number;
    size?: number | null;
}) => Promise<Uint8Array>;
//# sourceMappingURL=read.d.ts.map