@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
142 lines • 7.83 kB
TypeScript
import type { FileStat } from '../../types.ts';
import { type Clock } from '../../utils/clock.ts';
import type { Evicted, IndexSnapshot, ListResult, LookupResult, SetDirOptions } from './config.ts';
export declare abstract class IndexCacheStore {
/** The clock every listing deadline of this store is set and read on. */
readonly clock: Clock;
/** @param clock the clock listings expire on; undefined means the real one. */
constructor(clock?: Clock);
/** Seconds a listing lives when its writer names no expiry. */
abstract readonly ttl: number;
/**
* Merge snapshots by path; deferred stores flush before operations or
* close. Clear discards them. `version` replaces the version of every
* listed folder, and null clears it.
*/
abstract seed(entries: ReadonlyMap<string, FileStat>, children: ReadonlyMap<string, readonly string[]>, expiresAt: Date, version?: string | null): void;
/** Apply this index's ownership rules to a refill snapshot. */
scopeSnapshot(snapshot: IndexSnapshot): IndexSnapshot;
abstract entries(): Promise<Map<string, FileStat>>;
abstract get(vfsPath: string): Promise<LookupResult>;
/** Read retained rows by path, omitting missing entries. */
getMany(vfsPaths: readonly string[]): Promise<Map<string, FileStat>>;
abstract put(vfsPath: string, entry: FileStat): Promise<void>;
/**
* Keep a row a create just made, named in its parent's listing. A listing
* held for the parent gains the name, in order, and stays what it was: a
* complete one stays complete, since the create is the only change to it.
* Replacing a directory with a file leaves the parent partial so a
* coexisting prefix can be listed again.
* With none held, the parent gets a partial listing that names the one
* entry, which proves it without proving anything absent; `expiredAt` is
* the latest that listing may live, null for the store's own lifetime.
*/
abstract addEntry(vfsPath: string, entry: FileStat, expiredAt?: Date | null): Promise<void>;
/** Atomically replace an existing row without renewing its listing; custom stores may decline. */
replaceIfUnchanged(_path: string, _predecessor: string, _entry: FileStat): Promise<boolean>;
/**
* A directory's listing. Given `child`, the one key a lookup asks about,
* its entries are narrowed to that key, kept where the listing names it,
* so a stat of each child of a large directory costs no scan or copy of
* the whole listing, which made `ls` of one quadratic
* (strukto-ai/mirage#1840). A custom store may answer the whole listing
* instead: callers check the key against the entries either way.
*/
abstract listDir(vfsPath: string, child?: string): Promise<ListResult>;
/**
* Cache a complete directory listing. A complete listing names every
* child, so a child the previous listing named and this one does not is
* gone: its row goes, and a gone directory takes its listing and every
* row beneath it. Rows only `put` wrote were never named, so they stay. A
* window evicts nothing. Resolves to the children that went.
*/
abstract setDir(vfsPath: string, entries: readonly [string, FileStat][], expiredAt?: Date | null, options?: SetDirOptions): Promise<Evicted[]>;
/**
* Hand children a re-list found gone to the mount's cleanup. A raw store
* belongs to no mount, so there is nothing to clean.
*/
reportGone(_gone: readonly Evicted[]): Promise<void>;
/** Token captured before fetching listings, including descendant seeds. */
refillToken(): Promise<string>;
/** Expire complete parent listings contradicted by the observed immediate child keys. */
invalidateMissing(_paths: readonly string[]): Promise<boolean>;
/** null rejects an older refill without reporting any deletions. */
refillDir(_path: string, _entries: readonly [string, FileStat][], _token: string, _expiredAt?: Date | null, _options?: SetDirOptions & {
partial?: boolean;
}): Promise<Evicted[] | null>;
/**
* Drop a changed row and demote its parent listing to partial.
* Retain siblings, the original deadline and deletion history. Clear the
* parent's version and window without recording a new observation.
* Missing or stale membership must never become fresh.
*/
abstract invalidateEntry(vfsPath: string): Promise<void>;
abstract invalidateDir(vfsPath: string): Promise<void>;
/**
* Cache observed children without claiming a complete directory. Stores
* supporting partial freshness return these keys as `partialEntries`
* until expiry or invalidation. A partial listing proves nothing
* complete, so it carries no version. Custom stores inherit the conservative
* put-only fallback, which refreshes the parent on the next lookup.
*/
setPartialDir(vfsPath: string, entries: readonly [string, FileStat][], _expiredAt?: Date | null): Promise<void>;
/**
* Drop `vfsPath` and everything cached below it.
*
* `invalidateDir` drops one directory's listing and its direct children's
* entries, which is enough for a mutation that named a path. A push
* notification that can only name a scope needs the whole subtree gone,
* because the listings further down were cached independently and nothing
* above them expires them.
*
* `remember` retains current membership as deletion history for the next
* complete listing; the default forgets it.
* Mirrors Python `IndexCacheStore.invalidate_prefix`.
*/
abstract invalidatePrefix(vfsPath: string, excluded?: readonly string[], remember?: boolean): Promise<void>;
/**
* Whether the running command fetched `folder`'s listing itself.
*
* A raw store belongs to no mount and no command, so it cannot tell and
* answers false; a mount's view answers from its cache manager. Mirrors
* Python's `listed_this_command`.
*/
listedThisCommand(_folder: string): boolean;
/**
* Whether a listing is cached at `vfsPath` or anywhere under it.
*
* Asked when a removed path may be a folder, to avoid a subtree scan for
* each plain-file delete. Only a retained listing counts, even one past its
* ttl (expiry is checked when it is read). A row or tombstone does not prove
* a listing remains below the path. A children-first delete stream may
* already have removed every listing before the folder's own event arrives.
*
* A store that cannot tell answers true, so callers conservatively drop
* the subtree and refetch it.
*
* Mirrors Python `IndexCacheStore.holds_subtree`.
*/
holdsSubtree(_vfsPath: string): Promise<boolean>;
/**
* Mark every entry stale without discarding it.
*
* The difference from `clear` is what a later lookup can tell. `clear`
* leaves an empty store, which reads exactly like a store that was never
* filled, so a backend whose index *is* its listing cannot tell an
* invalidation from an empty repository. Expiring instead keeps that
* distinction: the lookup answers EXPIRED and the backend refetches.
*/
abstract invalidate(): Promise<void>;
abstract clear(): Promise<void>;
/**
* Release whatever the store holds open. The default is a no-op:
* an in-memory index owns nothing. A store backed by a connection
* (redis) overrides this and must be idempotent — `close()` is
* called once per owning VFS, and a VFS shared between
* workspaces is closed by whichever one owns it.
*
* Mirrors Python `IndexCacheStore.close` (`cache/index/store.py`).
*/
close(): Promise<void>;
}
//# sourceMappingURL=store.d.ts.map