@opennextjs/aws 3.6.1 → 3.6.2

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.
@@ -83,5 +83,9 @@ export function compileOpenNextConfigEdge(sourcePath, outputDir, externals) {
83
83
  conditions: ["worker", "browser"],
84
84
  platform: "browser",
85
85
  external: externals,
86
+ define: {
87
+ // with the default esbuild config, the NODE_ENV will be set to "development", we don't want that
88
+ "process.env.NODE_ENV": '"production"',
89
+ },
86
90
  });
87
91
  }
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { loadFunctionsConfigManifest, loadMiddlewareManifest, } from "../adapters/config/util.js";
4
4
  import logger from "../logger.js";
5
- import { buildEdgeBundle } from "./edge/createEdgeBundle.js";
5
+ import { buildEdgeBundle, copyMiddlewareResources, } from "./edge/createEdgeBundle.js";
6
6
  import * as buildHelper from "./helper.js";
7
7
  import { installDependencies } from "./installDeps.js";
8
8
  import { buildBundledNodeMiddleware, buildExternalNodeMiddleware, } from "./middleware/buildNodeMiddleware.js";
@@ -31,6 +31,7 @@ export async function createMiddleware(options, { forceOnlyBuildOnce = false } =
31
31
  }
32
32
  if (config.middleware?.external) {
33
33
  const outputPath = path.join(outputDir, "middleware");
34
+ copyMiddlewareResources(options, edgeMiddlewareInfo, outputPath);
34
35
  fs.mkdirSync(outputPath, { recursive: true });
35
36
  // Copy open-next.config.mjs
36
37
  buildHelper.copyOpenNextConfig(options.buildDir, outputPath, await buildHelper.isEdgeRuntime(config.middleware.override));
@@ -102,6 +102,32 @@ async function generateResult(event, localizedPath, cachedValue, lastModified) {
102
102
  },
103
103
  };
104
104
  }
105
+ /**
106
+ *
107
+ * https://github.com/vercel/next.js/blob/34039551d2e5f611c0abde31a197d9985918adaf/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts#L2-L10
108
+ */
109
+ function escapePathDelimiters(segment, escapeEncoded) {
110
+ return segment.replace(new RegExp(`([/#?]${escapeEncoded ? "|%(2f|23|3f|5c)" : ""})`, "gi"), (char) => encodeURIComponent(char));
111
+ }
112
+ /**
113
+ *
114
+ * SSG cache key needs to be decoded, but some characters needs to be properly escaped
115
+ * https://github.com/vercel/next.js/blob/34039551d2e5f611c0abde31a197d9985918adaf/packages/next/src/server/lib/router-utils/decode-path-params.ts#L11-L26
116
+ */
117
+ function decodePathParams(pathname) {
118
+ return pathname
119
+ .split("/")
120
+ .map((segment) => {
121
+ try {
122
+ return escapePathDelimiters(decodeURIComponent(segment), true);
123
+ }
124
+ catch (e) {
125
+ // If decodeURIComponent fails, we return the original segment
126
+ return segment;
127
+ }
128
+ })
129
+ .join("/");
130
+ }
105
131
  export async function cacheInterceptor(event) {
106
132
  if (Boolean(event.headers["next-action"]) ||
107
133
  Boolean(event.headers["x-prerender-revalidate"]))
@@ -114,6 +140,8 @@ export async function cacheInterceptor(event) {
114
140
  }
115
141
  // We also need to remove trailing slash
116
142
  localizedPath = localizedPath.replace(/\/$/, "");
143
+ // Then we decode the path params
144
+ localizedPath = decodePathParams(localizedPath);
117
145
  debug("Checking cache for", localizedPath, PrerenderManifest);
118
146
  const isISR = Object.keys(PrerenderManifest.routes).includes(localizedPath ?? "/") ||
119
147
  Object.values(PrerenderManifest.dynamicRoutes).some((dr) => new RegExp(dr.routeRegex).test(localizedPath));
@@ -1,5 +1,6 @@
1
1
  import { NextConfig } from "../../adapters/config/index";
2
2
  import { compile, match } from "path-to-regexp";
3
+ import { normalizeRepeatedSlashes } from "../../utils/normalize-path";
3
4
  import { emptyReadableStream, toReadableStream } from "../../utils/stream";
4
5
  import { debug } from "../../adapters/logger";
5
6
  import { handleLocaleRedirect, localizePath } from "./i18n";
@@ -169,6 +170,25 @@ export function handleRewrites(event, rewrites) {
169
170
  isExternalRewrite,
170
171
  };
171
172
  }
173
+ // Normalizes repeated slashes in the path e.g. hello//world -> hello/world
174
+ // or backslashes to forward slashes. This prevents requests such as //domain
175
+ // from invoking the middleware with `request.url === "domain"`.
176
+ // See: https://github.com/vercel/next.js/blob/3ecf087f10fdfba4426daa02b459387bc9c3c54f/packages/next/src/server/base-server.ts#L1016-L1020
177
+ function handleRepeatedSlashRedirect(event) {
178
+ // Redirect `https://example.com//foo` to `https://example.com/foo`.
179
+ if (event.rawPath.match(/(\\|\/\/)/)) {
180
+ return {
181
+ type: event.type,
182
+ statusCode: 308,
183
+ headers: {
184
+ Location: normalizeRepeatedSlashes(new URL(event.url)),
185
+ },
186
+ body: emptyReadableStream(),
187
+ isBase64Encoded: false,
188
+ };
189
+ }
190
+ return false;
191
+ }
172
192
  function handleTrailingSlashRedirect(event) {
173
193
  // When rawPath is `//domain`, `url.host` would be `domain`.
174
194
  // https://github.com/opennextjs/opennextjs-aws/issues/355
@@ -215,6 +235,9 @@ function handleTrailingSlashRedirect(event) {
215
235
  return false;
216
236
  }
217
237
  export function handleRedirects(event, redirects) {
238
+ const repeatedSlashRedirect = handleRepeatedSlashRedirect(event);
239
+ if (repeatedSlashRedirect)
240
+ return repeatedSlashRedirect;
218
241
  const trailingSlashRedirect = handleTrailingSlashRedirect(event);
219
242
  if (trailingSlashRedirect)
220
243
  return trailingSlashRedirect;
@@ -17,7 +17,8 @@ const converter = {
17
17
  Array.isArray(value) ? value.join(",") : value,
18
18
  ])
19
19
  .filter(([key]) => key));
20
- const url = new URL(req.url, `http://${extractHostFromHeaders(headers)}`);
20
+ // https://nodejs.org/api/http.html#messageurl
21
+ const url = new URL(`${req.protocol ? req.protocol : "http"}://${extractHostFromHeaders(headers)}${req.url}`);
21
22
  const query = getQueryFromSearchParams(url.searchParams);
22
23
  return {
23
24
  type: "core",
@@ -27,7 +27,7 @@ export function openNextEdgePlugins({ nextDir, middlewareInfo, isInCloudflare, }
27
27
  name: "opennext-edge",
28
28
  setup(build) {
29
29
  logger.debug(chalk.blue("OpenNext Edge plugin"));
30
- build.onResolve({ filter: /\.(mjs|wasm)$/g }, () => {
30
+ build.onResolve({ filter: /\.(mjs|wasm)$/ }, () => {
31
31
  return {
32
32
  external: true,
33
33
  };
@@ -1,2 +1,3 @@
1
1
  export declare function normalizePath(path: string): string;
2
+ export declare function normalizeRepeatedSlashes(url: URL): string;
2
3
  export declare function getMonorepoRelativePath(relativePath?: string): string;
@@ -2,6 +2,13 @@ import path from "node:path";
2
2
  export function normalizePath(path) {
3
3
  return path.replace(/\\/g, "/");
4
4
  }
5
+ // See: https://github.com/vercel/next.js/blob/3ecf087f10fdfba4426daa02b459387bc9c3c54f/packages/next/src/shared/lib/utils.ts#L348
6
+ export function normalizeRepeatedSlashes(url) {
7
+ const urlNoQuery = url.host + url.pathname;
8
+ return `${url.protocol}//${urlNoQuery
9
+ .replace(/\\/g, "/")
10
+ .replace(/\/\/+/g, "/")}${url.search}`;
11
+ }
5
12
  export function getMonorepoRelativePath(relativePath = "../..") {
6
13
  return path.join(globalThis.monorepoPackagePath
7
14
  .split("/")
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.6.1",
6
+ "version": "3.6.2",
7
7
  "bin": {
8
8
  "open-next": "./dist/index.js"
9
9
  },
@@ -14,8 +14,8 @@
14
14
  "main": "./dist/index.js",
15
15
  "exports": {
16
16
  "./*": {
17
- "default": "./dist/*",
18
- "types": "./dist/*.d.ts"
17
+ "types": "./dist/*.d.ts",
18
+ "default": "./dist/*"
19
19
  }
20
20
  },
21
21
  "typesVersions": {
@@ -44,7 +44,7 @@
44
44
  "@tsconfig/node18": "^1.0.1",
45
45
  "aws4fetch": "^1.0.18",
46
46
  "chalk": "^5.3.0",
47
- "esbuild": "0.19.2",
47
+ "esbuild": "0.25.4",
48
48
  "express": "5.0.1",
49
49
  "path-to-regexp": "^6.3.0",
50
50
  "urlpattern-polyfill": "^10.0.0",