fix(cache): honor entry expiry in CacheManager.exists() memory fallback

Merged
0X
4mo ago
+37-2

Summary

  • The in-memory branch of CacheManager.exists() (frontend/lib/cache.ts) returned !!entry without checking expiresAt.
  • Both get() and getAndRemoveIfMatch() already drop expired entries, so exists() could report a key as present while get() returns null for the same key — an inconsistent contract.
  • A caller that uses exists() as a gate (e.g. isAutocompleteCacheExists in lib/actions/autocomplete/cache.ts) would treat a stale entry as live and skip refreshing it.
  • Fix mirrors the expiry check in get(): delete the expired entry and return false. The Redis branch is unchanged (server-side TTL already handles expiry).
  • Exported CacheManager so the in-memory contract can be unit-tested without a Redis server, and added regression tests.
// before
const entry = this.memoryCache.get(key);
return !!entry;

// after
const entry = this.memoryCache.get(key);
if (!entry) return false;
if (entry.expiresAt && entry.expiresAt < Date.now()) {
  this.memoryCache.delete(key);
  return false;
}
return true;

Verification

pnpm test
# tests 117  # pass 117  # fail 0

New tests: tests/cache-exists-expiry.test.ts (expired -> false and agrees with get(); live -> true).


[!NOTE]
Low Risk
Small, localized cache contract fix with tests; no auth or data-model changes, and Redis behavior is untouched.

Overview
Aligns the in-memory CacheManager.exists() path with get() by treating past-expiresAt entries as absent: delete the stale entry and return false, instead of reporting presence from a non-expired check. Redis exists() is unchanged (TTL still handled server-side).

CacheManager is now exported so the in-memory path can be unit-tested without Redis. New tests in cache-exists-expiry.test.ts cover expired vs live keys and that exists() matches get().

This fixes callers such as isAutocompleteCacheExists that gate refresh on exists()—they could previously see a key as live while get() returned null when REDIS_URL is unset (dev/local memory cache).

Reviewed by Cursor Bugbot for commit c6d8fb9a02cbb501086e7f163f196c4a4ab7287b. Bugbot is set up for automated code reviews on this repo. Configure here.