@netlify/plugin-nextjs 5.10.1 → 5.10.3
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 +22 -0
- package/dist/esm-chunks/{package-UN6EVEHD.js → package-AKXSA3EX.js} +11 -10
- package/dist/run/config.js +5 -3
- package/dist/run/handlers/cache.cjs +75 -73
- package/dist/run/handlers/request-context.cjs +10 -3
- package/dist/run/handlers/server.js +2 -3
- package/dist/run/handlers/tracer.cjs +15 -2
- package/dist/run/handlers/tracing.js +1 -1
- package/dist/run/headers.js +20 -36
- package/dist/run/next.cjs +3 -6
- package/dist/run/revalidate.js +2 -2
- package/dist/run/{regional-blob-store.cjs → storage/regional-blob-store.cjs} +7 -4
- package/dist/run/storage/request-scoped-in-memory-cache.cjs +1475 -0
- package/dist/run/storage/storage.cjs +84 -0
- package/dist/shared/blob-types.cjs +37 -0
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2023 Netlify <team@netlify.com>
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -8,7 +8,7 @@ import "./chunk-OEQOKJGE.js";
|
|
|
8
8
|
|
|
9
9
|
// package.json
|
|
10
10
|
var name = "@netlify/plugin-nextjs";
|
|
11
|
-
var version = "5.10.
|
|
11
|
+
var version = "5.10.3";
|
|
12
12
|
var description = "Run Next.js seamlessly on Netlify";
|
|
13
13
|
var main = "./dist/index.js";
|
|
14
14
|
var type = "module";
|
|
@@ -56,15 +56,15 @@ var bugs = {
|
|
|
56
56
|
};
|
|
57
57
|
var homepage = "https://opennext.js.org/netlify";
|
|
58
58
|
var devDependencies = {
|
|
59
|
-
"@fastly/http-compute-js": "1.1.
|
|
60
|
-
"@netlify/blobs": "^8.1.
|
|
61
|
-
"@netlify/build": "^
|
|
62
|
-
"@netlify/edge-bundler": "^12.
|
|
63
|
-
"@netlify/edge-functions": "^2.11.
|
|
59
|
+
"@fastly/http-compute-js": "1.1.5",
|
|
60
|
+
"@netlify/blobs": "^8.1.2",
|
|
61
|
+
"@netlify/build": "^30.1.1",
|
|
62
|
+
"@netlify/edge-bundler": "^12.4.0",
|
|
63
|
+
"@netlify/edge-functions": "^2.11.1",
|
|
64
64
|
"@netlify/eslint-config-node": "^7.0.1",
|
|
65
|
-
"@netlify/functions": "^3.0.
|
|
66
|
-
"@netlify/serverless-functions-api": "^1.
|
|
67
|
-
"@netlify/zip-it-and-ship-it": "^
|
|
65
|
+
"@netlify/functions": "^3.0.4",
|
|
66
|
+
"@netlify/serverless-functions-api": "^1.36.0",
|
|
67
|
+
"@netlify/zip-it-and-ship-it": "^10.0.4",
|
|
68
68
|
"@opentelemetry/api": "^1.8.0",
|
|
69
69
|
"@opentelemetry/exporter-trace-otlp-http": "^0.51.0",
|
|
70
70
|
"@opentelemetry/resources": "^1.24.0",
|
|
@@ -84,10 +84,11 @@ var devDependencies = {
|
|
|
84
84
|
"fs-monkey": "^1.0.6",
|
|
85
85
|
"get-port": "^7.1.0",
|
|
86
86
|
"lambda-local": "^2.2.0",
|
|
87
|
+
"lru-cache": "^10.4.3",
|
|
87
88
|
memfs: "^4.9.2",
|
|
88
89
|
"mock-require": "^3.0.3",
|
|
89
90
|
msw: "^2.0.7",
|
|
90
|
-
"netlify-cli": "^
|
|
91
|
+
"netlify-cli": "^19.1.5",
|
|
91
92
|
next: "^15.0.0-canary.28",
|
|
92
93
|
os: "^0.1.2",
|
|
93
94
|
outdent: "^0.8.0",
|
package/dist/run/config.js
CHANGED
|
@@ -11,6 +11,7 @@ import { existsSync } from "node:fs";
|
|
|
11
11
|
import { readFile } from "node:fs/promises";
|
|
12
12
|
import { join, resolve } from "node:path";
|
|
13
13
|
import { PLUGIN_DIR, RUN_CONFIG } from "./constants.js";
|
|
14
|
+
import { setInMemoryCacheMaxSizeFromNextConfig } from "./storage/storage.cjs";
|
|
14
15
|
var getRunConfig = async () => {
|
|
15
16
|
return JSON.parse(await readFile(resolve(PLUGIN_DIR, RUN_CONFIG), "utf-8"));
|
|
16
17
|
};
|
|
@@ -21,12 +22,13 @@ var setRunConfig = (config) => {
|
|
|
21
22
|
}
|
|
22
23
|
config.experimental = {
|
|
23
24
|
...config.experimental,
|
|
24
|
-
//
|
|
25
|
-
// but we still need to set it for older Next.js versions
|
|
25
|
+
// Before Next.js 14.1.0 path to the cache handler was in experimental section, see NextConfigForMultipleVersions type
|
|
26
26
|
incrementalCacheHandlerPath: cacheHandler
|
|
27
27
|
};
|
|
28
28
|
config.cacheHandler = cacheHandler;
|
|
29
|
-
|
|
29
|
+
setInMemoryCacheMaxSizeFromNextConfig(
|
|
30
|
+
config.cacheMaxMemorySize ?? config.experimental?.isrMemoryCacheSize
|
|
31
|
+
);
|
|
30
32
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config);
|
|
31
33
|
};
|
|
32
34
|
export {
|
|
@@ -102,7 +102,7 @@ var init_builder = __esm({
|
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
// node_modules/@netlify/functions/dist/chunk-
|
|
105
|
+
// node_modules/@netlify/functions/dist/chunk-EZL2F32K.mjs
|
|
106
106
|
var import_process = require("process");
|
|
107
107
|
var purgeCache;
|
|
108
108
|
var init_purge_cache = __esm({
|
|
@@ -113,28 +113,37 @@ var init_purge_cache = __esm({
|
|
|
113
113
|
"`fetch` is not available. Please ensure you're using Node.js version 18.0.0 or above. Refer to https://ntl.fyi/functions-runtime for more information."
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
|
+
const { siteID } = options;
|
|
117
|
+
const { siteSlug } = options;
|
|
118
|
+
const { domain } = options;
|
|
119
|
+
if (siteID && siteSlug || siteID && domain || siteSlug && domain) {
|
|
120
|
+
throw new Error('Can only pass one of either "siteID", "siteSlug", or "domain"');
|
|
121
|
+
}
|
|
116
122
|
const payload = {
|
|
117
|
-
cache_tags: options.tags
|
|
118
|
-
deploy_alias: options.deployAlias
|
|
123
|
+
cache_tags: options.tags
|
|
119
124
|
};
|
|
125
|
+
if ("deployAlias" in options) {
|
|
126
|
+
payload.deploy_alias = options.deployAlias;
|
|
127
|
+
} else if (!import_process.env.NETLIFY_LOCAL) {
|
|
128
|
+
payload.deploy_alias = import_process.env.NETLIFY_BRANCH;
|
|
129
|
+
}
|
|
120
130
|
const token = import_process.env.NETLIFY_PURGE_API_TOKEN || options.token;
|
|
121
131
|
if (import_process.env.NETLIFY_LOCAL && !token) {
|
|
122
132
|
const scope = options.tags?.length ? ` for tags ${options.tags?.join(", ")}` : "";
|
|
123
133
|
console.log(`Skipping purgeCache${scope} in local development.`);
|
|
124
134
|
return;
|
|
125
135
|
}
|
|
126
|
-
if (
|
|
127
|
-
payload.site_slug =
|
|
128
|
-
} else if (
|
|
129
|
-
payload.domain =
|
|
136
|
+
if (siteSlug) {
|
|
137
|
+
payload.site_slug = siteSlug;
|
|
138
|
+
} else if (domain) {
|
|
139
|
+
payload.domain = domain;
|
|
130
140
|
} else {
|
|
131
|
-
|
|
132
|
-
if (!
|
|
141
|
+
payload.site_id = siteID || import_process.env.SITE_ID;
|
|
142
|
+
if (!payload.site_id) {
|
|
133
143
|
throw new Error(
|
|
134
144
|
"The Netlify site ID was not found in the execution environment. Please supply it manually using the `siteID` property."
|
|
135
145
|
);
|
|
136
146
|
}
|
|
137
|
-
payload.site_id = siteID;
|
|
138
147
|
}
|
|
139
148
|
if (!token) {
|
|
140
149
|
throw new Error(
|
|
@@ -155,7 +164,18 @@ var init_purge_cache = __esm({
|
|
|
155
164
|
body: JSON.stringify(payload)
|
|
156
165
|
});
|
|
157
166
|
if (!response.ok) {
|
|
158
|
-
|
|
167
|
+
let text;
|
|
168
|
+
try {
|
|
169
|
+
text = await response.text();
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
if (text) {
|
|
173
|
+
throw new Error(`Cache purge API call was unsuccessful.
|
|
174
|
+
Status: ${response.status}
|
|
175
|
+
Body: ${text}`);
|
|
176
|
+
}
|
|
177
|
+
throw new Error(`Cache purge API call was unsuccessful.
|
|
178
|
+
Status: ${response.status}`);
|
|
159
179
|
}
|
|
160
180
|
};
|
|
161
181
|
}
|
|
@@ -175,29 +195,23 @@ var import_constants = require("next/dist/lib/constants.js");
|
|
|
175
195
|
|
|
176
196
|
// package.json
|
|
177
197
|
var name = "@netlify/plugin-nextjs";
|
|
178
|
-
var version = "5.10.
|
|
198
|
+
var version = "5.10.3";
|
|
179
199
|
|
|
180
200
|
// src/run/handlers/cache.cts
|
|
181
201
|
var import_cache_types = require("../../shared/cache-types.cjs");
|
|
182
|
-
var
|
|
202
|
+
var import_storage = require("../storage/storage.cjs");
|
|
183
203
|
var import_request_context = require("./request-context.cjs");
|
|
184
204
|
var import_tracer = require("./tracer.cjs");
|
|
185
205
|
var purgeCacheUserAgent = `${name}@${version}`;
|
|
186
206
|
var NetlifyCacheHandler = class {
|
|
187
207
|
options;
|
|
188
208
|
revalidatedTags;
|
|
189
|
-
|
|
209
|
+
cacheStore;
|
|
190
210
|
tracer = (0, import_tracer.getTracer)();
|
|
191
|
-
tagManifestsFetchedFromBlobStoreInCurrentRequest;
|
|
192
211
|
constructor(options) {
|
|
193
212
|
this.options = options;
|
|
194
213
|
this.revalidatedTags = options.revalidatedTags;
|
|
195
|
-
this.
|
|
196
|
-
this.tagManifestsFetchedFromBlobStoreInCurrentRequest = {};
|
|
197
|
-
}
|
|
198
|
-
async encodeBlobKey(key) {
|
|
199
|
-
const { encodeBlobKey } = await import("../../shared/blobkey.js");
|
|
200
|
-
return await encodeBlobKey(key);
|
|
214
|
+
this.cacheStore = (0, import_storage.getMemoizedKeyValueStoreBackedByRegionalBlobStore)({ consistency: "strong" });
|
|
201
215
|
}
|
|
202
216
|
getTTL(blob) {
|
|
203
217
|
if (blob.value?.kind === "FETCH" || blob.value?.kind === "ROUTE" || blob.value?.kind === "APP_ROUTE" || blob.value?.kind === "PAGE" || blob.value?.kind === "PAGES" || blob.value?.kind === "APP_PAGE") {
|
|
@@ -218,26 +232,17 @@ var NetlifyCacheHandler = class {
|
|
|
218
232
|
}
|
|
219
233
|
const requestContext = (0, import_request_context.getRequestContext)();
|
|
220
234
|
if (!requestContext) {
|
|
221
|
-
|
|
222
|
-
new Error("CacheHandler was called without a request context")
|
|
223
|
-
);
|
|
224
|
-
getCacheKeySpan.setAttributes({
|
|
225
|
-
severity: "alert",
|
|
226
|
-
warning: true
|
|
227
|
-
});
|
|
235
|
+
(0, import_tracer.recordWarning)(new Error("CacheHandler was called without a request context"), getCacheKeySpan);
|
|
228
236
|
return;
|
|
229
237
|
}
|
|
230
238
|
if (requestContext.responseCacheKey && requestContext.responseCacheKey !== key) {
|
|
231
239
|
requestContext.responseCacheGetLastModified = void 0;
|
|
232
|
-
|
|
240
|
+
(0, import_tracer.recordWarning)(
|
|
233
241
|
new Error(
|
|
234
242
|
`Multiple response cache keys used in single request: ["${requestContext.responseCacheKey}, "${key}"]`
|
|
235
|
-
)
|
|
243
|
+
),
|
|
244
|
+
getCacheKeySpan
|
|
236
245
|
);
|
|
237
|
-
getCacheKeySpan.setAttributes({
|
|
238
|
-
severity: "alert",
|
|
239
|
-
warning: true
|
|
240
|
-
});
|
|
241
246
|
return;
|
|
242
247
|
}
|
|
243
248
|
requestContext.responseCacheKey = key;
|
|
@@ -254,9 +259,6 @@ var NetlifyCacheHandler = class {
|
|
|
254
259
|
return restOfRouteValue;
|
|
255
260
|
}
|
|
256
261
|
captureCacheTags(cacheValue, key) {
|
|
257
|
-
if (!cacheValue) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
262
|
const requestContext = (0, import_request_context.getRequestContext)();
|
|
261
263
|
if (!requestContext) {
|
|
262
264
|
return;
|
|
@@ -264,6 +266,11 @@ var NetlifyCacheHandler = class {
|
|
|
264
266
|
if (requestContext.responseCacheTags) {
|
|
265
267
|
return;
|
|
266
268
|
}
|
|
269
|
+
if (!cacheValue) {
|
|
270
|
+
const cacheTags = [`_N_T_${key === "/index" ? "/" : encodeURI(key)}`];
|
|
271
|
+
requestContext.responseCacheTags = cacheTags;
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
267
274
|
if (cacheValue.kind === "PAGE" || cacheValue.kind === "PAGES" || cacheValue.kind === "APP_PAGE" || cacheValue.kind === "ROUTE" || cacheValue.kind === "APP_ROUTE") {
|
|
268
275
|
if (cacheValue.headers?.[import_constants.NEXT_CACHE_TAGS_HEADER]) {
|
|
269
276
|
const cacheTags = cacheValue.headers[import_constants.NEXT_CACHE_TAGS_HEADER].split(/,|%2c/gi);
|
|
@@ -313,25 +320,18 @@ var NetlifyCacheHandler = class {
|
|
|
313
320
|
}
|
|
314
321
|
async get(...args) {
|
|
315
322
|
return this.tracer.withActiveSpan("get cache key", async (span) => {
|
|
316
|
-
const [key,
|
|
323
|
+
const [key, context = {}] = args;
|
|
317
324
|
(0, import_request_context.getLogger)().debug(`[NetlifyCacheHandler.get]: ${key}`);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const blob = await this.tracer.withActiveSpan("blobStore.get", async (blobGetSpan) => {
|
|
321
|
-
blobGetSpan.setAttributes({ key, blobKey });
|
|
322
|
-
return await this.blobStore.get(blobKey, {
|
|
323
|
-
type: "json"
|
|
324
|
-
});
|
|
325
|
-
});
|
|
325
|
+
span.setAttributes({ key });
|
|
326
|
+
const blob = await this.cacheStore.get(key, "blobStore.get");
|
|
326
327
|
if (!blob) {
|
|
327
|
-
span.addEvent("Cache miss", { key
|
|
328
|
+
span.addEvent("Cache miss", { key });
|
|
328
329
|
return null;
|
|
329
330
|
}
|
|
330
331
|
const ttl = this.getTTL(blob);
|
|
331
332
|
if ((0, import_request_context.getRequestContext)()?.isBackgroundRevalidation && typeof ttl === "number" && ttl < 0) {
|
|
332
333
|
span.addEvent("Discarding stale entry due to SWR background revalidation request", {
|
|
333
334
|
key,
|
|
334
|
-
blobKey,
|
|
335
335
|
ttl
|
|
336
336
|
});
|
|
337
337
|
(0, import_request_context.getLogger)().withFields({
|
|
@@ -342,18 +342,25 @@ var NetlifyCacheHandler = class {
|
|
|
342
342
|
);
|
|
343
343
|
return null;
|
|
344
344
|
}
|
|
345
|
-
const staleByTags = await this.checkCacheEntryStaleByTags(
|
|
345
|
+
const staleByTags = await this.checkCacheEntryStaleByTags(
|
|
346
|
+
blob,
|
|
347
|
+
context.tags,
|
|
348
|
+
context.softTags
|
|
349
|
+
);
|
|
346
350
|
if (staleByTags) {
|
|
347
|
-
span.addEvent("Stale", { staleByTags, key,
|
|
351
|
+
span.addEvent("Stale", { staleByTags, key, ttl });
|
|
348
352
|
return null;
|
|
349
353
|
}
|
|
350
354
|
this.captureResponseCacheLastModified(blob, key, span);
|
|
351
|
-
|
|
355
|
+
const isDataRequest = Boolean(context.fetchUrl);
|
|
356
|
+
if (!isDataRequest) {
|
|
357
|
+
this.captureCacheTags(blob.value, key);
|
|
358
|
+
}
|
|
352
359
|
switch (blob.value?.kind) {
|
|
353
360
|
case "FETCH":
|
|
354
361
|
span.addEvent("FETCH", {
|
|
355
362
|
lastModified: blob.lastModified,
|
|
356
|
-
revalidate:
|
|
363
|
+
revalidate: context.revalidate,
|
|
357
364
|
ttl
|
|
358
365
|
});
|
|
359
366
|
return {
|
|
@@ -441,17 +448,16 @@ var NetlifyCacheHandler = class {
|
|
|
441
448
|
async set(...args) {
|
|
442
449
|
return this.tracer.withActiveSpan("set cache key", async (span) => {
|
|
443
450
|
const [key, data, context] = args;
|
|
444
|
-
const blobKey = await this.encodeBlobKey(key);
|
|
445
451
|
const lastModified = Date.now();
|
|
446
|
-
span.setAttributes({ key, lastModified
|
|
452
|
+
span.setAttributes({ key, lastModified });
|
|
447
453
|
(0, import_request_context.getLogger)().debug(`[NetlifyCacheHandler.set]: ${key}`);
|
|
448
454
|
const value = this.transformToStorableObject(data, context);
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
});
|
|
454
|
-
if (data?.kind === "PAGE" || data?.kind === "PAGES") {
|
|
455
|
+
const isDataReq = Boolean(context.fetchUrl);
|
|
456
|
+
if (!isDataReq) {
|
|
457
|
+
this.captureCacheTags(value, key);
|
|
458
|
+
}
|
|
459
|
+
await this.cacheStore.set(key, { lastModified, value }, "blobStore.set");
|
|
460
|
+
if (!data && !isDataReq || data?.kind === "PAGE" || data?.kind === "PAGES") {
|
|
455
461
|
const requestContext = (0, import_request_context.getRequestContext)();
|
|
456
462
|
if (requestContext?.didPagesRouterOnDemandRevalidate) {
|
|
457
463
|
const tag = `_N_T_${key === "/index" ? "/" : encodeURI(key)}`;
|
|
@@ -491,7 +497,7 @@ var NetlifyCacheHandler = class {
|
|
|
491
497
|
await Promise.all(
|
|
492
498
|
tags.map(async (tag) => {
|
|
493
499
|
try {
|
|
494
|
-
await this.
|
|
500
|
+
await this.cacheStore.set(tag, data, "tagManifest.set");
|
|
495
501
|
} catch (error) {
|
|
496
502
|
(0, import_request_context.getLogger)().withError(error).log(`Failed to update tag manifest for ${tag}`);
|
|
497
503
|
}
|
|
@@ -502,7 +508,6 @@ var NetlifyCacheHandler = class {
|
|
|
502
508
|
});
|
|
503
509
|
}
|
|
504
510
|
resetRequestCache() {
|
|
505
|
-
this.tagManifestsFetchedFromBlobStoreInCurrentRequest = {};
|
|
506
511
|
}
|
|
507
512
|
/**
|
|
508
513
|
* Checks if a cache entry is stale through on demand revalidated tags
|
|
@@ -526,19 +531,16 @@ var NetlifyCacheHandler = class {
|
|
|
526
531
|
return new Promise((resolve, reject) => {
|
|
527
532
|
const tagManifestPromises = [];
|
|
528
533
|
for (const tag of cacheTags) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
span.setAttributes({ tag, blobKey });
|
|
534
|
-
return this.blobStore.get(blobKey, { type: "json" });
|
|
535
|
-
});
|
|
536
|
-
});
|
|
537
|
-
this.tagManifestsFetchedFromBlobStoreInCurrentRequest[tag] = tagManifestPromise;
|
|
538
|
-
}
|
|
534
|
+
const tagManifestPromise = this.cacheStore.get(
|
|
535
|
+
tag,
|
|
536
|
+
"tagManifest.get"
|
|
537
|
+
);
|
|
539
538
|
tagManifestPromises.push(
|
|
540
539
|
tagManifestPromise.then((tagManifest) => {
|
|
541
|
-
|
|
540
|
+
if (!tagManifest) {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
const isStale = tagManifest.revalidatedAt >= (cacheEntry.lastModified || Date.now());
|
|
542
544
|
if (isStale) {
|
|
543
545
|
resolve(true);
|
|
544
546
|
return true;
|
|
@@ -121,6 +121,14 @@ var init_internal = __esm({
|
|
|
121
121
|
init_internal();
|
|
122
122
|
|
|
123
123
|
// src/run/handlers/request-context.cts
|
|
124
|
+
var REQUEST_CONTEXT_GLOBAL_KEY = Symbol.for("nf-request-context-async-local-storage");
|
|
125
|
+
var REQUEST_COUNTER_KEY = Symbol.for("nf-request-counter");
|
|
126
|
+
var extendedGlobalThis = globalThis;
|
|
127
|
+
function getFallbackRequestID() {
|
|
128
|
+
const requestNumber = extendedGlobalThis[REQUEST_COUNTER_KEY] ?? 0;
|
|
129
|
+
extendedGlobalThis[REQUEST_COUNTER_KEY] = requestNumber + 1;
|
|
130
|
+
return `#${requestNumber}`;
|
|
131
|
+
}
|
|
124
132
|
function createRequestContext(request, context) {
|
|
125
133
|
const backgroundWorkPromises = [];
|
|
126
134
|
const isDebugRequest = request?.headers.has("x-nf-debug-logging") || request?.headers.has("x-next-debug-logging");
|
|
@@ -142,16 +150,15 @@ function createRequestContext(request, context) {
|
|
|
142
150
|
get backgroundWorkPromise() {
|
|
143
151
|
return Promise.allSettled(backgroundWorkPromises);
|
|
144
152
|
},
|
|
145
|
-
logger
|
|
153
|
+
logger,
|
|
154
|
+
requestID: request?.headers.get("x-nf-request-id") ?? getFallbackRequestID()
|
|
146
155
|
};
|
|
147
156
|
}
|
|
148
|
-
var REQUEST_CONTEXT_GLOBAL_KEY = Symbol.for("nf-request-context-async-local-storage");
|
|
149
157
|
var requestContextAsyncLocalStorage;
|
|
150
158
|
function getRequestContextAsyncLocalStorage() {
|
|
151
159
|
if (requestContextAsyncLocalStorage) {
|
|
152
160
|
return requestContextAsyncLocalStorage;
|
|
153
161
|
}
|
|
154
|
-
const extendedGlobalThis = globalThis;
|
|
155
162
|
if (extendedGlobalThis[REQUEST_CONTEXT_GLOBAL_KEY]) {
|
|
156
163
|
return extendedGlobalThis[REQUEST_CONTEXT_GLOBAL_KEY];
|
|
157
164
|
}
|
|
@@ -3098,8 +3098,8 @@ import {
|
|
|
3098
3098
|
setCacheTagsHeaders,
|
|
3099
3099
|
setVaryHeaders
|
|
3100
3100
|
} from "../headers.js";
|
|
3101
|
-
import { setFetchBeforeNextPatchedIt } from "../regional-blob-store.cjs";
|
|
3102
3101
|
import { nextResponseProxy } from "../revalidate.js";
|
|
3102
|
+
import { setFetchBeforeNextPatchedIt } from "../storage/storage.cjs";
|
|
3103
3103
|
import { getLogger } from "./request-context.cjs";
|
|
3104
3104
|
import { getTracer } from "./tracer.cjs";
|
|
3105
3105
|
import { setupWaitUntil } from "./wait-until.cjs";
|
|
@@ -3174,11 +3174,10 @@ var server_default = async (request, _context, topLevelSpan, requestContext) =>
|
|
|
3174
3174
|
headers: response.headers,
|
|
3175
3175
|
request,
|
|
3176
3176
|
span,
|
|
3177
|
-
tracer,
|
|
3178
3177
|
requestContext
|
|
3179
3178
|
});
|
|
3180
3179
|
}
|
|
3181
|
-
setCacheControlHeaders(response, request, requestContext
|
|
3180
|
+
setCacheControlHeaders(response, request, requestContext);
|
|
3182
3181
|
setCacheTagsHeaders(response.headers, requestContext);
|
|
3183
3182
|
setVaryHeaders(response.headers, request, nextConfig);
|
|
3184
3183
|
setCacheStatusHeader(response.headers, nextCache);
|
|
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/run/handlers/tracer.cts
|
|
21
21
|
var tracer_exports = {};
|
|
22
22
|
__export(tracer_exports, {
|
|
23
|
-
getTracer: () => getTracer
|
|
23
|
+
getTracer: () => getTracer,
|
|
24
|
+
recordWarning: () => recordWarning
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(tracer_exports);
|
|
26
27
|
|
|
@@ -897,7 +898,19 @@ function getTracer() {
|
|
|
897
898
|
}
|
|
898
899
|
return tracer;
|
|
899
900
|
}
|
|
901
|
+
function recordWarning(warning, span) {
|
|
902
|
+
const spanToRecordWarningOn = span ?? trace.getActiveSpan();
|
|
903
|
+
if (!spanToRecordWarningOn) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
spanToRecordWarningOn.recordException(warning);
|
|
907
|
+
spanToRecordWarningOn.setAttributes({
|
|
908
|
+
severity: "alert",
|
|
909
|
+
warning: true
|
|
910
|
+
});
|
|
911
|
+
}
|
|
900
912
|
// Annotate the CommonJS export names for ESM import in node:
|
|
901
913
|
0 && (module.exports = {
|
|
902
|
-
getTracer
|
|
914
|
+
getTracer,
|
|
915
|
+
recordWarning
|
|
903
916
|
});
|
|
@@ -68866,7 +68866,7 @@ var import_semantic_conventions = __toESM(require_src(), 1);
|
|
|
68866
68866
|
import { getLogger } from "./request-context.cjs";
|
|
68867
68867
|
var {
|
|
68868
68868
|
default: { version, name }
|
|
68869
|
-
} = await import("../../esm-chunks/package-
|
|
68869
|
+
} = await import("../../esm-chunks/package-AKXSA3EX.js");
|
|
68870
68870
|
var sdk = new import_sdk_node.NodeSDK({
|
|
68871
68871
|
resource: new import_resources.Resource({
|
|
68872
68872
|
[import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: name,
|
package/dist/run/headers.js
CHANGED
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
import "../esm-chunks/chunk-OEQOKJGE.js";
|
|
8
8
|
|
|
9
9
|
// src/run/headers.ts
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { getRegionalBlobStore } from "./regional-blob-store.cjs";
|
|
10
|
+
import { recordWarning } from "./handlers/tracer.cjs";
|
|
11
|
+
import { getMemoizedKeyValueStoreBackedByRegionalBlobStore } from "./storage/storage.cjs";
|
|
13
12
|
var ALL_VARIATIONS = Symbol.for("ALL_VARIATIONS");
|
|
14
13
|
var NetlifyVaryKeys = /* @__PURE__ */ new Set(["header", "language", "cookie", "query", "country"]);
|
|
15
14
|
var isNetlifyVaryKey = (key) => NetlifyVaryKeys.has(key);
|
|
@@ -88,7 +87,6 @@ var adjustDateHeader = async ({
|
|
|
88
87
|
headers,
|
|
89
88
|
request,
|
|
90
89
|
span,
|
|
91
|
-
tracer,
|
|
92
90
|
requestContext
|
|
93
91
|
}) => {
|
|
94
92
|
const key = new URL(request.url).pathname;
|
|
@@ -96,38 +94,24 @@ var adjustDateHeader = async ({
|
|
|
96
94
|
if (requestContext.responseCacheGetLastModified) {
|
|
97
95
|
lastModified = requestContext.responseCacheGetLastModified;
|
|
98
96
|
} else {
|
|
99
|
-
|
|
100
|
-
new Error("lastModified not found in requestContext, falling back to trying blobs")
|
|
97
|
+
recordWarning(
|
|
98
|
+
new Error("lastModified not found in requestContext, falling back to trying blobs"),
|
|
99
|
+
span
|
|
101
100
|
);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const blobStore = getRegionalBlobStore({ consistency: "strong" });
|
|
107
|
-
const blobKey = await encodeBlobKey(key);
|
|
108
|
-
lastModified = await tracer.withActiveSpan(
|
|
109
|
-
"get cache to calculate date header",
|
|
110
|
-
async (getBlobForDateSpan) => {
|
|
111
|
-
getBlobForDateSpan.setAttributes({
|
|
112
|
-
key,
|
|
113
|
-
blobKey
|
|
114
|
-
});
|
|
115
|
-
const blob = await blobStore.get(blobKey, { type: "json" }) ?? {};
|
|
116
|
-
getBlobForDateSpan.addEvent(blob ? "Cache hit" : "Cache miss");
|
|
117
|
-
return blob.lastModified;
|
|
118
|
-
}
|
|
101
|
+
const cacheStore = getMemoizedKeyValueStoreBackedByRegionalBlobStore({ consistency: "strong" });
|
|
102
|
+
const cacheEntry = await cacheStore.get(
|
|
103
|
+
key,
|
|
104
|
+
"get cache to calculate date header"
|
|
119
105
|
);
|
|
106
|
+
lastModified = cacheEntry?.lastModified;
|
|
120
107
|
}
|
|
121
108
|
if (!lastModified) {
|
|
122
|
-
|
|
109
|
+
recordWarning(
|
|
123
110
|
new Error(
|
|
124
111
|
"lastModified not found in either requestContext or blobs, date header for cached response is not set"
|
|
125
|
-
)
|
|
112
|
+
),
|
|
113
|
+
span
|
|
126
114
|
);
|
|
127
|
-
span.setAttributes({
|
|
128
|
-
severity: "alert",
|
|
129
|
-
warning: true
|
|
130
|
-
});
|
|
131
115
|
return;
|
|
132
116
|
}
|
|
133
117
|
const lastModifiedDate = new Date(lastModified);
|
|
@@ -141,15 +125,11 @@ function setCacheControlFromRequestContext(headers, revalidate) {
|
|
|
141
125
|
);
|
|
142
126
|
headers.set("netlify-cdn-cache-control", cdnCacheControl);
|
|
143
127
|
}
|
|
144
|
-
var setCacheControlHeaders = ({ headers, status }, request, requestContext
|
|
128
|
+
var setCacheControlHeaders = ({ headers, status }, request, requestContext) => {
|
|
145
129
|
if (typeof requestContext.routeHandlerRevalidate !== "undefined" && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control")) {
|
|
146
130
|
setCacheControlFromRequestContext(headers, requestContext.routeHandlerRevalidate);
|
|
147
131
|
return;
|
|
148
132
|
}
|
|
149
|
-
if (status === 308 && request.url.endsWith("/") !== nextConfig.trailingSlash) {
|
|
150
|
-
getLogger().withFields({ trailingSlash: nextConfig.trailingSlash, location: headers.get("location") }).log("NetlifyHeadersHandler.trailingSlashRedirect");
|
|
151
|
-
}
|
|
152
|
-
const cacheControl = headers.get("cache-control");
|
|
153
133
|
if (status === 404) {
|
|
154
134
|
if (request.url.endsWith(".php")) {
|
|
155
135
|
headers.set("cache-control", "public, max-age=0, must-revalidate");
|
|
@@ -161,6 +141,7 @@ var setCacheControlHeaders = ({ headers, status }, request, requestContext, next
|
|
|
161
141
|
return;
|
|
162
142
|
}
|
|
163
143
|
}
|
|
144
|
+
const cacheControl = headers.get("cache-control");
|
|
164
145
|
if (cacheControl !== null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control")) {
|
|
165
146
|
const browserCacheControl = omitHeaderValues(cacheControl, [
|
|
166
147
|
"s-maxage",
|
|
@@ -179,13 +160,16 @@ var setCacheControlHeaders = ({ headers, status }, request, requestContext, next
|
|
|
179
160
|
headers.set("netlify-cdn-cache-control", cdnCacheControl);
|
|
180
161
|
return;
|
|
181
162
|
}
|
|
182
|
-
if (cacheControl === null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsReadForNonFallback) {
|
|
163
|
+
if (cacheControl === null && ["GET", "HEAD"].includes(request.method) && !headers.has("cdn-cache-control") && !headers.has("netlify-cdn-cache-control") && requestContext.usedFsReadForNonFallback && !requestContext.didPagesRouterOnDemandRevalidate) {
|
|
183
164
|
headers.set("cache-control", "public, max-age=0, must-revalidate");
|
|
184
165
|
headers.set("netlify-cdn-cache-control", `max-age=31536000, durable`);
|
|
185
166
|
}
|
|
186
167
|
};
|
|
187
168
|
var setCacheTagsHeaders = (headers, requestContext) => {
|
|
188
|
-
if (
|
|
169
|
+
if (!headers.has("cache-control") && !headers.has("netlify-cdn-cache-control")) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (requestContext.responseCacheTags) {
|
|
189
173
|
headers.set("netlify-cache-tag", requestContext.responseCacheTags.join(","));
|
|
190
174
|
}
|
|
191
175
|
};
|
package/dist/run/next.cjs
CHANGED
|
@@ -493,7 +493,7 @@ var import_path = require("path");
|
|
|
493
493
|
var import_fs_monkey = __toESM(require_lib());
|
|
494
494
|
var import_request_context = require("./handlers/request-context.cjs");
|
|
495
495
|
var import_tracer = require("./handlers/tracer.cjs");
|
|
496
|
-
var
|
|
496
|
+
var import_storage = require("./storage/storage.cjs");
|
|
497
497
|
process.env.NODE_ENV = "production";
|
|
498
498
|
var { getRequestHandlers } = require("next/dist/server/lib/start-server.js");
|
|
499
499
|
var ResponseCache = require("next/dist/server/response-cache/index.js").default;
|
|
@@ -543,18 +543,15 @@ async function getMockedRequestHandler(...args) {
|
|
|
543
543
|
const tracer = (0, import_tracer.getTracer)();
|
|
544
544
|
return tracer.withActiveSpan("mocked request handler", async () => {
|
|
545
545
|
const ofs = { ...import_promises.default };
|
|
546
|
-
const { encodeBlobKey } = await import("../shared/blobkey.js");
|
|
547
546
|
async function readFileFallbackBlobStore(...fsargs) {
|
|
548
547
|
const [path, options] = fsargs;
|
|
549
548
|
try {
|
|
550
549
|
return await ofs.readFile(path, options);
|
|
551
550
|
} catch (error) {
|
|
552
551
|
if (typeof path === "string" && path.endsWith(".html")) {
|
|
553
|
-
const
|
|
552
|
+
const cacheStore = (0, import_storage.getMemoizedKeyValueStoreBackedByRegionalBlobStore)();
|
|
554
553
|
const relPath = (0, import_path.relative)((0, import_path.resolve)(".next/server/pages"), path);
|
|
555
|
-
const file = await
|
|
556
|
-
type: "json"
|
|
557
|
-
});
|
|
554
|
+
const file = await cacheStore.get(relPath, "staticHtml.get");
|
|
558
555
|
if (file !== null) {
|
|
559
556
|
if (!file.isFallback) {
|
|
560
557
|
const requestContext = (0, import_request_context.getRequestContext)();
|
package/dist/run/revalidate.js
CHANGED
|
@@ -11,8 +11,8 @@ import { isPromise } from "node:util/types";
|
|
|
11
11
|
function isRevalidateMethod(key, nextResponseField) {
|
|
12
12
|
return key === "revalidate" && typeof nextResponseField === "function";
|
|
13
13
|
}
|
|
14
|
-
var nextResponseProxy = (
|
|
15
|
-
return new Proxy(
|
|
14
|
+
var nextResponseProxy = (response, requestContext) => {
|
|
15
|
+
return new Proxy(response, {
|
|
16
16
|
get(target, key) {
|
|
17
17
|
const originalValue = Reflect.get(target, key);
|
|
18
18
|
if (isRevalidateMethod(key, originalValue)) {
|