Files
Codewalkers/apps/server/review/diff-cache.ts
Lukas May a50ee01626 test: Add DiffCache unit tests and getPhaseReviewDiff cache integration tests
Creates diff-cache.ts module with generic DiffCache<T> class (TTL, prefix
invalidation, env-var configuration) and exports phaseMetaCache / fileDiffCache
singletons. Wires cache into getPhaseReviewDiff via getHeadCommitHash on
BranchManager. Adds 6 unit tests for DiffCache and 5 integration tests
verifying cache hit/miss behaviour, prefix invalidation, and NOT_FOUND guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 20:06:28 +01:00

49 lines
1.4 KiB
TypeScript

/**
* DiffCache — in-memory TTL cache for git diff results.
*
* Keyed by `phaseId:headHash` (or `phaseId:headHash:filePath` for per-file diffs).
* TTL defaults to 5 minutes, configurable via REVIEW_DIFF_CACHE_TTL_MS env var.
* Prefix-based invalidation clears all entries for a phase when a new commit lands.
*/
interface CacheEntry<T> {
value: T;
expiresAt: number;
}
export class DiffCache<T> {
private store = new Map<string, CacheEntry<T>>();
private ttlMs: number;
constructor(ttlMs: number) {
this.ttlMs = ttlMs;
}
get(key: string): T | undefined {
const entry = this.store.get(key);
if (!entry) return undefined;
if (Date.now() > entry.expiresAt) {
this.store.delete(key);
return undefined;
}
return entry.value;
}
set(key: string, value: T): void {
this.store.set(key, { value, expiresAt: Date.now() + this.ttlMs });
}
invalidateByPrefix(prefix: string): void {
for (const key of this.store.keys()) {
if (key.startsWith(prefix)) this.store.delete(key);
}
}
}
const TTL = parseInt(process.env.REVIEW_DIFF_CACHE_TTL_MS ?? '300000', 10);
// Typed as unknown here; the actual type constraint is enforced at call sites
// in phase.ts where PhaseMetaResponse / FileDiffResponse are inferred.
export const phaseMetaCache = new DiffCache<unknown>(TTL);
export const fileDiffCache = new DiffCache<unknown>(TTL);