Skip to content

szmarczak/http-cache

Repository files navigation

@szmarczak/http-cache

RFC 9111-compliant client cache implementation.

This software has been developed without the use of Artifical Intelligence. Pull Requests with artificially generated code are rejected.

Deprecated functionality is not implemented and will never be.

Works with runtimes implementing either Node Stream API or Web Stream API. Requires crypto.randomUUID and Promise.withResolvers.

This software is work in progress

This software is work in progress. It needs tests. Indexing and partial content support is under consideration.

Benchmarks (Node.js v25.2.1)

Benchmarks (+/- <1%) on AMD 5600:

cache.get:        450k req/s
cache.onResponse: 135k req/s
fetch with cache: 130k req/s
raw refresh:       88k req/s
fetch refresh:     42k req/s

Legend:

  • cache.get - retrieve from cache,
  • cache.onResponse - revalidate & save,
  • fetch with cache - retrieve from cache using wrapped fetch,
  • raw refresh - clear cache, save to cache, retrieve from cache,
  • fetch refresh - raw refresh but using wrapped fetch.

Note that the raw benchmarks are an upper bound (this is a stress test). In a real application, there's lots of I/O going on, so expect the actual cache performance of at least 42k req/s (130k req/s is an upper bound).

Caveats

  • Trailers are not supported.
  • Partial content is not yet implemented.
  • no-cache=#field-name, private=#field-name response syntax is understood as the unqualified no-cache and private respectively.
  • Non-compliant quoted-string variants are accepted (example: max-age="4").
  • no-transform has no effect, the cache never transforms anything.
  • Duplicate cache-control directives result in the header being parsed as no-store.
  • Cache extensions are not supported.
  • The backing storage must be used by only a single instance of HttpCache. If multiple instances use the same storage, this WILL cause breakage.

Current limitations

The underlying storage is a simple Map<string, json> (accepts async variant for disk storage). It does not provide a TTL mechanism, therefore a LRU cache is strongly recommended.

Cache groups, clear-site-data: cache and content negotiation require indexing and concurrency handling to prevent race conditions.

If you need content negotiation, use a different cache for every type of negotiated content.

Example

See fetch.mts and example.mts.

Development

Requires the following types:

  • ReadableStream
  • ReadableStreamDefaultReader
  • ReadableByteStreamController

In this case they are pulled from @types/node.

allowImportingTsExtensions should be set to true in tsconfig.json. This allows Node to run in watch mode with erasable TypeScript syntax.

About

WIP 🍪

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published