@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
112 lines • 4.73 kB
JavaScript
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import { SystemClock } from "../../utils/clock.js";
export class IndexCacheStore {
/** The clock every listing deadline of this store is set and read on. */
clock;
/** @param clock the clock listings expire on; undefined means the real one. */
constructor(clock = new SystemClock()) {
this.clock = clock;
}
/** Apply this index's ownership rules to a refill snapshot. */
scopeSnapshot(snapshot) {
return snapshot;
}
/** Read retained rows by path, omitting missing entries. */
async getMany(vfsPaths) {
const rows = new Map();
for (const path of new Set(vfsPaths)) {
const entry = (await this.get(path)).entry;
if (entry != null)
rows.set(path, entry);
}
return rows;
}
/** Atomically replace an existing row without renewing its listing; custom stores may decline. */
replaceIfUnchanged(_path, _predecessor, _entry) {
return Promise.resolve(false);
}
/**
* 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) {
return Promise.resolve();
}
/** Token captured before fetching listings, including descendant seeds. */
refillToken() {
throw new Error('refillToken is not implemented');
}
/** Expire complete parent listings contradicted by the observed immediate child keys. */
invalidateMissing(_paths) {
throw new Error('invalidateMissing is not implemented');
}
/** null rejects an older refill without reporting any deletions. */
refillDir(_path, _entries, _token, _expiredAt, _options = {}) {
throw new Error('refillDir is not implemented');
}
/**
* 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.
*/
async setPartialDir(vfsPath, entries, _expiredAt) {
await this.invalidateDir(vfsPath);
const stem = vfsPath.replace(/\/$/, '');
for (const [name, entry] of entries)
await this.put(`${stem}/${name}`, entry);
}
/**
* 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) {
return false;
}
/**
* 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) {
return Promise.resolve(true);
}
/**
* 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() {
return Promise.resolve();
}
}
//# sourceMappingURL=store.js.map