410 lines
20 KiB
JavaScript
410 lines
20 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
0 && (module.exports = {
|
|
addImplicitTags: null,
|
|
patchFetch: null
|
|
});
|
|
function _export(target, all) {
|
|
for(var name in all)Object.defineProperty(target, name, {
|
|
enumerable: true,
|
|
get: all[name]
|
|
});
|
|
}
|
|
_export(exports, {
|
|
addImplicitTags: function() {
|
|
return addImplicitTags;
|
|
},
|
|
patchFetch: function() {
|
|
return patchFetch;
|
|
}
|
|
});
|
|
const _constants = require("./trace/constants");
|
|
const _tracer = require("./trace/tracer");
|
|
const _constants1 = require("../../lib/constants");
|
|
const isEdgeRuntime = process.env.NEXT_RUNTIME === "edge";
|
|
function addImplicitTags(staticGenerationStore) {
|
|
const newTags = [];
|
|
const pathname = staticGenerationStore == null ? void 0 : staticGenerationStore.originalPathname;
|
|
if (!pathname) {
|
|
return newTags;
|
|
}
|
|
if (!Array.isArray(staticGenerationStore.tags)) {
|
|
staticGenerationStore.tags = [];
|
|
}
|
|
if (!staticGenerationStore.tags.includes(pathname)) {
|
|
staticGenerationStore.tags.push(pathname);
|
|
}
|
|
newTags.push(pathname);
|
|
return newTags;
|
|
}
|
|
function trackFetchMetric(staticGenerationStore, ctx) {
|
|
if (!staticGenerationStore) return;
|
|
if (!staticGenerationStore.fetchMetrics) {
|
|
staticGenerationStore.fetchMetrics = [];
|
|
}
|
|
const dedupeFields = [
|
|
"url",
|
|
"status",
|
|
"method"
|
|
];
|
|
// don't add metric if one already exists for the fetch
|
|
if (staticGenerationStore.fetchMetrics.some((metric)=>{
|
|
return dedupeFields.every((field)=>metric[field] === ctx[field]);
|
|
})) {
|
|
return;
|
|
}
|
|
staticGenerationStore.fetchMetrics.push({
|
|
url: ctx.url,
|
|
cacheStatus: ctx.cacheStatus,
|
|
status: ctx.status,
|
|
method: ctx.method,
|
|
start: ctx.start,
|
|
end: Date.now(),
|
|
idx: staticGenerationStore.nextFetchId || 0
|
|
});
|
|
}
|
|
function patchFetch({ serverHooks , staticGenerationAsyncStorage }) {
|
|
if (!globalThis._nextOriginalFetch) {
|
|
globalThis._nextOriginalFetch = globalThis.fetch;
|
|
}
|
|
if (globalThis.fetch.__nextPatched) return;
|
|
const { DynamicServerError } = serverHooks;
|
|
const originFetch = globalThis._nextOriginalFetch;
|
|
globalThis.fetch = async (input, init)=>{
|
|
var _init_method;
|
|
let url;
|
|
try {
|
|
url = new URL(input instanceof Request ? input.url : input);
|
|
url.username = "";
|
|
url.password = "";
|
|
} catch {
|
|
// Error caused by malformed URL should be handled by native fetch
|
|
url = undefined;
|
|
}
|
|
const fetchUrl = (url == null ? void 0 : url.href) ?? "";
|
|
const fetchStart = Date.now();
|
|
const method = (init == null ? void 0 : (_init_method = init.method) == null ? void 0 : _init_method.toUpperCase()) || "GET";
|
|
return await (0, _tracer.getTracer)().trace(_constants.AppRenderSpan.fetch, {
|
|
kind: _tracer.SpanKind.CLIENT,
|
|
spanName: [
|
|
"fetch",
|
|
method,
|
|
fetchUrl
|
|
].filter(Boolean).join(" "),
|
|
attributes: {
|
|
"http.url": fetchUrl,
|
|
"http.method": method,
|
|
"net.peer.name": url == null ? void 0 : url.hostname,
|
|
"net.peer.port": (url == null ? void 0 : url.port) || undefined
|
|
}
|
|
}, async ()=>{
|
|
var _ref, _getRequestMeta;
|
|
const staticGenerationStore = staticGenerationAsyncStorage.getStore();
|
|
const isRequestInput = input && typeof input === "object" && typeof input.method === "string";
|
|
const getRequestMeta = (field)=>{
|
|
let value = isRequestInput ? input[field] : null;
|
|
return value || (init == null ? void 0 : init[field]);
|
|
};
|
|
// If the staticGenerationStore is not available, we can't do any
|
|
// special treatment of fetch, therefore fallback to the original
|
|
// fetch implementation.
|
|
if (!staticGenerationStore || ((_ref = init == null ? void 0 : init.next) == null ? void 0 : _ref.internal) || staticGenerationStore.isDraftMode) {
|
|
return originFetch(input, init);
|
|
}
|
|
let revalidate = undefined;
|
|
const getNextField = (field)=>{
|
|
var _init_next, _init_next1, _input_next;
|
|
return typeof (init == null ? void 0 : (_init_next = init.next) == null ? void 0 : _init_next[field]) !== "undefined" ? init == null ? void 0 : (_init_next1 = init.next) == null ? void 0 : _init_next1[field] : isRequestInput ? (_input_next = input.next) == null ? void 0 : _input_next[field] : undefined;
|
|
};
|
|
// RequestInit doesn't keep extra fields e.g. next so it's
|
|
// only available if init is used separate
|
|
let curRevalidate = getNextField("revalidate");
|
|
const tags = getNextField("tags") || [];
|
|
if (Array.isArray(tags)) {
|
|
if (!staticGenerationStore.tags) {
|
|
staticGenerationStore.tags = [];
|
|
}
|
|
for (const tag of tags){
|
|
if (!staticGenerationStore.tags.includes(tag)) {
|
|
staticGenerationStore.tags.push(tag);
|
|
}
|
|
}
|
|
}
|
|
const implicitTags = addImplicitTags(staticGenerationStore);
|
|
for (const tag of implicitTags || []){
|
|
if (!tags.includes(tag)) {
|
|
tags.push(tag);
|
|
}
|
|
}
|
|
const isOnlyCache = staticGenerationStore.fetchCache === "only-cache";
|
|
const isForceCache = staticGenerationStore.fetchCache === "force-cache";
|
|
const isDefaultCache = staticGenerationStore.fetchCache === "default-cache";
|
|
const isDefaultNoStore = staticGenerationStore.fetchCache === "default-no-store";
|
|
const isOnlyNoStore = staticGenerationStore.fetchCache === "only-no-store";
|
|
const isForceNoStore = staticGenerationStore.fetchCache === "force-no-store";
|
|
let _cache = getRequestMeta("cache");
|
|
if (typeof _cache === "string" && typeof curRevalidate !== "undefined") {
|
|
console.warn(`Warning: fetch for ${fetchUrl} on ${staticGenerationStore.pathname} specified "cache: ${_cache}" and "revalidate: ${curRevalidate}", only one should be specified.`);
|
|
_cache = undefined;
|
|
}
|
|
if (_cache === "force-cache") {
|
|
curRevalidate = false;
|
|
}
|
|
if ([
|
|
"no-cache",
|
|
"no-store"
|
|
].includes(_cache || "")) {
|
|
curRevalidate = 0;
|
|
}
|
|
if (typeof curRevalidate === "number" || curRevalidate === false) {
|
|
revalidate = curRevalidate;
|
|
}
|
|
let cacheReason = "";
|
|
const _headers = getRequestMeta("headers");
|
|
const initHeaders = typeof (_headers == null ? void 0 : _headers.get) === "function" ? _headers : new Headers(_headers || {});
|
|
const hasUnCacheableHeader = initHeaders.get("authorization") || initHeaders.get("cookie");
|
|
const isUnCacheableMethod = ![
|
|
"get",
|
|
"head"
|
|
].includes(((_getRequestMeta = getRequestMeta("method")) == null ? void 0 : _getRequestMeta.toLowerCase()) || "get");
|
|
// if there are authorized headers or a POST method and
|
|
// dynamic data usage was present above the tree we bail
|
|
// e.g. if cookies() is used before an authed/POST fetch
|
|
const autoNoCache = (hasUnCacheableHeader || isUnCacheableMethod) && staticGenerationStore.revalidate === 0;
|
|
if (isForceNoStore) {
|
|
revalidate = 0;
|
|
cacheReason = "fetchCache = force-no-store";
|
|
}
|
|
if (isOnlyNoStore) {
|
|
if (_cache === "force-cache" || revalidate === 0) {
|
|
throw new Error(`cache: 'force-cache' used on fetch for ${fetchUrl} with 'export const fetchCache = 'only-no-store'`);
|
|
}
|
|
revalidate = 0;
|
|
cacheReason = "fetchCache = only-no-store";
|
|
}
|
|
if (isOnlyCache && _cache === "no-store") {
|
|
throw new Error(`cache: 'no-store' used on fetch for ${fetchUrl} with 'export const fetchCache = 'only-cache'`);
|
|
}
|
|
if (isForceCache && (typeof curRevalidate === "undefined" || curRevalidate === 0)) {
|
|
cacheReason = "fetchCache = force-cache";
|
|
revalidate = false;
|
|
}
|
|
if (typeof revalidate === "undefined") {
|
|
if (isDefaultCache) {
|
|
revalidate = false;
|
|
cacheReason = "fetchCache = default-cache";
|
|
} else if (autoNoCache) {
|
|
revalidate = 0;
|
|
cacheReason = "auto no cache";
|
|
} else if (isDefaultNoStore) {
|
|
revalidate = 0;
|
|
cacheReason = "fetchCache = default-no-store";
|
|
} else {
|
|
cacheReason = "auto cache";
|
|
revalidate = typeof staticGenerationStore.revalidate === "boolean" || typeof staticGenerationStore.revalidate === "undefined" ? false : staticGenerationStore.revalidate;
|
|
}
|
|
} else if (!cacheReason) {
|
|
cacheReason = `revalidate: ${revalidate}`;
|
|
}
|
|
if (// we don't consider autoNoCache to switch to dynamic during
|
|
// revalidate although if it occurs during build we do
|
|
!autoNoCache && (typeof staticGenerationStore.revalidate === "undefined" || typeof revalidate === "number" && (staticGenerationStore.revalidate === false || typeof staticGenerationStore.revalidate === "number" && revalidate < staticGenerationStore.revalidate))) {
|
|
staticGenerationStore.revalidate = revalidate;
|
|
}
|
|
const isCacheableRevalidate = typeof revalidate === "number" && revalidate > 0 || revalidate === false;
|
|
let cacheKey;
|
|
if (staticGenerationStore.incrementalCache && isCacheableRevalidate) {
|
|
try {
|
|
cacheKey = await staticGenerationStore.incrementalCache.fetchCacheKey(fetchUrl, isRequestInput ? input : init);
|
|
} catch (err) {
|
|
console.error(`Failed to generate cache key for`, input);
|
|
}
|
|
}
|
|
const requestInputFields = [
|
|
"cache",
|
|
"credentials",
|
|
"headers",
|
|
"integrity",
|
|
"keepalive",
|
|
"method",
|
|
"mode",
|
|
"redirect",
|
|
"referrer",
|
|
"referrerPolicy",
|
|
"signal",
|
|
"window",
|
|
"duplex"
|
|
];
|
|
if (isRequestInput) {
|
|
const reqInput = input;
|
|
const reqOptions = {
|
|
body: reqInput._ogBody || reqInput.body
|
|
};
|
|
for (const field of requestInputFields){
|
|
// @ts-expect-error custom fields
|
|
reqOptions[field] = reqInput[field];
|
|
}
|
|
input = new Request(reqInput.url, reqOptions);
|
|
} else if (init) {
|
|
const initialInit = init;
|
|
init = {
|
|
body: init._ogBody || init.body
|
|
};
|
|
for (const field of requestInputFields){
|
|
// @ts-expect-error custom fields
|
|
init[field] = initialInit[field];
|
|
}
|
|
}
|
|
const fetchIdx = staticGenerationStore.nextFetchId ?? 1;
|
|
staticGenerationStore.nextFetchId = fetchIdx + 1;
|
|
const normalizedRevalidate = typeof revalidate !== "number" ? _constants1.CACHE_ONE_YEAR : revalidate;
|
|
const doOriginalFetch = async (isStale)=>{
|
|
// add metadata to init without editing the original
|
|
const clonedInit = {
|
|
...init,
|
|
next: {
|
|
...init == null ? void 0 : init.next,
|
|
fetchType: "origin",
|
|
fetchIdx
|
|
}
|
|
};
|
|
return originFetch(input, clonedInit).then(async (res)=>{
|
|
if (!isStale) {
|
|
trackFetchMetric(staticGenerationStore, {
|
|
start: fetchStart,
|
|
url: fetchUrl,
|
|
cacheReason,
|
|
cacheStatus: "miss",
|
|
status: res.status,
|
|
method: clonedInit.method || "GET"
|
|
});
|
|
}
|
|
if (res.status === 200 && staticGenerationStore.incrementalCache && cacheKey && isCacheableRevalidate) {
|
|
const bodyBuffer = Buffer.from(await res.arrayBuffer());
|
|
try {
|
|
await staticGenerationStore.incrementalCache.set(cacheKey, {
|
|
kind: "FETCH",
|
|
data: {
|
|
headers: Object.fromEntries(res.headers.entries()),
|
|
body: bodyBuffer.toString("base64"),
|
|
status: res.status,
|
|
tags,
|
|
url: res.url
|
|
},
|
|
revalidate: normalizedRevalidate
|
|
}, revalidate, true, fetchUrl, fetchIdx);
|
|
} catch (err) {
|
|
console.warn(`Failed to set fetch cache`, input, err);
|
|
}
|
|
const response = new Response(bodyBuffer, {
|
|
headers: new Headers(res.headers),
|
|
status: res.status
|
|
});
|
|
Object.defineProperty(response, "url", {
|
|
value: res.url
|
|
});
|
|
return response;
|
|
}
|
|
return res;
|
|
});
|
|
};
|
|
if (cacheKey && (staticGenerationStore == null ? void 0 : staticGenerationStore.incrementalCache)) {
|
|
const entry = staticGenerationStore.isOnDemandRevalidate ? null : await staticGenerationStore.incrementalCache.get(cacheKey, true, revalidate, fetchUrl, fetchIdx);
|
|
if ((entry == null ? void 0 : entry.value) && entry.value.kind === "FETCH") {
|
|
const currentTags = entry.value.data.tags;
|
|
// when stale and is revalidating we wait for fresh data
|
|
// so the revalidated entry has the updated data
|
|
if (!(staticGenerationStore.isRevalidate && entry.isStale)) {
|
|
if (entry.isStale) {
|
|
if (!staticGenerationStore.pendingRevalidates) {
|
|
staticGenerationStore.pendingRevalidates = [];
|
|
}
|
|
staticGenerationStore.pendingRevalidates.push(doOriginalFetch(true).catch(console.error));
|
|
} else if (tags && !tags.every((tag)=>{
|
|
return currentTags == null ? void 0 : currentTags.includes(tag);
|
|
})) {
|
|
var _staticGenerationStore_incrementalCache;
|
|
// if new tags are being added we need to set even if
|
|
// the data isn't stale
|
|
if (!entry.value.data.tags) {
|
|
entry.value.data.tags = [];
|
|
}
|
|
for (const tag of tags){
|
|
if (!entry.value.data.tags.includes(tag)) {
|
|
entry.value.data.tags.push(tag);
|
|
}
|
|
}
|
|
(_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.set(cacheKey, entry.value, revalidate, true, fetchUrl, fetchIdx);
|
|
}
|
|
const resData = entry.value.data;
|
|
let decodedBody;
|
|
if (process.env.NEXT_RUNTIME === "edge") {
|
|
const { decode } = require("../../shared/lib/base64-arraybuffer");
|
|
decodedBody = decode(resData.body);
|
|
} else {
|
|
decodedBody = Buffer.from(resData.body, "base64").subarray();
|
|
}
|
|
trackFetchMetric(staticGenerationStore, {
|
|
start: fetchStart,
|
|
url: fetchUrl,
|
|
cacheReason,
|
|
cacheStatus: "hit",
|
|
status: resData.status || 200,
|
|
method: (init == null ? void 0 : init.method) || "GET"
|
|
});
|
|
const response = new Response(decodedBody, {
|
|
headers: resData.headers,
|
|
status: resData.status
|
|
});
|
|
Object.defineProperty(response, "url", {
|
|
value: entry.value.data.url
|
|
});
|
|
return response;
|
|
}
|
|
}
|
|
}
|
|
if (staticGenerationStore.isStaticGeneration) {
|
|
if (init && typeof init === "object") {
|
|
const cache = init.cache;
|
|
// Delete `cache` property as Cloudflare Workers will throw an error
|
|
if (isEdgeRuntime) {
|
|
delete init.cache;
|
|
}
|
|
if (cache === "no-store") {
|
|
staticGenerationStore.revalidate = 0;
|
|
const dynamicUsageReason = `no-store fetch ${input}${staticGenerationStore.pathname ? ` ${staticGenerationStore.pathname}` : ""}`;
|
|
const err = new DynamicServerError(dynamicUsageReason);
|
|
staticGenerationStore.dynamicUsageErr = err;
|
|
staticGenerationStore.dynamicUsageStack = err.stack;
|
|
staticGenerationStore.dynamicUsageDescription = dynamicUsageReason;
|
|
}
|
|
const hasNextConfig = "next" in init;
|
|
const next = init.next || {};
|
|
if (typeof next.revalidate === "number" && (typeof staticGenerationStore.revalidate === "undefined" || typeof staticGenerationStore.revalidate === "number" && next.revalidate < staticGenerationStore.revalidate)) {
|
|
const forceDynamic = staticGenerationStore.forceDynamic;
|
|
if (!forceDynamic || next.revalidate !== 0) {
|
|
staticGenerationStore.revalidate = next.revalidate;
|
|
}
|
|
if (!forceDynamic && next.revalidate === 0) {
|
|
const dynamicUsageReason = `revalidate: ${next.revalidate} fetch ${input}${staticGenerationStore.pathname ? ` ${staticGenerationStore.pathname}` : ""}`;
|
|
const err = new DynamicServerError(dynamicUsageReason);
|
|
staticGenerationStore.dynamicUsageErr = err;
|
|
staticGenerationStore.dynamicUsageStack = err.stack;
|
|
staticGenerationStore.dynamicUsageDescription = dynamicUsageReason;
|
|
}
|
|
}
|
|
if (hasNextConfig) delete init.next;
|
|
}
|
|
}
|
|
return doOriginalFetch();
|
|
});
|
|
};
|
|
globalThis.fetch.__nextGetStaticStore = ()=>{
|
|
return staticGenerationAsyncStorage;
|
|
};
|
|
globalThis.fetch.__nextPatched = true;
|
|
}
|
|
|
|
//# sourceMappingURL=patch-fetch.js.map
|