@netlify/cache 3.3.4 → 3.4.0

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/dist/main.cjs CHANGED
@@ -29,6 +29,7 @@ __export(main_exports, {
29
29
  caches: () => caches,
30
30
  fetchWithCache: () => fetchWithCache,
31
31
  getCacheStatus: () => getCacheStatus,
32
+ needsRevalidation: () => needsRevalidation,
32
33
  setCacheHeaders: () => setCacheHeaders
33
34
  });
34
35
  module.exports = __toCommonJS(main_exports);
@@ -266,6 +267,19 @@ var parseCacheStatusValues = (cacheStatusValues) => {
266
267
  }
267
268
  return cacheStatus;
268
269
  };
270
+ var needsRevalidation = (response) => {
271
+ const header = response.headers.get(CacheStatus);
272
+ if (!header) {
273
+ return false;
274
+ }
275
+ for (const value of header.split(",")) {
276
+ const { attributes, name } = parseCacheStatusValue(value);
277
+ if (name === CACHE_DURABLE && attributes.detail === "client-revalidate") {
278
+ return true;
279
+ }
280
+ }
281
+ return false;
282
+ };
269
283
  var getCacheStatus = (input) => {
270
284
  if (typeof input === "string") {
271
285
  return parseCacheStatusValues(input);
@@ -336,6 +350,19 @@ var fetchWithCache = async (requestOrURL, optionsOrCacheSettings, cacheOptionsPa
336
350
  }
337
351
  const cached = await cache.match(request);
338
352
  if (cached) {
353
+ if (needsRevalidation(cached)) {
354
+ const { fetch: fetchFn = globalThis.fetch } = cacheOptions;
355
+ const revalidation = performBackgroundRevalidation(request, cache, cacheSettings, fetchFn);
356
+ if (onCachePut) {
357
+ await onCachePut(revalidation);
358
+ } else {
359
+ const netlifyGlobal = globalThis.Netlify;
360
+ const requestContext = netlifyGlobal?.context;
361
+ if (requestContext) {
362
+ requestContext.waitUntil(revalidation);
363
+ }
364
+ }
365
+ }
339
366
  return cached;
340
367
  }
341
368
  const { fetch = globalThis.fetch } = cacheOptions;
@@ -362,6 +389,19 @@ var fetchWithCache = async (requestOrURL, optionsOrCacheSettings, cacheOptionsPa
362
389
  }
363
390
  return clientResponse;
364
391
  };
392
+ var performBackgroundRevalidation = async (request, cache, cacheSettings, fetchFn) => {
393
+ try {
394
+ const fresh = await fetchFn(request);
395
+ if (!fresh.body) {
396
+ return;
397
+ }
398
+ const cacheResponse = new Response(fresh.body, fresh);
399
+ applyHeaders(cacheResponse.headers, cacheHeaders(cacheSettings));
400
+ await cache.put(request, cacheResponse);
401
+ } catch (error) {
402
+ console.warn("`fetchWithCache` has failed to revalidate a stale response:", error);
403
+ }
404
+ };
365
405
 
366
406
  // src/constants.ts
367
407
  var MINUTE = 60;
@@ -380,5 +420,6 @@ var YEAR = 365 * DAY;
380
420
  caches,
381
421
  fetchWithCache,
382
422
  getCacheStatus,
423
+ needsRevalidation,
383
424
  setCacheHeaders
384
425
  });
package/dist/main.d.cts CHANGED
@@ -129,6 +129,15 @@ type ParseCacheStatus = {
129
129
  (headers: Headers): CacheStatus | null;
130
130
  (response: Response): CacheStatus | null;
131
131
  };
132
+ /**
133
+ * Returns whether a cached response includes a signal that the client should
134
+ * perform a background revalidation. This may happen when using the Cache API
135
+ * with the `stale-while-revalidate` directive, since unlike the regular cache,
136
+ * the client is the one responsible for explicitly inserting new entries into
137
+ * the cache. So when this returns `true`, the caller should fetch the resource
138
+ * and write the fresh response back to the cache with `cache.put()`.
139
+ */
140
+ declare const needsRevalidation: (response: Response) => boolean;
132
141
  /**
133
142
  * Retrieves information about how a response has interacted with Netlify's
134
143
  * global caching infrastructure, including whether the response has been
@@ -193,4 +202,4 @@ declare const WEEK: number;
193
202
  */
194
203
  declare const YEAR: number;
195
204
 
196
- export { DAY, HOUR, MINUTE, WEEK, YEAR, cacheHeaders, caches, fetchWithCache, getCacheStatus, setCacheHeaders };
205
+ export { DAY, HOUR, MINUTE, WEEK, YEAR, cacheHeaders, caches, fetchWithCache, getCacheStatus, needsRevalidation, setCacheHeaders };
package/dist/main.d.ts CHANGED
@@ -129,6 +129,15 @@ type ParseCacheStatus = {
129
129
  (headers: Headers): CacheStatus | null;
130
130
  (response: Response): CacheStatus | null;
131
131
  };
132
+ /**
133
+ * Returns whether a cached response includes a signal that the client should
134
+ * perform a background revalidation. This may happen when using the Cache API
135
+ * with the `stale-while-revalidate` directive, since unlike the regular cache,
136
+ * the client is the one responsible for explicitly inserting new entries into
137
+ * the cache. So when this returns `true`, the caller should fetch the resource
138
+ * and write the fresh response back to the cache with `cache.put()`.
139
+ */
140
+ declare const needsRevalidation: (response: Response) => boolean;
132
141
  /**
133
142
  * Retrieves information about how a response has interacted with Netlify's
134
143
  * global caching infrastructure, including whether the response has been
@@ -193,4 +202,4 @@ declare const WEEK: number;
193
202
  */
194
203
  declare const YEAR: number;
195
204
 
196
- export { DAY, HOUR, MINUTE, WEEK, YEAR, cacheHeaders, caches, fetchWithCache, getCacheStatus, setCacheHeaders };
205
+ export { DAY, HOUR, MINUTE, WEEK, YEAR, cacheHeaders, caches, fetchWithCache, getCacheStatus, needsRevalidation, setCacheHeaders };
package/dist/main.js CHANGED
@@ -231,6 +231,19 @@ var parseCacheStatusValues = (cacheStatusValues) => {
231
231
  }
232
232
  return cacheStatus;
233
233
  };
234
+ var needsRevalidation = (response) => {
235
+ const header = response.headers.get(CacheStatus);
236
+ if (!header) {
237
+ return false;
238
+ }
239
+ for (const value of header.split(",")) {
240
+ const { attributes, name } = parseCacheStatusValue(value);
241
+ if (name === CACHE_DURABLE && attributes.detail === "client-revalidate") {
242
+ return true;
243
+ }
244
+ }
245
+ return false;
246
+ };
234
247
  var getCacheStatus = (input) => {
235
248
  if (typeof input === "string") {
236
249
  return parseCacheStatusValues(input);
@@ -301,6 +314,19 @@ var fetchWithCache = async (requestOrURL, optionsOrCacheSettings, cacheOptionsPa
301
314
  }
302
315
  const cached = await cache.match(request);
303
316
  if (cached) {
317
+ if (needsRevalidation(cached)) {
318
+ const { fetch: fetchFn = globalThis.fetch } = cacheOptions;
319
+ const revalidation = performBackgroundRevalidation(request, cache, cacheSettings, fetchFn);
320
+ if (onCachePut) {
321
+ await onCachePut(revalidation);
322
+ } else {
323
+ const netlifyGlobal = globalThis.Netlify;
324
+ const requestContext = netlifyGlobal?.context;
325
+ if (requestContext) {
326
+ requestContext.waitUntil(revalidation);
327
+ }
328
+ }
329
+ }
304
330
  return cached;
305
331
  }
306
332
  const { fetch = globalThis.fetch } = cacheOptions;
@@ -327,6 +353,19 @@ var fetchWithCache = async (requestOrURL, optionsOrCacheSettings, cacheOptionsPa
327
353
  }
328
354
  return clientResponse;
329
355
  };
356
+ var performBackgroundRevalidation = async (request, cache, cacheSettings, fetchFn) => {
357
+ try {
358
+ const fresh = await fetchFn(request);
359
+ if (!fresh.body) {
360
+ return;
361
+ }
362
+ const cacheResponse = new Response(fresh.body, fresh);
363
+ applyHeaders(cacheResponse.headers, cacheHeaders(cacheSettings));
364
+ await cache.put(request, cacheResponse);
365
+ } catch (error) {
366
+ console.warn("`fetchWithCache` has failed to revalidate a stale response:", error);
367
+ }
368
+ };
330
369
 
331
370
  // src/constants.ts
332
371
  var MINUTE = 60;
@@ -344,5 +383,6 @@ export {
344
383
  caches,
345
384
  fetchWithCache,
346
385
  getCacheStatus,
386
+ needsRevalidation,
347
387
  setCacheHeaders
348
388
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/cache",
3
- "version": "3.3.4",
3
+ "version": "3.4.0",
4
4
  "description": "TypeScript utilities for interacting with the Netlify cache",
5
5
  "type": "module",
6
6
  "engines": {
@@ -79,6 +79,6 @@
79
79
  "vitest": "^3.0.0"
80
80
  },
81
81
  "dependencies": {
82
- "@netlify/runtime-utils": "2.2.1"
82
+ "@netlify/runtime-utils": "2.3.0"
83
83
  }
84
84
  }