@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
98 lines • 4.78 kB
TypeScript
import type { ByteSource } from '../io/types.ts';
import { type CapacityResult, type PathSpec } from '../types.ts';
/** The bytes at a path, a directory's included; 0 for none. */
export type SizeOf = (path: PathSpec) => Promise<number>;
/** The bytes the whole store holds. */
export type CountAll = () => Promise<number>;
/**
* One store's capacity and the bytes counted against it.
*
* `used` is null until the store is counted. `pending` holds bytes a stream
* or an awaiting write admitted and has not landed yet. `active` holds the
* writes in flight. Every method but `counted` is
* synchronous, so a check and the change it guards run as one step on the
* one thread, which is what makes parallel writers safe without a lock. Two
* writes in flight on overlapping paths (a file and its folder) can both
* measure the same bytes, so they lose the credit for the bytes they replace
* and mark the count for a recount, which waits until no write is in flight. The count lives in this object: another
* process, or another VFS on the same disk folder, Redis prefix or OPFS
* directory, counts on its own, so together they can pass the limit.
* Mirrors Python's `StorageUsage`.
*/
export declare class StorageUsage {
readonly limit: number;
used: number | null;
pending: number;
readonly active: Charge[];
dirty: boolean;
private counting;
constructor(limit: number, used?: number | null);
/** Count the store when it is uncounted, or marked for a recount and no
* write is in flight; parallel callers wait on one count. */
counted(count: CountAll): Promise<void>;
private count;
/** Count the store again once no write is in flight, as bytes written
* past mirage (a native program on a disk folder) went uncounted. */
stale(): void;
/** Mark a write in flight; one overlapping another in flight takes both
* off their credit and marks the count for a recount. */
enter(held: Charge): void;
/** Mark a write done. */
leave(held: Charge): void;
/** Throw `edquot(path)` when positive growth would pass the limit;
* reaching it exactly passes. */
admit(path: PathSpec, growth: number): void;
/** Admit `size` and keep it in `pending` until it lands. */
hold(path: PathSpec, size: number): void;
/** Take `held` out of `pending` and add the measured `delta`. */
land(held: number, delta: number): void;
/** df's QUOTA row: total is the limit, available never below 0. */
report(): CapacityResult;
}
/**
* A backend's usage for its `capacity` setting; null for no cap. `used` is
* the bytes it starts with when the backend knows them, as an empty RAM
* store does. Mirrors Python's `storage_usage`.
*
* @throws VFSConfigError when the setting is not a size.
*/
export declare function storageUsage(name: string, capacity: number | string | null | undefined, used?: number | null): StorageUsage | null;
/**
* What one write reserves against a counted store, and the bytes it held so
* far; inert for an uncapped store. A replacement is credited with the bytes
* it replaces until another write overlaps it (`contended`), as that write
* may move those bytes elsewhere. Mirrors Python's `Charge`.
*/
export declare class Charge {
readonly usage: StorageUsage | null;
readonly path: PathSpec;
before: number;
held: number;
written: number;
contended: boolean;
constructor(usage: StorageUsage | null, path: PathSpec, before?: number);
/** Reserve `size` more bytes, or throw EDQUOT. */
hold(size: number): void;
/** The length the operand may reach within what this charge holds and is
* credited with. */
get reserved(): number;
/** Reserve what growing the operand to `size` bytes adds past what this
* charge already holds. */
growTo(size: number): void;
/** `data`, each chunk reserved as the writer takes it. With `append`
* false, a replacement reserves only what passes the bytes it replaces. */
stream(data: ByteSource, append?: boolean): ByteSource;
private take;
private held_;
}
/**
* Reserve before a write's bytes go and land what it really changed. The
* reservation is checked and taken in one synchronous step, so parallel
* writers can never pass the store's capacity together. After the write,
* however it ended, the operand is measured again and the change lands; one
* that overlapped another in flight marks the count for a recount. An
* uncapped store gets an inert charge and measures nothing. Mirrors Python's
* `charge`.
*/
export declare function charge<T>(usage: StorageUsage | null, path: PathSpec, sizeOf: SizeOf, count: CountAll, write: (held: Charge) => Promise<T>): Promise<T>;
//# sourceMappingURL=capacity.d.ts.map