Files
Codewalkers/apps/server/review/diff-cache.ts
Lukas May f1af9e5d7a chore: resolve merge conflicts for DiffCache test task
Resolves add/add conflict in diff-cache.ts (kept typed PhaseMetaResponse/
FileDiffResponse interfaces from HEAD over unknown-typed singletons from test
branch) and content conflict in phase.ts (kept both phaseMetaCache and
fileDiffCache imports; removed auto-merged duplicate firstClone/headHash/
cacheKey/cached declarations and unreachable empty-projects guard).

Also cleans auto-merged duplicate getHeadCommitHash in orchestrator.test.ts
and simple-git-branch-manager.ts.

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

71 lines
2.0 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.
*/
import type { FileStatEntry } from '../git/types.js';
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);
}
}
}
// ---------------------------------------------------------------------------
// Response shapes (mirror the return types of getPhaseReviewDiff / getFileDiff)
// ---------------------------------------------------------------------------
export interface PhaseMetaResponse {
phaseName: string;
sourceBranch: string;
targetBranch: string;
files: FileStatEntry[];
totalAdditions: number;
totalDeletions: number;
}
export interface FileDiffResponse {
binary: boolean;
rawDiff: string;
}
// ---------------------------------------------------------------------------
// Singleton instances — TTL is read once at module load time
// ---------------------------------------------------------------------------
const TTL = parseInt(process.env.REVIEW_DIFF_CACHE_TTL_MS ?? '300000', 10);
export const phaseMetaCache = new DiffCache<PhaseMetaResponse>(TTL);
export const fileDiffCache = new DiffCache<FileDiffResponse>(TTL);