@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.
- package/README.md +6 -1
- package/dist/adapters/cache.d.ts +1 -2
- package/dist/adapters/cache.js +2 -12
- package/dist/adapters/config/index.d.ts +2 -0
- package/dist/adapters/config/index.js +4 -3
- package/dist/adapters/config/util.d.ts +2 -0
- package/dist/adapters/config/util.js +12 -2
- package/dist/adapters/image-optimization-adapter.d.ts +1 -2
- package/dist/adapters/logger.js +32 -11
- package/dist/adapters/middleware.js +13 -2
- package/dist/adapters/plugins/image-optimization/image-optimization.d.ts +1 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.js +0 -1
- package/dist/adapters/plugins/image-optimization/image-optimization.replacement.d.ts +1 -0
- package/dist/adapters/util.js +5 -1
- package/dist/build/bundleNextServer.d.ts +2 -2
- package/dist/build/bundleNextServer.js +2 -2
- package/dist/build/copyTracedFiles.js +1 -1
- package/dist/build/createAssets.js +23 -24
- package/dist/build/createMiddleware.js +1 -1
- package/dist/build/createServerBundle.js +3 -3
- package/dist/build/edge/createEdgeBundle.d.ts +5 -4
- package/dist/build/edge/createEdgeBundle.js +35 -33
- package/dist/build/helper.d.ts +6 -1
- package/dist/build/helper.js +20 -5
- package/dist/build/validateConfig.js +3 -1
- package/dist/core/requestHandler.d.ts +1 -2
- package/dist/core/requestHandler.js +31 -20
- package/dist/core/routing/matcher.js +1 -1
- package/dist/core/routing/middleware.d.ts +3 -3
- package/dist/core/routing/middleware.js +3 -4
- package/dist/core/routing/routeMatcher.d.ts +10 -0
- package/dist/core/routing/routeMatcher.js +45 -0
- package/dist/core/routing/util.d.ts +3 -3
- package/dist/core/routing/util.js +7 -5
- package/dist/core/routingHandler.d.ts +5 -8
- package/dist/core/routingHandler.js +38 -37
- package/dist/helpers/withCloudflare.d.ts +1 -1
- package/dist/helpers/withCloudflare.js +2 -2
- package/dist/http/openNextResponse.d.ts +2 -10
- package/dist/http/openNextResponse.js +5 -3
- package/dist/overrides/converters/aws-apigw-v2.js +2 -1
- package/dist/overrides/converters/aws-cloudfront.js +1 -1
- package/dist/overrides/converters/edge.d.ts +2 -5
- package/dist/overrides/converters/edge.js +5 -4
- package/dist/overrides/incrementalCache/dummy.js +4 -3
- package/dist/overrides/proxyExternalRequest/dummy.js +2 -1
- package/dist/overrides/proxyExternalRequest/node.js +2 -2
- package/dist/overrides/queue/dummy.js +2 -1
- package/dist/overrides/warmer/dummy.js +2 -1
- package/dist/overrides/wrappers/aws-lambda-streaming.d.ts +1 -1
- package/dist/overrides/wrappers/aws-lambda-streaming.js +0 -4
- package/dist/overrides/wrappers/aws-lambda.js +0 -3
- package/dist/overrides/wrappers/cloudflare-edge.d.ts +9 -0
- package/dist/overrides/wrappers/{cloudflare.js → cloudflare-edge.js} +3 -3
- package/dist/overrides/wrappers/cloudflare-node.d.ts +8 -0
- package/dist/overrides/wrappers/cloudflare-node.js +50 -0
- package/dist/overrides/wrappers/dummy.d.ts +2 -2
- package/dist/overrides/wrappers/dummy.js +1 -1
- package/dist/overrides/wrappers/node.d.ts +1 -1
- package/dist/overrides/wrappers/node.js +0 -3
- package/dist/plugins/edge.js +6 -1
- package/dist/plugins/resolve.js +5 -1
- package/dist/types/open-next.d.ts +26 -1
- package/dist/types/overrides.d.ts +4 -5
- package/dist/{adapters → utils}/binary.js +1 -0
- package/dist/utils/error.d.ts +1 -0
- package/dist/utils/error.js +8 -0
- package/package.json +3 -3
- package/dist/overrides/wrappers/cloudflare.d.ts +0 -12
- /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 "../
|
|
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:
|
|
15
|
-
if (
|
|
16
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
|
34
|
-
?
|
|
35
|
-
:
|
|
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
|
|
47
|
-
|
|
55
|
+
if ("isExternalRewrite" in routingResult &&
|
|
56
|
+
routingResult.isExternalRewrite === true) {
|
|
48
57
|
try {
|
|
49
|
-
|
|
58
|
+
routingResult = await globalThis.proxyExternalRequest.proxy(routingResult.internalEvent);
|
|
50
59
|
}
|
|
51
60
|
catch (e) {
|
|
52
61
|
error("External request failed.", e);
|
|
53
|
-
|
|
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
|
|
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 =
|
|
86
|
+
response.statusCode = routingResult.statusCode;
|
|
76
87
|
response.flushHeaders();
|
|
77
|
-
const [bodyToConsume, bodyToReturn] =
|
|
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
|
-
|
|
93
|
+
routingResult.body = bodyToReturn;
|
|
83
94
|
}
|
|
84
|
-
return
|
|
95
|
+
return routingResult;
|
|
85
96
|
}
|
|
86
|
-
const preprocessedEvent =
|
|
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 =
|
|
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
|
|
2
|
+
type MiddlewareEvent = InternalEvent & {
|
|
3
3
|
responseHeaders?: Record<string, string | string[]>;
|
|
4
|
-
|
|
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<
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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,
|
|
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
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
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
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
57
|
+
const eventOrResult = await handleMiddleware(internalEvent);
|
|
58
|
+
const isResult = "statusCode" in eventOrResult;
|
|
59
|
+
if (isResult) {
|
|
60
|
+
return eventOrResult;
|
|
67
61
|
}
|
|
68
|
-
middlewareResponseHeaders =
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
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
|
|
79
|
-
|
|
80
|
-
if (!isStaticRoute
|
|
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
|
|
90
|
-
|
|
91
|
-
if (!isDynamicRoute
|
|
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
|
-
|
|
108
|
-
|
|
100
|
+
if (!(isRouteFoundBeforeAllRewrites ||
|
|
101
|
+
isApiRoute ||
|
|
102
|
+
isNextImageRoute ||
|
|
109
103
|
// We need to check again once all rewrites have been applied
|
|
110
|
-
|
|
111
|
-
|
|
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
|
}
|
|
@@ -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
|
|
3
|
+
import type { TransformCallback } from "node:stream";
|
|
4
4
|
import { Transform } from "node:stream";
|
|
5
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
5
|
+
throw new IgnorableError('"Dummy" cache does not cache anything');
|
|
5
6
|
},
|
|
6
7
|
set: async () => {
|
|
7
|
-
throw new
|
|
8
|
+
throw new IgnorableError('"Dummy" cache does not cache anything');
|
|
8
9
|
},
|
|
9
10
|
delete: async () => {
|
|
10
|
-
throw new
|
|
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
|
|
5
|
+
throw new FatalError("This is a dummy implementation");
|
|
5
6
|
},
|
|
6
7
|
};
|
|
7
8
|
export default DummyProxyExternalRequest;
|