@opennextjs/aws 3.7.4 → 3.7.5

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.
@@ -13,6 +13,10 @@ const EXCLUDED_PACKAGES = [
13
13
  // This seems to be only in Next 15
14
14
  // Some of sharp deps are under the @img scope
15
15
  "@img",
16
+ "typescript",
17
+ "next/dist/compiled/babel",
18
+ "next/dist/compiled/babel-packages",
19
+ "next/dist/compiled/amphtml-validator",
16
20
  ];
17
21
  function isExcluded(srcPath) {
18
22
  return EXCLUDED_PACKAGES.some((excluded) => srcPath.match(getCrossPlatformPathRegex(`/node_modules/${excluded}/`)));
@@ -167,7 +171,7 @@ File ${serverPath} does not exist
167
171
  const tracedFiles = [];
168
172
  //Actually copy the files
169
173
  filesToCopy.forEach((to, from) => {
170
- // We don't want to copy excluded packages (i.e sharp)
174
+ // We don't want to copy excluded packages (e.g. sharp)
171
175
  if (isExcluded(from)) {
172
176
  return;
173
177
  }
@@ -126,6 +126,7 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
126
126
  patches.patchEnvVars,
127
127
  patches.patchBackgroundRevalidation,
128
128
  patches.patchUseCacheForISR,
129
+ patches.patchNodeEnvironment,
129
130
  ...additionalCodePatches,
130
131
  ]);
131
132
  // Build Lambda code
@@ -3,6 +3,7 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { execSync } from "node:child_process";
5
5
  import logger from "../logger.js";
6
+ const AFFECTED_NODE_VERSIONS = ["22.17.0", "22.17.1", "22.18.0"];
6
7
  export function installDependencies(outputDir, installOptions) {
7
8
  try {
8
9
  if (!installOptions) {
@@ -37,8 +38,8 @@ export function installDependencies(outputDir, installOptions) {
37
38
  fs.cpSync(path.join(tempInstallDir, "node_modules"), path.join(outputDir, "node_modules"), { recursive: true, force: true, dereference: true });
38
39
  // This is a workaround for Node `22.17.0` and `22.17.1`
39
40
  // https://github.com/nodejs/node/issues/59168
40
- const nodeVersion = process.version;
41
- if (nodeVersion === "v22.17.0" || nodeVersion === "v22.17.1") {
41
+ const nodeVersion = process.versions.node;
42
+ if (AFFECTED_NODE_VERSIONS.includes(nodeVersion)) {
42
43
  const tempBinDir = path.join(tempInstallDir, "node_modules", ".bin");
43
44
  const outputBinDir = path.join(outputDir, "node_modules", ".bin");
44
45
  for (const fileName of fs.readdirSync(tempBinDir)) {
@@ -3,3 +3,4 @@ export { patchNextServer } from "./patchNextServer.js";
3
3
  export { patchFetchCacheForISR, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patchFetchCacheISR.js";
4
4
  export { patchFetchCacheSetMissingWaitUntil } from "./patchFetchCacheWaitUntil.js";
5
5
  export { patchBackgroundRevalidation } from "./patchBackgroundRevalidation.js";
6
+ export { patchNodeEnvironment } from "./patchNodeEnvironment.js";
@@ -3,3 +3,4 @@ export { patchNextServer } from "./patchNextServer.js";
3
3
  export { patchFetchCacheForISR, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patchFetchCacheISR.js";
4
4
  export { patchFetchCacheSetMissingWaitUntil } from "./patchFetchCacheWaitUntil.js";
5
5
  export { patchBackgroundRevalidation } from "./patchBackgroundRevalidation.js";
6
+ export { patchNodeEnvironment } from "./patchNodeEnvironment.js";
@@ -8,8 +8,4 @@ export declare const removeMiddlewareManifestRule = "\nrule:\n kind: statement_
8
8
  * @returns A rule to replace the body with a `throw`
9
9
  */
10
10
  export declare function createEmptyBodyRule(methodName: string): string;
11
- /**
12
- * Drops `require("./node-environment-extensions/error-inspect");`
13
- */
14
- export declare const errorInspectRule = "\nrule:\n pattern: require(\"./node-environment-extensions/error-inspect\");\nfix: |-\n // Removed by OpenNext\n // require(\"./node-environment-extensions/error-inspect\");\n";
15
11
  export declare const patchNextServer: CodePatcher;
@@ -48,16 +48,6 @@ fix: |-
48
48
  }
49
49
  `;
50
50
  }
51
- /**
52
- * Drops `require("./node-environment-extensions/error-inspect");`
53
- */
54
- export const errorInspectRule = `
55
- rule:
56
- pattern: require("./node-environment-extensions/error-inspect");
57
- fix: |-
58
- // Removed by OpenNext
59
- // require("./node-environment-extensions/error-inspect");
60
- `;
61
51
  const pathFilter = getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
62
52
  escape: false,
63
53
  });
@@ -81,12 +71,6 @@ const babelPatches = [
81
71
  contentFilter: /runEdgeFunction\(/,
82
72
  patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
83
73
  },
84
- // Drop `error-inspect` that pulls babel
85
- {
86
- pathFilter,
87
- contentFilter: /error-inspect/,
88
- patchCode: createPatchCode(errorInspectRule),
89
- },
90
74
  ];
91
75
  export const patchNextServer = {
92
76
  name: "patch-next-server",
@@ -0,0 +1,8 @@
1
+ import type { CodePatcher } from "../codePatcher.js";
2
+ /**
3
+ * Drops `require("./node-environment-extensions/error-inspect");`
4
+ *
5
+ * This is to avoid pulling babel (~4MB)
6
+ */
7
+ export declare const rule = "\nrule:\n pattern: require(\"./node-environment-extensions/error-inspect\");\nfix: |-\n // Removed by OpenNext\n // require(\"./node-environment-extensions/error-inspect\");\n";
8
+ export declare const patchNodeEnvironment: CodePatcher;
@@ -0,0 +1,27 @@
1
+ import { getCrossPlatformPathRegex } from "../../../utils/regex.js";
2
+ import { createPatchCode } from "../astCodePatcher.js";
3
+ /**
4
+ * Drops `require("./node-environment-extensions/error-inspect");`
5
+ *
6
+ * This is to avoid pulling babel (~4MB)
7
+ */
8
+ export const rule = `
9
+ rule:
10
+ pattern: require("./node-environment-extensions/error-inspect");
11
+ fix: |-
12
+ // Removed by OpenNext
13
+ // require("./node-environment-extensions/error-inspect");
14
+ `;
15
+ export const patchNodeEnvironment = {
16
+ name: "patch-node-environment-error-inspect",
17
+ patches: [
18
+ {
19
+ pathFilter: getCrossPlatformPathRegex(String.raw `/next/dist/server/node-environment\.js$`, {
20
+ escape: false,
21
+ }),
22
+ contentFilter: /error-inspect/,
23
+ patchCode: createPatchCode(rule),
24
+ versions: ">=15.0.0",
25
+ },
26
+ ],
27
+ };
package/dist/build.js CHANGED
@@ -28,10 +28,10 @@ export async function build(openNextConfigPath, nodeExternals) {
28
28
  // Build Next.js app
29
29
  printHeader("Building Next.js app");
30
30
  setStandaloneBuildMode(options);
31
+ buildHelper.initOutputDir(options);
31
32
  buildNextjsApp(options);
32
33
  // Generate deployable bundle
33
34
  printHeader("Generating bundle");
34
- buildHelper.initOutputDir(options);
35
35
  // Compile cache.ts
36
36
  compileCache(options);
37
37
  // Compile middleware
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { NextConfig, PrerenderManifest } from "../../adapters/config/index";
3
3
  import { emptyReadableStream, toReadableStream } from "../../utils/stream";
4
+ import { isBinaryContentType } from "../../utils/binary";
4
5
  import { getTagsFromValue, hasBeenRevalidated } from "../../utils/cache";
5
6
  import { debug } from "../../adapters/logger";
6
7
  import { localizePath } from "./i18n";
@@ -200,6 +201,21 @@ export async function cacheInterceptor(event) {
200
201
  isBase64Encoded: false,
201
202
  };
202
203
  }
204
+ case "route": {
205
+ const cacheControl = await computeCacheControl(localizedPath, cachedData.value.body, host, cachedData.value.revalidate, cachedData.lastModified);
206
+ const isBinary = isBinaryContentType(String(cachedData.value.meta?.headers?.["content-type"]));
207
+ return {
208
+ type: "core",
209
+ statusCode: cachedData.value.meta?.status ?? 200,
210
+ body: toReadableStream(cachedData.value.body, isBinary),
211
+ headers: {
212
+ ...cacheControl,
213
+ ...cachedData.value.meta?.headers,
214
+ vary: VARY_HEADER,
215
+ },
216
+ isBase64Encoded: isBinary,
217
+ };
218
+ }
203
219
  default:
204
220
  return event;
205
221
  }
@@ -65,6 +65,12 @@ export class OpenNextNodeResponse extends Transform {
65
65
  statusCode <= 599) {
66
66
  this.statusCode = statusCode;
67
67
  }
68
+ // https://github.com/vercel/next.js/blob/ea08bf2/packages/next/src/server/web/spec-extension/adapters/next-request.ts#L46-L54
69
+ // We want to destroy this response when the original response/request is closed. (i.e when the client disconnects)
70
+ // This is to support `request.signal.onabort` in route handlers
71
+ streamCreator?.abortSignal?.addEventListener("abort", () => {
72
+ this.destroy();
73
+ });
68
74
  }
69
75
  // Necessary for next 12
70
76
  // We might have to implement all the methods here
@@ -1,7 +1,7 @@
1
1
  import { Writable } from "node:stream";
2
2
  // Response with null body status (101, 204, 205, or 304) cannot have a body.
3
3
  const NULL_BODY_STATUSES = new Set([101, 204, 205, 304]);
4
- const handler = async (handler, converter) => async (request, env, ctx) => {
4
+ const handler = async (handler, converter) => async (request, env, ctx, abortSignal) => {
5
5
  globalThis.process = process;
6
6
  // Set the environment variables
7
7
  // Cloudflare suggests to not override the process.env object but instead apply the values to it
@@ -38,6 +38,10 @@ const handler = async (handler, converter) => async (request, env, ctx) => {
38
38
  resolveResponse(response);
39
39
  return Writable.fromWeb(writable);
40
40
  },
41
+ // This is for passing along the original abort signal from the initial Request you retrieve in your worker
42
+ // Ensures that the response we pass to NextServer is aborted if the request is aborted
43
+ // By doing this `request.signal.onabort` will work in route handlers
44
+ abortSignal: abortSignal,
41
45
  };
42
46
  ctx.waitUntil(handler(internalEvent, {
43
47
  streamCreator,
@@ -27,6 +27,7 @@ const wrapper = async (handler, converter) => {
27
27
  req.headers["x-forwarded-proto"] = req.protocol;
28
28
  }
29
29
  const internalEvent = await converter.convertFrom(req);
30
+ const abortController = new AbortController();
30
31
  const streamCreator = {
31
32
  writeHeaders: (prelude) => {
32
33
  res.setHeader("Set-Cookie", prelude.cookies);
@@ -35,7 +36,11 @@ const wrapper = async (handler, converter) => {
35
36
  return res;
36
37
  },
37
38
  onFinish: () => { },
39
+ abortSignal: abortController.signal,
38
40
  };
41
+ res.on("close", () => {
42
+ abortController.abort();
43
+ });
39
44
  await handler(internalEvent, { streamCreator });
40
45
  });
41
46
  const server = app.listen(Number.parseInt(process.env.PORT ?? "3000", 10), () => {
@@ -3,6 +3,7 @@ import { debug, error } from "../../adapters/logger";
3
3
  const wrapper = async (handler, converter) => {
4
4
  const server = createServer(async (req, res) => {
5
5
  const internalEvent = await converter.convertFrom(req);
6
+ const abortController = new AbortController();
6
7
  const streamCreator = {
7
8
  writeHeaders: (prelude) => {
8
9
  res.setHeader("Set-Cookie", prelude.cookies);
@@ -10,7 +11,11 @@ const wrapper = async (handler, converter) => {
10
11
  res.flushHeaders();
11
12
  return res;
12
13
  },
14
+ abortSignal: abortController.signal,
13
15
  };
16
+ res.on("close", () => {
17
+ abortController.abort();
18
+ });
14
19
  if (internalEvent.rawPath === "/__health") {
15
20
  res.writeHead(200, {
16
21
  "Content-Type": "text/plain",
@@ -18,7 +23,9 @@ const wrapper = async (handler, converter) => {
18
23
  res.end("OK");
19
24
  }
20
25
  else {
21
- await handler(internalEvent, { streamCreator });
26
+ await handler(internalEvent, {
27
+ streamCreator,
28
+ });
22
29
  }
23
30
  });
24
31
  await new Promise((resolve) => {
@@ -30,6 +30,7 @@ export interface StreamCreator {
30
30
  }): Writable;
31
31
  onWrite?: () => void;
32
32
  onFinish?: (length: number) => void;
33
+ abortSignal?: AbortSignal;
33
34
  }
34
35
  export type WaitUntil = (promise: Promise<void>) => void;
35
36
  export interface DangerousOptions {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.7.4",
6
+ "version": "3.7.5",
7
7
  "bin": {
8
8
  "open-next": "./dist/index.js"
9
9
  },