@blaze-cache/fetch 0.2.0-beta → 0.2.1-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,9 +10,12 @@ stale-while-revalidate and an `x-blaze-cache: HIT | MISS` marker.
10
10
  ## Install
11
11
 
12
12
  ```sh
13
- npm install @blaze-cache/fetch @blaze-cache/core
13
+ npm install @blaze-cache/fetch@beta @blaze-cache/core@beta
14
14
  ```
15
15
 
16
+ `@beta` is npm's dist-tag for the prerelease; drop it to install the last stable
17
+ release.
18
+
16
19
  ## Quick start
17
20
 
18
21
  ```ts
@@ -45,20 +48,33 @@ window.fetch = fetch; // now every request in the app is cache
45
48
  * **Only `GET` is cached** — pass `methods: ['GET', 'HEAD']` to include `HEAD`. Everything
46
49
  else (including errors from uncached methods) always goes to the network.
47
50
  * **`Cache-Control` is honoured on both sides** when `cacheControl` is on (the default):
48
- `max-age` overrides `ttlMs`, `Age` is deducted, `no-store`/`no-cache` on the request skip
49
- the read, and the same directives on the response stop it being stored.
51
+ on the request, `no-store`/`no-cache` and `max-age=0` skip the read; on the response,
52
+ `max-age` overrides `ttlMs`, `Age` is deducted, and `no-store`/`no-cache` — the per-field
53
+ `no-cache="set-cookie"` form included — stop it being stored.
54
+ `must-revalidate`/`proxy-revalidate` gets no stale window, however short the fresh one.
55
+ * **Identical concurrent requests coalesce** — one caller leads and the rest replay the
56
+ record it stored, so a burst of the same `GET` opens one connection. Only cacheable
57
+ requests lead, callers that demanded the network are never joined, and a leader that
58
+ fails opens the gate over an empty cache so its joiners fetch in turn.
50
59
  * **Only successful responses are stored** — the default `shouldCache` keeps `2xx`; replace
51
60
  it to widen or narrow that.
52
61
  * **`Authorization` participates in the default key** (hashed, never stored verbatim), so a
53
62
  personalized response is never replayed to a different user. Tune with `varyHeaders`.
63
+ * **The response's own `Vary` is honoured** — `Vary: *` is never stored (RFC 9111 §3), and
64
+ a response varying on a header you have not put in `varyHeaders` is left uncached rather
65
+ than replay a variant to the wrong caller. Server headers missing from `varyHeaders`?
66
+ That is the safe default working as intended — list them to opt in. The check runs
67
+ before *every* store, `cacheControl: false` included: variant correctness is not a
68
+ freshness preference.
54
69
  * **A hit is a real `Response`** — status, status text, headers, body, `url` after a
55
70
  redirect and `redirected` are replayed exactly, so your code cannot tell the difference
56
71
  apart from the marker header.
57
72
  * **Binary, `Blob` and chunked bodies are first-class** — the payload is buffered as raw
58
73
  bytes whether it arrived as a file, a `ReadableStream` or plain text, so an image
59
74
  replays byte-for-byte with its `content-type` intact and `blob().type`/`blob().size`
60
- still correct. A streamed (chunked) response is assembled *before* your `Response` is
61
- handed back, so a hit can never half-load.
75
+ still correct. Buffering runs on a teed clone *after* your `Response` is handed back, so
76
+ a streaming body is never held up waiting for the cache — and because the record is
77
+ complete before it is written, a hit can never half-load.
62
78
  * **Transport headers are corrected to the bytes stored** — `fetch` decodes
63
79
  `content-encoding` for you, so the record drops `content-encoding` and
64
80
  `transfer-encoding` and rewrites `content-length` to the payload's real size. Without
@@ -66,7 +82,10 @@ window.fetch = fetch; // now every request in the app is cache
66
82
  bytes — which breaks anything that measures a download. `HEAD` keeps its headers: no
67
83
  body was sent, so its `content-length` is what a GET *would* return.
68
84
  * **Failures behave like plain `fetch`** — a rejected network call still rejects; a cache
69
- that cannot store a response never breaks the request that produced it.
85
+ that cannot store a response never breaks the request that produced it. Reads, writes
86
+ and the `shouldCache` callback are all guarded: the first cache-layer failure is
87
+ announced once on the console, then the wrapper keeps working *without* the cache rather
88
+ than warning on every call.
70
89
 
71
90
  ## Options
72
91
 
@@ -150,8 +169,12 @@ pnpm --filter @blaze-cache/fetch test # stubbed network — deterministi
150
169
  pnpm --filter @blaze-cache/fetch test:live # real public API — opt-in, needs the network
151
170
  ```
152
171
 
153
- The live suite calls `api.github.com` (keyless, well under ten requests per run) to prove
154
- that *real* `Cache-Control` headers are read correctly — a stub can only simulate that.
172
+ The live suite calls `api.github.com`, `raw.githubusercontent.com` and
173
+ `jsonplaceholder.typicode.com` — all keyless, and well within GitHub's unauthenticated 60
174
+ requests/hour — to prove that *real* `Cache-Control` and `Vary` headers are read
175
+ correctly; a stub can only simulate that. It also lists each server's vary headers in
176
+ `varyHeaders`, which is exactly the configuration a real deployment needs: a response
177
+ varying on a header the key does not fold in is deliberately left uncached.
155
178
  Every test in it is skipped unless `BLAZE_CACHE_LIVE=1` is set, so the default suite always
156
179
  passes with no network at all.
157
180
 
@@ -1,5 +1,6 @@
1
1
  /**
2
- * What `Cache-Control` (and the related `Age`) say about a request or a response.
2
+ * What `Cache-Control` (and the related `Age`) say about a request or a response — plus the
3
+ * one `Vary` question a keying client must answer before storing anything.
3
4
  *
4
5
  * Package-local on purpose: this wrapper needs the `stale-while-revalidate` directive, which
5
6
  * `@blaze-cache/axios` does not, and each package is free to grow its own directives without
@@ -8,8 +9,10 @@
8
9
  export interface CacheControl {
9
10
  /** `no-store` — neither read nor write the cache. */
10
11
  noStore: boolean;
11
- /** `no-cache` — must not be served without revalidating. */
12
+ /** `no-cache` — must not be served without revalidating, per-field spellings (`no-cache="…"`) included. */
12
13
  noCache: boolean;
14
+ /** `must-revalidate` (or the shared-cache spelling `proxy-revalidate`) — never serve a stale response. */
15
+ mustRevalidate: boolean;
13
16
  /** `max-age=<seconds>`, converted to milliseconds. */
14
17
  maxAgeMs: number | undefined;
15
18
  /** `stale-while-revalidate=<seconds>`, converted to milliseconds. */
@@ -25,6 +28,23 @@ export declare const NO_DIRECTIVES: CacheControl;
25
28
  * ```
26
29
  */
27
30
  export declare function parseCacheControl(value: string | undefined | null): CacheControl;
31
+ /**
32
+ * Whether a response carrying `Vary: <responseVary>` may be stored under a key that already
33
+ * folds in `varyHeaders`.
34
+ *
35
+ * `Vary` names the *request* headers the response's identity depends on — `Cookie`,
36
+ * `Accept-Language`, `Origin`. A cache may only replay a stored response to a request whose
37
+ * keyed headers match, so a response varying on anything **not** folded into the key cannot
38
+ * be keyed correctly, and the only safe verdict is "store nothing": storing anyway would
39
+ * replay one caller's variant — another user's private payload, another locale's page — to
40
+ * the next caller whose unkeyed header happens to differ. `Vary: *` advertises variants
41
+ * that are unknowable by construction and is never cacheable (RFC 9111 §3).
42
+ *
43
+ * An absent, empty or unparsable header varies on nothing and is always storable; a listed
44
+ * name that *is* folded in (case-insensitively, as header names are) makes the response
45
+ * storable.
46
+ */
47
+ export declare function varyIsStorable(responseVary: string | null, varyHeaders: readonly string[]): boolean;
28
48
  /**
29
49
  * `Age: <seconds>` — how long an intermediate cache has been holding the response.
30
50
  *
@@ -1 +1 @@
1
- {"version":3,"file":"cache-control.d.ts","sourceRoot":"","sources":["../src/cache-control.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,qEAAqE;IACrE,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAED,iGAAiG;AACjG,eAAO,MAAM,aAAa,EAAE,YAK1B,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,YAAY,CAsBhF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAInE"}
1
+ {"version":3,"file":"cache-control.d.ts","sourceRoot":"","sources":["../src/cache-control.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,2GAA2G;IAC3G,OAAO,EAAE,OAAO,CAAC;IACjB,0GAA0G;IAC1G,cAAc,EAAE,OAAO,CAAC;IACxB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,qEAAqE;IACrE,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAED,iGAAiG;AACjG,eAAO,MAAM,aAAa,EAAE,YAM1B,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,YAAY,CAiChF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAYnG;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAInE"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * What `Cache-Control` (and the related `Age`) say about a request or a response.
2
+ * What `Cache-Control` (and the related `Age`) say about a request or a response — plus the
3
+ * one `Vary` question a keying client must answer before storing anything.
3
4
  *
4
5
  * Package-local on purpose: this wrapper needs the `stale-while-revalidate` directive, which
5
6
  * `@blaze-cache/axios` does not, and each package is free to grow its own directives without
@@ -9,6 +10,7 @@
9
10
  export const NO_DIRECTIVES = Object.freeze({
10
11
  noStore: false,
11
12
  noCache: false,
13
+ mustRevalidate: false,
12
14
  maxAgeMs: undefined,
13
15
  staleWhileRevalidateMs: undefined,
14
16
  });
@@ -23,6 +25,7 @@ export function parseCacheControl(value) {
23
25
  const result = {
24
26
  noStore: false,
25
27
  noCache: false,
28
+ mustRevalidate: false,
26
29
  maxAgeMs: undefined,
27
30
  staleWhileRevalidateMs: undefined,
28
31
  };
@@ -36,6 +39,18 @@ export function parseCacheControl(value) {
36
39
  else if (directive === 'no-cache') {
37
40
  result.noCache = true;
38
41
  }
42
+ else if (directive.startsWith('no-cache=')) {
43
+ // `no-cache="set-cookie, field2"` — reuse is forbidden until *those fields* have been
44
+ // revalidated, and this cache cannot revalidate individual fields, so it must read as
45
+ // the whole-response spelling. Matching only the bare directive would silently turn
46
+ // this opt-out back into "cacheable".
47
+ result.noCache = true;
48
+ }
49
+ else if (directive === 'must-revalidate' || directive === 'proxy-revalidate') {
50
+ // Two spellings of one rule — never serve a stale response. `proxy-revalidate` is the
51
+ // shared-cache name; a browser cache ignoring it would be just as wrong.
52
+ result.mustRevalidate = true;
53
+ }
39
54
  else if (directive.startsWith('max-age=')) {
40
55
  result.maxAgeMs = seconds(directive.slice('max-age='.length));
41
56
  }
@@ -45,6 +60,36 @@ export function parseCacheControl(value) {
45
60
  }
46
61
  return result;
47
62
  }
63
+ /**
64
+ * Whether a response carrying `Vary: <responseVary>` may be stored under a key that already
65
+ * folds in `varyHeaders`.
66
+ *
67
+ * `Vary` names the *request* headers the response's identity depends on — `Cookie`,
68
+ * `Accept-Language`, `Origin`. A cache may only replay a stored response to a request whose
69
+ * keyed headers match, so a response varying on anything **not** folded into the key cannot
70
+ * be keyed correctly, and the only safe verdict is "store nothing": storing anyway would
71
+ * replay one caller's variant — another user's private payload, another locale's page — to
72
+ * the next caller whose unkeyed header happens to differ. `Vary: *` advertises variants
73
+ * that are unknowable by construction and is never cacheable (RFC 9111 §3).
74
+ *
75
+ * An absent, empty or unparsable header varies on nothing and is always storable; a listed
76
+ * name that *is* folded in (case-insensitively, as header names are) makes the response
77
+ * storable.
78
+ */
79
+ export function varyIsStorable(responseVary, varyHeaders) {
80
+ if (responseVary === null)
81
+ return true;
82
+ const names = responseVary
83
+ .split(',')
84
+ .map((name) => name.trim().toLowerCase())
85
+ .filter((name) => name.length > 0);
86
+ if (names.length === 0)
87
+ return true; // `Vary:` with no names varies on nothing
88
+ if (names.includes('*'))
89
+ return false; // RFC 9111 §3: never usable from a cache
90
+ const keyed = new Set(varyHeaders.map((name) => name.toLowerCase()));
91
+ return names.every((name) => keyed.has(name));
92
+ }
48
93
  /**
49
94
  * `Age: <seconds>` — how long an intermediate cache has been holding the response.
50
95
  *
@@ -1 +1 @@
1
- {"version":3,"file":"cache-control.js","sourceRoot":"","sources":["../src/cache-control.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,iGAAiG;AACjG,MAAM,CAAC,MAAM,aAAa,GAAiB,MAAM,CAAC,MAAM,CAAC;IACvD,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,SAAS;IACnB,sBAAsB,EAAE,SAAS;CAClC,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAgC;IAChE,MAAM,MAAM,GAAiB;QAC3B,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,SAAS;QACnB,sBAAsB,EAAE,SAAS;KAClC,CAAC;IACF,IAAI,CAAC,KAAK;QAAE,OAAO,MAAM,CAAC;IAE1B,KAAK,MAAM,YAAY,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpD,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,CAAC;aAAM,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YACpC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,CAAC;aAAM,IAAI,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAChE,CAAC;aAAM,IAAI,SAAS,CAAC,UAAU,CAAC,yBAAyB,CAAC,EAAE,CAAC;YAC3D,MAAM,CAAC,sBAAsB,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgC;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC;IACrB,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,iGAAiG;AACjG,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"cache-control.js","sourceRoot":"","sources":["../src/cache-control.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,UAAU,EACV,mBAAmB,EAInB,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAgBpB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,mBAAmB,EAC1B,OAAO,GAAE,iBAAsB,GAC9B,UAAU,CAqLZ"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,UAAU,EACV,mBAAmB,EAInB,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAgBpB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,mBAAmB,EAC1B,OAAO,GAAE,iBAAsB,GAC9B,UAAU,CA2TZ"}
package/dist/client.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NO_DIRECTIVES, parseAgeMs, parseCacheControl } from './cache-control.js';
1
+ import { NO_DIRECTIVES, parseAgeMs, parseCacheControl, varyIsStorable } from './cache-control.js';
2
2
  import { defaultCacheKey } from './key.js';
3
3
  import { normalizeInit, resolveMethod, resolveUrl } from './request.js';
4
4
  /** Freshness window when neither the option nor `Cache-Control` says otherwise. */
@@ -43,6 +43,27 @@ export function createBlazeFetch(cache, options = {}) {
43
43
  const swrFallbackMs = typeof swr === 'number' && swr > 0 ? swr : 0;
44
44
  /** Keys with a background refresh already running — one network call per key at a time. */
45
45
  const revalidating = new Set();
46
+ /**
47
+ * Identical requests currently on the wire, keyed by cache key — one promise per key that
48
+ * opens only when the leader's store attempt has fully *settled*, so a joiner can trust
49
+ * whatever it then finds in the cache. See {@link dispatch}.
50
+ */
51
+ const inFlight = new Map();
52
+ /**
53
+ * Whether a cache-layer failure has been reported already.
54
+ *
55
+ * A throwing `cache.get`/`cache.set` or callback must never fail a request the network
56
+ * answered well — the first such failure is announced, then the wrapper keeps working
57
+ * (uncached) in silence rather than spamming the console on every call.
58
+ */
59
+ let warned = false;
60
+ /** The one place a cache-layer exception is allowed to surface: a single console warning. */
61
+ function warnCacheFailure(error) {
62
+ if (warned)
63
+ return;
64
+ warned = true;
65
+ console.warn('[blaze-cache] cache layer failed; continuing without it', error);
66
+ }
46
67
  const keyOf = (url, init) => options.key ? options.key(url, init) : defaultCacheKey(url, init, varyHeaders);
47
68
  async function dispatch(input, init) {
48
69
  const method = resolveMethod(input, init);
@@ -53,30 +74,113 @@ export function createBlazeFetch(cache, options = {}) {
53
74
  // `cacheControl: false` only the former is still obeyed.
54
75
  const control = cacheControl ? parseCacheControl(request.headers.get('Cache-Control')) : NO_DIRECTIVES;
55
76
  const bypassWrite = control.noStore || request.cache === 'no-store';
77
+ // A request `max-age=0` is, per RFC 9111 §5.2.2.1, a demand to revalidate before reuse.
78
+ // This cache has no conditional requests, so the closest honest reading is a full
79
+ // refetch — exactly what `bypassRead` does — rather than replaying the entry untouched.
56
80
  const bypassRead = bypassWrite ||
57
81
  control.noCache ||
82
+ control.maxAgeMs === 0 ||
58
83
  init.forceRefresh === true ||
59
84
  request.cache === 'no-cache' ||
60
85
  request.cache === 'reload';
61
86
  const cacheable = methods.has(method);
62
- if (cacheable && !bypassRead) {
63
- const record = cache.get(key);
64
- if (record) {
65
- const now = Date.now();
66
- // `force-cache` means "use it whatever its age"; otherwise freshness decides.
67
- if (request.cache === 'force-cache' || now <= record.freshUntil) {
68
- return replay(record, 'HIT');
87
+ if (cacheable) {
88
+ if (!bypassRead) {
89
+ const record = read(key);
90
+ if (record) {
91
+ const now = Date.now();
92
+ // `force-cache` means "use it whatever its age"; otherwise freshness decides.
93
+ if (request.cache === 'force-cache' || now <= record.freshUntil) {
94
+ return replay(record, 'HIT');
95
+ }
96
+ if (swrEnabled && now <= record.staleUntil) {
97
+ // Refreshed in the background: the caller is served *now*, the next call a `HIT`.
98
+ revalidate(input, init, key);
99
+ return replay(record, 'STALE');
100
+ }
69
101
  }
70
- if (swrEnabled && now <= record.staleUntil) {
71
- // Refreshed in the background: the caller is served *now*, the next call a `HIT`.
72
- revalidate(input, init, key);
73
- return replay(record, 'STALE');
102
+ }
103
+ // An identical request is already on the wire. Its `Response` cannot be handed over —
104
+ // a body stream can be consumed exactly once, and the leader's own caller is reading
105
+ // it — but the *stored record* is the replayable form of the very same bytes, so the
106
+ // cache doubles as the rendezvous: wait for the leader's write to settle, then replay
107
+ // what it landed. A leader that stored nothing (an unstorable response, a failed
108
+ // write) opens its gate over an empty cache, and the joiner falls through to the
109
+ // network itself — never an unstored response, never a deadlock: gates only ever wait
110
+ // on leaders, and no leader waits on a joiner.
111
+ //
112
+ // Joined only when this call would itself have accepted a cached read. A caller that
113
+ // explicitly demanded the network (`forceRefresh`, `cache: 'reload'`, request
114
+ // `no-cache`/`max-age=0`) is joined *out*: answering it from the cache — however
115
+ // recently written — breaks the promise it made, and it leads below instead.
116
+ if (!bypassRead) {
117
+ const pending = inFlight.get(key);
118
+ if (pending) {
119
+ await pending;
120
+ const shared = read(key);
121
+ // Freshly written, but a pathologically short TTL may have aged it out already.
122
+ if (shared && Date.now() <= shared.freshUntil)
123
+ return replay(shared, 'HIT');
74
124
  }
75
125
  }
76
126
  }
77
- const response = await network(input, init);
78
- if (cacheable && !bypassWrite && shouldCache(response, url, request)) {
79
- await store(response, key, url, request);
127
+ // From here on this call *leads* its key. The gate is registered before the network is
128
+ // touched — otherwise two callers could both miss and both fetch before either
129
+ // registers — and only cacheable, storable requests lead: a `POST` must never be
130
+ // silently coalesced with an identical one, side effects and all.
131
+ const leader = cacheable && !bypassWrite;
132
+ let settle = () => undefined;
133
+ const settled = new Promise((resolve) => {
134
+ settle = resolve;
135
+ });
136
+ if (leader)
137
+ inFlight.set(key, settled);
138
+ /**
139
+ * Opens the gate and retires the leadership — every exit passes through it.
140
+ *
141
+ * Identity-checked: a caller that demanded the network (`forceRefresh`, `reload`) leads
142
+ * too and may have replaced our gate with its own. Deleting whatever sits under `key`
143
+ * would retire *their* leadership while ours still stands, silently dropping the joiners
144
+ * waiting on them.
145
+ */
146
+ const done = () => {
147
+ if (leader && inFlight.get(key) === settled)
148
+ inFlight.delete(key);
149
+ settle();
150
+ };
151
+ let response;
152
+ try {
153
+ response = await network(input, init);
154
+ }
155
+ catch (error) {
156
+ // A failed leader still opens its gate — over an empty cache, so joiners wake and
157
+ // retry the network themselves instead of waiting on a promise that never settles.
158
+ done();
159
+ throw error;
160
+ }
161
+ let keep = false;
162
+ if (leader) {
163
+ try {
164
+ keep = shouldCache(response, url, request);
165
+ }
166
+ catch (error) {
167
+ // A callback that throws must not fail the response the network just delivered.
168
+ warnCacheFailure(error);
169
+ }
170
+ }
171
+ if (keep) {
172
+ // Deliberately fire-and-forget. `store` tees the body with `clone()` — the caller's
173
+ // copy of the stream is untouched — and fully buffers *its* copy before `cache.set`,
174
+ // so nothing about this call's latency depends on the write, and a later read can
175
+ // never race a half-written entry. The gate above, however, opens only once that
176
+ // write has settled: that is what lets a joiner trust the cache it finds.
177
+ void store(response, key, url, request)
178
+ .catch(warnCacheFailure)
179
+ .finally(done);
180
+ }
181
+ else {
182
+ // Nothing will be stored for this call: wake any joiners so they can lead in turn.
183
+ done();
80
184
  }
81
185
  // Marked last, so `shouldCache`/`tags`/`ttlMs` see exactly what the network sent.
82
186
  return mark(response, 'MISS');
@@ -86,13 +190,24 @@ export function createBlazeFetch(cache, options = {}) {
86
190
  if (revalidating.has(key))
87
191
  return;
88
192
  revalidating.add(key);
89
- void dispatch(input, { ...init, forceRefresh: true })
193
+ // The caller's `signal` is deliberately stripped. It belongs to the request that merely
194
+ // *happened* to notice the staleness — and such callers usually abort right after being
195
+ // served (an unmount, a route change), which would abort the refresh and leave the
196
+ // entry stale forever. A background refresh is the wrapper's own work and runs on the
197
+ // wrapper's own terms; `forceRefresh` keeps it from re-serving the stale entry to itself.
198
+ void dispatch(input, { ...init, signal: undefined, forceRefresh: true })
90
199
  // A background refresh must never reject into a caller: the stale entry simply stays
91
200
  // until the next attempt.
92
201
  .catch(() => undefined)
93
202
  .finally(() => revalidating.delete(key));
94
203
  }
95
- /** Buffers the body and writes the record. Returns early when nothing is worth keeping. */
204
+ /**
205
+ * Buffers the body and writes the record. Returns early when nothing is worth keeping.
206
+ *
207
+ * Deliberately fire-and-forget at the call site: the body it reads comes from a `clone()`
208
+ * of the caller's response, so every millisecond it spends buffering is invisible to the
209
+ * caller — and the record is complete (never half-written) by the time `cache.set` runs.
210
+ */
96
211
  async function store(response, key, url, request) {
97
212
  // An opaque response exposes no status, headers or body: there is nothing to store.
98
213
  if (response.status === 0)
@@ -102,6 +217,14 @@ export function createBlazeFetch(cache, options = {}) {
102
217
  // cache has no conditional requests — so neither is worth an entry.
103
218
  if (control.noStore || control.noCache)
104
219
  return;
220
+ // `Vary` decides which *request* headers this response's identity hangs on. Only a
221
+ // response whose every named header is already folded into the cache key may be stored;
222
+ // anything else would be keyed wrongly, and a wrong key replays the wrong variant —
223
+ // another user's `Cookie`, another locale's `Accept-Language`. When we cannot key on a
224
+ // header, the safe answer is not to cache at all. (Checked unconditionally, not only
225
+ // under `cacheControl`: variant correctness is not a freshness preference.)
226
+ if (!varyIsStorable(response.headers.get('Vary'), varyHeaders))
227
+ return;
105
228
  const configured = options.ttlMs;
106
229
  const ttl = typeof configured === 'function' ? configured(response, url, request) : (configured ?? DEFAULT_TTL_MS);
107
230
  const maxAge = control.maxAgeMs ?? ttl;
@@ -111,8 +234,11 @@ export function createBlazeFetch(cache, options = {}) {
111
234
  if (!(freshMs > 0))
112
235
  return;
113
236
  // The response's own directive wins; the numeric option is the fallback for servers that
114
- // never send one. When the whole feature is off there is no stale window at all.
115
- const staleMs = !swrEnabled
237
+ // never send one. When the whole feature is off there is no stale window at all — and
238
+ // `must-revalidate` (or its shared-cache spelling `proxy-revalidate`) closes the window
239
+ // even when the feature is on: such a response must never be replayed past its
240
+ // freshness, so there is nothing it may serve "while revalidating".
241
+ const staleMs = !swrEnabled || control.mustRevalidate
116
242
  ? 0
117
243
  : cacheControl && control.staleWhileRevalidateMs !== undefined
118
244
  ? control.staleWhileRevalidateMs
@@ -120,8 +246,8 @@ export function createBlazeFetch(cache, options = {}) {
120
246
  let body;
121
247
  try {
122
248
  // `clone()` tees the stream: the caller's response still delivers every byte, while
123
- // this copy is buffered *before* `dispatch` resolves — so a follow-up read can never
124
- // race an in-flight write.
249
+ // this copy is buffered in the background — and fully buffered *before* `cache.set`,
250
+ // so a follow-up read can never race a half-written entry.
125
251
  body = await response.clone().arrayBuffer();
126
252
  }
127
253
  catch {
@@ -147,9 +273,22 @@ export function createBlazeFetch(cache, options = {}) {
147
273
  tags: options.tags?.(response, url, request) ?? defaultTags(request.method, url),
148
274
  });
149
275
  }
276
+ /**
277
+ * `cache.get`, guarded: a cache-layer failure reads as a plain miss — the caller falls
278
+ * through to the network instead of having its request fail over a broken cache.
279
+ */
280
+ function read(key) {
281
+ try {
282
+ return cache.get(key);
283
+ }
284
+ catch (error) {
285
+ warnCacheFailure(error);
286
+ return undefined;
287
+ }
288
+ }
150
289
  /** Rebuilds a `Response` from a stored record, without touching cache statistics. */
151
290
  function replay(record, marker) {
152
- const headers = new Headers(record.headers);
291
+ const headers = headersFromRecord(record.headers);
153
292
  if (markerHeader !== false)
154
293
  headers.set(markerHeader, marker);
155
294
  const response = new Response(NULL_BODY_STATUSES.has(record.status) ? null : record.body, { status: record.status, statusText: record.statusText, headers });
@@ -201,9 +340,11 @@ function defaultTags(method, url) {
201
340
  /** Copies headers into a plain, structured-clone-friendly record. */
202
341
  function headersToRecord(headers) {
203
342
  const record = {};
204
- // `Headers.forEach` reports names already lower-cased.
343
+ // `Headers.forEach` reports names already lower-cased. Defined, never assigned: a plain
344
+ // `record[name] = value` hands a literal `__proto__` to the inherited setter, which
345
+ // ignores primitives — silently dropping a perfectly legal header instead of storing it.
205
346
  headers.forEach((value, name) => {
206
- record[name] = value;
347
+ Object.defineProperty(record, name, { value, enumerable: true, writable: true, configurable: true });
207
348
  });
208
349
  return record;
209
350
  }
@@ -240,4 +381,18 @@ function defineOwn(target, key, value) {
240
381
  // A frozen response: the missing metadata is cosmetic, never worth failing a hit over.
241
382
  }
242
383
  }
384
+ /**
385
+ * Rebuilds a `Headers` from a stored record, name by name.
386
+ *
387
+ * Never `new Headers(record)`: the platform's plain-object conversion drops a literal
388
+ * `__proto__` key on its way through the inherited setter, losing a legal header between
389
+ * the store and the replay. `append` accepts every name the store can hold.
390
+ */
391
+ function headersFromRecord(record) {
392
+ const headers = new Headers();
393
+ for (const [name, value] of Object.entries(record)) {
394
+ headers.append(name, value);
395
+ }
396
+ return headers;
397
+ }
243
398
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -20,7 +20,7 @@
20
20
  * @packageDocumentation
21
21
  */
22
22
  export { createBlazeFetch } from './client.js';
23
- export { parseCacheControl, parseAgeMs } from './cache-control.js';
23
+ export { parseCacheControl, parseAgeMs, varyIsStorable } from './cache-control.js';
24
24
  export type { CacheControl } from './cache-control.js';
25
25
  export { defaultCacheKey, fnv1a } from './key.js';
26
26
  export type { BlazeFetch, BlazeFetchCacheLike, BlazeFetchEffectiveInit, BlazeFetchInit, BlazeFetchMarker, BlazeFetchOptions, FetchCacheRecord, } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAElD,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnF,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAElD,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -20,6 +20,6 @@
20
20
  * @packageDocumentation
21
21
  */
22
22
  export { createBlazeFetch } from './client.js';
23
- export { parseCacheControl, parseAgeMs } from './cache-control.js';
23
+ export { parseCacheControl, parseAgeMs, varyIsStorable } from './cache-control.js';
24
24
  export { defaultCacheKey, fnv1a } from './key.js';
25
25
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGnE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGnF,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC"}
package/dist/key.d.ts CHANGED
@@ -11,7 +11,7 @@ export declare function fnv1a(input: string): string;
11
11
  * Default cache key: method + URL, plus a hash of the `varyHeaders` values.
12
12
  *
13
13
  * ```ts
14
- * defaultCacheKey('/api/users', init, ['authorization']); // "get /api/users/a3f9k"
14
+ * defaultCacheKey('/api/users', init, ['authorization']); // "get /api/users?a3f9k"
15
15
  * ```
16
16
  *
17
17
  * The hash is appended whenever `varyHeaders` is non-empty — including when every value is
package/dist/key.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,uBAAuB,EAC7B,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,MAAM,CAOR"}
1
+ {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,uBAAuB,EAC7B,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,MAAM,CAYR"}
package/dist/key.js CHANGED
@@ -17,7 +17,7 @@ export function fnv1a(input) {
17
17
  * Default cache key: method + URL, plus a hash of the `varyHeaders` values.
18
18
  *
19
19
  * ```ts
20
- * defaultCacheKey('/api/users', init, ['authorization']); // "get /api/users/a3f9k"
20
+ * defaultCacheKey('/api/users', init, ['authorization']); // "get /api/users?a3f9k"
21
21
  * ```
22
22
  *
23
23
  * The hash is appended whenever `varyHeaders` is non-empty — including when every value is
@@ -30,7 +30,12 @@ export function defaultCacheKey(url, init, varyHeaders) {
30
30
  if (varyHeaders.length === 0)
31
31
  return base;
32
32
  const headers = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
33
- const vary = varyHeaders.map((name) => headers.get(name) ?? '').join(' ');
33
+ // JSON, never a plain join: the encoding must stay *injective*, because a collision here
34
+ // would replay one identity's payload to another. Joining with a space lets a value
35
+ // containing the separator impersonate the boundary — `['x y', '']` and `['x', 'y']` are
36
+ // two different identities, and only a length-delimited encoding (JSON being the simplest)
37
+ // keeps them apart.
38
+ const vary = JSON.stringify(varyHeaders.map((name) => headers.get(name) ?? ''));
34
39
  return `${base}?${fnv1a(vary)}`;
35
40
  }
36
41
  //# sourceMappingURL=key.js.map
package/dist/key.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"key.js","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,KAAa;IACjC,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAW,EACX,IAA6B,EAC7B,WAA8B;IAE9B,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,GAAG,EAAE,CAAC;IACnD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3F,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1E,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"key.js","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,KAAa;IACjC,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAW,EACX,IAA6B,EAC7B,WAA8B;IAE9B,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,GAAG,EAAE,CAAC;IACnD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3F,yFAAyF;IACzF,oFAAoF;IACpF,yFAAyF;IACzF,2FAA2F;IAC3F,oBAAoB;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAChF,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AAClC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -104,19 +104,23 @@ export interface BlazeFetchOptions {
104
104
  * HTTP methods eligible for caching. Default: `['GET']`.
105
105
  *
106
106
  * Pass `['GET', 'HEAD']` to cache `HEAD` too. Any other method always goes to the network
107
- * and is never stored.
107
+ * and is never stored. Non-cacheable methods are also never coalesced with an identical
108
+ * in-flight request — replaying a side effect would be worse than repeating one.
108
109
  */
109
110
  methods?: readonly string[];
110
111
  /**
111
112
  * Honour `Cache-Control` on both sides of the exchange. Default: `true`.
112
113
  *
113
114
  * * request `no-store` → neither read nor write the cache;
114
- * * request `no-cache` → skip the read, still store the response;
115
- * * response `no-store`/`no-cache` → never stored;
115
+ * * request `no-cache` / `max-age=0` → skip the read, still store the response;
116
+ * * response `no-store` → never stored;
117
+ * * response `no-cache` (even per-field, `no-cache="field1"`) → never stored;
116
118
  * * response `max-age` → overrides {@link ttlMs}, minus the response's `Age`;
117
- * * response `stale-while-revalidate` → the stale window, when {@link staleWhileRevalidate} is on.
119
+ * * response `stale-while-revalidate` → the stale window, when {@link staleWhileRevalidate} is on;
120
+ * * response `must-revalidate` / `proxy-revalidate` → no stale window, however short the fresh one.
118
121
  *
119
- * Set to `false` to treat `ttlMs` as the only authority.
122
+ * Set to `false` to treat `ttlMs` as the only authority. The response's `Vary` header is
123
+ * *always* honoured (see {@link varyHeaders}) — variant correctness is not a preference.
120
124
  */
121
125
  cacheControl?: boolean;
122
126
  /**
@@ -128,7 +132,9 @@ export interface BlazeFetchOptions {
128
132
  * omits the directive, so opting in works against servers that never send it.
129
133
  *
130
134
  * Such responses are marked `x-blaze-cache: STALE` and revalidated once per key: the
131
- * refresh is a forced refresh, so it can never re-serve the stale entry to itself.
135
+ * refresh is a forced refresh, so it can never re-serve the stale entry to itself. A
136
+ * response carrying `must-revalidate`/`proxy-revalidate` never opens the stale window,
137
+ * and the refresh never inherits the caller's `signal` — it is the wrapper's own work.
132
138
  */
133
139
  staleWhileRevalidate?: boolean | number;
134
140
  /**
@@ -146,7 +152,9 @@ export interface BlazeFetchOptions {
146
152
  * (the {@link methods} gate has already applied by then).
147
153
  *
148
154
  * A response this rejects is still returned — it is simply not cached, and still carries
149
- * `x-blaze-cache: MISS`.
155
+ * `x-blaze-cache: MISS`. A callback that *throws* is treated exactly the same way (after
156
+ * one console warning): a cache-layer failure never fails a response the network answered
157
+ * well.
150
158
  */
151
159
  shouldCache?: (response: Response, url: string, init: BlazeFetchEffectiveInit) => boolean;
152
160
  /**
@@ -161,6 +169,10 @@ export interface BlazeFetchOptions {
161
169
  *
162
170
  * A personalized response must never be served to a different user just because the URL
163
171
  * matched. Values are hashed, never stored verbatim.
172
+ *
173
+ * A response's own `Vary` header is checked against this list before it is stored: a
174
+ * response varying on anything *not* listed cannot be keyed correctly, so it is left
175
+ * uncached — and `Vary: *` is never stored at all (RFC 9111 §3).
164
176
  */
165
177
  varyHeaders?: readonly string[];
166
178
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;;;;OAKG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB,+HAA+H;IAC/H,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,UAAU,EAAE,MAAM,CAAC;IACnB,4HAA4H;IAC5H,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,QAAQ,CAAC;IACzF,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEhG,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAErB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,MAAM,CAAC,CAAC;IAE9F;;;;;OAKG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAE5B;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAExC;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,MAAM,CAAC;IAE7D;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,OAAO,CAAC;IAE1F;;;;;OAKG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,SAAS,MAAM,EAAE,CAAC;IAE7F;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC/B;AAED,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CACzG"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;;;;OAKG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB,+HAA+H;IAC/H,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,UAAU,EAAE,MAAM,CAAC;IACnB,4HAA4H;IAC5H,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,QAAQ,CAAC;IACzF,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEhG,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAErB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,MAAM,CAAC,CAAC;IAE9F;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAE5B;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;;;OAYG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAExC;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,MAAM,CAAC;IAE7D;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,OAAO,CAAC;IAE1F;;;;;OAKG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,SAAS,MAAM,EAAE,CAAC;IAE7F;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC/B;AAED,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CACzG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaze-cache/fetch",
3
- "version": "0.2.0-beta",
3
+ "version": "0.2.1-beta",
4
4
  "description": "Drop-in fetch() replacement backed by a WebAssembly cache — TTLs, Cache-Control, stale-while-revalidate and an x-blaze-cache HIT/MISS marker",
5
5
  "keywords": [
6
6
  "fetch",
@@ -38,7 +38,7 @@
38
38
  "dist"
39
39
  ],
40
40
  "dependencies": {
41
- "@blaze-cache/core": "0.2.0-beta"
41
+ "@blaze-cache/core": "0.2.1-beta"
42
42
  },
43
43
  "devDependencies": {
44
44
  "typescript": "^5.9.3"