Skip to content

createArtifactCache

createArtifactCache(options): ArtifactCache

Defined in: packages/app-system/src/fs/artifact-cache.ts:219

Cross-process cache for expensive setup output — a compiled reference program, a generated corpus — keyed by a hash of everything the artifact depends on rather than by an author-chosen id, so a stale artifact is impossible rather than merely unlikely.

Concurrency is settled in two layers, and only the second one is load-bearing:

  1. A FileLock beside the destination keeps concurrent callers from compiling the same thing at once. It is acquired best-effort with a lockWaitMs budget, so a lock left behind by a killed builder costs one wait and one duplicated build instead of hanging the run forever.
  2. The build goes to a temp directory and is renamed into place. Rename is atomic on POSIX and within a Windows volume, so however many callers build, exactly one artifact exists and every caller returns the same path.

ArtifactCacheOptions

Root, run scoping, hit reporting and the lock budget. See ArtifactCacheOptions.

ArtifactCache

Compile a reference program once, reuse it forever

```ts
const cache = createArtifactCache({ root: "node_modules/.cache/my-tool" });
const source = await readFile("bench/reference.cpp", "utf8");
const directory = await cache.ensure(
{ name: "reference C++", inputs: [source, "-O3"], scope: [compilerVersion] },
async (staging, signal) => {
await run("g++", ["-O3", "-o", join(staging, "reference"), sourcePath], {
signal,
});
},
);
const program = join(directory, "reference");
```
Changing the source text or `-O3` changes the identity, so the next call
rebuilds; nothing has to remember to bump a version.

Scope an artifact to one run, and sweep it afterwards

```ts
const cache = createArtifactCache({ root, runId, onResolved: (r) =>
report.data({ artifact: r.key.name, cacheHit: r.cacheHit }),
});
await cache.ensure(
{ name: "corpus", inputs: [spec], lifetime: "run" },
generateCorpus,
);
// The owner sweeps: a crashed child cannot be asked what it left behind.
await rm(cache.runRoot!, { recursive: true, force: true });
```