@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
67 lines • 3.08 kB
TypeScript
import { type PathSpec } from '../types.ts';
export type Allowed = (virtual: string) => boolean;
/**
* A remnant cascade met an entry the session can see.
*
* Thrown by `removeRemnants` before the visible entry is touched: the
* caller's not-empty refusal is then simply true in the session's own
* view, so every arm answers this by re-raising that original refusal
* rather than deleting visible data.
*/
export declare class VisibleRemnant extends Error {
readonly code = "ENOTEMPTY";
readonly virtual: string;
readonly virtualPath: string;
constructor(virtual: string);
}
/**
* The four ops a remnant cascade speaks, on one plane's own protected
* channel.
*
* The channel carries every protection axis except visibility: a
* deletion must still answer for its path's mode and rules exactly as
* a first-class op would (the command plane binds its mode- and
* rule-guarded slots, the dispatcher routes through its own fenced op
* call), while the visibility filter stays off because the cascade
* exists to see and destroy what the session cannot. The cascade never
* sprinkles those checks itself; wiring a raw, unguarded channel here
* is the bug this contract exists to prevent.
*/
export interface RemnantChannel {
readdir(spec: PathSpec): Promise<string[]>;
stat(spec: PathSpec): Promise<unknown>;
unlink(spec: PathSpec): Promise<void>;
rmdir(spec: PathSpec): Promise<void>;
}
/**
* One listing entry's bare child name. Cold object-store listings mark
* a directory with a trailing slash, and some backends report whole
* paths rather than names; both normalize to the last component.
*/
export declare function entryName(entry: string): string;
/**
* Whether any listed name is visible as a child of `base`.
*
* The one emptiness predicate every remnant arm judges with, fed every
* name source its plane can enumerate (the backend listing, and on the
* ops plane the namespace's merged children too), so "visibly empty"
* cannot mean different things at different entry points.
*/
export declare function visibleBelow(base: string, names: Iterable<string>, allowed: Allowed): boolean;
/**
* Remove one directory and everything under it, children first,
* revalidating visibility at every step.
*
* The walk lists raw, but the moment any entry is visible the whole
* cascade aborts with `VisibleRemnant` before that entry is touched:
* between the caller's classification and each deletion another writer
* may have created something visible, and destroying it would turn an
* ostensibly empty rmdir into data loss. An entry that vanishes
* mid-walk is a completed removal (a prefix-store directory disappears
* with its last child), not an error. Every op goes through the
* channel, so the plane's other protections refuse exactly as they
* would a first-class op; the caller answers any cascade failure with
* its original refusal.
*/
export declare function removeRemnants(channel: RemnantChannel, allowed: Allowed, spec: PathSpec): Promise<void>;
//# sourceMappingURL=remnants.d.ts.map