
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
@danmat/query-cache
Advanced tools
RFC 10008-correct caching for the HTTP QUERY method: cache keys derived from the request body, plus a tiny in-memory cache. Zero dependencies.
RFC 10008-correct caching for the HTTP QUERY method. A QUERY's identity lives in its body, not its URL — so a correct cache key must incorporate the request content. This library derives such keys and ships a tiny in-memory cache built on them.
Zero dependencies. Fully typed. Isomorphic (Node 18+, Deno, Bun, browsers, edge — anywhere Web Crypto exists).
import { QueryCache } from "@danmat/query-cache";
const cache = new QueryCache({ maxEntries: 500 });
const res = await cache.wrap(
{ url: "https://api.example.com/search", body, headers },
() => query(url, { body, headers }), // your fetcher, only called on a miss
);
RFC 10008 says QUERY responses are cacheable, but with a catch:
The cache key for a QUERY request MUST incorporate the request content and related metadata.
Every existing HTTP cache keys on the URL. For QUERY, two requests to the same URL with different bodies are different queries — key on the URL alone and you'll serve one query's results for another. This library does the body-aware keying the spec requires.
npm install @danmat/query-cache
queryCacheKey(input, options?): Promise<string>Derives a stable, collision-resistant SHA-256 key that incorporates the method, normalized URL (query params sorted), content type, any configured Vary headers, and the request body bytes. Accepts either a Request or a plain { url, method?, body?, headers? } descriptor.
const key = await queryCacheKey({
url: "https://api.example.com/search",
body: JSON.stringify({ filter: { status: "active" } }),
headers: { "content-type": "application/json" },
});
// "9f2c…" — same bytes ⇒ same key; different body ⇒ different key
| Option | Type | Description |
|---|---|---|
varyHeaders | string[] | Extra request headers to fold into the key. content-type is always included. |
normalizeBody | (bytes, contentType) => Uint8Array | Canonicalize the body before hashing (e.g. sorted-key JSON) so semantically-equal bodies collapse to one key. |
class QueryCacheA minimal in-memory cache keyed by queryCacheKey. Honors Cache-Control: no-store and max-age, with optional LRU eviction and a default TTL. Responses are cloned on store and retrieval, so cached bodies stay readable.
const cache = new QueryCache({ maxEntries: 1000, ttl: 60_000 });
await cache.store(input, response); // respects no-store / max-age
const hit = await cache.match(input); // Response clone, or undefined
const res = await cache.wrap(input, fetch); // match-or-fetch-and-store
await cache.delete(input);
cache.clear();
cache.size; // number of live entries
Constructor options extend the key options above plus maxEntries, ttl (ms), and now (clock injection for testing).
SubtleCrypto.digest global, with a node:crypto fallback for older Node — no dependencies either way.FormData bodies aren't recommended as cache inputs — their multipart boundary is randomized, so they won't produce stable keys. Prefer JSON/text/SQL payloads (which QUERY is designed for), or supply normalizeBody.@danmat QUERY suite@danmat/query-fetch — client for the QUERY method.@danmat/accept-query — parse/build/negotiate the Accept-Query header.@danmat/query-cache — body-aware response caching (you are here).@danmat/query-server — server-side request validation & negotiation.▶️ See them work together: query-suite-example — a runnable demo using all four, with a 🌐 live playground.
MIT © Dan Matthew
FAQs
RFC 10008-correct caching for the HTTP QUERY method: cache keys derived from the request body, plus a tiny in-memory cache. Zero dependencies.
The npm package @danmat/query-cache receives a total of 1 weekly downloads. As such, @danmat/query-cache popularity was classified as not popular.
We found that @danmat/query-cache demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.