@netlify/plugin-nextjs 5.10.2 → 5.10.4

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.
@@ -8,7 +8,7 @@ import "./chunk-OEQOKJGE.js";
8
8
 
9
9
  // package.json
10
10
  var name = "@netlify/plugin-nextjs";
11
- var version = "5.10.2";
11
+ var version = "5.10.4";
12
12
  var description = "Run Next.js seamlessly on Netlify";
13
13
  var main = "./dist/index.js";
14
14
  var type = "module";
@@ -58,7 +58,7 @@ var homepage = "https://opennext.js.org/netlify";
58
58
  var devDependencies = {
59
59
  "@fastly/http-compute-js": "1.1.5",
60
60
  "@netlify/blobs": "^8.1.2",
61
- "@netlify/build": "^30.1.0",
61
+ "@netlify/build": "^30.1.1",
62
62
  "@netlify/edge-bundler": "^12.4.0",
63
63
  "@netlify/edge-functions": "^2.11.1",
64
64
  "@netlify/eslint-config-node": "^7.0.1",
@@ -88,7 +88,7 @@ var devDependencies = {
88
88
  memfs: "^4.9.2",
89
89
  "mock-require": "^3.0.3",
90
90
  msw: "^2.0.7",
91
- "netlify-cli": "^19.1.4",
91
+ "netlify-cli": "^19.1.5",
92
92
  next: "^15.0.0-canary.28",
93
93
  os: "^0.1.2",
94
94
  outdent: "^0.8.0",
@@ -195,7 +195,7 @@ var import_constants = require("next/dist/lib/constants.js");
195
195
 
196
196
  // package.json
197
197
  var name = "@netlify/plugin-nextjs";
198
- var version = "5.10.2";
198
+ var version = "5.10.4";
199
199
 
200
200
  // src/run/handlers/cache.cts
201
201
  var import_cache_types = require("../../shared/cache-types.cjs");
@@ -259,9 +259,6 @@ var NetlifyCacheHandler = class {
259
259
  return restOfRouteValue;
260
260
  }
261
261
  captureCacheTags(cacheValue, key) {
262
- if (!cacheValue) {
263
- return;
264
- }
265
262
  const requestContext = (0, import_request_context.getRequestContext)();
266
263
  if (!requestContext) {
267
264
  return;
@@ -269,6 +266,11 @@ var NetlifyCacheHandler = class {
269
266
  if (requestContext.responseCacheTags) {
270
267
  return;
271
268
  }
269
+ if (!cacheValue) {
270
+ const cacheTags = [`_N_T_${key === "/index" ? "/" : encodeURI(key)}`];
271
+ requestContext.responseCacheTags = cacheTags;
272
+ return;
273
+ }
272
274
  if (cacheValue.kind === "PAGE" || cacheValue.kind === "PAGES" || cacheValue.kind === "APP_PAGE" || cacheValue.kind === "ROUTE" || cacheValue.kind === "APP_ROUTE") {
273
275
  if (cacheValue.headers?.[import_constants.NEXT_CACHE_TAGS_HEADER]) {
274
276
  const cacheTags = cacheValue.headers[import_constants.NEXT_CACHE_TAGS_HEADER].split(/,|%2c/gi);
@@ -318,7 +320,7 @@ var NetlifyCacheHandler = class {
318
320
  }
319
321
  async get(...args) {
320
322
  return this.tracer.withActiveSpan("get cache key", async (span) => {
321
- const [key, ctx = {}] = args;
323
+ const [key, context = {}] = args;
322
324
  (0, import_request_context.getLogger)().debug(`[NetlifyCacheHandler.get]: ${key}`);
323
325
  span.setAttributes({ key });
324
326
  const blob = await this.cacheStore.get(key, "blobStore.get");
@@ -340,18 +342,25 @@ var NetlifyCacheHandler = class {
340
342
  );
341
343
  return null;
342
344
  }
343
- const staleByTags = await this.checkCacheEntryStaleByTags(blob, ctx.tags, ctx.softTags);
345
+ const staleByTags = await this.checkCacheEntryStaleByTags(
346
+ blob,
347
+ context.tags,
348
+ context.softTags
349
+ );
344
350
  if (staleByTags) {
345
351
  span.addEvent("Stale", { staleByTags, key, ttl });
346
352
  return null;
347
353
  }
348
354
  this.captureResponseCacheLastModified(blob, key, span);
349
- this.captureCacheTags(blob.value, key);
355
+ const isDataRequest = Boolean(context.fetchUrl);
356
+ if (!isDataRequest) {
357
+ this.captureCacheTags(blob.value, key);
358
+ }
350
359
  switch (blob.value?.kind) {
351
360
  case "FETCH":
352
361
  span.addEvent("FETCH", {
353
362
  lastModified: blob.lastModified,
354
- revalidate: ctx.revalidate,
363
+ revalidate: context.revalidate,
355
364
  ttl
356
365
  });
357
366
  return {
@@ -390,6 +399,10 @@ var NetlifyCacheHandler = class {
390
399
  };
391
400
  }
392
401
  case "APP_PAGE": {
402
+ const requestContext = (0, import_request_context.getRequestContext)();
403
+ if (requestContext && blob.value?.kind === "APP_PAGE") {
404
+ requestContext.isCacheableAppPage = true;
405
+ }
393
406
  const { revalidate, rscData, ...restOfPageValue } = blob.value;
394
407
  span.addEvent(blob.value?.kind, { lastModified: blob.lastModified, revalidate, ttl });
395
408
  await this.injectEntryToPrerenderManifest(key, blob.value);
@@ -443,9 +456,18 @@ var NetlifyCacheHandler = class {
443
456
  span.setAttributes({ key, lastModified });
444
457
  (0, import_request_context.getLogger)().debug(`[NetlifyCacheHandler.set]: ${key}`);
445
458
  const value = this.transformToStorableObject(data, context);
446
- this.captureCacheTags(value, key);
459
+ const isDataReq = Boolean(context.fetchUrl);
460
+ if (!isDataReq) {
461
+ this.captureCacheTags(value, key);
462
+ }
447
463
  await this.cacheStore.set(key, { lastModified, value }, "blobStore.set");
448
- if (data?.kind === "PAGE" || data?.kind === "PAGES") {
464
+ if (data?.kind === "APP_PAGE") {
465
+ const requestContext = (0, import_request_context.getRequestContext)();
466
+ if (requestContext) {
467
+ requestContext.isCacheableAppPage = true;
468
+ }
469
+ }
470
+ if (!data && !isDataReq || data?.kind === "PAGE" || data?.kind === "PAGES") {
449
471
  const requestContext = (0, import_request_context.getRequestContext)();
450
472
  if (requestContext?.didPagesRouterOnDemandRevalidate) {
451
473
  const tag = `_N_T_${key === "/index" ? "/" : encodeURI(key)}`;
@@ -3101,7 +3101,7 @@ import {
3101
3101
  import { nextResponseProxy } from "../revalidate.js";
3102
3102
  import { setFetchBeforeNextPatchedIt } from "../storage/storage.cjs";
3103
3103
  import { getLogger } from "./request-context.cjs";
3104
- import { getTracer } from "./tracer.cjs";
3104
+ import { getTracer, recordWarning } from "./tracer.cjs";
3105
3105
  import { setupWaitUntil } from "./wait-until.cjs";
3106
3106
  setFetchBeforeNextPatchedIt(globalThis.fetch);
3107
3107
  var nextImportPromise = import("../next.cjs");
@@ -3165,10 +3165,6 @@ var server_default = async (request, _context, topLevelSpan, requestContext) =>
3165
3165
  }
3166
3166
  const nextCache = response.headers.get("x-nextjs-cache");
3167
3167
  const isServedFromNextCache = nextCache === "HIT" || nextCache === "STALE";
3168
- topLevelSpan.setAttributes({
3169
- "x-nextjs-cache": nextCache ?? void 0,
3170
- isServedFromNextCache
3171
- });
3172
3168
  if (isServedFromNextCache) {
3173
3169
  await adjustDateHeader({
3174
3170
  headers: response.headers,
@@ -3177,10 +3173,37 @@ var server_default = async (request, _context, topLevelSpan, requestContext) =>
3177
3173
  requestContext
3178
3174
  });
3179
3175
  }
3180
- setCacheControlHeaders(response, request, requestContext, nextConfig);
3176
+ setCacheControlHeaders(response, request, requestContext);
3181
3177
  setCacheTagsHeaders(response.headers, requestContext);
3182
3178
  setVaryHeaders(response.headers, request, nextConfig);
3183
3179
  setCacheStatusHeader(response.headers, nextCache);
3180
+ const netlifyVary = response.headers.get("netlify-vary") ?? void 0;
3181
+ const netlifyCdnCacheControl = response.headers.get("netlify-cdn-cache-control") ?? void 0;
3182
+ topLevelSpan.setAttributes({
3183
+ "x-nextjs-cache": nextCache ?? void 0,
3184
+ isServedFromNextCache,
3185
+ netlifyVary,
3186
+ netlifyCdnCacheControl
3187
+ });
3188
+ if (requestContext.isCacheableAppPage) {
3189
+ const isRSCRequest = request.headers.get("rsc") === "1";
3190
+ const contentType = response.headers.get("content-type") ?? void 0;
3191
+ const isExpectedContentType = (isRSCRequest && contentType?.includes("text/x-component") || !isRSCRequest && contentType?.includes("text/html")) ?? false;
3192
+ topLevelSpan.setAttributes({
3193
+ isRSCRequest,
3194
+ isCacheableAppPage: true,
3195
+ contentType,
3196
+ isExpectedContentType
3197
+ });
3198
+ if (!isExpectedContentType) {
3199
+ recordWarning(
3200
+ new Error(
3201
+ `Unexpected content type was produced for App Router page response (isRSCRequest: ${isRSCRequest}, contentType: ${contentType})`
3202
+ ),
3203
+ topLevelSpan
3204
+ );
3205
+ }
3206
+ }
3184
3207
  async function waitForBackgroundWork() {
3185
3208
  await nextHandlerPromise;
3186
3209
  res.emit("close");
@@ -68866,7 +68866,7 @@ var import_semantic_conventions = __toESM(require_src(), 1);
68866
68866
  import { getLogger } from "./request-context.cjs";
68867
68867
  var {
68868
68868
  default: { version, name }
68869
- } = await import("../../esm-chunks/package-7HACW4PO.js");
68869
+ } = await import("../../esm-chunks/package-GF3YXDC5.js");
68870
68870
  var sdk = new import_sdk_node.NodeSDK({
68871
68871
  resource: new import_resources.Resource({
68872
68872
  [import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: name,
@@ -7,7 +7,6 @@
7
7
  import "../esm-chunks/chunk-OEQOKJGE.js";
8
8
 
9
9
  // src/run/headers.ts
10
- import { getLogger } from "./handlers/request-context.cjs";
11
10
  import { recordWarning } from "./handlers/tracer.cjs";
12
11
  import { getMemoizedKeyValueStoreBackedByRegionalBlobStore } from "./storage/storage.cjs";
13
12
  var ALL_VARIATIONS = Symbol.for("ALL_VARIATIONS");
@@ -126,15 +125,11 @@ function setCacheControlFromRequestContext(headers, revalidate) {
126
125
  );
127
126
  headers.set("netlify-cdn-cache-control", cdnCacheControl);
128
127
  }
129
- var setCacheControlHeaders = ({ headers, status }, request, requestContext, nextConfig) => {
128
+ var setCacheControlHeaders = ({ headers, status }, request, requestContext) => {
130
129
  if (typeof requestContext.routeHandlerRevalidate !== "undefined" && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control")) {
131
130
  setCacheControlFromRequestContext(headers, requestContext.routeHandlerRevalidate);
132
131
  return;
133
132
  }
134
- if (status === 308 && request.url.endsWith("/") !== nextConfig.trailingSlash) {
135
- getLogger().withFields({ trailingSlash: nextConfig.trailingSlash, location: headers.get("location") }).log("NetlifyHeadersHandler.trailingSlashRedirect");
136
- }
137
- const cacheControl = headers.get("cache-control");
138
133
  if (status === 404) {
139
134
  if (request.url.endsWith(".php")) {
140
135
  headers.set("cache-control", "public, max-age=0, must-revalidate");
@@ -146,6 +141,7 @@ var setCacheControlHeaders = ({ headers, status }, request, requestContext, next
146
141
  return;
147
142
  }
148
143
  }
144
+ const cacheControl = headers.get("cache-control");
149
145
  if (cacheControl !== null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control")) {
150
146
  const browserCacheControl = omitHeaderValues(cacheControl, [
151
147
  "s-maxage",
@@ -164,13 +160,16 @@ var setCacheControlHeaders = ({ headers, status }, request, requestContext, next
164
160
  headers.set("netlify-cdn-cache-control", cdnCacheControl);
165
161
  return;
166
162
  }
167
- if (cacheControl === null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsReadForNonFallback) {
163
+ if (cacheControl === null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsReadForNonFallback && !requestContext.didPagesRouterOnDemandRevalidate) {
168
164
  headers.set("cache-control", "public, max-age=0, must-revalidate");
169
165
  headers.set("netlify-cdn-cache-control", `max-age=31536000, durable`);
170
166
  }
171
167
  };
172
168
  var setCacheTagsHeaders = (headers, requestContext) => {
173
- if (requestContext.responseCacheTags && (headers.has("cache-control") || headers.has("netlify-cdn-cache-control"))) {
169
+ if (!headers.has("cache-control") && !headers.has("netlify-cdn-cache-control")) {
170
+ return;
171
+ }
172
+ if (requestContext.responseCacheTags) {
174
173
  headers.set("netlify-cache-tag", requestContext.responseCacheTags.join(","));
175
174
  }
176
175
  };
@@ -11,8 +11,8 @@ import { isPromise } from "node:util/types";
11
11
  function isRevalidateMethod(key, nextResponseField) {
12
12
  return key === "revalidate" && typeof nextResponseField === "function";
13
13
  }
14
- var nextResponseProxy = (res, requestContext) => {
15
- return new Proxy(res, {
14
+ var nextResponseProxy = (response, requestContext) => {
15
+ return new Proxy(response, {
16
16
  get(target, key) {
17
17
  const originalValue = Reflect.get(target, key);
18
18
  if (isRevalidateMethod(key, originalValue)) {
@@ -1409,36 +1409,49 @@ function setInMemoryCacheMaxSizeFromNextConfig(size) {
1409
1409
  extendedGlobalThis[IN_MEMORY_CACHE_MAX_SIZE] = size;
1410
1410
  }
1411
1411
  }
1412
- var estimateBlobSize = (valueToStore) => {
1412
+ var isPositiveNumber = (value) => {
1413
+ return typeof value === "number" && value > 0;
1414
+ };
1415
+ var BASE_BLOB_SIZE = 25;
1416
+ var estimateBlobKnownTypeSize = (valueToStore) => {
1413
1417
  if (valueToStore === null || (0, import_types.isPromise)(valueToStore) || (0, import_blob_types.isTagManifest)(valueToStore)) {
1414
- return 25;
1418
+ return BASE_BLOB_SIZE;
1415
1419
  }
1416
1420
  if ((0, import_blob_types.isHtmlBlob)(valueToStore)) {
1417
- return valueToStore.html.length;
1421
+ return BASE_BLOB_SIZE + valueToStore.html.length;
1422
+ }
1423
+ if (valueToStore.value?.kind === "FETCH") {
1424
+ return BASE_BLOB_SIZE + valueToStore.value.data.body.length;
1425
+ }
1426
+ if (valueToStore.value?.kind === "APP_PAGE") {
1427
+ return BASE_BLOB_SIZE + valueToStore.value.html.length + (valueToStore.value.rscData?.length ?? 0);
1418
1428
  }
1419
- let knownKindFailed = false;
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;
1431
+ }
1432
+ if (valueToStore.value?.kind === "ROUTE" || valueToStore.value?.kind === "APP_ROUTE") {
1433
+ return BASE_BLOB_SIZE + valueToStore.value.body.length;
1434
+ }
1435
+ };
1436
+ var estimateBlobSize = (valueToStore) => {
1437
+ let estimatedKnownTypeSize;
1438
+ let estimateBlobKnownTypeSizeError;
1420
1439
  try {
1421
- if (valueToStore.value?.kind === "FETCH") {
1422
- return valueToStore.value.data.body.length;
1423
- }
1424
- if (valueToStore.value?.kind === "APP_PAGE") {
1425
- return valueToStore.value.html.length + (valueToStore.value.rscData?.length ?? 0);
1426
- }
1427
- if (valueToStore.value?.kind === "PAGE" || valueToStore.value?.kind === "PAGES") {
1428
- return valueToStore.value.html.length + JSON.stringify(valueToStore.value.pageData).length;
1440
+ estimatedKnownTypeSize = estimateBlobKnownTypeSize(valueToStore);
1441
+ if (isPositiveNumber(estimatedKnownTypeSize)) {
1442
+ return estimatedKnownTypeSize;
1429
1443
  }
1430
- if (valueToStore.value?.kind === "ROUTE" || valueToStore.value?.kind === "APP_ROUTE") {
1431
- return valueToStore.value.body.length;
1432
- }
1433
- } catch {
1434
- knownKindFailed = true;
1444
+ } catch (error) {
1445
+ estimateBlobKnownTypeSizeError = error;
1435
1446
  }
1447
+ const calculatedSize = JSON.stringify(valueToStore).length;
1436
1448
  (0, import_tracer.recordWarning)(
1437
1449
  new Error(
1438
- `Blob size calculation did fallback to JSON.stringify. Kind: KnownKindFailed: ${knownKindFailed}, ${valueToStore.value?.kind ?? "undefined"}`
1450
+ `Blob size calculation did fallback to JSON.stringify. EstimatedKnownTypeSize: ${estimatedKnownTypeSize}, CalculatedSize: ${calculatedSize}, ValueToStore: ${JSON.stringify(valueToStore)}`,
1451
+ estimateBlobKnownTypeSizeError ? { cause: estimateBlobKnownTypeSizeError } : void 0
1439
1452
  )
1440
1453
  );
1441
- return JSON.stringify(valueToStore).length;
1454
+ return isPositiveNumber(calculatedSize) ? calculatedSize : BASE_BLOB_SIZE;
1442
1455
  };
1443
1456
  function getInMemoryLRUCache() {
1444
1457
  if (typeof extendedGlobalThis[IN_MEMORY_LRU_CACHE] === "undefined") {
@@ -1459,12 +1472,20 @@ var getRequestScopedInMemoryCache = () => {
1459
1472
  return {
1460
1473
  get(key) {
1461
1474
  if (!requestContext) return;
1462
- const value = inMemoryLRUCache?.get(`${requestContext.requestID}:${key}`);
1463
- return value === NullValue ? null : value;
1475
+ try {
1476
+ const value = inMemoryLRUCache?.get(`${requestContext.requestID}:${key}`);
1477
+ return value === NullValue ? null : value;
1478
+ } catch (error) {
1479
+ (0, import_tracer.recordWarning)(new Error("Failed to get value from memory cache", { cause: error }));
1480
+ }
1464
1481
  },
1465
1482
  set(key, value) {
1466
1483
  if (!requestContext) return;
1467
- inMemoryLRUCache?.set(`${requestContext?.requestID}:${key}`, value ?? NullValue);
1484
+ try {
1485
+ inMemoryLRUCache?.set(`${requestContext?.requestID}:${key}`, value ?? NullValue);
1486
+ } catch (error) {
1487
+ (0, import_tracer.recordWarning)(new Error("Failed to store value in memory cache", { cause: error }));
1488
+ }
1468
1489
  }
1469
1490
  };
1470
1491
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.10.2",
3
+ "version": "5.10.4",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",