Invalidation & Expiration
A cached function returned by defineCachedFunction exposes three methods for purging or refreshing its entries: .invalidate(), .expire(), and .resolveKeys(). Each takes the same arguments as the cached function. Standalone helpers cover the case where you don't have a reference to the cached function.
Invalidate
.invalidate() removes cached entries across all base prefixes. The next call re-invokes the function and waits for a fresh value.
import { defineCachedFunction } from "ocache";
const getUser = defineCachedFunction(async (id: string) => db.users.find(id), {
name: "getUser",
maxAge: 60,
getKey: (id) => id,
});
await getUser("user-123"); // resolves and caches
// e.g. after the user updates their profile
await getUser.invalidate("user-123");
await getUser("user-123"); // re-invokes the function, waits for the fresh value
Use the standalone invalidateCache() when you don't hold a reference to the cached function — for example from a webhook or a different module. Pass the same key options (name, getKey, and group / base if you customized them):
import { invalidateCache } from "ocache";
await invalidateCache({
options: { name: "getUser", getKey: (id: string) => id },
args: ["user-123"],
});
name, getKey, group, and base you cached with, or they'll target a different key and no-op.Expire (SWR refresh)
Where .invalidate() removes an entry entirely (the next call must wait for a fresh value), .expire() only marks it stale. With SWR enabled, the stale value keeps being served — still bounded by the originally configured staleMaxAge window — while the next access triggers a background refresh:
const getUser = defineCachedFunction(async (id: string) => db.users.find(id), {
name: "getUser",
maxAge: 60,
staleMaxAge: 300,
swr: true, // required to actually serve stale values
getKey: (id) => id,
});
// Next reader gets the stale value instantly; a refresh runs in the background
await getUser.expire("user-123");
swr: true, an expired entry is re-resolved in the foreground, so .expire() behaves much like .invalidate() for the next reader (they wait for a fresh value).The standalone expireCache() mirrors invalidateCache(). Pass the same maxAge / swr / staleMaxAge options you cache with, so the entry's remaining storage TTL is preserved rather than extended:
import { expireCache } from "ocache";
await expireCache({
options: {
name: "getUser",
getKey: (id: string) => id,
maxAge: 60,
swr: true,
staleMaxAge: 300,
},
args: ["user-123"],
});
.expire() when you want a smooth refresh with no blocking gap for readers. Reach for .invalidate() only when the next reader must get a guaranteed-fresh value.Resolving keys
For advanced use cases — inspecting entries, custom storage operations — .resolveKeys() returns the raw storage keys for a set of arguments (one per base prefix):
const keys = await getUser.resolveKeys("user-123");
// ["/cache:functions:getUser:user-123.json"]
The standalone resolveCacheKeys() does the same without a function reference (again, pass matching key options):
import { resolveCacheKeys, useStorage } from "ocache";
const keys = await resolveCacheKeys({
options: { name: "getUser", getKey: (id: string) => id },
args: ["user-123"],
});
for (const key of keys) {
const entry = await useStorage().get(key);
// ...inspect or manipulate the raw entry
}
See Storage for the underlying store, and HTTP Handlers for invalidating cached responses.