@opennextjs/aws 3.6.4 → 3.6.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.
@@ -14,7 +14,7 @@ import { copyMiddlewareResources, generateEdgeBundle, } from "./edge/createEdgeB
14
14
  import * as buildHelper from "./helper.js";
15
15
  import { installDependencies } from "./installDeps.js";
16
16
  import { applyCodePatches } from "./patch/codePatcher.js";
17
- import { patchBackgroundRevalidation, patchEnvVars, patchFetchCacheForISR, patchFetchCacheSetMissingWaitUntil, patchNextServer, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patch/patches/index.js";
17
+ import * as patches from "./patch/patches/index.js";
18
18
  export async function createServerBundle(options, codeCustomization) {
19
19
  const { config } = options;
20
20
  const foundRoutes = new Set();
@@ -119,13 +119,14 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
119
119
  });
120
120
  const additionalCodePatches = codeCustomization?.additionalCodePatches ?? [];
121
121
  await applyCodePatches(options, tracedFiles, manifests, [
122
- patchFetchCacheSetMissingWaitUntil,
123
- patchFetchCacheForISR,
124
- patchUnstableCacheForISR,
125
- patchNextServer,
126
- patchEnvVars,
127
- patchBackgroundRevalidation,
128
- patchUseCacheForISR,
122
+ patches.patchFetchCacheSetMissingWaitUntil,
123
+ patches.patchFetchCacheForISR,
124
+ patches.patchUnstableCacheForISR,
125
+ patches.patchNextServer,
126
+ patches.patchEnvVars,
127
+ patches.patchBackgroundRevalidation,
128
+ patches.patchUseCacheForISR,
129
+ patches.patchDropBabel,
129
130
  ...additionalCodePatches,
130
131
  ]);
131
132
  // Build Lambda code
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Patches to avoid pulling babel (~4MB).
3
+ *
4
+ * Details:
5
+ * - empty `NextServer#runMiddleware` and `NextServer#runEdgeFunction` that are not used
6
+ * - drop `next/dist/server/node-environment-extensions/error-inspect.js`
7
+ */
8
+ import type { CodePatcher } from "../codePatcher.js";
9
+ export declare const patchDropBabel: CodePatcher;
10
+ /**
11
+ * Swaps the body for a throwing implementation
12
+ *
13
+ * @param methodName The name of the method
14
+ * @returns A rule to replace the body with a `throw`
15
+ */
16
+ export declare function createEmptyBodyRule(methodName: string): string;
17
+ /**
18
+ * Drops `require("./node-environment-extensions/error-inspect");`
19
+ */
20
+ 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";
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Patches to avoid pulling babel (~4MB).
3
+ *
4
+ * Details:
5
+ * - empty `NextServer#runMiddleware` and `NextServer#runEdgeFunction` that are not used
6
+ * - drop `next/dist/server/node-environment-extensions/error-inspect.js`
7
+ */
8
+ import { getCrossPlatformPathRegex } from "../../../utils/regex.js";
9
+ import { patchCode } from "../astCodePatcher.js";
10
+ export const patchDropBabel = {
11
+ name: "patch-drop-babel",
12
+ patches: [
13
+ // Empty the body of `NextServer#runMiddleware`
14
+ {
15
+ field: {
16
+ pathFilter: getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
17
+ escape: false,
18
+ }),
19
+ contentFilter: /runMiddleware\(/,
20
+ patchCode: async ({ code }) => patchCode(code, createEmptyBodyRule("runMiddleware")),
21
+ },
22
+ },
23
+ // Empty the body of `NextServer#runEdgeFunction`
24
+ {
25
+ field: {
26
+ pathFilter: getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
27
+ escape: false,
28
+ }),
29
+ contentFilter: /runEdgeFunction\(/,
30
+ patchCode: async ({ code }) => patchCode(code, createEmptyBodyRule("runEdgeFunction")),
31
+ },
32
+ },
33
+ // Drop `error-inspect` that pulls babel
34
+ {
35
+ field: {
36
+ pathFilter: getCrossPlatformPathRegex(String.raw `next/dist/server/node-environment\.js$`, {
37
+ escape: false,
38
+ }),
39
+ contentFilter: /error-inspect/,
40
+ patchCode: async ({ code }) => patchCode(code, errorInspectRule),
41
+ },
42
+ },
43
+ ],
44
+ };
45
+ /**
46
+ * Swaps the body for a throwing implementation
47
+ *
48
+ * @param methodName The name of the method
49
+ * @returns A rule to replace the body with a `throw`
50
+ */
51
+ export function createEmptyBodyRule(methodName) {
52
+ return `
53
+ rule:
54
+ pattern:
55
+ selector: method_definition
56
+ context: "class { async ${methodName}($$$PARAMS) { $$$_ } }"
57
+ fix: |-
58
+ async ${methodName}($$$PARAMS) {
59
+ throw new Error("${methodName} should not be called with OpenNext");
60
+ }
61
+ `;
62
+ }
63
+ /**
64
+ * Drops `require("./node-environment-extensions/error-inspect");`
65
+ */
66
+ export const errorInspectRule = `
67
+ rule:
68
+ pattern: require("./node-environment-extensions/error-inspect");
69
+ fix: |-
70
+ // Removed by OpenNext
71
+ // require("./node-environment-extensions/error-inspect");
72
+ `;
@@ -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 { patchDropBabel } from "./dropBabel.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 { patchDropBabel } from "./dropBabel.js";
@@ -1,6 +1,6 @@
1
1
  import { Transform } from "node:stream";
2
2
  import { debug } from "../adapters/logger";
3
- import { parseCookies, parseHeaders } from "./util";
3
+ import { parseHeaders, parseSetCookieHeader } from "./util";
4
4
  const SET_COOKIE_HEADER = "set-cookie";
5
5
  const CANNOT_BE_USED = "This cannot be used in OpenNext";
6
6
  // We only need to implement the methods that are used by next.js
@@ -127,7 +127,7 @@ export class OpenNextNodeResponse extends Transform {
127
127
  ...this.initialHeaders,
128
128
  ...this.headers,
129
129
  };
130
- const initialCookies = parseCookies(this.initialHeaders[SET_COOKIE_HEADER]?.toString());
130
+ const initialCookies = parseSetCookieHeader(this.initialHeaders[SET_COOKIE_HEADER]?.toString());
131
131
  this._cookies =
132
132
  mergeHeadersPriority === "middleware"
133
133
  ? [...this._cookies, ...initialCookies]
@@ -1,7 +1,13 @@
1
1
  import type http from "node:http";
2
2
  export declare const parseHeaders: (headers?: http.OutgoingHttpHeader[] | http.OutgoingHttpHeaders) => Record<string, string>;
3
3
  export declare const convertHeader: (header: http.OutgoingHttpHeader) => string;
4
- export declare function parseCookies(cookies: string | string[] | null | undefined): string[];
4
+ /**
5
+ * Parses a (comma-separated) list of Set-Cookie headers
6
+ *
7
+ * @param cookies A comma-separated list of Set-Cookie headers or a list of Set-Cookie headers
8
+ * @returns A list of Set-Cookie header
9
+ */
10
+ export declare function parseSetCookieHeader(cookies: string | string[] | null | undefined): string[];
5
11
  /**
6
12
  *
7
13
  * Get the query object from an iterable of [key, value] pairs
package/dist/http/util.js CHANGED
@@ -20,13 +20,23 @@ export const convertHeader = (header) => {
20
20
  }
21
21
  return String(header);
22
22
  };
23
- export function parseCookies(cookies) {
23
+ /**
24
+ * Parses a (comma-separated) list of Set-Cookie headers
25
+ *
26
+ * @param cookies A comma-separated list of Set-Cookie headers or a list of Set-Cookie headers
27
+ * @returns A list of Set-Cookie header
28
+ */
29
+ export function parseSetCookieHeader(cookies) {
24
30
  if (!cookies) {
25
31
  return [];
26
32
  }
27
- return typeof cookies === "string"
28
- ? cookies.split(/(?<!Expires=\w+),/i).map((c) => c.trim())
29
- : cookies;
33
+ if (typeof cookies === "string") {
34
+ // Split the cookie string on ",".
35
+ // Note that "," can also appear in the Expires value (i.e. `Expires=Thu, 01 June`)
36
+ // so we have to skip it with a negative lookbehind.
37
+ return cookies.split(/(?<!Expires=\w+),/i).map((c) => c.trim());
38
+ }
39
+ return cookies;
30
40
  }
31
41
  /**
32
42
  *
@@ -1,4 +1,4 @@
1
- import { parseCookies } from "../../http/util";
1
+ import { parseSetCookieHeader } from "../../http/util";
2
2
  import { fromReadableStream } from "../../utils/stream";
3
3
  import { debug } from "../../adapters/logger";
4
4
  import { convertToQuery } from "../../core/routing/util";
@@ -87,7 +87,7 @@ async function convertToApiGatewayProxyResultV2(result) {
87
87
  const response = {
88
88
  statusCode: result.statusCode,
89
89
  headers,
90
- cookies: parseCookies(result.headers["set-cookie"]),
90
+ cookies: parseSetCookieHeader(result.headers["set-cookie"]),
91
91
  body,
92
92
  isBase64Encoded: result.isBase64Encoded,
93
93
  };
@@ -1,4 +1,4 @@
1
- import { parseCookies } from "../../http/util";
1
+ import { parseSetCookieHeader } from "../../http/util";
2
2
  import { fromReadableStream } from "../../utils/stream";
3
3
  import { debug } from "../../adapters/logger";
4
4
  import { convertToQuery, convertToQueryString } from "../../core/routing/util";
@@ -84,7 +84,7 @@ function convertToCloudfrontHeaders(headers, directResponse) {
84
84
  (directResponse ? !cloudfrontReadOnlyHeaders.includes(key) : true))
85
85
  .forEach(([key, value]) => {
86
86
  if (key === "set-cookie") {
87
- cloudfrontHeaders[key] = parseCookies(`${value}`).map((cookie) => ({
87
+ cloudfrontHeaders[key] = parseSetCookieHeader(`${value}`).map((cookie) => ({
88
88
  key,
89
89
  value: cookie,
90
90
  }));
@@ -1,5 +1,6 @@
1
1
  import { Buffer } from "node:buffer";
2
- import { parseCookies } from "../../http/util";
2
+ import cookieParser from "cookie";
3
+ import { parseSetCookieHeader } from "../../http/util";
3
4
  import { getQueryFromSearchParams } from "./utils.js";
4
5
  const converter = {
5
6
  convertFrom: async (event) => {
@@ -15,7 +16,10 @@ const converter = {
15
16
  const rawPath = url.pathname;
16
17
  const method = event.method;
17
18
  const shouldHaveBody = method !== "GET" && method !== "HEAD";
18
- const cookies = Object.fromEntries(parseCookies(event.headers.get("cookie")).map((cookie) => cookie.split("=")));
19
+ const cookieHeader = event.headers.get("cookie");
20
+ const cookies = cookieHeader
21
+ ? cookieParser.parse(cookieHeader)
22
+ : {};
19
23
  return {
20
24
  type: "core",
21
25
  method,
@@ -58,7 +62,7 @@ const converter = {
58
62
  if (key === "set-cookie" && typeof value === "string") {
59
63
  // If the value is a string, we need to parse it into an array
60
64
  // This is the case for middleware direct result
61
- const cookies = parseCookies(value);
65
+ const cookies = parseSetCookieHeader(value);
62
66
  for (const cookie of cookies) {
63
67
  headers.append(key, cookie);
64
68
  }
@@ -1,4 +1,4 @@
1
- import { parseCookies } from "../../http/util";
1
+ import cookieParser from "cookie";
2
2
  import { extractHostFromHeaders, getQueryFromSearchParams } from "./utils.js";
3
3
  const converter = {
4
4
  convertFrom: async (req) => {
@@ -20,6 +20,10 @@ const converter = {
20
20
  // https://nodejs.org/api/http.html#messageurl
21
21
  const url = new URL(`${req.protocol ? req.protocol : "http"}://${extractHostFromHeaders(headers)}${req.url}`);
22
22
  const query = getQueryFromSearchParams(url.searchParams);
23
+ const cookieHeader = req.headers.cookie;
24
+ const cookies = cookieHeader
25
+ ? cookieParser.parse(cookieHeader)
26
+ : {};
23
27
  return {
24
28
  type: "core",
25
29
  method: req.method ?? "GET",
@@ -31,10 +35,7 @@ const converter = {
31
35
  req.socket.remoteAddress ??
32
36
  "::1",
33
37
  query,
34
- cookies: Object.fromEntries(parseCookies(req.headers.cookie)?.map((cookie) => {
35
- const [key, value] = cookie.split("=");
36
- return [key, value];
37
- }) ?? []),
38
+ cookies,
38
39
  };
39
40
  },
40
41
  // Nothing to do here, it's streaming
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.6.4",
6
+ "version": "3.6.5",
7
7
  "bin": {
8
8
  "open-next": "./dist/index.js"
9
9
  },
@@ -44,6 +44,7 @@
44
44
  "@tsconfig/node18": "^1.0.1",
45
45
  "aws4fetch": "^1.0.18",
46
46
  "chalk": "^5.3.0",
47
+ "cookie": "^1.0.2",
47
48
  "esbuild": "0.25.4",
48
49
  "express": "5.0.1",
49
50
  "path-to-regexp": "^6.3.0",