@netlify/plugin-nextjs 5.0.0-rc.8 → 5.1.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/README.md CHANGED
@@ -1,105 +1,18 @@
1
- # Next.js Runtime
2
-
3
- Next.js is supported natively on Netlify, and in most cases you will not need to install or
4
- configure anything. This repo includes the packages used to support Next.js on Netlify.
5
-
6
- ## Lambda Folder structure:
7
-
8
- For a simple next.js app
9
-
10
- ```
11
- /___netlify-server-handler
12
- ├── .netlify
13
- │ ├── tags-manifest.json
14
- │ └── dist // the compiled runtime code
15
- │ └── run
16
- │ ├── handlers
17
- │ │ ├── server.js
18
- │ │ └── cache.cjs
19
- │ └── next.cjs
20
- ├── .next // or distDir name from the next.config.js
21
- │ └── // content from standalone
22
- ├── run-config.json // the config object from the required-server-files.json
23
- ├── node_modules
24
- ├── ___netlify-server-handler.json
25
- ├── ___netlify-server-handler.mjs
26
- └── package.json
27
- ```
28
-
29
- ## Testing
30
-
31
- The repo includes two types of tests: e2e tests in the repo that use Playwright, integration tests
32
- that use Vitest.
33
-
34
- By default the e2e and integration tests run against the latest version of Next.js. To run tests
35
- against a specific version, set the `NEXT_VERSION` environment variable to the desired version.
36
-
37
- By default, PRs will run the integration tests against the latest version of Next.js. To run tests
38
- against `latest`, `canary` and `13.5.1`, apply the `test all versions` label to the PR when you
39
- create it. These also run nightly and on release PRs.
40
-
41
- ### Integration testing
42
-
43
- > **Prerequisite** Run `npm run build` before running integration tests.
44
-
45
- How to add new integration test scenarios to the application:
46
-
47
- 1. Create a new folder under `tests/fixtures/<your-name>`
48
- 2. Adapt the `next.config.js` to be a standalone application
49
- 3. Create a `postinstall` script that runs the `next build`. It's important to notice that the
50
- integration tests rely on a already built next.js application in this folder. They rely on the
51
- `.next` folder.
52
- 4. Add your test
53
-
54
- > Currently the tests require a built version of the `dist/run/handlers/cache.cjs` so you need to
55
- > run `npm run build` before executing the integration tests.
56
-
57
- In addition, the integration tests need to be prepared before first use. You can do this by running
58
- `npm run pretest`. To speed up this process and build only the fixtures whose name starts with a
59
- given prefix, run `npm run pretest -- <prefix>`.
60
-
61
- ### E2E testing
62
-
63
- > **Prerequisite**
64
- >
65
- > Needs the `netlify-cli` installed and being logged in having access to Netlify Testing
66
- > Organization
67
-
68
- The e2e tests can be invoked with `npm run e2e` and perform a full e2e test. This means they do the
69
- following:
70
-
71
- 1. Building the next-runtime (just running `npm run build` in the repository)
72
- 2. Creating a temp directory and copying the provided fixture over to the directory.
73
- 3. Packing the runtime with `npm pack` to the temp directory.
74
- 4. Installing the runtime from the created zip artifact of `npm pack` (this is like installing a
75
- node_module from the registry)
76
- 5. Creating a `netlify.toml` inside the temp directory of the fixture and adding the runtime as a
77
- plugin.
78
- 6. Running `netlify deploy --build` invoking the runtime. This will use the
79
- [next-runtime-testing](https://app.netlify.com/sites/next-runtime-testing/overview) as site to
80
- deploy to.
81
- 7. Using the `deployId` and `url` of the deployed site to run some
82
- [playwright](https://playwright.dev/) tests against, asserting the correctness of the runtime.
83
- 8. After the tests where run successfully, it will delete the deployment again and clean everything
84
- up. In case of a failure, the deploy won't be cleaned up to leave it for troubleshooting
85
- purposes.
86
-
87
- > [!TIP] If you'd like to always keep the deployment and the local fixture around for
88
- > troubleshooting, run `E2E_PERSIST=1 npm run e2e`.
89
-
90
- ### Next.js tests
91
-
92
- There is a script `run-local-test.sh` and GitHub workflow that runs the e2e tests from the Next.js
93
- repo against this repo. It requires that `next.js` is checked out in the same parent directory as
94
- this repo, and is run from this repo with `./run-local-test.sh your-test-pattern-here`.
95
-
96
- #### cleanup old deploys
97
-
98
- To cleanup old and dangling deploys from failed builds you can run the following script:
99
-
100
- ```bash
101
- npx tsx ./tools/e2e/cleanup-deploys.ts
102
- ```
103
-
104
- This will cleanup all created deploys on the
105
- [next-runtime-testing](https://app.netlify.com/sites/next-runtime-testing/overview) site.
1
+ ![Next.js Runtime](https://github.com/netlify/next-runtime/raw/main/next-js-runtime.png)
2
+
3
+ # `@netlify/plugin-nextjs`
4
+
5
+ <p align="center">
6
+ <a aria-label="npm version" href="https://www.npmjs.com/package/@netlify/plugin-nextjs">
7
+ <img alt="" src="https://img.shields.io/npm/v/@netlify/plugin-nextjs">
8
+ </a>
9
+ <a aria-label="MIT License" href="https://img.shields.io/npm/l/@netlify/plugin-nextjs">
10
+ <img alt="" src="https://img.shields.io/npm/l/@netlify/plugin-nextjs">
11
+ </a>
12
+ </p>
13
+
14
+ This package handles the build process and creates the runtime environment for Next.js sites on
15
+ Netlify. You should not normally need to install it yourself, as it is used automatically during
16
+ builds of Next.js sites. See
17
+ [the docs for using Next.js on Netlify](https://docs.netlify.com/frameworks/next-js/overview/) for
18
+ more details.
@@ -0,0 +1,15 @@
1
+
2
+ var require = await (async () => {
3
+ var { createRequire } = await import("node:module");
4
+ return createRequire(import.meta.url);
5
+ })();
6
+
7
+ import {
8
+ ApiRouteType,
9
+ getAPIRoutesConfigs
10
+ } from "../esm-chunks/chunk-BG455SFE.js";
11
+ import "../esm-chunks/chunk-5JVNISGM.js";
12
+ export {
13
+ ApiRouteType,
14
+ getAPIRoutesConfigs
15
+ };
@@ -7,11 +7,11 @@
7
7
  import {
8
8
  copyFetchContent,
9
9
  copyPrerenderedContent
10
- } from "../../esm-chunks/chunk-4635LKT6.js";
10
+ } from "../../esm-chunks/chunk-MRD3XSKD.js";
11
+ import "../../esm-chunks/chunk-TYCYFZ22.js";
11
12
  import "../../esm-chunks/chunk-PDPDW32D.js";
12
13
  import "../../esm-chunks/chunk-Y3K5Q6FP.js";
13
14
  import "../../esm-chunks/chunk-VZNKO4OO.js";
14
- import "../../esm-chunks/chunk-TYCYFZ22.js";
15
15
  import "../../esm-chunks/chunk-5JVNISGM.js";
16
16
  export {
17
17
  copyFetchContent,
@@ -10,12 +10,13 @@ import {
10
10
  getPatchesToApply,
11
11
  verifyHandlerDirStructure,
12
12
  writeTagsManifest
13
- } from "../../esm-chunks/chunk-YSGPGDIG.js";
13
+ } from "../../esm-chunks/chunk-ZKJEJNSJ.js";
14
14
  import "../../esm-chunks/chunk-PDPDW32D.js";
15
15
  import "../../esm-chunks/chunk-Y3K5Q6FP.js";
16
16
  import "../../esm-chunks/chunk-VZNKO4OO.js";
17
- import "../../esm-chunks/chunk-MGPEWDDD.js";
17
+ import "../../esm-chunks/chunk-PH26UF2W.js";
18
18
  import "../../esm-chunks/chunk-PJG75HGC.js";
19
+ import "../../esm-chunks/chunk-BG455SFE.js";
19
20
  import "../../esm-chunks/chunk-UYKENJEU.js";
20
21
  import "../../esm-chunks/chunk-5JVNISGM.js";
21
22
  export {
@@ -10,11 +10,11 @@ import {
10
10
  copyStaticExport,
11
11
  publishStaticDir,
12
12
  unpublishStaticDir
13
- } from "../../esm-chunks/chunk-GV3YIJ33.js";
13
+ } from "../../esm-chunks/chunk-74THQNRG.js";
14
+ import "../../esm-chunks/chunk-TYCYFZ22.js";
14
15
  import "../../esm-chunks/chunk-PDPDW32D.js";
15
16
  import "../../esm-chunks/chunk-Y3K5Q6FP.js";
16
17
  import "../../esm-chunks/chunk-VZNKO4OO.js";
17
- import "../../esm-chunks/chunk-TYCYFZ22.js";
18
18
  import "../../esm-chunks/chunk-5JVNISGM.js";
19
19
  export {
20
20
  copyStaticAssets,
@@ -6,14 +6,15 @@
6
6
 
7
7
  import {
8
8
  createServerHandler
9
- } from "../../esm-chunks/chunk-757FQQND.js";
10
- import "../../esm-chunks/chunk-YSGPGDIG.js";
9
+ } from "../../esm-chunks/chunk-F5VQRN6L.js";
10
+ import "../../esm-chunks/chunk-ZKJEJNSJ.js";
11
11
  import "../../esm-chunks/chunk-PDPDW32D.js";
12
12
  import "../../esm-chunks/chunk-Y3K5Q6FP.js";
13
13
  import "../../esm-chunks/chunk-VZNKO4OO.js";
14
14
  import "../../esm-chunks/chunk-3NYX5FXN.js";
15
- import "../../esm-chunks/chunk-MGPEWDDD.js";
15
+ import "../../esm-chunks/chunk-PH26UF2W.js";
16
16
  import "../../esm-chunks/chunk-PJG75HGC.js";
17
+ import "../../esm-chunks/chunk-BG455SFE.js";
17
18
  import "../../esm-chunks/chunk-UYKENJEU.js";
18
19
  import "../../esm-chunks/chunk-5JVNISGM.js";
19
20
  export {
@@ -7,12 +7,15 @@
7
7
  import {
8
8
  verifyBuildConfig,
9
9
  verifyNextVersion,
10
+ verifyNoAdvancedAPIRoutes,
10
11
  verifyPublishDir
11
- } from "../esm-chunks/chunk-MGPEWDDD.js";
12
+ } from "../esm-chunks/chunk-PH26UF2W.js";
12
13
  import "../esm-chunks/chunk-PJG75HGC.js";
14
+ import "../esm-chunks/chunk-BG455SFE.js";
13
15
  import "../esm-chunks/chunk-5JVNISGM.js";
14
16
  export {
15
17
  verifyBuildConfig,
16
18
  verifyNextVersion,
19
+ verifyNoAdvancedAPIRoutes,
17
20
  verifyPublishDir
18
21
  };
@@ -647,6 +647,14 @@ var adjustDateHeader = async ({
647
647
  headers.set("date", lastModifiedDate.toUTCString());
648
648
  };
649
649
  var setCacheControlHeaders = (headers, request, requestContext) => {
650
+ if (typeof requestContext.routeHandlerRevalidate !== "undefined" && ["GET", "HEAD"].includes(request.method) && !headers.has("netlify-cdn-cache-control")) {
651
+ const cdnCacheControl = (
652
+ // if we are serving already stale response, instruct edge to not attempt to cache that response
653
+ headers.get("x-nextjs-cache") === "STALE" ? "public, max-age=0, must-revalidate" : `s-maxage=${requestContext.routeHandlerRevalidate === false ? 31536e3 : requestContext.routeHandlerRevalidate}, stale-while-revalidate=31536000`
654
+ );
655
+ headers.set("netlify-cdn-cache-control", cdnCacheControl);
656
+ return;
657
+ }
650
658
  const cacheControl = headers.get("cache-control");
651
659
  if (cacheControl !== null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control")) {
652
660
  const browserCacheControl = omitHeaderValues(cacheControl, [
@@ -662,6 +670,7 @@ var setCacheControlHeaders = (headers, request, requestContext) => {
662
670
  );
663
671
  headers.set("cache-control", browserCacheControl || "public, max-age=0, must-revalidate");
664
672
  headers.set("netlify-cdn-cache-control", cdnCacheControl);
673
+ return;
665
674
  }
666
675
  if (cacheControl === null && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsRead) {
667
676
  headers.set("cache-control", "public, max-age=0, must-revalidate");
@@ -0,0 +1,133 @@
1
+
2
+ var require = await (async () => {
3
+ var { createRequire } = await import("node:module");
4
+ return createRequire(import.meta.url);
5
+ })();
6
+
7
+ import {
8
+ __require
9
+ } from "./chunk-5JVNISGM.js";
10
+
11
+ // src/build/advanced-api-routes.ts
12
+ import { existsSync } from "node:fs";
13
+ import { readFile } from "node:fs/promises";
14
+ import { join } from "node:path";
15
+ var ApiRouteType = /* @__PURE__ */ ((ApiRouteType2) => {
16
+ ApiRouteType2["SCHEDULED"] = "experimental-scheduled";
17
+ ApiRouteType2["BACKGROUND"] = "experimental-background";
18
+ return ApiRouteType2;
19
+ })(ApiRouteType || {});
20
+ async function getAPIRoutesConfigs(ctx) {
21
+ const functionsConfigManifestPath = join(
22
+ ctx.publishDir,
23
+ "server",
24
+ "functions-config-manifest.json"
25
+ );
26
+ if (!existsSync(functionsConfigManifestPath)) {
27
+ return [];
28
+ }
29
+ const functionsConfigManifest = JSON.parse(
30
+ await readFile(functionsConfigManifestPath, "utf-8")
31
+ );
32
+ const appDir = ctx.resolveFromSiteDir(".");
33
+ const pagesDir = join(appDir, "pages");
34
+ const srcPagesDir = join(appDir, "src", "pages");
35
+ const { pageExtensions } = ctx.requiredServerFiles.config;
36
+ return Promise.all(
37
+ Object.keys(functionsConfigManifest.functions).map(async (apiRoute) => {
38
+ const filePath = getSourceFileForPage(apiRoute, [pagesDir, srcPagesDir], pageExtensions);
39
+ const sharedFields = {
40
+ apiRoute,
41
+ filePath,
42
+ config: {}
43
+ };
44
+ if (filePath) {
45
+ const config = await extractConfigFromFile(filePath, appDir);
46
+ return {
47
+ ...sharedFields,
48
+ config
49
+ };
50
+ }
51
+ return sharedFields;
52
+ })
53
+ );
54
+ }
55
+ var SOURCE_FILE_EXTENSIONS = ["js", "jsx", "ts", "tsx"];
56
+ var getSourceFileForPage = (page, roots, pageExtensions = SOURCE_FILE_EXTENSIONS) => {
57
+ for (const root of roots) {
58
+ for (const extension of pageExtensions) {
59
+ const file = join(root, `${page}.${extension}`);
60
+ if (existsSync(file)) {
61
+ return file;
62
+ }
63
+ const fileAtFolderIndex = join(root, page, `index.${extension}`);
64
+ if (existsSync(fileAtFolderIndex)) {
65
+ return fileAtFolderIndex;
66
+ }
67
+ }
68
+ }
69
+ };
70
+ var findModuleFromBase = ({
71
+ paths,
72
+ candidates
73
+ }) => {
74
+ for (const candidate of candidates) {
75
+ try {
76
+ const modulePath = __require.resolve(candidate, { paths });
77
+ if (modulePath) {
78
+ return modulePath;
79
+ }
80
+ } catch {
81
+ }
82
+ }
83
+ for (const candidate of candidates) {
84
+ try {
85
+ const modulePath = __require.resolve(candidate);
86
+ if (modulePath) {
87
+ return modulePath;
88
+ }
89
+ } catch {
90
+ }
91
+ }
92
+ return null;
93
+ };
94
+ var extractConstValue;
95
+ var parseModule;
96
+ var extractConfigFromFile = async (apiFilePath, appDir) => {
97
+ if (!apiFilePath || !existsSync(apiFilePath)) {
98
+ return {};
99
+ }
100
+ const extractConstValueModulePath = findModuleFromBase({
101
+ paths: [appDir],
102
+ candidates: ["next/dist/build/analysis/extract-const-value"]
103
+ });
104
+ const parseModulePath = findModuleFromBase({
105
+ paths: [appDir],
106
+ candidates: ["next/dist/build/analysis/parse-module"]
107
+ });
108
+ if (!extractConstValueModulePath || !parseModulePath) {
109
+ return {};
110
+ }
111
+ if (!extractConstValue && extractConstValueModulePath) {
112
+ extractConstValue = __require(extractConstValueModulePath);
113
+ }
114
+ if (!parseModule && parseModulePath) {
115
+ parseModule = __require(parseModulePath).parseModule;
116
+ }
117
+ const { extractExportedConstValue } = extractConstValue;
118
+ const fileContent = await readFile(apiFilePath, "utf8");
119
+ if (!fileContent.includes("config")) {
120
+ return {};
121
+ }
122
+ const ast = await parseModule(apiFilePath, fileContent);
123
+ try {
124
+ return extractExportedConstValue(ast, "config");
125
+ } catch {
126
+ return {};
127
+ }
128
+ };
129
+
130
+ export {
131
+ ApiRouteType,
132
+ getAPIRoutesConfigs
133
+ };
@@ -9,7 +9,7 @@ import {
9
9
  copyNextServerCode,
10
10
  verifyHandlerDirStructure,
11
11
  writeTagsManifest
12
- } from "./chunk-YSGPGDIG.js";
12
+ } from "./chunk-ZKJEJNSJ.js";
13
13
  import {
14
14
  wrapTracer
15
15
  } from "./chunk-PDPDW32D.js";
@@ -4,6 +4,9 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
+ import {
8
+ encodeBlobKey
9
+ } from "./chunk-TYCYFZ22.js";
7
10
  import {
8
11
  wrapTracer
9
12
  } from "./chunk-PDPDW32D.js";
@@ -14,9 +17,6 @@ import {
14
17
  import {
15
18
  require_out
16
19
  } from "./chunk-VZNKO4OO.js";
17
- import {
18
- encodeBlobKey
19
- } from "./chunk-TYCYFZ22.js";
20
20
  import {
21
21
  __toESM
22
22
  } from "./chunk-5JVNISGM.js";
@@ -165,10 +165,11 @@ var buildAppCacheValue = async (path) => {
165
165
  ...meta
166
166
  };
167
167
  };
168
- var buildRouteCacheValue = async (path) => ({
168
+ var buildRouteCacheValue = async (path, initialRevalidateSeconds) => ({
169
169
  kind: "ROUTE",
170
170
  body: await readFile(`${path}.body`, "base64"),
171
- ...JSON.parse(await readFile(`${path}.meta`, "utf-8"))
171
+ ...JSON.parse(await readFile(`${path}.meta`, "utf-8")),
172
+ revalidate: initialRevalidateSeconds
172
173
  });
173
174
  var buildFetchCacheValue = async (path) => ({
174
175
  kind: "FETCH",
@@ -199,7 +200,10 @@ var copyPrerenderedContent = async (ctx) => {
199
200
  value = await buildAppCacheValue(join(ctx.publishDir, "server/app", key));
200
201
  break;
201
202
  case meta.dataRoute === null:
202
- value = await buildRouteCacheValue(join(ctx.publishDir, "server/app", key));
203
+ value = await buildRouteCacheValue(
204
+ join(ctx.publishDir, "server/app", key),
205
+ meta.initialRevalidateSeconds
206
+ );
203
207
  break;
204
208
  default:
205
209
  throw new Error(`Unrecognized content: ${route}`);
@@ -7,6 +7,9 @@
7
7
  import {
8
8
  require_semver
9
9
  } from "./chunk-PJG75HGC.js";
10
+ import {
11
+ getAPIRoutesConfigs
12
+ } from "./chunk-BG455SFE.js";
10
13
  import {
11
14
  __toESM
12
15
  } from "./chunk-5JVNISGM.js";
@@ -60,9 +63,24 @@ function verifyBuildConfig(ctx) {
60
63
  );
61
64
  }
62
65
  }
66
+ async function verifyNoAdvancedAPIRoutes(ctx) {
67
+ const apiRoutesConfigs = await getAPIRoutesConfigs(ctx);
68
+ const unsupportedAPIRoutes = apiRoutesConfigs.filter((apiRouteConfig) => {
69
+ return apiRouteConfig.config.type === "experimental-background" /* BACKGROUND */ || apiRouteConfig.config.type === "experimental-scheduled" /* SCHEDULED */;
70
+ });
71
+ if (unsupportedAPIRoutes.length !== 0) {
72
+ ctx.failBuild(
73
+ `@netlify/plugin-next@5 does not support advanced API routes. The following API routes should be migrated to Netlify background or scheduled functions:
74
+ ${unsupportedAPIRoutes.map((apiRouteConfig) => ` - ${apiRouteConfig.apiRoute} (type: "${apiRouteConfig.config.type}")`).join("\n")}
75
+
76
+ Refer to https://ntl.fyi/next-scheduled-bg-function-migration as migration example.`
77
+ );
78
+ }
79
+ }
63
80
 
64
81
  export {
65
82
  verifyPublishDir,
66
83
  verifyNextVersion,
67
- verifyBuildConfig
84
+ verifyBuildConfig,
85
+ verifyNoAdvancedAPIRoutes
68
86
  };
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-VZNKO4OO.js";
17
17
  import {
18
18
  verifyNextVersion
19
- } from "./chunk-MGPEWDDD.js";
19
+ } from "./chunk-PH26UF2W.js";
20
20
  import {
21
21
  require_semver
22
22
  } from "./chunk-PJG75HGC.js";
@@ -8,7 +8,7 @@ import "./chunk-5JVNISGM.js";
8
8
 
9
9
  // package.json
10
10
  var name = "@netlify/plugin-nextjs";
11
- var version = "5.0.0-rc.8";
11
+ var version = "5.1.0";
12
12
  var description = "Run Next.js seamlessly on Netlify";
13
13
  var main = "./dist/index.js";
14
14
  var type = "module";
@@ -23,17 +23,22 @@ var engines = {
23
23
  var scripts = {
24
24
  prepack: "clean-package",
25
25
  postpack: "clean-package restore",
26
- pretest: "npm run build && node tests/prepare.mjs",
26
+ pretest: "npm run pretest:integration",
27
+ "pretest:integration": "npm run build && node tests/prepare.mjs",
27
28
  build: "node ./tools/build.js",
28
29
  "build:watch": "node ./tools/build.js --watch",
29
30
  lint: "eslint --cache --format=codeframe --max-warnings=0 --ext .ts,.cts,.js src",
30
31
  "format:fix": "prettier --write .",
31
32
  "format:check": "prettier --check .",
32
33
  test: "vitest",
33
- "test:ci": "vitest run --reporter=default --retry=3",
34
- typecheck: "tsc --noEmit",
35
- e2e: "playwright test",
36
- "e2e:ci": "playwright test"
34
+ "test:unit": "vitest run --project unit",
35
+ "test:integration": "vitest run --project integration",
36
+ "test:smoke": "vitest run --project smoke",
37
+ "test:e2e": "playwright test",
38
+ "test:ci:unit-and-integration": "vitest run --reporter=default --retry=3 --project=unit --project=integration",
39
+ "test:ci:smoke": "vitest run --reporter=default --retry=3 --project=smoke",
40
+ "test:ci:e2e": "playwright test",
41
+ typecheck: "tsc --noEmit"
37
42
  };
38
43
  var repository = {
39
44
  type: "git",
@@ -93,7 +98,7 @@ var devDependencies = {
93
98
  typescript: "^5.1.6",
94
99
  unionfs: "^4.5.1",
95
100
  uuid: "^9.0.1",
96
- vitest: "^1.2.2"
101
+ vitest: "^1.4.0"
97
102
  };
98
103
  var clean_package = {
99
104
  indent: 2,
package/dist/index.js CHANGED
@@ -4,23 +4,21 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
+ import {
8
+ createServerHandler
9
+ } from "./esm-chunks/chunk-F5VQRN6L.js";
7
10
  import {
8
11
  copyPrerenderedContent
9
- } from "./esm-chunks/chunk-4635LKT6.js";
12
+ } from "./esm-chunks/chunk-MRD3XSKD.js";
13
+ import "./esm-chunks/chunk-ZKJEJNSJ.js";
10
14
  import {
11
15
  copyStaticAssets,
12
16
  copyStaticContent,
13
17
  copyStaticExport,
14
18
  publishStaticDir,
15
19
  unpublishStaticDir
16
- } from "./esm-chunks/chunk-GV3YIJ33.js";
17
- import {
18
- createEdgeHandlers
19
- } from "./esm-chunks/chunk-OBKVBMAL.js";
20
- import {
21
- createServerHandler
22
- } from "./esm-chunks/chunk-757FQQND.js";
23
- import "./esm-chunks/chunk-YSGPGDIG.js";
20
+ } from "./esm-chunks/chunk-74THQNRG.js";
21
+ import "./esm-chunks/chunk-TYCYFZ22.js";
24
22
  import {
25
23
  wrapTracer
26
24
  } from "./esm-chunks/chunk-PDPDW32D.js";
@@ -28,6 +26,9 @@ import {
28
26
  init_esm,
29
27
  trace
30
28
  } from "./esm-chunks/chunk-Y3K5Q6FP.js";
29
+ import {
30
+ createEdgeHandlers
31
+ } from "./esm-chunks/chunk-OBKVBMAL.js";
31
32
  import "./esm-chunks/chunk-VZNKO4OO.js";
32
33
  import {
33
34
  restoreBuildCache,
@@ -41,11 +42,12 @@ import {
41
42
  } from "./esm-chunks/chunk-3NYX5FXN.js";
42
43
  import {
43
44
  verifyBuildConfig,
45
+ verifyNoAdvancedAPIRoutes,
44
46
  verifyPublishDir
45
- } from "./esm-chunks/chunk-MGPEWDDD.js";
47
+ } from "./esm-chunks/chunk-PH26UF2W.js";
46
48
  import "./esm-chunks/chunk-PJG75HGC.js";
49
+ import "./esm-chunks/chunk-BG455SFE.js";
47
50
  import "./esm-chunks/chunk-UYKENJEU.js";
48
- import "./esm-chunks/chunk-TYCYFZ22.js";
49
51
  import "./esm-chunks/chunk-5JVNISGM.js";
50
52
 
51
53
  // src/index.ts
@@ -71,6 +73,7 @@ var onBuild = async (options) => {
71
73
  if (ctx.buildConfig.output === "export") {
72
74
  return copyStaticExport(ctx);
73
75
  }
76
+ await verifyNoAdvancedAPIRoutes(ctx);
74
77
  await Promise.all([
75
78
  copyStaticAssets(ctx),
76
79
  copyStaticContent(ctx),
@@ -868,6 +868,14 @@ var NetlifyCacheHandler = class {
868
868
  requestContext.responseCacheGetLastModified = cacheValue.lastModified;
869
869
  }
870
870
  }
871
+ captureRouteRevalidateAndRemoveFromObject(cacheValue) {
872
+ const { revalidate, ...restOfRouteValue } = cacheValue;
873
+ const requestContext = (0, import_request_context.getRequestContext)();
874
+ if (requestContext) {
875
+ requestContext.routeHandlerRevalidate = revalidate;
876
+ }
877
+ return restOfRouteValue;
878
+ }
871
879
  async get(...args) {
872
880
  return this.tracer.withActiveSpan("get cache key", async (span) => {
873
881
  const [key, ctx = {}] = args;
@@ -897,15 +905,17 @@ var NetlifyCacheHandler = class {
897
905
  lastModified: blob.lastModified,
898
906
  value: blob.value
899
907
  };
900
- case "ROUTE":
908
+ case "ROUTE": {
901
909
  span.addEvent("ROUTE", { lastModified: blob.lastModified, status: blob.value.status });
910
+ const valueWithoutRevalidate = this.captureRouteRevalidateAndRemoveFromObject(blob.value);
902
911
  return {
903
912
  lastModified: blob.lastModified,
904
913
  value: {
905
- ...blob.value,
906
- body: import_node_buffer2.Buffer.from(blob.value.body, "base64")
914
+ ...valueWithoutRevalidate,
915
+ body: import_node_buffer2.Buffer.from(valueWithoutRevalidate.body, "base64")
907
916
  }
908
917
  };
918
+ }
909
919
  case "PAGE":
910
920
  span.addEvent("PAGE", { lastModified: blob.lastModified });
911
921
  return {
@@ -920,19 +930,19 @@ var NetlifyCacheHandler = class {
920
930
  }
921
931
  async set(...args) {
922
932
  return this.tracer.withActiveSpan("set cache key", async (span) => {
923
- const [key, data] = args;
933
+ const [key, data, context] = args;
924
934
  const blobKey = await this.encodeBlobKey(key);
925
935
  const lastModified = Date.now();
926
936
  span.setAttributes({ key, lastModified, blobKey });
927
937
  console.debug(`[NetlifyCacheHandler.set]: ${key}`);
928
- let value = data;
929
- if (data?.kind === "ROUTE") {
930
- value = {
938
+ const value = data?.kind === "ROUTE" ? (
939
+ // don't mutate data, as it's used for the initial response - instead create a new object
940
+ {
931
941
  ...data,
932
- // @ts-expect-error gotta find a better solution for this
942
+ revalidate: context.revalidate,
933
943
  body: data.body.toString("base64")
934
- };
935
- }
944
+ }
945
+ ) : data;
936
946
  await this.blobStore.setJSON(blobKey, {
937
947
  lastModified,
938
948
  value
@@ -4,24 +4,24 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
+ import {
8
+ adjustDateHeader,
9
+ setCacheControlHeaders,
10
+ setCacheStatusHeader,
11
+ setCacheTagsHeaders,
12
+ setVaryHeaders
13
+ } from "../../esm-chunks/chunk-57DK2TJ7.js";
7
14
  import {
8
15
  nextResponseProxy
9
16
  } from "../../esm-chunks/chunk-RL4K4CVH.js";
10
17
  import {
11
18
  import_internal
12
19
  } from "../../esm-chunks/chunk-HYBEXB2Z.js";
20
+ import "../../esm-chunks/chunk-TYCYFZ22.js";
13
21
  import {
14
22
  getTagsManifest
15
23
  } from "../../esm-chunks/chunk-3SUDZQ7L.js";
16
24
  import "../../esm-chunks/chunk-UYKENJEU.js";
17
- import {
18
- adjustDateHeader,
19
- setCacheControlHeaders,
20
- setCacheStatusHeader,
21
- setCacheTagsHeaders,
22
- setVaryHeaders
23
- } from "../../esm-chunks/chunk-M2ZKGJAI.js";
24
- import "../../esm-chunks/chunk-TYCYFZ22.js";
25
25
  import {
26
26
  __commonJS,
27
27
  __toESM
@@ -51202,7 +51202,7 @@ var import_sdk_trace_node = __toESM(require_src14(), 1);
51202
51202
  var import_semantic_conventions = __toESM(require_src(), 1);
51203
51203
  var {
51204
51204
  default: { version, name }
51205
- } = await import("../../esm-chunks/package-NFGYFGF2.js");
51205
+ } = await import("../../esm-chunks/package-RGWYJEMK.js");
51206
51206
  var sdk = new import_sdk_node.NodeSDK({
51207
51207
  resource: new import_resources.Resource({
51208
51208
  [import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: name,
@@ -10,7 +10,7 @@ import {
10
10
  setCacheStatusHeader,
11
11
  setCacheTagsHeaders,
12
12
  setVaryHeaders
13
- } from "../esm-chunks/chunk-M2ZKGJAI.js";
13
+ } from "../esm-chunks/chunk-57DK2TJ7.js";
14
14
  import "../esm-chunks/chunk-TYCYFZ22.js";
15
15
  import "../esm-chunks/chunk-5JVNISGM.js";
16
16
  export {
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/shared/cache-types.cts
17
+ var cache_types_exports = {};
18
+ module.exports = __toCommonJS(cache_types_exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "5.0.0-rc.8",
3
+ "version": "5.1.0",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
@@ -4,6 +4,9 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
+ import {
8
+ encodeBlobKey
9
+ } from "./chunk-TYCYFZ22.js";
7
10
  import {
8
11
  wrapTracer
9
12
  } from "./chunk-PDPDW32D.js";
@@ -14,9 +17,6 @@ import {
14
17
  import {
15
18
  require_out
16
19
  } from "./chunk-VZNKO4OO.js";
17
- import {
18
- encodeBlobKey
19
- } from "./chunk-TYCYFZ22.js";
20
20
  import {
21
21
  __toESM
22
22
  } from "./chunk-5JVNISGM.js";