Caching
Why this app has its own keyed cache instead of Next's unstable_cache.
Why not unstable_cache
createKeyedCache (src/lib/cache/keyed-cache.ts:22) exists because unstable_cache’s tagsoption is fixed at definition time and can’t be templated per call argument. The module comment is explicit about this being the actual bug it fixes:
// Exists because `unstable_cache`'s `tags` option is fixed at
// definition time and can't be templated per call argument — passing a
// per-key tag string there silently does nothing, so a `revalidateTag` at
// write time never matches anything cached under it (the bug this module
// fixes). Here, invalidation deletes the exact key directly, so it always
// works.A TTL (DEFAULT_TTL_MS = 30_000, src/lib/cache/keyed-cache.ts:18) is kept as a safety net in case a write path is ever added without remembering to call invalidate, but the actual invalidation path (below) never relies on the TTL to be timely.
What it caches
Two read-heavy, per-key lookups use it today:
getEventBySlugPublic(src/lib/data/events.ts:151), backed byeventBySlugPublicCache(src/lib/data/events.ts:141), keyed by slug — the public guest event page’s own read, hit on every guest visit but only changing when a host saves.getHostProfilePublic(src/lib/data/host-profile.ts:58), backed byhostProfilePublicCache(src/lib/data/host-profile.ts:40), keyed by host id — the public host profile card shown on guest event pages.
Invalidation on save
Each cache is invalidated by name at its own write path, precisely for the one key that changed — never a blanket clear. revalidateEventCache (src/lib/data/events.ts:180) calls eventBySlugPublicCache.invalidate(slug) alongside the Next revalidatePath calls for the guest and dashboard routes. The host profile cache is invalidated the same way at both of its write paths: updateHostProfileFields (src/lib/data/host-profile.ts:82) and setHostAvatarUrl (src/lib/data/host-profile.ts:93) each call hostProfilePublicCache.invalidate(hostId) right after their own Supabase write succeeds.
Good to know
src/lib/rate-limit.ts: the cache is an in-memory Map, one per server instance, so a write handled by one instance won’t invalidate another instance’s copy until that entry’s TTL expires there — at most a few seconds of staleness on other instances at this app’s current scale.