/** * Filesystem cache for {@link RemoteCatalogSource}. * * Cache layout (default `/catalog/`, see `defaultCatalogCacheDir`): * * / * index.json — JSON map of metadata entries with TTL bookkeeping * tarballs/.tgz — content-addressed tarball blobs (SHA256-verified) * * Two caches live in `index.json`: * * - **resolve cache** — keyed by canonical ref (`/@`), * value is the {@link CatalogAsset} or `null` (negative cache for missing refs) * plus a `fetchedAt` timestamp. * - **list cache** — keyed by a deterministic stringified filter, * value is the array of {@link CatalogAsset} plus a `fetchedAt` timestamp. * * Tarball blobs are cached on disk by SHA256; the SHA256 itself acts as the * integrity tag, so no separate TTL is needed — content-addressed blobs never * become stale. * * Concurrency: writes go through atomic temp-file rename to keep readers consistent. * Multiple processes writing to the same cache dir is safe at the per-key level * (last writer wins) but readers may see momentarily stale data — acceptable * for a CLI cache. * * @docLink packages/library/api-reference#catalog-cache */ import type { CatalogAsset, CatalogAssetFilter } from "@skaile/workspaces/plugins"; /** * One entry in the resolve cache. `value` is `null` to negatively-cache misses. * * @docLink packages/library/api-reference#catalog-cache */ export interface ResolveCacheEntry { fetchedAt: number; value: CatalogAsset | null; } /** * One entry in the list cache. `key` is a stable string derived from the * filter; `items` is the response array. * * @docLink packages/library/api-reference#catalog-cache */ export interface ListCacheEntry { fetchedAt: number; items: CatalogAsset[]; } /** * Persisted shape of `index.json`. * * @docLink packages/library/api-reference#catalog-cache */ export interface CatalogCacheIndex { /** Schema version — bumped on incompatible layout changes. */ version: 1; /** Resolve cache by canonical ref. */ resolve: Record; /** List cache by filter key. */ list: Record; } /** * Options for {@link CatalogCache}. * * @docLink packages/library/api-reference#catalog-cache */ export interface CatalogCacheOptions { /** Cache directory. Default: `/catalog` (see `defaultCatalogCacheDir`). */ dir?: string; /** TTL in milliseconds. `0` disables network and forces cache-only reads. */ ttlMs: number; /** Override clock for tests. */ now?: () => number; } /** * Catalog metadata cache dir: `/catalog`. Migrates the pre-consolidation * `~/.skaile/catalog-cache/`. NOTE: this now honours `SKAILE_CACHE_DIR`/`SKAILE_HOME` * (it previously keyed off `os.homedir()` directly) — see MIGRATION.md. */ export declare function defaultCatalogCacheDir(): string; /** * Filesystem-backed cache for catalog metadata + tarballs. * * Per-key freshness is computed against {@link CatalogCacheOptions.ttlMs}. When * `ttlMs === 0` the cache is treated as **air-gapped** — every entry is * considered valid forever, and the only way to refresh is an explicit * {@link CatalogCache.invalidateAll} call (driven by `skaile update`). * * @docLink packages/library/api-reference#catalog-cache */ export declare class CatalogCache { readonly dir: string; private readonly ttlMs; private readonly nowFn; private index; constructor(opts: CatalogCacheOptions); /** * Return a fresh resolve-cache entry for `ref`, or `null` if absent / stale. * * When `ttlMs === 0` (air-gapped), all entries are considered fresh * regardless of `fetchedAt`. */ getResolve(ref: string): ResolveCacheEntry | null; /** * Return a stale resolve-cache entry regardless of TTL — for stale-while-revalidate. */ getResolveStale(ref: string): ResolveCacheEntry | null; /** Persist a resolve-cache entry (use `null` to negatively cache misses). */ setResolve(ref: string, value: CatalogAsset | null): void; /** * Return a fresh list-cache entry for `filter`, or `null` if absent / stale. */ getList(filter?: CatalogAssetFilter): ListCacheEntry | null; /** Return a stale list-cache entry regardless of TTL — for stale-while-revalidate. */ getListStale(filter?: CatalogAssetFilter): ListCacheEntry | null; /** Persist a list-cache entry. */ setList(filter: CatalogAssetFilter | undefined, items: CatalogAsset[]): void; /** Absolute path where a tarball with `sha256` would be cached. */ tarballPath(sha256: string): string; /** Read a cached tarball from disk if present, otherwise `null`. */ readTarball(sha256: string): Uint8Array | null; /** Persist a tarball blob to disk (atomic write). */ writeTarball(sha256: string, bytes: Uint8Array): void; /** * Wipe all cached metadata (resolve + list). Tarballs are content-addressed * and remain valid — they are not invalidated. * * Called by `skaile update`. */ invalidateAll(): void; /** * Wipe all cached metadata **and** delete tarball blobs. Used for full reset. */ invalidateEverything(): void; /** Return whether `ttlMs` is zero (air-gapped mode). */ get airGapped(): boolean; private ensureDir; private indexPath; private loadIndex; private writeIndex; } /** * Stable string key for a {@link CatalogAssetFilter}. Sorts keys so semantically * equivalent filters share a cache slot. */ export declare function filterKey(filter?: CatalogAssetFilter): string; /** * Compute the SHA-256 digest of `bytes` as a lowercase hex string. * * Used by {@link RemoteCatalogSource.fetchTarball} to verify integrity of * downloaded tarballs (spec invariant: "Hash pinning ... Mismatch = hard fail"). * * @docLink packages/library/api-reference#catalog-cache */ export declare function sha256Hex(bytes: Uint8Array): string; //# sourceMappingURL=cache.d.ts.map