[]previous and next page

Caching: the KV store, the page cache and the data cache

Everything that keeps state between requests (the page cache, the data cache, sessions and rate limits) is built on one interface, KVStore, with get, set,…

For agentsUpdated

Everything that keeps state between requests (the page cache, the data cache, sessions and rate limits) is built on one interface, KVStore, with get, set, delete, list and increment. A value is JSON data. A TTL (ttlSeconds) expires an entry. increment sets its TTL when it creates the key.

Store Where Notes
createMemoryKVStore({ maxEntries, maxValueBytes }) @shadow-js/dusk/server In-process, least recently used. Default 10 000 entries and 1 MiB per value.
createFileKVStore({ directory }) @shadow-js/dusk/node One JSON file per key, written atomically. For development and a single server.
createKvCacheStore, createKvSessionStore, createKvRateLimitStore @shadow-js/dusk/server Adapters from a KVStore to the page cache, sessions and rate limits.

Pass a store to the handler to keep the page cache in it: createHandler({ cache: { kv } }). The data cache uses the same store when one is given, and a memory store otherwise. Sessions and rate limits take the adapter you pass to them.

cacheData(fn, { key, tags, revalidate | cacheLife }) requires a key and an explicit lifetime. The key is an array of plain data, stored in the query key format (hashKey from @shadow-js/query), so equal data names the same entry whatever the order of its object properties. revalidate is in seconds: the value is fresh for that long, and the stale window is as long again (the expiry is twice revalidate). A cacheLife name is a preset (seconds, minutes, hours, days, weeks, max) or one of yours from the file. Past the fresh window a stale value is returned at once while one background run refreshes it. An error is never cached, a value that is not JSON is a TypeError, and during draft mode the function runs every time.

revalidateTag(tag) removes the page-cache entries and the data-cache entries that carry the tag. cachedFetch(url, init, options) caches a public GET request the same way. It refuses authorization, cookie and proxy-authorization headers, because a shared cache must never hold one user's answer.

Server functions choose the cache-control of a successful answer: serverFn({ method: "GET", cacheControl: { visibility: "public", maxAge: 60, staleWhileRevalidate: 300 } }, handler). The default is no-store. A public answer is only allowed for a GET function, and it becomes private for a request that carries cookies or authorization. vary lists the request headers the answer depends on, and profile takes the stale and revalidate times of a cacheLife profile. Errors are always no-store.