@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,36 @@
|
|
|
1
|
+
import { NextConfig } from "../../../adapters/config/index.js";
|
|
2
|
+
import { debug } from "../../../adapters/logger.js";
|
|
3
|
+
import { acceptLanguage } from "./accept-header";
|
|
4
|
+
function isLocalizedPath(path) {
|
|
5
|
+
return (NextConfig.i18n?.locales.includes(path.split("/")[1].toLowerCase()) ?? false);
|
|
6
|
+
}
|
|
7
|
+
// https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/get-locale-redirect.ts
|
|
8
|
+
function getLocaleFromCookie(cookies) {
|
|
9
|
+
const i18n = NextConfig.i18n;
|
|
10
|
+
const nextLocale = cookies.NEXT_LOCALE?.toLowerCase();
|
|
11
|
+
return nextLocale
|
|
12
|
+
? i18n?.locales.find((locale) => nextLocale === locale.toLowerCase())
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|
|
15
|
+
function detectLocale(internalEvent, i18n) {
|
|
16
|
+
const cookiesLocale = getLocaleFromCookie(internalEvent.cookies);
|
|
17
|
+
const preferredLocale = acceptLanguage(internalEvent.headers["accept-language"], i18n?.locales);
|
|
18
|
+
debug({
|
|
19
|
+
cookiesLocale,
|
|
20
|
+
preferredLocale,
|
|
21
|
+
defaultLocale: i18n.defaultLocale,
|
|
22
|
+
});
|
|
23
|
+
return cookiesLocale ?? preferredLocale ?? i18n.defaultLocale;
|
|
24
|
+
// TODO: handle domain based locale detection
|
|
25
|
+
}
|
|
26
|
+
export function localizePath(internalEvent) {
|
|
27
|
+
const i18n = NextConfig.i18n;
|
|
28
|
+
if (!i18n) {
|
|
29
|
+
return internalEvent.rawPath;
|
|
30
|
+
}
|
|
31
|
+
if (isLocalizedPath(internalEvent.rawPath)) {
|
|
32
|
+
return internalEvent.rawPath;
|
|
33
|
+
}
|
|
34
|
+
const detectedLocale = detectLocale(internalEvent, i18n);
|
|
35
|
+
return `/${detectedLocale}${internalEvent.rawPath}`;
|
|
36
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { Header, PrerenderManifest, RedirectDefinition, RewriteDefinition } from "../../types/next-types";
|
|
3
|
+
import { InternalEvent, InternalResult } from "../../types/open-next";
|
|
4
|
+
export declare function addNextConfigHeaders(event: InternalEvent, configHeaders?: Header[] | undefined): Record<string, string | undefined>;
|
|
5
|
+
export declare function handleRewrites<T extends RewriteDefinition>(event: InternalEvent, rewrites: T[]): {
|
|
6
|
+
internalEvent: {
|
|
7
|
+
rawPath: string;
|
|
8
|
+
url: string;
|
|
9
|
+
method: string;
|
|
10
|
+
body?: Buffer | undefined;
|
|
11
|
+
headers: Record<string, string>;
|
|
12
|
+
query: Record<string, string | string[]>;
|
|
13
|
+
cookies: Record<string, string>;
|
|
14
|
+
remoteAddress: string;
|
|
15
|
+
type: "core";
|
|
16
|
+
};
|
|
17
|
+
__rewrite: T | undefined;
|
|
18
|
+
isExternalRewrite: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare function handleRedirects(event: InternalEvent, redirects: RedirectDefinition[]): InternalResult | undefined;
|
|
21
|
+
export declare function fixDataPage(internalEvent: InternalEvent, buildId: string): InternalEvent | InternalResult;
|
|
22
|
+
export declare function handleFallbackFalse(internalEvent: InternalEvent, prerenderManifest: PrerenderManifest): {
|
|
23
|
+
event: InternalEvent;
|
|
24
|
+
isISR: boolean;
|
|
25
|
+
};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { NextConfig } from "../../adapters/config/index";
|
|
2
|
+
import { compile, match, } from "path-to-regexp";
|
|
3
|
+
import { emptyReadableStream, toReadableStream } from "../../utils/stream";
|
|
4
|
+
import { debug } from "../../adapters/logger";
|
|
5
|
+
import { localizePath } from "./i18n";
|
|
6
|
+
import { convertFromQueryString, convertToQueryString, escapeRegex, getUrlParts, isExternal, unescapeRegex, } from "./util";
|
|
7
|
+
const routeHasMatcher = (headers, cookies, query) => (redirect) => {
|
|
8
|
+
switch (redirect.type) {
|
|
9
|
+
case "header":
|
|
10
|
+
return (!!headers?.[redirect.key.toLowerCase()] &&
|
|
11
|
+
new RegExp(redirect.value ?? "").test(headers[redirect.key.toLowerCase()] ?? ""));
|
|
12
|
+
case "cookie":
|
|
13
|
+
return (!!cookies?.[redirect.key] &&
|
|
14
|
+
new RegExp(redirect.value ?? "").test(cookies[redirect.key] ?? ""));
|
|
15
|
+
case "query":
|
|
16
|
+
return query[redirect.key] && Array.isArray(redirect.value)
|
|
17
|
+
? redirect.value.reduce((prev, current) => prev || new RegExp(current).test(query[redirect.key]), false)
|
|
18
|
+
: new RegExp(redirect.value ?? "").test(query[redirect.key] ?? "");
|
|
19
|
+
case "host":
|
|
20
|
+
return (headers?.host !== "" &&
|
|
21
|
+
new RegExp(redirect.value ?? "").test(headers.host));
|
|
22
|
+
default:
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
function checkHas(matcher, has, inverted = false) {
|
|
27
|
+
return has
|
|
28
|
+
? has.reduce((acc, cur) => {
|
|
29
|
+
if (acc === false)
|
|
30
|
+
return false;
|
|
31
|
+
return inverted ? !matcher(cur) : matcher(cur);
|
|
32
|
+
}, true)
|
|
33
|
+
: true;
|
|
34
|
+
}
|
|
35
|
+
const getParamsFromSource = (source) => (value) => {
|
|
36
|
+
debug("value", value);
|
|
37
|
+
const _match = source(value);
|
|
38
|
+
return _match ? _match.params : {};
|
|
39
|
+
};
|
|
40
|
+
const computeParamHas = (headers, cookies, query) => (has) => {
|
|
41
|
+
if (!has.value)
|
|
42
|
+
return {};
|
|
43
|
+
const matcher = new RegExp(`^${has.value}$`);
|
|
44
|
+
const fromSource = (value) => {
|
|
45
|
+
const matches = value.match(matcher);
|
|
46
|
+
return matches?.groups ?? {};
|
|
47
|
+
};
|
|
48
|
+
switch (has.type) {
|
|
49
|
+
case "header":
|
|
50
|
+
return fromSource(headers[has.key.toLowerCase()] ?? "");
|
|
51
|
+
case "cookie":
|
|
52
|
+
return fromSource(cookies[has.key] ?? "");
|
|
53
|
+
case "query":
|
|
54
|
+
return Array.isArray(query[has.key])
|
|
55
|
+
? fromSource(query[has.key].join(","))
|
|
56
|
+
: fromSource(query[has.key] ?? "");
|
|
57
|
+
case "host":
|
|
58
|
+
return fromSource(headers.host ?? "");
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function convertMatch(match, toDestination, destination) {
|
|
62
|
+
if (match) {
|
|
63
|
+
const { params } = match;
|
|
64
|
+
const isUsingParams = Object.keys(params).length > 0;
|
|
65
|
+
if (isUsingParams) {
|
|
66
|
+
return toDestination(params);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return destination;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return destination;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function addNextConfigHeaders(event, configHeaders) {
|
|
77
|
+
const addedHeaders = {};
|
|
78
|
+
if (!configHeaders)
|
|
79
|
+
return addedHeaders;
|
|
80
|
+
const { rawPath, headers, query, cookies } = event;
|
|
81
|
+
const matcher = routeHasMatcher(headers, cookies, query);
|
|
82
|
+
const requestHeaders = {};
|
|
83
|
+
const localizedRawPath = localizePath(event);
|
|
84
|
+
for (const { headers, has, missing, regex, source, locale, } of configHeaders) {
|
|
85
|
+
const path = locale === false ? rawPath : localizedRawPath;
|
|
86
|
+
if (new RegExp(regex).test(path) &&
|
|
87
|
+
checkHas(matcher, has) &&
|
|
88
|
+
checkHas(matcher, missing, true)) {
|
|
89
|
+
const fromSource = match(source);
|
|
90
|
+
const _match = fromSource(path);
|
|
91
|
+
headers.forEach((h) => {
|
|
92
|
+
try {
|
|
93
|
+
const key = convertMatch(_match, compile(h.key), h.key);
|
|
94
|
+
const value = convertMatch(_match, compile(h.value), h.value);
|
|
95
|
+
requestHeaders[key] = value;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
debug("Error matching header ", h.key, " with value ", h.value);
|
|
99
|
+
requestHeaders[h.key] = h.value;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return requestHeaders;
|
|
105
|
+
}
|
|
106
|
+
export function handleRewrites(event, rewrites) {
|
|
107
|
+
const { rawPath, headers, query, cookies } = event;
|
|
108
|
+
const localizedRawPath = localizePath(event);
|
|
109
|
+
const matcher = routeHasMatcher(headers, cookies, query);
|
|
110
|
+
const computeHas = computeParamHas(headers, cookies, query);
|
|
111
|
+
const rewrite = rewrites.find((route) => {
|
|
112
|
+
const path = route.locale === false ? rawPath : localizedRawPath;
|
|
113
|
+
return (new RegExp(route.regex).test(path) &&
|
|
114
|
+
checkHas(matcher, route.has) &&
|
|
115
|
+
checkHas(matcher, route.missing, true));
|
|
116
|
+
});
|
|
117
|
+
let finalQuery = query;
|
|
118
|
+
let rewrittenUrl = rawPath;
|
|
119
|
+
const isExternalRewrite = isExternal(rewrite?.destination);
|
|
120
|
+
debug("isExternalRewrite", isExternalRewrite);
|
|
121
|
+
if (rewrite) {
|
|
122
|
+
const { pathname, protocol, hostname, queryString } = getUrlParts(rewrite.destination, isExternalRewrite);
|
|
123
|
+
// We need to use a localized path if the rewrite is not locale specific
|
|
124
|
+
const pathToUse = rewrite.locale === false ? rawPath : localizedRawPath;
|
|
125
|
+
debug("urlParts", { pathname, protocol, hostname, queryString });
|
|
126
|
+
const toDestinationPath = compile(escapeRegex(pathname ?? "") ?? "");
|
|
127
|
+
const toDestinationHost = compile(escapeRegex(hostname ?? "") ?? "");
|
|
128
|
+
const toDestinationQuery = compile(escapeRegex(queryString ?? "") ?? "");
|
|
129
|
+
let params = {
|
|
130
|
+
// params for the source
|
|
131
|
+
...getParamsFromSource(match(escapeRegex(rewrite?.source) ?? ""))(pathToUse),
|
|
132
|
+
// params for the has
|
|
133
|
+
...rewrite.has?.reduce((acc, cur) => {
|
|
134
|
+
return { ...acc, ...computeHas(cur) };
|
|
135
|
+
}, {}),
|
|
136
|
+
// params for the missing
|
|
137
|
+
...rewrite.missing?.reduce((acc, cur) => {
|
|
138
|
+
return { ...acc, ...computeHas(cur) };
|
|
139
|
+
}, {}),
|
|
140
|
+
};
|
|
141
|
+
const isUsingParams = Object.keys(params).length > 0;
|
|
142
|
+
let rewrittenQuery = queryString;
|
|
143
|
+
let rewrittenHost = hostname;
|
|
144
|
+
let rewrittenPath = pathname;
|
|
145
|
+
if (isUsingParams) {
|
|
146
|
+
rewrittenPath = unescapeRegex(toDestinationPath(params));
|
|
147
|
+
rewrittenHost = unescapeRegex(toDestinationHost(params));
|
|
148
|
+
rewrittenQuery = unescapeRegex(toDestinationQuery(params));
|
|
149
|
+
}
|
|
150
|
+
rewrittenUrl = isExternalRewrite
|
|
151
|
+
? `${protocol}//${rewrittenHost}${rewrittenPath}`
|
|
152
|
+
: `/${rewrittenPath}`;
|
|
153
|
+
// Should we merge the query params or use only the ones from the rewrite?
|
|
154
|
+
finalQuery = {
|
|
155
|
+
...query,
|
|
156
|
+
...convertFromQueryString(rewrittenQuery),
|
|
157
|
+
};
|
|
158
|
+
debug("rewrittenUrl", { rewrittenUrl, finalQuery, isUsingParams });
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
internalEvent: {
|
|
162
|
+
...event,
|
|
163
|
+
rawPath: rewrittenUrl,
|
|
164
|
+
url: `${rewrittenUrl}${convertToQueryString(finalQuery)}`,
|
|
165
|
+
},
|
|
166
|
+
__rewrite: rewrite,
|
|
167
|
+
isExternalRewrite,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function handleTrailingSlashRedirect(event) {
|
|
171
|
+
const url = new URL(event.url, "http://localhost");
|
|
172
|
+
const emptyBody = emptyReadableStream();
|
|
173
|
+
if (
|
|
174
|
+
// Someone is trying to redirect to a different origin, let's not do that
|
|
175
|
+
url.host !== "localhost" ||
|
|
176
|
+
NextConfig.skipTrailingSlashRedirect ||
|
|
177
|
+
// We should not apply trailing slash redirect to API routes
|
|
178
|
+
event.rawPath.startsWith("/api/")) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if (NextConfig.trailingSlash &&
|
|
182
|
+
!event.headers["x-nextjs-data"] &&
|
|
183
|
+
!event.rawPath.endsWith("/") &&
|
|
184
|
+
!event.rawPath.match(/[\w-]+\.[\w]+$/g)) {
|
|
185
|
+
const headersLocation = event.url.split("?");
|
|
186
|
+
return {
|
|
187
|
+
type: event.type,
|
|
188
|
+
statusCode: 308,
|
|
189
|
+
headers: {
|
|
190
|
+
Location: `${headersLocation[0]}/${headersLocation[1] ? `?${headersLocation[1]}` : ""}`,
|
|
191
|
+
},
|
|
192
|
+
body: emptyBody,
|
|
193
|
+
isBase64Encoded: false,
|
|
194
|
+
};
|
|
195
|
+
// eslint-disable-next-line sonarjs/elseif-without-else
|
|
196
|
+
}
|
|
197
|
+
else if (!NextConfig.trailingSlash &&
|
|
198
|
+
event.rawPath.endsWith("/") &&
|
|
199
|
+
event.rawPath !== "/") {
|
|
200
|
+
const headersLocation = event.url.split("?");
|
|
201
|
+
return {
|
|
202
|
+
type: event.type,
|
|
203
|
+
statusCode: 308,
|
|
204
|
+
headers: {
|
|
205
|
+
Location: `${headersLocation[0].replace(/\/$/, "")}${headersLocation[1] ? `?${headersLocation[1]}` : ""}`,
|
|
206
|
+
},
|
|
207
|
+
body: emptyBody,
|
|
208
|
+
isBase64Encoded: false,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
else
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
export function handleRedirects(event, redirects) {
|
|
215
|
+
const trailingSlashRedirect = handleTrailingSlashRedirect(event);
|
|
216
|
+
if (trailingSlashRedirect)
|
|
217
|
+
return trailingSlashRedirect;
|
|
218
|
+
const { internalEvent, __rewrite } = handleRewrites(event, redirects.filter((r) => !r.internal));
|
|
219
|
+
if (__rewrite && !__rewrite.internal) {
|
|
220
|
+
return {
|
|
221
|
+
type: event.type,
|
|
222
|
+
statusCode: __rewrite.statusCode ?? 308,
|
|
223
|
+
headers: {
|
|
224
|
+
Location: internalEvent.url,
|
|
225
|
+
},
|
|
226
|
+
body: emptyReadableStream(),
|
|
227
|
+
isBase64Encoded: false,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
export function fixDataPage(internalEvent, buildId) {
|
|
232
|
+
const { rawPath, query } = internalEvent;
|
|
233
|
+
const dataPattern = `/_next/data/${buildId}`;
|
|
234
|
+
// Return 404 for data requests that don't match the buildId
|
|
235
|
+
if (rawPath.startsWith("/_next/data") && !rawPath.startsWith(dataPattern)) {
|
|
236
|
+
return {
|
|
237
|
+
type: internalEvent.type,
|
|
238
|
+
statusCode: 404,
|
|
239
|
+
body: toReadableStream("{}"),
|
|
240
|
+
headers: {
|
|
241
|
+
"Content-Type": "application/json",
|
|
242
|
+
},
|
|
243
|
+
isBase64Encoded: false,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
if (rawPath.startsWith(dataPattern) && rawPath.endsWith(".json")) {
|
|
247
|
+
let newPath = rawPath.replace(dataPattern, "").replace(/\.json$/, "");
|
|
248
|
+
newPath = newPath === "/index" ? "/" : newPath;
|
|
249
|
+
query.__nextDataReq = "1";
|
|
250
|
+
return {
|
|
251
|
+
...internalEvent,
|
|
252
|
+
rawPath: newPath,
|
|
253
|
+
query,
|
|
254
|
+
url: `${newPath}${convertToQueryString(query)}`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return internalEvent;
|
|
258
|
+
}
|
|
259
|
+
export function handleFallbackFalse(internalEvent, prerenderManifest) {
|
|
260
|
+
const { rawPath } = internalEvent;
|
|
261
|
+
const { dynamicRoutes, routes } = prerenderManifest;
|
|
262
|
+
const routeFallback = Object.entries(dynamicRoutes)
|
|
263
|
+
.filter(([, { fallback }]) => fallback === false)
|
|
264
|
+
.some(([, { routeRegex }]) => {
|
|
265
|
+
const routeRegexExp = new RegExp(routeRegex);
|
|
266
|
+
return routeRegexExp.test(rawPath);
|
|
267
|
+
});
|
|
268
|
+
const locales = NextConfig.i18n?.locales;
|
|
269
|
+
const routesAlreadyHaveLocale = (locales !== undefined && locales.includes(rawPath.split("/")[1])) ||
|
|
270
|
+
// If we don't use locales, we don't need to add the default locale
|
|
271
|
+
locales === undefined;
|
|
272
|
+
const localizedPath = routesAlreadyHaveLocale
|
|
273
|
+
? rawPath
|
|
274
|
+
: `/${NextConfig.i18n?.defaultLocale}${rawPath}`;
|
|
275
|
+
const isPregenerated = Object.keys(routes).includes(localizedPath);
|
|
276
|
+
if (routeFallback && !isPregenerated) {
|
|
277
|
+
return {
|
|
278
|
+
event: {
|
|
279
|
+
...internalEvent,
|
|
280
|
+
rawPath: "/404",
|
|
281
|
+
url: "/404",
|
|
282
|
+
headers: {
|
|
283
|
+
...internalEvent.headers,
|
|
284
|
+
"x-invoke-status": "404",
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
isISR: false,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
event: internalEvent,
|
|
292
|
+
isISR: routeFallback || isPregenerated,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { InternalEvent, InternalResult } from "../../types/open-next.js";
|
|
2
|
+
type MiddlewareOutputEvent = InternalEvent & {
|
|
3
|
+
responseHeaders?: Record<string, string | string[]>;
|
|
4
|
+
externalRewrite?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function handleMiddleware(internalEvent: InternalEvent): Promise<MiddlewareOutputEvent | InternalResult>;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { MiddlewareManifest, NextConfig } from "../../adapters/config/index.js";
|
|
2
|
+
import { emptyReadableStream } from "../../utils/stream.js";
|
|
3
|
+
import { localizePath } from "./i18n/index.js";
|
|
4
|
+
//NOTE: we should try to avoid importing stuff from next as much as possible
|
|
5
|
+
// every release of next could break this
|
|
6
|
+
// const { run } = require("next/dist/server/web/sandbox");
|
|
7
|
+
// const { getCloneableBody } = require("next/dist/server/body-streams");
|
|
8
|
+
// const {
|
|
9
|
+
// signalFromNodeResponse,
|
|
10
|
+
// } = require("next/dist/server/web/spec-extension/adapters/next-request");
|
|
11
|
+
import { convertBodyToReadableStream, convertToQueryString, getMiddlewareMatch, isExternal, } from "./util.js";
|
|
12
|
+
const middlewareManifest = MiddlewareManifest;
|
|
13
|
+
const middleMatch = getMiddlewareMatch(middlewareManifest);
|
|
14
|
+
// NOTE: As of Nextjs 13.4.13+, the middleware is handled outside the next-server.
|
|
15
|
+
// OpenNext will run the middleware in a sandbox and set the appropriate req headers
|
|
16
|
+
// and res.body prior to processing the next-server.
|
|
17
|
+
// @returns undefined | res.end()
|
|
18
|
+
// if res.end() is return, the parent needs to return and not process next server
|
|
19
|
+
export async function handleMiddleware(internalEvent) {
|
|
20
|
+
const { query } = internalEvent;
|
|
21
|
+
const normalizedPath = localizePath(internalEvent);
|
|
22
|
+
// We only need the normalizedPath to check if the middleware should run
|
|
23
|
+
const hasMatch = middleMatch.some((r) => r.test(normalizedPath));
|
|
24
|
+
if (!hasMatch)
|
|
25
|
+
return internalEvent;
|
|
26
|
+
// We bypass the middleware if the request is internal
|
|
27
|
+
if (internalEvent.headers["x-isr"])
|
|
28
|
+
return internalEvent;
|
|
29
|
+
const host = internalEvent.headers.host
|
|
30
|
+
? `https://${internalEvent.headers.host}`
|
|
31
|
+
: "http://localhost:3000";
|
|
32
|
+
const initialUrl = new URL(normalizedPath, host);
|
|
33
|
+
initialUrl.search = convertToQueryString(query);
|
|
34
|
+
const url = initialUrl.toString();
|
|
35
|
+
// console.log("url", url, normalizedPath);
|
|
36
|
+
// @ts-expect-error - This is bundled
|
|
37
|
+
const middleware = await import("./middleware.mjs");
|
|
38
|
+
const result = await middleware.default({
|
|
39
|
+
geo: {
|
|
40
|
+
city: internalEvent.headers["x-open-next-city"],
|
|
41
|
+
country: internalEvent.headers["x-open-next-country"],
|
|
42
|
+
region: internalEvent.headers["x-open-next-region"],
|
|
43
|
+
latitude: internalEvent.headers["x-open-next-latitude"],
|
|
44
|
+
longitude: internalEvent.headers["x-open-next-longitude"],
|
|
45
|
+
},
|
|
46
|
+
headers: internalEvent.headers,
|
|
47
|
+
method: internalEvent.method || "GET",
|
|
48
|
+
nextConfig: {
|
|
49
|
+
basePath: NextConfig.basePath,
|
|
50
|
+
i18n: NextConfig.i18n,
|
|
51
|
+
trailingSlash: NextConfig.trailingSlash,
|
|
52
|
+
},
|
|
53
|
+
url,
|
|
54
|
+
body: convertBodyToReadableStream(internalEvent.method, internalEvent.body),
|
|
55
|
+
});
|
|
56
|
+
const statusCode = result.status;
|
|
57
|
+
/* Apply override headers from middleware
|
|
58
|
+
NextResponse.next({
|
|
59
|
+
request: {
|
|
60
|
+
headers: new Headers(request.headers),
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
Nextjs will set `x-middleware-override-headers` as a comma separated list of keys.
|
|
64
|
+
All the keys will be prefixed with `x-middleware-request-<key>`
|
|
65
|
+
|
|
66
|
+
We can delete `x-middleware-override-headers` and check if the key starts with
|
|
67
|
+
x-middleware-request- to set the req headers
|
|
68
|
+
*/
|
|
69
|
+
const responseHeaders = result.headers;
|
|
70
|
+
const reqHeaders = {};
|
|
71
|
+
const resHeaders = {};
|
|
72
|
+
responseHeaders.delete("x-middleware-override-headers");
|
|
73
|
+
const xMiddlewareKey = "x-middleware-request-";
|
|
74
|
+
responseHeaders.forEach((value, key) => {
|
|
75
|
+
if (key.startsWith(xMiddlewareKey)) {
|
|
76
|
+
const k = key.substring(xMiddlewareKey.length);
|
|
77
|
+
reqHeaders[k] = value;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
if (key.toLowerCase() === "set-cookie") {
|
|
81
|
+
resHeaders[key] = resHeaders[key]
|
|
82
|
+
? [...resHeaders[key], value]
|
|
83
|
+
: [value];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
resHeaders[key] = value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// If the middleware returned a Redirect, we set the `Location` header with
|
|
91
|
+
// the redirected url and end the response.
|
|
92
|
+
if (statusCode >= 300 && statusCode < 400) {
|
|
93
|
+
resHeaders.location =
|
|
94
|
+
responseHeaders
|
|
95
|
+
.get("location")
|
|
96
|
+
?.replace("http://localhost:3000", `https://${internalEvent.headers.host}`) ?? resHeaders.location;
|
|
97
|
+
// res.setHeader("Location", location);
|
|
98
|
+
return {
|
|
99
|
+
body: emptyReadableStream(),
|
|
100
|
+
type: internalEvent.type,
|
|
101
|
+
statusCode: statusCode,
|
|
102
|
+
headers: resHeaders,
|
|
103
|
+
isBase64Encoded: false,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// If the middleware returned a Rewrite, set the `url` to the pathname of the rewrite
|
|
107
|
+
// NOTE: the header was added to `req` from above
|
|
108
|
+
const rewriteUrl = responseHeaders.get("x-middleware-rewrite");
|
|
109
|
+
let rewritten = false;
|
|
110
|
+
let externalRewrite = false;
|
|
111
|
+
let middlewareQueryString = internalEvent.query;
|
|
112
|
+
let newUrl = internalEvent.url;
|
|
113
|
+
if (rewriteUrl) {
|
|
114
|
+
// If not a string, it should probably throw
|
|
115
|
+
if (isExternal(rewriteUrl, internalEvent.headers.host)) {
|
|
116
|
+
newUrl = rewriteUrl;
|
|
117
|
+
rewritten = true;
|
|
118
|
+
externalRewrite = true;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const rewriteUrlObject = new URL(rewriteUrl);
|
|
122
|
+
newUrl = rewriteUrlObject.pathname;
|
|
123
|
+
// Reset the query params if the middleware is a rewrite
|
|
124
|
+
if (middlewareQueryString["__nextDataReq"]) {
|
|
125
|
+
middlewareQueryString = {
|
|
126
|
+
__nextDataReq: middlewareQueryString["__nextDataReq"],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
middlewareQueryString = {};
|
|
131
|
+
}
|
|
132
|
+
rewriteUrlObject.searchParams.forEach((v, k) => {
|
|
133
|
+
middlewareQueryString[k] = v;
|
|
134
|
+
});
|
|
135
|
+
rewritten = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// If the middleware returned a `NextResponse`, pipe the body to res. This will return
|
|
139
|
+
// the body immediately to the client.
|
|
140
|
+
if (result.body) {
|
|
141
|
+
// transfer response body to res
|
|
142
|
+
const body = result.body;
|
|
143
|
+
// await pipeReadable(result.response.body, res);
|
|
144
|
+
return {
|
|
145
|
+
type: internalEvent.type,
|
|
146
|
+
statusCode: statusCode,
|
|
147
|
+
headers: resHeaders,
|
|
148
|
+
body,
|
|
149
|
+
isBase64Encoded: false,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
responseHeaders: resHeaders,
|
|
154
|
+
url: newUrl,
|
|
155
|
+
rawPath: rewritten
|
|
156
|
+
? newUrl ?? internalEvent.rawPath
|
|
157
|
+
: internalEvent.rawPath,
|
|
158
|
+
type: internalEvent.type,
|
|
159
|
+
headers: { ...internalEvent.headers, ...reqHeaders },
|
|
160
|
+
body: internalEvent.body,
|
|
161
|
+
method: internalEvent.method,
|
|
162
|
+
query: middlewareQueryString,
|
|
163
|
+
cookies: internalEvent.cookies,
|
|
164
|
+
remoteAddress: internalEvent.remoteAddress,
|
|
165
|
+
externalRewrite,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { OutgoingHttpHeaders } from "node:http";
|
|
4
|
+
import type { IncomingMessage, StreamCreator } from "../../http/index.js";
|
|
5
|
+
import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
|
|
6
|
+
import type { MiddlewareManifest } from "../../types/next-types";
|
|
7
|
+
import { InternalEvent, InternalResult } from "../../types/open-next.js";
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @__PURE__
|
|
11
|
+
*/
|
|
12
|
+
export declare function isExternal(url?: string, host?: string): boolean;
|
|
13
|
+
export declare function convertFromQueryString(query: string): Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @__PURE__
|
|
17
|
+
*/
|
|
18
|
+
export declare function getUrlParts(url: string, isExternal: boolean): {
|
|
19
|
+
hostname: string;
|
|
20
|
+
pathname: string;
|
|
21
|
+
protocol: string;
|
|
22
|
+
queryString: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @__PURE__
|
|
27
|
+
*/
|
|
28
|
+
export declare function convertRes(res: OpenNextNodeResponse): InternalResult;
|
|
29
|
+
/**
|
|
30
|
+
* Make sure that multi-value query parameters are transformed to
|
|
31
|
+
* ?key=value1&key=value2&... so that Next converts those parameters
|
|
32
|
+
* to an array when reading the query parameters
|
|
33
|
+
* @__PURE__
|
|
34
|
+
*/
|
|
35
|
+
export declare function convertToQueryString(query: Record<string, string | string[]>): string;
|
|
36
|
+
/**
|
|
37
|
+
* Given a raw query string, returns a record with key value-array pairs
|
|
38
|
+
* similar to how multiValueQueryStringParameters are structured
|
|
39
|
+
* @__PURE__
|
|
40
|
+
*/
|
|
41
|
+
export declare function convertToQuery(querystring: string): Record<string, string | string[]>;
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @__PURE__
|
|
45
|
+
*/
|
|
46
|
+
export declare function getMiddlewareMatch(middlewareManifest: MiddlewareManifest): RegExp[];
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @__PURE__
|
|
50
|
+
*/
|
|
51
|
+
export declare function escapeRegex(str: string): string;
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @__PURE__
|
|
55
|
+
*/
|
|
56
|
+
export declare function unescapeRegex(str: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* @__PURE__
|
|
59
|
+
*/
|
|
60
|
+
export declare function convertBodyToReadableStream(method: string, body?: string | Buffer): ReadableStream<any> | undefined;
|
|
61
|
+
/**
|
|
62
|
+
*
|
|
63
|
+
* @__PURE__
|
|
64
|
+
*/
|
|
65
|
+
export declare function proxyRequest(internalEvent: InternalEvent, res: OpenNextNodeResponse): Promise<void>;
|
|
66
|
+
declare global {
|
|
67
|
+
var openNextDebug: boolean;
|
|
68
|
+
var openNextVersion: string;
|
|
69
|
+
var lastModified: Record<string, number>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* @__PURE__
|
|
74
|
+
*/
|
|
75
|
+
export declare function fixCacheHeaderForHtmlPages(rawPath: string, headers: OutgoingHttpHeaders): void;
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @__PURE__
|
|
79
|
+
*/
|
|
80
|
+
export declare function fixSWRCacheHeader(headers: OutgoingHttpHeaders): void;
|
|
81
|
+
/**
|
|
82
|
+
*
|
|
83
|
+
* @__PURE__
|
|
84
|
+
*/
|
|
85
|
+
export declare function addOpenNextHeader(headers: OutgoingHttpHeaders): void;
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @__PURE__
|
|
89
|
+
*/
|
|
90
|
+
export declare function revalidateIfRequired(host: string, rawPath: string, headers: OutgoingHttpHeaders, req?: IncomingMessage): Promise<void>;
|
|
91
|
+
export declare function generateMessageGroupId(rawPath: string): string;
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @__PURE__
|
|
95
|
+
*/
|
|
96
|
+
export declare function fixISRHeaders(headers: OutgoingHttpHeaders): void;
|
|
97
|
+
/**
|
|
98
|
+
*
|
|
99
|
+
* @param internalEvent
|
|
100
|
+
* @param headers
|
|
101
|
+
* @param responseStream
|
|
102
|
+
* @returns
|
|
103
|
+
* @__PURE__
|
|
104
|
+
*/
|
|
105
|
+
export declare function createServerResponse(internalEvent: InternalEvent, headers: Record<string, string | string[] | undefined>, responseStream?: StreamCreator): OpenNextNodeResponse;
|