@opennextjs/aws 3.5.7 → 3.6.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 -0
- package/dist/adapters/cache.js +35 -10
- package/dist/adapters/composable-cache.d.ts +17 -0
- package/dist/adapters/composable-cache.js +89 -0
- package/dist/adapters/image-optimization-adapter.js +14 -12
- package/dist/build/compileCache.d.ts +5 -2
- package/dist/build/compileCache.js +26 -4
- package/dist/build/copyTracedFiles.d.ts +1 -0
- package/dist/build/copyTracedFiles.js +41 -22
- package/dist/build/createServerBundle.js +7 -2
- package/dist/build/patch/patches/index.d.ts +2 -1
- package/dist/build/patch/patches/index.js +2 -1
- package/dist/build/patch/patches/patchFetchCacheISR.d.ts +2 -0
- package/dist/build/patch/patches/patchFetchCacheISR.js +35 -0
- package/dist/core/routing/middleware.js +9 -11
- package/dist/core/util.js +6 -0
- package/dist/overrides/incrementalCache/s3-lite.js +4 -4
- package/dist/overrides/incrementalCache/s3.js +4 -4
- package/dist/overrides/tagCache/dynamodb-nextMode.d.ts +1 -0
- package/dist/overrides/tagCache/dynamodb-nextMode.js +4 -0
- package/dist/overrides/tagCache/fs-dev.js +2 -1
- package/dist/plugins/edge.js +2 -1
- package/dist/types/cache.d.ts +51 -7
- package/dist/types/next-types.d.ts +1 -0
- package/dist/types/overrides.d.ts +9 -4
- package/dist/utils/cache.d.ts +1 -1
- package/dist/utils/normalize-path.d.ts +1 -0
- package/dist/utils/normalize-path.js +3 -0
- package/package.json +1 -1
package/dist/adapters/cache.d.ts
CHANGED
package/dist/adapters/cache.js
CHANGED
|
@@ -29,7 +29,7 @@ export default class Cache {
|
|
|
29
29
|
async getFetchCache(key, softTags, tags) {
|
|
30
30
|
debug("get fetch cache", { key, softTags, tags });
|
|
31
31
|
try {
|
|
32
|
-
const cachedEntry = await globalThis.incrementalCache.get(key,
|
|
32
|
+
const cachedEntry = await globalThis.incrementalCache.get(key, "fetch");
|
|
33
33
|
if (cachedEntry?.value === undefined)
|
|
34
34
|
return null;
|
|
35
35
|
const _tags = [...(tags ?? []), ...(softTags ?? [])];
|
|
@@ -65,7 +65,7 @@ export default class Cache {
|
|
|
65
65
|
}
|
|
66
66
|
async getIncrementalCache(key) {
|
|
67
67
|
try {
|
|
68
|
-
const cachedEntry = await globalThis.incrementalCache.get(key,
|
|
68
|
+
const cachedEntry = await globalThis.incrementalCache.get(key, "cache");
|
|
69
69
|
if (!cachedEntry?.value) {
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
@@ -150,6 +150,7 @@ export default class Cache {
|
|
|
150
150
|
await globalThis.incrementalCache.delete(key);
|
|
151
151
|
}
|
|
152
152
|
else {
|
|
153
|
+
const revalidate = this.extractRevalidateForSet(ctx);
|
|
153
154
|
switch (data.kind) {
|
|
154
155
|
case "ROUTE":
|
|
155
156
|
case "APP_ROUTE": {
|
|
@@ -163,7 +164,8 @@ export default class Cache {
|
|
|
163
164
|
status,
|
|
164
165
|
headers,
|
|
165
166
|
},
|
|
166
|
-
|
|
167
|
+
revalidate,
|
|
168
|
+
}, "cache");
|
|
167
169
|
break;
|
|
168
170
|
}
|
|
169
171
|
case "PAGE":
|
|
@@ -179,14 +181,16 @@ export default class Cache {
|
|
|
179
181
|
status,
|
|
180
182
|
headers,
|
|
181
183
|
},
|
|
182
|
-
|
|
184
|
+
revalidate,
|
|
185
|
+
}, "cache");
|
|
183
186
|
}
|
|
184
187
|
else {
|
|
185
188
|
await globalThis.incrementalCache.set(key, {
|
|
186
189
|
type: "page",
|
|
187
190
|
html,
|
|
188
191
|
json: pageData,
|
|
189
|
-
|
|
192
|
+
revalidate,
|
|
193
|
+
}, "cache");
|
|
190
194
|
}
|
|
191
195
|
break;
|
|
192
196
|
}
|
|
@@ -200,17 +204,19 @@ export default class Cache {
|
|
|
200
204
|
status,
|
|
201
205
|
headers,
|
|
202
206
|
},
|
|
203
|
-
|
|
207
|
+
revalidate,
|
|
208
|
+
}, "cache");
|
|
204
209
|
break;
|
|
205
210
|
}
|
|
206
211
|
case "FETCH":
|
|
207
|
-
await globalThis.incrementalCache.set(key, data,
|
|
212
|
+
await globalThis.incrementalCache.set(key, data, "fetch");
|
|
208
213
|
break;
|
|
209
214
|
case "REDIRECT":
|
|
210
215
|
await globalThis.incrementalCache.set(key, {
|
|
211
216
|
type: "redirect",
|
|
212
217
|
props: data.props,
|
|
213
|
-
|
|
218
|
+
revalidate,
|
|
219
|
+
}, "cache");
|
|
214
220
|
break;
|
|
215
221
|
case "IMAGE":
|
|
216
222
|
// Not implemented
|
|
@@ -233,8 +239,11 @@ export default class Cache {
|
|
|
233
239
|
if (config?.disableTagCache || config?.disableIncrementalCache) {
|
|
234
240
|
return;
|
|
235
241
|
}
|
|
242
|
+
const _tags = Array.isArray(tags) ? tags : [tags];
|
|
243
|
+
if (_tags.length === 0) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
236
246
|
try {
|
|
237
|
-
const _tags = Array.isArray(tags) ? tags : [tags];
|
|
238
247
|
if (globalThis.tagCache.mode === "nextMode") {
|
|
239
248
|
const paths = (await globalThis.tagCache.getPathsByTags?.(_tags)) ?? [];
|
|
240
249
|
await globalThis.tagCache.writeTags(_tags);
|
|
@@ -320,7 +329,8 @@ export default class Cache {
|
|
|
320
329
|
// Write derivedTags to the tag cache
|
|
321
330
|
// If we use an in house version of getDerivedTags in build we should use it here instead of next's one
|
|
322
331
|
const derivedTags = data?.kind === "FETCH"
|
|
323
|
-
?
|
|
332
|
+
? //@ts-expect-error - On older versions of next, ctx was a number, but for these cases we use data?.data?.tags
|
|
333
|
+
(ctx?.tags ?? data?.data?.tags ?? []) // before version 14 next.js used data?.data?.tags so we keep it for backward compatibility
|
|
324
334
|
: data?.kind === "PAGE"
|
|
325
335
|
? (data.headers?.["x-next-cache-tags"]?.split(",") ?? [])
|
|
326
336
|
: [];
|
|
@@ -339,4 +349,19 @@ export default class Cache {
|
|
|
339
349
|
})));
|
|
340
350
|
}
|
|
341
351
|
}
|
|
352
|
+
extractRevalidateForSet(ctx) {
|
|
353
|
+
if (ctx === undefined) {
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
if (typeof ctx === "number" || ctx === false) {
|
|
357
|
+
return ctx;
|
|
358
|
+
}
|
|
359
|
+
if ("revalidate" in ctx) {
|
|
360
|
+
return ctx.revalidate;
|
|
361
|
+
}
|
|
362
|
+
if ("cacheControl" in ctx) {
|
|
363
|
+
return ctx.cacheControl?.revalidate;
|
|
364
|
+
}
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
342
367
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ComposableCacheEntry } from "../types/cache";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
get(cacheKey: string): Promise<{
|
|
4
|
+
value: import("stream/web").ReadableStream<any>;
|
|
5
|
+
tags: string[];
|
|
6
|
+
stale: number;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
expire: number;
|
|
9
|
+
revalidate: number;
|
|
10
|
+
} | undefined>;
|
|
11
|
+
set(cacheKey: string, pendingEntry: Promise<ComposableCacheEntry>): Promise<void>;
|
|
12
|
+
refreshTags(): Promise<void>;
|
|
13
|
+
getExpiration(...tags: string[]): Promise<number>;
|
|
14
|
+
expireTags(...tags: string[]): Promise<void>;
|
|
15
|
+
receiveExpiredTags(...tags: string[]): Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { fromReadableStream, toReadableStream } from "../utils/stream";
|
|
2
|
+
import { debug } from "./logger";
|
|
3
|
+
export default {
|
|
4
|
+
async get(cacheKey) {
|
|
5
|
+
try {
|
|
6
|
+
const result = await globalThis.incrementalCache.get(cacheKey, "composable");
|
|
7
|
+
if (!result?.value?.value) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
debug("composable cache result", result);
|
|
11
|
+
// We need to check if the tags associated with this entry has been revalidated
|
|
12
|
+
if (globalThis.tagCache.mode === "nextMode" &&
|
|
13
|
+
result.value.tags.length > 0) {
|
|
14
|
+
const hasBeenRevalidated = await globalThis.tagCache.hasBeenRevalidated(result.value.tags, result.lastModified);
|
|
15
|
+
if (hasBeenRevalidated)
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
else if (globalThis.tagCache.mode === "original" ||
|
|
19
|
+
globalThis.tagCache.mode === undefined) {
|
|
20
|
+
const hasBeenRevalidated = (await globalThis.tagCache.getLastModified(cacheKey, result.lastModified)) === -1;
|
|
21
|
+
if (hasBeenRevalidated)
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
...result.value,
|
|
26
|
+
value: toReadableStream(result.value.value),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
debug("Cannot read composable cache entry");
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
async set(cacheKey, pendingEntry) {
|
|
35
|
+
const entry = await pendingEntry;
|
|
36
|
+
const valueToStore = await fromReadableStream(entry.value);
|
|
37
|
+
await globalThis.incrementalCache.set(cacheKey, {
|
|
38
|
+
...entry,
|
|
39
|
+
value: valueToStore,
|
|
40
|
+
}, "composable");
|
|
41
|
+
if (globalThis.tagCache.mode === "original") {
|
|
42
|
+
const storedTags = await globalThis.tagCache.getByPath(cacheKey);
|
|
43
|
+
const tagsToWrite = entry.tags.filter((tag) => !storedTags.includes(tag));
|
|
44
|
+
if (tagsToWrite.length > 0) {
|
|
45
|
+
await globalThis.tagCache.writeTags(tagsToWrite.map((tag) => ({ tag, path: cacheKey })));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
async refreshTags() {
|
|
50
|
+
// We don't do anything for now, do we want to do something here ???
|
|
51
|
+
return;
|
|
52
|
+
},
|
|
53
|
+
async getExpiration(...tags) {
|
|
54
|
+
if (globalThis.tagCache.mode === "nextMode") {
|
|
55
|
+
return globalThis.tagCache.getLastRevalidated(tags);
|
|
56
|
+
}
|
|
57
|
+
// We always return 0 here, original tag cache are handled directly in the get part
|
|
58
|
+
// TODO: We need to test this more, i'm not entirely sure that this is working as expected
|
|
59
|
+
return 0;
|
|
60
|
+
},
|
|
61
|
+
async expireTags(...tags) {
|
|
62
|
+
if (globalThis.tagCache.mode === "nextMode") {
|
|
63
|
+
return globalThis.tagCache.writeTags(tags);
|
|
64
|
+
}
|
|
65
|
+
const tagCache = globalThis.tagCache;
|
|
66
|
+
const revalidatedAt = Date.now();
|
|
67
|
+
// For the original mode, we have more work to do here.
|
|
68
|
+
// We need to find all paths linked to to these tags
|
|
69
|
+
const pathsToUpdate = await Promise.all(tags.map(async (tag) => {
|
|
70
|
+
const paths = await tagCache.getByTag(tag);
|
|
71
|
+
return paths.map((path) => ({
|
|
72
|
+
path,
|
|
73
|
+
tag,
|
|
74
|
+
revalidatedAt,
|
|
75
|
+
}));
|
|
76
|
+
}));
|
|
77
|
+
// We need to deduplicate paths, we use a set for that
|
|
78
|
+
const setToWrite = new Set();
|
|
79
|
+
for (const entry of pathsToUpdate.flat()) {
|
|
80
|
+
setToWrite.add(entry);
|
|
81
|
+
}
|
|
82
|
+
await globalThis.tagCache.writeTags(Array.from(setToWrite));
|
|
83
|
+
},
|
|
84
|
+
// This one is necessary for older versions of next
|
|
85
|
+
async receiveExpiredTags(...tags) {
|
|
86
|
+
// This function does absolutely nothing
|
|
87
|
+
return;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
@@ -50,6 +50,12 @@ export async function defaultHandler(event, options) {
|
|
|
50
50
|
process.env.HOST = headersHost;
|
|
51
51
|
}
|
|
52
52
|
const imageParams = validateImageParams(headers, queryString === null ? undefined : queryString);
|
|
53
|
+
// We return a 400 here if imageParams returns an errorMessage
|
|
54
|
+
// https://github.com/vercel/next.js/blob/512d8283054407ab92b2583ecce3b253c3be7b85/packages/next/src/server/next-server.ts#L937-L941
|
|
55
|
+
if ("errorMessage" in imageParams) {
|
|
56
|
+
error("Error during validation of image params", imageParams.errorMessage);
|
|
57
|
+
return buildFailureResponse(imageParams.errorMessage, options?.streamCreator, 400);
|
|
58
|
+
}
|
|
53
59
|
let etag;
|
|
54
60
|
// We don't cache any images, so in order to be able to return 304 responses, we compute an ETag from what is assumed to be static
|
|
55
61
|
if (process.env.OPENNEXT_STATIC_ETAG) {
|
|
@@ -68,7 +74,8 @@ export async function defaultHandler(event, options) {
|
|
|
68
74
|
return buildSuccessResponse(result, options?.streamCreator, etag);
|
|
69
75
|
}
|
|
70
76
|
catch (e) {
|
|
71
|
-
|
|
77
|
+
error("Failed to optimize image", e);
|
|
78
|
+
return buildFailureResponse("Internal server error", options?.streamCreator);
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
//////////////////////
|
|
@@ -81,9 +88,6 @@ function validateImageParams(headers, query) {
|
|
|
81
88
|
// @ts-ignore
|
|
82
89
|
{ headers }, query, nextConfig, false);
|
|
83
90
|
debug("image params", imageParams);
|
|
84
|
-
if ("errorMessage" in imageParams) {
|
|
85
|
-
throw new Error(imageParams.errorMessage);
|
|
86
|
-
}
|
|
87
91
|
return imageParams;
|
|
88
92
|
}
|
|
89
93
|
function computeEtag(imageParams) {
|
|
@@ -119,28 +123,26 @@ function buildSuccessResponse(result, streamCreator, etag) {
|
|
|
119
123
|
headers,
|
|
120
124
|
};
|
|
121
125
|
}
|
|
122
|
-
function buildFailureResponse(
|
|
123
|
-
debug(
|
|
126
|
+
function buildFailureResponse(errorMessage, streamCreator, statusCode = 500) {
|
|
127
|
+
debug(errorMessage, statusCode);
|
|
124
128
|
if (streamCreator) {
|
|
125
129
|
const response = new OpenNextNodeResponse(() => void 0, async () => void 0, streamCreator);
|
|
126
|
-
response.writeHead(
|
|
130
|
+
response.writeHead(statusCode, {
|
|
127
131
|
Vary: "Accept",
|
|
128
132
|
"Cache-Control": "public,max-age=60,immutable",
|
|
129
|
-
"Content-Type": "application/json",
|
|
130
133
|
});
|
|
131
|
-
response.end(
|
|
134
|
+
response.end(errorMessage);
|
|
132
135
|
}
|
|
133
136
|
return {
|
|
134
137
|
type: "core",
|
|
135
138
|
isBase64Encoded: false,
|
|
136
|
-
statusCode:
|
|
139
|
+
statusCode: statusCode,
|
|
137
140
|
headers: {
|
|
138
141
|
Vary: "Accept",
|
|
139
142
|
// For failed images, allow client to retry after 1 minute.
|
|
140
143
|
"Cache-Control": "public,max-age=60,immutable",
|
|
141
|
-
"Content-Type": "application/json",
|
|
142
144
|
},
|
|
143
|
-
body: toReadableStream(
|
|
145
|
+
body: toReadableStream(errorMessage),
|
|
144
146
|
};
|
|
145
147
|
}
|
|
146
148
|
const loader = await resolveImageLoader(globalThis.openNextConfig.imageOptimization?.loader ?? "s3");
|
|
@@ -4,6 +4,9 @@ import * as buildHelper from "./helper.js";
|
|
|
4
4
|
*
|
|
5
5
|
* @param options Build options.
|
|
6
6
|
* @param format Output format.
|
|
7
|
-
* @returns
|
|
7
|
+
* @returns An object containing the paths to the compiled cache and composable cache files.
|
|
8
8
|
*/
|
|
9
|
-
export declare function compileCache(options: buildHelper.BuildOptions, format?: "cjs" | "esm"):
|
|
9
|
+
export declare function compileCache(options: buildHelper.BuildOptions, format?: "cjs" | "esm"): {
|
|
10
|
+
cache: string;
|
|
11
|
+
composableCache: string;
|
|
12
|
+
};
|
|
@@ -5,17 +5,18 @@ import * as buildHelper from "./helper.js";
|
|
|
5
5
|
*
|
|
6
6
|
* @param options Build options.
|
|
7
7
|
* @param format Output format.
|
|
8
|
-
* @returns
|
|
8
|
+
* @returns An object containing the paths to the compiled cache and composable cache files.
|
|
9
9
|
*/
|
|
10
10
|
export function compileCache(options, format = "cjs") {
|
|
11
11
|
const { config } = options;
|
|
12
12
|
const ext = format === "cjs" ? "cjs" : "mjs";
|
|
13
|
-
const
|
|
13
|
+
const compiledCacheFile = path.join(options.buildDir, `cache.${ext}`);
|
|
14
14
|
const isAfter15 = buildHelper.compareSemver(options.nextVersion, ">=", "15.0.0");
|
|
15
|
+
// Normal cache
|
|
15
16
|
buildHelper.esbuildSync({
|
|
16
17
|
external: ["next", "styled-jsx", "react", "@aws-sdk/*"],
|
|
17
18
|
entryPoints: [path.join(options.openNextDistDir, "adapters", "cache.js")],
|
|
18
|
-
outfile:
|
|
19
|
+
outfile: compiledCacheFile,
|
|
19
20
|
target: ["node18"],
|
|
20
21
|
format,
|
|
21
22
|
banner: {
|
|
@@ -26,5 +27,26 @@ export function compileCache(options, format = "cjs") {
|
|
|
26
27
|
].join(""),
|
|
27
28
|
},
|
|
28
29
|
}, options);
|
|
29
|
-
|
|
30
|
+
const compiledComposableCacheFile = path.join(options.buildDir, `composable-cache.${ext}`);
|
|
31
|
+
// Composable cache
|
|
32
|
+
buildHelper.esbuildSync({
|
|
33
|
+
external: ["next", "styled-jsx", "react", "@aws-sdk/*"],
|
|
34
|
+
entryPoints: [
|
|
35
|
+
path.join(options.openNextDistDir, "adapters", "composable-cache.js"),
|
|
36
|
+
],
|
|
37
|
+
outfile: compiledComposableCacheFile,
|
|
38
|
+
target: ["node18"],
|
|
39
|
+
format,
|
|
40
|
+
banner: {
|
|
41
|
+
js: [
|
|
42
|
+
`globalThis.disableIncrementalCache = ${config.dangerous?.disableIncrementalCache ?? false};`,
|
|
43
|
+
`globalThis.disableDynamoDBCache = ${config.dangerous?.disableTagCache ?? false};`,
|
|
44
|
+
`globalThis.isNextAfter15 = ${isAfter15};`,
|
|
45
|
+
].join(""),
|
|
46
|
+
},
|
|
47
|
+
}, options);
|
|
48
|
+
return {
|
|
49
|
+
cache: compiledCacheFile,
|
|
50
|
+
composableCache: compiledComposableCacheFile,
|
|
51
|
+
};
|
|
30
52
|
}
|
|
@@ -17,6 +17,7 @@ export declare function getManifests(nextDir: string): {
|
|
|
17
17
|
};
|
|
18
18
|
export declare function copyTracedFiles({ buildOutputPath, packagePath, outputDir, routes, bundledNextServer, skipServerFiles, }: CopyTracedFilesOptions): Promise<{
|
|
19
19
|
tracedFiles: string[];
|
|
20
|
+
nodePackages: Map<string, string>;
|
|
20
21
|
manifests: {
|
|
21
22
|
buildId: string;
|
|
22
23
|
config: import("../types/next-types.js").NextConfig;
|
|
@@ -41,18 +41,38 @@ export async function copyTracedFiles({ buildOutputPath, packagePath, outputDir,
|
|
|
41
41
|
const standaloneNextDir = path.join(standaloneDir, packagePath, ".next");
|
|
42
42
|
const standaloneServerDir = path.join(standaloneNextDir, "server");
|
|
43
43
|
const outputNextDir = path.join(outputDir, packagePath, ".next");
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
// For next 13, we need to include them otherwise we get runtime error
|
|
47
|
-
const requiredServerFiles = JSON.parse(readFileSync(path.join(dotNextDir, bundledNextServer
|
|
48
|
-
? "next-minimal-server.js.nft.json"
|
|
49
|
-
: "next-server.js.nft.json"), "utf8"));
|
|
44
|
+
// Files to copy
|
|
45
|
+
// Map from files in the `.next/standalone` to files in the `.open-next` folder
|
|
50
46
|
const filesToCopy = new Map();
|
|
47
|
+
// Node packages
|
|
48
|
+
// Map from folders in the project to folders in the `.open-next` folder
|
|
49
|
+
// The map might also include the mono-repo path.
|
|
50
|
+
const nodePackages = new Map();
|
|
51
|
+
/**
|
|
52
|
+
* Extracts files and node packages from a .nft.json file
|
|
53
|
+
* @param nftFile path to the .nft.json file relative to `.next/`
|
|
54
|
+
*/
|
|
55
|
+
const processNftFile = (nftFile) => {
|
|
56
|
+
const subDir = path.dirname(nftFile);
|
|
57
|
+
const files = JSON.parse(readFileSync(path.join(dotNextDir, nftFile), "utf8")).files;
|
|
58
|
+
files.forEach((tracedPath) => {
|
|
59
|
+
const src = path.join(standaloneNextDir, subDir, tracedPath);
|
|
60
|
+
const dst = path.join(outputNextDir, subDir, tracedPath);
|
|
61
|
+
filesToCopy.set(src, dst);
|
|
62
|
+
const module = path.join(dotNextDir, subDir, tracedPath);
|
|
63
|
+
if (module.endsWith("package.json")) {
|
|
64
|
+
nodePackages.set(path.dirname(module), path.dirname(dst));
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
};
|
|
51
68
|
// Files necessary by the server
|
|
52
69
|
if (!skipServerFiles) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
// On next 14+, we might not have to include those files
|
|
71
|
+
// For next 13, we need to include them otherwise we get runtime error
|
|
72
|
+
const nftFile = bundledNextServer
|
|
73
|
+
? "next-minimal-server.js.nft.json"
|
|
74
|
+
: "next-server.js.nft.json";
|
|
75
|
+
processNftFile(nftFile);
|
|
56
76
|
}
|
|
57
77
|
// create directory for pages
|
|
58
78
|
if (existsSync(path.join(standaloneNextDir, "server/pages"))) {
|
|
@@ -69,13 +89,12 @@ export async function copyTracedFiles({ buildOutputPath, packagePath, outputDir,
|
|
|
69
89
|
recursive: true,
|
|
70
90
|
});
|
|
71
91
|
const computeCopyFilesForPage = (pagePath) => {
|
|
72
|
-
const
|
|
73
|
-
let requiredFiles;
|
|
92
|
+
const serverPath = `server/${pagePath}.js`;
|
|
74
93
|
try {
|
|
75
|
-
|
|
94
|
+
processNftFile(`${serverPath}.nft.json`);
|
|
76
95
|
}
|
|
77
96
|
catch (e) {
|
|
78
|
-
if (existsSync(path.join(
|
|
97
|
+
if (existsSync(path.join(dotNextDir, serverPath))) {
|
|
79
98
|
//TODO: add a link to the docs
|
|
80
99
|
throw new Error(`
|
|
81
100
|
--------------------------------------------------------------------------------
|
|
@@ -88,18 +107,14 @@ See the docs for more information on how to bundle edge runtime functions.
|
|
|
88
107
|
throw new Error(`
|
|
89
108
|
--------------------------------------------------------------------------------
|
|
90
109
|
We cannot find the route for ${pagePath}.
|
|
91
|
-
File ${
|
|
110
|
+
File ${serverPath} does not exist
|
|
92
111
|
--------------------------------------------------------------------------------`);
|
|
93
112
|
}
|
|
94
|
-
|
|
95
|
-
extractFiles(requiredFiles.files, path.join(standaloneNextDir, dir)).forEach((f) => {
|
|
96
|
-
filesToCopy.set(f, f.replace(standaloneDir, outputDir));
|
|
97
|
-
});
|
|
98
|
-
if (!existsSync(path.join(standaloneNextDir, fullFilePath))) {
|
|
113
|
+
if (!existsSync(path.join(standaloneNextDir, serverPath))) {
|
|
99
114
|
throw new Error(`This error should only happen for static 404 and 500 page from page router. Report this if that's not the case.,
|
|
100
|
-
File ${
|
|
115
|
+
File ${serverPath} does not exist`);
|
|
101
116
|
}
|
|
102
|
-
filesToCopy.set(path.join(standaloneNextDir,
|
|
117
|
+
filesToCopy.set(path.join(standaloneNextDir, serverPath), path.join(outputNextDir, serverPath));
|
|
103
118
|
};
|
|
104
119
|
const safeComputeCopyFilesForPage = (pagePath, alternativePath) => {
|
|
105
120
|
try {
|
|
@@ -148,12 +163,15 @@ File ${fullFilePath} does not exist
|
|
|
148
163
|
routes.forEach((route) => {
|
|
149
164
|
computeCopyFilesForPage(route);
|
|
150
165
|
});
|
|
166
|
+
// Only files that are actually copied
|
|
167
|
+
const tracedFiles = [];
|
|
151
168
|
//Actually copy the files
|
|
152
169
|
filesToCopy.forEach((to, from) => {
|
|
153
170
|
// We don't want to copy excluded packages (i.e sharp)
|
|
154
171
|
if (isExcluded(from)) {
|
|
155
172
|
return;
|
|
156
173
|
}
|
|
174
|
+
tracedFiles.push(to);
|
|
157
175
|
mkdirSync(path.dirname(to), { recursive: true });
|
|
158
176
|
let symlink = null;
|
|
159
177
|
// For pnpm symlink we need to do that
|
|
@@ -233,7 +251,8 @@ File ${fullFilePath} does not exist
|
|
|
233
251
|
}
|
|
234
252
|
logger.debug("copyTracedFiles:", Date.now() - tsStart, "ms");
|
|
235
253
|
return {
|
|
236
|
-
tracedFiles
|
|
254
|
+
tracedFiles,
|
|
255
|
+
nodePackages,
|
|
237
256
|
manifests: getManifests(standaloneNextDir),
|
|
238
257
|
};
|
|
239
258
|
}
|
|
@@ -14,8 +14,7 @@ import { copyMiddlewareResources, generateEdgeBundle, } from "./edge/createEdgeB
|
|
|
14
14
|
import * as buildHelper from "./helper.js";
|
|
15
15
|
import { installDependencies } from "./installDeps.js";
|
|
16
16
|
import { applyCodePatches } from "./patch/codePatcher.js";
|
|
17
|
-
import { patchEnvVars, patchFetchCacheForISR, patchFetchCacheSetMissingWaitUntil, patchNextServer, patchUnstableCacheForISR, } from "./patch/patches/index.js";
|
|
18
|
-
import { patchBackgroundRevalidation } from "./patch/patches/patchBackgroundRevalidation.js";
|
|
17
|
+
import { patchBackgroundRevalidation, patchEnvVars, patchFetchCacheForISR, patchFetchCacheSetMissingWaitUntil, patchNextServer, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patch/patches/index.js";
|
|
19
18
|
export async function createServerBundle(options, codeCustomization) {
|
|
20
19
|
const { config } = options;
|
|
21
20
|
const foundRoutes = new Set();
|
|
@@ -86,7 +85,10 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
|
|
|
86
85
|
const outPackagePath = path.join(outputPath, packagePath);
|
|
87
86
|
fs.mkdirSync(outPackagePath, { recursive: true });
|
|
88
87
|
const ext = fnOptions.runtime === "deno" ? "mjs" : "cjs";
|
|
88
|
+
// Normal cache
|
|
89
89
|
fs.copyFileSync(path.join(options.buildDir, `cache.${ext}`), path.join(outPackagePath, "cache.cjs"));
|
|
90
|
+
// Composable cache
|
|
91
|
+
fs.copyFileSync(path.join(options.buildDir, `composable-cache.${ext}`), path.join(outPackagePath, "composable-cache.cjs"));
|
|
90
92
|
if (fnOptions.runtime === "deno") {
|
|
91
93
|
addDenoJson(outputPath, packagePath);
|
|
92
94
|
}
|
|
@@ -123,6 +125,7 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
|
|
|
123
125
|
patchNextServer,
|
|
124
126
|
patchEnvVars,
|
|
125
127
|
patchBackgroundRevalidation,
|
|
128
|
+
patchUseCacheForISR,
|
|
126
129
|
...additionalCodePatches,
|
|
127
130
|
]);
|
|
128
131
|
// Build Lambda code
|
|
@@ -135,6 +138,7 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
|
|
|
135
138
|
const isBefore13413 = buildHelper.compareSemver(options.nextVersion, "<=", "13.4.13");
|
|
136
139
|
const isAfter141 = buildHelper.compareSemver(options.nextVersion, ">=", "14.1");
|
|
137
140
|
const isAfter142 = buildHelper.compareSemver(options.nextVersion, ">=", "14.2");
|
|
141
|
+
const isAfter152 = buildHelper.compareSemver(options.nextVersion, ">=", "15.2.0");
|
|
138
142
|
const disableRouting = isBefore13413 || config.middleware?.external;
|
|
139
143
|
const updater = new ContentUpdater(options);
|
|
140
144
|
const additionalPlugins = codeCustomization?.additionalPlugins
|
|
@@ -160,6 +164,7 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
|
|
|
160
164
|
...(isAfter141
|
|
161
165
|
? ["experimentalIncrementalCacheHandler"]
|
|
162
166
|
: ["stableIncrementalCache"]),
|
|
167
|
+
...(isAfter152 ? [] : ["composableCache"]),
|
|
163
168
|
],
|
|
164
169
|
}),
|
|
165
170
|
openNextResolvePlugin({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { envVarRuleCreator, patchEnvVars } from "./patchEnvVar.js";
|
|
2
2
|
export { patchNextServer } from "./patchNextServer.js";
|
|
3
|
-
export { patchFetchCacheForISR, patchUnstableCacheForISR, } from "./patchFetchCacheISR.js";
|
|
3
|
+
export { patchFetchCacheForISR, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patchFetchCacheISR.js";
|
|
4
4
|
export { patchFetchCacheSetMissingWaitUntil } from "./patchFetchCacheWaitUntil.js";
|
|
5
|
+
export { patchBackgroundRevalidation } from "./patchBackgroundRevalidation.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { envVarRuleCreator, patchEnvVars } from "./patchEnvVar.js";
|
|
2
2
|
export { patchNextServer } from "./patchNextServer.js";
|
|
3
|
-
export { patchFetchCacheForISR, patchUnstableCacheForISR, } from "./patchFetchCacheISR.js";
|
|
3
|
+
export { patchFetchCacheForISR, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patchFetchCacheISR.js";
|
|
4
4
|
export { patchFetchCacheSetMissingWaitUntil } from "./patchFetchCacheWaitUntil.js";
|
|
5
|
+
export { patchBackgroundRevalidation } from "./patchBackgroundRevalidation.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { CodePatcher } from "../codePatcher.js";
|
|
2
2
|
export declare const fetchRule = "\nrule:\n kind: member_expression\n pattern: $WORK_STORE.isOnDemandRevalidate\n inside:\n kind: ternary_expression\n all:\n - has: {kind: 'null'}\n - has: \n kind: await_expression\n has:\n kind: call_expression\n all:\n - has:\n kind: member_expression\n has:\n kind: property_identifier\n field: property\n regex: get\n - has:\n kind: arguments\n has:\n kind: object\n has:\n kind: pair\n all:\n - has:\n kind: property_identifier\n field: key\n regex: softTags\n inside:\n kind: variable_declarator\n\nfix:\n ($WORK_STORE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)\n";
|
|
3
3
|
export declare const unstable_cacheRule = "\nrule:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isOnDemandRevalidate\n inside:\n kind: if_statement\n stopBy: end\n has:\n kind: statement_block\n has:\n kind: variable_declarator\n has: \n kind: await_expression\n has:\n kind: call_expression\n all:\n - has:\n kind: member_expression\n has:\n kind: property_identifier\n field: property\n regex: get\n - has:\n kind: arguments\n has:\n kind: object\n has:\n kind: pair\n all:\n - has:\n kind: property_identifier\n field: key\n regex: softTags\n stopBy: end\nfix:\n ($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)\n";
|
|
4
|
+
export declare const useCacheRule = "\nrule:\n kind: member_expression\n pattern: $STORE_OR_CACHE.isOnDemandRevalidate\n inside:\n kind: binary_expression\n has: \n kind: member_expression\n pattern: $STORE_OR_CACHE.isDraftMode\n inside:\n kind: if_statement\n stopBy: end\n has: \n kind: return_statement\n any:\n - has:\n kind: 'true'\n - has:\n regex: '!0'\n stopBy: end\nfix:\n '($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)'";
|
|
4
5
|
export declare const patchFetchCacheForISR: CodePatcher;
|
|
5
6
|
export declare const patchUnstableCacheForISR: CodePatcher;
|
|
7
|
+
export declare const patchUseCacheForISR: CodePatcher;
|
|
@@ -74,6 +74,28 @@ rule:
|
|
|
74
74
|
fix:
|
|
75
75
|
($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)
|
|
76
76
|
`;
|
|
77
|
+
export const useCacheRule = `
|
|
78
|
+
rule:
|
|
79
|
+
kind: member_expression
|
|
80
|
+
pattern: $STORE_OR_CACHE.isOnDemandRevalidate
|
|
81
|
+
inside:
|
|
82
|
+
kind: binary_expression
|
|
83
|
+
has:
|
|
84
|
+
kind: member_expression
|
|
85
|
+
pattern: $STORE_OR_CACHE.isDraftMode
|
|
86
|
+
inside:
|
|
87
|
+
kind: if_statement
|
|
88
|
+
stopBy: end
|
|
89
|
+
has:
|
|
90
|
+
kind: return_statement
|
|
91
|
+
any:
|
|
92
|
+
- has:
|
|
93
|
+
kind: 'true'
|
|
94
|
+
- has:
|
|
95
|
+
regex: '!0'
|
|
96
|
+
stopBy: end
|
|
97
|
+
fix:
|
|
98
|
+
'($STORE_OR_CACHE.isOnDemandRevalidate && !globalThis.__openNextAls?.getStore()?.isISRRevalidation)'`;
|
|
77
99
|
export const patchFetchCacheForISR = {
|
|
78
100
|
name: "patch-fetch-cache-for-isr",
|
|
79
101
|
patches: [
|
|
@@ -100,3 +122,16 @@ export const patchUnstableCacheForISR = {
|
|
|
100
122
|
},
|
|
101
123
|
],
|
|
102
124
|
};
|
|
125
|
+
export const patchUseCacheForISR = {
|
|
126
|
+
name: "patch-use-cache-for-isr",
|
|
127
|
+
patches: [
|
|
128
|
+
{
|
|
129
|
+
versions: ">=15.3.0",
|
|
130
|
+
field: {
|
|
131
|
+
pathFilter: getCrossPlatformPathRegex(String.raw `(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`, { escape: false }),
|
|
132
|
+
contentFilter: /\.isOnDemandRevalidate/,
|
|
133
|
+
patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FunctionsConfigManifest, MiddlewareManifest, NextConfig, PrerenderManifest, } from "../../adapters/config/index.js";
|
|
2
2
|
import { emptyReadableStream } from "../../utils/stream.js";
|
|
3
|
+
import { getQueryFromSearchParams } from "../../overrides/converters/utils.js";
|
|
3
4
|
import { localizePath } from "./i18n/index.js";
|
|
4
5
|
import { convertBodyToReadableStream, getMiddlewareMatch, isExternal, } from "./util.js";
|
|
5
6
|
const middlewareManifest = MiddlewareManifest;
|
|
@@ -103,7 +104,7 @@ export async function handleMiddleware(internalEvent, initialSearch, middlewareL
|
|
|
103
104
|
// NOTE: the header was added to `req` from above
|
|
104
105
|
const rewriteUrl = responseHeaders.get("x-middleware-rewrite");
|
|
105
106
|
let isExternalRewrite = false;
|
|
106
|
-
let
|
|
107
|
+
let middlewareQuery = internalEvent.query;
|
|
107
108
|
let newUrl = internalEvent.url;
|
|
108
109
|
if (rewriteUrl) {
|
|
109
110
|
newUrl = rewriteUrl;
|
|
@@ -113,15 +114,12 @@ export async function handleMiddleware(internalEvent, initialSearch, middlewareL
|
|
|
113
114
|
}
|
|
114
115
|
else {
|
|
115
116
|
const rewriteUrlObject = new URL(rewriteUrl);
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
rewriteUrlObject.searchParams.forEach((v, k) => {
|
|
123
|
-
middlewareQueryString[k] = v;
|
|
124
|
-
});
|
|
117
|
+
// Search params from the rewritten URL override the original search params
|
|
118
|
+
middlewareQuery = getQueryFromSearchParams(rewriteUrlObject.searchParams);
|
|
119
|
+
// We still need to add internal search params to the query string for pages router on older versions of Next.js
|
|
120
|
+
if ("__nextDataReq" in internalEvent.query) {
|
|
121
|
+
middlewareQuery.__nextDataReq = internalEvent.query.__nextDataReq;
|
|
122
|
+
}
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
// If the middleware wants to directly return a response (i.e. not using `NextResponse.next()` or `NextResponse.rewrite()`)
|
|
@@ -145,7 +143,7 @@ export async function handleMiddleware(internalEvent, initialSearch, middlewareL
|
|
|
145
143
|
headers: { ...internalEvent.headers, ...reqHeaders },
|
|
146
144
|
body: internalEvent.body,
|
|
147
145
|
method: internalEvent.method,
|
|
148
|
-
query:
|
|
146
|
+
query: middlewareQuery,
|
|
149
147
|
cookies: internalEvent.cookies,
|
|
150
148
|
remoteAddress: internalEvent.remoteAddress,
|
|
151
149
|
isExternalRewrite,
|
package/dist/core/util.js
CHANGED
|
@@ -15,6 +15,7 @@ overrideNextjsRequireHooks(NextConfig);
|
|
|
15
15
|
applyNextjsRequireHooksOverride();
|
|
16
16
|
//#endOverride
|
|
17
17
|
const cacheHandlerPath = require.resolve("./cache.cjs");
|
|
18
|
+
const composableCacheHandlerPath = require.resolve("./composable-cache.cjs");
|
|
18
19
|
// @ts-ignore
|
|
19
20
|
const nextServer = new NextServer.default({
|
|
20
21
|
//#override requestHandlerHost
|
|
@@ -42,6 +43,11 @@ const nextServer = new NextServer.default({
|
|
|
42
43
|
//#override experimentalIncrementalCacheHandler
|
|
43
44
|
incrementalCacheHandlerPath: cacheHandlerPath,
|
|
44
45
|
//#endOverride
|
|
46
|
+
//#override composableCache
|
|
47
|
+
cacheHandlers: {
|
|
48
|
+
default: composableCacheHandlerPath,
|
|
49
|
+
},
|
|
50
|
+
//#endOverride
|
|
45
51
|
},
|
|
46
52
|
},
|
|
47
53
|
customServer: false,
|
|
@@ -30,8 +30,8 @@ function buildS3Key(key, extension) {
|
|
|
30
30
|
return path.posix.join(CACHE_BUCKET_KEY_PREFIX ?? "", extension === "fetch" ? "__fetch" : "", NEXT_BUILD_ID ?? "", extension === "fetch" ? key : `${key}.${extension}`);
|
|
31
31
|
}
|
|
32
32
|
const incrementalCache = {
|
|
33
|
-
async get(key,
|
|
34
|
-
const result = await awsFetch(buildS3Key(key,
|
|
33
|
+
async get(key, cacheType) {
|
|
34
|
+
const result = await awsFetch(buildS3Key(key, cacheType ?? "cache"), {
|
|
35
35
|
method: "GET",
|
|
36
36
|
});
|
|
37
37
|
if (result.status === 404) {
|
|
@@ -46,8 +46,8 @@ const incrementalCache = {
|
|
|
46
46
|
lastModified: new Date(result.headers.get("last-modified") ?? "").getTime(),
|
|
47
47
|
};
|
|
48
48
|
},
|
|
49
|
-
async set(key, value,
|
|
50
|
-
const response = await awsFetch(buildS3Key(key,
|
|
49
|
+
async set(key, value, cacheType) {
|
|
50
|
+
const response = await awsFetch(buildS3Key(key, cacheType ?? "cache"), {
|
|
51
51
|
method: "PUT",
|
|
52
52
|
body: JSON.stringify(value),
|
|
53
53
|
});
|
|
@@ -15,10 +15,10 @@ function buildS3Key(key, extension) {
|
|
|
15
15
|
return path.posix.join(CACHE_BUCKET_KEY_PREFIX ?? "", extension === "fetch" ? "__fetch" : "", NEXT_BUILD_ID ?? "", extension === "fetch" ? key : `${key}.${extension}`);
|
|
16
16
|
}
|
|
17
17
|
const incrementalCache = {
|
|
18
|
-
async get(key,
|
|
18
|
+
async get(key, cacheType) {
|
|
19
19
|
const result = await s3Client.send(new GetObjectCommand({
|
|
20
20
|
Bucket: CACHE_BUCKET_NAME,
|
|
21
|
-
Key: buildS3Key(key,
|
|
21
|
+
Key: buildS3Key(key, cacheType ?? "cache"),
|
|
22
22
|
}));
|
|
23
23
|
const cacheData = JSON.parse((await result.Body?.transformToString()) ?? "{}");
|
|
24
24
|
return {
|
|
@@ -26,10 +26,10 @@ const incrementalCache = {
|
|
|
26
26
|
lastModified: result.LastModified?.getTime(),
|
|
27
27
|
};
|
|
28
28
|
},
|
|
29
|
-
async set(key, value,
|
|
29
|
+
async set(key, value, cacheType) {
|
|
30
30
|
await s3Client.send(new PutObjectCommand({
|
|
31
31
|
Bucket: CACHE_BUCKET_NAME,
|
|
32
|
-
Key: buildS3Key(key,
|
|
32
|
+
Key: buildS3Key(key, cacheType ?? "cache"),
|
|
33
33
|
Body: JSON.stringify(value),
|
|
34
34
|
}));
|
|
35
35
|
},
|
|
@@ -52,6 +52,10 @@ function buildDynamoObject(tag, revalidatedAt) {
|
|
|
52
52
|
export default {
|
|
53
53
|
name: "ddb-nextMode",
|
|
54
54
|
mode: "nextMode",
|
|
55
|
+
getLastRevalidated: async (tags) => {
|
|
56
|
+
// Not supported for now
|
|
57
|
+
return 0;
|
|
58
|
+
},
|
|
55
59
|
hasBeenRevalidated: async (tags, lastModified) => {
|
|
56
60
|
if (globalThis.openNextConfig.dangerous?.disableTagCache) {
|
|
57
61
|
return false;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
// TODO: fix this for monorepo
|
|
2
3
|
const tagFile = "../../dynamodb-provider/dynamodb-cache.json";
|
|
3
4
|
const tagContent = fs.readFileSync(tagFile, "utf-8");
|
|
4
5
|
let tags = JSON.parse(tagContent);
|
|
@@ -26,7 +27,7 @@ const tagCache = {
|
|
|
26
27
|
tags = unchangedTags.concat(newTags.map((tag) => ({
|
|
27
28
|
tag: { S: tag.tag },
|
|
28
29
|
path: { S: tag.path },
|
|
29
|
-
revalidatedAt: { N: String(tag.revalidatedAt) },
|
|
30
|
+
revalidatedAt: { N: String(tag.revalidatedAt ?? 1) },
|
|
30
31
|
})));
|
|
31
32
|
},
|
|
32
33
|
};
|
package/dist/plugins/edge.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { loadAppPathRoutesManifest, loadAppPathsManifest, loadAppPathsManifestKeys, loadBuildId, loadConfig, loadConfigHeaders, loadFunctionsConfigManifest, loadHtmlPages, loadMiddlewareManifest, loadPrerenderManifest, loadRoutesManifest, } from "../adapters/config/util.js";
|
|
5
5
|
import logger from "../logger.js";
|
|
6
|
+
import { normalizePath } from "../utils/normalize-path.js";
|
|
6
7
|
import { getCrossPlatformPathRegex } from "../utils/regex.js";
|
|
7
8
|
/**
|
|
8
9
|
* @param opts.nextDir - The path to the .next directory
|
|
@@ -11,7 +12,7 @@ import { getCrossPlatformPathRegex } from "../utils/regex.js";
|
|
|
11
12
|
* @returns
|
|
12
13
|
*/
|
|
13
14
|
export function openNextEdgePlugins({ nextDir, middlewareInfo, isInCloudflare, }) {
|
|
14
|
-
const entryFiles = middlewareInfo?.files.map((file) => path.join(nextDir, file)) ?? [];
|
|
15
|
+
const entryFiles = middlewareInfo?.files.map((file) => normalizePath(path.join(nextDir, file))) ?? [];
|
|
15
16
|
const routes = middlewareInfo
|
|
16
17
|
? [
|
|
17
18
|
{
|
package/dist/types/cache.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReadableStream } from "node:stream/web";
|
|
1
2
|
interface CachedFetchValue {
|
|
2
3
|
kind: "FETCH";
|
|
3
4
|
data: {
|
|
@@ -61,7 +62,7 @@ export interface CacheHandlerValue {
|
|
|
61
62
|
cacheState?: string;
|
|
62
63
|
value: IncrementalCacheValue | null;
|
|
63
64
|
}
|
|
64
|
-
export type Extension = "cache" | "fetch";
|
|
65
|
+
export type Extension = "cache" | "fetch" | "composable";
|
|
65
66
|
type MetaHeaders = {
|
|
66
67
|
"x-next-cache-tags"?: string;
|
|
67
68
|
[k: string]: string | string[] | undefined;
|
|
@@ -82,11 +83,54 @@ export type TagCacheMetaFile = {
|
|
|
82
83
|
N: string;
|
|
83
84
|
};
|
|
84
85
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
interface SetIncrementalFetchCacheContext {
|
|
87
|
+
fetchCache: true;
|
|
88
|
+
fetchUrl?: string;
|
|
89
|
+
fetchIdx?: number;
|
|
90
|
+
tags?: string[];
|
|
91
|
+
}
|
|
92
|
+
interface SetIncrementalResponseCacheContext {
|
|
93
|
+
fetchCache?: false;
|
|
94
|
+
cacheControl?: {
|
|
95
|
+
revalidate: number | false;
|
|
96
|
+
expire?: number;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* True if the route is enabled for PPR.
|
|
100
|
+
*/
|
|
101
|
+
isRoutePPREnabled?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* True if this is a fallback request.
|
|
104
|
+
*/
|
|
105
|
+
isFallback?: boolean;
|
|
106
|
+
}
|
|
107
|
+
interface SetIncrementalCacheContext {
|
|
108
|
+
revalidate?: number | false;
|
|
109
|
+
isRoutePPREnabled?: boolean;
|
|
110
|
+
isFallback?: boolean;
|
|
111
|
+
}
|
|
112
|
+
type OldSetIncrementalCacheContext = number | false | undefined;
|
|
113
|
+
export type IncrementalCacheContext = OldSetIncrementalCacheContext | SetIncrementalCacheContext | SetIncrementalFetchCacheContext | SetIncrementalResponseCacheContext;
|
|
114
|
+
export interface ComposableCacheEntry {
|
|
115
|
+
value: ReadableStream<Uint8Array>;
|
|
116
|
+
tags: string[];
|
|
117
|
+
stale: number;
|
|
118
|
+
timestamp: number;
|
|
119
|
+
expire: number;
|
|
120
|
+
revalidate: number;
|
|
121
|
+
}
|
|
122
|
+
export type StoredComposableCacheEntry = Omit<ComposableCacheEntry, "value"> & {
|
|
123
|
+
value: string;
|
|
91
124
|
};
|
|
125
|
+
export interface ComposableCacheHandler {
|
|
126
|
+
get(cacheKey: string): Promise<ComposableCacheEntry | undefined>;
|
|
127
|
+
set(cacheKey: string, pendingEntry: Promise<ComposableCacheEntry>): Promise<void>;
|
|
128
|
+
refreshTags(): Promise<void>;
|
|
129
|
+
getExpiration(...tags: string[]): Promise<number>;
|
|
130
|
+
expireTags(...tags: string[]): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* This function is only there for older versions and do nothing
|
|
133
|
+
*/
|
|
134
|
+
receiveExpiredTags(...tags: string[]): Promise<void>;
|
|
135
|
+
}
|
|
92
136
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Readable } from "node:stream";
|
|
2
|
-
import type { Meta } from "./cache";
|
|
2
|
+
import type { Extension, Meta, StoredComposableCacheEntry } from "./cache";
|
|
3
3
|
import type { BaseEventOrResult, BaseOverride, InternalEvent, InternalResult, Origin, ResolvedRoute, StreamCreator, WaitUntil } from "./open-next";
|
|
4
4
|
export interface QueueMessage {
|
|
5
5
|
MessageDeduplicationId: string;
|
|
@@ -51,12 +51,16 @@ export type WithLastModified<T> = {
|
|
|
51
51
|
lastModified?: number;
|
|
52
52
|
value?: T;
|
|
53
53
|
};
|
|
54
|
-
export type
|
|
54
|
+
export type CacheEntryType = Extension;
|
|
55
|
+
export type CacheValue<CacheType extends CacheEntryType> = (CacheType extends "fetch" ? CachedFetchValue : CacheType extends "cache" ? CachedFile : StoredComposableCacheEntry) & {
|
|
56
|
+
/**
|
|
57
|
+
* This is available for page cache entry, but only at runtime.
|
|
58
|
+
*/
|
|
55
59
|
revalidate?: number | false;
|
|
56
60
|
};
|
|
57
61
|
export type IncrementalCache = {
|
|
58
|
-
get<
|
|
59
|
-
set<
|
|
62
|
+
get<CacheType extends CacheEntryType = "cache">(key: string, cacheType?: CacheType): Promise<WithLastModified<CacheValue<CacheType>> | null>;
|
|
63
|
+
set<CacheType extends CacheEntryType = "cache">(key: string, value: CacheValue<CacheType>, isFetch?: CacheType): Promise<void>;
|
|
60
64
|
delete(key: string): Promise<void>;
|
|
61
65
|
name: string;
|
|
62
66
|
};
|
|
@@ -86,6 +90,7 @@ Cons :
|
|
|
86
90
|
*/
|
|
87
91
|
export type NextModeTagCache = BaseTagCache & {
|
|
88
92
|
mode: "nextMode";
|
|
93
|
+
getLastRevalidated(tags: string[]): Promise<number>;
|
|
89
94
|
hasBeenRevalidated(tags: string[], lastModified?: number): Promise<boolean>;
|
|
90
95
|
writeTags(tags: string[]): Promise<void>;
|
|
91
96
|
getPathsByTags?: (tags: string[]) => Promise<string[]>;
|
package/dist/utils/cache.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { CacheValue, WithLastModified } from "../types/overrides";
|
|
2
2
|
export declare function hasBeenRevalidated(key: string, tags: string[], cacheEntry: WithLastModified<CacheValue<any>>): Promise<boolean>;
|
|
3
|
-
export declare function getTagsFromValue(value?: CacheValue<
|
|
3
|
+
export declare function getTagsFromValue(value?: CacheValue<"cache">): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizePath(path: string): string;
|