/** * Stamp-keyed caches for the analysis artifacts a serving process reads repeatedly. * * The artifacts under `.openlore/analysis/` are written by OTHER processes — * `openlore analyze`, `openlore generate`, the watcher's own flush. A cache keyed on * the project directory alone therefore goes stale silently and stays stale for the * whole lifetime of a daemon. Every cache here keys on an identity stamp of the file * it holds, so an external rewrite is picked up on the next read and an unchanged * artifact is parsed exactly once. * * These artifacts are also untrusted repository content, and a cache makes that * sharper: what is parsed here is RETAINED. Reads therefore follow the same rules as * the repo's other untrusted-artifact readers (`readCorpusSidecarBounded`, * `readFileConfinedWithStat`) — no symlink following, regular files only, a byte * ceiling enforced on the READ rather than on a prior stat, and an identity check * taken from the same descriptor that produced the bytes. * * Deliberately its own module rather than part of `utils.ts`: `utils.ts` is mocked * wholesale by most handler tests, and a shared read path should not depend on every * one of those mocks listing it. * * Callers pass an absolute path they have already confined to a validated project * directory (every current one builds it as `join(await validateDirectory(dir), * '.openlore', 'analysis', …)`). This module does not re-derive that confinement; it * defends the read itself. * * (spec: ServingCachesInvalidateOnExternalAnalyze, change: optimize-serving-hot-path-caches) */ import { artifactStamp, readArtifactBounded, type StampedArtifact } from '../../../utils/bounded-artifact-read.js'; export { artifactStamp, readArtifactBounded, type StampedArtifact }; import { type PartialArtifactName } from '../../runtime/partial-index.js'; /** * Read-and-parse a JSON artifact at most once per version of that artifact. * * `derive` runs only on a stamp miss; its result is cached against the stamp of the * bytes that produced it. A read failure, a parse failure, an oversized file, or a * file that moved mid-read caches nothing and returns `null`, so a half-written * artifact is retried rather than pinned. * * `derivationKey` namespaces the entry: two callers deriving DIFFERENT shapes from the * same file must not read each other's cached value. Derived values are shared across * callers and MUST be treated as read-only. */ export declare function readJsonArtifactCached(path: string, derivationKey: string, derive: (parsed: unknown) => T | null): Promise; /** * The parsed `dependency-graph.json` for a project, or `null` when it is absent or * structurally unusable. * * One shared entry point rather than two call-site derivations, because two callers * caching different derivations of the SAME repo-sized artifact would retain two * copies of it — and, worse, would disagree about validation: whichever ran first * would decide whether the other saw a shape-checked graph or a raw one. A * valid-but-partial artifact (`{}`, or an interrupted analyze) parses fine but has no * `nodes`/`edges` arrays, so it is rejected here for every caller. * * The returned object is SHARED and must be treated as read-only. * (change: optimize-serving-hot-path-caches) */ export declare function readDependencyGraphCached(path: string): Promise; /** * The parsed dependency graph for a project, falling back to a live partial first-run index * when no published one exists yet (change: refine-first-run-partial-serving). * * Ordered so a repository with a published index pays nothing: the published read runs exactly * as before, and only its `null` — meaning the artifact is absent or unusable — reaches for the * partial one. When the fallback answers, the request is marked so `dispatchTool` attaches the * completeness receipt; a caller can never receive these bytes without being told what they are. */ export declare function readDependencyGraphOrPartial(analysisDir: string, artifactName: string): Promise; /** * The raw text of one analysis artifact, falling back to a live partial index the same way. * * Used by readers that parse an artifact themselves rather than through the shared cache. */ export declare function readAnalysisArtifactOrPartial(analysisDir: string, artifact: PartialArtifactName): Promise; /** Test-only: drop every stamp-keyed sibling-artifact entry. */ export declare function _resetJsonArtifactCacheForTesting(): void; /** Test-only: how many artifacts the sibling-artifact cache currently holds. */ export declare function _jsonArtifactCacheSizeForTesting(): number; /** Test-only: the bounded, descriptor-stamped read behind every cached artifact. */ export declare const _readArtifactBoundedForTesting: typeof readArtifactBounded; //# sourceMappingURL=artifact-cache.d.ts.map