@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
575 lines • 31.4 kB
TypeScript
import type { z } from 'zod';
import { type Accessor } from '../accessor/base.ts';
import type { ConditionSupport, ReplaceRequest } from '../cache/types.ts';
import type { CLI } from '../commands/cli/types.ts';
import type { Command } from '../commands/config.ts';
import type { DeltaHook } from '../events/base.ts';
import type { ByteSource } from '../io/types.ts';
import type { CapacityResult, DirListing, FileStat, PathSpec, SearchQuery, SetAttrFields } from '../types.ts';
import { ListingVersion } from '../types.ts';
import type { StorageUsage } from './capacity.ts';
import type { RedactedSchema } from './secrets.ts';
import type { VFSStateBase } from './types.ts';
import { type ConfigState, type Handed } from './types.ts';
/**
* The brand every driver carries, keyed through the symbol registry so a
* script file that loaded its own copy of this package still passes the
* loader's check: the class identity may differ, the brand does not.
*/
export declare const VFS_BRAND: unique symbol;
/**
* The facts a subclass that does not declare them as members hands the
* constructor. Every field is optional, so a class that declares its facts
* as members calls `super()` bare. Mirrors the keyword arguments of
* Python's `BaseVFS.__init__`.
*/
export interface VFSOptions<A extends Accessor = Accessor> {
/**
* VFS name commands register under, and the `type` key `getState`
* writes into a snapshot. Also the registry key when the backend is
* exposed through `registerVfs`.
*/
name?: string;
/** Backend handle the functions use. */
accessor?: A;
/**
* This VFS's part of VFS.md, in Markdown: its layout and file formats,
* `{prefix}` standing for the mount path.
*/
vfsMd?: string;
/**
* Extra commands, from `command({...})`, or `CLI` trees: bespoke verbs, a
* program's verbs as one command tree under its root's name, or
* replacements that win over the generic command of the same name.
*/
commands?: readonly (Command | CLI)[];
/** Serve repeat reads from the file cache. Read-mostly content only. */
cachesReads?: boolean;
/**
* Whether `stat` sizes every regular file without fetching it, which is
* also what makes the mount legal on FSKit.
*/
sizesAlwaysKnown?: boolean;
/**
* Whether `stat` fills `FileStat.fingerprint` with a stable per-path
* version marker. Setting it without that is not drift detection.
*/
supportsSnapshot?: boolean;
/**
* Whether `stat` and the read record stamp the *same kind* of content
* token, so a `read: fresh` mount can compare them. Setting it without
* that makes every read verdict stale; a mount declaring `fresh` on a
* backend that leaves it false is refused.
*/
readRevalidatable?: boolean;
}
/**
* A backend: an accessor, the facts about it, and its functions.
*
* A VFS answers `readdir`, `read` and `stat`; every other function
* (`write`, `unlink`, a native `find` or `search`, ...) is optional, and a VFS answers exactly the ones it defines. Every generic
* shell command (`ls`, `cat`, `grep`, `find`, `head`, `wc`, ...) runs on
* the three required ones, and a line that needs a function the VFS does
* not define answers `Operation not supported` at that call, so `gzip -c`
* and `tar -t` still run as readers on a read-only backend. A method
* marked `@vfsCall` is also reachable by name through the dispatcher
* (`ws.dispatch('search_abc', path)`), with every check the dispatcher runs; the
* built-in ones are marked here, and an override keeps the mark.
*
* Everything a tree needs to run one (the placement, the index store, the
* registered commands, the reference it was built from) lives on the
* mount, so an author never sees it.
*
* Snapshots and versions see one of two things, and a subclass picks
* which by what it owns. Content the VFS holds itself (an in-memory
* store) is mirage-owned state: override `getState` and `loadState` to
* carry it, register the class under its name, and a snapshot or a
* version rebuilds the mount with that content and no override. Content
* that lives in a remote service is only observed: keep the default
* state, set `supportsSnapshot` and fill `FileStat.fingerprint`, and a
* snapshot pins what it read while `Workspace.load` asks for the live VFS
* back. Mirrors Python's `BaseVFS`.
*/
export declare class BaseVFS<A extends Accessor = Accessor> {
#private;
readonly [VFS_BRAND]: true;
readonly name: string;
get conditionSupport(): ConditionSupport;
vfsMd: string;
readonly indexTtl: number;
/**
* Whether reads of this VFS may be served from / written to the
* local file cache. A network-backed VFS whose content is read-mostly
* (e.g. object storage) sets this to true so reads can be cached; a
* VFS whose content is live (e.g. a database collection) leaves it
* false so reads always hit the backend and live follows (`tail -f`)
* are not masked by a cached snapshot.
*/
readonly cachesReads: boolean;
/**
* Whether this VFS carries enough version information for
* snapshot+replay drift detection. When true, the driver's `stat` op
* must populate {@link FileStat.fingerprint}
* (and optionally {@link FileStat.revision}) with stable per-path
* markers. When false (the default), reads are treated as live-only
* at replay time: no fingerprint is captured at snapshot, no drift
* check fires at load.
*/
readonly supportsSnapshot: boolean;
/**
* Whether the driver's `stat` op can size every regular file without
* fetching its content, i.e. {@link FileStat.size} is null only for
* directories. True for byte stores that keep a length in their
* metadata (ram, disk, redis, s3, gridfs); false for mounts that
* render content on read, where the size is unknowable until the bytes
* exist (slack, gmail, notion, postgres rows.jsonl, dify documents).
*
* FUSE does not need this: direct_io + attrTimeout '0' + hydrate-on-open
* make size-unknown files read correctly anyway. FSKit has no direct_io
* equivalent, so a mount there is driven entirely by the reported size
* and a false VFS would serve silent empty files. Mirrors Python's
* `BaseVFS.sizes_always_known`.
*/
readonly sizesAlwaysKnown: boolean;
/**
* Whether a `read: fresh` mount can actually be revalidated against this
* backend: the driver's `stat` op and the read record must stamp the
* *same kind* of content token, so the gate can compare them with `===`. False
* (the default) is refused at mount time rather than degraded, because a
* mount that declares fresh and silently serves bounded is the bug the
* policy exists to prevent.
*
* Distinct from {@link BaseVFS.supportsSnapshot}, which asks whether a
* token exists at all, and from {@link BaseVFS.cachesReads}, which asks
* whether the gate can fire. A backend can have a token on both sides
* and still fail this one, by stamping two different kinds.
*
* A declarer must stamp the token on every read, not only while a
* recorder is active: node's read_revalidatable.test.ts holds each one to
* that (#1165). onedrive and sharepoint qualify because every unpinned
* byte read fetches the item's cTag before its bytes, recorded or not; a
* stream stamps only under a recorder, the one place its token can land.
*
* Mirrors Python's `BaseVFS.read_revalidatable`.
*/
readonly readRevalidatable: boolean;
/**
* What a `read: fresh` mount checks a cached listing against before it
* lists again: nothing (NONE, the default), one version for the whole mount
* answered by a stat of its root (MOUNT), or each folder's own version
* answered by a stat of that folder (FOLDER). A declarer stores with each
* listing it writes a version no newer than its rows: taken from the same
* response (github's tree names its head), or read first and the rows then
* read at it or after it (hf walks the tree at the commit its revision
* request answered; disk stats a folder before it scans), so a change in
* between leaves the stored version behind and the next check re-lists.
* Its `stat` must answer the same kind of token: node's
* listing_version.test.ts holds each one to that.
*
* Mirrors Python's `BaseVFS.listing_version`.
*/
readonly listingVersion: ListingVersion;
/**
* The stats each of this VFS's functions is handed, by method name: a
* function named here gets a `Handed` holding each stat it lists, found
* in the mount's stored listings, where it takes its index otherwise.
* Python reads the same off each function's parameters.
*/
readonly handed: Readonly<Partial<Record<string, readonly (keyof Handed)[]>>>;
/**
* The version every listing of this mount is pinned at, when its ref names
* a commit outright (github's full-sha ref; see `pinOf` in
* vfs/github/github.ts for why that cannot move). A stored listing whose
* version equals it is served without a check. It depends on the mount's config, so
* an instance sets it; null pins nothing.
*/
readonly listingsPin: string | null;
/**
* Whether `read` fetches a byte window from the store itself. When false
* the caller reads the whole file and slices it, so `read` is only ever
* handed a window by a VFS that sets this.
*/
readonly readsRanges: boolean;
/**
* Whether the data lives on the host filesystem, which lets a command
* aggregate on the host instead of streaming through mirage.
*/
readonly local: boolean;
/** The store's capacity and counted bytes, set by a backend whose config
* caps it; null when uncapped. */
readonly usage: StorageUsage | null;
/**
* The files `filesContaining` answers for, as mount-relative globs matched
* segment by segment (a glob naming a directory covers what is below it);
* null for every file. grep and rg read any other file whatever the
* answer, as a full scan would.
*/
readonly searchable: readonly string[] | null;
/**
* `filesContaining` answers only a whole-word search (grep -w, rg -w);
* any other pattern reads every file.
*/
readonly wholeWordSearch: boolean;
/**
* The most files one command walks under a directory of this mount: grep
* -r, rg and git grep stop reading there, find, ls -R, tree, du and
* getfattr -R stop listing, git status and the other verbs that walk a
* work tree fail, a glob matching more is refused, and so are tar -c, zip
* -r, cp -r, rm -r, chmod -R, chown -R, chgrp -R, mv to another mount and
* diff -r of a directory holding more (`beforeFullWalk`); -1 for no cap.
* This is the backend's own value: the mount's `'@all'` command limit, else
* the workspace's, replaces it when the VFS is mounted.
*/
walkLimit: number;
/**
* Extensions whose `read` is a rendering rather than the stored bytes,
* each to the name of the method that renders it, which takes `read`'s
* arguments, window included. A rendered read is never served from or
* kept in the file cache, and a `raw` read asks for `read` itself.
*/
readonly renderers: Readonly<Record<string, string>>;
/**
* The backend handle every function takes. A builtin declares and
* assigns its own; one that brings none runs over a no-op accessor.
*/
readonly accessor: A;
/**
* Set the facts a subclass does not declare as members. Every option is
* optional, so a class that declares its facts as members calls
* `super()` bare.
*/
constructor(options?: VFSOptions<A>);
/**
* Whether this VFS defines the function `name`. A function the base
* declares is supported once a subclass or the instance itself replaces
* it; one only a subclass declares (a custom `@vfsCall`) is supported
* because it exists.
*/
supports(name: string): boolean;
/** The bespoke commands and command trees this VFS was handed. */
commands(): readonly (Command | CLI)[];
/**
* List the children of a directory, each as its stat answers it.
*
* On a walk, `handed.limit` is the most entries the walk can still use;
* a readdir may stop once it holds that many and answer them as
* `new DirListing({ entries, partial: true })`. A glob hands the word it
* matches as `path.pattern`; a backend that filters by it answers
* `partial: true` too. Mirrors Python's `readdir`.
*/
readdir(path: PathSpec, _handed?: Handed): Promise<readonly FileStat[] | DirListing>;
/**
* Read a file's bytes, or a window of them. Answer with the bytes, or with
* an async iterable that hands them out as the caller pulls, so a large
* file never sits in memory: an `async` method that resolves to either, or
* an `async *` one that yields chunks. Mirage collects a stream for a
* caller that needs the bytes whole and hands bytes to a streaming caller
* as one chunk. A window reaches this only when `readsRanges` is set: the
* caller otherwise reads the whole file and slices it.
*/
read(path: PathSpec, _handed?: Handed, _offset?: number, _size?: number | null, _signal?: AbortSignal): Promise<ByteSource> | AsyncIterable<Uint8Array>;
/** Describe a path; rejects with ENOENT when nothing is there. */
stat(path: PathSpec, _handed?: Handed): Promise<FileStat>;
/** Whether anything is at `path`; derived from `stat` when not defined. */
exists(path: PathSpec, _handed?: Handed): Promise<boolean>;
/**
* The first `n` lines of a file, without reading the rest.
*
* `head -n N` asks this before it reads, so a backend that can fetch the
* start of a file on its own (a `LIMIT` on a table) does not send the whole
* file. The answer stands in for the file: exactly the first `n` lines a
* read gives, each with its newline, and the whole file when it has fewer.
* A file the read cache holds is read instead. Resolves null to have the
* file read the usual way; rejects with the file's read error otherwise
* (`EFBIG` when the answer passes a ceiling on one read, such as
* `max_read_rows`).
*/
firstLines(path: PathSpec, _n: number, _handed?: Handed): Promise<Uint8Array | null>;
/**
* The last `n` lines of a file, without reading the rest.
*
* `tail -n N` asks this before it reads, and `tail -f` for its first print.
* The answer stands in for the file: exactly the last `n` lines a read
* gives, each with its newline, and the whole file when it has fewer. A
* file the read cache holds is read instead. Resolves null to have the file
* read the usual way; rejects with the file's read error otherwise (`EFBIG`
* when the answer passes a ceiling on one read).
*/
lastLines(path: PathSpec, _n: number, _handed?: Handed): Promise<Uint8Array | null>;
/**
* How many newlines a read of the file gives, without reading it.
*
* `wc -l` asks this before it reads (a `COUNT(*)` on a table), and only
* when it counts lines alone. A file the read cache holds is read instead.
* Resolves null to have the file read the usual way; rejects with the
* file's read error otherwise.
*/
lineCount(path: PathSpec, _handed?: Handed): Promise<number | null>;
/**
* The digest the backend keeps for a file, without reading it.
*
* `md5sum` and its siblings ask this before they read, except under `-c`,
* which checks the bytes themselves, so a backend that stores a file's
* digest (an object's MD5 ETag, a drive's `md5Checksum`) does not send the
* file. Answer only a digest of exactly the bytes a read gives, in
* lowercase hex: a stored value that can be anything else (a multipart or
* encrypted object's ETag) is null. `algorithm` is the hashlib name, `md5`,
* `sha1`, `sha224`, `sha256`, `sha384`, `sha512` or `blake2b`, or
* `blake2b-N` for BLAKE2b at N bits. A file the read cache holds is read
* instead. Resolves null to have the file read and hashed; rejects
* with the file's read error otherwise.
*/
checksum(path: PathSpec, _algorithm: string, _handed?: Handed): Promise<string | null>;
/**
* The last `n` lines of a file, then each line added to it, as it lands.
*
* `tail -f` on one file asks this for all it prints, so a backend that can
* be told about new data (a change stream) does not have to be polled, one
* that can be asked for only what is new does not read the whole file again
* on each poll, and the lines it prints first and the ones it follows meet
* at one point: none is lost or printed twice. The stream yields whole
* lines, each with its newline, in the order a read would show them, and
* ends only when the caller closes it; closing it ends a wait for the next
* line. `interval` is `tail -s`, the seconds between two asks for what is
* new; a change stream has no use for it. Resolves null to have `tail` read
* the file and poll it every `-s` seconds; rejects with the file's read
* error otherwise.
*/
follow(path: PathSpec, _n: number, _interval: number, _handed?: Handed): Promise<AsyncIterable<Uint8Array> | null>;
/**
* Every entry under a directory, in one answer.
*
* `find`, `du`, `ls -R`, `tree`, `grep -r` and `rg` ask this before they
* walk a directory, so a backend that can list a subtree on its own (a
* recursive listing, one query over many folders) does not take a
* `readdir` per directory. The answer stands in for the walk: every file and
* directory below `path`, keyed by its path below `path` (`a`, `a/b.txt`),
* each with the stat `stat` gives for it. The walk lists each directory from it in name order.
* Resolve null to have the command walk `readdir` the usual way; reject with
* what `readdir` of `path` rejects with otherwise. `handed.limit` is the
* most entries the walk can still use; resolve null once the tree holds
* more. A walk that reads one directory at a time asks with `level: true`,
* which the mount answers from its own listing (the directory's children,
* each with its stat) and never asks this function. Mirrors Python's
* `read_tree`.
*/
readTree(path: PathSpec, _handed?: Handed): Promise<Map<string, FileStat> | null>;
/**
* Replace a file's bytes, creating it when missing. `data` is the whole
* content, or an async iterable that hands it over as it is produced (a
* program's output redirected into the file); `materialize(data)` collects
* it for a store that takes one body. A stream that lands as it arrives
* lets a reader watch the file grow, and `atomic` asks that nothing show
* until it has ended whole, which a write that collects first already does.
*/
write(path: PathSpec, _data: ByteSource, _signal?: AbortSignal, _handed?: Handed, _atomic?: boolean): Promise<unknown>;
_replace(request: ReplaceRequest, _signal?: AbortSignal, _handed?: Handed): Promise<unknown>;
/**
* Add bytes to the end of a file, creating it when missing. `data` is
* bytes or a stream, as `write` takes it. A VFS that defines `write` and
* not this is appended to by reading the file and writing it back.
*/
append(path: PathSpec, _data: ByteSource, _handed?: Handed, _signal?: AbortSignal): Promise<unknown>;
/**
* Write bytes at an offset, keeping every byte outside them. As
* pwrite(2): a gap past the end reads back as zeros and a missing file
* is created. A VFS that defines `write` and not this is written by
* reading the file and writing it back.
*/
pwrite(path: PathSpec, _data: Uint8Array, _offset: number, _handed?: Handed, _signal?: AbortSignal): Promise<unknown>;
/** Create an empty file, leaving an existing one as it is. */
create(path: PathSpec, _handed?: Handed): Promise<unknown>;
/** Make a directory; `parents` makes missing parents too, as `mkdir -p`. */
mkdir(path: PathSpec, _parents?: boolean, _handed?: Handed): Promise<unknown>;
/** Remove a file. */
unlink(path: PathSpec, _handed?: Handed): Promise<void>;
/**
* Remove an empty directory. The index is the mount's, which a refused
* rmdir's hidden-remnant walk lists through. A store that checks
* emptiness, then deletes, looks again after: a child written in between
* keeps the directory, which stays as it was, and the call rejects with
* ENOTEMPTY.
*/
rmdir(path: PathSpec, _handed?: Handed): Promise<void>;
/**
* Remove a subtree in one call instead of entry by entry. A store that
* lists, then deletes, looks again after: a child written under the root
* since its listing stays, inside its directories, and the call rejects
* with ENOTEMPTY on the root, never success over a key it left.
*/
rmR(path: PathSpec, _handed?: Handed): Promise<void>;
/**
* Move a name within this VFS. A store that moves a directory by listing
* it moves only what it listed: a child written under `src` since stays
* there, inside its directories, and the call rejects with ENOTEMPTY on
* `src`.
*/
rename(src: PathSpec, _dst: PathSpec, _handed?: Handed): Promise<unknown>;
/** Copy a file within this VFS without moving its bytes through mirage. */
copy(_src: PathSpec, dst: PathSpec, _signal?: AbortSignal, _handed?: Handed): Promise<unknown>;
/** Copy a directory tree within this VFS in one call. */
/**
* Copy a file from another mount onto this one without moving its bytes
* through mirage.
*
* `cp` and `mv` between two mounts ask this before they read the file and
* write it here, once the dispatcher has judged the source as a read and
* the destination as a create. It is no dispatcher call of its own, so
* nothing reaches it unjudged. `source` is the source mount's VFS and `src`
* the file there. Reject EXDEV when this backend cannot copy from `source`
* (another kind of store, other credentials, a refusal), and the bytes move
* through the read and the write instead.
*/
copyFrom(_source: BaseVFS, _src: PathSpec, dst: PathSpec): Promise<void>;
dirCopy(_src: PathSpec, dst: PathSpec, _handed?: Handed): Promise<unknown>;
/**
* Resize a file, padding with zeros or cutting the end. `noCreate`
* refuses a missing file instead of creating it; a VFS that cannot hold
* that atomically rejects with ENOTSUP before writing.
*/
truncate(path: PathSpec, _length: number, _noCreate?: boolean, _handed?: Handed): Promise<unknown>;
/**
* Store metadata fields the backend keeps itself. Resolves to the fields
* it stored; the rest land in the namespace's attribute overlay.
*/
setattr(path: PathSpec, _fields: SetAttrFields, _handed?: Handed): Promise<Record<string, number | string>>;
/**
* Search the resource under `path`; null declines, [] is none. One
* `[path, record]` pair per hit: the hit's virtual path, which the
* dispatcher drops the hit for when the session hides it, and the record
* the `search` CLI prints, a header line naming the path (`path:score`
* where the store ranks) and then the hit's text. Errors and incomplete
* results reject, never answered as a miss.
*/
search(path: PathSpec, _query: SearchQuery, _handed?: Handed): Promise<[string, string][] | null>;
/** Search several scopes as one ranked query. */
searchMany(paths: PathSpec[], _query: SearchQuery, _handed?: Handed): Promise<[string, string][] | null>;
/**
* Read several whole files in one request, for a read-ahead. Keyed by each
* answered path's `virtual`. A file may be left out (one larger than
* `limit` bytes, one the request could not read), and its own read answers
* it later; an error of the whole request rejects. Each file read is
* recorded as `read` records it, fingerprint included, so the read cache
* keeps its token. A VFS that needs what the listings hold declares
* `readMany` in `handed` and gets each path's `Handed`, in the order of
* `paths`. Mirrors Python's `read_many`.
*/
readMany(paths: PathSpec[], _limit: number, _handed?: readonly Handed[]): Promise<Map<string, Uint8Array>>;
/**
* Files under `path` whose content may contain `text`. grep and rg still
* walk, filter, order and label every file, and read only the ones answered
* here, matched on `vfsPath` without case, so an extra file costs a read and
* a missing one is a wrong answer. A search that holds only keys names each one with
* `mountedPath(path, '/' + key)`. Resolve null when the answer may be
* incomplete (an error, a truncated result, an index that lags writes), and
* every file is read; reject to refuse the command, and the error's message
* is what it prints. The dispatcher drops every file the session hides
* from the answer.
*
* @param path a directory walked: one of grep's directory operands under -r
* or -R, or of rg's operands or the cwd; asked once per directory.
* @param text plain text every match holds, never a pattern: the pattern
* or each -e of grep and rg, or for a regex a fixed piece of at least
* three characters every match contains. Asked once per text; a file any
* answer holds is read.
* @param opts `wholeWord` is true under -w or -x with a plain-text
* pattern, where `text` is a whole word of every match, and false
* otherwise, where it may sit inside a word. `ignoreCase` is true under
* -i, and under rg -S with a lowercase pattern; folding case when false
* is fine.
*/
filesContaining(_path: PathSpec, _text: string, _opts: {
wholeWord: boolean;
ignoreCase: boolean;
}, _handed?: Handed): Promise<PathSpec[] | null>;
/**
* The lines of `path` that may contain `text`, in file order. grep and rg
* match each line themselves, so an extra line is fine and a missing one is
* a wrong answer. Each line keeps the newline the file has, whole or
* streamed. The lines stand in for the file when the output shows no line
* positions (no -n, -b, --column, --vimgrep), no context (no -A, -B, -C) and
* there is one text; otherwise the file is read only when some answer holds
* a line, and only a stream's first chunk is pulled. null reads the file;
* answer null for a file that may hold a NUL byte, since grep and rg call
* such a file binary from bytes outside its matching lines. Reject to refuse
* the command.
*
* @param path the file.
* @param text plain text every match holds, as `filesContaining` gets it.
* @param opts `ignoreCase` is true under -i, and under rg -S with a
* lowercase pattern.
*/
linesContaining(_path: PathSpec, _text: string, _opts: {
ignoreCase: boolean;
}, _handed?: Handed): Promise<ByteSource | null>;
/**
* Called before a command acts on every file under `path`, once per
* directory a command copies, compares, changes or removes whole, before
* the first file it touches there: tar -c, zip -r, cp -r, mv across
* mounts, diff -r, rm -r, chmod -R, chown -R and chgrp -R. Resolve to let
* the walk run; reject to refuse it, and the error's message is what the
* command prints. The dispatcher has already refused more than the
* command's `walkLimit` files, so the default lets the walk run. Searches
* and listings are never refused: they stop after `walkLimit` files.
*
* @param path the directory about to be walked.
* @param files how many files the session sees under `path`, with every
* hidden file dropped: the mount's `readTree`, or under a
* `walkLimit` a walk of its listings that stops one file past it;
* null when neither counts, and the guard counts them itself.
*/
beforeFullWalk(_path: PathSpec, _files: number | null, _handed?: Handed): Promise<void>;
/** Whether the backend is there to answer at all. */
isMounted(): boolean;
deltaHook?(): DeltaHook;
/**
* Where this driver's bytes live, as one string a person can read:
* `disk:/srv/data`, `s3:aws:my-bucket/prefix`. Two mounts with the
* same location address the same bytes, which is how `cp` and `mv`
* across mounts refuse to copy a file onto itself. Null, the default,
* means unknown, and the mount then treats this instance as a location
* of its own, which is the safe direction to be wrong in: a false
* "different" only keeps the pre-existing behavior, while a false
* "same" would refuse a legitimate move. A driver whose config pins
* the storage (a disk root, a bucket and key prefix) overrides this so
* two instances pointing at one target compare equal.
*/
storageLocation(): string | null;
/**
* How much space this backend has, for `df`. The default is UNKNOWN,
* which `df` renders as `-`. A driver that can answer truthfully (a
* real filesystem, a provider that exposes a storage quota) overrides
* this. Never fabricate a number.
*/
capacity(): Promise<CapacityResult>;
/**
* What a snapshot records for this driver: its type and `needs_override`,
* since the base cannot know a subclass's constructor, so both loaders
* then require the mount to be handed back live (`load`'s overrides;
* `copy()` does this itself). A driver that owns its content (an
* in-memory store) overrides this and {@link BaseVFS.loadState} to carry
* it and drops the flag; a driver over a remote service keeps the default
* and pins what it read through `supportsSnapshot` fingerprints instead.
* `toStateDict` calls this and `loadState` on every mount, which is why
* neither is optional. Mirrors Python `BaseVFS.get_state`.
*/
getState(): VFSStateBase | Promise<VFSStateBase>;
/** Snapshot a config-backed driver through its schema's secret markers. */
configState<S extends z.ZodObject>(schema: S, config: unknown): ConfigState<RedactedSchema<S>>;
/**
* Take back what {@link BaseVFS.getState} put out. A no-op by
* default, because the bare `{type}` carries nothing to restore.
* Mirrors Python `BaseVFS.load_state`.
*/
loadState(_state: VFSStateBase): void | Promise<void>;
get isClosed(): boolean;
/**
* Release what this driver owns, exactly once: its accessor's handles
* are its own to close, since the Accessor seam carries no lifecycle.
* A backend with handles of its own (a db pool, an ssh channel)
* overrides this and calls `super.close()`. Mirrors Python
* `BaseVFS.close`.
*/
close(): Promise<void>;
}
//# sourceMappingURL=base.d.ts.map