@netlify/plugin-nextjs 5.14.4 → 5.14.6

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.
@@ -384,6 +384,25 @@ var Store = class _Store {
384
384
  throw new BlobsInternalError(res);
385
385
  }
386
386
  }
387
+ async deleteAll() {
388
+ let totalDeletedBlobs = 0;
389
+ let hasMore = true;
390
+ while (hasMore) {
391
+ const res = await this.client.makeRequest({ method: "delete", storeName: this.name });
392
+ if (res.status !== 200) {
393
+ throw new BlobsInternalError(res);
394
+ }
395
+ const data = await res.json();
396
+ if (typeof data.blobs_deleted !== "number") {
397
+ throw new BlobsInternalError(res);
398
+ }
399
+ totalDeletedBlobs += data.blobs_deleted;
400
+ hasMore = typeof data.has_more === "boolean" && data.has_more;
401
+ }
402
+ return {
403
+ deletedBlobs: totalDeletedBlobs
404
+ };
405
+ }
387
406
  async get(key, options) {
388
407
  return withActiveSpan(getTracer(), "blobs.get", async (span) => {
389
408
  const { consistency, type } = options ?? {};
@@ -401,6 +420,7 @@ var Store = class _Store {
401
420
  storeName: this.name
402
421
  });
403
422
  span?.setAttributes({
423
+ "blobs.response.body.size": res.headers.get("content-length") ?? void 0,
404
424
  "blobs.response.status": res.status
405
425
  });
406
426
  if (res.status === 404) {
@@ -475,6 +495,7 @@ var Store = class _Store {
475
495
  });
476
496
  const responseETag = res?.headers.get("etag") ?? void 0;
477
497
  span?.setAttributes({
498
+ "blobs.response.body.size": res.headers.get("content-length") ?? void 0,
478
499
  "blobs.response.etag": responseETag,
479
500
  "blobs.response.status": res.status
480
501
  });
@@ -1400,6 +1400,9 @@ var import_blob_types = require("../../shared/blob-types.cjs");
1400
1400
  var import_request_context = require("../handlers/request-context.cjs");
1401
1401
  var import_tracer = require("../handlers/tracer.cjs");
1402
1402
  var NullValue = Symbol.for("null-value");
1403
+ var isDataWithEtag = (value) => {
1404
+ return typeof value === "object" && value !== null && "data" in value && "etag" in value;
1405
+ };
1403
1406
  var IN_MEMORY_CACHE_MAX_SIZE = Symbol.for("nf-in-memory-cache-max-size");
1404
1407
  var IN_MEMORY_LRU_CACHE = Symbol.for("nf-in-memory-lru-cache");
1405
1408
  var extendedGlobalThis = globalThis;
@@ -1413,24 +1416,29 @@ var isPositiveNumber = (value) => {
1413
1416
  return typeof value === "number" && value > 0;
1414
1417
  };
1415
1418
  var BASE_BLOB_SIZE = 25;
1419
+ var BASE_BLOB_WITH_ETAG_SIZE = BASE_BLOB_SIZE + 34;
1416
1420
  var estimateBlobKnownTypeSize = (valueToStore) => {
1417
- if (valueToStore === null || (0, import_types.isPromise)(valueToStore) || (0, import_blob_types.isTagManifest)(valueToStore)) {
1421
+ if (valueToStore === null || (0, import_types.isPromise)(valueToStore)) {
1418
1422
  return BASE_BLOB_SIZE;
1419
1423
  }
1420
- if ((0, import_blob_types.isHtmlBlob)(valueToStore)) {
1421
- return BASE_BLOB_SIZE + valueToStore.html.length;
1424
+ const { data, baseSize } = isDataWithEtag(valueToStore) ? { data: valueToStore.data, baseSize: BASE_BLOB_WITH_ETAG_SIZE } : { data: valueToStore, baseSize: BASE_BLOB_SIZE };
1425
+ if ((0, import_blob_types.isTagManifest)(data)) {
1426
+ return baseSize;
1427
+ }
1428
+ if ((0, import_blob_types.isHtmlBlob)(data)) {
1429
+ return baseSize + data.html.length;
1422
1430
  }
1423
- if (valueToStore.value?.kind === "FETCH") {
1424
- return BASE_BLOB_SIZE + valueToStore.value.data.body.length;
1431
+ if (data.value?.kind === "FETCH") {
1432
+ return baseSize + data.value.data.body.length;
1425
1433
  }
1426
- if (valueToStore.value?.kind === "APP_PAGE") {
1427
- return BASE_BLOB_SIZE + valueToStore.value.html.length + (valueToStore.value.rscData?.length ?? 0);
1434
+ if (data.value?.kind === "APP_PAGE") {
1435
+ return baseSize + data.value.html.length + (data.value.rscData?.length ?? 0);
1428
1436
  }
1429
- if (valueToStore.value?.kind === "PAGE" || valueToStore.value?.kind === "PAGES") {
1430
- return BASE_BLOB_SIZE + valueToStore.value.html.length + JSON.stringify(valueToStore.value.pageData).length;
1437
+ if (data.value?.kind === "PAGE" || data.value?.kind === "PAGES") {
1438
+ return baseSize + data.value.html.length + JSON.stringify(data.value.pageData).length;
1431
1439
  }
1432
- if (valueToStore.value?.kind === "ROUTE" || valueToStore.value?.kind === "APP_ROUTE") {
1433
- return BASE_BLOB_SIZE + valueToStore.value.body.length;
1440
+ if (data.value?.kind === "ROUTE" || data.value?.kind === "APP_ROUTE") {
1441
+ return baseSize + data.value.body.length;
1434
1442
  }
1435
1443
  };
1436
1444
  var estimateBlobSize = (valueToStore) => {
@@ -1456,13 +1464,22 @@ var estimateBlobSize = (valueToStore) => {
1456
1464
  function getInMemoryLRUCache() {
1457
1465
  if (typeof extendedGlobalThis[IN_MEMORY_LRU_CACHE] === "undefined") {
1458
1466
  const maxSize = typeof extendedGlobalThis[IN_MEMORY_CACHE_MAX_SIZE] === "number" ? extendedGlobalThis[IN_MEMORY_CACHE_MAX_SIZE] : DEFAULT_FALLBACK_MAX_SIZE;
1459
- extendedGlobalThis[IN_MEMORY_LRU_CACHE] = maxSize === 0 ? null : new LRUCache({
1460
- max: 1e3,
1461
- maxSize,
1462
- sizeCalculation: (valueToStore) => {
1463
- return estimateBlobSize(valueToStore === NullValue ? null : valueToStore);
1464
- }
1465
- });
1467
+ if (maxSize === 0) {
1468
+ extendedGlobalThis[IN_MEMORY_LRU_CACHE] = null;
1469
+ } else {
1470
+ const global = /* @__PURE__ */ new Map();
1471
+ const perRequest = new LRUCache({
1472
+ max: 1e3,
1473
+ maxSize,
1474
+ sizeCalculation: (valueToStore) => {
1475
+ return estimateBlobSize(valueToStore === NullValue ? null : valueToStore);
1476
+ }
1477
+ });
1478
+ extendedGlobalThis[IN_MEMORY_LRU_CACHE] = {
1479
+ perRequest,
1480
+ global
1481
+ };
1482
+ }
1466
1483
  }
1467
1484
  return extendedGlobalThis[IN_MEMORY_LRU_CACHE];
1468
1485
  }
@@ -1473,8 +1490,27 @@ var getRequestScopedInMemoryCache = () => {
1473
1490
  get(key) {
1474
1491
  if (!requestContext) return;
1475
1492
  try {
1476
- const value = inMemoryLRUCache?.get(`${requestContext.requestID}:${key}`);
1477
- return value === NullValue ? null : value;
1493
+ const currentRequestValue = inMemoryLRUCache?.perRequest.get(
1494
+ `${requestContext.requestID}:${key}`
1495
+ );
1496
+ if (currentRequestValue) {
1497
+ return {
1498
+ conditional: false,
1499
+ currentRequestValue: currentRequestValue === NullValue ? null : isDataWithEtag(currentRequestValue) ? currentRequestValue.data : currentRequestValue
1500
+ };
1501
+ }
1502
+ const globalEntry = inMemoryLRUCache?.global.get(key);
1503
+ if (globalEntry) {
1504
+ const derefencedGlobalEntry = globalEntry.deref();
1505
+ if (derefencedGlobalEntry) {
1506
+ return {
1507
+ conditional: true,
1508
+ globalValue: derefencedGlobalEntry.data,
1509
+ etag: derefencedGlobalEntry.etag
1510
+ };
1511
+ }
1512
+ inMemoryLRUCache?.global.delete(key);
1513
+ }
1478
1514
  } catch (error) {
1479
1515
  (0, import_tracer.recordWarning)(new Error("Failed to get value from memory cache", { cause: error }));
1480
1516
  }
@@ -1482,7 +1518,10 @@ var getRequestScopedInMemoryCache = () => {
1482
1518
  set(key, value) {
1483
1519
  if (!requestContext) return;
1484
1520
  try {
1485
- inMemoryLRUCache?.set(`${requestContext?.requestID}:${key}`, value ?? NullValue);
1521
+ if (isDataWithEtag(value)) {
1522
+ inMemoryLRUCache?.global.set(key, new WeakRef(value));
1523
+ }
1524
+ inMemoryLRUCache?.perRequest.set(`${requestContext.requestID}:${key}`, value ?? NullValue);
1486
1525
  } catch (error) {
1487
1526
  (0, import_tracer.recordWarning)(new Error("Failed to store value in memory cache", { cause: error }));
1488
1527
  }
@@ -51,15 +51,32 @@ var getMemoizedKeyValueStoreBackedByRegionalBlobStore = (...args) => {
51
51
  async get(key, otelSpanTitle) {
52
52
  const inMemoryCache = (0, import_request_scoped_in_memory_cache.getRequestScopedInMemoryCache)();
53
53
  const memoizedValue = inMemoryCache.get(key);
54
- if (typeof memoizedValue !== "undefined") {
55
- return memoizedValue;
54
+ if (memoizedValue?.conditional === false && typeof memoizedValue?.currentRequestValue !== "undefined") {
55
+ return memoizedValue.currentRequestValue;
56
56
  }
57
57
  const blobKey = await encodeBlobKey(key);
58
58
  const getPromise = (0, import_tracer.withActiveSpan)(tracer, otelSpanTitle, async (span) => {
59
- span?.setAttributes({ key, blobKey });
60
- const blob = await store.get(blobKey, { type: "json" });
61
- inMemoryCache.set(key, blob);
62
- span?.addEvent(blob ? "Hit" : "Miss");
59
+ const { etag: previousEtag, globalValue: previousBlob } = memoizedValue?.conditional ? memoizedValue : {};
60
+ span?.setAttributes({ key, blobKey, previousEtag });
61
+ const result = await store.getWithMetadata(blobKey, {
62
+ type: "json",
63
+ etag: previousEtag
64
+ });
65
+ const shouldReuseMemoizedBlob = result?.etag && previousEtag === result?.etag;
66
+ const blob = shouldReuseMemoizedBlob ? previousBlob : result?.data;
67
+ if (result?.etag && blob) {
68
+ inMemoryCache.set(key, {
69
+ data: blob,
70
+ etag: result?.etag
71
+ });
72
+ } else {
73
+ inMemoryCache.set(key, blob);
74
+ }
75
+ span?.setAttributes({
76
+ etag: result?.etag,
77
+ reusingPreviouslyFetchedBlob: shouldReuseMemoizedBlob,
78
+ status: blob ? shouldReuseMemoizedBlob ? "Hit, no change" : "Hit" : "Miss"
79
+ });
63
80
  return blob;
64
81
  });
65
82
  inMemoryCache.set(key, getPromise);
@@ -71,7 +88,14 @@ var getMemoizedKeyValueStoreBackedByRegionalBlobStore = (...args) => {
71
88
  const blobKey = await encodeBlobKey(key);
72
89
  return (0, import_tracer.withActiveSpan)(tracer, otelSpanTitle, async (span) => {
73
90
  span?.setAttributes({ key, blobKey });
74
- return await store.setJSON(blobKey, value);
91
+ const writeResult = await store.setJSON(blobKey, value);
92
+ if (writeResult?.etag) {
93
+ inMemoryCache.set(key, {
94
+ data: value,
95
+ etag: writeResult.etag
96
+ });
97
+ }
98
+ return writeResult;
75
99
  });
76
100
  }
77
101
  };
@@ -1,16 +1,21 @@
1
1
  // NOTE: This is a fragment of a JavaScript program that will be inlined with
2
2
  // a Webpack bundle. You should not import this file from anywhere in the
3
3
  // application.
4
- import { AsyncLocalStorage } from 'node:async_hooks'
5
-
6
4
  import { createRequire } from 'node:module' // used in dynamically generated part
7
- import process from 'node:process'
8
5
 
9
6
  import { registerCJSModules } from '../edge-runtime/lib/cjs.ts' // used in dynamically generated part
10
7
 
11
- globalThis.process = process
8
+ if (typeof process === 'undefined') {
9
+ globalThis.process = (await import('node:process')).default
10
+ }
11
+
12
+ if (typeof AsyncLocalStorage === 'undefined') {
13
+ globalThis.AsyncLocalStorage = (await import('node:async_hooks')).AsyncLocalStorage
14
+ }
12
15
 
13
- globalThis.AsyncLocalStorage = AsyncLocalStorage
16
+ if (typeof Buffer === 'undefined') {
17
+ globalThis.Buffer = (await import('node:buffer')).Buffer
18
+ }
14
19
 
15
20
  // needed for path.relative and path.resolve to work
16
21
  Deno.cwd = () => ''
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.14.4",
3
+ "version": "5.14.6",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",