@opennextjs/aws 3.1.4
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/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/adapters/binary.d.ts +1 -0
- package/dist/adapters/binary.js +63 -0
- package/dist/adapters/cache.d.ts +96 -0
- package/dist/adapters/cache.js +278 -0
- package/dist/adapters/config/index.d.ts +27 -0
- package/dist/adapters/config/index.js +21 -0
- package/dist/adapters/config/util.d.ts +28 -0
- package/dist/adapters/config/util.js +84 -0
- package/dist/adapters/dynamo-provider.d.ts +8 -0
- package/dist/adapters/dynamo-provider.js +42 -0
- package/dist/adapters/edge-adapter.d.ts +8 -0
- package/dist/adapters/edge-adapter.js +54 -0
- package/dist/adapters/image-optimization-adapter.d.ts +4 -0
- package/dist/adapters/image-optimization-adapter.js +193 -0
- package/dist/adapters/logger.d.ts +13 -0
- package/dist/adapters/logger.js +51 -0
- package/dist/adapters/middleware.d.ts +5 -0
- package/dist/adapters/middleware.js +84 -0
- package/dist/adapters/plugins/14.1/util.d.ts +1 -0
- package/dist/adapters/plugins/14.1/util.js +29 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.d.ts +11 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.js +14 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.replacement.d.ts +11 -0
- package/dist/adapters/plugins/image-optimization/image-optimization.replacement.js +22 -0
- package/dist/adapters/plugins/without-routing/requestHandler.d.ts +2 -0
- package/dist/adapters/plugins/without-routing/requestHandler.js +10 -0
- package/dist/adapters/revalidate.d.ts +9 -0
- package/dist/adapters/revalidate.js +71 -0
- package/dist/adapters/server-adapter.d.ts +4 -0
- package/dist/adapters/server-adapter.js +27 -0
- package/dist/adapters/util.d.ts +10 -0
- package/dist/adapters/util.js +28 -0
- package/dist/adapters/warmer-function.d.ts +12 -0
- package/dist/adapters/warmer-function.js +80 -0
- package/dist/build/bundleNextServer.d.ts +1 -0
- package/dist/build/bundleNextServer.js +87 -0
- package/dist/build/compileConfig.d.ts +3 -0
- package/dist/build/compileConfig.js +64 -0
- package/dist/build/copyTracedFiles.d.ts +1 -0
- package/dist/build/copyTracedFiles.js +207 -0
- package/dist/build/createServerBundle.d.ts +3 -0
- package/dist/build/createServerBundle.js +228 -0
- package/dist/build/edge/createEdgeBundle.d.ts +20 -0
- package/dist/build/edge/createEdgeBundle.js +149 -0
- package/dist/build/generateOutput.d.ts +2 -0
- package/dist/build/generateOutput.js +239 -0
- package/dist/build/helper.d.ts +33 -0
- package/dist/build/helper.js +193 -0
- package/dist/build/patch/patchedAsyncStorage.d.ts +5 -0
- package/dist/build/patch/patchedAsyncStorage.js +16 -0
- package/dist/build/validateConfig.d.ts +2 -0
- package/dist/build/validateConfig.js +76 -0
- package/dist/build.d.ts +7 -0
- package/dist/build.js +533 -0
- package/dist/cache/incremental/s3-lite.d.ts +3 -0
- package/dist/cache/incremental/s3-lite.js +72 -0
- package/dist/cache/incremental/s3.d.ts +3 -0
- package/dist/cache/incremental/s3.js +44 -0
- package/dist/cache/incremental/types.d.ts +34 -0
- package/dist/cache/incremental/types.js +1 -0
- package/dist/cache/next-types.d.ts +62 -0
- package/dist/cache/next-types.js +1 -0
- package/dist/cache/tag/constants.d.ts +2 -0
- package/dist/cache/tag/constants.js +17 -0
- package/dist/cache/tag/dynamodb-lite.d.ts +3 -0
- package/dist/cache/tag/dynamodb-lite.js +174 -0
- package/dist/cache/tag/dynamodb.d.ts +3 -0
- package/dist/cache/tag/dynamodb.js +129 -0
- package/dist/cache/tag/types.d.ts +11 -0
- package/dist/cache/tag/types.js +1 -0
- package/dist/converters/aws-apigw-v1.d.ts +3 -0
- package/dist/converters/aws-apigw-v1.js +89 -0
- package/dist/converters/aws-apigw-v2.d.ts +3 -0
- package/dist/converters/aws-apigw-v2.js +99 -0
- package/dist/converters/aws-cloudfront.d.ts +3 -0
- package/dist/converters/aws-cloudfront.js +170 -0
- package/dist/converters/dummy.d.ts +7 -0
- package/dist/converters/dummy.js +16 -0
- package/dist/converters/edge.d.ts +6 -0
- package/dist/converters/edge.js +88 -0
- package/dist/converters/node.d.ts +3 -0
- package/dist/converters/node.js +45 -0
- package/dist/converters/sqs-revalidate.d.ts +4 -0
- package/dist/converters/sqs-revalidate.js +22 -0
- package/dist/converters/utils.d.ts +1 -0
- package/dist/converters/utils.js +9 -0
- package/dist/core/createGenericHandler.d.ts +11 -0
- package/dist/core/createGenericHandler.js +16 -0
- package/dist/core/createMainHandler.d.ts +18 -0
- package/dist/core/createMainHandler.js +24 -0
- package/dist/core/edgeFunctionHandler.d.ts +54 -0
- package/dist/core/edgeFunctionHandler.js +21 -0
- package/dist/core/patchAsyncStorage.d.ts +1 -0
- package/dist/core/patchAsyncStorage.js +16 -0
- package/dist/core/requestHandler.d.ts +3 -0
- package/dist/core/requestHandler.js +162 -0
- package/dist/core/require-hooks.d.ts +3 -0
- package/dist/core/require-hooks.js +102 -0
- package/dist/core/resolve.d.ts +31 -0
- package/dist/core/resolve.js +81 -0
- package/dist/core/routing/cacheInterceptor.d.ts +2 -0
- package/dist/core/routing/cacheInterceptor.js +162 -0
- package/dist/core/routing/i18n/accept-header.d.ts +1 -0
- package/dist/core/routing/i18n/accept-header.js +101 -0
- package/dist/core/routing/i18n/index.d.ts +2 -0
- package/dist/core/routing/i18n/index.js +36 -0
- package/dist/core/routing/matcher.d.ts +25 -0
- package/dist/core/routing/matcher.js +294 -0
- package/dist/core/routing/middleware.d.ts +7 -0
- package/dist/core/routing/middleware.js +167 -0
- package/dist/core/routing/util.d.ts +105 -0
- package/dist/core/routing/util.js +415 -0
- package/dist/core/routingHandler.d.ts +8 -0
- package/dist/core/routingHandler.js +127 -0
- package/dist/core/util.d.ts +5 -0
- package/dist/core/util.js +84 -0
- package/dist/helpers/withCloudflare.d.ts +65 -0
- package/dist/helpers/withCloudflare.js +58 -0
- package/dist/helpers/withSST.d.ts +54 -0
- package/dist/helpers/withSST.js +28 -0
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +4 -0
- package/dist/http/openNextResponse.d.ts +78 -0
- package/dist/http/openNextResponse.js +281 -0
- package/dist/http/request.d.ts +12 -0
- package/dist/http/request.js +35 -0
- package/dist/http/util.d.ts +4 -0
- package/dist/http/util.js +34 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +13 -0
- package/dist/minimize-js.d.ts +1 -0
- package/dist/minimize-js.js +101 -0
- package/dist/overrides/imageLoader/host.d.ts +3 -0
- package/dist/overrides/imageLoader/host.js +29 -0
- package/dist/overrides/imageLoader/s3.d.ts +3 -0
- package/dist/overrides/imageLoader/s3.js +33 -0
- package/dist/plugins/edge.d.ts +15 -0
- package/dist/plugins/edge.js +157 -0
- package/dist/plugins/replacement.d.ts +42 -0
- package/dist/plugins/replacement.js +74 -0
- package/dist/plugins/resolve.d.ts +18 -0
- package/dist/plugins/resolve.js +45 -0
- package/dist/queue/sqs-lite.d.ts +3 -0
- package/dist/queue/sqs-lite.js +52 -0
- package/dist/queue/sqs.d.ts +3 -0
- package/dist/queue/sqs.js +20 -0
- package/dist/queue/types.d.ts +12 -0
- package/dist/queue/types.js +1 -0
- package/dist/types/aws-lambda.d.ts +22 -0
- package/dist/types/aws-lambda.js +1 -0
- package/dist/types/next-types.d.ts +155 -0
- package/dist/types/next-types.js +2 -0
- package/dist/types/open-next.d.ts +303 -0
- package/dist/types/open-next.js +1 -0
- package/dist/utils/error.d.ts +23 -0
- package/dist/utils/error.js +32 -0
- package/dist/utils/fetch.d.ts +2 -0
- package/dist/utils/fetch.js +23 -0
- package/dist/utils/promise.d.ts +18 -0
- package/dist/utils/promise.js +48 -0
- package/dist/utils/stream.d.ts +5 -0
- package/dist/utils/stream.js +30 -0
- package/dist/wrappers/aws-lambda-streaming.d.ts +7 -0
- package/dist/wrappers/aws-lambda-streaming.js +88 -0
- package/dist/wrappers/aws-lambda.d.ts +7 -0
- package/dist/wrappers/aws-lambda.js +39 -0
- package/dist/wrappers/cloudflare.d.ts +11 -0
- package/dist/wrappers/cloudflare.js +20 -0
- package/dist/wrappers/node.d.ts +7 -0
- package/dist/wrappers/node.js +57 -0
- package/package.json +66 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import { BuildId, HtmlPages } from "../../adapters/config/index.js";
|
|
4
|
+
import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
|
|
5
|
+
import { parseHeaders } from "../../http/util.js";
|
|
6
|
+
import { isBinaryContentType } from "../../adapters/binary.js";
|
|
7
|
+
import { debug, error } from "../../adapters/logger.js";
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @__PURE__
|
|
11
|
+
*/
|
|
12
|
+
export function isExternal(url, host) {
|
|
13
|
+
if (!url)
|
|
14
|
+
return false;
|
|
15
|
+
const pattern = /^https?:\/\//;
|
|
16
|
+
if (host) {
|
|
17
|
+
return pattern.test(url) && !url.includes(host);
|
|
18
|
+
}
|
|
19
|
+
return pattern.test(url);
|
|
20
|
+
}
|
|
21
|
+
export function convertFromQueryString(query) {
|
|
22
|
+
if (query === "")
|
|
23
|
+
return {};
|
|
24
|
+
const queryParts = query.split("&");
|
|
25
|
+
return queryParts.reduce((acc, part) => {
|
|
26
|
+
const [key, value] = part.split("=");
|
|
27
|
+
return { ...acc, [key]: value };
|
|
28
|
+
}, {});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @__PURE__
|
|
33
|
+
*/
|
|
34
|
+
export function getUrlParts(url, isExternal) {
|
|
35
|
+
if (!isExternal) {
|
|
36
|
+
const regex = /\/([^?]*)\??(.*)/;
|
|
37
|
+
const match = url.match(regex);
|
|
38
|
+
return {
|
|
39
|
+
hostname: "",
|
|
40
|
+
pathname: match?.[1] ?? url,
|
|
41
|
+
protocol: "",
|
|
42
|
+
queryString: match?.[2] ?? "",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const regex = /^(https?:)\/\/?([^\/\s]+)(\/[^?]*)?(\?.*)?/;
|
|
46
|
+
const match = url.match(regex);
|
|
47
|
+
if (!match) {
|
|
48
|
+
throw new Error(`Invalid external URL: ${url}`);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
protocol: match[1] ?? "https:",
|
|
52
|
+
hostname: match[2],
|
|
53
|
+
pathname: match[3],
|
|
54
|
+
queryString: match[4]?.slice(1) ?? "",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
*
|
|
59
|
+
* @__PURE__
|
|
60
|
+
*/
|
|
61
|
+
export function convertRes(res) {
|
|
62
|
+
// Format Next.js response to Lambda response
|
|
63
|
+
const statusCode = res.statusCode || 200;
|
|
64
|
+
// When using HEAD requests, it seems that flushHeaders is not called, not sure why
|
|
65
|
+
// Probably some kind of race condition
|
|
66
|
+
const headers = parseHeaders(res.getFixedHeaders());
|
|
67
|
+
const isBase64Encoded = isBinaryContentType(headers["content-type"]) ||
|
|
68
|
+
!!headers["content-encoding"];
|
|
69
|
+
// We cannot convert the OpenNextNodeResponse to a ReadableStream directly
|
|
70
|
+
// You can look in the `aws-lambda.ts` file for some context
|
|
71
|
+
const body = Readable.toWeb(Readable.from(res.getBody()));
|
|
72
|
+
return {
|
|
73
|
+
type: "core",
|
|
74
|
+
statusCode,
|
|
75
|
+
headers,
|
|
76
|
+
body,
|
|
77
|
+
isBase64Encoded,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Make sure that multi-value query parameters are transformed to
|
|
82
|
+
* ?key=value1&key=value2&... so that Next converts those parameters
|
|
83
|
+
* to an array when reading the query parameters
|
|
84
|
+
* @__PURE__
|
|
85
|
+
*/
|
|
86
|
+
export function convertToQueryString(query) {
|
|
87
|
+
const urlQuery = new URLSearchParams();
|
|
88
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
value.forEach((entry) => urlQuery.append(key, entry));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
urlQuery.append(key, value);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const queryString = urlQuery.toString();
|
|
97
|
+
return queryString ? `?${queryString}` : "";
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Given a raw query string, returns a record with key value-array pairs
|
|
101
|
+
* similar to how multiValueQueryStringParameters are structured
|
|
102
|
+
* @__PURE__
|
|
103
|
+
*/
|
|
104
|
+
export function convertToQuery(querystring) {
|
|
105
|
+
const query = new URLSearchParams(querystring);
|
|
106
|
+
const queryObject = {};
|
|
107
|
+
for (const key of query.keys()) {
|
|
108
|
+
const queries = query.getAll(key);
|
|
109
|
+
queryObject[key] = queries.length > 1 ? queries : queries[0];
|
|
110
|
+
}
|
|
111
|
+
return queryObject;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
*
|
|
115
|
+
* @__PURE__
|
|
116
|
+
*/
|
|
117
|
+
export function getMiddlewareMatch(middlewareManifest) {
|
|
118
|
+
const rootMiddleware = middlewareManifest.middleware["/"];
|
|
119
|
+
if (!rootMiddleware?.matchers)
|
|
120
|
+
return [];
|
|
121
|
+
return rootMiddleware.matchers.map(({ regexp }) => new RegExp(regexp));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
*
|
|
125
|
+
* @__PURE__
|
|
126
|
+
*/
|
|
127
|
+
export function escapeRegex(str) {
|
|
128
|
+
let path = str.replace(/\(\.\)/g, "_µ1_");
|
|
129
|
+
path = path.replace(/\(\.{2}\)/g, "_µ2_");
|
|
130
|
+
path = path.replace(/\(\.{3}\)/g, "_µ3_");
|
|
131
|
+
return path;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
*
|
|
135
|
+
* @__PURE__
|
|
136
|
+
*/
|
|
137
|
+
export function unescapeRegex(str) {
|
|
138
|
+
let path = str.replace(/_µ1_/g, "(.)");
|
|
139
|
+
path = path.replace(/_µ2_/g, "(..)");
|
|
140
|
+
path = path.replace(/_µ3_/g, "(...)");
|
|
141
|
+
return path;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
*
|
|
145
|
+
* @__PURE__
|
|
146
|
+
*/
|
|
147
|
+
function filterHeadersForProxy(headers) {
|
|
148
|
+
const filteredHeaders = {};
|
|
149
|
+
const disallowedHeaders = [
|
|
150
|
+
"host",
|
|
151
|
+
"connection",
|
|
152
|
+
"via",
|
|
153
|
+
"x-cache",
|
|
154
|
+
"transfer-encoding",
|
|
155
|
+
"content-encoding",
|
|
156
|
+
"content-length",
|
|
157
|
+
];
|
|
158
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
159
|
+
const lowerKey = key.toLowerCase();
|
|
160
|
+
if (disallowedHeaders.includes(lowerKey) || lowerKey.startsWith("x-amz"))
|
|
161
|
+
return;
|
|
162
|
+
else {
|
|
163
|
+
filteredHeaders[key] = value?.toString() ?? "";
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return filteredHeaders;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* @__PURE__
|
|
170
|
+
*/
|
|
171
|
+
export function convertBodyToReadableStream(method, body) {
|
|
172
|
+
if (method === "GET" || method === "HEAD")
|
|
173
|
+
return undefined;
|
|
174
|
+
if (!body)
|
|
175
|
+
return undefined;
|
|
176
|
+
const readable = new ReadableStream({
|
|
177
|
+
start(controller) {
|
|
178
|
+
controller.enqueue(body);
|
|
179
|
+
controller.close();
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
return readable;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
*
|
|
186
|
+
* @__PURE__
|
|
187
|
+
*/
|
|
188
|
+
export async function proxyRequest(internalEvent, res) {
|
|
189
|
+
const { url, headers, method, body } = internalEvent;
|
|
190
|
+
const request = await import("node:https").then((m) => m.request);
|
|
191
|
+
debug("proxyRequest", url);
|
|
192
|
+
await new Promise((resolve, reject) => {
|
|
193
|
+
const filteredHeaders = filterHeadersForProxy(headers);
|
|
194
|
+
debug("filteredHeaders", filteredHeaders);
|
|
195
|
+
const req = request(url, {
|
|
196
|
+
headers: filteredHeaders,
|
|
197
|
+
method,
|
|
198
|
+
rejectUnauthorized: false,
|
|
199
|
+
}, (_res) => {
|
|
200
|
+
res.writeHead(_res.statusCode ?? 200, filterHeadersForProxy(_res.headers));
|
|
201
|
+
if (_res.headers["content-encoding"] === "br") {
|
|
202
|
+
_res.pipe(require("node:zlib").createBrotliDecompress()).pipe(res);
|
|
203
|
+
}
|
|
204
|
+
else if (_res.headers["content-encoding"] === "gzip") {
|
|
205
|
+
_res.pipe(require("node:zlib").createGunzip()).pipe(res);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
_res.pipe(res);
|
|
209
|
+
}
|
|
210
|
+
_res.on("error", (e) => {
|
|
211
|
+
error("proxyRequest error", e);
|
|
212
|
+
res.end();
|
|
213
|
+
reject(e);
|
|
214
|
+
});
|
|
215
|
+
_res.on("end", () => {
|
|
216
|
+
resolve();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
if (body && method !== "GET" && method !== "HEAD") {
|
|
220
|
+
req.write(body);
|
|
221
|
+
}
|
|
222
|
+
req.end();
|
|
223
|
+
});
|
|
224
|
+
// console.log("result", result);
|
|
225
|
+
// res.writeHead(result.status, resHeaders);
|
|
226
|
+
// res.end(await result.text());
|
|
227
|
+
}
|
|
228
|
+
var CommonHeaders;
|
|
229
|
+
(function (CommonHeaders) {
|
|
230
|
+
CommonHeaders["CACHE_CONTROL"] = "cache-control";
|
|
231
|
+
CommonHeaders["NEXT_CACHE"] = "x-nextjs-cache";
|
|
232
|
+
})(CommonHeaders || (CommonHeaders = {}));
|
|
233
|
+
/**
|
|
234
|
+
*
|
|
235
|
+
* @__PURE__
|
|
236
|
+
*/
|
|
237
|
+
export function fixCacheHeaderForHtmlPages(rawPath, headers) {
|
|
238
|
+
// We don't want to cache error pages
|
|
239
|
+
if (rawPath === "/404" || rawPath === "/500") {
|
|
240
|
+
headers[CommonHeaders.CACHE_CONTROL] =
|
|
241
|
+
"private, no-cache, no-store, max-age=0, must-revalidate";
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// WORKAROUND: `NextServer` does not set cache headers for HTML pages — https://github.com/serverless-stack/open-next#workaround-nextserver-does-not-set-cache-headers-for-html-pages
|
|
245
|
+
if (HtmlPages.includes(rawPath)) {
|
|
246
|
+
headers[CommonHeaders.CACHE_CONTROL] =
|
|
247
|
+
"public, max-age=0, s-maxage=31536000, must-revalidate";
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
*
|
|
252
|
+
* @__PURE__
|
|
253
|
+
*/
|
|
254
|
+
export function fixSWRCacheHeader(headers) {
|
|
255
|
+
// WORKAROUND: `NextServer` does not set correct SWR cache headers — https://github.com/sst/open-next#workaround-nextserver-does-not-set-correct-swr-cache-headers
|
|
256
|
+
let cacheControl = headers[CommonHeaders.CACHE_CONTROL];
|
|
257
|
+
if (!cacheControl)
|
|
258
|
+
return;
|
|
259
|
+
if (Array.isArray(cacheControl)) {
|
|
260
|
+
cacheControl = cacheControl.join(",");
|
|
261
|
+
}
|
|
262
|
+
if (typeof cacheControl !== "string")
|
|
263
|
+
return;
|
|
264
|
+
headers[CommonHeaders.CACHE_CONTROL] = cacheControl.replace(/\bstale-while-revalidate(?!=)/, "stale-while-revalidate=2592000");
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
*
|
|
268
|
+
* @__PURE__
|
|
269
|
+
*/
|
|
270
|
+
export function addOpenNextHeader(headers) {
|
|
271
|
+
headers["X-OpenNext"] = "1";
|
|
272
|
+
if (globalThis.openNextDebug) {
|
|
273
|
+
headers["X-OpenNext-Version"] = globalThis.openNextVersion;
|
|
274
|
+
headers["X-OpenNext-RequestId"] = globalThis.__als.getStore()?.requestId;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
*
|
|
279
|
+
* @__PURE__
|
|
280
|
+
*/
|
|
281
|
+
export async function revalidateIfRequired(host, rawPath, headers, req) {
|
|
282
|
+
if (headers[CommonHeaders.NEXT_CACHE] === "STALE") {
|
|
283
|
+
// If the URL is rewritten, revalidation needs to be done on the rewritten URL.
|
|
284
|
+
// - Link to Next.js doc: https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration#on-demand-revalidation
|
|
285
|
+
// - Link to NextInternalRequestMeta: https://github.com/vercel/next.js/blob/57ab2818b93627e91c937a130fb56a36c41629c3/packages/next/src/server/request-meta.ts#L11
|
|
286
|
+
// @ts-ignore
|
|
287
|
+
const internalMeta = req?.[Symbol.for("NextInternalRequestMeta")];
|
|
288
|
+
// When using Pages Router, two requests will be received:
|
|
289
|
+
// 1. one for the page: /foo
|
|
290
|
+
// 2. one for the json data: /_next/data/BUILD_ID/foo.json
|
|
291
|
+
// The rewritten url is correct for 1, but that for the second request
|
|
292
|
+
// does not include the "/_next/data/" prefix. Need to add it.
|
|
293
|
+
const revalidateUrl = internalMeta?._nextDidRewrite
|
|
294
|
+
? rawPath.startsWith("/_next/data/")
|
|
295
|
+
? `/_next/data/${BuildId}${internalMeta?._nextRewroteUrl}.json`
|
|
296
|
+
: internalMeta?._nextRewroteUrl
|
|
297
|
+
: rawPath;
|
|
298
|
+
// We need to pass etag to the revalidation queue to try to bypass the default 5 min deduplication window.
|
|
299
|
+
// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagededuplicationid-property.html
|
|
300
|
+
// If you need to have a revalidation happen more frequently than 5 minutes,
|
|
301
|
+
// your page will need to have a different etag to bypass the deduplication window.
|
|
302
|
+
// If data has the same etag during these 5 min dedup window, it will be deduplicated and not revalidated.
|
|
303
|
+
try {
|
|
304
|
+
const hash = (str) => crypto.createHash("md5").update(str).digest("hex");
|
|
305
|
+
const requestId = globalThis.__als.getStore()?.requestId ?? "";
|
|
306
|
+
const lastModified = globalThis.lastModified[requestId] > 0
|
|
307
|
+
? globalThis.lastModified[requestId]
|
|
308
|
+
: "";
|
|
309
|
+
// For some weird cases, lastModified is not set, haven't been able to figure out yet why
|
|
310
|
+
// For those cases we add the etag to the deduplication id, it might help
|
|
311
|
+
const etag = headers["etag"] ?? headers["ETag"] ?? "";
|
|
312
|
+
await globalThis.queue.send({
|
|
313
|
+
MessageBody: { host, url: revalidateUrl },
|
|
314
|
+
MessageDeduplicationId: hash(`${rawPath}-${lastModified}-${etag}`),
|
|
315
|
+
MessageGroupId: generateMessageGroupId(rawPath),
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
catch (e) {
|
|
319
|
+
error(`Failed to revalidate stale page ${rawPath}`, e);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Since we're using a FIFO queue, every messageGroupId is treated sequentially
|
|
324
|
+
// This could cause a backlog of messages in the queue if there is too much page to
|
|
325
|
+
// revalidate at once. To avoid this, we generate a random messageGroupId for each
|
|
326
|
+
// revalidation request.
|
|
327
|
+
// We can't just use a random string because we need to ensure that the same rawPath
|
|
328
|
+
// will always have the same messageGroupId.
|
|
329
|
+
// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript#answer-47593316
|
|
330
|
+
export function generateMessageGroupId(rawPath) {
|
|
331
|
+
let a = cyrb128(rawPath);
|
|
332
|
+
// We use mulberry32 to generate a random int between 0 and MAX_REVALIDATE_CONCURRENCY
|
|
333
|
+
var t = (a += 0x6d2b79f5);
|
|
334
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
335
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
336
|
+
const randomFloat = ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
337
|
+
// This will generate a random int between 0 and MAX_REVALIDATE_CONCURRENCY
|
|
338
|
+
// This means that we could have 1000 revalidate request at the same time
|
|
339
|
+
const maxConcurrency = parseInt(process.env.MAX_REVALIDATE_CONCURRENCY ?? "10");
|
|
340
|
+
const randomInt = Math.floor(randomFloat * maxConcurrency);
|
|
341
|
+
return `revalidate-${randomInt}`;
|
|
342
|
+
}
|
|
343
|
+
// Used to generate a hash int from a string
|
|
344
|
+
function cyrb128(str) {
|
|
345
|
+
let h1 = 1779033703, h2 = 3144134277, h3 = 1013904242, h4 = 2773480762;
|
|
346
|
+
for (let i = 0, k; i < str.length; i++) {
|
|
347
|
+
k = str.charCodeAt(i);
|
|
348
|
+
h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
|
|
349
|
+
h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
|
|
350
|
+
h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
|
|
351
|
+
h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
|
|
352
|
+
}
|
|
353
|
+
h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);
|
|
354
|
+
h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);
|
|
355
|
+
h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);
|
|
356
|
+
h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);
|
|
357
|
+
(h1 ^= h2 ^ h3 ^ h4), (h2 ^= h1), (h3 ^= h1), (h4 ^= h1);
|
|
358
|
+
return h1 >>> 0;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
*
|
|
362
|
+
* @__PURE__
|
|
363
|
+
*/
|
|
364
|
+
export function fixISRHeaders(headers) {
|
|
365
|
+
if (headers[CommonHeaders.NEXT_CACHE] === "REVALIDATED") {
|
|
366
|
+
headers[CommonHeaders.CACHE_CONTROL] =
|
|
367
|
+
"private, no-cache, no-store, max-age=0, must-revalidate";
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const requestId = globalThis.__als.getStore()?.requestId ?? "";
|
|
371
|
+
const _lastModified = globalThis.lastModified[requestId] ?? 0;
|
|
372
|
+
if (headers[CommonHeaders.NEXT_CACHE] === "HIT" && _lastModified > 0) {
|
|
373
|
+
// calculate age
|
|
374
|
+
const age = Math.round((Date.now() - _lastModified) / 1000);
|
|
375
|
+
// extract s-maxage from cache-control
|
|
376
|
+
const regex = /s-maxage=(\d+)/;
|
|
377
|
+
const cacheControl = headers[CommonHeaders.CACHE_CONTROL];
|
|
378
|
+
debug("cache-control", cacheControl, globalThis.lastModified, Date.now());
|
|
379
|
+
if (typeof cacheControl !== "string")
|
|
380
|
+
return;
|
|
381
|
+
const match = cacheControl.match(regex);
|
|
382
|
+
const sMaxAge = match ? parseInt(match[1]) : undefined;
|
|
383
|
+
// 31536000 is the default s-maxage value for SSG pages
|
|
384
|
+
if (sMaxAge && sMaxAge !== 31536000) {
|
|
385
|
+
const remainingTtl = Math.max(sMaxAge - age, 1);
|
|
386
|
+
headers[CommonHeaders.CACHE_CONTROL] = `s-maxage=${remainingTtl}, stale-while-revalidate=2592000`;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (headers[CommonHeaders.NEXT_CACHE] !== "STALE")
|
|
390
|
+
return;
|
|
391
|
+
// If the cache is stale, we revalidate in the background
|
|
392
|
+
// In order for CloudFront SWR to work, we set the stale-while-revalidate value to 2 seconds
|
|
393
|
+
// This will cause CloudFront to cache the stale data for a short period of time while we revalidate in the background
|
|
394
|
+
// Once the revalidation is complete, CloudFront will serve the fresh data
|
|
395
|
+
headers[CommonHeaders.CACHE_CONTROL] =
|
|
396
|
+
"s-maxage=2, stale-while-revalidate=2592000";
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
*
|
|
400
|
+
* @param internalEvent
|
|
401
|
+
* @param headers
|
|
402
|
+
* @param responseStream
|
|
403
|
+
* @returns
|
|
404
|
+
* @__PURE__
|
|
405
|
+
*/
|
|
406
|
+
export function createServerResponse(internalEvent, headers, responseStream) {
|
|
407
|
+
return new OpenNextNodeResponse((_headers) => {
|
|
408
|
+
fixCacheHeaderForHtmlPages(internalEvent.rawPath, _headers);
|
|
409
|
+
fixSWRCacheHeader(_headers);
|
|
410
|
+
addOpenNextHeader(_headers);
|
|
411
|
+
fixISRHeaders(_headers);
|
|
412
|
+
}, async (_headers) => {
|
|
413
|
+
await revalidateIfRequired(internalEvent.headers.host, internalEvent.rawPath, _headers);
|
|
414
|
+
}, responseStream, headers);
|
|
415
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { InternalEvent, InternalResult, Origin } from "../types/open-next";
|
|
2
|
+
export interface MiddlewareOutputEvent {
|
|
3
|
+
internalEvent: InternalEvent;
|
|
4
|
+
isExternalRewrite: boolean;
|
|
5
|
+
origin: Origin | false;
|
|
6
|
+
isISR: boolean;
|
|
7
|
+
}
|
|
8
|
+
export default function routingHandler(event: InternalEvent): Promise<InternalResult | MiddlewareOutputEvent>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { BuildId, ConfigHeaders, PrerenderManifest, RoutesManifest, } from "../adapters/config/index";
|
|
2
|
+
import { debug } from "../adapters/logger";
|
|
3
|
+
import { cacheInterceptor } from "./routing/cacheInterceptor";
|
|
4
|
+
import { addNextConfigHeaders, fixDataPage, handleFallbackFalse, handleRedirects, handleRewrites, } from "./routing/matcher";
|
|
5
|
+
import { handleMiddleware } from "./routing/middleware";
|
|
6
|
+
// Add the locale prefix to the regex so we correctly match the rawPath
|
|
7
|
+
const optionalLocalePrefixRegex = !!RoutesManifest.locales.length
|
|
8
|
+
? `^/(?:${RoutesManifest.locales.map((locale) => `${locale}/?`).join("|")})?`
|
|
9
|
+
: "^/";
|
|
10
|
+
// Add the basepath prefix to the regex so we correctly match the rawPath
|
|
11
|
+
const optionalBasepathPrefixRegex = !!RoutesManifest.basePath
|
|
12
|
+
? `^${RoutesManifest.basePath}/?`
|
|
13
|
+
: "^/";
|
|
14
|
+
// Add the basePath prefix to the api routes
|
|
15
|
+
const apiPrefix = !!RoutesManifest.basePath
|
|
16
|
+
? `${RoutesManifest.basePath}/api`
|
|
17
|
+
: "/api";
|
|
18
|
+
const staticRegexp = RoutesManifest.routes.static.map((route) => new RegExp(route.regex
|
|
19
|
+
.replace("^/", optionalLocalePrefixRegex)
|
|
20
|
+
.replace("^/", optionalBasepathPrefixRegex)));
|
|
21
|
+
const dynamicRegexp = RoutesManifest.routes.dynamic.map((route) => new RegExp(route.regex
|
|
22
|
+
.replace("^/", optionalLocalePrefixRegex)
|
|
23
|
+
.replace("^/", optionalBasepathPrefixRegex)));
|
|
24
|
+
function applyMiddlewareHeaders(eventHeaders, middlewareHeaders, setPrefix = true) {
|
|
25
|
+
Object.entries(middlewareHeaders).forEach(([key, value]) => {
|
|
26
|
+
if (value) {
|
|
27
|
+
eventHeaders[`${setPrefix ? "x-middleware-response-" : ""}${key}`] =
|
|
28
|
+
Array.isArray(value) ? value.join(",") : value;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export default async function routingHandler(event) {
|
|
33
|
+
const nextHeaders = addNextConfigHeaders(event, ConfigHeaders) ?? {};
|
|
34
|
+
let internalEvent = fixDataPage(event, BuildId);
|
|
35
|
+
if ("statusCode" in internalEvent) {
|
|
36
|
+
return internalEvent;
|
|
37
|
+
}
|
|
38
|
+
const redirect = handleRedirects(internalEvent, RoutesManifest.redirects);
|
|
39
|
+
if (redirect) {
|
|
40
|
+
debug("redirect", redirect);
|
|
41
|
+
return redirect;
|
|
42
|
+
}
|
|
43
|
+
const middleware = await handleMiddleware(internalEvent);
|
|
44
|
+
let middlewareResponseHeaders = {};
|
|
45
|
+
if ("statusCode" in middleware) {
|
|
46
|
+
return middleware;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
middlewareResponseHeaders = middleware.responseHeaders || {};
|
|
50
|
+
internalEvent = middleware;
|
|
51
|
+
}
|
|
52
|
+
// At this point internalEvent is an InternalEvent or a MiddlewareOutputEvent
|
|
53
|
+
let isExternalRewrite = middleware.externalRewrite ?? false;
|
|
54
|
+
if (!isExternalRewrite) {
|
|
55
|
+
// First rewrite to be applied
|
|
56
|
+
const beforeRewrites = handleRewrites(internalEvent, RoutesManifest.rewrites.beforeFiles);
|
|
57
|
+
internalEvent = beforeRewrites.internalEvent;
|
|
58
|
+
isExternalRewrite = beforeRewrites.isExternalRewrite;
|
|
59
|
+
}
|
|
60
|
+
const isStaticRoute = !isExternalRewrite &&
|
|
61
|
+
staticRegexp.some((route) => route.test(internalEvent.rawPath));
|
|
62
|
+
if (!isStaticRoute && !isExternalRewrite) {
|
|
63
|
+
// Second rewrite to be applied
|
|
64
|
+
const afterRewrites = handleRewrites(internalEvent, RoutesManifest.rewrites.afterFiles);
|
|
65
|
+
internalEvent = afterRewrites.internalEvent;
|
|
66
|
+
isExternalRewrite = afterRewrites.isExternalRewrite;
|
|
67
|
+
}
|
|
68
|
+
// We want to run this just before the dynamic route check
|
|
69
|
+
const { event: fallbackEvent, isISR } = handleFallbackFalse(internalEvent, PrerenderManifest);
|
|
70
|
+
internalEvent = fallbackEvent;
|
|
71
|
+
const isDynamicRoute = !isExternalRewrite &&
|
|
72
|
+
dynamicRegexp.some((route) => route.test(internalEvent.rawPath));
|
|
73
|
+
if (!isDynamicRoute && !isStaticRoute && !isExternalRewrite) {
|
|
74
|
+
// Fallback rewrite to be applied
|
|
75
|
+
const fallbackRewrites = handleRewrites(internalEvent, RoutesManifest.rewrites.fallback);
|
|
76
|
+
internalEvent = fallbackRewrites.internalEvent;
|
|
77
|
+
isExternalRewrite = fallbackRewrites.isExternalRewrite;
|
|
78
|
+
}
|
|
79
|
+
// Api routes are not present in the routes manifest except if they're not behind /api
|
|
80
|
+
// /api even if it's a page route doesn't get generated in the manifest
|
|
81
|
+
// Ideally we would need to properly check api routes here
|
|
82
|
+
const isApiRoute = internalEvent.rawPath === apiPrefix ||
|
|
83
|
+
internalEvent.rawPath.startsWith(`${apiPrefix}/`);
|
|
84
|
+
const isNextImageRoute = internalEvent.rawPath.startsWith("/_next/image");
|
|
85
|
+
const isRouteFoundBeforeAllRewrites = isStaticRoute || isDynamicRoute || isExternalRewrite;
|
|
86
|
+
// If we still haven't found a route, we show the 404 page
|
|
87
|
+
// We need to ensure that rewrites are applied before showing the 404 page
|
|
88
|
+
if (!isRouteFoundBeforeAllRewrites &&
|
|
89
|
+
!isApiRoute &&
|
|
90
|
+
!isNextImageRoute &&
|
|
91
|
+
// We need to check again once all rewrites have been applied
|
|
92
|
+
!staticRegexp.some((route) => route.test(internalEvent.rawPath)) &&
|
|
93
|
+
!dynamicRegexp.some((route) => route.test(internalEvent.rawPath))) {
|
|
94
|
+
internalEvent = {
|
|
95
|
+
...internalEvent,
|
|
96
|
+
rawPath: "/404",
|
|
97
|
+
url: "/404",
|
|
98
|
+
headers: {
|
|
99
|
+
...internalEvent.headers,
|
|
100
|
+
"x-middleware-response-cache-control": "private, no-cache, no-store, max-age=0, must-revalidate",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (globalThis.openNextConfig.dangerous?.enableCacheInterception &&
|
|
105
|
+
!("statusCode" in internalEvent)) {
|
|
106
|
+
debug("Cache interception enabled");
|
|
107
|
+
internalEvent = await cacheInterceptor(internalEvent);
|
|
108
|
+
if ("statusCode" in internalEvent) {
|
|
109
|
+
applyMiddlewareHeaders(internalEvent.headers, {
|
|
110
|
+
...middlewareResponseHeaders,
|
|
111
|
+
...nextHeaders,
|
|
112
|
+
}, false);
|
|
113
|
+
return internalEvent;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// We apply the headers from the middleware response last
|
|
117
|
+
applyMiddlewareHeaders(internalEvent.headers, {
|
|
118
|
+
...middlewareResponseHeaders,
|
|
119
|
+
...nextHeaders,
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
internalEvent,
|
|
123
|
+
isExternalRewrite,
|
|
124
|
+
origin: false,
|
|
125
|
+
isISR,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { MiddlewareManifest } from "../types/next-types.js";
|
|
2
|
+
export declare const requestHandler: any;
|
|
3
|
+
export declare function getMiddlewareMatch(middlewareManifest: MiddlewareManifest): RegExp[];
|
|
4
|
+
export declare function loadMiddlewareManifest(nextDir: string): MiddlewareManifest;
|
|
5
|
+
export declare function setNextjsPrebundledReact(rawPath: string): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { AppPathsManifestKeys, NextConfig, RoutesManifest, } from "../adapters/config/index.js";
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import NextServer from "next/dist/server/next-server.js";
|
|
6
|
+
import { debug } from "../adapters/logger.js";
|
|
7
|
+
import { applyOverride as applyNextjsRequireHooksOverride, overrideHooks as overrideNextjsRequireHooks, } from "./require-hooks.js";
|
|
8
|
+
// WORKAROUND: Set `__NEXT_PRIVATE_PREBUNDLED_REACT` to use prebundled React — https://github.com/serverless-stack/open-next#workaround-set-__next_private_prebundled_react-to-use-prebundled-react
|
|
9
|
+
// Step 1: Need to override the require hooks for React before Next.js server
|
|
10
|
+
// overrides them with prebundled ones in the case of app dir
|
|
11
|
+
// Step 2: Import Next.js server
|
|
12
|
+
// Step 3: Apply the override after Next.js server is imported since the
|
|
13
|
+
// override that Next.js does is done at import time
|
|
14
|
+
//#override requireHooks
|
|
15
|
+
overrideNextjsRequireHooks(NextConfig);
|
|
16
|
+
applyNextjsRequireHooksOverride();
|
|
17
|
+
//#endOverride
|
|
18
|
+
const cacheHandlerPath = require.resolve("./cache.cjs");
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
export const requestHandler = new NextServer.default({
|
|
21
|
+
//#override requestHandlerHost
|
|
22
|
+
hostname: "localhost",
|
|
23
|
+
port: 3000,
|
|
24
|
+
//#endOverride
|
|
25
|
+
conf: {
|
|
26
|
+
...NextConfig,
|
|
27
|
+
// Next.js compression should be disabled because of a bug in the bundled
|
|
28
|
+
// `compression` package — https://github.com/vercel/next.js/issues/11669
|
|
29
|
+
compress: false,
|
|
30
|
+
// By default, Next.js uses local disk to store ISR cache. We will use
|
|
31
|
+
// our own cache handler to store the cache on S3.
|
|
32
|
+
//#override stableIncrementalCache
|
|
33
|
+
cacheHandler: cacheHandlerPath,
|
|
34
|
+
cacheMaxMemorySize: 0,
|
|
35
|
+
//#endOverride
|
|
36
|
+
experimental: {
|
|
37
|
+
...NextConfig.experimental,
|
|
38
|
+
// This uses the request.headers.host as the URL
|
|
39
|
+
// https://github.com/vercel/next.js/blob/canary/packages/next/src/server/next-server.ts#L1749-L1754
|
|
40
|
+
//#override trustHostHeader
|
|
41
|
+
trustHostHeader: true,
|
|
42
|
+
//#endOverride
|
|
43
|
+
//#override experimentalIncrementalCacheHandler
|
|
44
|
+
incrementalCacheHandlerPath: cacheHandlerPath,
|
|
45
|
+
//#endOverride
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
customServer: false,
|
|
49
|
+
dev: false,
|
|
50
|
+
dir: __dirname,
|
|
51
|
+
}).getRequestHandler();
|
|
52
|
+
export function getMiddlewareMatch(middlewareManifest) {
|
|
53
|
+
const rootMiddleware = middlewareManifest.middleware["/"];
|
|
54
|
+
if (!rootMiddleware?.matchers)
|
|
55
|
+
return [];
|
|
56
|
+
return rootMiddleware.matchers.map(({ regexp }) => new RegExp(regexp));
|
|
57
|
+
}
|
|
58
|
+
export function loadMiddlewareManifest(nextDir) {
|
|
59
|
+
const filePath = path.join(nextDir, "server", "middleware-manifest.json");
|
|
60
|
+
const json = fs.readFileSync(filePath, "utf-8");
|
|
61
|
+
return JSON.parse(json);
|
|
62
|
+
}
|
|
63
|
+
//#override setNextjsPrebundledReact
|
|
64
|
+
export function setNextjsPrebundledReact(rawPath) {
|
|
65
|
+
// WORKAROUND: Set `__NEXT_PRIVATE_PREBUNDLED_REACT` to use prebundled React — https://github.com/serverless-stack/open-next#workaround-set-__next_private_prebundled_react-to-use-prebundled-react
|
|
66
|
+
const routes = [
|
|
67
|
+
...RoutesManifest.routes.static,
|
|
68
|
+
...RoutesManifest.routes.dynamic,
|
|
69
|
+
];
|
|
70
|
+
const route = routes.find((route) => new RegExp(route.regex).test(rawPath ?? ""));
|
|
71
|
+
const isApp = AppPathsManifestKeys.includes(route?.page ?? "");
|
|
72
|
+
debug("setNextjsPrebundledReact", { url: rawPath, isApp, route });
|
|
73
|
+
// app routes => use prebundled React
|
|
74
|
+
if (isApp) {
|
|
75
|
+
process.env.__NEXT_PRIVATE_PREBUNDLED_REACT = NextConfig.experimental
|
|
76
|
+
.serverActions
|
|
77
|
+
? "experimental"
|
|
78
|
+
: "next";
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// page routes => use node_modules React
|
|
82
|
+
process.env.__NEXT_PRIVATE_PREBUNDLED_REACT = undefined;
|
|
83
|
+
}
|
|
84
|
+
//#endOverride
|