@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
72 lines • 4.48 kB
TypeScript
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