@opennextjs/aws 3.3.0 → 3.4.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/dist/adapters/cache.d.ts +1 -2
- package/dist/adapters/cache.js +20 -11
- package/dist/adapters/config/index.d.ts +2 -0
- package/dist/adapters/config/index.js +4 -3
- package/dist/adapters/config/util.d.ts +2 -0
- package/dist/adapters/config/util.js +12 -2
- package/dist/adapters/middleware.js +13 -2
- package/dist/adapters/util.js +5 -1
- package/dist/build/createAssets.js +22 -23
- package/dist/build/createImageOptimizationBundle.js +2 -1
- package/dist/build/createServerBundle.js +4 -4
- package/dist/build/edge/createEdgeBundle.d.ts +4 -3
- package/dist/build/edge/createEdgeBundle.js +14 -22
- package/dist/build/validateConfig.js +2 -1
- package/dist/core/createMainHandler.js +2 -1
- package/dist/core/requestHandler.js +24 -6
- package/dist/core/resolve.d.ts +4 -0
- package/dist/core/resolve.js +10 -0
- package/dist/core/routing/middleware.js +3 -1
- package/dist/core/routing/routeMatcher.d.ts +10 -0
- package/dist/core/routing/routeMatcher.js +45 -0
- package/dist/core/routing/util.d.ts +4 -3
- package/dist/core/routing/util.js +24 -5
- package/dist/core/routingHandler.d.ts +3 -0
- package/dist/core/routingHandler.js +30 -29
- package/dist/overrides/cdnInvalidation/cloudfront.d.ts +9 -0
- package/dist/overrides/cdnInvalidation/cloudfront.js +26 -0
- package/dist/overrides/cdnInvalidation/dummy.d.ts +9 -0
- package/dist/overrides/cdnInvalidation/dummy.js +6 -0
- package/dist/overrides/imageLoader/fs-dev.d.ts +10 -0
- package/dist/overrides/imageLoader/fs-dev.js +14 -0
- package/dist/overrides/incrementalCache/fs-dev.d.ts +3 -0
- package/dist/overrides/incrementalCache/fs-dev.js +30 -0
- package/dist/overrides/incrementalCache/multi-tier-ddb-s3.d.ts +10 -0
- package/dist/overrides/incrementalCache/multi-tier-ddb-s3.js +120 -0
- package/dist/overrides/incrementalCache/s3-lite.d.ts +2 -0
- package/dist/overrides/incrementalCache/s3-lite.js +1 -1
- package/dist/overrides/proxyExternalRequest/node.js +6 -5
- package/dist/overrides/queue/direct.d.ts +3 -0
- package/dist/overrides/queue/direct.js +18 -0
- package/dist/overrides/tagCache/fs-dev.d.ts +3 -0
- package/dist/overrides/tagCache/fs-dev.js +32 -0
- package/dist/overrides/wrappers/cloudflare-edge.js +11 -4
- package/dist/overrides/wrappers/cloudflare-node.js +4 -1
- package/dist/overrides/wrappers/dummy.d.ts +1 -1
- package/dist/overrides/wrappers/dummy.js +6 -2
- package/dist/overrides/wrappers/express-dev.d.ts +7 -0
- package/dist/overrides/wrappers/express-dev.js +43 -0
- package/dist/plugins/edge.js +10 -4
- package/dist/plugins/replacement.d.ts +1 -1
- package/dist/plugins/replacement.js +1 -1
- package/dist/plugins/resolve.d.ts +1 -0
- package/dist/plugins/resolve.js +4 -1
- package/dist/types/global.d.ts +7 -1
- package/dist/types/open-next.d.ts +19 -6
- package/dist/types/overrides.d.ts +13 -4
- package/dist/utils/lru.d.ts +8 -0
- package/dist/utils/lru.js +29 -0
- package/dist/utils/regex.d.ts +18 -0
- package/dist/utils/regex.js +16 -0
- package/package.json +4 -1
package/dist/adapters/cache.d.ts
CHANGED
|
@@ -58,8 +58,7 @@ interface CacheHandlerValue {
|
|
|
58
58
|
cacheState?: string;
|
|
59
59
|
value: IncrementalCacheValue | null;
|
|
60
60
|
}
|
|
61
|
-
export
|
|
62
|
-
export default class S3Cache {
|
|
61
|
+
export default class Cache {
|
|
63
62
|
get(key: string, options?: boolean | {
|
|
64
63
|
fetchCache?: boolean;
|
|
65
64
|
kindHint?: "app" | "pages" | "fetch";
|
package/dist/adapters/cache.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { isBinaryContentType } from "../utils/binary";
|
|
2
2
|
import { debug, error, warn } from "./logger";
|
|
3
|
-
/** Beginning single backslash is intentional, to look for the dot + the extension. Do not escape it again. */
|
|
4
|
-
const CACHE_EXTENSION_REGEX = /\.(cache|fetch)$/;
|
|
5
|
-
export function hasCacheExtension(key) {
|
|
6
|
-
return CACHE_EXTENSION_REGEX.test(key);
|
|
7
|
-
}
|
|
8
3
|
function isFetchCache(options) {
|
|
9
4
|
if (typeof options === "boolean") {
|
|
10
5
|
return options;
|
|
@@ -17,7 +12,7 @@ function isFetchCache(options) {
|
|
|
17
12
|
return false;
|
|
18
13
|
}
|
|
19
14
|
// We need to use globalThis client here as this class can be defined at load time in next 12 but client is not available at load time
|
|
20
|
-
export default class
|
|
15
|
+
export default class Cache {
|
|
21
16
|
async get(key,
|
|
22
17
|
// fetchCache is for next 13.5 and above, kindHint is for next 14 and above and boolean is for earlier versions
|
|
23
18
|
options) {
|
|
@@ -34,7 +29,6 @@ export default class S3Cache {
|
|
|
34
29
|
debug("get fetch cache", { key, softTags, tags });
|
|
35
30
|
try {
|
|
36
31
|
const { value, lastModified } = await globalThis.incrementalCache.get(key, true);
|
|
37
|
-
// const { Body, LastModified } = await this.getS3Object(key, "fetch");
|
|
38
32
|
const _lastModified = await globalThis.tagCache.getLastModified(key, lastModified);
|
|
39
33
|
if (_lastModified === -1) {
|
|
40
34
|
// If some tags are stale we need to force revalidation
|
|
@@ -71,10 +65,6 @@ export default class S3Cache {
|
|
|
71
65
|
async getIncrementalCache(key) {
|
|
72
66
|
try {
|
|
73
67
|
const { value: cacheData, lastModified } = await globalThis.incrementalCache.get(key, false);
|
|
74
|
-
// const { Body, LastModified } = await this.getS3Object(key, "cache");
|
|
75
|
-
// const cacheData = JSON.parse(
|
|
76
|
-
// (await Body?.transformToString()) ?? "{}",
|
|
77
|
-
// ) as S3CachedFile;
|
|
78
68
|
const meta = cacheData?.meta;
|
|
79
69
|
const _lastModified = await globalThis.tagCache.getLastModified(key, lastModified);
|
|
80
70
|
if (_lastModified === -1) {
|
|
@@ -285,6 +275,25 @@ export default class S3Cache {
|
|
|
285
275
|
}
|
|
286
276
|
// Update all keys with the given tag with revalidatedAt set to now
|
|
287
277
|
await globalThis.tagCache.writeTags(toInsert);
|
|
278
|
+
// We can now invalidate all paths in the CDN
|
|
279
|
+
// This only applies to `revalidateTag`, not to `res.revalidate()`
|
|
280
|
+
const uniquePaths = Array.from(new Set(toInsert
|
|
281
|
+
// We need to filter fetch cache key as they are not in the CDN
|
|
282
|
+
.filter((t) => t.tag.startsWith("_N_T_/"))
|
|
283
|
+
.map((t) => `/${t.path}`)));
|
|
284
|
+
if (uniquePaths.length > 0) {
|
|
285
|
+
await globalThis.cdnInvalidationHandler.invalidatePaths(uniquePaths.map((path) => ({
|
|
286
|
+
initialPath: path,
|
|
287
|
+
rawPath: path,
|
|
288
|
+
resolvedRoutes: [
|
|
289
|
+
{
|
|
290
|
+
route: path,
|
|
291
|
+
// TODO: ideally here we should check if it's an app router page or route
|
|
292
|
+
type: "app",
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
})));
|
|
296
|
+
}
|
|
288
297
|
}
|
|
289
298
|
}
|
|
290
299
|
catch (e) {
|
|
@@ -25,3 +25,5 @@ export declare const ConfigHeaders: import("../../types/next-types").Header[] |
|
|
|
25
25
|
export declare const PrerenderManifest: import("../../types/next-types").PrerenderManifest;
|
|
26
26
|
export declare const AppPathsManifestKeys: string[];
|
|
27
27
|
export declare const MiddlewareManifest: import("../../types/next-types").MiddlewareManifest;
|
|
28
|
+
export declare const AppPathsManifest: Record<string, string>;
|
|
29
|
+
export declare const AppPathRoutesManifest: Record<string, string>;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { debug } from "../logger";
|
|
3
|
-
import { loadAppPathsManifestKeys, loadBuildId, loadConfig, loadConfigHeaders, loadHtmlPages, loadMiddlewareManifest, loadPrerenderManifest,
|
|
4
|
-
// loadPublicAssets,
|
|
5
|
-
loadRoutesManifest, } from "./util.js";
|
|
3
|
+
import { loadAppPathRoutesManifest, loadAppPathsManifest, loadAppPathsManifestKeys, loadBuildId, loadConfig, loadConfigHeaders, loadHtmlPages, loadMiddlewareManifest, loadPrerenderManifest, loadRoutesManifest, } from "./util.js";
|
|
6
4
|
export const NEXT_DIR = path.join(__dirname, ".next");
|
|
7
5
|
export const OPEN_NEXT_DIR = path.join(__dirname, ".open-next");
|
|
8
6
|
debug({ NEXT_DIR, OPEN_NEXT_DIR });
|
|
@@ -19,3 +17,6 @@ export const AppPathsManifestKeys =
|
|
|
19
17
|
/* @__PURE__ */ loadAppPathsManifestKeys(NEXT_DIR);
|
|
20
18
|
export const MiddlewareManifest =
|
|
21
19
|
/* @__PURE__ */ loadMiddlewareManifest(NEXT_DIR);
|
|
20
|
+
export const AppPathsManifest = /* @__PURE__ */ loadAppPathsManifest(NEXT_DIR);
|
|
21
|
+
export const AppPathRoutesManifest =
|
|
22
|
+
/* @__PURE__ */ loadAppPathRoutesManifest(NEXT_DIR);
|
|
@@ -24,5 +24,7 @@ export declare function loadRoutesManifest(nextDir: string): {
|
|
|
24
24
|
};
|
|
25
25
|
export declare function loadConfigHeaders(nextDir: string): import("../../types/next-types").Header[] | undefined;
|
|
26
26
|
export declare function loadPrerenderManifest(nextDir: string): PrerenderManifest;
|
|
27
|
+
export declare function loadAppPathsManifest(nextDir: string): Record<string, string>;
|
|
28
|
+
export declare function loadAppPathRoutesManifest(nextDir: string): Record<string, string>;
|
|
27
29
|
export declare function loadAppPathsManifestKeys(nextDir: string): string[];
|
|
28
30
|
export declare function loadMiddlewareManifest(nextDir: string): MiddlewareManifest;
|
|
@@ -60,12 +60,22 @@ export function loadPrerenderManifest(nextDir) {
|
|
|
60
60
|
const json = fs.readFileSync(filePath, "utf-8");
|
|
61
61
|
return JSON.parse(json);
|
|
62
62
|
}
|
|
63
|
-
export function
|
|
63
|
+
export function loadAppPathsManifest(nextDir) {
|
|
64
64
|
const appPathsManifestPath = path.join(nextDir, "server", "app-paths-manifest.json");
|
|
65
65
|
const appPathsManifestJson = fs.existsSync(appPathsManifestPath)
|
|
66
66
|
? fs.readFileSync(appPathsManifestPath, "utf-8")
|
|
67
67
|
: "{}";
|
|
68
|
-
|
|
68
|
+
return JSON.parse(appPathsManifestJson);
|
|
69
|
+
}
|
|
70
|
+
export function loadAppPathRoutesManifest(nextDir) {
|
|
71
|
+
const appPathRoutesManifestPath = path.join(nextDir, "app-path-routes-manifest.json");
|
|
72
|
+
if (fs.existsSync(appPathRoutesManifestPath)) {
|
|
73
|
+
return JSON.parse(fs.readFileSync(appPathRoutesManifestPath, "utf-8"));
|
|
74
|
+
}
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
export function loadAppPathsManifestKeys(nextDir) {
|
|
78
|
+
const appPathsManifest = loadAppPathsManifest(nextDir);
|
|
69
79
|
return Object.keys(appPathsManifest).map((key) => {
|
|
70
80
|
// Remove parallel route
|
|
71
81
|
let cleanedKey = key.replace(/\/@[^\/]+/g, "");
|
|
@@ -2,7 +2,7 @@ import { runWithOpenNextRequestContext } from "../utils/promise";
|
|
|
2
2
|
import { debug, error } from "../adapters/logger";
|
|
3
3
|
import { createGenericHandler } from "../core/createGenericHandler";
|
|
4
4
|
import { resolveIncrementalCache, resolveOriginResolver, resolveProxyRequest, resolveQueue, resolveTagCache, } from "../core/resolve";
|
|
5
|
-
import routingHandler from "../core/routingHandler";
|
|
5
|
+
import routingHandler, { INTERNAL_HEADER_INITIAL_PATH, INTERNAL_HEADER_RESOLVED_ROUTES, } from "../core/routingHandler";
|
|
6
6
|
globalThis.internalFetch = fetch;
|
|
7
7
|
globalThis.__openNextAls = new AsyncLocalStorage();
|
|
8
8
|
const defaultHandler = async (internalEvent) => {
|
|
@@ -22,10 +22,19 @@ const defaultHandler = async (internalEvent) => {
|
|
|
22
22
|
const origin = await originResolver.resolve(result.internalEvent.rawPath);
|
|
23
23
|
return {
|
|
24
24
|
type: "middleware",
|
|
25
|
-
internalEvent:
|
|
25
|
+
internalEvent: {
|
|
26
|
+
...result.internalEvent,
|
|
27
|
+
headers: {
|
|
28
|
+
...result.internalEvent.headers,
|
|
29
|
+
[INTERNAL_HEADER_INITIAL_PATH]: internalEvent.rawPath,
|
|
30
|
+
[INTERNAL_HEADER_RESOLVED_ROUTES]: JSON.stringify(result.resolvedRoutes) ?? "[]",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
26
33
|
isExternalRewrite: result.isExternalRewrite,
|
|
27
34
|
origin,
|
|
28
35
|
isISR: result.isISR,
|
|
36
|
+
initialPath: result.initialPath,
|
|
37
|
+
resolvedRoutes: result.resolvedRoutes,
|
|
29
38
|
};
|
|
30
39
|
}
|
|
31
40
|
try {
|
|
@@ -45,6 +54,8 @@ const defaultHandler = async (internalEvent) => {
|
|
|
45
54
|
isExternalRewrite: false,
|
|
46
55
|
origin: false,
|
|
47
56
|
isISR: result.isISR,
|
|
57
|
+
initialPath: result.internalEvent.rawPath,
|
|
58
|
+
resolvedRoutes: [{ route: "/500", type: "page" }],
|
|
48
59
|
};
|
|
49
60
|
}
|
|
50
61
|
}
|
package/dist/adapters/util.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
//TODO: We should probably move all the utils to a separate location
|
|
2
2
|
export function setNodeEnv() {
|
|
3
|
-
|
|
3
|
+
// Note: we create a `processEnv` variable instead of just using `process.env` directly
|
|
4
|
+
// because build tools can substitute `process.env.NODE_ENV` on build making
|
|
5
|
+
// assignments such as `process.env.NODE_ENV = ...` problematic
|
|
6
|
+
const processEnv = process.env;
|
|
7
|
+
processEnv.NODE_ENV = process.env.NODE_ENV ?? "production";
|
|
4
8
|
}
|
|
5
9
|
export function generateUniqueId() {
|
|
6
10
|
return Math.random().toString(36).slice(2, 8);
|
|
@@ -109,10 +109,29 @@ export function createCacheAssets(options) {
|
|
|
109
109
|
};
|
|
110
110
|
fs.writeFileSync(cacheFilePath, JSON.stringify(cacheFileContent));
|
|
111
111
|
});
|
|
112
|
+
// We need to traverse the cache to find every .meta file
|
|
113
|
+
const metaFiles = [];
|
|
114
|
+
// Copy fetch-cache to cache folder
|
|
115
|
+
const fetchCachePath = path.join(appBuildOutputPath, ".next/cache/fetch-cache");
|
|
116
|
+
if (fs.existsSync(fetchCachePath)) {
|
|
117
|
+
const fetchOutputPath = path.join(outputDir, "cache", "__fetch", buildId);
|
|
118
|
+
fs.mkdirSync(fetchOutputPath, { recursive: true });
|
|
119
|
+
fs.cpSync(fetchCachePath, fetchOutputPath, { recursive: true });
|
|
120
|
+
buildHelper.traverseFiles(fetchCachePath, () => true, ({ absolutePath, relativePath }) => {
|
|
121
|
+
const fileContent = fs.readFileSync(absolutePath, "utf8");
|
|
122
|
+
const fileData = JSON.parse(fileContent);
|
|
123
|
+
fileData?.tags?.forEach((tag) => {
|
|
124
|
+
metaFiles.push({
|
|
125
|
+
tag: { S: path.posix.join(buildId, tag) },
|
|
126
|
+
path: {
|
|
127
|
+
S: path.posix.join(buildId, relativePath),
|
|
128
|
+
},
|
|
129
|
+
revalidatedAt: { N: "1" },
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
112
134
|
if (!options.config.dangerous?.disableTagCache) {
|
|
113
|
-
// Generate dynamodb data
|
|
114
|
-
// We need to traverse the cache to find every .meta file
|
|
115
|
-
const metaFiles = [];
|
|
116
135
|
// Compute dynamodb cache data
|
|
117
136
|
// Traverse files inside cache to find all meta files and cache tags associated with them
|
|
118
137
|
buildHelper.traverseFiles(outputPath, ({ absolutePath }) => absolutePath.endsWith(".meta"), ({ absolutePath, relativePath }) => {
|
|
@@ -134,26 +153,6 @@ export function createCacheAssets(options) {
|
|
|
134
153
|
});
|
|
135
154
|
}
|
|
136
155
|
});
|
|
137
|
-
// Copy fetch-cache to cache folder
|
|
138
|
-
const fetchCachePath = path.join(appBuildOutputPath, ".next/cache/fetch-cache");
|
|
139
|
-
if (fs.existsSync(fetchCachePath)) {
|
|
140
|
-
const fetchOutputPath = path.join(outputDir, "cache", "__fetch", buildId);
|
|
141
|
-
fs.mkdirSync(fetchOutputPath, { recursive: true });
|
|
142
|
-
fs.cpSync(fetchCachePath, fetchOutputPath, { recursive: true });
|
|
143
|
-
buildHelper.traverseFiles(fetchCachePath, () => true, ({ absolutePath, relativePath }) => {
|
|
144
|
-
const fileContent = fs.readFileSync(absolutePath, "utf8");
|
|
145
|
-
const fileData = JSON.parse(fileContent);
|
|
146
|
-
fileData?.tags?.forEach((tag) => {
|
|
147
|
-
metaFiles.push({
|
|
148
|
-
tag: { S: path.posix.join(buildId, tag) },
|
|
149
|
-
path: {
|
|
150
|
-
S: path.posix.join(buildId, relativePath),
|
|
151
|
-
},
|
|
152
|
-
revalidatedAt: { N: "1" },
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
156
|
if (metaFiles.length > 0) {
|
|
158
157
|
useTagCache = true;
|
|
159
158
|
const providerPath = path.join(outputDir, "dynamodb-provider");
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import logger from "../logger.js";
|
|
5
5
|
import { openNextReplacementPlugin } from "../plugins/replacement.js";
|
|
6
6
|
import { openNextResolvePlugin } from "../plugins/resolve.js";
|
|
7
|
+
import { getCrossPlatformPathRegex } from "../utils/regex.js";
|
|
7
8
|
import * as buildHelper from "./helper.js";
|
|
8
9
|
import { installDependencies } from "./installDeps.js";
|
|
9
10
|
const require = createRequire(import.meta.url);
|
|
@@ -28,7 +29,7 @@ export async function createImageOptimizationBundle(options) {
|
|
|
28
29
|
if (buildHelper.compareSemver(options.nextVersion, "14.1.1") >= 0) {
|
|
29
30
|
plugins.push(openNextReplacementPlugin({
|
|
30
31
|
name: "opennext-14.1.1-image-optimization",
|
|
31
|
-
target: /
|
|
32
|
+
target: getCrossPlatformPathRegex("plugins/image-optimization/image-optimization.js"),
|
|
32
33
|
replacements: [
|
|
33
34
|
require.resolve("../adapters/plugins/image-optimization/image-optimization.replacement.js"),
|
|
34
35
|
],
|
|
@@ -4,6 +4,7 @@ import logger from "../logger.js";
|
|
|
4
4
|
import { minifyAll } from "../minimize-js.js";
|
|
5
5
|
import { openNextReplacementPlugin } from "../plugins/replacement.js";
|
|
6
6
|
import { openNextResolvePlugin } from "../plugins/resolve.js";
|
|
7
|
+
import { getCrossPlatformPathRegex } from "../utils/regex.js";
|
|
7
8
|
import { bundleNextServer } from "./bundleNextServer.js";
|
|
8
9
|
import { compileCache } from "./compileCache.js";
|
|
9
10
|
import { copyTracedFiles } from "./copyTracedFiles.js";
|
|
@@ -114,7 +115,7 @@ async function generateBundle(name, options, fnOptions) {
|
|
|
114
115
|
const plugins = [
|
|
115
116
|
openNextReplacementPlugin({
|
|
116
117
|
name: `requestHandlerOverride ${name}`,
|
|
117
|
-
target: /
|
|
118
|
+
target: getCrossPlatformPathRegex("core/requestHandler.js"),
|
|
118
119
|
deletes: [
|
|
119
120
|
...(disableNextPrebundledReact ? ["applyNextjsPrebundledReact"] : []),
|
|
120
121
|
...(disableRouting ? ["withRouting"] : []),
|
|
@@ -122,11 +123,10 @@ async function generateBundle(name, options, fnOptions) {
|
|
|
122
123
|
}),
|
|
123
124
|
openNextReplacementPlugin({
|
|
124
125
|
name: `utilOverride ${name}`,
|
|
125
|
-
target: /
|
|
126
|
+
target: getCrossPlatformPathRegex("core/util.js"),
|
|
126
127
|
deletes: [
|
|
127
128
|
...(disableNextPrebundledReact ? ["requireHooks"] : []),
|
|
128
|
-
...(
|
|
129
|
-
...(!isBefore13413 ? ["requestHandlerHost"] : []),
|
|
129
|
+
...(isBefore13413 ? ["trustHostHeader"] : ["requestHandlerHost"]),
|
|
130
130
|
...(isAfter141
|
|
131
131
|
? ["experimentalIncrementalCacheHandler"]
|
|
132
132
|
: ["stableIncrementalCache"]),
|
|
@@ -2,14 +2,15 @@ import type { MiddlewareInfo } from "../../types/next-types";
|
|
|
2
2
|
import type { IncludedConverter, IncludedOriginResolver, LazyLoadedOverride, OverrideOptions, SplittedFunctionOptions } from "../../types/open-next";
|
|
3
3
|
import type { OriginResolver } from "../../types/overrides.js";
|
|
4
4
|
import { type BuildOptions } from "../helper.js";
|
|
5
|
+
type Override = OverrideOptions & {
|
|
6
|
+
originResolver?: LazyLoadedOverride<OriginResolver> | IncludedOriginResolver;
|
|
7
|
+
};
|
|
5
8
|
interface BuildEdgeBundleOptions {
|
|
6
9
|
middlewareInfo?: MiddlewareInfo;
|
|
7
10
|
entrypoint: string;
|
|
8
11
|
outfile: string;
|
|
9
12
|
options: BuildOptions;
|
|
10
|
-
overrides?:
|
|
11
|
-
originResolver?: LazyLoadedOverride<OriginResolver> | IncludedOriginResolver;
|
|
12
|
-
};
|
|
13
|
+
overrides?: Override;
|
|
13
14
|
defaultConverter?: IncludedConverter;
|
|
14
15
|
additionalInject?: string;
|
|
15
16
|
includeCache?: boolean;
|
|
@@ -6,10 +6,16 @@ import logger from "../../logger.js";
|
|
|
6
6
|
import { openNextEdgePlugins } from "../../plugins/edge.js";
|
|
7
7
|
import { openNextReplacementPlugin } from "../../plugins/replacement.js";
|
|
8
8
|
import { openNextResolvePlugin } from "../../plugins/resolve.js";
|
|
9
|
+
import { getCrossPlatformPathRegex } from "../../utils/regex.js";
|
|
9
10
|
import { isEdgeRuntime } from "../helper.js";
|
|
10
11
|
import { copyOpenNextConfig, esbuildAsync } from "../helper.js";
|
|
11
12
|
export async function buildEdgeBundle({ middlewareInfo, entrypoint, outfile, options, defaultConverter, overrides, additionalInject, includeCache, additionalExternals, onlyBuildOnce, name, }) {
|
|
12
13
|
const isInCloudfare = await isEdgeRuntime(overrides);
|
|
14
|
+
function override(target) {
|
|
15
|
+
return typeof overrides?.[target] === "string"
|
|
16
|
+
? overrides[target]
|
|
17
|
+
: undefined;
|
|
18
|
+
}
|
|
13
19
|
await esbuildAsync({
|
|
14
20
|
entryPoints: [entrypoint],
|
|
15
21
|
bundle: true,
|
|
@@ -20,37 +26,23 @@ export async function buildEdgeBundle({ middlewareInfo, entrypoint, outfile, opt
|
|
|
20
26
|
plugins: [
|
|
21
27
|
openNextResolvePlugin({
|
|
22
28
|
overrides: {
|
|
23
|
-
wrapper:
|
|
24
|
-
|
|
25
|
-
: "aws-lambda",
|
|
26
|
-
converter: typeof overrides?.converter === "string"
|
|
27
|
-
? overrides.converter
|
|
28
|
-
: defaultConverter,
|
|
29
|
+
wrapper: override("wrapper") ?? "aws-lambda",
|
|
30
|
+
converter: override("converter") ?? defaultConverter,
|
|
29
31
|
...(includeCache
|
|
30
32
|
? {
|
|
31
|
-
tagCache:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
incrementalCache: typeof overrides?.incrementalCache === "string"
|
|
35
|
-
? overrides.incrementalCache
|
|
36
|
-
: "s3-lite",
|
|
37
|
-
queue: typeof overrides?.queue === "string"
|
|
38
|
-
? overrides.queue
|
|
39
|
-
: "sqs-lite",
|
|
33
|
+
tagCache: override("tagCache") ?? "dynamodb-lite",
|
|
34
|
+
incrementalCache: override("incrementalCache") ?? "s3-lite",
|
|
35
|
+
queue: override("queue") ?? "sqs-lite",
|
|
40
36
|
}
|
|
41
37
|
: {}),
|
|
42
|
-
originResolver:
|
|
43
|
-
|
|
44
|
-
: "pattern-env",
|
|
45
|
-
proxyExternalRequest: typeof overrides?.proxyExternalRequest === "string"
|
|
46
|
-
? overrides.proxyExternalRequest
|
|
47
|
-
: "node",
|
|
38
|
+
originResolver: override("originResolver") ?? "pattern-env",
|
|
39
|
+
proxyExternalRequest: override("proxyExternalRequest") ?? "node",
|
|
48
40
|
},
|
|
49
41
|
fnName: name,
|
|
50
42
|
}),
|
|
51
43
|
openNextReplacementPlugin({
|
|
52
44
|
name: "externalMiddlewareOverrides",
|
|
53
|
-
target: /
|
|
45
|
+
target: getCrossPlatformPathRegex("adapters/middleware.js"),
|
|
54
46
|
deletes: includeCache ? [] : ["includeCacheInMiddleware"],
|
|
55
47
|
}),
|
|
56
48
|
openNextEdgePlugins({
|
|
@@ -11,7 +11,8 @@ const compatibilityMatrix = {
|
|
|
11
11
|
"cloudflare-edge": ["edge"],
|
|
12
12
|
"cloudflare-node": ["edge"],
|
|
13
13
|
node: ["node"],
|
|
14
|
-
|
|
14
|
+
"express-dev": ["node"],
|
|
15
|
+
dummy: ["dummy"],
|
|
15
16
|
};
|
|
16
17
|
function validateFunctionOptions(fnOptions) {
|
|
17
18
|
if (fnOptions.runtime === "edge" && fnOptions.experimentalBundledNextServer) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { debug } from "../adapters/logger";
|
|
2
2
|
import { generateUniqueId } from "../adapters/util";
|
|
3
3
|
import { openNextHandler } from "./requestHandler";
|
|
4
|
-
import { resolveConverter, resolveIncrementalCache, resolveProxyRequest, resolveQueue, resolveTagCache, resolveWrapper, } from "./resolve";
|
|
4
|
+
import { resolveCdnInvalidation, resolveConverter, resolveIncrementalCache, resolveProxyRequest, resolveQueue, resolveTagCache, resolveWrapper, } from "./resolve";
|
|
5
5
|
export async function createMainHandler() {
|
|
6
6
|
// @ts-expect-error `./open-next.config.mjs` exists only in the build output
|
|
7
7
|
const config = await import("./open-next.config.mjs").then((m) => m.default);
|
|
@@ -15,6 +15,7 @@ export async function createMainHandler() {
|
|
|
15
15
|
globalThis.incrementalCache = await resolveIncrementalCache(thisFunction.override?.incrementalCache);
|
|
16
16
|
globalThis.tagCache = await resolveTagCache(thisFunction.override?.tagCache);
|
|
17
17
|
globalThis.proxyExternalRequest = await resolveProxyRequest(thisFunction.override?.proxyExternalRequest);
|
|
18
|
+
globalThis.cdnInvalidationHandler = await resolveCdnInvalidation(thisFunction.override?.cdnInvalidation);
|
|
18
19
|
globalThis.lastModified = {};
|
|
19
20
|
// From the config, we create the converter
|
|
20
21
|
const converter = await resolveConverter(thisFunction.override?.converter);
|
|
@@ -4,23 +4,32 @@ import { runWithOpenNextRequestContext } from "../utils/promise";
|
|
|
4
4
|
import { debug, error, warn } from "../adapters/logger";
|
|
5
5
|
import { patchAsyncStorage } from "./patchAsyncStorage";
|
|
6
6
|
import { convertRes, createServerResponse } from "./routing/util";
|
|
7
|
-
import routingHandler, { MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
|
|
7
|
+
import routingHandler, { INTERNAL_HEADER_INITIAL_PATH, INTERNAL_HEADER_RESOLVED_ROUTES, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
|
|
8
8
|
import { requestHandler, setNextjsPrebundledReact } from "./util";
|
|
9
9
|
// This is used to identify requests in the cache
|
|
10
10
|
globalThis.__openNextAls = new AsyncLocalStorage();
|
|
11
11
|
patchAsyncStorage();
|
|
12
12
|
export async function openNextHandler(internalEvent, responseStreaming) {
|
|
13
|
+
const initialHeaders = internalEvent.headers;
|
|
13
14
|
// We run everything in the async local storage context so that it is available in the middleware as well as in NextServer
|
|
14
|
-
return runWithOpenNextRequestContext({ isISRRevalidation:
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
return runWithOpenNextRequestContext({ isISRRevalidation: initialHeaders["x-isr"] === "1" }, async () => {
|
|
16
|
+
if (initialHeaders["x-forwarded-host"]) {
|
|
17
|
+
initialHeaders.host = initialHeaders["x-forwarded-host"];
|
|
17
18
|
}
|
|
18
19
|
debug("internalEvent", internalEvent);
|
|
20
|
+
// These 2 will get overwritten by the routing handler if not using an external middleware
|
|
21
|
+
const internalHeaders = {
|
|
22
|
+
initialPath: initialHeaders[INTERNAL_HEADER_INITIAL_PATH] ?? internalEvent.rawPath,
|
|
23
|
+
resolvedRoutes: initialHeaders[INTERNAL_HEADER_RESOLVED_ROUTES]
|
|
24
|
+
? JSON.parse(initialHeaders[INTERNAL_HEADER_RESOLVED_ROUTES])
|
|
25
|
+
: [],
|
|
26
|
+
};
|
|
19
27
|
let routingResult = {
|
|
20
28
|
internalEvent,
|
|
21
29
|
isExternalRewrite: false,
|
|
22
30
|
origin: false,
|
|
23
31
|
isISR: false,
|
|
32
|
+
...internalHeaders,
|
|
24
33
|
};
|
|
25
34
|
//#override withRouting
|
|
26
35
|
try {
|
|
@@ -65,13 +74,22 @@ export async function openNextHandler(internalEvent, responseStreaming) {
|
|
|
65
74
|
isExternalRewrite: false,
|
|
66
75
|
isISR: false,
|
|
67
76
|
origin: false,
|
|
77
|
+
initialPath: internalEvent.rawPath,
|
|
78
|
+
resolvedRoutes: [{ route: "/500", type: "page" }],
|
|
68
79
|
};
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
if ("type" in routingResult) {
|
|
72
83
|
// response is used only in the streaming case
|
|
73
84
|
if (responseStreaming) {
|
|
74
|
-
const response = createServerResponse(
|
|
85
|
+
const response = createServerResponse({
|
|
86
|
+
internalEvent,
|
|
87
|
+
isExternalRewrite: false,
|
|
88
|
+
isISR: false,
|
|
89
|
+
resolvedRoutes: [],
|
|
90
|
+
origin: false,
|
|
91
|
+
initialPath: internalEvent.rawPath,
|
|
92
|
+
}, headers, responseStreaming);
|
|
75
93
|
response.statusCode = routingResult.statusCode;
|
|
76
94
|
response.flushHeaders();
|
|
77
95
|
const [bodyToConsume, bodyToReturn] = routingResult.body.tee();
|
|
@@ -106,7 +124,7 @@ export async function openNextHandler(internalEvent, responseStreaming) {
|
|
|
106
124
|
store.mergeHeadersPriority = mergeHeadersPriority;
|
|
107
125
|
}
|
|
108
126
|
const req = new IncomingMessage(reqProps);
|
|
109
|
-
const res = createServerResponse(
|
|
127
|
+
const res = createServerResponse(routingResult, overwrittenResponseHeaders, responseStreaming);
|
|
110
128
|
await processRequest(req, res, preprocessedEvent);
|
|
111
129
|
const { statusCode, headers: responseHeaders, isBase64Encoded, body, } = convertRes(res);
|
|
112
130
|
const internalResult = {
|
package/dist/core/resolve.d.ts
CHANGED
|
@@ -43,4 +43,8 @@ export declare function resolveWarmerInvoke(warmer: RemoveUndefined<OpenNextConf
|
|
|
43
43
|
* @__PURE__
|
|
44
44
|
*/
|
|
45
45
|
export declare function resolveProxyRequest(proxyRequest: OverrideOptions["proxyExternalRequest"]): Promise<import("../types/overrides").ProxyExternalRequest>;
|
|
46
|
+
/**
|
|
47
|
+
* @__PURE__
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveCdnInvalidation(cdnInvalidation: OverrideOptions["cdnInvalidation"]): Promise<import("../types/overrides").CDNInvalidationHandler>;
|
|
46
50
|
export {};
|
package/dist/core/resolve.js
CHANGED
|
@@ -98,3 +98,13 @@ export async function resolveProxyRequest(proxyRequest) {
|
|
|
98
98
|
const m_1 = await import("../overrides/proxyExternalRequest/node.js");
|
|
99
99
|
return m_1.default;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* @__PURE__
|
|
103
|
+
*/
|
|
104
|
+
export async function resolveCdnInvalidation(cdnInvalidation) {
|
|
105
|
+
if (typeof cdnInvalidation === "function") {
|
|
106
|
+
return cdnInvalidation();
|
|
107
|
+
}
|
|
108
|
+
const m_1 = await import("../overrides/cdnInvalidation/dummy.js");
|
|
109
|
+
return m_1.default;
|
|
110
|
+
}
|
|
@@ -44,7 +44,9 @@ export async function handleMiddleware(internalEvent, middlewareLoader = default
|
|
|
44
44
|
const result = await middleware.default({
|
|
45
45
|
// `geo` is pre Next 15.
|
|
46
46
|
geo: {
|
|
47
|
-
city
|
|
47
|
+
// The city name is percent-encoded.
|
|
48
|
+
// See https://github.com/vercel/vercel/blob/4cb6143/packages/functions/src/headers.ts#L94C19-L94C37
|
|
49
|
+
city: decodeURIComponent(headers["x-open-next-city"]),
|
|
48
50
|
country: headers["x-open-next-country"],
|
|
49
51
|
region: headers["x-open-next-region"],
|
|
50
52
|
latitude: headers["x-open-next-latitude"],
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RouteType } from "../../types/open-next";
|
|
2
|
+
export declare const apiPrefix: string;
|
|
3
|
+
export declare const staticRouteMatcher: (path: string) => {
|
|
4
|
+
route: string;
|
|
5
|
+
type: RouteType;
|
|
6
|
+
}[];
|
|
7
|
+
export declare const dynamicRouteMatcher: (path: string) => {
|
|
8
|
+
route: string;
|
|
9
|
+
type: RouteType;
|
|
10
|
+
}[];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { AppPathRoutesManifest, RoutesManifest } from "../../adapters/config/index";
|
|
2
|
+
// Add the locale prefix to the regex so we correctly match the rawPath
|
|
3
|
+
const optionalLocalePrefixRegex = `^/(?:${RoutesManifest.locales.map((locale) => `${locale}/?`).join("|")})?`;
|
|
4
|
+
// Add the basepath prefix to the regex so we correctly match the rawPath
|
|
5
|
+
const optionalBasepathPrefixRegex = RoutesManifest.basePath
|
|
6
|
+
? `^${RoutesManifest.basePath}/?`
|
|
7
|
+
: "^/";
|
|
8
|
+
// Add the basePath prefix to the api routes
|
|
9
|
+
export const apiPrefix = `${RoutesManifest.basePath ?? ""}/api`;
|
|
10
|
+
const optionalPrefix = optionalLocalePrefixRegex.replace("^/", optionalBasepathPrefixRegex);
|
|
11
|
+
function routeMatcher(routeDefinitions) {
|
|
12
|
+
const regexp = routeDefinitions.map((route) => ({
|
|
13
|
+
page: route.page,
|
|
14
|
+
regexp: new RegExp(route.regex.replace("^/", optionalPrefix)),
|
|
15
|
+
}));
|
|
16
|
+
const appPathsSet = new Set();
|
|
17
|
+
const routePathsSet = new Set();
|
|
18
|
+
// We need to use AppPathRoutesManifest here
|
|
19
|
+
for (const [k, v] of Object.entries(AppPathRoutesManifest)) {
|
|
20
|
+
if (k.endsWith("page")) {
|
|
21
|
+
appPathsSet.add(v);
|
|
22
|
+
}
|
|
23
|
+
else if (k.endsWith("route")) {
|
|
24
|
+
routePathsSet.add(v);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return function matchRoute(path) {
|
|
28
|
+
const foundRoutes = regexp.filter((route) => route.regexp.test(path));
|
|
29
|
+
return foundRoutes.map((foundRoute) => {
|
|
30
|
+
let routeType = "page";
|
|
31
|
+
if (appPathsSet.has(foundRoute.page)) {
|
|
32
|
+
routeType = "app";
|
|
33
|
+
}
|
|
34
|
+
else if (routePathsSet.has(foundRoute.page)) {
|
|
35
|
+
routeType = "route";
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
route: foundRoute.page,
|
|
39
|
+
type: routeType,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export const staticRouteMatcher = routeMatcher(RoutesManifest.routes.static);
|
|
45
|
+
export const dynamicRouteMatcher = routeMatcher(RoutesManifest.routes.dynamic);
|
|
@@ -2,7 +2,7 @@ import type { OutgoingHttpHeaders } from "node:http";
|
|
|
2
2
|
import type { IncomingMessage } from "../../http/index.js";
|
|
3
3
|
import { OpenNextNodeResponse } from "../../http/openNextResponse.js";
|
|
4
4
|
import type { MiddlewareManifest } from "../../types/next-types";
|
|
5
|
-
import type { InternalEvent, InternalResult, StreamCreator } from "../../types/open-next.js";
|
|
5
|
+
import type { InternalEvent, InternalResult, RoutingResult, StreamCreator } from "../../types/open-next.js";
|
|
6
6
|
/**
|
|
7
7
|
*
|
|
8
8
|
* @__PURE__
|
|
@@ -60,7 +60,7 @@ export declare function convertBodyToReadableStream(method: string, body?: strin
|
|
|
60
60
|
*
|
|
61
61
|
* @__PURE__
|
|
62
62
|
*/
|
|
63
|
-
export declare function fixCacheHeaderForHtmlPages(
|
|
63
|
+
export declare function fixCacheHeaderForHtmlPages(internalEvent: InternalEvent, headers: OutgoingHttpHeaders): void;
|
|
64
64
|
/**
|
|
65
65
|
*
|
|
66
66
|
* @__PURE__
|
|
@@ -90,4 +90,5 @@ export declare function fixISRHeaders(headers: OutgoingHttpHeaders): void;
|
|
|
90
90
|
* @returns
|
|
91
91
|
* @__PURE__
|
|
92
92
|
*/
|
|
93
|
-
export declare function createServerResponse(
|
|
93
|
+
export declare function createServerResponse(routingResult: RoutingResult, headers: Record<string, string | string[] | undefined>, responseStream?: StreamCreator): OpenNextNodeResponse;
|
|
94
|
+
export declare function invalidateCDNOnRequest(params: RoutingResult, headers: OutgoingHttpHeaders): Promise<void>;
|