@opennextjs/aws 3.2.2 → 3.3.1

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 (70) hide show
  1. package/README.md +6 -1
  2. package/dist/adapters/cache.d.ts +1 -2
  3. package/dist/adapters/cache.js +2 -12
  4. package/dist/adapters/config/index.d.ts +2 -0
  5. package/dist/adapters/config/index.js +4 -3
  6. package/dist/adapters/config/util.d.ts +2 -0
  7. package/dist/adapters/config/util.js +12 -2
  8. package/dist/adapters/image-optimization-adapter.d.ts +1 -2
  9. package/dist/adapters/logger.js +32 -11
  10. package/dist/adapters/middleware.js +13 -2
  11. package/dist/adapters/plugins/image-optimization/image-optimization.d.ts +1 -0
  12. package/dist/adapters/plugins/image-optimization/image-optimization.js +0 -1
  13. package/dist/adapters/plugins/image-optimization/image-optimization.replacement.d.ts +1 -0
  14. package/dist/adapters/util.js +5 -1
  15. package/dist/build/bundleNextServer.d.ts +2 -2
  16. package/dist/build/bundleNextServer.js +2 -2
  17. package/dist/build/copyTracedFiles.js +1 -1
  18. package/dist/build/createAssets.js +23 -24
  19. package/dist/build/createMiddleware.js +1 -1
  20. package/dist/build/createServerBundle.js +3 -3
  21. package/dist/build/edge/createEdgeBundle.d.ts +5 -4
  22. package/dist/build/edge/createEdgeBundle.js +35 -33
  23. package/dist/build/helper.d.ts +6 -1
  24. package/dist/build/helper.js +20 -5
  25. package/dist/build/validateConfig.js +3 -1
  26. package/dist/core/requestHandler.d.ts +1 -2
  27. package/dist/core/requestHandler.js +31 -20
  28. package/dist/core/routing/matcher.js +1 -1
  29. package/dist/core/routing/middleware.d.ts +3 -3
  30. package/dist/core/routing/middleware.js +3 -4
  31. package/dist/core/routing/routeMatcher.d.ts +10 -0
  32. package/dist/core/routing/routeMatcher.js +45 -0
  33. package/dist/core/routing/util.d.ts +3 -3
  34. package/dist/core/routing/util.js +7 -5
  35. package/dist/core/routingHandler.d.ts +5 -8
  36. package/dist/core/routingHandler.js +38 -37
  37. package/dist/helpers/withCloudflare.d.ts +1 -1
  38. package/dist/helpers/withCloudflare.js +2 -2
  39. package/dist/http/openNextResponse.d.ts +2 -10
  40. package/dist/http/openNextResponse.js +5 -3
  41. package/dist/overrides/converters/aws-apigw-v2.js +2 -1
  42. package/dist/overrides/converters/aws-cloudfront.js +1 -1
  43. package/dist/overrides/converters/edge.d.ts +2 -5
  44. package/dist/overrides/converters/edge.js +5 -4
  45. package/dist/overrides/incrementalCache/dummy.js +4 -3
  46. package/dist/overrides/proxyExternalRequest/dummy.js +2 -1
  47. package/dist/overrides/proxyExternalRequest/node.js +2 -2
  48. package/dist/overrides/queue/dummy.js +2 -1
  49. package/dist/overrides/warmer/dummy.js +2 -1
  50. package/dist/overrides/wrappers/aws-lambda-streaming.d.ts +1 -1
  51. package/dist/overrides/wrappers/aws-lambda-streaming.js +0 -4
  52. package/dist/overrides/wrappers/aws-lambda.js +0 -3
  53. package/dist/overrides/wrappers/cloudflare-edge.d.ts +9 -0
  54. package/dist/overrides/wrappers/{cloudflare.js → cloudflare-edge.js} +3 -3
  55. package/dist/overrides/wrappers/cloudflare-node.d.ts +8 -0
  56. package/dist/overrides/wrappers/cloudflare-node.js +50 -0
  57. package/dist/overrides/wrappers/dummy.d.ts +2 -2
  58. package/dist/overrides/wrappers/dummy.js +1 -1
  59. package/dist/overrides/wrappers/node.d.ts +1 -1
  60. package/dist/overrides/wrappers/node.js +0 -3
  61. package/dist/plugins/edge.js +6 -1
  62. package/dist/plugins/resolve.js +5 -1
  63. package/dist/types/open-next.d.ts +26 -1
  64. package/dist/types/overrides.d.ts +4 -5
  65. package/dist/{adapters → utils}/binary.js +1 -0
  66. package/dist/utils/error.d.ts +1 -0
  67. package/dist/utils/error.js +8 -0
  68. package/package.json +3 -3
  69. package/dist/overrides/wrappers/cloudflare.d.ts +0 -12
  70. /package/dist/{adapters → utils}/binary.d.ts +0 -0
@@ -8,6 +8,8 @@ const compatibilityMatrix = {
8
8
  ],
9
9
  "aws-lambda-streaming": ["aws-apigw-v2"],
10
10
  cloudflare: ["edge"],
11
+ "cloudflare-edge": ["edge"],
12
+ "cloudflare-node": ["edge"],
11
13
  node: ["node"],
12
14
  dummy: [],
13
15
  };
@@ -63,7 +65,7 @@ export function validateConfig(config) {
63
65
  logger.warn("You've disabled incremental cache. This means that ISR and SSG will not work.");
64
66
  }
65
67
  if (config.dangerous?.disableTagCache) {
66
- logger.warn(`You've disabled tag cache.
68
+ logger.warn(`You've disabled tag cache.
67
69
  This means that revalidatePath and revalidateTag from next/cache will not work.
68
70
  It is safe to disable if you only use page router`);
69
71
  }
@@ -1,3 +1,2 @@
1
- import type { StreamCreator } from "../http/index.js";
2
- import type { InternalEvent, InternalResult } from "../types/open-next";
1
+ import type { InternalEvent, InternalResult, StreamCreator } from "../types/open-next";
3
2
  export declare function openNextHandler(internalEvent: InternalEvent, responseStreaming?: StreamCreator): Promise<InternalResult>;
@@ -4,35 +4,44 @@ import { runWithOpenNextRequestContext } from "../utils/promise";
4
4
  import { debug, error, warn } from "../adapters/logger";
5
5
  import { patchAsyncStorage } from "./patchAsyncStorage";
6
6
  import { convertRes, createServerResponse } from "./routing/util";
7
- import routingHandler, { MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
7
+ import routingHandler, { INTERNAL_HEADER_INITIAL_PATH, INTERNAL_HEADER_RESOLVED_ROUTES, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
8
8
  import { requestHandler, setNextjsPrebundledReact } from "./util";
9
9
  // This is used to identify requests in the cache
10
10
  globalThis.__openNextAls = new AsyncLocalStorage();
11
11
  patchAsyncStorage();
12
12
  export async function openNextHandler(internalEvent, responseStreaming) {
13
+ const initialHeaders = internalEvent.headers;
13
14
  // We run everything in the async local storage context so that it is available in the middleware as well as in NextServer
14
- return runWithOpenNextRequestContext({ isISRRevalidation: internalEvent.headers["x-isr"] === "1" }, async () => {
15
- if (internalEvent.headers["x-forwarded-host"]) {
16
- internalEvent.headers.host = internalEvent.headers["x-forwarded-host"];
15
+ return runWithOpenNextRequestContext({ isISRRevalidation: initialHeaders["x-isr"] === "1" }, async () => {
16
+ if (initialHeaders["x-forwarded-host"]) {
17
+ initialHeaders.host = initialHeaders["x-forwarded-host"];
17
18
  }
18
19
  debug("internalEvent", internalEvent);
19
- let preprocessResult = {
20
- internalEvent: internalEvent,
20
+ // These 2 will get overwritten by the routing handler if not using an external middleware
21
+ const internalHeaders = {
22
+ initialPath: initialHeaders[INTERNAL_HEADER_INITIAL_PATH] ?? internalEvent.rawPath,
23
+ resolvedRoutes: initialHeaders[INTERNAL_HEADER_RESOLVED_ROUTES]
24
+ ? JSON.parse(initialHeaders[INTERNAL_HEADER_RESOLVED_ROUTES])
25
+ : [],
26
+ };
27
+ let routingResult = {
28
+ internalEvent,
21
29
  isExternalRewrite: false,
22
30
  origin: false,
23
31
  isISR: false,
32
+ ...internalHeaders,
24
33
  };
25
34
  //#override withRouting
26
35
  try {
27
- preprocessResult = await routingHandler(internalEvent);
36
+ routingResult = await routingHandler(internalEvent);
28
37
  }
29
38
  catch (e) {
30
39
  warn("Routing failed.", e);
31
40
  }
32
41
  //#endOverride
33
- const headers = "type" in preprocessResult
34
- ? preprocessResult.headers
35
- : preprocessResult.internalEvent.headers;
42
+ const headers = "type" in routingResult
43
+ ? routingResult.headers
44
+ : routingResult.internalEvent.headers;
36
45
  const overwrittenResponseHeaders = {};
37
46
  for (const [rawKey, value] of Object.entries(headers)) {
38
47
  if (!rawKey.startsWith(MIDDLEWARE_HEADER_PREFIX)) {
@@ -43,14 +52,14 @@ export async function openNextHandler(internalEvent, responseStreaming) {
43
52
  headers[key] = value;
44
53
  delete headers[rawKey];
45
54
  }
46
- if ("isExternalRewrite" in preprocessResult &&
47
- preprocessResult.isExternalRewrite === true) {
55
+ if ("isExternalRewrite" in routingResult &&
56
+ routingResult.isExternalRewrite === true) {
48
57
  try {
49
- preprocessResult = await globalThis.proxyExternalRequest.proxy(preprocessResult.internalEvent);
58
+ routingResult = await globalThis.proxyExternalRequest.proxy(routingResult.internalEvent);
50
59
  }
51
60
  catch (e) {
52
61
  error("External request failed.", e);
53
- preprocessResult = {
62
+ routingResult = {
54
63
  internalEvent: {
55
64
  type: "core",
56
65
  rawPath: "/500",
@@ -65,25 +74,27 @@ export async function openNextHandler(internalEvent, responseStreaming) {
65
74
  isExternalRewrite: false,
66
75
  isISR: false,
67
76
  origin: false,
77
+ initialPath: internalEvent.rawPath,
78
+ resolvedRoutes: [{ route: "/500", type: "page" }],
68
79
  };
69
80
  }
70
81
  }
71
- if ("type" in preprocessResult) {
82
+ if ("type" in routingResult) {
72
83
  // response is used only in the streaming case
73
84
  if (responseStreaming) {
74
85
  const response = createServerResponse(internalEvent, headers, responseStreaming);
75
- response.statusCode = preprocessResult.statusCode;
86
+ response.statusCode = routingResult.statusCode;
76
87
  response.flushHeaders();
77
- const [bodyToConsume, bodyToReturn] = preprocessResult.body.tee();
88
+ const [bodyToConsume, bodyToReturn] = routingResult.body.tee();
78
89
  for await (const chunk of bodyToConsume) {
79
90
  response.write(chunk);
80
91
  }
81
92
  response.end();
82
- preprocessResult.body = bodyToReturn;
93
+ routingResult.body = bodyToReturn;
83
94
  }
84
- return preprocessResult;
95
+ return routingResult;
85
96
  }
86
- const preprocessedEvent = preprocessResult.internalEvent;
97
+ const preprocessedEvent = routingResult.internalEvent;
87
98
  debug("preprocessedEvent", preprocessedEvent);
88
99
  const reqProps = {
89
100
  method: preprocessedEvent.method,
@@ -227,7 +227,7 @@ export function handleRedirects(event, redirects) {
227
227
  }
228
228
  export function fixDataPage(internalEvent, buildId) {
229
229
  const { rawPath, query } = internalEvent;
230
- const dataPattern = `/_next/data/${buildId}`;
230
+ const dataPattern = `${NextConfig.basePath ?? ""}/_next/data/${buildId}`;
231
231
  // Return 404 for data requests that don't match the buildId
232
232
  if (rawPath.startsWith("/_next/data") && !rawPath.startsWith(dataPattern)) {
233
233
  return {
@@ -1,11 +1,11 @@
1
1
  import type { InternalEvent, InternalResult } from "../../types/open-next.js";
2
- type MiddlewareOutputEvent = InternalEvent & {
2
+ type MiddlewareEvent = InternalEvent & {
3
3
  responseHeaders?: Record<string, string | string[]>;
4
- externalRewrite?: boolean;
4
+ isExternalRewrite?: boolean;
5
5
  };
6
6
  type Middleware = (request: Request) => Response | Promise<Response>;
7
7
  type MiddlewareLoader = () => Promise<{
8
8
  default: Middleware;
9
9
  }>;
10
- export declare function handleMiddleware(internalEvent: InternalEvent, middlewareLoader?: MiddlewareLoader): Promise<MiddlewareOutputEvent | InternalResult>;
10
+ export declare function handleMiddleware(internalEvent: InternalEvent, middlewareLoader?: MiddlewareLoader): Promise<MiddlewareEvent | InternalResult>;
11
11
  export {};
@@ -114,7 +114,7 @@ export async function handleMiddleware(internalEvent, middlewareLoader = default
114
114
  // NOTE: the header was added to `req` from above
115
115
  const rewriteUrl = responseHeaders.get("x-middleware-rewrite");
116
116
  let rewritten = false;
117
- let externalRewrite = false;
117
+ let isExternalRewrite = false;
118
118
  let middlewareQueryString = internalEvent.query;
119
119
  let newUrl = internalEvent.url;
120
120
  if (rewriteUrl) {
@@ -122,7 +122,7 @@ export async function handleMiddleware(internalEvent, middlewareLoader = default
122
122
  if (isExternal(rewriteUrl, internalEvent.headers.host)) {
123
123
  newUrl = rewriteUrl;
124
124
  rewritten = true;
125
- externalRewrite = true;
125
+ isExternalRewrite = true;
126
126
  }
127
127
  else {
128
128
  const rewriteUrlObject = new URL(rewriteUrl);
@@ -147,7 +147,6 @@ export async function handleMiddleware(internalEvent, middlewareLoader = default
147
147
  if (result.body) {
148
148
  // transfer response body to res
149
149
  const body = result.body;
150
- // await pipeReadable(result.response.body, res);
151
150
  return {
152
151
  type: internalEvent.type,
153
152
  statusCode: statusCode,
@@ -169,6 +168,6 @@ export async function handleMiddleware(internalEvent, middlewareLoader = default
169
168
  query: middlewareQueryString,
170
169
  cookies: internalEvent.cookies,
171
170
  remoteAddress: internalEvent.remoteAddress,
172
- externalRewrite,
171
+ isExternalRewrite,
173
172
  };
174
173
  }
@@ -0,0 +1,10 @@
1
+ import type { RouteType } from "../../types/open-next";
2
+ export declare const apiPrefix: string;
3
+ export declare const staticRouteMatcher: (path: string) => {
4
+ route: string;
5
+ type: RouteType;
6
+ }[];
7
+ export declare const dynamicRouteMatcher: (path: string) => {
8
+ route: string;
9
+ type: RouteType;
10
+ }[];
@@ -0,0 +1,45 @@
1
+ import { AppPathRoutesManifest, RoutesManifest } from "../../adapters/config/index";
2
+ // Add the locale prefix to the regex so we correctly match the rawPath
3
+ const optionalLocalePrefixRegex = `^/(?:${RoutesManifest.locales.map((locale) => `${locale}/?`).join("|")})?`;
4
+ // Add the basepath prefix to the regex so we correctly match the rawPath
5
+ const optionalBasepathPrefixRegex = RoutesManifest.basePath
6
+ ? `^${RoutesManifest.basePath}/?`
7
+ : "^/";
8
+ // Add the basePath prefix to the api routes
9
+ export const apiPrefix = `${RoutesManifest.basePath ?? ""}/api`;
10
+ const optionalPrefix = optionalLocalePrefixRegex.replace("^/", optionalBasepathPrefixRegex);
11
+ function routeMatcher(routeDefinitions) {
12
+ const regexp = routeDefinitions.map((route) => ({
13
+ page: route.page,
14
+ regexp: new RegExp(route.regex.replace("^/", optionalPrefix)),
15
+ }));
16
+ const appPathsSet = new Set();
17
+ const routePathsSet = new Set();
18
+ // We need to use AppPathRoutesManifest here
19
+ for (const [k, v] of Object.entries(AppPathRoutesManifest)) {
20
+ if (k.endsWith("page")) {
21
+ appPathsSet.add(v);
22
+ }
23
+ else if (k.endsWith("route")) {
24
+ routePathsSet.add(v);
25
+ }
26
+ }
27
+ return function matchRoute(path) {
28
+ const foundRoutes = regexp.filter((route) => route.regexp.test(path));
29
+ return foundRoutes.map((foundRoute) => {
30
+ let routeType = "page";
31
+ if (appPathsSet.has(foundRoute.page)) {
32
+ routeType = "app";
33
+ }
34
+ else if (routePathsSet.has(foundRoute.page)) {
35
+ routeType = "route";
36
+ }
37
+ return {
38
+ route: foundRoute.page,
39
+ type: routeType,
40
+ };
41
+ });
42
+ };
43
+ }
44
+ export const staticRouteMatcher = routeMatcher(RoutesManifest.routes.static);
45
+ export const dynamicRouteMatcher = routeMatcher(RoutesManifest.routes.dynamic);
@@ -1,8 +1,8 @@
1
1
  import type { OutgoingHttpHeaders } from "node:http";
2
- import type { IncomingMessage, StreamCreator } from "../../http/index.js";
2
+ import type { IncomingMessage } from "../../http/index.js";
3
3
  import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
4
4
  import type { MiddlewareManifest } from "../../types/next-types";
5
- import type { InternalEvent, InternalResult } from "../../types/open-next.js";
5
+ import type { InternalEvent, InternalResult, StreamCreator } from "../../types/open-next.js";
6
6
  /**
7
7
  *
8
8
  * @__PURE__
@@ -60,7 +60,7 @@ export declare function convertBodyToReadableStream(method: string, body?: strin
60
60
  *
61
61
  * @__PURE__
62
62
  */
63
- export declare function fixCacheHeaderForHtmlPages(rawPath: string, headers: OutgoingHttpHeaders): void;
63
+ export declare function fixCacheHeaderForHtmlPages(internalEvent: InternalEvent, headers: OutgoingHttpHeaders): void;
64
64
  /**
65
65
  *
66
66
  * @__PURE__
@@ -3,8 +3,9 @@ import { Readable } from "node:stream";
3
3
  import { BuildId, HtmlPages, NextConfig } from "../../adapters/config/index.js";
4
4
  import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
5
5
  import { parseHeaders } from "../../http/util.js";
6
- import { isBinaryContentType } from "../../adapters/binary.js";
7
6
  import { debug, error } from "../../adapters/logger.js";
7
+ import { isBinaryContentType } from "../../utils/binary.js";
8
+ import { localizePath } from "./i18n/index.js";
8
9
  /**
9
10
  *
10
11
  * @__PURE__
@@ -169,9 +170,9 @@ var CommonHeaders;
169
170
  *
170
171
  * @__PURE__
171
172
  */
172
- export function fixCacheHeaderForHtmlPages(rawPath, headers) {
173
+ export function fixCacheHeaderForHtmlPages(internalEvent, headers) {
173
174
  // We don't want to cache error pages
174
- if (rawPath === "/404" || rawPath === "/500") {
175
+ if (internalEvent.rawPath === "/404" || internalEvent.rawPath === "/500") {
175
176
  if (process.env.OPEN_NEXT_DANGEROUSLY_SET_ERROR_HEADERS === "true") {
176
177
  return;
177
178
  }
@@ -179,9 +180,10 @@ export function fixCacheHeaderForHtmlPages(rawPath, headers) {
179
180
  "private, no-cache, no-store, max-age=0, must-revalidate";
180
181
  return;
181
182
  }
183
+ const localizedPath = localizePath(internalEvent);
182
184
  // WORKAROUND: `NextServer` does not set cache headers for HTML pages
183
185
  // https://opennext.js.org/aws/v2/advanced/workaround#workaround-nextserver-does-not-set-cache-headers-for-html-pages
184
- if (HtmlPages.includes(rawPath)) {
186
+ if (HtmlPages.includes(localizedPath)) {
185
187
  headers[CommonHeaders.CACHE_CONTROL] =
186
188
  "public, max-age=0, s-maxage=31536000, must-revalidate";
187
189
  }
@@ -352,7 +354,7 @@ export function fixISRHeaders(headers) {
352
354
  */
353
355
  export function createServerResponse(internalEvent, headers, responseStream) {
354
356
  return new OpenNextNodeResponse((_headers) => {
355
- fixCacheHeaderForHtmlPages(internalEvent.rawPath, _headers);
357
+ fixCacheHeaderForHtmlPages(internalEvent, _headers);
356
358
  fixSWRCacheHeader(_headers);
357
359
  addOpenNextHeader(_headers);
358
360
  fixISRHeaders(_headers);
@@ -1,10 +1,7 @@
1
- import type { InternalEvent, InternalResult, Origin } from "../types/open-next";
1
+ import type { InternalEvent, InternalResult, RoutingResult } from "../types/open-next";
2
2
  export declare const MIDDLEWARE_HEADER_PREFIX = "x-middleware-response-";
3
3
  export declare const MIDDLEWARE_HEADER_PREFIX_LEN: number;
4
- export interface MiddlewareOutputEvent {
5
- internalEvent: InternalEvent;
6
- isExternalRewrite: boolean;
7
- origin: Origin | false;
8
- isISR: boolean;
9
- }
10
- export default function routingHandler(event: InternalEvent): Promise<InternalResult | MiddlewareOutputEvent>;
4
+ export declare const INTERNAL_HEADER_PREFIX = "x-opennext-";
5
+ export declare const INTERNAL_HEADER_INITIAL_PATH = "x-opennext-initial-path";
6
+ export declare const INTERNAL_HEADER_RESOLVED_ROUTES = "x-opennext-resolved-routes";
7
+ export default function routingHandler(event: InternalEvent): Promise<InternalResult | RoutingResult>;
@@ -3,26 +3,12 @@ import { debug } from "../adapters/logger";
3
3
  import { cacheInterceptor } from "./routing/cacheInterceptor";
4
4
  import { fixDataPage, getNextConfigHeaders, handleFallbackFalse, handleRedirects, handleRewrites, } from "./routing/matcher";
5
5
  import { handleMiddleware } from "./routing/middleware";
6
+ import { apiPrefix, dynamicRouteMatcher, staticRouteMatcher, } from "./routing/routeMatcher";
6
7
  export const MIDDLEWARE_HEADER_PREFIX = "x-middleware-response-";
7
8
  export const MIDDLEWARE_HEADER_PREFIX_LEN = MIDDLEWARE_HEADER_PREFIX.length;
8
- // Add the locale prefix to the regex so we correctly match the rawPath
9
- const optionalLocalePrefixRegex = RoutesManifest.locales.length
10
- ? `^/(?:${RoutesManifest.locales.map((locale) => `${locale}/?`).join("|")})?`
11
- : "^/";
12
- // Add the basepath prefix to the regex so we correctly match the rawPath
13
- const optionalBasepathPrefixRegex = RoutesManifest.basePath
14
- ? `^${RoutesManifest.basePath}/?`
15
- : "^/";
16
- // Add the basePath prefix to the api routes
17
- const apiPrefix = RoutesManifest.basePath
18
- ? `${RoutesManifest.basePath}/api`
19
- : "/api";
20
- const staticRegexp = RoutesManifest.routes.static.map((route) => new RegExp(route.regex
21
- .replace("^/", optionalLocalePrefixRegex)
22
- .replace("^/", optionalBasepathPrefixRegex)));
23
- const dynamicRegexp = RoutesManifest.routes.dynamic.map((route) => new RegExp(route.regex
24
- .replace("^/", optionalLocalePrefixRegex)
25
- .replace("^/", optionalBasepathPrefixRegex)));
9
+ export const INTERNAL_HEADER_PREFIX = "x-opennext-";
10
+ export const INTERNAL_HEADER_INITIAL_PATH = `${INTERNAL_HEADER_PREFIX}initial-path`;
11
+ export const INTERNAL_HEADER_RESOLVED_ROUTES = `${INTERNAL_HEADER_PREFIX}resolved-routes`;
26
12
  // Geolocation headers starting from Nextjs 15
27
13
  // See https://github.com/vercel/vercel/blob/7714b1c/packages/functions/src/headers.ts
28
14
  const geoHeaderToNextHeader = {
@@ -50,6 +36,14 @@ export default async function routingHandler(event) {
50
36
  event.headers[nextGeoName] = value;
51
37
  }
52
38
  }
39
+ // First we remove internal headers
40
+ // We don't want to allow users to set these headers
41
+ for (const key of Object.keys(event.headers)) {
42
+ if (key.startsWith(INTERNAL_HEADER_PREFIX) ||
43
+ key.startsWith(MIDDLEWARE_HEADER_PREFIX)) {
44
+ delete event.headers[key];
45
+ }
46
+ }
53
47
  const nextHeaders = getNextConfigHeaders(event, ConfigHeaders);
54
48
  let internalEvent = fixDataPage(event, BuildId);
55
49
  if ("statusCode" in internalEvent) {
@@ -60,24 +54,24 @@ export default async function routingHandler(event) {
60
54
  debug("redirect", redirect);
61
55
  return redirect;
62
56
  }
63
- const middleware = await handleMiddleware(internalEvent);
64
- let middlewareResponseHeaders = {};
65
- if ("statusCode" in middleware) {
66
- return middleware;
57
+ const eventOrResult = await handleMiddleware(internalEvent);
58
+ const isResult = "statusCode" in eventOrResult;
59
+ if (isResult) {
60
+ return eventOrResult;
67
61
  }
68
- middlewareResponseHeaders = middleware.responseHeaders || {};
69
- internalEvent = middleware;
70
- // At this point internalEvent is an InternalEvent or a MiddlewareOutputEvent
71
- let isExternalRewrite = middleware.externalRewrite ?? false;
62
+ const middlewareResponseHeaders = eventOrResult.responseHeaders;
63
+ let isExternalRewrite = eventOrResult.isExternalRewrite ?? false;
64
+ // internalEvent is `InternalEvent | MiddlewareEvent`
65
+ internalEvent = eventOrResult;
72
66
  if (!isExternalRewrite) {
73
67
  // First rewrite to be applied
74
68
  const beforeRewrites = handleRewrites(internalEvent, RoutesManifest.rewrites.beforeFiles);
75
69
  internalEvent = beforeRewrites.internalEvent;
76
70
  isExternalRewrite = beforeRewrites.isExternalRewrite;
77
71
  }
78
- const isStaticRoute = !isExternalRewrite &&
79
- staticRegexp.some((route) => route.test(internalEvent.rawPath));
80
- if (!isStaticRoute && !isExternalRewrite) {
72
+ const foundStaticRoute = staticRouteMatcher(internalEvent.rawPath);
73
+ const isStaticRoute = !isExternalRewrite && foundStaticRoute.length > 0;
74
+ if (!(isStaticRoute || isExternalRewrite)) {
81
75
  // Second rewrite to be applied
82
76
  const afterRewrites = handleRewrites(internalEvent, RoutesManifest.rewrites.afterFiles);
83
77
  internalEvent = afterRewrites.internalEvent;
@@ -86,9 +80,9 @@ export default async function routingHandler(event) {
86
80
  // We want to run this just before the dynamic route check
87
81
  const { event: fallbackEvent, isISR } = handleFallbackFalse(internalEvent, PrerenderManifest);
88
82
  internalEvent = fallbackEvent;
89
- const isDynamicRoute = !isExternalRewrite &&
90
- dynamicRegexp.some((route) => route.test(internalEvent.rawPath));
91
- if (!isDynamicRoute && !isStaticRoute && !isExternalRewrite) {
83
+ const foundDynamicRoute = dynamicRouteMatcher(internalEvent.rawPath);
84
+ const isDynamicRoute = !isExternalRewrite && foundDynamicRoute.length > 0;
85
+ if (!(isDynamicRoute || isStaticRoute || isExternalRewrite)) {
92
86
  // Fallback rewrite to be applied
93
87
  const fallbackRewrites = handleRewrites(internalEvent, RoutesManifest.rewrites.fallback);
94
88
  internalEvent = fallbackRewrites.internalEvent;
@@ -103,12 +97,12 @@ export default async function routingHandler(event) {
103
97
  const isRouteFoundBeforeAllRewrites = isStaticRoute || isDynamicRoute || isExternalRewrite;
104
98
  // If we still haven't found a route, we show the 404 page
105
99
  // We need to ensure that rewrites are applied before showing the 404 page
106
- if (!isRouteFoundBeforeAllRewrites &&
107
- !isApiRoute &&
108
- !isNextImageRoute &&
100
+ if (!(isRouteFoundBeforeAllRewrites ||
101
+ isApiRoute ||
102
+ isNextImageRoute ||
109
103
  // We need to check again once all rewrites have been applied
110
- !staticRegexp.some((route) => route.test(internalEvent.rawPath)) &&
111
- !dynamicRegexp.some((route) => route.test(internalEvent.rawPath))) {
104
+ staticRouteMatcher(internalEvent.rawPath).length > 0 ||
105
+ dynamicRouteMatcher(internalEvent.rawPath).length > 0)) {
112
106
  internalEvent = {
113
107
  ...internalEvent,
114
108
  rawPath: "/404",
@@ -136,10 +130,17 @@ export default async function routingHandler(event) {
136
130
  ...middlewareResponseHeaders,
137
131
  ...nextHeaders,
138
132
  });
133
+ const resolvedRoutes = [
134
+ ...foundStaticRoute,
135
+ ...foundDynamicRoute,
136
+ ];
137
+ debug("resolvedRoutes", resolvedRoutes);
139
138
  return {
140
139
  internalEvent,
141
140
  isExternalRewrite,
142
141
  origin: false,
143
142
  isISR,
143
+ initialPath: event.rawPath,
144
+ resolvedRoutes,
144
145
  };
145
146
  }
@@ -57,7 +57,7 @@ export declare function withCloudflare<Fn extends Record<string, CloudflareCompa
57
57
  external: true;
58
58
  originResolver: "pattern-env";
59
59
  override: {
60
- wrapper: "cloudflare";
60
+ wrapper: "cloudflare-edge";
61
61
  converter: "edge";
62
62
  };
63
63
  };
@@ -36,7 +36,7 @@ export function withCloudflare(config) {
36
36
  routes: [fn.routes],
37
37
  patterns: [fn.patterns],
38
38
  override: {
39
- wrapper: "cloudflare",
39
+ wrapper: "cloudflare-edge",
40
40
  converter: "edge",
41
41
  },
42
42
  }
@@ -50,7 +50,7 @@ export function withCloudflare(config) {
50
50
  external: true,
51
51
  originResolver: "pattern-env",
52
52
  override: {
53
- wrapper: "cloudflare",
53
+ wrapper: "cloudflare-edge",
54
54
  converter: "edge",
55
55
  },
56
56
  },
@@ -1,16 +1,8 @@
1
1
  import type { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from "node:http";
2
2
  import type { Socket } from "node:net";
3
- import type { TransformCallback, Writable } from "node:stream";
3
+ import type { TransformCallback } from "node:stream";
4
4
  import { Transform } from "node:stream";
5
- export interface StreamCreator {
6
- writeHeaders(prelude: {
7
- statusCode: number;
8
- cookies: string[];
9
- headers: Record<string, string>;
10
- }): Writable;
11
- onWrite?: () => void;
12
- onFinish: (length: number) => void;
13
- }
5
+ import type { StreamCreator } from "../types/open-next";
14
6
  export declare class OpenNextNodeResponse extends Transform implements ServerResponse {
15
7
  private fixHeaders;
16
8
  private onEnd;
@@ -64,7 +64,9 @@ export class OpenNextNodeResponse extends Transform {
64
64
  return this;
65
65
  }
66
66
  get finished() {
67
- return Boolean(this.writableFinished && this.responseStream?.writableFinished);
67
+ return this.responseStream
68
+ ? this.responseStream?.writableFinished
69
+ : this.writableFinished;
68
70
  }
69
71
  setHeader(name, value) {
70
72
  const key = name.toLowerCase();
@@ -125,7 +127,7 @@ export class OpenNextNodeResponse extends Transform {
125
127
  ...this.initialHeaders,
126
128
  ...this.headers,
127
129
  };
128
- const initialCookies = parseCookies(this.initialHeaders[SET_COOKIE_HEADER]);
130
+ const initialCookies = parseCookies(this.initialHeaders[SET_COOKIE_HEADER]?.toString());
129
131
  this._cookies =
130
132
  mergeHeadersPriority === "middleware"
131
133
  ? [...this._cookies, ...initialCookies]
@@ -226,7 +228,7 @@ export class OpenNextNodeResponse extends Transform {
226
228
  ?.getStore()
227
229
  ?.pendingPromiseRunner.add(this.onEnd(this.headers));
228
230
  const bodyLength = this.getBody().length;
229
- this.streamCreator?.onFinish(bodyLength);
231
+ this.streamCreator?.onFinish?.(bodyLength);
230
232
  //This is only here because of aws broken streaming implementation.
231
233
  //Hopefully one day they will be able to give us a working streaming implementation in lambda for everyone
232
234
  //If you're lucky you have a working streaming implementation in your aws account and don't need this
@@ -3,7 +3,8 @@ import { fromReadableStream } from "../../utils/stream";
3
3
  import { debug } from "../../adapters/logger";
4
4
  import { convertToQuery } from "../../core/routing/util";
5
5
  import { removeUndefinedFromQuery } from "./utils";
6
- // Not sure which one is reallly needed as this is not documented anywhere but server actions redirect are not working without this, it causes a 500 error from cloudfront itself with a 'x-amzErrortype: InternalFailure' header
6
+ // Not sure which one is really needed as this is not documented anywhere but server actions redirect are not working without this,
7
+ // it causes a 500 error from cloudfront itself with a 'x-amzErrortype: InternalFailure' header
7
8
  const CloudFrontBlacklistedHeaders = [
8
9
  "connection",
9
10
  "expect",
@@ -1,7 +1,7 @@
1
1
  import { parseCookies } from "../../http/util";
2
2
  import { fromReadableStream } from "../../utils/stream";
3
3
  import { debug } from "../../adapters/logger";
4
- import { convertToQuery, convertToQueryString, } from "../../core/routing/util";
4
+ import { convertToQuery, convertToQueryString } from "../../core/routing/util";
5
5
  const cloudfrontBlacklistedHeaders = [
6
6
  // Disallowed headers, see: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-function-restrictions-all.html#function-restrictions-disallowed-headers
7
7
  "connection",
@@ -1,10 +1,7 @@
1
- import type { InternalEvent, InternalResult } from "../../types/open-next";
1
+ import type { InternalEvent, InternalResult, MiddlewareResult } from "../../types/open-next";
2
2
  import type { Converter } from "../../types/overrides";
3
- import type { MiddlewareOutputEvent } from "../../core/routingHandler";
4
3
  declare global {
5
4
  var __dangerous_ON_edge_converter_returns_request: boolean | undefined;
6
5
  }
7
- declare const converter: Converter<InternalEvent, InternalResult | ({
8
- type: "middleware";
9
- } & MiddlewareOutputEvent)>;
6
+ declare const converter: Converter<InternalEvent, InternalResult | MiddlewareResult>;
10
7
  export default converter;
@@ -2,7 +2,8 @@ import { Buffer } from "node:buffer";
2
2
  import { parseCookies } from "../../http/util";
3
3
  const converter = {
4
4
  convertFrom: async (event) => {
5
- const searchParams = new URL(event.url).searchParams;
5
+ const url = new URL(event.url);
6
+ const searchParams = url.searchParams;
6
7
  const query = {};
7
8
  for (const [key, value] of searchParams.entries()) {
8
9
  if (key in query) {
@@ -17,13 +18,13 @@ const converter = {
17
18
  query[key] = value;
18
19
  }
19
20
  }
20
- //Transform body into Buffer
21
+ // Transform body into Buffer
21
22
  const body = await event.arrayBuffer();
22
23
  const headers = {};
23
24
  event.headers.forEach((value, key) => {
24
25
  headers[key] = value;
25
26
  });
26
- const rawPath = new URL(event.url).pathname;
27
+ const rawPath = url.pathname;
27
28
  const method = event.method;
28
29
  const shouldHaveBody = method !== "GET" && method !== "HEAD";
29
30
  const cookies = Object.fromEntries(parseCookies(event.headers.get("cookie")).map((cookie) => cookie.split("=")));
@@ -79,7 +80,7 @@ const converter = {
79
80
  }
80
81
  return new Response(result.body, {
81
82
  status: result.statusCode,
82
- headers: headers,
83
+ headers,
83
84
  });
84
85
  },
85
86
  name: "edge",
@@ -1,13 +1,14 @@
1
+ import { IgnorableError } from "../../utils/error";
1
2
  const dummyIncrementalCache = {
2
3
  name: "dummy",
3
4
  get: async () => {
4
- throw new Error("Dummy cache is not implemented");
5
+ throw new IgnorableError('"Dummy" cache does not cache anything');
5
6
  },
6
7
  set: async () => {
7
- throw new Error("Dummy cache is not implemented");
8
+ throw new IgnorableError('"Dummy" cache does not cache anything');
8
9
  },
9
10
  delete: async () => {
10
- throw new Error("Dummy cache is not implemented");
11
+ throw new IgnorableError('"Dummy" cache does not cache anything');
11
12
  },
12
13
  };
13
14
  export default dummyIncrementalCache;
@@ -1,7 +1,8 @@
1
+ import { FatalError } from "../../utils/error";
1
2
  const DummyProxyExternalRequest = {
2
3
  name: "dummy",
3
4
  proxy: async (_event) => {
4
- throw new Error("This is a dummy implementation");
5
+ throw new FatalError("This is a dummy implementation");
5
6
  },
6
7
  };
7
8
  export default DummyProxyExternalRequest;