@netlify/plugin-nextjs 5.0.0-beta.8 → 5.0.0-rc.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.
Files changed (40) hide show
  1. package/README.md +23 -0
  2. package/dist/build/cache.js +1 -1
  3. package/dist/build/content/prerendered.js +2 -1
  4. package/dist/build/content/server.js +2 -1
  5. package/dist/build/content/static.js +1 -1
  6. package/dist/build/functions/edge.js +2 -3
  7. package/dist/build/functions/server.js +4 -4
  8. package/dist/build/image-cdn.js +3 -1
  9. package/dist/build/plugin-context.js +1 -2
  10. package/dist/build/templates/handler-monorepo.tmpl.js +33 -30
  11. package/dist/build/templates/handler.tmpl.js +31 -25
  12. package/dist/esm-chunks/{chunk-YMFYCTRI.js → chunk-4J4A5OE2.js} +23 -3
  13. package/dist/esm-chunks/{chunk-XFDUV7DP.js → chunk-67EWAGDQ.js} +29 -20
  14. package/dist/esm-chunks/chunk-72ZI2IVI.js +36 -0
  15. package/dist/esm-chunks/{chunk-WSPFUAK4.js → chunk-FTCARYDZ.js} +6 -6
  16. package/dist/esm-chunks/{chunk-XIP2W57K.js → chunk-NL5YH5N6.js} +5 -4
  17. package/dist/esm-chunks/{chunk-IZ2AVCVF.js → chunk-PGQNT7XM.js} +52 -24
  18. package/dist/esm-chunks/chunk-RL4K4CVH.js +27 -0
  19. package/dist/esm-chunks/{chunk-N23TUUXK.js → chunk-UTCWWUFW.js} +68 -29
  20. package/dist/esm-chunks/{chunk-ETPYUOBQ.js → chunk-UX4JCTAE.js} +5 -5
  21. package/dist/esm-chunks/{chunk-K233JI4O.js → chunk-UYKENJEU.js} +4 -2
  22. package/dist/esm-chunks/{chunk-ZWFKLYLH.js → chunk-WQIG4U66.js} +5 -4
  23. package/dist/esm-chunks/chunk-XXBTIYSL.js +7199 -0
  24. package/dist/esm-chunks/{package-2CI3IXK3.js → package-5SG7C3OT.js} +13 -8
  25. package/dist/index.js +13 -14
  26. package/dist/run/config.js +2 -2
  27. package/dist/run/constants.js +5 -3
  28. package/dist/run/handlers/cache.cjs +165 -79
  29. package/dist/run/handlers/request-context.cjs +56 -0
  30. package/dist/run/handlers/server.js +34 -20
  31. package/dist/run/handlers/tracing.js +1 -1
  32. package/dist/run/headers.js +3 -3
  33. package/dist/run/next.cjs +6 -1
  34. package/dist/run/revalidate.js +1 -1
  35. package/edge-runtime/lib/response.ts +25 -21
  36. package/edge-runtime/lib/util.ts +6 -1
  37. package/package.json +1 -1
  38. package/dist/esm-chunks/chunk-EPSI5TTB.js +0 -28
  39. package/dist/esm-chunks/chunk-WT2HN3M6.js +0 -255
  40. package/dist/esm-chunks/chunk-XA2CZH5Y.js +0 -32
package/README.md CHANGED
@@ -3,6 +3,29 @@
3
3
  Next.js is supported natively on Netlify, and in most cases you will not need to install or
4
4
  configure anything. This repo includes the packages used to support Next.js on Netlify.
5
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
+
6
29
  ## Testing
7
30
 
8
31
  ### Integration testing
@@ -7,7 +7,7 @@
7
7
  import {
8
8
  restoreBuildCache,
9
9
  saveBuildCache
10
- } from "../esm-chunks/chunk-XA2CZH5Y.js";
10
+ } from "../esm-chunks/chunk-72ZI2IVI.js";
11
11
  import "../esm-chunks/chunk-5JVNISGM.js";
12
12
  export {
13
13
  restoreBuildCache,
@@ -7,8 +7,9 @@
7
7
  import {
8
8
  copyFetchContent,
9
9
  copyPrerenderedContent
10
- } from "../../esm-chunks/chunk-XFDUV7DP.js";
10
+ } from "../../esm-chunks/chunk-67EWAGDQ.js";
11
11
  import "../../esm-chunks/chunk-VZNKO4OO.js";
12
+ import "../../esm-chunks/chunk-TYCYFZ22.js";
12
13
  import "../../esm-chunks/chunk-5JVNISGM.js";
13
14
  export {
14
15
  copyFetchContent,
@@ -8,8 +8,9 @@ import {
8
8
  copyNextDependencies,
9
9
  copyNextServerCode,
10
10
  writeTagsManifest
11
- } from "../../esm-chunks/chunk-YMFYCTRI.js";
11
+ } from "../../esm-chunks/chunk-4J4A5OE2.js";
12
12
  import "../../esm-chunks/chunk-VZNKO4OO.js";
13
+ import "../../esm-chunks/chunk-UYKENJEU.js";
13
14
  import "../../esm-chunks/chunk-5JVNISGM.js";
14
15
  export {
15
16
  copyNextDependencies,
@@ -9,7 +9,7 @@ import {
9
9
  copyStaticContent,
10
10
  publishStaticDir,
11
11
  unpublishStaticDir
12
- } from "../../esm-chunks/chunk-ZWFKLYLH.js";
12
+ } from "../../esm-chunks/chunk-WQIG4U66.js";
13
13
  import "../../esm-chunks/chunk-VZNKO4OO.js";
14
14
  import "../../esm-chunks/chunk-TYCYFZ22.js";
15
15
  import "../../esm-chunks/chunk-5JVNISGM.js";
@@ -6,10 +6,9 @@
6
6
 
7
7
  import {
8
8
  createEdgeHandlers
9
- } from "../../esm-chunks/chunk-ETPYUOBQ.js";
10
- import "../../esm-chunks/chunk-IZ2AVCVF.js";
9
+ } from "../../esm-chunks/chunk-UX4JCTAE.js";
11
10
  import "../../esm-chunks/chunk-VZNKO4OO.js";
12
- import "../../esm-chunks/chunk-TYCYFZ22.js";
11
+ import "../../esm-chunks/chunk-PGQNT7XM.js";
13
12
  import "../../esm-chunks/chunk-5JVNISGM.js";
14
13
  export {
15
14
  createEdgeHandlers
@@ -6,11 +6,11 @@
6
6
 
7
7
  import {
8
8
  createServerHandler
9
- } from "../../esm-chunks/chunk-WSPFUAK4.js";
10
- import "../../esm-chunks/chunk-YMFYCTRI.js";
11
- import "../../esm-chunks/chunk-IZ2AVCVF.js";
9
+ } from "../../esm-chunks/chunk-FTCARYDZ.js";
10
+ import "../../esm-chunks/chunk-4J4A5OE2.js";
12
11
  import "../../esm-chunks/chunk-VZNKO4OO.js";
13
- import "../../esm-chunks/chunk-TYCYFZ22.js";
12
+ import "../../esm-chunks/chunk-PGQNT7XM.js";
13
+ import "../../esm-chunks/chunk-UYKENJEU.js";
14
14
  import "../../esm-chunks/chunk-5JVNISGM.js";
15
15
  export {
16
16
  createServerHandler
@@ -5,9 +5,11 @@
5
5
  })();
6
6
 
7
7
  import {
8
+ generateRegexFromPattern,
8
9
  setImageConfig
9
- } from "../esm-chunks/chunk-EPSI5TTB.js";
10
+ } from "../esm-chunks/chunk-XXBTIYSL.js";
10
11
  import "../esm-chunks/chunk-5JVNISGM.js";
11
12
  export {
13
+ generateRegexFromPattern,
12
14
  setImageConfig
13
15
  };
@@ -8,8 +8,7 @@ import {
8
8
  EDGE_HANDLER_NAME,
9
9
  PluginContext,
10
10
  SERVER_HANDLER_NAME
11
- } from "../esm-chunks/chunk-IZ2AVCVF.js";
12
- import "../esm-chunks/chunk-TYCYFZ22.js";
11
+ } from "../esm-chunks/chunk-PGQNT7XM.js";
13
12
  import "../esm-chunks/chunk-5JVNISGM.js";
14
13
  export {
15
14
  EDGE_HANDLER_NAME,
@@ -1,4 +1,4 @@
1
- import tracing, { trace } from '{{cwd}}/dist/run/handlers/tracing.js'
1
+ import tracing, { trace } from '{{cwd}}/.netlify/dist/run/handlers/tracing.js'
2
2
 
3
3
  process.chdir('{{cwd}}')
4
4
 
@@ -8,36 +8,39 @@ export default async function (req, context) {
8
8
  tracing.start()
9
9
  }
10
10
 
11
- return trace
12
- .getTracer('Next.js Runtime')
13
- .startActiveSpan('Next.js Server Handler', async (span) => {
14
- try {
15
- span.setAttributes({
16
- 'account.id': context.account.id,
17
- 'deploy.id': context.deploy.id,
18
- 'request.id': context.requestId,
19
- 'site.id': context.site.id,
20
- 'http.method': req.method,
21
- 'http.target': req.url,
22
- monorepo: true,
23
- cwd: '{{cwd}}',
24
- })
25
- if (!cachedHandler) {
26
- const { default: handler } = await import('./{{nextServerHandler}}')
27
- cachedHandler = handler
28
- }
29
- const response = await cachedHandler(req, context)
30
- span.setAttributes({
31
- 'http.status_code': response.status,
32
- })
33
- return response
34
- } catch (error) {
35
- span.recordException(error)
36
- throw error
37
- } finally {
38
- span.end()
11
+ /** @type {import('@opentelemetry/api').Tracer} */
12
+ const tracer = trace.getTracer('Next.js Runtime')
13
+ return tracer.startActiveSpan('Next.js Server Handler', async (span) => {
14
+ try {
15
+ span.setAttributes({
16
+ 'account.id': context.account.id,
17
+ 'deploy.id': context.deploy.id,
18
+ 'request.id': context.requestId,
19
+ 'site.id': context.site.id,
20
+ 'http.method': req.method,
21
+ 'http.target': req.url,
22
+ monorepo: true,
23
+ cwd: '{{cwd}}',
24
+ })
25
+ if (!cachedHandler) {
26
+ const { default: handler } = await import('{{nextServerHandler}}')
27
+ cachedHandler = handler
39
28
  }
40
- })
29
+ const response = await cachedHandler(req, context)
30
+ span.setAttributes({
31
+ 'http.status_code': response.status,
32
+ })
33
+ return response
34
+ } catch (error) {
35
+ span.recordException(error)
36
+ if (error instanceof Error) {
37
+ span.addEvent({ name: error.name, message: error.message })
38
+ }
39
+ throw error
40
+ } finally {
41
+ span.end()
42
+ }
43
+ })
41
44
  }
42
45
 
43
46
  export const config = {
@@ -1,34 +1,40 @@
1
- import serverHandler from './dist/run/handlers/server.js'
2
- import tracing, { trace } from './dist/run/handlers/tracing.js'
1
+ import serverHandler from './.netlify/dist/run/handlers/server.js'
2
+ import tracing, { trace } from './.netlify/dist/run/handlers/tracing.js'
3
3
 
4
4
  export default async function handler(req, context) {
5
5
  if (process.env.NETLIFY_OTLP_TRACE_EXPORTER_URL) {
6
6
  tracing.start()
7
7
  }
8
- return trace
9
- .getTracer('Next.js Runtime')
10
- .startActiveSpan('Next.js Server Handler', async (span) => {
11
- try {
12
- span.setAttributes({
13
- 'account.id': context.account.id,
14
- 'deploy.id': context.deploy.id,
15
- 'request.id': context.requestId,
16
- 'site.id': context.site.id,
17
- 'http.method': req.method,
18
- 'http.target': req.url,
19
- })
20
- const response = await serverHandler(req, context)
21
- span.setAttributes({
22
- 'http.status_code': response.status,
23
- })
24
- return response
25
- } catch (error) {
26
- span.recordException(error)
27
- throw error
28
- } finally {
29
- span.end()
8
+
9
+ /** @type {import('@opentelemetry/api').Tracer} */
10
+ const tracer = trace.getTracer('Next.js Runtime')
11
+ return tracer.startActiveSpan('Next.js Server Handler', async (span) => {
12
+ try {
13
+ span.setAttributes({
14
+ 'account.id': context.account.id,
15
+ 'deploy.id': context.deploy.id,
16
+ 'request.id': context.requestId,
17
+ 'site.id': context.site.id,
18
+ 'http.method': req.method,
19
+ 'http.target': req.url,
20
+ monorepo: false,
21
+ cwd: process.cwd(),
22
+ })
23
+ const response = await serverHandler(req, context)
24
+ span.setAttributes({
25
+ 'http.status_code': response.status,
26
+ })
27
+ return response
28
+ } catch (error) {
29
+ span.recordException(error)
30
+ if (error instanceof Error) {
31
+ span.addEvent({ name: error.name, message: error.message })
30
32
  }
31
- })
33
+ throw error
34
+ } finally {
35
+ span.end()
36
+ }
37
+ })
32
38
  }
33
39
 
34
40
  export const config = {
@@ -7,6 +7,9 @@
7
7
  import {
8
8
  require_out
9
9
  } from "./chunk-VZNKO4OO.js";
10
+ import {
11
+ RUN_CONFIG
12
+ } from "./chunk-UYKENJEU.js";
10
13
  import {
11
14
  __toESM
12
15
  } from "./chunk-5JVNISGM.js";
@@ -18,8 +21,25 @@ import { cp, mkdir, readFile, readdir, readlink, symlink, writeFile } from "node
18
21
  import { createRequire } from "node:module";
19
22
  import { dirname, join, resolve } from "node:path";
20
23
  var copyNextServerCode = async (ctx) => {
21
- const srcDir = join(ctx.standaloneDir, ".next");
22
- const destDir = join(ctx.serverHandlerDir, ".next");
24
+ const reqServerFilesPath = join(
25
+ ctx.standaloneRootDir,
26
+ ctx.relPublishDir,
27
+ "required-server-files.json"
28
+ );
29
+ const reqServerFiles = JSON.parse(await readFile(reqServerFilesPath, "utf-8"));
30
+ if (ctx.distDir.replace(new RegExp(`^${ctx.packagePath}/?`), "") !== reqServerFiles.config.distDir) {
31
+ reqServerFiles.config.distDir = ctx.nextDistDir;
32
+ await writeFile(reqServerFilesPath, JSON.stringify(reqServerFiles));
33
+ }
34
+ await mkdir(ctx.serverHandlerDir, { recursive: true });
35
+ await writeFile(
36
+ join(ctx.serverHandlerDir, RUN_CONFIG),
37
+ JSON.stringify(reqServerFiles.config),
38
+ "utf-8"
39
+ );
40
+ const srcDir = join(ctx.standaloneDir, ctx.nextDistDir);
41
+ const nextFolder = ctx.distDir === ctx.buildConfig.distDir ? ctx.distDir : ctx.nextDistDir;
42
+ const destDir = join(ctx.serverHandlerDir, nextFolder);
23
43
  const paths = await (0, import_fast_glob.default)(
24
44
  [`*`, `server/*`, `server/chunks/*`, `server/edge-chunks/*`, `server/+(app|pages)/**/*.js`],
25
45
  {
@@ -67,7 +87,7 @@ async function recreateNodeModuleSymlinks(src, dest, org) {
67
87
  var copyNextDependencies = async (ctx) => {
68
88
  const entries = await readdir(ctx.standaloneDir);
69
89
  const promises = entries.map(async (entry) => {
70
- if (entry === "package.json" || entry === ".next") {
90
+ if (entry === "package.json" || entry === ctx.nextDistDir) {
71
91
  return;
72
92
  }
73
93
  const src = join(ctx.standaloneDir, entry);
@@ -7,6 +7,9 @@
7
7
  import {
8
8
  require_out
9
9
  } from "./chunk-VZNKO4OO.js";
10
+ import {
11
+ encodeBlobKey
12
+ } from "./chunk-TYCYFZ22.js";
10
13
  import {
11
14
  __toESM
12
15
  } from "./chunk-5JVNISGM.js";
@@ -14,13 +17,25 @@ import {
14
17
  // src/build/content/prerendered.ts
15
18
  var import_fast_glob = __toESM(require_out(), 1);
16
19
  import { existsSync } from "node:fs";
17
- import { readFile } from "node:fs/promises";
18
- import { join } from "node:path";
20
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
21
+ import { dirname, join } from "node:path";
22
+ var writeCacheEntry = async (route, value, lastModified, ctx) => {
23
+ const path = join(ctx.blobDir, await encodeBlobKey(route));
24
+ const entry = JSON.stringify({
25
+ lastModified,
26
+ value
27
+ });
28
+ await mkdir(dirname(path), { recursive: true });
29
+ await writeFile(path, entry, "utf-8");
30
+ };
19
31
  var routeToFilePath = (path) => path === "/" ? "/index" : path;
20
32
  var buildPagesCacheValue = async (path) => ({
21
33
  kind: "PAGE",
22
34
  html: await readFile(`${path}.html`, "utf-8"),
23
- pageData: JSON.parse(await readFile(`${path}.json`, "utf-8"))
35
+ pageData: JSON.parse(await readFile(`${path}.json`, "utf-8")),
36
+ postponed: void 0,
37
+ headers: void 0,
38
+ status: void 0
24
39
  });
25
40
  var buildAppCacheValue = async (path) => ({
26
41
  kind: "PAGE",
@@ -42,39 +57,32 @@ var copyPrerenderedContent = async (ctx) => {
42
57
  const manifest = await ctx.getPrerenderManifest();
43
58
  await Promise.all(
44
59
  Object.entries(manifest.routes).map(async ([route, meta]) => {
60
+ const lastModified = meta.initialRevalidateSeconds ? Date.now() - 31536e6 : Date.now();
45
61
  const key = routeToFilePath(route);
46
62
  let value;
47
- let path;
48
63
  switch (true) {
49
64
  case (meta.dataRoute?.endsWith("/default.rsc") && !existsSync(join(ctx.publishDir, "server/app", `${key}.html`))):
50
65
  return;
51
66
  case meta.dataRoute?.endsWith(".json"):
52
- path = join(ctx.publishDir, "server/pages", key);
53
- value = await buildPagesCacheValue(path);
67
+ value = await buildPagesCacheValue(join(ctx.publishDir, "server/pages", key));
54
68
  break;
55
69
  case meta.dataRoute?.endsWith(".rsc"):
56
- path = join(ctx.publishDir, "server/app", key);
57
- value = await buildAppCacheValue(path);
70
+ value = await buildAppCacheValue(join(ctx.publishDir, "server/app", key));
58
71
  break;
59
72
  case meta.dataRoute === null:
60
- path = join(ctx.publishDir, "server/app", key);
61
- value = await buildRouteCacheValue(path);
73
+ value = await buildRouteCacheValue(join(ctx.publishDir, "server/app", key));
62
74
  break;
63
75
  default:
64
76
  throw new Error(`Unrecognized content: ${route}`);
65
77
  }
66
- await ctx.writeCacheEntry(
67
- key,
68
- value,
69
- meta.dataRoute === null ? `${path}.body` : `${path}.html`
70
- );
78
+ await writeCacheEntry(key, value, lastModified, ctx);
71
79
  })
72
80
  );
73
81
  if (existsSync(join(ctx.publishDir, `server/app/_not-found.html`))) {
82
+ const lastModified = Date.now();
74
83
  const key = "/404";
75
- const path = join(ctx.publishDir, "server/app/_not-found");
76
- const value = await buildAppCacheValue(path);
77
- await ctx.writeCacheEntry(key, value, `${path}.html`);
84
+ const value = await buildAppCacheValue(join(ctx.publishDir, "server/app/_not-found"));
85
+ await writeCacheEntry(key, value, lastModified, ctx);
78
86
  }
79
87
  } catch (error) {
80
88
  ctx.failBuild("Failed assembling prerendered content for upload", error);
@@ -82,15 +90,16 @@ var copyPrerenderedContent = async (ctx) => {
82
90
  };
83
91
  var copyFetchContent = async (ctx) => {
84
92
  try {
85
- const paths = await (0, import_fast_glob.default)(["!(*.*)"], {
93
+ const paths = await (0, import_fast_glob.glob)(["!(*.*)"], {
86
94
  cwd: join(ctx.publishDir, "cache/fetch-cache"),
87
95
  extglob: true
88
96
  });
89
97
  await Promise.all(
90
98
  paths.map(async (key) => {
99
+ const lastModified = Date.now() - 31536e6;
91
100
  const path = join(ctx.publishDir, "cache/fetch-cache", key);
92
101
  const value = await buildFetchCacheValue(path);
93
- await ctx.writeCacheEntry(key, value, path);
102
+ await writeCacheEntry(key, value, lastModified, ctx);
94
103
  })
95
104
  );
96
105
  } catch (error) {
@@ -0,0 +1,36 @@
1
+
2
+ var require = await (async () => {
3
+ var { createRequire } = await import("node:module");
4
+ return createRequire(import.meta.url);
5
+ })();
6
+
7
+
8
+ // src/build/cache.ts
9
+ import { existsSync } from "node:fs";
10
+ import { rm } from "node:fs/promises";
11
+ import { join } from "node:path";
12
+ var saveBuildCache = async (ctx) => {
13
+ const { cache } = ctx.utils;
14
+ const cacheDir = join(ctx.publishDir, "cache");
15
+ if (existsSync(cacheDir)) {
16
+ await rm(join(cacheDir, "fetch-cache"), { recursive: true, force: true });
17
+ await cache.save(cacheDir);
18
+ console.log("Next.js cache saved");
19
+ } else {
20
+ console.log("No Next.js cache to save");
21
+ }
22
+ };
23
+ var restoreBuildCache = async (ctx) => {
24
+ const { cache } = ctx.utils;
25
+ const cacheDir = join(ctx.publishDir, "cache");
26
+ if (await cache.restore(cacheDir)) {
27
+ console.log("Next.js cache restored");
28
+ } else {
29
+ console.log("No Next.js cache to restore");
30
+ }
31
+ };
32
+
33
+ export {
34
+ saveBuildCache,
35
+ restoreBuildCache
36
+ };
@@ -8,13 +8,13 @@ import {
8
8
  copyNextDependencies,
9
9
  copyNextServerCode,
10
10
  writeTagsManifest
11
- } from "./chunk-YMFYCTRI.js";
12
- import {
13
- SERVER_HANDLER_NAME
14
- } from "./chunk-IZ2AVCVF.js";
11
+ } from "./chunk-4J4A5OE2.js";
15
12
  import {
16
13
  require_out
17
14
  } from "./chunk-VZNKO4OO.js";
15
+ import {
16
+ SERVER_HANDLER_NAME
17
+ } from "./chunk-PGQNT7XM.js";
18
18
  import {
19
19
  __toESM
20
20
  } from "./chunk-5JVNISGM.js";
@@ -27,7 +27,7 @@ var copyHandlerDependencies = async (ctx) => {
27
27
  const fileList = await (0, import_fast_glob.glob)("dist/**/*", { cwd: ctx.pluginDir });
28
28
  await Promise.all(
29
29
  [...fileList].map(
30
- (path) => cp(join(ctx.pluginDir, path), join(ctx.serverHandlerDir, path), {
30
+ (path) => cp(join(ctx.pluginDir, path), join(ctx.serverHandlerDir, ".netlify", path), {
31
31
  recursive: true,
32
32
  force: true
33
33
  })
@@ -61,7 +61,7 @@ var getHandlerFile = async (ctx) => {
61
61
  const templatesDir = join(ctx.pluginDir, "dist/build/templates");
62
62
  if (ctx.packagePath.length !== 0) {
63
63
  const template = await readFile(join(templatesDir, "handler-monorepo.tmpl.js"), "utf-8");
64
- return template.replaceAll("{{cwd}}", join("/var/task", ctx.packagePath)).replace("{{nextServerHandler}}", ctx.nextServerHandler);
64
+ return template.replaceAll("{{cwd}}", ctx.lambdaWorkingDirectory).replace("{{nextServerHandler}}", ctx.nextServerHandler);
65
65
  }
66
66
  return await readFile(join(templatesDir, "handler.tmpl.js"), "utf-8");
67
67
  };
@@ -5,18 +5,19 @@
5
5
  })();
6
6
 
7
7
  import {
8
- PLUGIN_DIR
9
- } from "./chunk-K233JI4O.js";
8
+ PLUGIN_DIR,
9
+ RUN_CONFIG
10
+ } from "./chunk-UYKENJEU.js";
10
11
 
11
12
  // src/run/config.ts
12
13
  import { existsSync } from "node:fs";
13
14
  import { readFile } from "node:fs/promises";
14
15
  import { join, resolve } from "node:path";
15
16
  var getRunConfig = async () => {
16
- return JSON.parse(await readFile(resolve(".next/required-server-files.json"), "utf-8")).config;
17
+ return JSON.parse(await readFile(resolve(RUN_CONFIG), "utf-8"));
17
18
  };
18
19
  var setRunConfig = (config) => {
19
- const cacheHandler = join(PLUGIN_DIR, "dist/run/handlers/cache.cjs");
20
+ const cacheHandler = join(PLUGIN_DIR, ".netlify/dist/run/handlers/cache.cjs");
20
21
  if (!existsSync(cacheHandler)) {
21
22
  throw new Error(`Cache handler not found at ${cacheHandler}`);
22
23
  }
@@ -4,17 +4,15 @@
4
4
  return createRequire(import.meta.url);
5
5
  })();
6
6
 
7
- import {
8
- encodeBlobKey
9
- } from "./chunk-TYCYFZ22.js";
10
7
 
11
8
  // src/build/plugin-context.ts
12
9
  import { readFileSync } from "node:fs";
13
- import { mkdir, readFile, writeFile, stat } from "node:fs/promises";
14
- import { dirname, join, resolve } from "node:path";
10
+ import { readFile } from "node:fs/promises";
11
+ import { join, relative, resolve } from "node:path";
15
12
  import { fileURLToPath } from "node:url";
16
13
  var MODULE_DIR = fileURLToPath(new URL(".", import.meta.url));
17
14
  var PLUGIN_DIR = join(MODULE_DIR, "../..");
15
+ var DEFAULT_PUBLISH_DIR = ".next";
18
16
  var SERVER_HANDLER_NAME = "___netlify-server-handler";
19
17
  var EDGE_HANDLER_NAME = "___netlify-edge-handler";
20
18
  var PluginContext = class {
@@ -26,9 +24,16 @@ var PluginContext = class {
26
24
  packageJSON;
27
25
  /** Absolute path of the next runtime plugin directory */
28
26
  pluginDir = PLUGIN_DIR;
27
+ get relPublishDir() {
28
+ return this.constants.PUBLISH_DIR ?? join(this.packagePath, DEFAULT_PUBLISH_DIR);
29
+ }
30
+ /** Temporary directory for stashing the build output */
31
+ get tempPublishDir() {
32
+ return this.resolve(".netlify/.next");
33
+ }
29
34
  /** Absolute path of the publish directory */
30
35
  get publishDir() {
31
- return resolve(this.constants.PUBLISH_DIR);
36
+ return resolve(this.relPublishDir);
32
37
  }
33
38
  /**
34
39
  * Relative package path in non monorepo setups this is an empty string
@@ -38,15 +43,38 @@ var PluginContext = class {
38
43
  get packagePath() {
39
44
  return this.constants.PACKAGE_PATH || "";
40
45
  }
46
+ /**
47
+ * The working directory inside the lambda that is used for monorepos to execute the serverless function
48
+ */
49
+ get lambdaWorkingDirectory() {
50
+ return join("/var/task", this.distFolder);
51
+ }
41
52
  /**
42
53
  * Retrieves the root of the `.next/standalone` directory
43
54
  */
44
55
  get standaloneRootDir() {
45
56
  return join(this.publishDir, "standalone");
46
57
  }
58
+ /**
59
+ * The resolved relative next dist directory defaults to `.next`,
60
+ * but can be configured through the next.config.js. For monorepos this will include the packagePath
61
+ * If we need just the plain dist dir use the `nextDistDir`
62
+ */
63
+ get distDir() {
64
+ const dir = this.buildConfig.distDir ?? DEFAULT_PUBLISH_DIR;
65
+ return relative(process.cwd(), resolve(this.packagePath, dir));
66
+ }
67
+ /** The dist folder represents the parent directory of the .next folder or custom distDir */
68
+ get distFolder() {
69
+ return join(this.distDir, "..");
70
+ }
71
+ /** The `.next` folder or what the custom dist dir is set to */
72
+ get nextDistDir() {
73
+ return relative(this.distFolder, this.distDir);
74
+ }
47
75
  /** Retrieves the `.next/standalone/` directory monorepo aware */
48
76
  get standaloneDir() {
49
- return join(this.standaloneRootDir, this.constants.PACKAGE_PATH || "");
77
+ return join(this.standaloneRootDir, this.distFolder);
50
78
  }
51
79
  /**
52
80
  * Absolute path of the directory that is published and deployed to the Netlify CDN
@@ -75,10 +103,16 @@ var PluginContext = class {
75
103
  return join(this.serverFunctionsDir, SERVER_HANDLER_NAME);
76
104
  }
77
105
  get serverHandlerDir() {
78
- return join(this.serverHandlerRootDir, this.constants.PACKAGE_PATH || "");
106
+ if (this.packagePath.length === 0) {
107
+ return this.serverHandlerRootDir;
108
+ }
109
+ return join(this.serverHandlerRootDir, this.distFolder);
79
110
  }
80
111
  get nextServerHandler() {
81
- return join(this.constants.PACKAGE_PATH || "", "dist/run/handlers/server.js");
112
+ if (this.packagePath.length !== 0) {
113
+ return join(this.lambdaWorkingDirectory, ".netlify/dist/run/handlers/server.js");
114
+ }
115
+ return "./.netlify/dist/run/handlers/server.js";
82
116
  }
83
117
  /**
84
118
  * Absolute path of the directory containing the files for deno edge functions
@@ -115,9 +149,16 @@ var PluginContext = class {
115
149
  await readFile(join(this.publishDir, "server/middleware-manifest.json"), "utf-8")
116
150
  );
117
151
  }
152
+ // don't make private as it is handy inside testing to override the config
153
+ _buildConfig = null;
118
154
  /** Get Next Config from build output **/
119
- async getBuildConfig() {
120
- return JSON.parse(await readFile(join(this.publishDir, "required-server-files.json"), "utf-8")).config;
155
+ get buildConfig() {
156
+ if (!this._buildConfig) {
157
+ this._buildConfig = JSON.parse(
158
+ readFileSync(join(this.publishDir, "required-server-files.json"), "utf-8")
159
+ ).config;
160
+ }
161
+ return this._buildConfig;
121
162
  }
122
163
  /**
123
164
  * Get Next.js routes manifest from the build output
@@ -125,19 +166,6 @@ var PluginContext = class {
125
166
  async getRoutesManifest() {
126
167
  return JSON.parse(await readFile(join(this.publishDir, "routes-manifest.json"), "utf-8"));
127
168
  }
128
- /**
129
- * Write a cache entry to the blob upload directory.
130
- */
131
- async writeCacheEntry(route, value, filePath) {
132
- const { mtime } = await stat(filePath);
133
- const path = join(this.blobDir, await encodeBlobKey(route));
134
- const entry = JSON.stringify({
135
- lastModified: mtime.getTime(),
136
- value
137
- });
138
- await mkdir(dirname(path), { recursive: true });
139
- await writeFile(path, entry, "utf-8");
140
- }
141
169
  /** Fails a build with a message and an optional error */
142
170
  failBuild(message, error) {
143
171
  return this.utils.build.failBuild(message, error instanceof Error ? { error } : void 0);