@opennextjs/aws 3.6.0 → 3.6.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/dist/core/requestHandler.js +57 -29
- package/dist/core/routing/cacheInterceptor.js +2 -6
- package/dist/core/routing/matcher.js +15 -5
- package/dist/core/routing/middleware.js +0 -1
- package/dist/core/routing/routeMatcher.d.ts +3 -9
- package/dist/overrides/converters/edge.js +17 -1
- package/dist/overrides/imageLoader/fs-dev.js +4 -2
- package/dist/overrides/incrementalCache/fs-dev.js +2 -1
- package/dist/overrides/tagCache/fs-dev.js +3 -2
- package/dist/overrides/wrappers/express-dev.js +4 -2
- package/dist/types/global.d.ts +5 -0
- package/dist/utils/normalize-path.d.ts +1 -0
- package/dist/utils/normalize-path.js +8 -0
- package/package.json +1 -1
|
@@ -51,7 +51,11 @@ export async function openNextHandler(internalEvent, options) {
|
|
|
51
51
|
continue;
|
|
52
52
|
}
|
|
53
53
|
const key = rawKey.slice(MIDDLEWARE_HEADER_PREFIX_LEN);
|
|
54
|
-
|
|
54
|
+
// We skip this header here since it is used by Next internally and we don't want it on the response headers.
|
|
55
|
+
// This header needs to be present in the request headers for processRequest, so cookies().get() from Next will work on initial render.
|
|
56
|
+
if (key !== "x-middleware-set-cookie") {
|
|
57
|
+
overwrittenResponseHeaders[key] = value;
|
|
58
|
+
}
|
|
55
59
|
headers[key] = value;
|
|
56
60
|
delete headers[rawKey];
|
|
57
61
|
}
|
|
@@ -151,44 +155,68 @@ async function processRequest(req, res, routingResult) {
|
|
|
151
155
|
// Next.js doesn't parse body if the property exists
|
|
152
156
|
// https://github.com/dougmoscrop/serverless-http/issues/227
|
|
153
157
|
delete req.body;
|
|
158
|
+
// Here we try to apply as much request metadata as possible
|
|
159
|
+
// We apply every metadata from `resolve-routes` https://github.com/vercel/next.js/blob/916f105b97211de50f8580f0b39c9e7c60de4886/packages/next/src/server/lib/router-utils/resolve-routes.ts
|
|
160
|
+
// and `router-server` https://github.com/vercel/next.js/blob/916f105b97211de50f8580f0b39c9e7c60de4886/packages/next/src/server/lib/router-server.ts
|
|
161
|
+
const initialURL = new URL(routingResult.initialURL);
|
|
162
|
+
let invokeStatus;
|
|
163
|
+
if (routingResult.internalEvent.rawPath === "/500") {
|
|
164
|
+
invokeStatus = 500;
|
|
165
|
+
}
|
|
166
|
+
else if (routingResult.internalEvent.rawPath === "/404") {
|
|
167
|
+
invokeStatus = 404;
|
|
168
|
+
}
|
|
169
|
+
const requestMetadata = {
|
|
170
|
+
isNextDataReq: routingResult.internalEvent.query.__nextDataReq === "1",
|
|
171
|
+
initURL: routingResult.initialURL,
|
|
172
|
+
initQuery: convertToQuery(initialURL.search),
|
|
173
|
+
initProtocol: initialURL.protocol,
|
|
174
|
+
defaultLocale: NextConfig.i18n?.defaultLocale,
|
|
175
|
+
locale: routingResult.locale,
|
|
176
|
+
middlewareInvoke: false,
|
|
177
|
+
// By setting invokePath and invokeQuery we can bypass some of the routing logic in Next.js
|
|
178
|
+
invokePath: routingResult.internalEvent.rawPath,
|
|
179
|
+
invokeQuery: routingResult.internalEvent.query,
|
|
180
|
+
// invokeStatus is only used for error pages
|
|
181
|
+
invokeStatus,
|
|
182
|
+
};
|
|
154
183
|
try {
|
|
155
184
|
//#override applyNextjsPrebundledReact
|
|
156
185
|
setNextjsPrebundledReact(routingResult.internalEvent.rawPath);
|
|
157
186
|
//#endOverride
|
|
158
|
-
// Here we try to apply as much request metadata as possible
|
|
159
|
-
// We apply every metadata from `resolve-routes` https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
|
|
160
|
-
// and `router-server` https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-server.ts
|
|
161
|
-
const initialURL = new URL(routingResult.initialURL);
|
|
162
|
-
let invokeStatus;
|
|
163
|
-
if (routingResult.internalEvent.rawPath === "/500") {
|
|
164
|
-
invokeStatus = 500;
|
|
165
|
-
}
|
|
166
|
-
else if (routingResult.internalEvent.rawPath === "/404") {
|
|
167
|
-
invokeStatus = 404;
|
|
168
|
-
}
|
|
169
|
-
const requestMetadata = {
|
|
170
|
-
isNextDataReq: routingResult.internalEvent.query.__nextDataReq === "1",
|
|
171
|
-
initURL: routingResult.initialURL,
|
|
172
|
-
initQuery: convertToQuery(initialURL.search),
|
|
173
|
-
initProtocol: initialURL.protocol,
|
|
174
|
-
defaultLocale: NextConfig.i18n?.defaultLocale,
|
|
175
|
-
locale: routingResult.locale,
|
|
176
|
-
middlewareInvoke: false,
|
|
177
|
-
// By setting invokePath and invokeQuery we can bypass some of the routing logic in Next.js
|
|
178
|
-
invokePath: routingResult.internalEvent.rawPath,
|
|
179
|
-
invokeQuery: routingResult.internalEvent.query,
|
|
180
|
-
// invokeStatus is only used for error pages
|
|
181
|
-
invokeStatus,
|
|
182
|
-
};
|
|
183
187
|
// Next Server
|
|
184
188
|
await requestHandler(requestMetadata)(req, res);
|
|
185
189
|
}
|
|
186
190
|
catch (e) {
|
|
187
191
|
// This might fail when using bundled next, importing won't do the trick either
|
|
188
192
|
if (e.constructor.name === "NoFallbackError") {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
await handleNoFallbackError(req, res, routingResult, requestMetadata);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
error("NextJS request failed.", e);
|
|
197
|
+
await tryRenderError("500", res, routingResult.internalEvent);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async function handleNoFallbackError(req, res, routingResult, metadata, index = 1) {
|
|
202
|
+
if (index >= 5) {
|
|
203
|
+
await tryRenderError("500", res, routingResult.internalEvent);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (index >= routingResult.resolvedRoutes.length) {
|
|
207
|
+
await tryRenderError("404", res, routingResult.internalEvent);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
await requestHandler({
|
|
212
|
+
...routingResult,
|
|
213
|
+
invokeOutput: routingResult.resolvedRoutes[index].route,
|
|
214
|
+
...metadata,
|
|
215
|
+
})(req, res);
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
if (e.constructor.name === "NoFallbackError") {
|
|
219
|
+
await handleNoFallbackError(req, res, routingResult, metadata, index + 1);
|
|
192
220
|
}
|
|
193
221
|
else {
|
|
194
222
|
error("NextJS request failed.", e);
|
|
@@ -114,17 +114,13 @@ export async function cacheInterceptor(event) {
|
|
|
114
114
|
}
|
|
115
115
|
// We also need to remove trailing slash
|
|
116
116
|
localizedPath = localizedPath.replace(/\/$/, "");
|
|
117
|
-
// If empty path, it means we want index
|
|
118
|
-
if (localizedPath === "") {
|
|
119
|
-
localizedPath = "index";
|
|
120
|
-
}
|
|
121
117
|
debug("Checking cache for", localizedPath, PrerenderManifest);
|
|
122
|
-
const isISR = Object.keys(PrerenderManifest.routes).includes(localizedPath) ||
|
|
118
|
+
const isISR = Object.keys(PrerenderManifest.routes).includes(localizedPath ?? "/") ||
|
|
123
119
|
Object.values(PrerenderManifest.dynamicRoutes).some((dr) => new RegExp(dr.routeRegex).test(localizedPath));
|
|
124
120
|
debug("isISR", isISR);
|
|
125
121
|
if (isISR) {
|
|
126
122
|
try {
|
|
127
|
-
const cachedData = await globalThis.incrementalCache.get(localizedPath);
|
|
123
|
+
const cachedData = await globalThis.incrementalCache.get(localizedPath ?? "/index");
|
|
128
124
|
debug("cached data in interceptor", cachedData);
|
|
129
125
|
if (!cachedData?.value) {
|
|
130
126
|
return event;
|
|
@@ -3,6 +3,7 @@ import { compile, match } from "path-to-regexp";
|
|
|
3
3
|
import { emptyReadableStream, toReadableStream } from "../../utils/stream";
|
|
4
4
|
import { debug } from "../../adapters/logger";
|
|
5
5
|
import { handleLocaleRedirect, localizePath } from "./i18n";
|
|
6
|
+
import { dynamicRouteMatcher, staticRouteMatcher } from "./routeMatcher";
|
|
6
7
|
import { constructNextUrl, convertFromQueryString, convertToQueryString, escapeRegex, getUrlParts, isExternal, unescapeRegex, } from "./util";
|
|
7
8
|
const routeHasMatcher = (headers, cookies, query) => (redirect) => {
|
|
8
9
|
switch (redirect.type) {
|
|
@@ -265,9 +266,8 @@ export function fixDataPage(internalEvent, buildId) {
|
|
|
265
266
|
export function handleFallbackFalse(internalEvent, prerenderManifest) {
|
|
266
267
|
const { rawPath } = internalEvent;
|
|
267
268
|
const { dynamicRoutes, routes } = prerenderManifest;
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
.some(([, { routeRegex }]) => {
|
|
269
|
+
const prerenderedFallbackRoutes = Object.entries(dynamicRoutes).filter(([, { fallback }]) => fallback === false);
|
|
270
|
+
const routeFallback = prerenderedFallbackRoutes.some(([, { routeRegex }]) => {
|
|
271
271
|
const routeRegexExp = new RegExp(routeRegex);
|
|
272
272
|
return routeRegexExp.test(rawPath);
|
|
273
273
|
});
|
|
@@ -275,11 +275,21 @@ export function handleFallbackFalse(internalEvent, prerenderManifest) {
|
|
|
275
275
|
const routesAlreadyHaveLocale = locales?.includes(rawPath.split("/")[1]) ||
|
|
276
276
|
// If we don't use locales, we don't need to add the default locale
|
|
277
277
|
locales === undefined;
|
|
278
|
-
|
|
278
|
+
let localizedPath = routesAlreadyHaveLocale
|
|
279
279
|
? rawPath
|
|
280
280
|
: `/${NextConfig.i18n?.defaultLocale}${rawPath}`;
|
|
281
|
+
// We need to remove the trailing slash if it exists
|
|
282
|
+
if (NextConfig.trailingSlash && localizedPath.endsWith("/")) {
|
|
283
|
+
localizedPath = localizedPath.slice(0, -1);
|
|
284
|
+
}
|
|
285
|
+
const matchedStaticRoute = staticRouteMatcher(localizedPath);
|
|
286
|
+
const prerenderedFallbackRoutesName = prerenderedFallbackRoutes.map(([name]) => name);
|
|
287
|
+
const matchedDynamicRoute = dynamicRouteMatcher(localizedPath).filter(({ route }) => !prerenderedFallbackRoutesName.includes(route));
|
|
281
288
|
const isPregenerated = Object.keys(routes).includes(localizedPath);
|
|
282
|
-
if (routeFallback &&
|
|
289
|
+
if (routeFallback &&
|
|
290
|
+
!isPregenerated &&
|
|
291
|
+
matchedStaticRoute.length === 0 &&
|
|
292
|
+
matchedDynamicRoute.length === 0) {
|
|
283
293
|
return {
|
|
284
294
|
event: {
|
|
285
295
|
...internalEvent,
|
|
@@ -75,7 +75,6 @@ export async function handleMiddleware(internalEvent, initialSearch, middlewareL
|
|
|
75
75
|
// These are internal headers used by Next.js, we don't want to expose them to the client
|
|
76
76
|
const filteredHeaders = [
|
|
77
77
|
"x-middleware-override-headers",
|
|
78
|
-
"x-middleware-set-cookie",
|
|
79
78
|
"x-middleware-next",
|
|
80
79
|
"x-middleware-rewrite",
|
|
81
80
|
// We need to drop `content-encoding` because it will be decoded
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResolvedRoute } from "../../types/open-next";
|
|
2
2
|
export declare const apiPrefix: string;
|
|
3
|
-
export declare const staticRouteMatcher: (path: string) =>
|
|
4
|
-
|
|
5
|
-
type: RouteType;
|
|
6
|
-
}[];
|
|
7
|
-
export declare const dynamicRouteMatcher: (path: string) => {
|
|
8
|
-
route: string;
|
|
9
|
-
type: RouteType;
|
|
10
|
-
}[];
|
|
3
|
+
export declare const staticRouteMatcher: (path: string) => ResolvedRoute[];
|
|
4
|
+
export declare const dynamicRouteMatcher: (path: string) => ResolvedRoute[];
|
|
@@ -55,7 +55,23 @@ const converter = {
|
|
|
55
55
|
}
|
|
56
56
|
const headers = new Headers();
|
|
57
57
|
for (const [key, value] of Object.entries(result.headers)) {
|
|
58
|
-
|
|
58
|
+
if (key === "set-cookie" && typeof value === "string") {
|
|
59
|
+
// If the value is a string, we need to parse it into an array
|
|
60
|
+
// This is the case for middleware direct result
|
|
61
|
+
const cookies = parseCookies(value);
|
|
62
|
+
for (const cookie of cookies) {
|
|
63
|
+
headers.append(key, cookie);
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
for (const v of value) {
|
|
69
|
+
headers.append(key, v);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
headers.set(key, value);
|
|
74
|
+
}
|
|
59
75
|
}
|
|
60
76
|
return new Response(result.body, {
|
|
61
77
|
status: result.statusCode,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getMonorepoRelativePath } from "../../utils/normalize-path";
|
|
2
4
|
export default {
|
|
3
5
|
name: "fs-dev",
|
|
4
6
|
load: async (url) => {
|
|
5
|
-
const
|
|
6
|
-
const body = fs.createReadStream(
|
|
7
|
+
const imagePath = path.join(getMonorepoRelativePath(), "assets", url);
|
|
8
|
+
const body = fs.createReadStream(imagePath);
|
|
7
9
|
const contentType = url.endsWith(".png") ? "image/png" : "image/jpeg";
|
|
8
10
|
return {
|
|
9
11
|
body,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { getMonorepoRelativePath } from "../../utils/normalize-path";
|
|
3
4
|
const buildId = process.env.NEXT_BUILD_ID;
|
|
4
|
-
const basePath = path.
|
|
5
|
+
const basePath = path.join(getMonorepoRelativePath(), `cache/${buildId}`);
|
|
5
6
|
const getCacheKey = (key) => {
|
|
6
7
|
return path.join(basePath, `${key}.cache`);
|
|
7
8
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getMonorepoRelativePath } from "../../utils/normalize-path";
|
|
4
|
+
const tagFile = path.join(getMonorepoRelativePath(), "dynamodb-provider/dynamodb-cache.json");
|
|
4
5
|
const tagContent = fs.readFileSync(tagFile, "utf-8");
|
|
5
6
|
let tags = JSON.parse(tagContent);
|
|
6
7
|
const tagCache = {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import express from "express";
|
|
3
|
+
import { getMonorepoRelativePath } from "../../utils/normalize-path";
|
|
2
4
|
const wrapper = async (handler, converter) => {
|
|
3
5
|
const app = express();
|
|
4
6
|
// To serve static assets
|
|
5
|
-
app.use(express.static("
|
|
6
|
-
const imageHandlerPath = "
|
|
7
|
+
app.use(express.static(path.join(getMonorepoRelativePath(), "assets")));
|
|
8
|
+
const imageHandlerPath = path.join(getMonorepoRelativePath(), "image-optimization-function/index.mjs");
|
|
7
9
|
const imageHandler = await import(imageHandlerPath).then((m) => m.handler);
|
|
8
10
|
app.all("/_next/image", async (req, res) => {
|
|
9
11
|
const internalEvent = await converter.convertFrom(req);
|
package/dist/types/global.d.ts
CHANGED
|
@@ -185,5 +185,10 @@ declare global {
|
|
|
185
185
|
* Only available in main functions.
|
|
186
186
|
*/
|
|
187
187
|
var __next_route_preloader: (stage: "waitUntil" | "start" | "warmerEvent" | "onDemand") => Promise<void>;
|
|
188
|
+
/**
|
|
189
|
+
* This is the relative package path of the monorepo. It will be an empty string "" in normal repos.
|
|
190
|
+
* ex. `packages/web`
|
|
191
|
+
*/
|
|
192
|
+
var monorepoPackagePath: string;
|
|
188
193
|
}
|
|
189
194
|
export {};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
export function normalizePath(path) {
|
|
2
3
|
return path.replace(/\\/g, "/");
|
|
3
4
|
}
|
|
5
|
+
export function getMonorepoRelativePath(relativePath = "../..") {
|
|
6
|
+
return path.join(globalThis.monorepoPackagePath
|
|
7
|
+
.split("/")
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.map(() => "..")
|
|
10
|
+
.join("/"), relativePath);
|
|
11
|
+
}
|