@opennextjs/aws 3.6.5 → 3.7.0
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 +1 -1
- package/dist/adapters/cache.js +4 -4
- package/dist/adapters/composable-cache.js +14 -4
- package/dist/adapters/edge-adapter.js +5 -1
- package/dist/adapters/middleware.js +18 -8
- package/dist/build/copyTracedFiles.js +10 -5
- package/dist/build/createAssets.js +55 -51
- package/dist/build/createServerBundle.js +0 -1
- package/dist/build/patch/patches/index.d.ts +0 -1
- package/dist/build/patch/patches/index.js +0 -1
- package/dist/build/patch/patches/patchNextServer.d.ts +13 -3
- package/dist/build/patch/patches/patchNextServer.js +82 -44
- package/dist/core/createMainHandler.js +4 -1
- package/dist/core/requestHandler.js +11 -2
- package/dist/core/resolve.d.ts +5 -0
- package/dist/core/resolve.js +11 -0
- package/dist/core/routing/cacheInterceptor.js +13 -1
- package/dist/core/routing/matcher.d.ts +5 -0
- package/dist/core/routing/matcher.js +9 -3
- package/dist/core/routing/util.js +2 -0
- package/dist/core/routingHandler.d.ts +5 -1
- package/dist/core/routingHandler.js +75 -52
- package/dist/overrides/assetResolver/dummy.d.ts +8 -0
- package/dist/overrides/assetResolver/dummy.js +9 -0
- package/dist/overrides/converters/edge.js +7 -1
- package/dist/types/global.d.ts +9 -1
- package/dist/types/next-types.d.ts +2 -0
- package/dist/types/open-next.d.ts +8 -1
- package/dist/types/overrides.d.ts +19 -5
- package/dist/utils/cache.d.ts +2 -1
- package/dist/utils/cache.js +32 -0
- package/dist/utils/promise.d.ts +2 -1
- package/dist/utils/promise.js +3 -2
- package/package.json +1 -1
- package/dist/build/patch/patches/dropBabel.d.ts +0 -20
- package/dist/build/patch/patches/dropBabel.js +0 -72
package/dist/core/resolve.d.ts
CHANGED
|
@@ -35,6 +35,11 @@ export declare function resolveImageLoader(imageLoader: RemoveUndefined<OpenNext
|
|
|
35
35
|
* @__PURE__
|
|
36
36
|
*/
|
|
37
37
|
export declare function resolveOriginResolver(originResolver: RemoveUndefined<OpenNextConfig["middleware"]>["originResolver"]): Promise<import("../types/overrides").OriginResolver>;
|
|
38
|
+
/**
|
|
39
|
+
* @returns
|
|
40
|
+
* @__PURE__
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveAssetResolver(assetResolver: RemoveUndefined<OpenNextConfig["middleware"]>["assetResolver"]): Promise<import("../types/overrides").AssetResolver>;
|
|
38
43
|
/**
|
|
39
44
|
* @__PURE__
|
|
40
45
|
*/
|
package/dist/core/resolve.js
CHANGED
|
@@ -78,6 +78,17 @@ export async function resolveOriginResolver(originResolver) {
|
|
|
78
78
|
const m_1 = await import("../overrides/originResolver/pattern-env.js");
|
|
79
79
|
return m_1.default;
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* @returns
|
|
83
|
+
* @__PURE__
|
|
84
|
+
*/
|
|
85
|
+
export async function resolveAssetResolver(assetResolver) {
|
|
86
|
+
if (typeof assetResolver === "function") {
|
|
87
|
+
return assetResolver();
|
|
88
|
+
}
|
|
89
|
+
const m_1 = await import("../overrides/assetResolver/dummy.js");
|
|
90
|
+
return m_1.default;
|
|
91
|
+
}
|
|
81
92
|
/**
|
|
82
93
|
* @__PURE__
|
|
83
94
|
*/
|
|
@@ -7,6 +7,16 @@ import { localizePath } from "./i18n";
|
|
|
7
7
|
import { generateMessageGroupId } from "./queue";
|
|
8
8
|
const CACHE_ONE_YEAR = 60 * 60 * 24 * 365;
|
|
9
9
|
const CACHE_ONE_MONTH = 60 * 60 * 24 * 30;
|
|
10
|
+
/*
|
|
11
|
+
* We use this header to prevent Firefox (and possibly some CDNs) from incorrectly reusing the RSC responses during caching.
|
|
12
|
+
* This can especially happen when there's a redirect in the middleware as the `_rsc` query parameter is not visible there.
|
|
13
|
+
* So it will get dropped during the redirect, which results in the RSC response being cached instead of the actual HTML on the path `/`.
|
|
14
|
+
* This value can be found in the routes manifest, under `rsc.varyHeader`.
|
|
15
|
+
* They recompute it here in Next:
|
|
16
|
+
* https://github.com/vercel/next.js/blob/c5bf5bb4c8b01b1befbbfa7ad97a97476ee9d0d7/packages/next/src/server/base-server.ts#L2011
|
|
17
|
+
* Also see this PR: https://github.com/vercel/next.js/pull/79426
|
|
18
|
+
*/
|
|
19
|
+
const VARY_HEADER = "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Next-Url";
|
|
10
20
|
async function computeCacheControl(path, body, host, revalidate, lastModified) {
|
|
11
21
|
let finalRevalidate = CACHE_ONE_YEAR;
|
|
12
22
|
const existingRoute = Object.entries(PrerenderManifest.routes).find((p) => p[0] === path)?.[1];
|
|
@@ -92,13 +102,15 @@ async function generateResult(event, localizedPath, cachedValue, lastModified) {
|
|
|
92
102
|
const cacheControl = await computeCacheControl(localizedPath, body, event.headers.host, cachedValue.revalidate, lastModified);
|
|
93
103
|
return {
|
|
94
104
|
type: "core",
|
|
95
|
-
|
|
105
|
+
// sometimes other status codes can be cached, like 404. For these cases, we should return the correct status code
|
|
106
|
+
statusCode: cachedValue.meta?.status ?? 200,
|
|
96
107
|
body: toReadableStream(body, false),
|
|
97
108
|
isBase64Encoded: false,
|
|
98
109
|
headers: {
|
|
99
110
|
...cacheControl,
|
|
100
111
|
"content-type": type,
|
|
101
112
|
...cachedValue.meta?.headers,
|
|
113
|
+
vary: VARY_HEADER,
|
|
102
114
|
},
|
|
103
115
|
};
|
|
104
116
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { Header, PrerenderManifest, RedirectDefinition, RewriteDefinition } from "../../types/next-types";
|
|
2
2
|
import type { InternalEvent, InternalResult } from "../../types/open-next";
|
|
3
3
|
export declare function getNextConfigHeaders(event: InternalEvent, configHeaders?: Header[] | undefined): Record<string, string | undefined>;
|
|
4
|
+
/**
|
|
5
|
+
* TODO: This method currently only check for the first match.
|
|
6
|
+
* It should check for all matches for `beforeFiles` and `afterFiles` rewrite
|
|
7
|
+
* See https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites
|
|
8
|
+
*/
|
|
4
9
|
export declare function handleRewrites<T extends RewriteDefinition>(event: InternalEvent, rewrites: T[]): {
|
|
5
10
|
internalEvent: {
|
|
6
11
|
query: Record<string, string | string[]>;
|
|
@@ -97,6 +97,11 @@ export function getNextConfigHeaders(event, configHeaders) {
|
|
|
97
97
|
}
|
|
98
98
|
return requestHeaders;
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* TODO: This method currently only check for the first match.
|
|
102
|
+
* It should check for all matches for `beforeFiles` and `afterFiles` rewrite
|
|
103
|
+
* See https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites
|
|
104
|
+
*/
|
|
100
105
|
export function handleRewrites(event, rewrites) {
|
|
101
106
|
const { rawPath, headers, query, cookies, url } = event;
|
|
102
107
|
const localizedRawPath = localizePath(event);
|
|
@@ -259,7 +264,8 @@ export function handleRedirects(event, redirects) {
|
|
|
259
264
|
}
|
|
260
265
|
export function fixDataPage(internalEvent, buildId) {
|
|
261
266
|
const { rawPath, query } = internalEvent;
|
|
262
|
-
const
|
|
267
|
+
const basePath = NextConfig.basePath ?? "";
|
|
268
|
+
const dataPattern = `${basePath}/_next/data/${buildId}`;
|
|
263
269
|
// Return 404 for data requests that don't match the buildId
|
|
264
270
|
if (rawPath.startsWith("/_next/data") && !rawPath.startsWith(dataPattern)) {
|
|
265
271
|
return {
|
|
@@ -273,9 +279,9 @@ export function fixDataPage(internalEvent, buildId) {
|
|
|
273
279
|
};
|
|
274
280
|
}
|
|
275
281
|
if (rawPath.startsWith(dataPattern) && rawPath.endsWith(".json")) {
|
|
276
|
-
const newPath = rawPath
|
|
282
|
+
const newPath = `${basePath}${rawPath
|
|
277
283
|
.slice(dataPattern.length, -".json".length)
|
|
278
|
-
.replace(/^\/index$/, "/")
|
|
284
|
+
.replace(/^\/index$/, "/")}`;
|
|
279
285
|
query.__nextDataReq = "1";
|
|
280
286
|
return {
|
|
281
287
|
...internalEvent,
|
|
@@ -233,6 +233,8 @@ export function addOpenNextHeader(headers) {
|
|
|
233
233
|
}
|
|
234
234
|
if (globalThis.openNextDebug) {
|
|
235
235
|
headers["X-OpenNext-Version"] = globalThis.openNextVersion;
|
|
236
|
+
}
|
|
237
|
+
if (process.env.OPEN_NEXT_REQUEST_ID_HEADER || globalThis.openNextDebug) {
|
|
236
238
|
headers["X-OpenNext-RequestId"] =
|
|
237
239
|
globalThis.__openNextAls.getStore()?.requestId;
|
|
238
240
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { InternalEvent, InternalResult, RoutingResult } from "../types/open-next";
|
|
2
|
+
import type { AssetResolver } from "../types/overrides";
|
|
2
3
|
export declare const MIDDLEWARE_HEADER_PREFIX = "x-middleware-response-";
|
|
3
4
|
export declare const MIDDLEWARE_HEADER_PREFIX_LEN: number;
|
|
4
5
|
export declare const INTERNAL_HEADER_PREFIX = "x-opennext-";
|
|
5
6
|
export declare const INTERNAL_HEADER_INITIAL_URL = "x-opennext-initial-url";
|
|
6
7
|
export declare const INTERNAL_HEADER_LOCALE = "x-opennext-locale";
|
|
7
8
|
export declare const INTERNAL_HEADER_RESOLVED_ROUTES = "x-opennext-resolved-routes";
|
|
8
|
-
export
|
|
9
|
+
export declare const INTERNAL_EVENT_REQUEST_ID = "x-opennext-request-id";
|
|
10
|
+
export default function routingHandler(event: InternalEvent, { assetResolver }: {
|
|
11
|
+
assetResolver?: AssetResolver;
|
|
12
|
+
}): Promise<InternalResult | RoutingResult>;
|
|
@@ -12,6 +12,7 @@ export const INTERNAL_HEADER_PREFIX = "x-opennext-";
|
|
|
12
12
|
export const INTERNAL_HEADER_INITIAL_URL = `${INTERNAL_HEADER_PREFIX}initial-url`;
|
|
13
13
|
export const INTERNAL_HEADER_LOCALE = `${INTERNAL_HEADER_PREFIX}locale`;
|
|
14
14
|
export const INTERNAL_HEADER_RESOLVED_ROUTES = `${INTERNAL_HEADER_PREFIX}resolved-routes`;
|
|
15
|
+
export const INTERNAL_EVENT_REQUEST_ID = `${INTERNAL_HEADER_PREFIX}request-id`;
|
|
15
16
|
// Geolocation headers starting from Nextjs 15
|
|
16
17
|
// See https://github.com/vercel/vercel/blob/7714b1c/packages/functions/src/headers.ts
|
|
17
18
|
const geoHeaderToNextHeader = {
|
|
@@ -21,17 +22,25 @@ const geoHeaderToNextHeader = {
|
|
|
21
22
|
"x-open-next-latitude": "x-vercel-ip-latitude",
|
|
22
23
|
"x-open-next-longitude": "x-vercel-ip-longitude",
|
|
23
24
|
};
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Adds the middleware headers to an event or result.
|
|
27
|
+
*
|
|
28
|
+
* @param eventOrResult
|
|
29
|
+
* @param middlewareHeaders
|
|
30
|
+
*/
|
|
31
|
+
function applyMiddlewareHeaders(eventOrResult, middlewareHeaders) {
|
|
32
|
+
// Use the `MIDDLEWARE_HEADER_PREFIX` prefix for events, they will be processed by the request handler later.
|
|
33
|
+
// Results do not go through the request handler and should not be prefixed.
|
|
34
|
+
const isResult = isInternalResult(eventOrResult);
|
|
35
|
+
const headers = eventOrResult.headers;
|
|
36
|
+
const keyPrefix = isResult ? "" : MIDDLEWARE_HEADER_PREFIX;
|
|
26
37
|
Object.entries(middlewareHeaders).forEach(([key, value]) => {
|
|
27
38
|
if (value) {
|
|
28
|
-
|
|
29
|
-
? value.join(",")
|
|
30
|
-
: value;
|
|
39
|
+
headers[keyPrefix + key] = Array.isArray(value) ? value.join(",") : value;
|
|
31
40
|
}
|
|
32
41
|
});
|
|
33
42
|
}
|
|
34
|
-
export default async function routingHandler(event) {
|
|
43
|
+
export default async function routingHandler(event, { assetResolver }) {
|
|
35
44
|
try {
|
|
36
45
|
// Add Next geo headers
|
|
37
46
|
for (const [openNextGeoName, nextGeoName] of Object.entries(geoHeaderToNextHeader)) {
|
|
@@ -48,12 +57,13 @@ export default async function routingHandler(event) {
|
|
|
48
57
|
delete event.headers[key];
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
|
-
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
// Headers from the Next config and middleware (the later are applied further down).
|
|
61
|
+
let headers = getNextConfigHeaders(event, ConfigHeaders);
|
|
62
|
+
let eventOrResult = fixDataPage(event, BuildId);
|
|
63
|
+
if (isInternalResult(eventOrResult)) {
|
|
64
|
+
return eventOrResult;
|
|
55
65
|
}
|
|
56
|
-
const redirect = handleRedirects(
|
|
66
|
+
const redirect = handleRedirects(eventOrResult, RoutesManifest.redirects);
|
|
57
67
|
if (redirect) {
|
|
58
68
|
// We need to encode the value in the Location header to make sure it is valid according to RFC
|
|
59
69
|
// https://stackoverflow.com/a/7654605/16587222
|
|
@@ -61,99 +71,105 @@ export default async function routingHandler(event) {
|
|
|
61
71
|
debug("redirect", redirect);
|
|
62
72
|
return redirect;
|
|
63
73
|
}
|
|
64
|
-
const
|
|
74
|
+
const middlewareEventOrResult = await handleMiddleware(eventOrResult,
|
|
65
75
|
// We need to pass the initial search without any decoding
|
|
66
76
|
// TODO: we'd need to refactor InternalEvent to include the initial querystring directly
|
|
67
77
|
// Should be done in another PR because it is a breaking change
|
|
68
78
|
new URL(event.url).search);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return eventOrResult;
|
|
79
|
+
if (isInternalResult(middlewareEventOrResult)) {
|
|
80
|
+
return middlewareEventOrResult;
|
|
72
81
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
headers = {
|
|
83
|
+
...middlewareEventOrResult.responseHeaders,
|
|
84
|
+
...headers,
|
|
85
|
+
};
|
|
86
|
+
let isExternalRewrite = middlewareEventOrResult.isExternalRewrite ?? false;
|
|
87
|
+
eventOrResult = middlewareEventOrResult;
|
|
77
88
|
if (!isExternalRewrite) {
|
|
78
89
|
// First rewrite to be applied
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
isExternalRewrite =
|
|
90
|
+
const beforeRewrite = handleRewrites(eventOrResult, RoutesManifest.rewrites.beforeFiles);
|
|
91
|
+
eventOrResult = beforeRewrite.internalEvent;
|
|
92
|
+
isExternalRewrite = beforeRewrite.isExternalRewrite;
|
|
93
|
+
// Check for matching public files after `beforeFiles` rewrites
|
|
94
|
+
// See:
|
|
95
|
+
// - https://nextjs.org/docs/app/api-reference/file-conventions/middleware#execution-order
|
|
96
|
+
// - https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites
|
|
97
|
+
if (!isExternalRewrite) {
|
|
98
|
+
const assetResult = await assetResolver?.maybeGetAssetResult?.(eventOrResult);
|
|
99
|
+
if (assetResult) {
|
|
100
|
+
applyMiddlewareHeaders(assetResult, headers);
|
|
101
|
+
return assetResult;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
82
104
|
}
|
|
83
|
-
const foundStaticRoute = staticRouteMatcher(
|
|
105
|
+
const foundStaticRoute = staticRouteMatcher(eventOrResult.rawPath);
|
|
84
106
|
const isStaticRoute = !isExternalRewrite && foundStaticRoute.length > 0;
|
|
85
107
|
if (!(isStaticRoute || isExternalRewrite)) {
|
|
86
108
|
// Second rewrite to be applied
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
isExternalRewrite =
|
|
109
|
+
const afterRewrite = handleRewrites(eventOrResult, RoutesManifest.rewrites.afterFiles);
|
|
110
|
+
eventOrResult = afterRewrite.internalEvent;
|
|
111
|
+
isExternalRewrite = afterRewrite.isExternalRewrite;
|
|
90
112
|
}
|
|
91
113
|
let isISR = false;
|
|
92
114
|
// We want to run this just before the dynamic route check
|
|
93
115
|
// We can skip it if its an external rewrite
|
|
94
116
|
if (!isExternalRewrite) {
|
|
95
|
-
const fallbackResult = handleFallbackFalse(
|
|
96
|
-
|
|
117
|
+
const fallbackResult = handleFallbackFalse(eventOrResult, PrerenderManifest);
|
|
118
|
+
eventOrResult = fallbackResult.event;
|
|
97
119
|
isISR = fallbackResult.isISR;
|
|
98
120
|
}
|
|
99
|
-
const foundDynamicRoute = dynamicRouteMatcher(
|
|
121
|
+
const foundDynamicRoute = dynamicRouteMatcher(eventOrResult.rawPath);
|
|
100
122
|
const isDynamicRoute = !isExternalRewrite && foundDynamicRoute.length > 0;
|
|
101
123
|
if (!(isDynamicRoute || isStaticRoute || isExternalRewrite)) {
|
|
102
124
|
// Fallback rewrite to be applied
|
|
103
|
-
const fallbackRewrites = handleRewrites(
|
|
104
|
-
|
|
125
|
+
const fallbackRewrites = handleRewrites(eventOrResult, RoutesManifest.rewrites.fallback);
|
|
126
|
+
eventOrResult = fallbackRewrites.internalEvent;
|
|
105
127
|
isExternalRewrite = fallbackRewrites.isExternalRewrite;
|
|
106
128
|
}
|
|
107
|
-
const isNextImageRoute =
|
|
129
|
+
const isNextImageRoute = eventOrResult.rawPath.startsWith("/_next/image");
|
|
108
130
|
const isRouteFoundBeforeAllRewrites = isStaticRoute || isDynamicRoute || isExternalRewrite;
|
|
109
131
|
// If we still haven't found a route, we show the 404 page
|
|
110
132
|
// We need to ensure that rewrites are applied before showing the 404 page
|
|
111
133
|
if (!(isRouteFoundBeforeAllRewrites ||
|
|
112
134
|
isNextImageRoute ||
|
|
113
135
|
// We need to check again once all rewrites have been applied
|
|
114
|
-
staticRouteMatcher(
|
|
115
|
-
dynamicRouteMatcher(
|
|
116
|
-
|
|
117
|
-
...
|
|
136
|
+
staticRouteMatcher(eventOrResult.rawPath).length > 0 ||
|
|
137
|
+
dynamicRouteMatcher(eventOrResult.rawPath).length > 0)) {
|
|
138
|
+
eventOrResult = {
|
|
139
|
+
...eventOrResult,
|
|
118
140
|
rawPath: "/404",
|
|
119
|
-
url: constructNextUrl(
|
|
141
|
+
url: constructNextUrl(eventOrResult.url, "/404"),
|
|
120
142
|
headers: {
|
|
121
|
-
...
|
|
143
|
+
...eventOrResult.headers,
|
|
122
144
|
"x-middleware-response-cache-control": "private, no-cache, no-store, max-age=0, must-revalidate",
|
|
123
145
|
},
|
|
124
146
|
};
|
|
125
147
|
}
|
|
126
148
|
if (globalThis.openNextConfig.dangerous?.enableCacheInterception &&
|
|
127
|
-
!(
|
|
149
|
+
!isInternalResult(eventOrResult)) {
|
|
128
150
|
debug("Cache interception enabled");
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
applyMiddlewareHeaders(
|
|
132
|
-
|
|
133
|
-
...nextHeaders,
|
|
134
|
-
}, false);
|
|
135
|
-
return internalEvent;
|
|
151
|
+
eventOrResult = await cacheInterceptor(eventOrResult);
|
|
152
|
+
if (isInternalResult(eventOrResult)) {
|
|
153
|
+
applyMiddlewareHeaders(eventOrResult, headers);
|
|
154
|
+
return eventOrResult;
|
|
136
155
|
}
|
|
137
156
|
}
|
|
138
157
|
// We apply the headers from the middleware response last
|
|
139
|
-
applyMiddlewareHeaders(
|
|
140
|
-
...middlewareResponseHeaders,
|
|
141
|
-
...nextHeaders,
|
|
142
|
-
});
|
|
158
|
+
applyMiddlewareHeaders(eventOrResult, headers);
|
|
143
159
|
const resolvedRoutes = [
|
|
144
160
|
...foundStaticRoute,
|
|
145
161
|
...foundDynamicRoute,
|
|
146
162
|
];
|
|
147
163
|
debug("resolvedRoutes", resolvedRoutes);
|
|
148
164
|
return {
|
|
149
|
-
internalEvent,
|
|
165
|
+
internalEvent: eventOrResult,
|
|
150
166
|
isExternalRewrite,
|
|
151
167
|
origin: false,
|
|
152
168
|
isISR,
|
|
153
169
|
resolvedRoutes,
|
|
154
170
|
initialURL: event.url,
|
|
155
171
|
locale: NextConfig.i18n
|
|
156
|
-
? detectLocale(
|
|
172
|
+
? detectLocale(eventOrResult, NextConfig.i18n)
|
|
157
173
|
: undefined,
|
|
158
174
|
};
|
|
159
175
|
}
|
|
@@ -184,3 +200,10 @@ export default async function routingHandler(event) {
|
|
|
184
200
|
};
|
|
185
201
|
}
|
|
186
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* @param eventOrResult
|
|
205
|
+
* @returns Whether the event is an instance of `InternalResult`
|
|
206
|
+
*/
|
|
207
|
+
function isInternalResult(eventOrResult) {
|
|
208
|
+
return eventOrResult != null && "statusCode" in eventOrResult;
|
|
209
|
+
}
|
|
@@ -2,6 +2,8 @@ import { Buffer } from "node:buffer";
|
|
|
2
2
|
import cookieParser from "cookie";
|
|
3
3
|
import { parseSetCookieHeader } from "../../http/util";
|
|
4
4
|
import { getQueryFromSearchParams } from "./utils.js";
|
|
5
|
+
// https://fetch.spec.whatwg.org/#statuses
|
|
6
|
+
const NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);
|
|
5
7
|
const converter = {
|
|
6
8
|
convertFrom: async (event) => {
|
|
7
9
|
const url = new URL(event.url);
|
|
@@ -77,7 +79,11 @@ const converter = {
|
|
|
77
79
|
headers.set(key, value);
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
|
-
return
|
|
82
|
+
// We should not return a body for statusCode's that doesn't allow bodies
|
|
83
|
+
const body = NULL_BODY_STATUSES.has(result.statusCode)
|
|
84
|
+
? null
|
|
85
|
+
: result.body;
|
|
86
|
+
return new Response(body, {
|
|
81
87
|
status: result.statusCode,
|
|
82
88
|
headers,
|
|
83
89
|
});
|
package/dist/types/global.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import type { OutgoingHttpHeaders } from "node:http";
|
|
3
|
-
import type { CDNInvalidationHandler, IncrementalCache, ProxyExternalRequest, Queue, TagCache } from "./overrides";
|
|
3
|
+
import type { AssetResolver, CDNInvalidationHandler, IncrementalCache, ProxyExternalRequest, Queue, TagCache } from "./overrides";
|
|
4
4
|
import type { DetachedPromiseRunner } from "../utils/promise";
|
|
5
5
|
import type { OpenNextConfig, WaitUntil } from "./open-next";
|
|
6
6
|
export interface RequestData {
|
|
@@ -53,6 +53,8 @@ interface OpenNextRequestContext {
|
|
|
53
53
|
mergeHeadersPriority?: "middleware" | "handler";
|
|
54
54
|
lastModified?: number;
|
|
55
55
|
waitUntil?: WaitUntil;
|
|
56
|
+
/** We use this to deduplicate write of the tags*/
|
|
57
|
+
writtenTags: Set<string>;
|
|
56
58
|
}
|
|
57
59
|
declare global {
|
|
58
60
|
/**
|
|
@@ -179,6 +181,12 @@ declare global {
|
|
|
179
181
|
* Defined in `createMainHandler`
|
|
180
182
|
*/
|
|
181
183
|
var cdnInvalidationHandler: CDNInvalidationHandler;
|
|
184
|
+
/**
|
|
185
|
+
* The function called to resolve assets.
|
|
186
|
+
* Available in main functions
|
|
187
|
+
* Defined in `createMainHandler` when the middleware is internal
|
|
188
|
+
*/
|
|
189
|
+
var assetResolver: AssetResolver | undefined;
|
|
182
190
|
/**
|
|
183
191
|
* A function to preload the routes.
|
|
184
192
|
* This needs to be defined on globalThis because it can be used by custom overrides.
|
|
@@ -72,10 +72,12 @@ export interface NextConfig {
|
|
|
72
72
|
experimental: {
|
|
73
73
|
serverActions?: boolean;
|
|
74
74
|
appDir?: boolean;
|
|
75
|
+
optimizeCss?: boolean;
|
|
75
76
|
};
|
|
76
77
|
images: ImageConfig;
|
|
77
78
|
poweredByHeader?: boolean;
|
|
78
79
|
serverExternalPackages?: string[];
|
|
80
|
+
deploymentId?: string;
|
|
79
81
|
}
|
|
80
82
|
export interface RouteDefinition {
|
|
81
83
|
page: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReadableStream } from "node:stream/web";
|
|
2
2
|
import type { Writable } from "node:stream";
|
|
3
3
|
import type { WarmerEvent, WarmerResponse } from "../adapters/warmer-function";
|
|
4
|
-
import type { CDNInvalidationHandler, Converter, ImageLoader, IncrementalCache, OriginResolver, ProxyExternalRequest, Queue, TagCache, Warmer, Wrapper } from "./overrides";
|
|
4
|
+
import type { AssetResolver, CDNInvalidationHandler, Converter, ImageLoader, IncrementalCache, OriginResolver, ProxyExternalRequest, Queue, TagCache, Warmer, Wrapper } from "./overrides";
|
|
5
5
|
export type BaseEventOrResult<T extends string = string> = {
|
|
6
6
|
type: T;
|
|
7
7
|
};
|
|
@@ -103,6 +103,7 @@ export type IncludedOriginResolver = "pattern-env" | "dummy";
|
|
|
103
103
|
export type IncludedWarmer = "aws-lambda" | "dummy";
|
|
104
104
|
export type IncludedProxyExternalRequest = "node" | "fetch" | "dummy";
|
|
105
105
|
export type IncludedCDNInvalidationHandler = "cloudfront" | "dummy";
|
|
106
|
+
export type IncludedAssetResolver = "dummy";
|
|
106
107
|
export interface DefaultOverrideOptions<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> {
|
|
107
108
|
/**
|
|
108
109
|
* This is the main entrypoint of your app.
|
|
@@ -273,6 +274,12 @@ export interface OpenNextConfig {
|
|
|
273
274
|
* @default "pattern-env"
|
|
274
275
|
*/
|
|
275
276
|
originResolver?: IncludedOriginResolver | LazyLoadedOverride<OriginResolver>;
|
|
277
|
+
/**
|
|
278
|
+
* The assetResolver is used to resolve assets in the routing layer.
|
|
279
|
+
*
|
|
280
|
+
* @default "dummy"
|
|
281
|
+
*/
|
|
282
|
+
assetResolver?: IncludedAssetResolver | LazyLoadedOverride<AssetResolver>;
|
|
276
283
|
};
|
|
277
284
|
/**
|
|
278
285
|
* Override the default warmer
|
|
@@ -15,6 +15,19 @@ export interface Queue {
|
|
|
15
15
|
send(message: QueueMessage): Promise<void>;
|
|
16
16
|
name: string;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves assets in the routing layer.
|
|
20
|
+
*/
|
|
21
|
+
export interface AssetResolver {
|
|
22
|
+
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* Called by the routing layer to check for a matching static asset.
|
|
25
|
+
*
|
|
26
|
+
* @param event
|
|
27
|
+
* @returns an `InternalResult` when an asset is found a the path from the event, undefined otherwise.
|
|
28
|
+
*/
|
|
29
|
+
maybeGetAssetResult?: (event: InternalEvent) => Promise<InternalResult | undefined> | undefined;
|
|
30
|
+
}
|
|
18
31
|
export type CachedFile = {
|
|
19
32
|
type: "redirect";
|
|
20
33
|
props?: Object;
|
|
@@ -95,6 +108,11 @@ export type NextModeTagCache = BaseTagCache & {
|
|
|
95
108
|
writeTags(tags: string[]): Promise<void>;
|
|
96
109
|
getPathsByTags?: (tags: string[]) => Promise<string[]>;
|
|
97
110
|
};
|
|
111
|
+
export interface OriginalTagCacheWriteInput {
|
|
112
|
+
tag: string;
|
|
113
|
+
path: string;
|
|
114
|
+
revalidatedAt?: number;
|
|
115
|
+
}
|
|
98
116
|
/**
|
|
99
117
|
* On get :
|
|
100
118
|
We just check for the cache key in the tag cache. If it has been revalidated we just return null, otherwise we continue
|
|
@@ -119,11 +137,7 @@ export type OriginalTagCache = BaseTagCache & {
|
|
|
119
137
|
getByTag(tag: string): Promise<string[]>;
|
|
120
138
|
getByPath(path: string): Promise<string[]>;
|
|
121
139
|
getLastModified(path: string, lastModified?: number): Promise<number>;
|
|
122
|
-
writeTags(tags:
|
|
123
|
-
tag: string;
|
|
124
|
-
path: string;
|
|
125
|
-
revalidatedAt?: number;
|
|
126
|
-
}[]): Promise<void>;
|
|
140
|
+
writeTags(tags: OriginalTagCacheWriteInput[]): Promise<void>;
|
|
127
141
|
};
|
|
128
142
|
export type TagCache = NextModeTagCache | OriginalTagCache;
|
|
129
143
|
export type WrapperHandler<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> = (handler: OpenNextHandler<E, R>, converter: Converter<E, R>) => Promise<(...args: any[]) => any>;
|
package/dist/utils/cache.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type { CacheValue, WithLastModified } from "../types/overrides";
|
|
1
|
+
import type { CacheValue, OriginalTagCacheWriteInput, WithLastModified } from "../types/overrides";
|
|
2
2
|
export declare function hasBeenRevalidated(key: string, tags: string[], cacheEntry: WithLastModified<CacheValue<any>>): Promise<boolean>;
|
|
3
3
|
export declare function getTagsFromValue(value?: CacheValue<"cache">): string[];
|
|
4
|
+
export declare function writeTags(tags: (string | OriginalTagCacheWriteInput)[]): Promise<void>;
|
package/dist/utils/cache.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { debug } from "../adapters/logger";
|
|
1
2
|
export async function hasBeenRevalidated(key, tags, cacheEntry) {
|
|
2
3
|
if (globalThis.openNextConfig.dangerous?.disableTagCache) {
|
|
3
4
|
return false;
|
|
@@ -30,3 +31,34 @@ export function getTagsFromValue(value) {
|
|
|
30
31
|
return [];
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
function getTagKey(tag) {
|
|
35
|
+
if (typeof tag === "string") {
|
|
36
|
+
return tag;
|
|
37
|
+
}
|
|
38
|
+
return JSON.stringify({
|
|
39
|
+
tag: tag.tag,
|
|
40
|
+
path: tag.path,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export async function writeTags(tags) {
|
|
44
|
+
const store = globalThis.__openNextAls.getStore();
|
|
45
|
+
debug("Writing tags", tags, store);
|
|
46
|
+
if (!store || globalThis.openNextConfig.dangerous?.disableTagCache) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const tagsToWrite = tags.filter((t) => {
|
|
50
|
+
const tagKey = getTagKey(t);
|
|
51
|
+
const shouldWrite = !store.writtenTags.has(tagKey);
|
|
52
|
+
// We preemptively add the tag to the writtenTags set
|
|
53
|
+
// to avoid writing the same tag multiple times in the same request
|
|
54
|
+
if (shouldWrite) {
|
|
55
|
+
store.writtenTags.add(tagKey);
|
|
56
|
+
}
|
|
57
|
+
return shouldWrite;
|
|
58
|
+
});
|
|
59
|
+
if (tagsToWrite.length === 0) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Here we know that we have the correct type
|
|
63
|
+
await globalThis.tagCache.writeTags(tagsToWrite);
|
|
64
|
+
}
|
package/dist/utils/promise.d.ts
CHANGED
|
@@ -17,7 +17,8 @@ export declare class DetachedPromiseRunner {
|
|
|
17
17
|
add<T>(promise: Promise<T>): void;
|
|
18
18
|
await(): Promise<void>;
|
|
19
19
|
}
|
|
20
|
-
export declare function runWithOpenNextRequestContext<T>({ isISRRevalidation, waitUntil, }: {
|
|
20
|
+
export declare function runWithOpenNextRequestContext<T>({ isISRRevalidation, waitUntil, requestId, }: {
|
|
21
21
|
isISRRevalidation: boolean;
|
|
22
22
|
waitUntil?: WaitUntil;
|
|
23
|
+
requestId?: string;
|
|
23
24
|
}, fn: () => Promise<T>): Promise<T>;
|
package/dist/utils/promise.js
CHANGED
|
@@ -77,12 +77,13 @@ function provideNextAfterProvider() {
|
|
|
77
77
|
globalThis[VERCEL_REQUEST_CONTEXT_SYMBOL] = nextAfterContext;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
export function runWithOpenNextRequestContext({ isISRRevalidation, waitUntil, }, fn) {
|
|
80
|
+
export function runWithOpenNextRequestContext({ isISRRevalidation, waitUntil, requestId = Math.random().toString(36), }, fn) {
|
|
81
81
|
return globalThis.__openNextAls.run({
|
|
82
|
-
requestId
|
|
82
|
+
requestId,
|
|
83
83
|
pendingPromiseRunner: new DetachedPromiseRunner(),
|
|
84
84
|
isISRRevalidation,
|
|
85
85
|
waitUntil,
|
|
86
|
+
writtenTags: new Set(),
|
|
86
87
|
}, async () => {
|
|
87
88
|
provideNextAfterProvider();
|
|
88
89
|
let result;
|
package/package.json
CHANGED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Patches to avoid pulling babel (~4MB).
|
|
3
|
-
*
|
|
4
|
-
* Details:
|
|
5
|
-
* - empty `NextServer#runMiddleware` and `NextServer#runEdgeFunction` that are not used
|
|
6
|
-
* - drop `next/dist/server/node-environment-extensions/error-inspect.js`
|
|
7
|
-
*/
|
|
8
|
-
import type { CodePatcher } from "../codePatcher.js";
|
|
9
|
-
export declare const patchDropBabel: CodePatcher;
|
|
10
|
-
/**
|
|
11
|
-
* Swaps the body for a throwing implementation
|
|
12
|
-
*
|
|
13
|
-
* @param methodName The name of the method
|
|
14
|
-
* @returns A rule to replace the body with a `throw`
|
|
15
|
-
*/
|
|
16
|
-
export declare function createEmptyBodyRule(methodName: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Drops `require("./node-environment-extensions/error-inspect");`
|
|
19
|
-
*/
|
|
20
|
-
export declare const errorInspectRule = "\nrule:\n pattern: require(\"./node-environment-extensions/error-inspect\");\nfix: |-\n // Removed by OpenNext\n // require(\"./node-environment-extensions/error-inspect\");\n";
|