@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
89 lines • 4.73 kB
TypeScript
import type { ObserverStore } from '../../observe/store.ts';
import type { NamespaceStore } from '../mount/namespace/store.ts';
import type { JobStore } from '../../shell/job_table/store.ts';
export type WorkspaceFields = Record<string, unknown>;
export interface WorkspaceStateStoreOverrides {
namespace?: WorkspaceStateStore;
observer?: WorkspaceStateStore;
workspace?: WorkspaceStateStore;
jobs?: WorkspaceStateStore;
}
/**
* Provider for a workspace's whole control-plane state.
*
* One store, five planes, each scoped by workspace id: namespace nodes
* (symlinks, attribute overlays), observer events (command history),
* the session table (mount grants, cwd, env), the workspace metadata
* record (discovery: which sessions exist, which is the default), and
* the jobs (each session's job list and each job's console). Handing two
* processes the same store config plus a workspace id gives them the same
* workspace state, which is the seam that lets a kernel tier bind a
* session-bound mountpoint created by another daemon, and lets any of
* them list, wait on and kill a session's jobs.
*
* The node table and the session table are two NamespaceStores, the
* observer keeps its ObserverStore and the jobs their JobStore; this
* provider only unifies their construction, connection, and key scoping. Per-group overrides
* redirect a plane group to a different provider (e.g. large observer
* logs elsewhere while everything else stays on Redis). Sessions and
* metadata form one inseparable group: the default-session pointer in
* the metadata must never live on a different server than the session
* table it points into.
*/
export declare abstract class WorkspaceStateStore {
private readonly namespaceOverride;
private readonly observerOverride;
private readonly workspaceOverride;
private readonly jobsOverride;
constructor(overrides?: WorkspaceStateStoreOverrides);
/** The namespace plane (nodes) for one workspace. */
namespace(workspaceId: string): NamespaceStore;
/** The observer plane (history events) for one workspace. */
observer(workspaceId: string): ObserverStore;
/** The session table for one workspace. */
sessions(workspaceId: string): NamespaceStore;
/** The job plane (job lists, consoles, leases) for one workspace. */
jobs(workspaceId: string): JobStore;
/** Read one workspace's metadata record; null when never written. */
loadMeta(workspaceId: string): Promise<WorkspaceFields | null>;
/**
* Write the metadata record iff its stored generation matches.
*
* Same optimistic-concurrency contract as NamespaceStore.casSet: a
* missing record (and a legacy record without the field) counts as
* generation 0, so create-if-absent is `expectedGeneration = 0`.
* Resolves true when the write landed, false on conflict.
*/
casSetMeta(workspaceId: string, fields: WorkspaceFields, expectedGeneration: number): Promise<boolean>;
/**
* CAS-write `fields` over the stored record, retrying on conflict.
*
* Ours-wins content (snapshot restore semantics): each attempt
* merges `fields` over the stored record, preserves the stored
* `created_at`, bumps the generation, and retries when another
* writer got there first. Resolves with the record as written.
*/
replaceMeta(workspaceId: string, fields: WorkspaceFields): Promise<WorkspaceFields>;
/**
* Delete everything this store holds for one workspace.
*
* Deleting a workspace calls this and closing one does not, which is
* what lets a daemon's workspaces survive a restart. Each plane is
* cleared through its own store, then every provider involved forgets
* the workspace (its metadata record and the handles it keeps for the
* id), so a workspace created later under the same id starts empty.
*/
drop(workspaceId: string): Promise<void>;
/** Release connections held by this provider and its overrides. */
close(): Promise<void>;
private overrides;
protected abstract makeNamespace(workspaceId: string): NamespaceStore;
protected abstract makeObserver(workspaceId: string): ObserverStore;
protected abstract makeSessions(workspaceId: string): NamespaceStore;
protected abstract makeJobs(workspaceId: string): JobStore;
protected abstract readMeta(workspaceId: string): Promise<WorkspaceFields | null>;
protected abstract casWriteMeta(workspaceId: string, fields: WorkspaceFields, expectedGeneration: number): Promise<boolean>;
protected abstract forgetSelf(workspaceId: string): Promise<void>;
protected abstract closeSelf(): Promise<void>;
}
//# sourceMappingURL=base.d.ts.map