Initial boiler plate project

This commit is contained in:
2024-09-24 03:52:46 +00:00
parent 6120b2d6c3
commit 154b93e267
10034 changed files with 2079352 additions and 2 deletions

View File

@ -0,0 +1,603 @@
import { RSC_HEADER, RSC_CONTENT_TYPE_HEADER } from "../../client/components/app-router-headers";
import { isNotFoundError } from "../../client/components/not-found";
import { getRedirectStatusCodeFromError, getURLFromRedirectError, isRedirectError } from "../../client/components/redirect";
import RenderResult from "../render-result";
import { FlightRenderResult } from "./flight-render-result";
import { filterReqHeaders, actionsForbiddenHeaders } from "../lib/server-ipc/utils";
import { appendMutableCookies, getModifiedCookieValues } from "../web/spec-extension/adapters/request-cookies";
import { NEXT_CACHE_REVALIDATED_TAGS_HEADER, NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER } from "../../lib/constants";
import { getServerActionRequestMetadata } from "../lib/server-action-request-meta";
import { isCsrfOriginAllowed } from "./csrf-protection";
import { warn } from "../../build/output/log";
import { RequestCookies, ResponseCookies } from "../web/spec-extension/cookies";
import { HeadersAdapter } from "../web/spec-extension/adapters/headers";
import { fromNodeOutgoingHttpHeaders } from "../web/utils";
import { selectWorkerForForwarding } from "./action-utils";
function formDataFromSearchQueryString(query) {
const searchParams = new URLSearchParams(query);
const formData = new FormData();
for (const [key, value] of searchParams){
formData.append(key, value);
}
return formData;
}
function nodeHeadersToRecord(headers) {
const record = {};
for (const [key, value] of Object.entries(headers)){
if (value !== undefined) {
record[key] = Array.isArray(value) ? value.join(", ") : `${value}`;
}
}
return record;
}
function getForwardedHeaders(req, res) {
// Get request headers and cookies
const requestHeaders = req.headers;
const requestCookies = new RequestCookies(HeadersAdapter.from(requestHeaders));
// Get response headers and cookies
const responseHeaders = res.getHeaders();
const responseCookies = new ResponseCookies(fromNodeOutgoingHttpHeaders(responseHeaders));
// Merge request and response headers
const mergedHeaders = filterReqHeaders({
...nodeHeadersToRecord(requestHeaders),
...nodeHeadersToRecord(responseHeaders)
}, actionsForbiddenHeaders);
// Merge cookies into requestCookies, so responseCookies always take precedence
// and overwrite/delete those from requestCookies.
responseCookies.getAll().forEach((cookie)=>{
if (typeof cookie.value === "undefined") {
requestCookies.delete(cookie.name);
} else {
requestCookies.set(cookie);
}
});
// Update the 'cookie' header with the merged cookies
mergedHeaders["cookie"] = requestCookies.toString();
// Remove headers that should not be forwarded
delete mergedHeaders["transfer-encoding"];
return new Headers(mergedHeaders);
}
async function addRevalidationHeader(res, { staticGenerationStore, requestStore }) {
var _staticGenerationStore_incrementalCache, _staticGenerationStore_revalidatedTags;
await Promise.all([
(_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.revalidateTag(staticGenerationStore.revalidatedTags || []),
...Object.values(staticGenerationStore.pendingRevalidates || {})
]);
// If a tag was revalidated, the client router needs to invalidate all the
// client router cache as they may be stale. And if a path was revalidated, the
// client needs to invalidate all subtrees below that path.
// To keep the header size small, we use a tuple of
// [[revalidatedPaths], isTagRevalidated ? 1 : 0, isCookieRevalidated ? 1 : 0]
// instead of a JSON object.
// TODO-APP: Currently the prefetch cache doesn't have subtree information,
// so we need to invalidate the entire cache if a path was revalidated.
// TODO-APP: Currently paths are treated as tags, so the second element of the tuple
// is always empty.
const isTagRevalidated = ((_staticGenerationStore_revalidatedTags = staticGenerationStore.revalidatedTags) == null ? void 0 : _staticGenerationStore_revalidatedTags.length) ? 1 : 0;
const isCookieRevalidated = getModifiedCookieValues(requestStore.mutableCookies).length ? 1 : 0;
res.setHeader("x-action-revalidated", JSON.stringify([
[],
isTagRevalidated,
isCookieRevalidated
]));
}
/**
* Forwards a server action request to a separate worker. Used when the requested action is not available in the current worker.
*/ async function createForwardedActionResponse(req, res, host, workerPathname, basePath, staticGenerationStore) {
var _staticGenerationStore_incrementalCache;
if (!host) {
throw new Error("Invariant: Missing `host` header from a forwarded Server Actions request.");
}
const forwardedHeaders = getForwardedHeaders(req, res);
// indicate that this action request was forwarded from another worker
// we use this to skip rendering the flight tree so that we don't update the UI
// with the response from the forwarded worker
forwardedHeaders.set("x-action-forwarded", "1");
const proto = ((_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.requestProtocol) || "https";
// For standalone or the serverful mode, use the internal origin directly
// other than the host headers from the request.
const origin = process.env.__NEXT_PRIVATE_ORIGIN || `${proto}://${host.value}`;
const fetchUrl = new URL(`${origin}${basePath}${workerPathname}`);
try {
let readableStream;
if (process.env.NEXT_RUNTIME === "edge") {
const webRequest = req;
if (!webRequest.body) {
throw new Error("invariant: Missing request body.");
}
readableStream = webRequest.body;
} else {
// Convert the Node.js readable stream to a Web Stream.
readableStream = new ReadableStream({
start (controller) {
req.on("data", (chunk)=>{
controller.enqueue(new Uint8Array(chunk));
});
req.on("end", ()=>{
controller.close();
});
req.on("error", (err)=>{
controller.error(err);
});
}
});
}
// Forward the request to the new worker
const response = await fetch(fetchUrl, {
method: "POST",
body: readableStream,
duplex: "half",
headers: forwardedHeaders,
next: {
// @ts-ignore
internal: 1
}
});
if (response.headers.get("content-type") === RSC_CONTENT_TYPE_HEADER) {
// copy the headers from the redirect response to the response we're sending
for (const [key, value] of response.headers){
if (!actionsForbiddenHeaders.includes(key)) {
res.setHeader(key, value);
}
}
return new FlightRenderResult(response.body);
} else {
var // Since we aren't consuming the response body, we cancel it to avoid memory leaks
_response_body;
(_response_body = response.body) == null ? void 0 : _response_body.cancel();
}
} catch (err) {
// we couldn't stream the forwarded response, so we'll just do a normal redirect
console.error(`failed to forward action response`, err);
}
}
async function createRedirectRenderResult(req, res, originalHost, redirectUrl, basePath, staticGenerationStore) {
res.setHeader("x-action-redirect", redirectUrl);
// If we're redirecting to another route of this Next.js application, we'll
// try to stream the response from the other worker path. When that works,
// we can save an extra roundtrip and avoid a full page reload.
// When the redirect URL starts with a `/`, or to the same host as application,
// we treat it as an app-relative redirect.
const parsedRedirectUrl = new URL(redirectUrl, "http://n");
const isAppRelativeRedirect = redirectUrl.startsWith("/") || originalHost && originalHost.value === parsedRedirectUrl.host;
if (isAppRelativeRedirect) {
var _staticGenerationStore_incrementalCache;
if (!originalHost) {
throw new Error("Invariant: Missing `host` header from a forwarded Server Actions request.");
}
const forwardedHeaders = getForwardedHeaders(req, res);
forwardedHeaders.set(RSC_HEADER, "1");
const proto = ((_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.requestProtocol) || "https";
// For standalone or the serverful mode, use the internal origin directly
// other than the host headers from the request.
const origin = process.env.__NEXT_PRIVATE_ORIGIN || `${proto}://${originalHost.value}`;
const fetchUrl = new URL(`${origin}${basePath}${parsedRedirectUrl.pathname}${parsedRedirectUrl.search}`);
if (staticGenerationStore.revalidatedTags) {
var _staticGenerationStore_incrementalCache_prerenderManifest_preview, _staticGenerationStore_incrementalCache_prerenderManifest, _staticGenerationStore_incrementalCache1;
forwardedHeaders.set(NEXT_CACHE_REVALIDATED_TAGS_HEADER, staticGenerationStore.revalidatedTags.join(","));
forwardedHeaders.set(NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER, ((_staticGenerationStore_incrementalCache1 = staticGenerationStore.incrementalCache) == null ? void 0 : (_staticGenerationStore_incrementalCache_prerenderManifest = _staticGenerationStore_incrementalCache1.prerenderManifest) == null ? void 0 : (_staticGenerationStore_incrementalCache_prerenderManifest_preview = _staticGenerationStore_incrementalCache_prerenderManifest.preview) == null ? void 0 : _staticGenerationStore_incrementalCache_prerenderManifest_preview.previewModeId) || "");
}
// Ensures that when the path was revalidated we don't return a partial response on redirects
forwardedHeaders.delete("next-router-state-tree");
try {
const response = await fetch(fetchUrl, {
method: "GET",
headers: forwardedHeaders,
next: {
// @ts-ignore
internal: 1
}
});
if (response.headers.get("content-type") === RSC_CONTENT_TYPE_HEADER) {
// copy the headers from the redirect response to the response we're sending
for (const [key, value] of response.headers){
if (!actionsForbiddenHeaders.includes(key)) {
res.setHeader(key, value);
}
}
return new FlightRenderResult(response.body);
} else {
var // Since we aren't consuming the response body, we cancel it to avoid memory leaks
_response_body;
(_response_body = response.body) == null ? void 0 : _response_body.cancel();
}
} catch (err) {
// we couldn't stream the redirect response, so we'll just do a normal redirect
console.error(`failed to get redirect response`, err);
}
}
return RenderResult.fromStatic("{}");
}
var HostType;
/**
* Ensures the value of the header can't create long logs.
*/ function limitUntrustedHeaderValueForLogs(value) {
return value.length > 100 ? value.slice(0, 100) + "..." : value;
}
export async function handleAction({ req, res, ComponentMod, serverModuleMap, generateFlight, staticGenerationStore, requestStore, serverActions, ctx }) {
const contentType = req.headers["content-type"];
const { serverActionsManifest, page } = ctx.renderOpts;
const { actionId, isURLEncodedAction, isMultipartAction, isFetchAction, isServerAction } = getServerActionRequestMetadata(req);
// If it's not a Server Action, skip handling.
if (!isServerAction) {
return;
}
if (staticGenerationStore.isStaticGeneration) {
throw new Error("Invariant: server actions can't be handled during static rendering");
}
// When running actions the default is no-store, you can still `cache: 'force-cache'`
staticGenerationStore.fetchCache = "default-no-store";
const originDomain = typeof req.headers["origin"] === "string" ? new URL(req.headers["origin"]).host : undefined;
const forwardedHostHeader = req.headers["x-forwarded-host"];
const hostHeader = req.headers["host"];
const host = forwardedHostHeader ? {
type: "x-forwarded-host",
value: forwardedHostHeader
} : hostHeader ? {
type: "host",
value: hostHeader
} : undefined;
let warning = undefined;
function warnBadServerActionRequest() {
if (warning) {
warn(warning);
}
}
// This is to prevent CSRF attacks. If `x-forwarded-host` is set, we need to
// ensure that the request is coming from the same host.
if (!originDomain) {
// This might be an old browser that doesn't send `host` header. We ignore
// this case.
warning = "Missing `origin` header from a forwarded Server Actions request.";
} else if (!host || originDomain !== host.value) {
// If the customer sets a list of allowed origins, we'll allow the request.
// These are considered safe but might be different from forwarded host set
// by the infra (i.e. reverse proxies).
if (isCsrfOriginAllowed(originDomain, serverActions == null ? void 0 : serverActions.allowedOrigins)) {
// Ignore it
} else {
if (host) {
// This seems to be an CSRF attack. We should not proceed the action.
console.error(`\`${host.type}\` header with value \`${limitUntrustedHeaderValueForLogs(host.value)}\` does not match \`origin\` header with value \`${limitUntrustedHeaderValueForLogs(originDomain)}\` from a forwarded Server Actions request. Aborting the action.`);
} else {
// This is an attack. We should not proceed the action.
console.error(`\`x-forwarded-host\` or \`host\` headers are not provided. One of these is needed to compare the \`origin\` header from a forwarded Server Actions request. Aborting the action.`);
}
const error = new Error("Invalid Server Actions request.");
if (isFetchAction) {
var _staticGenerationStore_incrementalCache;
res.statusCode = 500;
await Promise.all([
(_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.revalidateTag(staticGenerationStore.revalidatedTags || []),
...Object.values(staticGenerationStore.pendingRevalidates || {})
]);
const promise = Promise.reject(error);
try {
// we need to await the promise to trigger the rejection early
// so that it's already handled by the time we call
// the RSC runtime. Otherwise, it will throw an unhandled
// promise rejection error in the renderer.
await promise;
} catch {
// swallow error, it's gonna be handled on the client
}
return {
type: "done",
result: await generateFlight(ctx, {
actionResult: promise,
// if the page was not revalidated, we can skip the rendering the flight tree
skipFlight: !staticGenerationStore.pathWasRevalidated
})
};
}
throw error;
}
}
// ensure we avoid caching server actions unexpectedly
res.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
let bound = [];
const { actionAsyncStorage } = ComponentMod;
let actionResult;
let formState;
let actionModId;
const actionWasForwarded = Boolean(req.headers["x-action-forwarded"]);
if (actionId) {
const forwardedWorker = selectWorkerForForwarding(actionId, page, serverActionsManifest);
// If forwardedWorker is truthy, it means there isn't a worker for the action
// in the current handler, so we forward the request to a worker that has the action.
if (forwardedWorker) {
return {
type: "done",
result: await createForwardedActionResponse(req, res, host, forwardedWorker, ctx.renderOpts.basePath, staticGenerationStore)
};
}
}
try {
await actionAsyncStorage.run({
isAction: true
}, async ()=>{
if (process.env.NEXT_RUNTIME === "edge") {
// Use react-server-dom-webpack/server.edge
const { decodeReply, decodeAction, decodeFormState } = ComponentMod;
const webRequest = req;
if (!webRequest.body) {
throw new Error("invariant: Missing request body.");
}
if (isMultipartAction) {
// TODO-APP: Add streaming support
const formData = await webRequest.request.formData();
if (isFetchAction) {
bound = await decodeReply(formData, serverModuleMap);
} else {
const action = await decodeAction(formData, serverModuleMap);
if (typeof action === "function") {
// Only warn if it's a server action, otherwise skip for other post requests
warnBadServerActionRequest();
const actionReturnedState = await action();
formState = decodeFormState(actionReturnedState, formData);
}
// Skip the fetch path
return;
}
} else {
try {
actionModId = getActionModIdOrError(actionId, serverModuleMap);
} catch (err) {
if (actionId !== null) {
console.error(err);
}
return {
type: "not-found"
};
}
let actionData = "";
const reader = webRequest.body.getReader();
while(true){
const { done, value } = await reader.read();
if (done) {
break;
}
actionData += new TextDecoder().decode(value);
}
if (isURLEncodedAction) {
const formData = formDataFromSearchQueryString(actionData);
bound = await decodeReply(formData, serverModuleMap);
} else {
bound = await decodeReply(actionData, serverModuleMap);
}
}
} else {
// Use react-server-dom-webpack/server.node which supports streaming
const { decodeReply, decodeReplyFromBusboy, decodeAction, decodeFormState } = require(`./react-server.node`);
if (isMultipartAction) {
if (isFetchAction) {
const readableLimit = (serverActions == null ? void 0 : serverActions.bodySizeLimit) ?? "1 MB";
const limit = require("next/dist/compiled/bytes").parse(readableLimit);
const busboy = require("busboy");
const bb = busboy({
headers: req.headers,
limits: {
fieldSize: limit
}
});
req.pipe(bb);
bound = await decodeReplyFromBusboy(bb, serverModuleMap);
} else {
// Convert the Node.js readable stream to a Web Stream.
const readableStream = new ReadableStream({
start (controller) {
req.on("data", (chunk)=>{
controller.enqueue(new Uint8Array(chunk));
});
req.on("end", ()=>{
controller.close();
});
req.on("error", (err)=>{
controller.error(err);
});
}
});
// React doesn't yet publish a busboy version of decodeAction
// so we polyfill the parsing of FormData.
const fakeRequest = new Request("http://localhost", {
method: "POST",
// @ts-expect-error
headers: {
"Content-Type": contentType
},
body: readableStream,
duplex: "half"
});
const formData = await fakeRequest.formData();
const action = await decodeAction(formData, serverModuleMap);
if (typeof action === "function") {
// Only warn if it's a server action, otherwise skip for other post requests
warnBadServerActionRequest();
const actionReturnedState = await action();
formState = await decodeFormState(actionReturnedState, formData);
}
// Skip the fetch path
return;
}
} else {
try {
actionModId = getActionModIdOrError(actionId, serverModuleMap);
} catch (err) {
if (actionId !== null) {
console.error(err);
}
return {
type: "not-found"
};
}
const chunks = [];
for await (const chunk of req){
chunks.push(Buffer.from(chunk));
}
const actionData = Buffer.concat(chunks).toString("utf-8");
const readableLimit = (serverActions == null ? void 0 : serverActions.bodySizeLimit) ?? "1 MB";
const limit = require("next/dist/compiled/bytes").parse(readableLimit);
if (actionData.length > limit) {
const { ApiError } = require("../api-utils");
throw new ApiError(413, `Body exceeded ${readableLimit} limit.
To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit`);
}
if (isURLEncodedAction) {
const formData = formDataFromSearchQueryString(actionData);
bound = await decodeReply(formData, serverModuleMap);
} else {
bound = await decodeReply(actionData, serverModuleMap);
}
}
}
// actions.js
// app/page.js
// action worker1
// appRender1
// app/foo/page.js
// action worker2
// appRender
// / -> fire action -> POST / -> appRender1 -> modId for the action file
// /foo -> fire action -> POST /foo -> appRender2 -> modId for the action file
try {
actionModId = actionModId ?? getActionModIdOrError(actionId, serverModuleMap);
} catch (err) {
if (actionId !== null) {
console.error(err);
}
return {
type: "not-found"
};
}
const actionHandler = (await ComponentMod.__next_app__.require(actionModId))[// `actionId` must exist if we got here, as otherwise we would have thrown an error above
actionId];
const returnVal = await actionHandler.apply(null, bound);
// For form actions, we need to continue rendering the page.
if (isFetchAction) {
await addRevalidationHeader(res, {
staticGenerationStore,
requestStore
});
actionResult = await generateFlight(ctx, {
actionResult: Promise.resolve(returnVal),
// if the page was not revalidated, or if the action was forwarded from another worker, we can skip the rendering the flight tree
skipFlight: !staticGenerationStore.pathWasRevalidated || actionWasForwarded
});
}
});
return {
type: "done",
result: actionResult,
formState
};
} catch (err) {
if (isRedirectError(err)) {
const redirectUrl = getURLFromRedirectError(err);
const statusCode = getRedirectStatusCodeFromError(err);
await addRevalidationHeader(res, {
staticGenerationStore,
requestStore
});
// if it's a fetch action, we'll set the status code for logging/debugging purposes
// but we won't set a Location header, as the redirect will be handled by the client router
res.statusCode = statusCode;
if (isFetchAction) {
return {
type: "done",
result: await createRedirectRenderResult(req, res, host, redirectUrl, ctx.renderOpts.basePath, staticGenerationStore)
};
}
if (err.mutableCookies) {
const headers = new Headers();
// If there were mutable cookies set, we need to set them on the
// response.
if (appendMutableCookies(headers, err.mutableCookies)) {
res.setHeader("set-cookie", Array.from(headers.values()));
}
}
res.setHeader("Location", redirectUrl);
return {
type: "done",
result: RenderResult.fromStatic("")
};
} else if (isNotFoundError(err)) {
res.statusCode = 404;
await addRevalidationHeader(res, {
staticGenerationStore,
requestStore
});
if (isFetchAction) {
const promise = Promise.reject(err);
try {
// we need to await the promise to trigger the rejection early
// so that it's already handled by the time we call
// the RSC runtime. Otherwise, it will throw an unhandled
// promise rejection error in the renderer.
await promise;
} catch {
// swallow error, it's gonna be handled on the client
}
return {
type: "done",
result: await generateFlight(ctx, {
skipFlight: false,
actionResult: promise,
asNotFound: true
})
};
}
return {
type: "not-found"
};
}
if (isFetchAction) {
var _staticGenerationStore_incrementalCache1;
res.statusCode = 500;
await Promise.all([
(_staticGenerationStore_incrementalCache1 = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache1.revalidateTag(staticGenerationStore.revalidatedTags || []),
...Object.values(staticGenerationStore.pendingRevalidates || {})
]);
const promise = Promise.reject(err);
try {
// we need to await the promise to trigger the rejection early
// so that it's already handled by the time we call
// the RSC runtime. Otherwise, it will throw an unhandled
// promise rejection error in the renderer.
await promise;
} catch {
// swallow error, it's gonna be handled on the client
}
return {
type: "done",
result: await generateFlight(ctx, {
actionResult: promise,
// if the page was not revalidated, or if the action was forwarded from another worker, we can skip the rendering the flight tree
skipFlight: !staticGenerationStore.pathWasRevalidated || actionWasForwarded
})
};
}
throw err;
}
}
/**
* Attempts to find the module ID for the action from the module map. When this fails, it could be a deployment skew where
* the action came from a different deployment. It could also simply be an invalid POST request that is not a server action.
* In either case, we'll throw an error to be handled by the caller.
*/ function getActionModIdOrError(actionId, serverModuleMap) {
try {
var _serverModuleMap_actionId;
// if we're missing the action ID header, we can't do any further processing
if (!actionId) {
throw new Error("Invariant: Missing 'next-action' header.");
}
const actionModId = serverModuleMap == null ? void 0 : (_serverModuleMap_actionId = serverModuleMap[actionId]) == null ? void 0 : _serverModuleMap_actionId.id;
if (!actionModId) {
throw new Error("Invariant: Couldn't find action module ID from module map.");
}
return actionModId;
} catch (err) {
throw new Error(`Failed to find Server Action "${actionId}". This request might be from an older or newer deployment. ${err instanceof Error ? `Original error: ${err.message}` : ""}`);
}
}
//# sourceMappingURL=action-handler.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,50 @@
import { normalizeAppPath } from "../../shared/lib/router/utils/app-paths";
import { pathHasPrefix } from "../../shared/lib/router/utils/path-has-prefix";
import { removePathPrefix } from "../../shared/lib/router/utils/remove-path-prefix";
// This function creates a Flight-acceptable server module map proxy from our
// Server Reference Manifest similar to our client module map.
// This is because our manifest contains a lot of internal Next.js data that
// are relevant to the runtime, workers, etc. that React doesn't need to know.
export function createServerModuleMap({ serverActionsManifest, pageName }) {
return new Proxy({}, {
get: (_, id)=>{
return {
id: serverActionsManifest[process.env.NEXT_RUNTIME === "edge" ? "edge" : "node"][id].workers[normalizeWorkerPageName(pageName)],
name: id,
chunks: []
};
}
});
}
/**
* Checks if the requested action has a worker for the current page.
* If not, it returns the first worker that has a handler for the action.
*/ export function selectWorkerForForwarding(actionId, pageName, serverActionsManifest) {
var _serverActionsManifest__actionId;
const workers = (_serverActionsManifest__actionId = serverActionsManifest[process.env.NEXT_RUNTIME === "edge" ? "edge" : "node"][actionId]) == null ? void 0 : _serverActionsManifest__actionId.workers;
const workerName = normalizeWorkerPageName(pageName);
// no workers, nothing to forward to
if (!workers) return;
// if there is a worker for this page, no need to forward it.
if (workers[workerName]) {
return;
}
// otherwise, grab the first worker that has a handler for this action id
return denormalizeWorkerPageName(Object.keys(workers)[0]);
}
/**
* The flight entry loader keys actions by bundlePath.
* bundlePath corresponds with the relative path (including 'app') to the page entrypoint.
*/ function normalizeWorkerPageName(pageName) {
if (pathHasPrefix(pageName, "app")) {
return pageName;
}
return "app" + pageName;
}
/**
* Converts a bundlePath (relative path to the entrypoint) to a routable page name
*/ function denormalizeWorkerPageName(bundlePath) {
return normalizeAppPath(removePathPrefix(bundlePath, "app"));
}
//# sourceMappingURL=action-utils.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/action-utils.ts"],"names":["normalizeAppPath","pathHasPrefix","removePathPrefix","createServerModuleMap","serverActionsManifest","pageName","Proxy","get","_","id","process","env","NEXT_RUNTIME","workers","normalizeWorkerPageName","name","chunks","selectWorkerForForwarding","actionId","workerName","denormalizeWorkerPageName","Object","keys","bundlePath"],"mappings":"AACA,SAASA,gBAAgB,QAAQ,0CAAyC;AAC1E,SAASC,aAAa,QAAQ,gDAA+C;AAC7E,SAASC,gBAAgB,QAAQ,mDAAkD;AAEnF,6EAA6E;AAC7E,8DAA8D;AAC9D,4EAA4E;AAC5E,8EAA8E;AAC9E,OAAO,SAASC,sBAAsB,EACpCC,qBAAqB,EACrBC,QAAQ,EAIT;IACC,OAAO,IAAIC,MACT,CAAC,GACD;QACEC,KAAK,CAACC,GAAGC;YACP,OAAO;gBACLA,IAAIL,qBAAqB,CACvBM,QAAQC,GAAG,CAACC,YAAY,KAAK,SAAS,SAAS,OAChD,CAACH,GAAG,CAACI,OAAO,CAACC,wBAAwBT,UAAU;gBAChDU,MAAMN;gBACNO,QAAQ,EAAE;YACZ;QACF;IACF;AAEJ;AAEA;;;CAGC,GACD,OAAO,SAASC,0BACdC,QAAgB,EAChBb,QAAgB,EAChBD,qBAAqC;QAGnCA;IADF,MAAMS,WACJT,mCAAAA,qBAAqB,CACnBM,QAAQC,GAAG,CAACC,YAAY,KAAK,SAAS,SAAS,OAChD,CAACM,SAAS,qBAFXd,iCAEaS,OAAO;IACtB,MAAMM,aAAaL,wBAAwBT;IAE3C,oCAAoC;IACpC,IAAI,CAACQ,SAAS;IAEd,6DAA6D;IAC7D,IAAIA,OAAO,CAACM,WAAW,EAAE;QACvB;IACF;IAEA,yEAAyE;IACzE,OAAOC,0BAA0BC,OAAOC,IAAI,CAACT,QAAQ,CAAC,EAAE;AAC1D;AAEA;;;CAGC,GACD,SAASC,wBAAwBT,QAAgB;IAC/C,IAAIJ,cAAcI,UAAU,QAAQ;QAClC,OAAOA;IACT;IAEA,OAAO,QAAQA;AACjB;AAEA;;CAEC,GACD,SAASe,0BAA0BG,UAAkB;IACnD,OAAOvB,iBAAiBE,iBAAiBqB,YAAY;AACvD"}

View File

@ -0,0 +1,962 @@
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React from "react";
import RenderResult from "../render-result";
import { chainStreams, renderToInitialFizzStream, continueFizzStream, continueDynamicPrerender, continueStaticPrerender, continueDynamicHTMLResume, continueDynamicDataResume } from "../stream-utils/node-web-streams-helper";
import { canSegmentBeOverridden } from "../../client/components/match-segments";
import { stripInternalQueries } from "../internal-utils";
import { NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE, NEXT_URL, RSC_HEADER } from "../../client/components/app-router-headers";
import { createMetadataComponents, createMetadataContext } from "../../lib/metadata/metadata";
import { RequestAsyncStorageWrapper } from "../async-storage/request-async-storage-wrapper";
import { StaticGenerationAsyncStorageWrapper } from "../async-storage/static-generation-async-storage-wrapper";
import { isNotFoundError } from "../../client/components/not-found";
import { getURLFromRedirectError, isRedirectError, getRedirectStatusCodeFromError } from "../../client/components/redirect";
import { addImplicitTags } from "../lib/patch-fetch";
import { AppRenderSpan, NextNodeServerSpan } from "../lib/trace/constants";
import { getTracer } from "../lib/trace/tracer";
import { FlightRenderResult } from "./flight-render-result";
import { createErrorHandler, ErrorHandlerSource } from "./create-error-handler";
import { getShortDynamicParamType, dynamicParamTypes } from "./get-short-dynamic-param-type";
import { getSegmentParam } from "./get-segment-param";
import { getScriptNonceFromHeader } from "./get-script-nonce-from-header";
import { parseAndValidateFlightRouterState } from "./parse-and-validate-flight-router-state";
import { validateURL } from "./validate-url";
import { createFlightRouterStateFromLoaderTree } from "./create-flight-router-state-from-loader-tree";
import { handleAction } from "./action-handler";
import { isBailoutToCSRError } from "../../shared/lib/lazy-dynamic/bailout-to-csr";
import { warn, error } from "../../build/output/log";
import { appendMutableCookies } from "../web/spec-extension/adapters/request-cookies";
import { createServerInsertedHTML } from "./server-inserted-html";
import { getRequiredScripts } from "./required-scripts";
import { addPathPrefix } from "../../shared/lib/router/utils/add-path-prefix";
import { makeGetServerInsertedHTML } from "./make-get-server-inserted-html";
import { walkTreeWithFlightRouterState } from "./walk-tree-with-flight-router-state";
import { createComponentTree } from "./create-component-tree";
import { getAssetQueryString } from "./get-asset-query-string";
import { setReferenceManifestsSingleton } from "./encryption-utils";
import { createStaticRenderer, getDynamicDataPostponedState, getDynamicHTMLPostponedState } from "./static/static-renderer";
import { isDynamicServerError } from "../../client/components/hooks-server-context";
import { useFlightStream, createInlinedDataReadableStream, flightRenderComplete } from "./use-flight-response";
import { StaticGenBailoutError, isStaticGenBailoutError } from "../../client/components/static-generation-bailout";
import { isInterceptionRouteAppPath } from "../future/helpers/interception-routes";
import { getStackWithoutErrorMessage } from "../../lib/format-server-error";
import { usedDynamicAPIs, createPostponedAbortSignal, formatDynamicAPIAccesses } from "./dynamic-rendering";
import { getClientComponentLoaderMetrics, wrapClientComponentLoader } from "../client-component-renderer-logger";
import { createServerModuleMap } from "./action-utils";
function createNotFoundLoaderTree(loaderTree) {
// Align the segment with parallel-route-default in next-app-loader
return [
"",
{},
loaderTree[2]
];
}
/* This method is important for intercepted routes to function:
* when a route is intercepted, e.g. /blog/[slug], it will be rendered
* with the layout of the previous page, e.g. /profile/[id]. The problem is
* that the loader tree needs to know the dynamic param in order to render (id and slug in the example).
* Normally they are read from the path but since we are intercepting the route, the path would not contain id,
* so we need to read it from the router state.
*/ function findDynamicParamFromRouterState(flightRouterState, segment) {
if (!flightRouterState) {
return null;
}
const treeSegment = flightRouterState[0];
if (canSegmentBeOverridden(segment, treeSegment)) {
if (!Array.isArray(treeSegment) || Array.isArray(segment)) {
return null;
}
return {
param: treeSegment[0],
value: treeSegment[1],
treeSegment: treeSegment,
type: treeSegment[2]
};
}
for (const parallelRouterState of Object.values(flightRouterState[1])){
const maybeDynamicParam = findDynamicParamFromRouterState(parallelRouterState, segment);
if (maybeDynamicParam) {
return maybeDynamicParam;
}
}
return null;
}
/**
* Returns a function that parses the dynamic segment and return the associated value.
*/ function makeGetDynamicParamFromSegment(params, flightRouterState) {
return function getDynamicParamFromSegment(// [slug] / [[slug]] / [...slug]
segment) {
const segmentParam = getSegmentParam(segment);
if (!segmentParam) {
return null;
}
const key = segmentParam.param;
let value = params[key];
// this is a special marker that will be present for interception routes
if (value === "__NEXT_EMPTY_PARAM__") {
value = undefined;
}
if (Array.isArray(value)) {
value = value.map((i)=>encodeURIComponent(i));
} else if (typeof value === "string") {
value = encodeURIComponent(value);
}
if (!value) {
// Handle case where optional catchall does not have a value, e.g. `/dashboard/[...slug]` when requesting `/dashboard`
if (segmentParam.type === "optional-catchall") {
const type = dynamicParamTypes[segmentParam.type];
return {
param: key,
value: null,
type: type,
// This value always has to be a string.
treeSegment: [
key,
"",
type
]
};
}
return findDynamicParamFromRouterState(flightRouterState, segment);
}
const type = getShortDynamicParamType(segmentParam.type);
return {
param: key,
// The value that is passed to user code.
value: value,
// The value that is rendered in the router tree.
treeSegment: [
key,
Array.isArray(value) ? value.join("/") : value,
type
],
type: type
};
};
}
function NonIndex({ ctx }) {
const is404Page = ctx.pagePath === "/404";
const isInvalidStatusCode = typeof ctx.res.statusCode === "number" && ctx.res.statusCode > 400;
if (is404Page || isInvalidStatusCode) {
return /*#__PURE__*/ _jsx("meta", {
name: "robots",
content: "noindex"
});
}
return null;
}
// Handle Flight render request. This is only used when client-side navigating. E.g. when you `router.push('/dashboard')` or `router.reload()`.
async function generateFlight(ctx, options) {
// Flight data that is going to be passed to the browser.
// Currently a single item array but in the future multiple patches might be combined in a single request.
let flightData = null;
const { componentMod: { tree: loaderTree, renderToReadableStream, createDynamicallyTrackedSearchParams }, getDynamicParamFromSegment, appUsingSizeAdjustment, staticGenerationStore: { urlPathname }, query, requestId, flightRouterState } = ctx;
if (!(options == null ? void 0 : options.skipFlight)) {
const [MetadataTree, MetadataOutlet] = createMetadataComponents({
tree: loaderTree,
query,
metadataContext: createMetadataContext(urlPathname, ctx.renderOpts),
getDynamicParamFromSegment,
appUsingSizeAdjustment,
createDynamicallyTrackedSearchParams
});
flightData = (await walkTreeWithFlightRouterState({
ctx,
createSegmentPath: (child)=>child,
loaderTreeToFilter: loaderTree,
parentParams: {},
flightRouterState,
isFirst: true,
// For flight, render metadata inside leaf page
// NOTE: in 14.2, fragment doesn't work well with React, using array instead
rscPayloadHead: [
/*#__PURE__*/ _jsx(MetadataTree, {}, requestId),
/*#__PURE__*/ _jsx(NonIndex, {
ctx: ctx
}, "noindex")
],
injectedCSS: new Set(),
injectedJS: new Set(),
injectedFontPreloadTags: new Set(),
rootLayoutIncluded: false,
asNotFound: ctx.isNotFoundPath || (options == null ? void 0 : options.asNotFound),
metadataOutlet: /*#__PURE__*/ _jsx(MetadataOutlet, {})
})).map((path)=>path.slice(1)) // remove the '' (root) segment
;
}
const buildIdFlightDataPair = [
ctx.renderOpts.buildId,
flightData
];
// For app dir, use the bundled version of Flight server renderer (renderToReadableStream)
// which contains the subset React.
const flightReadableStream = renderToReadableStream(options ? [
options.actionResult,
buildIdFlightDataPair
] : buildIdFlightDataPair, ctx.clientReferenceManifest.clientModules, {
onError: ctx.flightDataRendererErrorHandler
});
return new FlightRenderResult(flightReadableStream);
}
/**
* Creates a resolver that eagerly generates a flight payload that is then
* resolved when the resolver is called.
*/ function createFlightDataResolver(ctx) {
// Generate the flight data and as soon as it can, convert it into a string.
const promise = generateFlight(ctx).then(async (result)=>({
flightData: await result.toUnchunkedString(true)
}))// Otherwise if it errored, return the error.
.catch((err)=>({
err
}));
return async ()=>{
// Resolve the promise to get the flight data or error.
const result = await promise;
// If the flight data failed to render due to an error, re-throw the error
// here.
if ("err" in result) {
throw result.err;
}
// Otherwise, return the flight data.
return result.flightData;
};
}
/**
* Crawlers will inadvertently think the canonicalUrl in the RSC payload should be crawled
* when our intention is to just seed the router state with the current URL.
* This function splits up the pathname so that we can later join it on
* when we're ready to consume the path.
*/ function prepareInitialCanonicalUrl(pathname) {
return pathname.split("/");
}
// This is the root component that runs in the RSC context
async function ReactServerApp({ tree, ctx, asNotFound }) {
// Create full component tree from root to leaf.
const injectedCSS = new Set();
const injectedJS = new Set();
const injectedFontPreloadTags = new Set();
const missingSlots = new Set();
const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { AppRouter, GlobalError, createDynamicallyTrackedSearchParams }, staticGenerationStore: { urlPathname } } = ctx;
const initialTree = createFlightRouterStateFromLoaderTree(tree, getDynamicParamFromSegment, query);
const [MetadataTree, MetadataOutlet] = createMetadataComponents({
tree,
errorType: asNotFound ? "not-found" : undefined,
query,
metadataContext: createMetadataContext(urlPathname, ctx.renderOpts),
getDynamicParamFromSegment: getDynamicParamFromSegment,
appUsingSizeAdjustment: appUsingSizeAdjustment,
createDynamicallyTrackedSearchParams
});
const seedData = await createComponentTree({
ctx,
createSegmentPath: (child)=>child,
loaderTree: tree,
parentParams: {},
firstItem: true,
injectedCSS,
injectedJS,
injectedFontPreloadTags,
rootLayoutIncluded: false,
asNotFound: asNotFound,
metadataOutlet: /*#__PURE__*/ _jsx(MetadataOutlet, {}),
missingSlots
});
// When the `vary` response header is present with `Next-URL`, that means there's a chance
// it could respond differently if there's an interception route. We provide this information
// to `AppRouter` so that it can properly seed the prefetch cache with a prefix, if needed.
const varyHeader = ctx.res.getHeader("vary");
const couldBeIntercepted = typeof varyHeader === "string" && varyHeader.includes(NEXT_URL);
return /*#__PURE__*/ _jsx(AppRouter, {
buildId: ctx.renderOpts.buildId,
assetPrefix: ctx.assetPrefix,
urlParts: prepareInitialCanonicalUrl(urlPathname),
// This is the router state tree.
initialTree: initialTree,
// This is the tree of React nodes that are seeded into the cache
initialSeedData: seedData,
couldBeIntercepted: couldBeIntercepted,
initialHead: /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx(NonIndex, {
ctx: ctx
}),
/*#__PURE__*/ _jsx(MetadataTree, {}, ctx.requestId)
]
}),
globalErrorComponent: GlobalError,
// This is used to provide debug information (when in development mode)
// about which slots were not filled by page components while creating the component tree.
missingSlots: missingSlots
});
}
// This is the root component that runs in the RSC context
async function ReactServerError({ tree, ctx, errorType }) {
const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { AppRouter, GlobalError, createDynamicallyTrackedSearchParams }, staticGenerationStore: { urlPathname }, requestId } = ctx;
const [MetadataTree] = createMetadataComponents({
tree,
metadataContext: createMetadataContext(urlPathname, ctx.renderOpts),
errorType,
query,
getDynamicParamFromSegment,
appUsingSizeAdjustment,
createDynamicallyTrackedSearchParams
});
const head = /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx(MetadataTree, {}, requestId),
process.env.NODE_ENV === "development" && /*#__PURE__*/ _jsx("meta", {
name: "next-error",
content: "not-found"
}),
/*#__PURE__*/ _jsx(NonIndex, {
ctx: ctx
})
]
});
const initialTree = createFlightRouterStateFromLoaderTree(tree, getDynamicParamFromSegment, query);
// For metadata notFound error there's no global not found boundary on top
// so we create a not found page with AppRouter
const initialSeedData = [
initialTree[0],
{},
/*#__PURE__*/ _jsxs("html", {
id: "__next_error__",
children: [
/*#__PURE__*/ _jsx("head", {}),
/*#__PURE__*/ _jsx("body", {})
]
}),
null
];
return /*#__PURE__*/ _jsx(AppRouter, {
buildId: ctx.renderOpts.buildId,
assetPrefix: ctx.assetPrefix,
urlParts: prepareInitialCanonicalUrl(urlPathname),
initialTree: initialTree,
initialHead: head,
globalErrorComponent: GlobalError,
initialSeedData: initialSeedData,
missingSlots: new Set()
});
}
// This component must run in an SSR context. It will render the RSC root component
function ReactServerEntrypoint({ reactServerStream, preinitScripts, clientReferenceManifest, nonce }) {
preinitScripts();
const response = useFlightStream(reactServerStream, clientReferenceManifest, nonce);
return React.use(response);
}
async function renderToHTMLOrFlightImpl(req, res, pagePath, query, renderOpts, baseCtx, requestEndedState) {
var _getTracer_getRootSpanAttributes, _staticGenerationStore_prerenderState;
const isNotFoundPath = pagePath === "/404";
// A unique request timestamp used by development to ensure that it's
// consistent and won't change during this request. This is important to
// avoid that resources can be deduped by React Float if the same resource is
// rendered or preloaded multiple times: `<link href="a.css?v={Date.now()}"/>`.
const requestTimestamp = Date.now();
const { buildManifest, subresourceIntegrityManifest, serverActionsManifest, ComponentMod, dev, nextFontManifest, supportsDynamicResponse, serverActions, appDirDevErrorLogger, assetPrefix = "", enableTainting } = renderOpts;
// We need to expose the bundled `require` API globally for
// react-server-dom-webpack. This is a hack until we find a better way.
if (ComponentMod.__next_app__) {
const instrumented = wrapClientComponentLoader(ComponentMod);
// @ts-ignore
globalThis.__next_require__ = instrumented.require;
// @ts-ignore
globalThis.__next_chunk_load__ = instrumented.loadChunk;
}
if (typeof req.on === "function") {
req.on("end", ()=>{
requestEndedState.ended = true;
if ("performance" in globalThis) {
const metrics = getClientComponentLoaderMetrics({
reset: true
});
if (metrics) {
getTracer().startSpan(NextNodeServerSpan.clientComponentLoading, {
startTime: metrics.clientComponentLoadStart,
attributes: {
"next.clientComponentLoadCount": metrics.clientComponentLoadCount
}
}).end(metrics.clientComponentLoadStart + metrics.clientComponentLoadTimes);
}
}
});
}
const metadata = {};
const appUsingSizeAdjustment = !!(nextFontManifest == null ? void 0 : nextFontManifest.appUsingSizeAdjust);
// TODO: fix this typescript
const clientReferenceManifest = renderOpts.clientReferenceManifest;
const serverModuleMap = createServerModuleMap({
serverActionsManifest,
pageName: renderOpts.page
});
setReferenceManifestsSingleton({
clientReferenceManifest,
serverActionsManifest,
serverModuleMap
});
const digestErrorsMap = new Map();
const allCapturedErrors = [];
const isNextExport = !!renderOpts.nextExport;
const { staticGenerationStore, requestStore } = baseCtx;
const { isStaticGeneration } = staticGenerationStore;
// when static generation fails during PPR, we log the errors separately. We intentionally
// silence the error logger in this case to avoid double logging.
const silenceStaticGenerationErrors = renderOpts.experimental.ppr && isStaticGeneration;
const serverComponentsErrorHandler = createErrorHandler({
source: ErrorHandlerSource.serverComponents,
dev,
isNextExport,
errorLogger: appDirDevErrorLogger,
digestErrorsMap,
silenceLogger: silenceStaticGenerationErrors
});
const flightDataRendererErrorHandler = createErrorHandler({
source: ErrorHandlerSource.flightData,
dev,
isNextExport,
errorLogger: appDirDevErrorLogger,
digestErrorsMap,
silenceLogger: silenceStaticGenerationErrors
});
const htmlRendererErrorHandler = createErrorHandler({
source: ErrorHandlerSource.html,
dev,
isNextExport,
errorLogger: appDirDevErrorLogger,
digestErrorsMap,
allCapturedErrors,
silenceLogger: silenceStaticGenerationErrors
});
ComponentMod.patchFetch();
/**
* Rules of Static & Dynamic HTML:
*
* 1.) We must generate static HTML unless the caller explicitly opts
* in to dynamic HTML support.
*
* 2.) If dynamic HTML support is requested, we must honor that request
* or throw an error. It is the sole responsibility of the caller to
* ensure they aren't e.g. requesting dynamic HTML for an AMP page.
*
* These rules help ensure that other existing features like request caching,
* coalescing, and ISR continue working as intended.
*/ const generateStaticHTML = supportsDynamicResponse !== true;
// Pull out the hooks/references from the component.
const { tree: loaderTree, taintObjectReference } = ComponentMod;
if (enableTainting) {
taintObjectReference("Do not pass process.env to client components since it will leak sensitive data", process.env);
}
staticGenerationStore.fetchMetrics = [];
metadata.fetchMetrics = staticGenerationStore.fetchMetrics;
// don't modify original query object
query = {
...query
};
stripInternalQueries(query);
const isRSCRequest = req.headers[RSC_HEADER.toLowerCase()] !== undefined;
const isPrefetchRSCRequest = isRSCRequest && req.headers[NEXT_ROUTER_PREFETCH_HEADER.toLowerCase()] !== undefined;
/**
* Router state provided from the client-side router. Used to handle rendering
* from the common layout down. This value will be undefined if the request
* is not a client-side navigation request or if the request is a prefetch
* request (except when it's a prefetch request for an interception route
* which is always dynamic).
*/ const shouldProvideFlightRouterState = isRSCRequest && (!isPrefetchRSCRequest || !renderOpts.experimental.ppr || // Interception routes currently depend on the flight router state to
// extract dynamic params.
isInterceptionRouteAppPath(pagePath));
const parsedFlightRouterState = parseAndValidateFlightRouterState(req.headers[NEXT_ROUTER_STATE_TREE.toLowerCase()]);
/**
* The metadata items array created in next-app-loader with all relevant information
* that we need to resolve the final metadata.
*/ let requestId;
if (process.env.NEXT_RUNTIME === "edge") {
requestId = crypto.randomUUID();
} else {
requestId = require("next/dist/compiled/nanoid").nanoid();
}
/**
* Dynamic parameters. E.g. when you visit `/dashboard/vercel` which is rendered by `/dashboard/[slug]` the value will be {"slug": "vercel"}.
*/ const params = renderOpts.params ?? {};
const getDynamicParamFromSegment = makeGetDynamicParamFromSegment(params, // `FlightRouterState` is unconditionally provided here because this method uses it
// to extract dynamic params as a fallback if they're not present in the path.
parsedFlightRouterState);
const ctx = {
...baseCtx,
getDynamicParamFromSegment,
query,
isPrefetch: isPrefetchRSCRequest,
requestTimestamp,
appUsingSizeAdjustment,
flightRouterState: shouldProvideFlightRouterState ? parsedFlightRouterState : undefined,
requestId,
defaultRevalidate: false,
pagePath,
clientReferenceManifest,
assetPrefix,
flightDataRendererErrorHandler,
serverComponentsErrorHandler,
isNotFoundPath,
res
};
if (isRSCRequest && !isStaticGeneration) {
return generateFlight(ctx);
}
// Create the resolver that can get the flight payload when it's ready or
// throw the error if it occurred. If we are not generating static HTML, we
// don't need to generate the flight payload because it's a dynamic request
// which means we're either getting the flight payload only or just the
// regular HTML.
const flightDataResolver = isStaticGeneration ? createFlightDataResolver(ctx) : null;
// Get the nonce from the incoming request if it has one.
const csp = req.headers["content-security-policy"] || req.headers["content-security-policy-report-only"];
let nonce;
if (csp && typeof csp === "string") {
nonce = getScriptNonceFromHeader(csp);
}
const validateRootLayout = dev;
const { HeadManagerContext } = require("../../shared/lib/head-manager-context.shared-runtime");
// On each render, create a new `ServerInsertedHTML` context to capture
// injected nodes from user code (`useServerInsertedHTML`).
const { ServerInsertedHTMLProvider, renderServerInsertedHTML } = createServerInsertedHTML();
(_getTracer_getRootSpanAttributes = getTracer().getRootSpanAttributes()) == null ? void 0 : _getTracer_getRootSpanAttributes.set("next.route", pagePath);
const renderToStream = getTracer().wrap(AppRenderSpan.getBodyResult, {
spanName: `render route (app) ${pagePath}`,
attributes: {
"next.route": pagePath
}
}, async ({ asNotFound, tree, formState })=>{
const polyfills = buildManifest.polyfillFiles.filter((polyfill)=>polyfill.endsWith(".js") && !polyfill.endsWith(".module.js")).map((polyfill)=>({
src: `${assetPrefix}/_next/${polyfill}${getAssetQueryString(ctx, false)}`,
integrity: subresourceIntegrityManifest == null ? void 0 : subresourceIntegrityManifest[polyfill],
crossOrigin: renderOpts.crossOrigin,
noModule: true,
nonce
}));
const [preinitScripts, bootstrapScript] = getRequiredScripts(buildManifest, assetPrefix, renderOpts.crossOrigin, subresourceIntegrityManifest, getAssetQueryString(ctx, true), nonce);
// We kick off the Flight Request (render) here. It is ok to initiate the render in an arbitrary
// place however it is critical that we only construct the Flight Response inside the SSR
// render so that directives like preloads are correctly piped through
const serverStream = ComponentMod.renderToReadableStream(/*#__PURE__*/ _jsx(ReactServerApp, {
tree: tree,
ctx: ctx,
asNotFound: asNotFound
}), clientReferenceManifest.clientModules, {
onError: serverComponentsErrorHandler
});
// We are going to consume this render both for SSR and for inlining the flight data
let [renderStream, dataStream] = serverStream.tee();
const children = /*#__PURE__*/ _jsx(HeadManagerContext.Provider, {
value: {
appDir: true,
nonce
},
children: /*#__PURE__*/ _jsx(ServerInsertedHTMLProvider, {
children: /*#__PURE__*/ _jsx(ReactServerEntrypoint, {
reactServerStream: renderStream,
preinitScripts: preinitScripts,
clientReferenceManifest: clientReferenceManifest,
nonce: nonce
})
})
});
const isResume = !!renderOpts.postponed;
const onHeaders = staticGenerationStore.prerenderState ? (headers)=>{
headers.forEach((value, key)=>{
metadata.headers ??= {};
metadata.headers[key] = value;
});
} : isStaticGeneration || isResume ? // ask React to emit headers. For Resume this is just not supported
// For static generation we know there will be an entire HTML document
// output and so moving from tag to header for preloading can only
// server to alter preloading priorities in unwanted ways
undefined : // early headers to the response
(headers)=>{
headers.forEach((value, key)=>{
res.appendHeader(key, value);
});
};
const getServerInsertedHTML = makeGetServerInsertedHTML({
polyfills,
renderServerInsertedHTML,
serverCapturedErrors: allCapturedErrors,
basePath: renderOpts.basePath
});
const renderer = createStaticRenderer({
ppr: renderOpts.experimental.ppr,
isStaticGeneration,
// If provided, the postpone state should be parsed as JSON so it can be
// provided to React.
postponed: typeof renderOpts.postponed === "string" ? JSON.parse(renderOpts.postponed) : null,
streamOptions: {
onError: htmlRendererErrorHandler,
onHeaders,
maxHeadersLength: 600,
nonce,
bootstrapScripts: [
bootstrapScript
],
formState
}
});
try {
let { stream, postponed, resumed } = await renderer.render(children);
const prerenderState = staticGenerationStore.prerenderState;
if (prerenderState) {
/**
* When prerendering there are three outcomes to consider
*
* Dynamic HTML: The prerender has dynamic holes (caused by using Next.js Dynamic Rendering APIs)
* We will need to resume this result when requests are handled and we don't include
* any server inserted HTML or inlined flight data in the static HTML
*
* Dynamic Data: The prerender has no dynamic holes but dynamic APIs were used. We will not
* resume this render when requests are handled but we will generate new inlined
* flight data since it is dynamic and differences may end up reconciling on the client
*
* Static: The prerender has no dynamic holes and no dynamic APIs were used. We statically encode
* all server inserted HTML and flight data
*/ // First we check if we have any dynamic holes in our HTML prerender
if (usedDynamicAPIs(prerenderState)) {
if (postponed != null) {
// This is the Dynamic HTML case.
metadata.postponed = JSON.stringify(getDynamicHTMLPostponedState(postponed));
} else {
// This is the Dynamic Data case
metadata.postponed = JSON.stringify(getDynamicDataPostponedState());
}
// Regardless of whether this is the Dynamic HTML or Dynamic Data case we need to ensure we include
// server inserted html in the static response because the html that is part of the prerender may depend on it
// It is possible in the set of stream transforms for Dynamic HTML vs Dynamic Data may differ but currently both states
// require the same set so we unify the code path here
return {
stream: await continueDynamicPrerender(stream, {
getServerInsertedHTML
})
};
} else {
// We may still be rendering the RSC stream even though the HTML is finished.
// We wait for the RSC stream to complete and check again if dynamic was used
const [original, flightSpy] = dataStream.tee();
dataStream = original;
await flightRenderComplete(flightSpy);
if (usedDynamicAPIs(prerenderState)) {
// This is the same logic above just repeated after ensuring the RSC stream itself has completed
if (postponed != null) {
// This is the Dynamic HTML case.
metadata.postponed = JSON.stringify(getDynamicHTMLPostponedState(postponed));
} else {
// This is the Dynamic Data case
metadata.postponed = JSON.stringify(getDynamicDataPostponedState());
}
// Regardless of whether this is the Dynamic HTML or Dynamic Data case we need to ensure we include
// server inserted html in the static response because the html that is part of the prerender may depend on it
// It is possible in the set of stream transforms for Dynamic HTML vs Dynamic Data may differ but currently both states
// require the same set so we unify the code path here
return {
stream: await continueDynamicPrerender(stream, {
getServerInsertedHTML
})
};
} else {
// This is the Static case
// We still have not used any dynamic APIs. At this point we can produce an entirely static prerender response
let renderedHTMLStream = stream;
if (staticGenerationStore.forceDynamic) {
throw new StaticGenBailoutError('Invariant: a Page with `dynamic = "force-dynamic"` did not trigger the dynamic pathway. This is a bug in Next.js');
}
if (postponed != null) {
// We postponed but nothing dynamic was used. We resume the render now and immediately abort it
// so we can set all the postponed boundaries to client render mode before we store the HTML response
const resumeRenderer = createStaticRenderer({
ppr: true,
isStaticGeneration: false,
postponed: getDynamicHTMLPostponedState(postponed),
streamOptions: {
signal: createPostponedAbortSignal("static prerender resume"),
onError: htmlRendererErrorHandler,
nonce
}
});
// We don't actually want to render anything so we just pass a stream
// that never resolves. The resume call is going to abort immediately anyway
const foreverStream = new ReadableStream();
const resumeChildren = /*#__PURE__*/ _jsx(HeadManagerContext.Provider, {
value: {
appDir: true,
nonce
},
children: /*#__PURE__*/ _jsx(ServerInsertedHTMLProvider, {
children: /*#__PURE__*/ _jsx(ReactServerEntrypoint, {
reactServerStream: foreverStream,
preinitScripts: ()=>{},
clientReferenceManifest: clientReferenceManifest,
nonce: nonce
})
})
});
const { stream: resumeStream } = await resumeRenderer.render(resumeChildren);
// First we write everything from the prerender, then we write everything from the aborted resume render
renderedHTMLStream = chainStreams(stream, resumeStream);
}
return {
stream: await continueStaticPrerender(renderedHTMLStream, {
inlinedDataStream: createInlinedDataReadableStream(dataStream, nonce, formState),
getServerInsertedHTML
})
};
}
}
} else if (renderOpts.postponed) {
// This is a continuation of either an Incomplete or Dynamic Data Prerender.
const inlinedDataStream = createInlinedDataReadableStream(dataStream, nonce, formState);
if (resumed) {
// We have new HTML to stream and we also need to include server inserted HTML
return {
stream: await continueDynamicHTMLResume(stream, {
inlinedDataStream,
getServerInsertedHTML
})
};
} else {
// We are continuing a Dynamic Data Prerender and simply need to append new inlined flight data
return {
stream: await continueDynamicDataResume(stream, {
inlinedDataStream
})
};
}
} else {
// This may be a static render or a dynamic render
// @TODO factor this further to make the render types more clearly defined and remove
// the deluge of optional params that passed to configure the various behaviors
return {
stream: await continueFizzStream(stream, {
inlinedDataStream: createInlinedDataReadableStream(dataStream, nonce, formState),
isStaticGeneration: isStaticGeneration || generateStaticHTML,
getServerInsertedHTML,
serverInsertedHTMLToHead: true,
validateRootLayout
})
};
}
} catch (err) {
if (isStaticGenBailoutError(err) || typeof err === "object" && err !== null && "message" in err && typeof err.message === "string" && err.message.includes("https://nextjs.org/docs/advanced-features/static-html-export")) {
// Ensure that "next dev" prints the red error overlay
throw err;
}
// If this is a static generation error, we need to throw it so that it
// can be handled by the caller if we're in static generation mode.
if (isStaticGeneration && isDynamicServerError(err)) {
throw err;
}
// If a bailout made it to this point, it means it wasn't wrapped inside
// a suspense boundary.
const shouldBailoutToCSR = isBailoutToCSRError(err);
if (shouldBailoutToCSR) {
const stack = getStackWithoutErrorMessage(err);
if (renderOpts.experimental.missingSuspenseWithCSRBailout) {
error(`${err.reason} should be wrapped in a suspense boundary at page "${pagePath}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n${stack}`);
throw err;
}
warn(`Entire page "${pagePath}" deopted into client-side rendering due to "${err.reason}". Read more: https://nextjs.org/docs/messages/deopted-into-client-rendering\n${stack}`);
}
if (isNotFoundError(err)) {
res.statusCode = 404;
}
let hasRedirectError = false;
if (isRedirectError(err)) {
hasRedirectError = true;
res.statusCode = getRedirectStatusCodeFromError(err);
if (err.mutableCookies) {
const headers = new Headers();
// If there were mutable cookies set, we need to set them on the
// response.
if (appendMutableCookies(headers, err.mutableCookies)) {
res.setHeader("set-cookie", Array.from(headers.values()));
}
}
const redirectUrl = addPathPrefix(getURLFromRedirectError(err), renderOpts.basePath);
res.setHeader("Location", redirectUrl);
}
const is404 = ctx.res.statusCode === 404;
if (!is404 && !hasRedirectError && !shouldBailoutToCSR) {
res.statusCode = 500;
}
const errorType = is404 ? "not-found" : hasRedirectError ? "redirect" : undefined;
const [errorPreinitScripts, errorBootstrapScript] = getRequiredScripts(buildManifest, assetPrefix, renderOpts.crossOrigin, subresourceIntegrityManifest, getAssetQueryString(ctx, false), nonce);
const errorServerStream = ComponentMod.renderToReadableStream(/*#__PURE__*/ _jsx(ReactServerError, {
tree: tree,
ctx: ctx,
errorType: errorType
}), clientReferenceManifest.clientModules, {
onError: serverComponentsErrorHandler
});
try {
const fizzStream = await renderToInitialFizzStream({
ReactDOMServer: require("react-dom/server.edge"),
element: /*#__PURE__*/ _jsx(ReactServerEntrypoint, {
reactServerStream: errorServerStream,
preinitScripts: errorPreinitScripts,
clientReferenceManifest: clientReferenceManifest,
nonce: nonce
}),
streamOptions: {
nonce,
// Include hydration scripts in the HTML
bootstrapScripts: [
errorBootstrapScript
],
formState
}
});
return {
// Returning the error that was thrown so it can be used to handle
// the response in the caller.
err,
stream: await continueFizzStream(fizzStream, {
inlinedDataStream: createInlinedDataReadableStream(// This is intentionally using the readable datastream from the
// main render rather than the flight data from the error page
// render
dataStream, nonce, formState),
isStaticGeneration,
getServerInsertedHTML: makeGetServerInsertedHTML({
polyfills,
renderServerInsertedHTML,
serverCapturedErrors: [],
basePath: renderOpts.basePath
}),
serverInsertedHTMLToHead: true,
validateRootLayout
})
};
} catch (finalErr) {
if (process.env.NODE_ENV === "development" && isNotFoundError(finalErr)) {
const bailOnNotFound = require("../../client/components/dev-root-not-found-boundary").bailOnNotFound;
bailOnNotFound();
}
throw finalErr;
}
}
});
// For action requests, we handle them differently with a special render result.
const actionRequestResult = await handleAction({
req,
res,
ComponentMod,
serverModuleMap,
generateFlight,
staticGenerationStore,
requestStore,
serverActions,
ctx
});
let formState = null;
if (actionRequestResult) {
if (actionRequestResult.type === "not-found") {
const notFoundLoaderTree = createNotFoundLoaderTree(loaderTree);
const response = await renderToStream({
asNotFound: true,
tree: notFoundLoaderTree,
formState
});
return new RenderResult(response.stream, {
metadata
});
} else if (actionRequestResult.type === "done") {
if (actionRequestResult.result) {
actionRequestResult.result.assignMetadata(metadata);
return actionRequestResult.result;
} else if (actionRequestResult.formState) {
formState = actionRequestResult.formState;
}
}
}
const options = {
metadata
};
let response = await renderToStream({
asNotFound: isNotFoundPath,
tree: loaderTree,
formState
});
// If we have pending revalidates, wait until they are all resolved.
if (staticGenerationStore.pendingRevalidates) {
var _staticGenerationStore_incrementalCache;
options.waitUntil = Promise.all([
(_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.revalidateTag(staticGenerationStore.revalidatedTags || []),
...Object.values(staticGenerationStore.pendingRevalidates || {})
]);
}
addImplicitTags(staticGenerationStore);
if (staticGenerationStore.tags) {
metadata.fetchTags = staticGenerationStore.tags.join(",");
}
// Create the new render result for the response.
const result = new RenderResult(response.stream, options);
// If we aren't performing static generation, we can return the result now.
if (!isStaticGeneration) {
return result;
}
// If this is static generation, we should read this in now rather than
// sending it back to be sent to the client.
response.stream = await result.toUnchunkedString(true);
const buildFailingError = digestErrorsMap.size > 0 ? digestErrorsMap.values().next().value : null;
// If we're debugging partial prerendering, print all the dynamic API accesses
// that occurred during the render.
if (staticGenerationStore.prerenderState && usedDynamicAPIs(staticGenerationStore.prerenderState) && ((_staticGenerationStore_prerenderState = staticGenerationStore.prerenderState) == null ? void 0 : _staticGenerationStore_prerenderState.isDebugSkeleton)) {
warn("The following dynamic usage was detected:");
for (const access of formatDynamicAPIAccesses(staticGenerationStore.prerenderState)){
warn(access);
}
}
if (!flightDataResolver) {
throw new Error("Invariant: Flight data resolver is missing when generating static HTML");
}
// If we encountered any unexpected errors during build we fail the
// prerendering phase and the build.
if (buildFailingError) {
throw buildFailingError;
}
// Wait for and collect the flight payload data if we don't have it
// already
const flightData = await flightDataResolver();
if (flightData) {
metadata.flightData = flightData;
}
// If force static is specifically set to false, we should not revalidate
// the page.
if (staticGenerationStore.forceStatic === false) {
staticGenerationStore.revalidate = 0;
}
// Copy the revalidation value onto the render result metadata.
metadata.revalidate = staticGenerationStore.revalidate ?? ctx.defaultRevalidate;
// provide bailout info for debugging
if (metadata.revalidate === 0) {
metadata.staticBailoutInfo = {
description: staticGenerationStore.dynamicUsageDescription,
stack: staticGenerationStore.dynamicUsageStack
};
}
return new RenderResult(response.stream, options);
}
export const renderToHTMLOrFlight = (req, res, pagePath, query, renderOpts)=>{
// TODO: this includes query string, should it?
const pathname = validateURL(req.url);
return RequestAsyncStorageWrapper.wrap(renderOpts.ComponentMod.requestAsyncStorage, {
req,
res,
renderOpts
}, (requestStore)=>StaticGenerationAsyncStorageWrapper.wrap(renderOpts.ComponentMod.staticGenerationAsyncStorage, {
urlPathname: pathname,
renderOpts,
requestEndedState: {
ended: false
}
}, (staticGenerationStore)=>renderToHTMLOrFlightImpl(req, res, pagePath, query, renderOpts, {
requestStore,
staticGenerationStore,
componentMod: renderOpts.ComponentMod,
renderOpts
}, staticGenerationStore.requestEndedState || {})));
};
//# sourceMappingURL=app-render.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,38 @@
import { jsx as _jsx } from "react/jsx-runtime";
import React from "react";
import { interopDefault } from "./interop-default";
import { getLinkAndScriptTags } from "./get-css-inlined-link-tags";
import { getAssetQueryString } from "./get-asset-query-string";
import { encodeURIPath } from "../../shared/lib/encode-uri-path";
export async function createComponentStylesAndScripts({ filePath, getComponent, injectedCSS, injectedJS, ctx }) {
const { styles: cssHrefs, scripts: jsHrefs } = getLinkAndScriptTags(ctx.clientReferenceManifest, filePath, injectedCSS, injectedJS);
const styles = cssHrefs ? cssHrefs.map((href, index)=>{
const fullHref = `${ctx.assetPrefix}/_next/${encodeURIPath(href)}${getAssetQueryString(ctx, true)}`;
// `Precedence` is an opt-in signal for React to handle resource
// loading and deduplication, etc. It's also used as the key to sort
// resources so they will be injected in the correct order.
// During HMR, it's critical to use different `precedence` values
// for different stylesheets, so their order will be kept.
// https://github.com/facebook/react/pull/25060
const precedence = process.env.NODE_ENV === "development" ? "next_" + href : "next";
return /*#__PURE__*/ _jsx("link", {
rel: "stylesheet",
href: fullHref,
// @ts-ignore
precedence: precedence,
crossOrigin: ctx.renderOpts.crossOrigin
}, index);
}) : null;
const scripts = jsHrefs ? jsHrefs.map((href)=>/*#__PURE__*/ _jsx("script", {
src: `${ctx.assetPrefix}/_next/${encodeURIPath(href)}${getAssetQueryString(ctx, true)}`,
async: true
})) : null;
const Comp = interopDefault(await getComponent());
return [
Comp,
styles,
scripts
];
}
//# sourceMappingURL=create-component-styles-and-scripts.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/create-component-styles-and-scripts.tsx"],"names":["React","interopDefault","getLinkAndScriptTags","getAssetQueryString","encodeURIPath","createComponentStylesAndScripts","filePath","getComponent","injectedCSS","injectedJS","ctx","styles","cssHrefs","scripts","jsHrefs","clientReferenceManifest","map","href","index","fullHref","assetPrefix","precedence","process","env","NODE_ENV","link","rel","crossOrigin","renderOpts","script","src","async","Comp"],"mappings":";AAAA,OAAOA,WAAW,QAAO;AACzB,SAASC,cAAc,QAAQ,oBAAmB;AAClD,SAASC,oBAAoB,QAAQ,8BAA6B;AAElE,SAASC,mBAAmB,QAAQ,2BAA0B;AAC9D,SAASC,aAAa,QAAQ,mCAAkC;AAEhE,OAAO,eAAeC,gCAAgC,EACpDC,QAAQ,EACRC,YAAY,EACZC,WAAW,EACXC,UAAU,EACVC,GAAG,EAOJ;IACC,MAAM,EAAEC,QAAQC,QAAQ,EAAEC,SAASC,OAAO,EAAE,GAAGZ,qBAC7CQ,IAAIK,uBAAuB,EAC3BT,UACAE,aACAC;IAGF,MAAME,SAASC,WACXA,SAASI,GAAG,CAAC,CAACC,MAAMC;QAClB,MAAMC,WAAW,CAAC,EAAET,IAAIU,WAAW,CAAC,OAAO,EAAEhB,cAC3Ca,MACA,EAAEd,oBAAoBO,KAAK,MAAM,CAAC;QAEpC,gEAAgE;QAChE,oEAAoE;QACpE,2DAA2D;QAC3D,iEAAiE;QACjE,0DAA0D;QAC1D,+CAA+C;QAC/C,MAAMW,aACJC,QAAQC,GAAG,CAACC,QAAQ,KAAK,gBAAgB,UAAUP,OAAO;QAE5D,qBACE,KAACQ;YACCC,KAAI;YACJT,MAAME;YACN,aAAa;YACbE,YAAYA;YACZM,aAAajB,IAAIkB,UAAU,CAACD,WAAW;WAClCT;IAGX,KACA;IAEJ,MAAML,UAAUC,UACZA,QAAQE,GAAG,CAAC,CAACC,qBACX,KAACY;YACCC,KAAK,CAAC,EAAEpB,IAAIU,WAAW,CAAC,OAAO,EAAEhB,cAC/Ba,MACA,EAAEd,oBAAoBO,KAAK,MAAM,CAAC;YACpCqB,OAAO;cAGX;IAEJ,MAAMC,OAAO/B,eAAe,MAAMM;IAElC,OAAO;QAACyB;QAAMrB;QAAQE;KAAQ;AAChC"}

View File

@ -0,0 +1,442 @@
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React from "react";
import { isClientReference } from "../../lib/client-reference";
import { getLayoutOrPageModule } from "../lib/app-dir-module";
import { interopDefault } from "./interop-default";
import { parseLoaderTree } from "./parse-loader-tree";
import { createComponentStylesAndScripts } from "./create-component-styles-and-scripts";
import { getLayerAssets } from "./get-layer-assets";
import { hasLoadingComponentInTree } from "./has-loading-component-in-tree";
import { validateRevalidate } from "../lib/patch-fetch";
import { PARALLEL_ROUTE_DEFAULT_PATH } from "../../client/components/parallel-route-default";
import { getTracer } from "../lib/trace/tracer";
import { NextNodeServerSpan } from "../lib/trace/constants";
import { StaticGenBailoutError } from "../../client/components/static-generation-bailout";
/**
* Use the provided loader tree to create the React Component tree.
*/ export function createComponentTree(props) {
return getTracer().trace(NextNodeServerSpan.createComponentTree, {
spanName: "build component tree"
}, ()=>createComponentTreeInternal(props));
}
async function createComponentTreeInternal({ createSegmentPath, loaderTree: tree, parentParams, firstItem, rootLayoutIncluded, injectedCSS, injectedJS, injectedFontPreloadTags, asNotFound, metadataOutlet, ctx, missingSlots }) {
const { renderOpts: { nextConfigOutput, experimental }, staticGenerationStore, componentMod: { NotFoundBoundary, LayoutRouter, RenderFromTemplateContext, ClientPageRoot, createUntrackedSearchParams, createDynamicallyTrackedSearchParams, serverHooks: { DynamicServerError }, Postpone }, pagePath, getDynamicParamFromSegment, isPrefetch, query } = ctx;
const { page, layoutOrPagePath, segment, components, parallelRoutes } = parseLoaderTree(tree);
const { layout, template, error, loading, "not-found": notFound } = components;
const injectedCSSWithCurrentLayout = new Set(injectedCSS);
const injectedJSWithCurrentLayout = new Set(injectedJS);
const injectedFontPreloadTagsWithCurrentLayout = new Set(injectedFontPreloadTags);
const layerAssets = getLayerAssets({
ctx,
layoutOrPagePath,
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout,
injectedFontPreloadTags: injectedFontPreloadTagsWithCurrentLayout
});
const [Template, templateStyles, templateScripts] = template ? await createComponentStylesAndScripts({
ctx,
filePath: template[1],
getComponent: template[0],
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout
}) : [
React.Fragment
];
const [ErrorComponent, errorStyles, errorScripts] = error ? await createComponentStylesAndScripts({
ctx,
filePath: error[1],
getComponent: error[0],
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout
}) : [];
const [Loading, loadingStyles, loadingScripts] = loading ? await createComponentStylesAndScripts({
ctx,
filePath: loading[1],
getComponent: loading[0],
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout
}) : [];
const isLayout = typeof layout !== "undefined";
const isPage = typeof page !== "undefined";
const [layoutOrPageMod] = await getTracer().trace(NextNodeServerSpan.getLayoutOrPageModule, {
hideSpan: !(isLayout || isPage),
spanName: "resolve segment modules",
attributes: {
"next.segment": segment
}
}, ()=>getLayoutOrPageModule(tree));
/**
* Checks if the current segment is a root layout.
*/ const rootLayoutAtThisLevel = isLayout && !rootLayoutIncluded;
/**
* Checks if the current segment or any level above it has a root layout.
*/ const rootLayoutIncludedAtThisLevelOrAbove = rootLayoutIncluded || rootLayoutAtThisLevel;
const [NotFound, notFoundStyles] = notFound ? await createComponentStylesAndScripts({
ctx,
filePath: notFound[1],
getComponent: notFound[0],
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout
}) : [];
let dynamic = layoutOrPageMod == null ? void 0 : layoutOrPageMod.dynamic;
if (nextConfigOutput === "export") {
if (!dynamic || dynamic === "auto") {
dynamic = "error";
} else if (dynamic === "force-dynamic") {
// force-dynamic is always incompatible with 'export'. We must interrupt the build
throw new StaticGenBailoutError(`Page with \`dynamic = "force-dynamic"\` couldn't be exported. \`output: "export"\` requires all pages be renderable statically because there is not runtime server to dynamic render routes in this output format. Learn more: https://nextjs.org/docs/app/building-your-application/deploying/static-exports`);
}
}
if (typeof dynamic === "string") {
// the nested most config wins so we only force-static
// if it's configured above any parent that configured
// otherwise
if (dynamic === "error") {
staticGenerationStore.dynamicShouldError = true;
} else if (dynamic === "force-dynamic") {
staticGenerationStore.forceDynamic = true;
// TODO: (PPR) remove this bailout once PPR is the default
if (staticGenerationStore.isStaticGeneration && !staticGenerationStore.prerenderState) {
// If the postpone API isn't available, we can't postpone the render and
// therefore we can't use the dynamic API.
const err = new DynamicServerError(`Page with \`dynamic = "force-dynamic"\` won't be rendered statically.`);
staticGenerationStore.dynamicUsageDescription = err.message;
staticGenerationStore.dynamicUsageStack = err.stack;
throw err;
}
} else {
staticGenerationStore.dynamicShouldError = false;
staticGenerationStore.forceStatic = dynamic === "force-static";
}
}
if (typeof (layoutOrPageMod == null ? void 0 : layoutOrPageMod.fetchCache) === "string") {
staticGenerationStore.fetchCache = layoutOrPageMod == null ? void 0 : layoutOrPageMod.fetchCache;
}
if (typeof (layoutOrPageMod == null ? void 0 : layoutOrPageMod.revalidate) !== "undefined") {
validateRevalidate(layoutOrPageMod == null ? void 0 : layoutOrPageMod.revalidate, staticGenerationStore.urlPathname);
}
if (typeof (layoutOrPageMod == null ? void 0 : layoutOrPageMod.revalidate) === "number") {
ctx.defaultRevalidate = layoutOrPageMod.revalidate;
if (typeof staticGenerationStore.revalidate === "undefined" || typeof staticGenerationStore.revalidate === "number" && staticGenerationStore.revalidate > ctx.defaultRevalidate) {
staticGenerationStore.revalidate = ctx.defaultRevalidate;
}
if (!staticGenerationStore.forceStatic && staticGenerationStore.isStaticGeneration && ctx.defaultRevalidate === 0 && // If the postpone API isn't available, we can't postpone the render and
// therefore we can't use the dynamic API.
!staticGenerationStore.prerenderState) {
const dynamicUsageDescription = `revalidate: 0 configured ${segment}`;
staticGenerationStore.dynamicUsageDescription = dynamicUsageDescription;
throw new DynamicServerError(dynamicUsageDescription);
}
}
// If there's a dynamic usage error attached to the store, throw it.
if (staticGenerationStore.dynamicUsageErr) {
throw staticGenerationStore.dynamicUsageErr;
}
const LayoutOrPage = layoutOrPageMod ? await interopDefault(layoutOrPageMod) : undefined;
/**
* The React Component to render.
*/ let Component = LayoutOrPage;
const parallelKeys = Object.keys(parallelRoutes);
const hasSlotKey = parallelKeys.length > 1;
// TODO-APP: This is a hack to support unmatched parallel routes, which will throw `notFound()`.
// This ensures that a `NotFoundBoundary` is available for when that happens,
// but it's not ideal, as it needlessly invokes the `NotFound` component and renders the `RootLayout` twice.
// We should instead look into handling the fallback behavior differently in development mode so that it doesn't
// rely on the `NotFound` behavior.
if (hasSlotKey && rootLayoutAtThisLevel && LayoutOrPage) {
Component = (componentProps)=>{
const NotFoundComponent = NotFound;
const RootLayoutComponent = LayoutOrPage;
return /*#__PURE__*/ _jsx(NotFoundBoundary, {
notFound: NotFoundComponent ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
layerAssets,
/*#__PURE__*/ _jsxs(RootLayoutComponent, {
params: componentProps.params,
children: [
notFoundStyles,
/*#__PURE__*/ _jsx(NotFoundComponent, {})
]
})
]
}) : undefined,
children: /*#__PURE__*/ _jsx(RootLayoutComponent, {
...componentProps
})
});
};
}
if (process.env.NODE_ENV === "development") {
const { isValidElementType } = require("next/dist/compiled/react-is");
if ((isPage || typeof Component !== "undefined") && !isValidElementType(Component)) {
throw new Error(`The default export is not a React Component in page: "${pagePath}"`);
}
if (typeof ErrorComponent !== "undefined" && !isValidElementType(ErrorComponent)) {
throw new Error(`The default export of error is not a React Component in page: ${segment}`);
}
if (typeof Loading !== "undefined" && !isValidElementType(Loading)) {
throw new Error(`The default export of loading is not a React Component in ${segment}`);
}
if (typeof NotFound !== "undefined" && !isValidElementType(NotFound)) {
throw new Error(`The default export of notFound is not a React Component in ${segment}`);
}
}
// Handle dynamic segment params.
const segmentParam = getDynamicParamFromSegment(segment);
/**
* Create object holding the parent params and current params
*/ const currentParams = // Handle null case where dynamic param is optional
segmentParam && segmentParam.value !== null ? {
...parentParams,
[segmentParam.param]: segmentParam.value
} : parentParams;
// Resolve the segment param
const actualSegment = segmentParam ? segmentParam.treeSegment : segment;
//
// TODO: Combine this `map` traversal with the loop below that turns the array
// into an object.
const parallelRouteMap = await Promise.all(Object.keys(parallelRoutes).map(async (parallelRouteKey)=>{
const isChildrenRouteKey = parallelRouteKey === "children";
const currentSegmentPath = firstItem ? [
parallelRouteKey
] : [
actualSegment,
parallelRouteKey
];
const parallelRoute = parallelRoutes[parallelRouteKey];
const notFoundComponent = NotFound && isChildrenRouteKey ? /*#__PURE__*/ _jsx(NotFound, {}) : undefined;
// if we're prefetching and that there's a Loading component, we bail out
// otherwise we keep rendering for the prefetch.
// We also want to bail out if there's no Loading component in the tree.
let childCacheNodeSeedData = null;
if (// Before PPR, the way instant navigations work in Next.js is we
// prefetch everything up to the first route segment that defines a
// loading.tsx boundary. (We do the same if there's no loading
// boundary in the entire tree, because we don't want to prefetch too
// much) The rest of the tree is defered until the actual navigation.
// It does not take into account whether the data is dynamic — even if
// the tree is completely static, it will still defer everything
// inside the loading boundary.
//
// This behavior predates PPR and is only relevant if the
// PPR flag is not enabled.
isPrefetch && (Loading || !hasLoadingComponentInTree(parallelRoute)) && // The approach with PPR is different — loading.tsx behaves like a
// regular Suspense boundary and has no special behavior.
//
// With PPR, we prefetch as deeply as possible, and only defer when
// dynamic data is accessed. If so, we only defer the nearest parent
// Suspense boundary of the dynamic data access, regardless of whether
// the boundary is defined by loading.tsx or a normal <Suspense>
// component in userspace.
//
// NOTE: In practice this usually means we'll end up prefetching more
// than we were before PPR, which may or may not be considered a
// performance regression by some apps. The plan is to address this
// before General Availability of PPR by introducing granular
// per-segment fetching, so we can reuse as much of the tree as
// possible during both prefetches and dynamic navigations. But during
// the beta period, we should be clear about this trade off in our
// communications.
!experimental.ppr) {
// Don't prefetch this child. This will trigger a lazy fetch by the
// client router.
} else {
// Create the child component
if (process.env.NODE_ENV === "development" && missingSlots) {
var _parsedTree_layoutOrPagePath;
// When we detect the default fallback (which triggers a 404), we collect the missing slots
// to provide more helpful debug information during development mode.
const parsedTree = parseLoaderTree(parallelRoute);
if ((_parsedTree_layoutOrPagePath = parsedTree.layoutOrPagePath) == null ? void 0 : _parsedTree_layoutOrPagePath.endsWith(PARALLEL_ROUTE_DEFAULT_PATH)) {
missingSlots.add(parallelRouteKey);
}
}
const seedData = await createComponentTreeInternal({
createSegmentPath: (child)=>{
return createSegmentPath([
...currentSegmentPath,
...child
]);
},
loaderTree: parallelRoute,
parentParams: currentParams,
rootLayoutIncluded: rootLayoutIncludedAtThisLevelOrAbove,
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout,
injectedFontPreloadTags: injectedFontPreloadTagsWithCurrentLayout,
asNotFound,
metadataOutlet,
ctx,
missingSlots
});
childCacheNodeSeedData = seedData;
}
// This is turned back into an object below.
return [
parallelRouteKey,
/*#__PURE__*/ _jsx(LayoutRouter, {
parallelRouterKey: parallelRouteKey,
segmentPath: createSegmentPath(currentSegmentPath),
// TODO-APP: Add test for loading returning `undefined`. This currently can't be tested as the `webdriver()` tab will wait for the full page to load before returning.
error: ErrorComponent,
errorStyles: errorStyles,
errorScripts: errorScripts,
template: /*#__PURE__*/ _jsx(Template, {
children: /*#__PURE__*/ _jsx(RenderFromTemplateContext, {})
}),
templateStyles: templateStyles,
templateScripts: templateScripts,
notFound: notFoundComponent,
notFoundStyles: notFoundStyles
}),
childCacheNodeSeedData
];
}));
// Convert the parallel route map into an object after all promises have been resolved.
let parallelRouteProps = {};
let parallelRouteCacheNodeSeedData = {};
for (const parallelRoute of parallelRouteMap){
const [parallelRouteKey, parallelRouteProp, flightData] = parallelRoute;
parallelRouteProps[parallelRouteKey] = parallelRouteProp;
parallelRouteCacheNodeSeedData[parallelRouteKey] = flightData;
}
const loadingData = Loading ? [
/*#__PURE__*/ _jsx(Loading, {}),
loadingStyles,
loadingScripts
] : null;
// When the segment does not have a layout or page we still have to add the layout router to ensure the path holds the loading component
if (!Component) {
return [
actualSegment,
parallelRouteCacheNodeSeedData,
// TODO: I don't think the extra fragment is necessary. React treats top
// level fragments as transparent, i.e. the runtime behavior should be
// identical even without it. But maybe there's some findDOMNode-related
// reason that I'm not aware of, so I'm leaving it as-is out of extreme
// caution, for now.
/*#__PURE__*/ _jsxs(_Fragment, {
children: [
layerAssets,
parallelRouteProps.children
]
}),
loadingData
];
}
// If force-dynamic is used and the current render supports postponing, we
// replace it with a node that will postpone the render. This ensures that the
// postpone is invoked during the react render phase and not during the next
// render phase.
// @TODO this does not actually do what it seems like it would or should do. The idea is that
// if we are rendering in a force-dynamic mode and we can postpone we should only make the segments
// that ask for force-dynamic to be dynamic, allowing other segments to still prerender. However
// because this comes after the children traversal and the static generation store is mutated every segment
// along the parent path of a force-dynamic segment will hit this condition effectively making the entire
// render force-dynamic. We should refactor this function so that we can correctly track which segments
// need to be dynamic
if (staticGenerationStore.forceDynamic && staticGenerationStore.prerenderState) {
return [
actualSegment,
parallelRouteCacheNodeSeedData,
/*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx(Postpone, {
prerenderState: staticGenerationStore.prerenderState,
reason: 'dynamic = "force-dynamic" was used',
pathname: staticGenerationStore.urlPathname
}),
layerAssets
]
}),
loadingData
];
}
const isClientComponent = isClientReference(layoutOrPageMod);
// We avoid cloning this object because it gets consumed here exclusively.
const props = parallelRouteProps;
// If it's a not found route, and we don't have any matched parallel
// routes, we try to render the not found component if it exists.
if (NotFound && asNotFound && // In development, it could hit the parallel-route-default not found, so we only need to check the segment.
// Or if there's no parallel routes means it reaches the end.
!parallelRouteMap.length) {
props.children = /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("meta", {
name: "robots",
content: "noindex"
}),
process.env.NODE_ENV === "development" && /*#__PURE__*/ _jsx("meta", {
name: "next-error",
content: "not-found"
}),
notFoundStyles,
/*#__PURE__*/ _jsx(NotFound, {})
]
});
}
// Assign params to props
if (process.env.NODE_ENV === "development" && "params" in parallelRouteProps) {
// @TODO consider making this an error and running the check in build as well
console.error(`"params" is a reserved prop in Layouts and Pages and cannot be used as the name of a parallel route in ${segment}`);
}
props.params = currentParams;
let segmentElement;
if (isPage) {
// Assign searchParams to props if this is a page
if (isClientComponent) {
// When we are passing searchParams to a client component Page we don't want to track the dynamic access
// here in the RSC layer because the serialization will trigger a dynamic API usage.
// Instead we pass the searchParams untracked but we wrap the Page in a root client component
// which can among other things adds the dynamic tracking before rendering the page.
// @TODO make the root wrapper part of next-app-loader so we don't need the extra client component
props.searchParams = createUntrackedSearchParams(query);
segmentElement = /*#__PURE__*/ _jsxs(_Fragment, {
children: [
metadataOutlet,
/*#__PURE__*/ _jsx(ClientPageRoot, {
props: props,
Component: Component
}),
layerAssets
]
});
} else {
// If we are passing searchParams to a server component Page we need to track their usage in case
// the current render mode tracks dynamic API usage.
props.searchParams = createDynamicallyTrackedSearchParams(query);
segmentElement = /*#__PURE__*/ _jsxs(_Fragment, {
children: [
metadataOutlet,
/*#__PURE__*/ _jsx(Component, {
...props
}),
layerAssets
]
});
}
} else {
// For layouts we just render the component
segmentElement = /*#__PURE__*/ _jsxs(_Fragment, {
children: [
layerAssets,
/*#__PURE__*/ _jsx(Component, {
...props
})
]
});
}
return [
actualSegment,
parallelRouteCacheNodeSeedData,
/*#__PURE__*/ _jsxs(_Fragment, {
children: [
segmentElement,
null
]
}),
loadingData
];
}
//# sourceMappingURL=create-component-tree.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,76 @@
import stringHash from "next/dist/compiled/string-hash";
import { formatServerError } from "../../lib/format-server-error";
import { SpanStatusCode, getTracer } from "../lib/trace/tracer";
import { isAbortError } from "../pipe-readable";
import { isDynamicUsageError } from "../../export/helpers/is-dynamic-usage-error";
export const ErrorHandlerSource = {
serverComponents: "serverComponents",
flightData: "flightData",
html: "html"
};
/**
* Create error handler for renderers.
* Tolerate dynamic server errors during prerendering so console
* isn't spammed with unactionable errors
*/ export function createErrorHandler({ /**
* Used for debugging
*/ source, dev, isNextExport, errorLogger, digestErrorsMap, allCapturedErrors, silenceLogger }) {
return (err, errorInfo)=>{
var _err_message;
// If the error already has a digest, respect the original digest,
// so it won't get re-generated into another new error.
if (!err.digest) {
// TODO-APP: look at using webcrypto instead. Requires a promise to be awaited.
err.digest = stringHash(err.message + ((errorInfo == null ? void 0 : errorInfo.stack) || err.stack || "")).toString();
}
const digest = err.digest;
if (allCapturedErrors) allCapturedErrors.push(err);
// These errors are expected. We return the digest
// so that they can be properly handled.
if (isDynamicUsageError(err)) return err.digest;
// If the response was closed, we don't need to log the error.
if (isAbortError(err)) return;
if (!digestErrorsMap.has(digest)) {
digestErrorsMap.set(digest, err);
} else if (source === ErrorHandlerSource.html) {
// For SSR errors, if we have the existing digest in errors map,
// we should use the existing error object to avoid duplicate error logs.
err = digestErrorsMap.get(digest);
}
// Format server errors in development to add more helpful error messages
if (dev) {
formatServerError(err);
}
// Used for debugging error source
// console.error(source, err)
// Don't log the suppressed error during export
if (!(isNextExport && (err == null ? void 0 : (_err_message = err.message) == null ? void 0 : _err_message.includes("The specific message is omitted in production builds to avoid leaking sensitive details.")))) {
// Record exception in an active span, if available.
const span = getTracer().getActiveScopeSpan();
if (span) {
span.recordException(err);
span.setStatus({
code: SpanStatusCode.ERROR,
message: err.message
});
}
if (!silenceLogger) {
if (errorLogger) {
errorLogger(err).catch(()=>{});
} else {
// The error logger is currently not provided in the edge runtime.
// Use the exposed `__next_log_error__` instead.
// This will trace error traces to the original source code.
if (typeof __next_log_error__ === "function") {
__next_log_error__(err);
} else {
console.error(err);
}
}
}
}
return err.digest;
};
}
//# sourceMappingURL=create-error-handler.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/create-error-handler.tsx"],"names":["stringHash","formatServerError","SpanStatusCode","getTracer","isAbortError","isDynamicUsageError","ErrorHandlerSource","serverComponents","flightData","html","createErrorHandler","source","dev","isNextExport","errorLogger","digestErrorsMap","allCapturedErrors","silenceLogger","err","errorInfo","digest","message","stack","toString","push","has","set","get","includes","span","getActiveScopeSpan","recordException","setStatus","code","ERROR","catch","__next_log_error__","console","error"],"mappings":"AAAA,OAAOA,gBAAgB,iCAAgC;AACvD,SAASC,iBAAiB,QAAQ,gCAA+B;AACjE,SAASC,cAAc,EAAEC,SAAS,QAAQ,sBAAqB;AAC/D,SAASC,YAAY,QAAQ,mBAAkB;AAC/C,SAASC,mBAAmB,QAAQ,8CAA6C;AAWjF,OAAO,MAAMC,qBAAqB;IAChCC,kBAAkB;IAClBC,YAAY;IACZC,MAAM;AACR,EAAU;AAEV;;;;CAIC,GACD,OAAO,SAASC,mBAAmB,EACjC;;GAEC,GACDC,MAAM,EACNC,GAAG,EACHC,YAAY,EACZC,WAAW,EACXC,eAAe,EACfC,iBAAiB,EACjBC,aAAa,EASd;IACC,OAAO,CAACC,KAAUC;YAsCZD;QArCJ,kEAAkE;QAClE,uDAAuD;QACvD,IAAI,CAACA,IAAIE,MAAM,EAAE;YACf,+EAA+E;YAC/EF,IAAIE,MAAM,GAAGpB,WACXkB,IAAIG,OAAO,GAAIF,CAAAA,CAAAA,6BAAAA,UAAWG,KAAK,KAAIJ,IAAII,KAAK,IAAI,EAAC,GACjDC,QAAQ;QACZ;QACA,MAAMH,SAASF,IAAIE,MAAM;QAEzB,IAAIJ,mBAAmBA,kBAAkBQ,IAAI,CAACN;QAE9C,kDAAkD;QAClD,wCAAwC;QACxC,IAAIb,oBAAoBa,MAAM,OAAOA,IAAIE,MAAM;QAE/C,8DAA8D;QAC9D,IAAIhB,aAAac,MAAM;QAEvB,IAAI,CAACH,gBAAgBU,GAAG,CAACL,SAAS;YAChCL,gBAAgBW,GAAG,CAACN,QAAQF;QAC9B,OAAO,IAAIP,WAAWL,mBAAmBG,IAAI,EAAE;YAC7C,gEAAgE;YAChE,yEAAyE;YACzES,MAAMH,gBAAgBY,GAAG,CAACP;QAC5B;QAEA,yEAAyE;QACzE,IAAIR,KAAK;YACPX,kBAAkBiB;QACpB;QACA,kCAAkC;QAClC,6BAA6B;QAC7B,+CAA+C;QAC/C,IACE,CACEL,CAAAA,iBACAK,wBAAAA,eAAAA,IAAKG,OAAO,qBAAZH,aAAcU,QAAQ,CACpB,4FACF,GAEF;YACA,oDAAoD;YACpD,MAAMC,OAAO1B,YAAY2B,kBAAkB;YAC3C,IAAID,MAAM;gBACRA,KAAKE,eAAe,CAACb;gBACrBW,KAAKG,SAAS,CAAC;oBACbC,MAAM/B,eAAegC,KAAK;oBAC1Bb,SAASH,IAAIG,OAAO;gBACtB;YACF;YAEA,IAAI,CAACJ,eAAe;gBAClB,IAAIH,aAAa;oBACfA,YAAYI,KAAKiB,KAAK,CAAC,KAAO;gBAChC,OAAO;oBACL,kEAAkE;oBAClE,gDAAgD;oBAChD,4DAA4D;oBAC5D,IAAI,OAAOC,uBAAuB,YAAY;wBAC5CA,mBAAmBlB;oBACrB,OAAO;wBACLmB,QAAQC,KAAK,CAACpB;oBAChB;gBACF;YACF;QACF;QAEA,OAAOA,IAAIE,MAAM;IACnB;AACF"}

View File

@ -0,0 +1,28 @@
import { PAGE_SEGMENT_KEY } from "../../shared/lib/segment";
export function addSearchParamsIfPageSegment(segment, searchParams) {
const isPageSegment = segment === PAGE_SEGMENT_KEY;
if (isPageSegment) {
const stringifiedQuery = JSON.stringify(searchParams);
return stringifiedQuery !== "{}" ? segment + "?" + stringifiedQuery : segment;
}
return segment;
}
export function createFlightRouterStateFromLoaderTree([segment, parallelRoutes, { layout }], getDynamicParamFromSegment, searchParams, rootLayoutIncluded = false) {
const dynamicParam = getDynamicParamFromSegment(segment);
const treeSegment = dynamicParam ? dynamicParam.treeSegment : segment;
const segmentTree = [
addSearchParamsIfPageSegment(treeSegment, searchParams),
{}
];
if (!rootLayoutIncluded && typeof layout !== "undefined") {
rootLayoutIncluded = true;
segmentTree[4] = true;
}
segmentTree[1] = Object.keys(parallelRoutes).reduce((existingValue, currentValue)=>{
existingValue[currentValue] = createFlightRouterStateFromLoaderTree(parallelRoutes[currentValue], getDynamicParamFromSegment, searchParams, rootLayoutIncluded);
return existingValue;
}, {});
return segmentTree;
}
//# sourceMappingURL=create-flight-router-state-from-loader-tree.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/create-flight-router-state-from-loader-tree.ts"],"names":["PAGE_SEGMENT_KEY","addSearchParamsIfPageSegment","segment","searchParams","isPageSegment","stringifiedQuery","JSON","stringify","createFlightRouterStateFromLoaderTree","parallelRoutes","layout","getDynamicParamFromSegment","rootLayoutIncluded","dynamicParam","treeSegment","segmentTree","Object","keys","reduce","existingValue","currentValue"],"mappings":"AAGA,SAASA,gBAAgB,QAAQ,2BAA0B;AAE3D,OAAO,SAASC,6BACdC,OAAgB,EAChBC,YAAiB;IAEjB,MAAMC,gBAAgBF,YAAYF;IAElC,IAAII,eAAe;QACjB,MAAMC,mBAAmBC,KAAKC,SAAS,CAACJ;QACxC,OAAOE,qBAAqB,OACxBH,UAAU,MAAMG,mBAChBH;IACN;IAEA,OAAOA;AACT;AAEA,OAAO,SAASM,sCACd,CAACN,SAASO,gBAAgB,EAAEC,MAAM,EAAE,CAAa,EACjDC,0BAAsD,EACtDR,YAAiB,EACjBS,qBAAqB,KAAK;IAE1B,MAAMC,eAAeF,2BAA2BT;IAChD,MAAMY,cAAcD,eAAeA,aAAaC,WAAW,GAAGZ;IAE9D,MAAMa,cAAiC;QACrCd,6BAA6Ba,aAAaX;QAC1C,CAAC;KACF;IAED,IAAI,CAACS,sBAAsB,OAAOF,WAAW,aAAa;QACxDE,qBAAqB;QACrBG,WAAW,CAAC,EAAE,GAAG;IACnB;IAEAA,WAAW,CAAC,EAAE,GAAGC,OAAOC,IAAI,CAACR,gBAAgBS,MAAM,CACjD,CAACC,eAAeC;QACdD,aAAa,CAACC,aAAa,GAAGZ,sCAC5BC,cAAc,CAACW,aAAa,EAC5BT,4BACAR,cACAS;QAEF,OAAOO;IACT,GACA,CAAC;IAGH,OAAOJ;AACT"}

View File

@ -0,0 +1,80 @@
// micromatch is only available at node runtime, so it cannot be used here since the code path that calls this function
// can be run from edge. This is a simple implementation that safely achieves the required functionality.
// the goal is to match the functionality for remotePatterns as defined here -
// https://nextjs.org/docs/app/api-reference/components/image#remotepatterns
// TODO - retrofit micromatch to work in edge and use that instead
function matchWildcardDomain(domain, pattern) {
const domainParts = domain.split(".");
const patternParts = pattern.split(".");
if (patternParts.length < 1) {
// pattern is empty and therefore invalid to match against
return false;
}
if (domainParts.length < patternParts.length) {
// domain has too few segments and thus cannot match
return false;
}
let depth = 0;
while(patternParts.length && depth++ < 2){
const patternPart = patternParts.pop();
const domainPart = domainParts.pop();
switch(patternPart){
case "":
case "*":
case "**":
{
// invalid pattern. pattern segments must be non empty
// Additionally wildcards are only supported below the domain level
return false;
}
default:
{
if (domainPart !== patternPart) {
return false;
}
}
}
}
while(patternParts.length){
const patternPart = patternParts.pop();
const domainPart = domainParts.pop();
switch(patternPart){
case "":
{
// invalid pattern. pattern segments must be non empty
return false;
}
case "*":
{
// wildcard matches anything so we continue if the domain part is non-empty
if (domainPart) {
continue;
} else {
return false;
}
}
case "**":
{
// if this is not the last item in the pattern the pattern is invalid
if (patternParts.length > 0) {
return false;
}
// recursive wildcard matches anything so we terminate here if the domain part is non empty
return domainPart !== undefined;
}
default:
{
if (domainPart !== patternPart) {
return false;
}
}
}
}
// We exhausted the pattern. If we also exhausted the domain we have a match
return domainParts.length === 0;
}
export const isCsrfOriginAllowed = (originDomain, allowedOrigins = [])=>{
return allowedOrigins.some((allowedOrigin)=>allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin)));
};
//# sourceMappingURL=csrf-protection.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/csrf-protection.ts"],"names":["matchWildcardDomain","domain","pattern","domainParts","split","patternParts","length","depth","patternPart","pop","domainPart","undefined","isCsrfOriginAllowed","originDomain","allowedOrigins","some","allowedOrigin"],"mappings":"AAAA,uHAAuH;AACvH,yGAAyG;AACzG,8EAA8E;AAC9E,4EAA4E;AAC5E,kEAAkE;AAClE,SAASA,oBAAoBC,MAAc,EAAEC,OAAe;IAC1D,MAAMC,cAAcF,OAAOG,KAAK,CAAC;IACjC,MAAMC,eAAeH,QAAQE,KAAK,CAAC;IAEnC,IAAIC,aAAaC,MAAM,GAAG,GAAG;QAC3B,0DAA0D;QAC1D,OAAO;IACT;IAEA,IAAIH,YAAYG,MAAM,GAAGD,aAAaC,MAAM,EAAE;QAC5C,oDAAoD;QACpD,OAAO;IACT;IAEA,IAAIC,QAAQ;IACZ,MAAOF,aAAaC,MAAM,IAAIC,UAAU,EAAG;QACzC,MAAMC,cAAcH,aAAaI,GAAG;QACpC,MAAMC,aAAaP,YAAYM,GAAG;QAElC,OAAQD;YACN,KAAK;YACL,KAAK;YACL,KAAK;gBAAM;oBACT,sDAAsD;oBACtD,mEAAmE;oBACnE,OAAO;gBACT;YACA;gBAAS;oBACP,IAAIE,eAAeF,aAAa;wBAC9B,OAAO;oBACT;gBACF;QACF;IACF;IAEA,MAAOH,aAAaC,MAAM,CAAE;QAC1B,MAAME,cAAcH,aAAaI,GAAG;QACpC,MAAMC,aAAaP,YAAYM,GAAG;QAElC,OAAQD;YACN,KAAK;gBAAI;oBACP,sDAAsD;oBACtD,OAAO;gBACT;YACA,KAAK;gBAAK;oBACR,2EAA2E;oBAC3E,IAAIE,YAAY;wBACd;oBACF,OAAO;wBACL,OAAO;oBACT;gBACF;YACA,KAAK;gBAAM;oBACT,qEAAqE;oBACrE,IAAIL,aAAaC,MAAM,GAAG,GAAG;wBAC3B,OAAO;oBACT;oBACA,2FAA2F;oBAC3F,OAAOI,eAAeC;gBACxB;YACA;gBAAS;oBACP,IAAID,eAAeF,aAAa;wBAC9B,OAAO;oBACT;gBACF;QACF;IACF;IAEA,4EAA4E;IAC5E,OAAOL,YAAYG,MAAM,KAAK;AAChC;AAEA,OAAO,MAAMM,sBAAsB,CACjCC,cACAC,iBAA2B,EAAE;IAE7B,OAAOA,eAAeC,IAAI,CACxB,CAACC,gBACCA,iBACCA,CAAAA,kBAAkBH,gBACjBb,oBAAoBa,cAAcG,cAAa;AAEvD,EAAC"}

View File

@ -0,0 +1,164 @@
/**
* The functions provided by this module are used to communicate certain properties
* about the currently running code so that Next.js can make decisions on how to handle
* the current execution in different rendering modes such as pre-rendering, resuming, and SSR.
*
* Today Next.js treats all code as potentially static. Certain APIs may only make sense when dynamically rendering.
* Traditionally this meant deopting the entire render to dynamic however with PPR we can now deopt parts
* of a React tree as dynamic while still keeping other parts static. There are really two different kinds of
* Dynamic indications.
*
* The first is simply an intention to be dynamic. unstable_noStore is an example of this where
* the currently executing code simply declares that the current scope is dynamic but if you use it
* inside unstable_cache it can still be cached. This type of indication can be removed if we ever
* make the default dynamic to begin with because the only way you would ever be static is inside
* a cache scope which this indication does not affect.
*
* The second is an indication that a dynamic data source was read. This is a stronger form of dynamic
* because it means that it is inappropriate to cache this at all. using a dynamic data source inside
* unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should
* read that data outside the cache and pass it in as an argument to the cached function.
*/ // Once postpone is in stable we should switch to importing the postpone export directly
import React from "react";
import { DynamicServerError } from "../../client/components/hooks-server-context";
import { StaticGenBailoutError } from "../../client/components/static-generation-bailout";
import { getPathname } from "../../lib/url";
const hasPostpone = typeof React.unstable_postpone === "function";
export function createPrerenderState(isDebugSkeleton) {
return {
isDebugSkeleton,
dynamicAccesses: []
};
}
/**
* This function communicates that the current scope should be treated as dynamic.
*
* In most cases this function is a no-op but if called during
* a PPR prerender it will postpone the current sub-tree.
*/ export function markCurrentScopeAsDynamic(store, expression) {
const pathname = getPathname(store.urlPathname);
if (store.isUnstableCacheCallback) {
// inside cache scopes marking a scope as dynamic has no effect because the outer cache scope
// creates a cache boundary. This is subtly different from reading a dynamic data source which is
// forbidden inside a cache scope.
return;
} else if (store.dynamicShouldError) {
throw new StaticGenBailoutError(`Route ${pathname} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`);
} else if (// We are in a prerender (PPR enabled, during build)
store.prerenderState) {
// We track that we had a dynamic scope that postponed.
// This will be used by the renderer to decide whether
// the prerender requires a resume
postponeWithTracking(store.prerenderState, expression, pathname);
} else {
store.revalidate = 0;
if (store.isStaticGeneration) {
// We aren't prerendering but we are generating a static page. We need to bail out of static generation
const err = new DynamicServerError(`Route ${pathname} couldn't be rendered statically because it used ${expression}. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`);
store.dynamicUsageDescription = expression;
store.dynamicUsageStack = err.stack;
throw err;
}
}
}
/**
* This function communicates that some dynamic data was read. This typically would refer to accessing
* a Request specific data store such as cookies or headers. This function is not how end-users will
* describe reading from dynamic data sources which are valid to cache and up to the author to make
* a determination of when to do so.
*
* If we are inside a cache scope we error
* Also during a PPR Prerender we postpone
*/ export function trackDynamicDataAccessed(store, expression) {
const pathname = getPathname(store.urlPathname);
if (store.isUnstableCacheCallback) {
throw new Error(`Route ${pathname} used "${expression}" inside a function cached with "unstable_cache(...)". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "${expression}" outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`);
} else if (store.dynamicShouldError) {
throw new StaticGenBailoutError(`Route ${pathname} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`);
} else if (// We are in a prerender (PPR enabled, during build)
store.prerenderState) {
// We track that we had a dynamic scope that postponed.
// This will be used by the renderer to decide whether
// the prerender requires a resume
postponeWithTracking(store.prerenderState, expression, pathname);
} else {
store.revalidate = 0;
if (store.isStaticGeneration) {
// We aren't prerendering but we are generating a static page. We need to bail out of static generation
const err = new DynamicServerError(`Route ${pathname} couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`);
store.dynamicUsageDescription = expression;
store.dynamicUsageStack = err.stack;
throw err;
}
}
}
export function Postpone({ reason, prerenderState, pathname }) {
postponeWithTracking(prerenderState, reason, pathname);
}
// @TODO refactor patch-fetch and this function to better model dynamic semantics. Currently this implementation
// is too explicit about postponing if we are in a prerender and patch-fetch contains a lot of logic for determining
// what makes the fetch "dynamic". It also doesn't handle Non PPR cases so it is isn't as consistent with the other
// dynamic-rendering methods.
export function trackDynamicFetch(store, expression) {
if (store.prerenderState) {
postponeWithTracking(store.prerenderState, expression, store.urlPathname);
}
}
function postponeWithTracking(prerenderState, expression, pathname) {
assertPostpone();
const reason = `Route ${pathname} needs to bail out of prerendering at this point because it used ${expression}. ` + `React throws this special object to indicate where. It should not be caught by ` + `your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error`;
prerenderState.dynamicAccesses.push({
// When we aren't debugging, we don't need to create another error for the
// stack trace.
stack: prerenderState.isDebugSkeleton ? new Error().stack : undefined,
expression
});
React.unstable_postpone(reason);
}
export function usedDynamicAPIs(prerenderState) {
return prerenderState.dynamicAccesses.length > 0;
}
export function formatDynamicAPIAccesses(prerenderState) {
return prerenderState.dynamicAccesses.filter((access)=>typeof access.stack === "string" && access.stack.length > 0).map(({ expression, stack })=>{
stack = stack.split("\n")// Remove the "Error: " prefix from the first line of the stack trace as
// well as the first 4 lines of the stack trace which is the distance
// from the user code and the `new Error().stack` call.
.slice(4).filter((line)=>{
// Exclude Next.js internals from the stack trace.
if (line.includes("node_modules/next/")) {
return false;
}
// Exclude anonymous functions from the stack trace.
if (line.includes(" (<anonymous>)")) {
return false;
}
// Exclude Node.js internals from the stack trace.
if (line.includes(" (node:")) {
return false;
}
return true;
}).join("\n");
return `Dynamic API Usage Debug - ${expression}:\n${stack}`;
});
}
function assertPostpone() {
if (!hasPostpone) {
throw new Error(`Invariant: React.unstable_postpone is not defined. This suggests the wrong version of React was loaded. This is a bug in Next.js`);
}
}
/**
* This is a bit of a hack to allow us to abort a render using a Postpone instance instead of an Error which changes React's
* abort semantics slightly.
*/ export function createPostponedAbortSignal(reason) {
assertPostpone();
const controller = new AbortController();
// We get our hands on a postpone instance by calling postpone and catching the throw
try {
React.unstable_postpone(reason);
} catch (x) {
controller.abort(x);
}
return controller.signal;
}
//# sourceMappingURL=dynamic-rendering.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/dynamic-rendering.ts"],"names":["React","DynamicServerError","StaticGenBailoutError","getPathname","hasPostpone","unstable_postpone","createPrerenderState","isDebugSkeleton","dynamicAccesses","markCurrentScopeAsDynamic","store","expression","pathname","urlPathname","isUnstableCacheCallback","dynamicShouldError","prerenderState","postponeWithTracking","revalidate","isStaticGeneration","err","dynamicUsageDescription","dynamicUsageStack","stack","trackDynamicDataAccessed","Error","Postpone","reason","trackDynamicFetch","assertPostpone","push","undefined","usedDynamicAPIs","length","formatDynamicAPIAccesses","filter","access","map","split","slice","line","includes","join","createPostponedAbortSignal","controller","AbortController","x","abort","signal"],"mappings":"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"}

View File

@ -0,0 +1,124 @@
// Keep the key in memory as it should never change during the lifetime of the server in
// both development and production.
let __next_encryption_key_generation_promise = null;
let __next_loaded_action_key;
let __next_internal_development_raw_action_key;
export function arrayBufferToString(buffer) {
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
// @anonrig: V8 has a limit of 65535 arguments in a function.
// For len < 65535, this is faster.
// https://github.com/vercel/next.js/pull/56377#pullrequestreview-1656181623
if (len < 65535) {
return String.fromCharCode.apply(null, bytes);
}
let binary = "";
for(let i = 0; i < len; i++){
binary += String.fromCharCode(bytes[i]);
}
return binary;
}
export function stringToUint8Array(binary) {
const len = binary.length;
const arr = new Uint8Array(len);
for(let i = 0; i < len; i++){
arr[i] = binary.charCodeAt(i);
}
return arr;
}
export function encrypt(key, iv, data) {
return crypto.subtle.encrypt({
name: "AES-GCM",
iv
}, key, data);
}
export function decrypt(key, iv, data) {
return crypto.subtle.decrypt({
name: "AES-GCM",
iv
}, key, data);
}
export async function generateEncryptionKeyBase64(dev) {
// For development, we just keep one key in memory for all actions.
// This makes things faster.
if (dev) {
if (typeof __next_internal_development_raw_action_key !== "undefined") {
return __next_internal_development_raw_action_key;
}
}
// This avoids it being generated multiple times in parallel.
if (!__next_encryption_key_generation_promise) {
__next_encryption_key_generation_promise = new Promise(async (resolve, reject)=>{
try {
const key = await crypto.subtle.generateKey({
name: "AES-GCM",
length: 256
}, true, [
"encrypt",
"decrypt"
]);
const exported = await crypto.subtle.exportKey("raw", key);
const b64 = btoa(arrayBufferToString(exported));
resolve([
key,
b64
]);
} catch (error) {
reject(error);
}
});
}
const [key, b64] = await __next_encryption_key_generation_promise;
__next_loaded_action_key = key;
if (dev) {
__next_internal_development_raw_action_key = b64;
}
return b64;
}
// This is a global singleton that is used to encode/decode the action bound args from
// the closure. This can't be using a AsyncLocalStorage as it might happen on the module
// level. Since the client reference manifest won't be mutated, let's use a global singleton
// to keep it.
const SERVER_ACTION_MANIFESTS_SINGLETON = Symbol.for("next.server.action-manifests");
export function setReferenceManifestsSingleton({ clientReferenceManifest, serverActionsManifest, serverModuleMap }) {
// @ts-ignore
globalThis[SERVER_ACTION_MANIFESTS_SINGLETON] = {
clientReferenceManifest,
serverActionsManifest,
serverModuleMap
};
}
export function getServerModuleMap() {
const serverActionsManifestSingleton = globalThis[SERVER_ACTION_MANIFESTS_SINGLETON];
if (!serverActionsManifestSingleton) {
throw new Error("Missing manifest for Server Actions. This is a bug in Next.js");
}
return serverActionsManifestSingleton.serverModuleMap;
}
export function getClientReferenceManifestSingleton() {
const serverActionsManifestSingleton = globalThis[SERVER_ACTION_MANIFESTS_SINGLETON];
if (!serverActionsManifestSingleton) {
throw new Error("Missing manifest for Server Actions. This is a bug in Next.js");
}
return serverActionsManifestSingleton.clientReferenceManifest;
}
export async function getActionEncryptionKey() {
if (__next_loaded_action_key) {
return __next_loaded_action_key;
}
const serverActionsManifestSingleton = globalThis[SERVER_ACTION_MANIFESTS_SINGLETON];
if (!serverActionsManifestSingleton) {
throw new Error("Missing manifest for Server Actions. This is a bug in Next.js");
}
const rawKey = process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY || serverActionsManifestSingleton.serverActionsManifest.encryptionKey;
if (rawKey === undefined) {
throw new Error("Missing encryption key for Server Actions");
}
__next_loaded_action_key = await crypto.subtle.importKey("raw", stringToUint8Array(atob(rawKey)), "AES-GCM", true, [
"encrypt",
"decrypt"
]);
return __next_loaded_action_key;
}
//# sourceMappingURL=encryption-utils.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/encryption-utils.ts"],"names":["__next_encryption_key_generation_promise","__next_loaded_action_key","__next_internal_development_raw_action_key","arrayBufferToString","buffer","bytes","Uint8Array","len","byteLength","String","fromCharCode","apply","binary","i","stringToUint8Array","length","arr","charCodeAt","encrypt","key","iv","data","crypto","subtle","name","decrypt","generateEncryptionKeyBase64","dev","Promise","resolve","reject","generateKey","exported","exportKey","b64","btoa","error","SERVER_ACTION_MANIFESTS_SINGLETON","Symbol","for","setReferenceManifestsSingleton","clientReferenceManifest","serverActionsManifest","serverModuleMap","globalThis","getServerModuleMap","serverActionsManifestSingleton","Error","getClientReferenceManifestSingleton","getActionEncryptionKey","rawKey","process","env","NEXT_SERVER_ACTIONS_ENCRYPTION_KEY","encryptionKey","undefined","importKey","atob"],"mappings":"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"}

View File

@ -0,0 +1,72 @@
/* eslint-disable import/no-extraneous-dependencies */ import "server-only";
/* eslint-disable import/no-extraneous-dependencies */ import { renderToReadableStream, decodeReply } from "react-server-dom-webpack/server.edge";
/* eslint-disable import/no-extraneous-dependencies */ import { createFromReadableStream, encodeReply } from "react-server-dom-webpack/client.edge";
import { streamToString } from "../stream-utils/node-web-streams-helper";
import { arrayBufferToString, decrypt, encrypt, getActionEncryptionKey, getClientReferenceManifestSingleton, getServerModuleMap, stringToUint8Array } from "./encryption-utils";
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
async function decodeActionBoundArg(actionId, arg) {
const key = await getActionEncryptionKey();
if (typeof key === "undefined") {
throw new Error(`Missing encryption key for Server Action. This is a bug in Next.js`);
}
// Get the iv (16 bytes) and the payload from the arg.
const originalPayload = atob(arg);
const ivValue = originalPayload.slice(0, 16);
const payload = originalPayload.slice(16);
const decrypted = textDecoder.decode(await decrypt(key, stringToUint8Array(ivValue), stringToUint8Array(payload)));
if (!decrypted.startsWith(actionId)) {
throw new Error("Invalid Server Action payload: failed to decrypt.");
}
return decrypted.slice(actionId.length);
}
async function encodeActionBoundArg(actionId, arg) {
const key = await getActionEncryptionKey();
if (key === undefined) {
throw new Error(`Missing encryption key for Server Action. This is a bug in Next.js`);
}
// Get 16 random bytes as iv.
const randomBytes = new Uint8Array(16);
crypto.getRandomValues(randomBytes);
const ivValue = arrayBufferToString(randomBytes.buffer);
const encrypted = await encrypt(key, randomBytes, textEncoder.encode(actionId + arg));
return btoa(ivValue + arrayBufferToString(encrypted));
}
// Encrypts the action's bound args into a string.
export async function encryptActionBoundArgs(actionId, args) {
const clientReferenceManifestSingleton = getClientReferenceManifestSingleton();
// Using Flight to serialize the args into a string.
const serialized = await streamToString(renderToReadableStream(args, clientReferenceManifestSingleton.clientModules));
// Encrypt the serialized string with the action id as the salt.
// Add a prefix to later ensure that the payload is correctly decrypted, similar
// to a checksum.
const encrypted = await encodeActionBoundArg(actionId, serialized);
return encrypted;
}
// Decrypts the action's bound args from the encrypted string.
export async function decryptActionBoundArgs(actionId, encrypted) {
// Decrypt the serialized string with the action id as the salt.
const decryped = await decodeActionBoundArg(actionId, await encrypted);
// Using Flight to deserialize the args from the string.
const deserialized = await createFromReadableStream(new ReadableStream({
start (controller) {
controller.enqueue(textEncoder.encode(decryped));
controller.close();
}
}), {
ssrManifest: {
// TODO: We can't use the client reference manifest to resolve the modules
// on the server side - instead they need to be recovered as the module
// references (proxies) again.
// For now, we'll just use an empty module map.
moduleLoading: {},
moduleMap: {}
}
});
// This extra step ensures that the server references are recovered.
const serverModuleMap = getServerModuleMap();
const transformed = await decodeReply(await encodeReply(deserialized), serverModuleMap);
return transformed;
}
//# sourceMappingURL=encryption.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/encryption.ts"],"names":["renderToReadableStream","decodeReply","createFromReadableStream","encodeReply","streamToString","arrayBufferToString","decrypt","encrypt","getActionEncryptionKey","getClientReferenceManifestSingleton","getServerModuleMap","stringToUint8Array","textEncoder","TextEncoder","textDecoder","TextDecoder","decodeActionBoundArg","actionId","arg","key","Error","originalPayload","atob","ivValue","slice","payload","decrypted","decode","startsWith","length","encodeActionBoundArg","undefined","randomBytes","Uint8Array","crypto","getRandomValues","buffer","encrypted","encode","btoa","encryptActionBoundArgs","args","clientReferenceManifestSingleton","serialized","clientModules","decryptActionBoundArgs","decryped","deserialized","ReadableStream","start","controller","enqueue","close","ssrManifest","moduleLoading","moduleMap","serverModuleMap","transformed"],"mappings":"AAAA,oDAAoD,GACpD,OAAO,cAAa;AAEpB,oDAAoD,GACpD,SACEA,sBAAsB,EACtBC,WAAW,QACN,uCAAsC;AAC7C,oDAAoD,GACpD,SACEC,wBAAwB,EACxBC,WAAW,QACN,uCAAsC;AAE7C,SAASC,cAAc,QAAQ,0CAAyC;AACxE,SACEC,mBAAmB,EACnBC,OAAO,EACPC,OAAO,EACPC,sBAAsB,EACtBC,mCAAmC,EACnCC,kBAAkB,EAClBC,kBAAkB,QACb,qBAAoB;AAE3B,MAAMC,cAAc,IAAIC;AACxB,MAAMC,cAAc,IAAIC;AAExB,eAAeC,qBAAqBC,QAAgB,EAAEC,GAAW;IAC/D,MAAMC,MAAM,MAAMX;IAClB,IAAI,OAAOW,QAAQ,aAAa;QAC9B,MAAM,IAAIC,MACR,CAAC,kEAAkE,CAAC;IAExE;IAEA,sDAAsD;IACtD,MAAMC,kBAAkBC,KAAKJ;IAC7B,MAAMK,UAAUF,gBAAgBG,KAAK,CAAC,GAAG;IACzC,MAAMC,UAAUJ,gBAAgBG,KAAK,CAAC;IAEtC,MAAME,YAAYZ,YAAYa,MAAM,CAClC,MAAMrB,QAAQa,KAAKR,mBAAmBY,UAAUZ,mBAAmBc;IAGrE,IAAI,CAACC,UAAUE,UAAU,CAACX,WAAW;QACnC,MAAM,IAAIG,MAAM;IAClB;IAEA,OAAOM,UAAUF,KAAK,CAACP,SAASY,MAAM;AACxC;AAEA,eAAeC,qBAAqBb,QAAgB,EAAEC,GAAW;IAC/D,MAAMC,MAAM,MAAMX;IAClB,IAAIW,QAAQY,WAAW;QACrB,MAAM,IAAIX,MACR,CAAC,kEAAkE,CAAC;IAExE;IAEA,6BAA6B;IAC7B,MAAMY,cAAc,IAAIC,WAAW;IACnCC,OAAOC,eAAe,CAACH;IACvB,MAAMT,UAAUlB,oBAAoB2B,YAAYI,MAAM;IAEtD,MAAMC,YAAY,MAAM9B,QACtBY,KACAa,aACApB,YAAY0B,MAAM,CAACrB,WAAWC;IAGhC,OAAOqB,KAAKhB,UAAUlB,oBAAoBgC;AAC5C;AAEA,kDAAkD;AAClD,OAAO,eAAeG,uBAAuBvB,QAAgB,EAAEwB,IAAW;IACxE,MAAMC,mCAAmCjC;IAEzC,oDAAoD;IACpD,MAAMkC,aAAa,MAAMvC,eACvBJ,uBAAuByC,MAAMC,iCAAiCE,aAAa;IAG7E,gEAAgE;IAChE,gFAAgF;IAChF,iBAAiB;IACjB,MAAMP,YAAY,MAAMP,qBAAqBb,UAAU0B;IAEvD,OAAON;AACT;AAEA,8DAA8D;AAC9D,OAAO,eAAeQ,uBACpB5B,QAAgB,EAChBoB,SAA0B;IAE1B,gEAAgE;IAChE,MAAMS,WAAW,MAAM9B,qBAAqBC,UAAU,MAAMoB;IAE5D,wDAAwD;IACxD,MAAMU,eAAe,MAAM7C,yBACzB,IAAI8C,eAAe;QACjBC,OAAMC,UAAU;YACdA,WAAWC,OAAO,CAACvC,YAAY0B,MAAM,CAACQ;YACtCI,WAAWE,KAAK;QAClB;IACF,IACA;QACEC,aAAa;YACX,0EAA0E;YAC1E,uEAAuE;YACvE,8BAA8B;YAC9B,+CAA+C;YAC/CC,eAAe,CAAC;YAChBC,WAAW,CAAC;QACd;IACF;IAGF,oEAAoE;IACpE,MAAMC,kBAAkB9C;IACxB,MAAM+C,cAAc,MAAMxD,YACxB,MAAME,YAAY4C,eAClBS;IAGF,OAAOC;AACT"}

View File

@ -0,0 +1,29 @@
// eslint-disable-next-line import/no-extraneous-dependencies
export { renderToReadableStream, decodeReply, decodeAction, decodeFormState } from "react-server-dom-webpack/server.edge";
import AppRouter from "../../client/components/app-router";
import LayoutRouter from "../../client/components/layout-router";
import RenderFromTemplateContext from "../../client/components/render-from-template-context";
import { staticGenerationAsyncStorage } from "../../client/components/static-generation-async-storage.external";
import { requestAsyncStorage } from "../../client/components/request-async-storage.external";
import { actionAsyncStorage } from "../../client/components/action-async-storage.external";
import { ClientPageRoot } from "../../client/components/client-page";
import { createUntrackedSearchParams, createDynamicallyTrackedSearchParams } from "../../client/components/search-params";
import * as serverHooks from "../../client/components/hooks-server-context";
import { NotFoundBoundary } from "../../client/components/not-found-boundary";
import { patchFetch as _patchFetch } from "../lib/patch-fetch";
// not being used but needs to be included in the client manifest for /_not-found
import "../../client/components/error-boundary";
import { preloadStyle, preloadFont, preconnect } from "../../server/app-render/rsc/preloads";
import { Postpone } from "../../server/app-render/rsc/postpone";
import { taintObjectReference } from "../../server/app-render/rsc/taint";
// patchFetch makes use of APIs such as `React.unstable_postpone` which are only available
// in the experimental channel of React, so export it from here so that it comes from the bundled runtime
function patchFetch() {
return _patchFetch({
serverHooks,
staticGenerationAsyncStorage
});
}
export { AppRouter, LayoutRouter, RenderFromTemplateContext, staticGenerationAsyncStorage, requestAsyncStorage, actionAsyncStorage, createUntrackedSearchParams, createDynamicallyTrackedSearchParams, serverHooks, preloadStyle, preloadFont, preconnect, Postpone, taintObjectReference, ClientPageRoot, NotFoundBoundary, patchFetch, };
//# sourceMappingURL=entry-base.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/entry-base.ts"],"names":["renderToReadableStream","decodeReply","decodeAction","decodeFormState","AppRouter","LayoutRouter","RenderFromTemplateContext","staticGenerationAsyncStorage","requestAsyncStorage","actionAsyncStorage","ClientPageRoot","createUntrackedSearchParams","createDynamicallyTrackedSearchParams","serverHooks","NotFoundBoundary","patchFetch","_patchFetch","preloadStyle","preloadFont","preconnect","Postpone","taintObjectReference"],"mappings":"AAAA,6DAA6D;AAC7D,SACEA,sBAAsB,EACtBC,WAAW,EACXC,YAAY,EACZC,eAAe,QACV,uCAAsC;AAE7C,OAAOC,eAAe,qCAAoC;AAC1D,OAAOC,kBAAkB,wCAAuC;AAChE,OAAOC,+BAA+B,uDAAsD;AAC5F,SAASC,4BAA4B,QAAQ,mEAAkE;AAC/G,SAASC,mBAAmB,QAAQ,yDAAwD;AAC5F,SAASC,kBAAkB,QAAQ,wDAAuD;AAC1F,SAASC,cAAc,QAAQ,sCAAqC;AACpE,SACEC,2BAA2B,EAC3BC,oCAAoC,QAC/B,wCAAuC;AAC9C,YAAYC,iBAAiB,+CAA8C;AAC3E,SAASC,gBAAgB,QAAQ,6CAA4C;AAC7E,SAASC,cAAcC,WAAW,QAAQ,qBAAoB;AAC9D,iFAAiF;AACjF,OAAO,yCAAwC;AAE/C,SACEC,YAAY,EACZC,WAAW,EACXC,UAAU,QACL,uCAAsC;AAC7C,SAASC,QAAQ,QAAQ,uCAAsC;AAC/D,SAASC,oBAAoB,QAAQ,oCAAmC;AAExE,0FAA0F;AAC1F,yGAAyG;AACzG,SAASN;IACP,OAAOC,YAAY;QAAEH;QAAaN;IAA6B;AACjE;AAEA,SACEH,SAAS,EACTC,YAAY,EACZC,yBAAyB,EACzBC,4BAA4B,EAC5BC,mBAAmB,EACnBC,kBAAkB,EAClBE,2BAA2B,EAC3BC,oCAAoC,EACpCC,WAAW,EACXI,YAAY,EACZC,WAAW,EACXC,UAAU,EACVC,QAAQ,EACRC,oBAAoB,EACpBX,cAAc,EACdI,gBAAgB,EAChBC,UAAU,KACX"}

View File

@ -0,0 +1,14 @@
import { RSC_CONTENT_TYPE_HEADER } from "../../client/components/app-router-headers";
import RenderResult from "../render-result";
/**
* Flight Response is always set to RSC_CONTENT_TYPE_HEADER to ensure it does not get interpreted as HTML.
*/ export class FlightRenderResult extends RenderResult {
constructor(response){
super(response, {
contentType: RSC_CONTENT_TYPE_HEADER,
metadata: {}
});
}
}
//# sourceMappingURL=flight-render-result.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/flight-render-result.ts"],"names":["RSC_CONTENT_TYPE_HEADER","RenderResult","FlightRenderResult","constructor","response","contentType","metadata"],"mappings":"AAAA,SAASA,uBAAuB,QAAQ,6CAA4C;AACpF,OAAOC,kBAAkB,mBAAkB;AAE3C;;CAEC,GACD,OAAO,MAAMC,2BAA2BD;IACtCE,YAAYC,QAA6C,CAAE;QACzD,KAAK,CAACA,UAAU;YAAEC,aAAaL;YAAyBM,UAAU,CAAC;QAAE;IACvE;AACF"}

View File

@ -0,0 +1,18 @@
const isDev = process.env.NODE_ENV === "development";
const isTurbopack = !!process.env.TURBOPACK;
export function getAssetQueryString(ctx, addTimestamp) {
let qs = "";
// In development we add the request timestamp to allow react to
// reload assets when a new RSC response is received.
// Turbopack handles HMR of assets itself and react doesn't need to reload them
// so this approach is not needed for Turbopack.
if (isDev && !isTurbopack && addTimestamp) {
qs += `?v=${ctx.requestTimestamp}`;
}
if (ctx.renderOpts.deploymentId) {
qs += `${isDev ? "&" : "?"}dpl=${ctx.renderOpts.deploymentId}`;
}
return qs;
}
//# sourceMappingURL=get-asset-query-string.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-asset-query-string.ts"],"names":["isDev","process","env","NODE_ENV","isTurbopack","TURBOPACK","getAssetQueryString","ctx","addTimestamp","qs","requestTimestamp","renderOpts","deploymentId"],"mappings":"AAEA,MAAMA,QAAQC,QAAQC,GAAG,CAACC,QAAQ,KAAK;AACvC,MAAMC,cAAc,CAAC,CAACH,QAAQC,GAAG,CAACG,SAAS;AAC3C,OAAO,SAASC,oBACdC,GAAqB,EACrBC,YAAqB;IAErB,IAAIC,KAAK;IAET,gEAAgE;IAChE,qDAAqD;IACrD,+EAA+E;IAC/E,gDAAgD;IAChD,IAAIT,SAAS,CAACI,eAAeI,cAAc;QACzCC,MAAM,CAAC,GAAG,EAAEF,IAAIG,gBAAgB,CAAC,CAAC;IACpC;IAEA,IAAIH,IAAII,UAAU,CAACC,YAAY,EAAE;QAC/BH,MAAM,CAAC,EAAET,QAAQ,MAAM,IAAI,IAAI,EAAEO,IAAII,UAAU,CAACC,YAAY,CAAC,CAAC;IAChE;IACA,OAAOH;AACT"}

View File

@ -0,0 +1,40 @@
/**
* Get external stylesheet link hrefs based on server CSS manifest.
*/ export function getLinkAndScriptTags(clientReferenceManifest, filePath, injectedCSS, injectedScripts, collectNewImports) {
var _clientReferenceManifest_entryJSFiles;
const filePathWithoutExt = filePath.replace(/\.[^.]+$/, "");
const cssChunks = new Set();
const jsChunks = new Set();
const entryCSSFiles = clientReferenceManifest.entryCSSFiles[filePathWithoutExt];
const entryJSFiles = ((_clientReferenceManifest_entryJSFiles = clientReferenceManifest.entryJSFiles) == null ? void 0 : _clientReferenceManifest_entryJSFiles[filePathWithoutExt]) ?? [];
if (entryCSSFiles) {
for (const file of entryCSSFiles){
if (!injectedCSS.has(file)) {
if (collectNewImports) {
injectedCSS.add(file);
}
cssChunks.add(file);
}
}
}
if (entryJSFiles) {
for (const file of entryJSFiles){
if (!injectedScripts.has(file)) {
if (collectNewImports) {
injectedScripts.add(file);
}
jsChunks.add(file);
}
}
}
return {
styles: [
...cssChunks
],
scripts: [
...jsChunks
]
};
}
//# sourceMappingURL=get-css-inlined-link-tags.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-css-inlined-link-tags.tsx"],"names":["getLinkAndScriptTags","clientReferenceManifest","filePath","injectedCSS","injectedScripts","collectNewImports","filePathWithoutExt","replace","cssChunks","Set","jsChunks","entryCSSFiles","entryJSFiles","file","has","add","styles","scripts"],"mappings":"AAGA;;CAEC,GACD,OAAO,SAASA,qBACdC,uBAA8D,EAC9DC,QAAgB,EAChBC,WAAwB,EACxBC,eAA4B,EAC5BC,iBAA2B;QASzBJ;IAPF,MAAMK,qBAAqBJ,SAASK,OAAO,CAAC,YAAY;IACxD,MAAMC,YAAY,IAAIC;IACtB,MAAMC,WAAW,IAAID;IAErB,MAAME,gBACJV,wBAAwBU,aAAa,CAACL,mBAAmB;IAC3D,MAAMM,eACJX,EAAAA,wCAAAA,wBAAwBW,YAAY,qBAApCX,qCAAsC,CAACK,mBAAmB,KAAI,EAAE;IAElE,IAAIK,eAAe;QACjB,KAAK,MAAME,QAAQF,cAAe;YAChC,IAAI,CAACR,YAAYW,GAAG,CAACD,OAAO;gBAC1B,IAAIR,mBAAmB;oBACrBF,YAAYY,GAAG,CAACF;gBAClB;gBACAL,UAAUO,GAAG,CAACF;YAChB;QACF;IACF;IAEA,IAAID,cAAc;QAChB,KAAK,MAAMC,QAAQD,aAAc;YAC/B,IAAI,CAACR,gBAAgBU,GAAG,CAACD,OAAO;gBAC9B,IAAIR,mBAAmB;oBACrBD,gBAAgBW,GAAG,CAACF;gBACtB;gBACAH,SAASK,GAAG,CAACF;YACf;QACF;IACF;IAEA,OAAO;QAAEG,QAAQ;eAAIR;SAAU;QAAES,SAAS;eAAIP;SAAS;IAAC;AAC1D"}

View File

@ -0,0 +1,70 @@
import { jsx as _jsx } from "react/jsx-runtime";
import React from "react";
import { getLinkAndScriptTags } from "./get-css-inlined-link-tags";
import { getPreloadableFonts } from "./get-preloadable-fonts";
import { getAssetQueryString } from "./get-asset-query-string";
import { encodeURIPath } from "../../shared/lib/encode-uri-path";
export function getLayerAssets({ ctx, layoutOrPagePath, injectedCSS: injectedCSSWithCurrentLayout, injectedJS: injectedJSWithCurrentLayout, injectedFontPreloadTags: injectedFontPreloadTagsWithCurrentLayout }) {
const { styles: styleTags, scripts: scriptTags } = layoutOrPagePath ? getLinkAndScriptTags(ctx.clientReferenceManifest, layoutOrPagePath, injectedCSSWithCurrentLayout, injectedJSWithCurrentLayout, true) : {
styles: [],
scripts: []
};
const preloadedFontFiles = layoutOrPagePath ? getPreloadableFonts(ctx.renderOpts.nextFontManifest, layoutOrPagePath, injectedFontPreloadTagsWithCurrentLayout) : null;
if (preloadedFontFiles) {
if (preloadedFontFiles.length) {
for(let i = 0; i < preloadedFontFiles.length; i++){
const fontFilename = preloadedFontFiles[i];
const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(fontFilename)[1];
const type = `font/${ext}`;
const href = `${ctx.assetPrefix}/_next/${encodeURIPath(fontFilename)}`;
ctx.componentMod.preloadFont(href, type, ctx.renderOpts.crossOrigin);
}
} else {
try {
let url = new URL(ctx.assetPrefix);
ctx.componentMod.preconnect(url.origin, "anonymous");
} catch (error) {
// assetPrefix must not be a fully qualified domain name. We assume
// we should preconnect to same origin instead
ctx.componentMod.preconnect("/", "anonymous");
}
}
}
const styles = styleTags ? styleTags.map((href, index)=>{
// In dev, Safari and Firefox will cache the resource during HMR:
// - https://github.com/vercel/next.js/issues/5860
// - https://bugs.webkit.org/show_bug.cgi?id=187726
// Because of this, we add a `?v=` query to bypass the cache during
// development. We need to also make sure that the number is always
// increasing.
const fullHref = `${ctx.assetPrefix}/_next/${encodeURIPath(href)}${getAssetQueryString(ctx, true)}`;
// `Precedence` is an opt-in signal for React to handle resource
// loading and deduplication, etc. It's also used as the key to sort
// resources so they will be injected in the correct order.
// During HMR, it's critical to use different `precedence` values
// for different stylesheets, so their order will be kept.
// https://github.com/facebook/react/pull/25060
const precedence = process.env.NODE_ENV === "development" ? "next_" + href : "next";
ctx.componentMod.preloadStyle(fullHref, ctx.renderOpts.crossOrigin);
return /*#__PURE__*/ _jsx("link", {
rel: "stylesheet",
href: fullHref,
// @ts-ignore
precedence: precedence,
crossOrigin: ctx.renderOpts.crossOrigin
}, index);
}) : [];
const scripts = scriptTags ? scriptTags.map((href, index)=>{
const fullSrc = `${ctx.assetPrefix}/_next/${encodeURIPath(href)}${getAssetQueryString(ctx, true)}`;
return /*#__PURE__*/ _jsx("script", {
src: fullSrc,
async: true
}, `script-${index}`);
}) : [];
return styles.length || scripts.length ? [
...styles,
...scripts
] : null;
}
//# sourceMappingURL=get-layer-assets.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-layer-assets.tsx"],"names":["React","getLinkAndScriptTags","getPreloadableFonts","getAssetQueryString","encodeURIPath","getLayerAssets","ctx","layoutOrPagePath","injectedCSS","injectedCSSWithCurrentLayout","injectedJS","injectedJSWithCurrentLayout","injectedFontPreloadTags","injectedFontPreloadTagsWithCurrentLayout","styles","styleTags","scripts","scriptTags","clientReferenceManifest","preloadedFontFiles","renderOpts","nextFontManifest","length","i","fontFilename","ext","exec","type","href","assetPrefix","componentMod","preloadFont","crossOrigin","url","URL","preconnect","origin","error","map","index","fullHref","precedence","process","env","NODE_ENV","preloadStyle","link","rel","fullSrc","script","src","async"],"mappings":";AAAA,OAAOA,WAAW,QAAO;AACzB,SAASC,oBAAoB,QAAQ,8BAA6B;AAClE,SAASC,mBAAmB,QAAQ,0BAAyB;AAE7D,SAASC,mBAAmB,QAAQ,2BAA0B;AAC9D,SAASC,aAAa,QAAQ,mCAAkC;AAEhE,OAAO,SAASC,eAAe,EAC7BC,GAAG,EACHC,gBAAgB,EAChBC,aAAaC,4BAA4B,EACzCC,YAAYC,2BAA2B,EACvCC,yBAAyBC,wCAAwC,EAOlE;IACC,MAAM,EAAEC,QAAQC,SAAS,EAAEC,SAASC,UAAU,EAAE,GAAGV,mBAC/CN,qBACEK,IAAIY,uBAAuB,EAC3BX,kBACAE,8BACAE,6BACA,QAEF;QAAEG,QAAQ,EAAE;QAAEE,SAAS,EAAE;IAAC;IAE9B,MAAMG,qBAAqBZ,mBACvBL,oBACEI,IAAIc,UAAU,CAACC,gBAAgB,EAC/Bd,kBACAM,4CAEF;IAEJ,IAAIM,oBAAoB;QACtB,IAAIA,mBAAmBG,MAAM,EAAE;YAC7B,IAAK,IAAIC,IAAI,GAAGA,IAAIJ,mBAAmBG,MAAM,EAAEC,IAAK;gBAClD,MAAMC,eAAeL,kBAAkB,CAACI,EAAE;gBAC1C,MAAME,MAAM,8BAA8BC,IAAI,CAACF,aAAc,CAAC,EAAE;gBAChE,MAAMG,OAAO,CAAC,KAAK,EAAEF,IAAI,CAAC;gBAC1B,MAAMG,OAAO,CAAC,EAAEtB,IAAIuB,WAAW,CAAC,OAAO,EAAEzB,cAAcoB,cAAc,CAAC;gBACtElB,IAAIwB,YAAY,CAACC,WAAW,CAACH,MAAMD,MAAMrB,IAAIc,UAAU,CAACY,WAAW;YACrE;QACF,OAAO;YACL,IAAI;gBACF,IAAIC,MAAM,IAAIC,IAAI5B,IAAIuB,WAAW;gBACjCvB,IAAIwB,YAAY,CAACK,UAAU,CAACF,IAAIG,MAAM,EAAE;YAC1C,EAAE,OAAOC,OAAO;gBACd,mEAAmE;gBACnE,8CAA8C;gBAC9C/B,IAAIwB,YAAY,CAACK,UAAU,CAAC,KAAK;YACnC;QACF;IACF;IAEA,MAAMrB,SAASC,YACXA,UAAUuB,GAAG,CAAC,CAACV,MAAMW;QACnB,iEAAiE;QACjE,kDAAkD;QAClD,mDAAmD;QACnD,mEAAmE;QACnE,mEAAmE;QACnE,cAAc;QACd,MAAMC,WAAW,CAAC,EAAElC,IAAIuB,WAAW,CAAC,OAAO,EAAEzB,cAC3CwB,MACA,EAAEzB,oBAAoBG,KAAK,MAAM,CAAC;QAEpC,gEAAgE;QAChE,oEAAoE;QACpE,2DAA2D;QAC3D,iEAAiE;QACjE,0DAA0D;QAC1D,+CAA+C;QAC/C,MAAMmC,aACJC,QAAQC,GAAG,CAACC,QAAQ,KAAK,gBAAgB,UAAUhB,OAAO;QAE5DtB,IAAIwB,YAAY,CAACe,YAAY,CAACL,UAAUlC,IAAIc,UAAU,CAACY,WAAW;QAElE,qBACE,KAACc;YACCC,KAAI;YACJnB,MAAMY;YACN,aAAa;YACbC,YAAYA;YACZT,aAAa1B,IAAIc,UAAU,CAACY,WAAW;WAClCO;IAGX,KACA,EAAE;IAEN,MAAMvB,UAAUC,aACZA,WAAWqB,GAAG,CAAC,CAACV,MAAMW;QACpB,MAAMS,UAAU,CAAC,EAAE1C,IAAIuB,WAAW,CAAC,OAAO,EAAEzB,cAC1CwB,MACA,EAAEzB,oBAAoBG,KAAK,MAAM,CAAC;QAEpC,qBAAO,KAAC2C;YAAOC,KAAKF;YAASG,OAAO;WAAW,CAAC,OAAO,EAAEZ,MAAM,CAAC;IAClE,KACA,EAAE;IAEN,OAAOzB,OAAOQ,MAAM,IAAIN,QAAQM,MAAM,GAAG;WAAIR;WAAWE;KAAQ,GAAG;AACrE"}

View File

@ -0,0 +1,35 @@
/**
* Get hrefs for fonts to preload
* Returns null if there are no fonts at all.
* Returns string[] if there are fonts to preload (font paths)
* Returns empty string[] if there are fonts but none to preload and no other fonts have been preloaded
* Returns null if there are fonts but none to preload and at least some were previously preloaded
*/ export function getPreloadableFonts(nextFontManifest, filePath, injectedFontPreloadTags) {
if (!nextFontManifest || !filePath) {
return null;
}
const filepathWithoutExtension = filePath.replace(/\.[^.]+$/, "");
const fontFiles = new Set();
let foundFontUsage = false;
const preloadedFontFiles = nextFontManifest.app[filepathWithoutExtension];
if (preloadedFontFiles) {
foundFontUsage = true;
for (const fontFile of preloadedFontFiles){
if (!injectedFontPreloadTags.has(fontFile)) {
fontFiles.add(fontFile);
injectedFontPreloadTags.add(fontFile);
}
}
}
if (fontFiles.size) {
return [
...fontFiles
].sort();
} else if (foundFontUsage && injectedFontPreloadTags.size === 0) {
return [];
} else {
return null;
}
}
//# sourceMappingURL=get-preloadable-fonts.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-preloadable-fonts.tsx"],"names":["getPreloadableFonts","nextFontManifest","filePath","injectedFontPreloadTags","filepathWithoutExtension","replace","fontFiles","Set","foundFontUsage","preloadedFontFiles","app","fontFile","has","add","size","sort"],"mappings":"AAGA;;;;;;CAMC,GACD,OAAO,SAASA,oBACdC,gBAA4D,EAC5DC,QAA4B,EAC5BC,uBAAoC;IAEpC,IAAI,CAACF,oBAAoB,CAACC,UAAU;QAClC,OAAO;IACT;IACA,MAAME,2BAA2BF,SAASG,OAAO,CAAC,YAAY;IAC9D,MAAMC,YAAY,IAAIC;IACtB,IAAIC,iBAAiB;IAErB,MAAMC,qBAAqBR,iBAAiBS,GAAG,CAACN,yBAAyB;IACzE,IAAIK,oBAAoB;QACtBD,iBAAiB;QACjB,KAAK,MAAMG,YAAYF,mBAAoB;YACzC,IAAI,CAACN,wBAAwBS,GAAG,CAACD,WAAW;gBAC1CL,UAAUO,GAAG,CAACF;gBACdR,wBAAwBU,GAAG,CAACF;YAC9B;QACF;IACF;IAEA,IAAIL,UAAUQ,IAAI,EAAE;QAClB,OAAO;eAAIR;SAAU,CAACS,IAAI;IAC5B,OAAO,IAAIP,kBAAkBL,wBAAwBW,IAAI,KAAK,GAAG;QAC/D,OAAO,EAAE;IACX,OAAO;QACL,OAAO;IACT;AACF"}

View File

@ -0,0 +1,30 @@
import { ESCAPE_REGEX } from "../htmlescape";
export function getScriptNonceFromHeader(cspHeaderValue) {
var _directive_split_slice_map_find;
const directives = cspHeaderValue// Directives are split by ';'.
.split(";").map((directive)=>directive.trim());
// First try to find the directive for the 'script-src', otherwise try to
// fallback to the 'default-src'.
const directive = directives.find((dir)=>dir.startsWith("script-src")) || directives.find((dir)=>dir.startsWith("default-src"));
// If no directive could be found, then we're done.
if (!directive) {
return;
}
// Extract the nonce from the directive
const nonce = (_directive_split_slice_map_find = directive.split(" ")// Remove the 'strict-src'/'default-src' string, this can't be the nonce.
.slice(1).map((source)=>source.trim())// Find the first source with the 'nonce-' prefix.
.find((source)=>source.startsWith("'nonce-") && source.length > 8 && source.endsWith("'"))) == null ? void 0 : _directive_split_slice_map_find.slice(7, -1);
// If we could't find the nonce, then we're done.
if (!nonce) {
return;
}
// Don't accept the nonce value if it contains HTML escape characters.
// Technically, the spec requires a base64'd value, but this is just an
// extra layer.
if (ESCAPE_REGEX.test(nonce)) {
throw new Error("Nonce value from Content-Security-Policy contained HTML escape characters.\nLearn more: https://nextjs.org/docs/messages/nonce-contained-invalid-characters");
}
return nonce;
}
//# sourceMappingURL=get-script-nonce-from-header.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-script-nonce-from-header.tsx"],"names":["ESCAPE_REGEX","getScriptNonceFromHeader","cspHeaderValue","directive","directives","split","map","trim","find","dir","startsWith","nonce","slice","source","length","endsWith","test","Error"],"mappings":"AAAA,SAASA,YAAY,QAAQ,gBAAe;AAE5C,OAAO,SAASC,yBACdC,cAAsB;QAmBRC;IAjBd,MAAMC,aAAaF,cACjB,+BAA+B;KAC9BG,KAAK,CAAC,KACNC,GAAG,CAAC,CAACH,YAAcA,UAAUI,IAAI;IAEpC,yEAAyE;IACzE,iCAAiC;IACjC,MAAMJ,YACJC,WAAWI,IAAI,CAAC,CAACC,MAAQA,IAAIC,UAAU,CAAC,kBACxCN,WAAWI,IAAI,CAAC,CAACC,MAAQA,IAAIC,UAAU,CAAC;IAE1C,mDAAmD;IACnD,IAAI,CAACP,WAAW;QACd;IACF;IAEA,uCAAuC;IACvC,MAAMQ,SAAQR,kCAAAA,UACXE,KAAK,CAAC,IACP,yEAAyE;KACxEO,KAAK,CAAC,GACNN,GAAG,CAAC,CAACO,SAAWA,OAAON,IAAI,GAC5B,kDAAkD;KACjDC,IAAI,CACH,CAACK,SACCA,OAAOH,UAAU,CAAC,cAClBG,OAAOC,MAAM,GAAG,KAChBD,OAAOE,QAAQ,CAAC,0BAVRZ,gCAaVS,KAAK,CAAC,GAAG,CAAC;IAEd,iDAAiD;IACjD,IAAI,CAACD,OAAO;QACV;IACF;IAEA,sEAAsE;IACtE,uEAAuE;IACvE,eAAe;IACf,IAAIX,aAAagB,IAAI,CAACL,QAAQ;QAC5B,MAAM,IAAIM,MACR;IAEJ;IAEA,OAAON;AACT"}

View File

@ -0,0 +1,34 @@
import { INTERCEPTION_ROUTE_MARKERS } from "../future/helpers/interception-routes";
/**
* Parse dynamic route segment to type of parameter
*/ export function getSegmentParam(segment) {
const interceptionMarker = INTERCEPTION_ROUTE_MARKERS.find((marker)=>segment.startsWith(marker));
// if an interception marker is part of the path segment, we need to jump ahead
// to the relevant portion for param parsing
if (interceptionMarker) {
segment = segment.slice(interceptionMarker.length);
}
if (segment.startsWith("[[...") && segment.endsWith("]]")) {
return {
// TODO-APP: Optional catchall does not currently work with parallel routes,
// so for now aren't handling a potential interception marker.
type: "optional-catchall",
param: segment.slice(5, -2)
};
}
if (segment.startsWith("[...") && segment.endsWith("]")) {
return {
type: interceptionMarker ? "catchall-intercepted" : "catchall",
param: segment.slice(4, -1)
};
}
if (segment.startsWith("[") && segment.endsWith("]")) {
return {
type: interceptionMarker ? "dynamic-intercepted" : "dynamic",
param: segment.slice(1, -1)
};
}
return null;
}
//# sourceMappingURL=get-segment-param.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-segment-param.tsx"],"names":["INTERCEPTION_ROUTE_MARKERS","getSegmentParam","segment","interceptionMarker","find","marker","startsWith","slice","length","endsWith","type","param"],"mappings":"AAAA,SAASA,0BAA0B,QAAQ,wCAAuC;AAGlF;;CAEC,GACD,OAAO,SAASC,gBAAgBC,OAAe;IAI7C,MAAMC,qBAAqBH,2BAA2BI,IAAI,CAAC,CAACC,SAC1DH,QAAQI,UAAU,CAACD;IAGrB,+EAA+E;IAC/E,4CAA4C;IAC5C,IAAIF,oBAAoB;QACtBD,UAAUA,QAAQK,KAAK,CAACJ,mBAAmBK,MAAM;IACnD;IAEA,IAAIN,QAAQI,UAAU,CAAC,YAAYJ,QAAQO,QAAQ,CAAC,OAAO;QACzD,OAAO;YACL,4EAA4E;YAC5E,8DAA8D;YAC9DC,MAAM;YACNC,OAAOT,QAAQK,KAAK,CAAC,GAAG,CAAC;QAC3B;IACF;IAEA,IAAIL,QAAQI,UAAU,CAAC,WAAWJ,QAAQO,QAAQ,CAAC,MAAM;QACvD,OAAO;YACLC,MAAMP,qBAAqB,yBAAyB;YACpDQ,OAAOT,QAAQK,KAAK,CAAC,GAAG,CAAC;QAC3B;IACF;IAEA,IAAIL,QAAQI,UAAU,CAAC,QAAQJ,QAAQO,QAAQ,CAAC,MAAM;QACpD,OAAO;YACLC,MAAMP,qBAAqB,wBAAwB;YACnDQ,OAAOT,QAAQK,KAAK,CAAC,GAAG,CAAC;QAC3B;IACF;IAEA,OAAO;AACT"}

View File

@ -0,0 +1,18 @@
export const dynamicParamTypes = {
catchall: "c",
"catchall-intercepted": "ci",
"optional-catchall": "oc",
dynamic: "d",
"dynamic-intercepted": "di"
};
/**
* Shorten the dynamic param in order to make it smaller when transmitted to the browser.
*/ export function getShortDynamicParamType(type) {
const short = dynamicParamTypes[type];
if (!short) {
throw new Error("Unknown dynamic param type");
}
return short;
}
//# sourceMappingURL=get-short-dynamic-param-type.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/get-short-dynamic-param-type.tsx"],"names":["dynamicParamTypes","catchall","dynamic","getShortDynamicParamType","type","short","Error"],"mappings":"AAEA,OAAO,MAAMA,oBAGT;IACFC,UAAU;IACV,wBAAwB;IACxB,qBAAqB;IACrBC,SAAS;IACT,uBAAuB;AACzB,EAAC;AAED;;CAEC,GACD,OAAO,SAASC,yBACdC,IAAuB;IAEvB,MAAMC,QAAQL,iBAAiB,CAACI,KAAK;IACrC,IAAI,CAACC,OAAO;QACV,MAAM,IAAIC,MAAM;IAClB;IACA,OAAOD;AACT"}

View File

@ -0,0 +1,9 @@
export function hasLoadingComponentInTree(tree) {
const [, parallelRoutes, { loading }] = tree;
if (loading) {
return true;
}
return Object.values(parallelRoutes).some((parallelRoute)=>hasLoadingComponentInTree(parallelRoute));
}
//# sourceMappingURL=has-loading-component-in-tree.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/has-loading-component-in-tree.tsx"],"names":["hasLoadingComponentInTree","tree","parallelRoutes","loading","Object","values","some","parallelRoute"],"mappings":"AAEA,OAAO,SAASA,0BAA0BC,IAAgB;IACxD,MAAM,GAAGC,gBAAgB,EAAEC,OAAO,EAAE,CAAC,GAAGF;IAExC,IAAIE,SAAS;QACX,OAAO;IACT;IAEA,OAAOC,OAAOC,MAAM,CAACH,gBAAgBI,IAAI,CAAC,CAACC,gBACzCP,0BAA0BO;AAE9B"}

View File

@ -0,0 +1,7 @@
/**
* Interop between "export default" and "module.exports".
*/ export function interopDefault(mod) {
return mod.default || mod;
}
//# sourceMappingURL=interop-default.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/interop-default.ts"],"names":["interopDefault","mod","default"],"mappings":"AAAA;;CAEC,GACD,OAAO,SAASA,eAAeC,GAAQ;IACrC,OAAOA,IAAIC,OAAO,IAAID;AACxB"}

View File

@ -0,0 +1,68 @@
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React from "react";
import { isNotFoundError } from "../../client/components/not-found";
import { getURLFromRedirectError, isRedirectError, getRedirectStatusCodeFromError } from "../../client/components/redirect";
import { renderToReadableStream } from "react-dom/server.edge";
import { streamToString } from "../stream-utils/node-web-streams-helper";
import { RedirectStatusCode } from "../../client/components/redirect-status-code";
import { addPathPrefix } from "../../shared/lib/router/utils/add-path-prefix";
export function makeGetServerInsertedHTML({ polyfills, renderServerInsertedHTML, serverCapturedErrors, basePath }) {
let flushedErrorMetaTagsUntilIndex = 0;
let hasUnflushedPolyfills = polyfills.length !== 0;
return async function getServerInsertedHTML() {
// Loop through all the errors that have been captured but not yet
// flushed.
const errorMetaTags = [];
while(flushedErrorMetaTagsUntilIndex < serverCapturedErrors.length){
const error = serverCapturedErrors[flushedErrorMetaTagsUntilIndex];
flushedErrorMetaTagsUntilIndex++;
if (isNotFoundError(error)) {
errorMetaTags.push(/*#__PURE__*/ _jsx("meta", {
name: "robots",
content: "noindex"
}, error.digest), process.env.NODE_ENV === "development" ? /*#__PURE__*/ _jsx("meta", {
name: "next-error",
content: "not-found"
}, "next-error") : null);
} else if (isRedirectError(error)) {
const redirectUrl = addPathPrefix(getURLFromRedirectError(error), basePath);
const statusCode = getRedirectStatusCodeFromError(error);
const isPermanent = statusCode === RedirectStatusCode.PermanentRedirect ? true : false;
if (redirectUrl) {
errorMetaTags.push(/*#__PURE__*/ _jsx("meta", {
id: "__next-page-redirect",
httpEquiv: "refresh",
content: `${isPermanent ? 0 : 1};url=${redirectUrl}`
}, error.digest));
}
}
}
const serverInsertedHTML = renderServerInsertedHTML();
// Skip React rendering if we know the content is empty.
if (!hasUnflushedPolyfills && errorMetaTags.length === 0 && Array.isArray(serverInsertedHTML) && serverInsertedHTML.length === 0) {
return "";
}
const stream = await renderToReadableStream(/*#__PURE__*/ _jsxs(_Fragment, {
children: [
/* Insert the polyfills if they haven't been flushed yet. */ hasUnflushedPolyfills && polyfills.map((polyfill)=>{
return /*#__PURE__*/ _jsx("script", {
...polyfill
}, polyfill.src);
}),
serverInsertedHTML,
errorMetaTags
]
}), {
// Larger chunk because this isn't sent over the network.
// Let's set it to 1MB.
progressiveChunkSize: 1024 * 1024
});
hasUnflushedPolyfills = false;
// There's no need to wait for the stream to be ready
// e.g. calling `await stream.allReady` because `streamToString` will
// wait and decode the stream progressively with better parallelism.
return streamToString(stream);
};
}
//# sourceMappingURL=make-get-server-inserted-html.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/make-get-server-inserted-html.tsx"],"names":["React","isNotFoundError","getURLFromRedirectError","isRedirectError","getRedirectStatusCodeFromError","renderToReadableStream","streamToString","RedirectStatusCode","addPathPrefix","makeGetServerInsertedHTML","polyfills","renderServerInsertedHTML","serverCapturedErrors","basePath","flushedErrorMetaTagsUntilIndex","hasUnflushedPolyfills","length","getServerInsertedHTML","errorMetaTags","error","push","meta","name","content","digest","process","env","NODE_ENV","redirectUrl","statusCode","isPermanent","PermanentRedirect","id","httpEquiv","serverInsertedHTML","Array","isArray","stream","map","polyfill","script","src","progressiveChunkSize"],"mappings":";AAAA,OAAOA,WAAW,QAAO;AACzB,SAASC,eAAe,QAAQ,oCAAmC;AACnE,SACEC,uBAAuB,EACvBC,eAAe,EACfC,8BAA8B,QACzB,mCAAkC;AACzC,SAASC,sBAAsB,QAAQ,wBAAuB;AAC9D,SAASC,cAAc,QAAQ,0CAAyC;AACxE,SAASC,kBAAkB,QAAQ,+CAA8C;AACjF,SAASC,aAAa,QAAQ,gDAA+C;AAE7E,OAAO,SAASC,0BAA0B,EACxCC,SAAS,EACTC,wBAAwB,EACxBC,oBAAoB,EACpBC,QAAQ,EAMT;IACC,IAAIC,iCAAiC;IACrC,IAAIC,wBAAwBL,UAAUM,MAAM,KAAK;IAEjD,OAAO,eAAeC;QACpB,kEAAkE;QAClE,WAAW;QACX,MAAMC,gBAAgB,EAAE;QACxB,MAAOJ,iCAAiCF,qBAAqBI,MAAM,CAAE;YACnE,MAAMG,QAAQP,oBAAoB,CAACE,+BAA+B;YAClEA;YAEA,IAAIb,gBAAgBkB,QAAQ;gBAC1BD,cAAcE,IAAI,eAChB,KAACC;oBAAKC,MAAK;oBAASC,SAAQ;mBAAeJ,MAAMK,MAAM,GACvDC,QAAQC,GAAG,CAACC,QAAQ,KAAK,8BACvB,KAACN;oBAAKC,MAAK;oBAAaC,SAAQ;mBAAgB,gBAC9C;YAER,OAAO,IAAIpB,gBAAgBgB,QAAQ;gBACjC,MAAMS,cAAcpB,cAClBN,wBAAwBiB,QACxBN;gBAEF,MAAMgB,aAAazB,+BAA+Be;gBAClD,MAAMW,cACJD,eAAetB,mBAAmBwB,iBAAiB,GAAG,OAAO;gBAC/D,IAAIH,aAAa;oBACfV,cAAcE,IAAI,eAChB,KAACC;wBACCW,IAAG;wBACHC,WAAU;wBACVV,SAAS,CAAC,EAAEO,cAAc,IAAI,EAAE,KAAK,EAAEF,YAAY,CAAC;uBAC/CT,MAAMK,MAAM;gBAGvB;YACF;QACF;QAEA,MAAMU,qBAAqBvB;QAE3B,wDAAwD;QACxD,IACE,CAACI,yBACDG,cAAcF,MAAM,KAAK,KACzBmB,MAAMC,OAAO,CAACF,uBACdA,mBAAmBlB,MAAM,KAAK,GAC9B;YACA,OAAO;QACT;QAEA,MAAMqB,SAAS,MAAMhC,qCACnB;;gBAEI,0DAA0D,GAC1DU,yBACEL,UAAU4B,GAAG,CAAC,CAACC;oBACb,qBAAO,KAACC;wBAA2B,GAAGD,QAAQ;uBAA1BA,SAASE,GAAG;gBAClC;gBAEHP;gBACAhB;;YAEH;YACE,yDAAyD;YACzD,uBAAuB;YACvBwB,sBAAsB,OAAO;QAC/B;QAGF3B,wBAAwB;QAExB,qDAAqD;QACrD,qEAAqE;QACrE,oEAAoE;QACpE,OAAOT,eAAe+B;IACxB;AACF"}

View File

@ -0,0 +1,27 @@
import { flightRouterStateSchema } from "./types";
import { assert } from "next/dist/compiled/superstruct";
export function parseAndValidateFlightRouterState(stateHeader) {
if (typeof stateHeader === "undefined") {
return undefined;
}
if (Array.isArray(stateHeader)) {
throw new Error("Multiple router state headers were sent. This is not allowed.");
}
// We limit the size of the router state header to ~40kb. This is to prevent
// a malicious user from sending a very large header and slowing down the
// resolving of the router state.
// This is around 2,000 nested or parallel route segment states:
// '{"children":["",{}]}'.length === 20.
if (stateHeader.length > 20 * 2000) {
throw new Error("The router state header was too large.");
}
try {
const state = JSON.parse(decodeURIComponent(stateHeader));
assert(state, flightRouterStateSchema);
return state;
} catch {
throw new Error("The router state header was sent but could not be parsed.");
}
}
//# sourceMappingURL=parse-and-validate-flight-router-state.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/parse-and-validate-flight-router-state.tsx"],"names":["flightRouterStateSchema","assert","parseAndValidateFlightRouterState","stateHeader","undefined","Array","isArray","Error","length","state","JSON","parse","decodeURIComponent"],"mappings":"AACA,SAASA,uBAAuB,QAAQ,UAAS;AACjD,SAASC,MAAM,QAAQ,iCAAgC;AAEvD,OAAO,SAASC,kCACdC,WAA0C;IAE1C,IAAI,OAAOA,gBAAgB,aAAa;QACtC,OAAOC;IACT;IACA,IAAIC,MAAMC,OAAO,CAACH,cAAc;QAC9B,MAAM,IAAII,MACR;IAEJ;IAEA,4EAA4E;IAC5E,yEAAyE;IACzE,iCAAiC;IACjC,gEAAgE;IAChE,wCAAwC;IACxC,IAAIJ,YAAYK,MAAM,GAAG,KAAK,MAAM;QAClC,MAAM,IAAID,MAAM;IAClB;IAEA,IAAI;QACF,MAAME,QAAQC,KAAKC,KAAK,CAACC,mBAAmBT;QAC5CF,OAAOQ,OAAOT;QACd,OAAOS;IACT,EAAE,OAAM;QACN,MAAM,IAAIF,MAAM;IAClB;AACF"}

View File

@ -0,0 +1,19 @@
import { DEFAULT_SEGMENT_KEY } from "../../shared/lib/segment";
export function parseLoaderTree(tree) {
const [segment, parallelRoutes, components] = tree;
const { layout } = components;
let { page } = components;
// a __DEFAULT__ segment means that this route didn't match any of the
// segments in the route, so we should use the default page
page = segment === DEFAULT_SEGMENT_KEY ? components.defaultPage : page;
const layoutOrPagePath = (layout == null ? void 0 : layout[1]) || (page == null ? void 0 : page[1]);
return {
page,
segment,
components,
layoutOrPagePath,
parallelRoutes
};
}
//# sourceMappingURL=parse-loader-tree.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/parse-loader-tree.ts"],"names":["DEFAULT_SEGMENT_KEY","parseLoaderTree","tree","segment","parallelRoutes","components","layout","page","defaultPage","layoutOrPagePath"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,2BAA0B;AAG9D,OAAO,SAASC,gBAAgBC,IAAgB;IAC9C,MAAM,CAACC,SAASC,gBAAgBC,WAAW,GAAGH;IAC9C,MAAM,EAAEI,MAAM,EAAE,GAAGD;IACnB,IAAI,EAAEE,IAAI,EAAE,GAAGF;IACf,sEAAsE;IACtE,2DAA2D;IAC3DE,OAAOJ,YAAYH,sBAAsBK,WAAWG,WAAW,GAAGD;IAElE,MAAME,mBAAmBH,CAAAA,0BAAAA,MAAQ,CAAC,EAAE,MAAIC,wBAAAA,IAAM,CAAC,EAAE;IAEjD,OAAO;QACLA;QACAJ;QACAE;QACAI;QACAL;IACF;AACF"}

View File

@ -0,0 +1,5 @@
// This file should be opted into the react-server layer
// eslint-disable-next-line import/no-extraneous-dependencies
export { decodeReply, decodeReplyFromBusboy, decodeAction, decodeFormState } from "react-server-dom-webpack/server.node";
//# sourceMappingURL=react-server.node.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/react-server.node.ts"],"names":["decodeReply","decodeReplyFromBusboy","decodeAction","decodeFormState"],"mappings":"AAAA,wDAAwD;AAExD,6DAA6D;AAC7D,SACEA,WAAW,EACXC,qBAAqB,EACrBC,YAAY,EACZC,eAAe,QACV,uCAAsC"}

View File

@ -0,0 +1,12 @@
import { streamToString } from "../stream-utils/node-web-streams-helper";
import { AppRenderSpan } from "../lib/trace/constants";
import { getTracer } from "../lib/trace/tracer";
export async function renderToString({ ReactDOMServer, element }) {
return getTracer().trace(AppRenderSpan.renderToString, async ()=>{
const renderStream = await ReactDOMServer.renderToReadableStream(element);
await renderStream.allReady;
return streamToString(renderStream);
});
}
//# sourceMappingURL=render-to-string.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/render-to-string.tsx"],"names":["streamToString","AppRenderSpan","getTracer","renderToString","ReactDOMServer","element","trace","renderStream","renderToReadableStream","allReady"],"mappings":"AAAA,SAASA,cAAc,QAAQ,0CAAyC;AACxE,SAASC,aAAa,QAAQ,yBAAwB;AACtD,SAASC,SAAS,QAAQ,sBAAqB;AAE/C,OAAO,eAAeC,eAAe,EACnCC,cAAc,EACdC,OAAO,EAIR;IACC,OAAOH,YAAYI,KAAK,CAACL,cAAcE,cAAc,EAAE;QACrD,MAAMI,eAAe,MAAMH,eAAeI,sBAAsB,CAACH;QACjE,MAAME,aAAaE,QAAQ;QAC3B,OAAOT,eAAeO;IACxB;AACF"}

View File

@ -0,0 +1,56 @@
import { encodeURIPath } from "../../shared/lib/encode-uri-path";
import ReactDOM from "react-dom";
export function getRequiredScripts(buildManifest, assetPrefix, crossOrigin, SRIManifest, qs, nonce) {
let preinitScripts;
let preinitScriptCommands = [];
const bootstrapScript = {
src: "",
crossOrigin
};
const files = buildManifest.rootMainFiles.map(encodeURIPath);
if (files.length === 0) {
throw new Error("Invariant: missing bootstrap script. This is a bug in Next.js");
}
if (SRIManifest) {
bootstrapScript.src = `${assetPrefix}/_next/` + files[0] + qs;
bootstrapScript.integrity = SRIManifest[files[0]];
for(let i = 1; i < files.length; i++){
const src = `${assetPrefix}/_next/` + files[i] + qs;
const integrity = SRIManifest[files[i]];
preinitScriptCommands.push(src, integrity);
}
preinitScripts = ()=>{
// preinitScriptCommands is a double indexed array of src/integrity pairs
for(let i = 0; i < preinitScriptCommands.length; i += 2){
ReactDOM.preinit(preinitScriptCommands[i], {
as: "script",
integrity: preinitScriptCommands[i + 1],
crossOrigin,
nonce
});
}
};
} else {
bootstrapScript.src = `${assetPrefix}/_next/` + files[0] + qs;
for(let i = 1; i < files.length; i++){
const src = `${assetPrefix}/_next/` + files[i] + qs;
preinitScriptCommands.push(src);
}
preinitScripts = ()=>{
// preinitScriptCommands is a singled indexed array of src values
for(let i = 0; i < preinitScriptCommands.length; i++){
ReactDOM.preinit(preinitScriptCommands[i], {
as: "script",
nonce,
crossOrigin
});
}
};
}
return [
preinitScripts,
bootstrapScript
];
}
//# sourceMappingURL=required-scripts.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/required-scripts.tsx"],"names":["encodeURIPath","ReactDOM","getRequiredScripts","buildManifest","assetPrefix","crossOrigin","SRIManifest","qs","nonce","preinitScripts","preinitScriptCommands","bootstrapScript","src","files","rootMainFiles","map","length","Error","integrity","i","push","preinit","as"],"mappings":"AAAA,SAASA,aAAa,QAAQ,mCAAkC;AAGhE,OAAOC,cAAc,YAAW;AAEhC,OAAO,SAASC,mBACdC,aAA4B,EAC5BC,WAAmB,EACnBC,WAA6D,EAC7DC,WAA+C,EAC/CC,EAAU,EACVC,KAAyB;IAKzB,IAAIC;IACJ,IAAIC,wBAAkC,EAAE;IACxC,MAAMC,kBAIF;QACFC,KAAK;QACLP;IACF;IAEA,MAAMQ,QAAQV,cAAcW,aAAa,CAACC,GAAG,CAACf;IAC9C,IAAIa,MAAMG,MAAM,KAAK,GAAG;QACtB,MAAM,IAAIC,MACR;IAEJ;IACA,IAAIX,aAAa;QACfK,gBAAgBC,GAAG,GAAG,CAAC,EAAER,YAAY,OAAO,CAAC,GAAGS,KAAK,CAAC,EAAE,GAAGN;QAC3DI,gBAAgBO,SAAS,GAAGZ,WAAW,CAACO,KAAK,CAAC,EAAE,CAAC;QAEjD,IAAK,IAAIM,IAAI,GAAGA,IAAIN,MAAMG,MAAM,EAAEG,IAAK;YACrC,MAAMP,MAAM,CAAC,EAAER,YAAY,OAAO,CAAC,GAAGS,KAAK,CAACM,EAAE,GAAGZ;YACjD,MAAMW,YAAYZ,WAAW,CAACO,KAAK,CAACM,EAAE,CAAC;YACvCT,sBAAsBU,IAAI,CAACR,KAAKM;QAClC;QACAT,iBAAiB;YACf,yEAAyE;YACzE,IAAK,IAAIU,IAAI,GAAGA,IAAIT,sBAAsBM,MAAM,EAAEG,KAAK,EAAG;gBACxDlB,SAASoB,OAAO,CAACX,qBAAqB,CAACS,EAAE,EAAE;oBACzCG,IAAI;oBACJJ,WAAWR,qBAAqB,CAACS,IAAI,EAAE;oBACvCd;oBACAG;gBACF;YACF;QACF;IACF,OAAO;QACLG,gBAAgBC,GAAG,GAAG,CAAC,EAAER,YAAY,OAAO,CAAC,GAAGS,KAAK,CAAC,EAAE,GAAGN;QAE3D,IAAK,IAAIY,IAAI,GAAGA,IAAIN,MAAMG,MAAM,EAAEG,IAAK;YACrC,MAAMP,MAAM,CAAC,EAAER,YAAY,OAAO,CAAC,GAAGS,KAAK,CAACM,EAAE,GAAGZ;YACjDG,sBAAsBU,IAAI,CAACR;QAC7B;QACAH,iBAAiB;YACf,iEAAiE;YACjE,IAAK,IAAIU,IAAI,GAAGA,IAAIT,sBAAsBM,MAAM,EAAEG,IAAK;gBACrDlB,SAASoB,OAAO,CAACX,qBAAqB,CAACS,EAAE,EAAE;oBACzCG,IAAI;oBACJd;oBACAH;gBACF;YACF;QACF;IACF;IAEA,OAAO;QAACI;QAAgBE;KAAgB;AAC1C"}

View File

@ -0,0 +1,8 @@
/*
Files in the rsc directory are meant to be packaged as part of the RSC graph using next-app-loader.
*/ // When postpone is available in canary React we can switch to importing it directly
export { Postpone } from "../dynamic-rendering";
//# sourceMappingURL=postpone.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/rsc/postpone.ts"],"names":["Postpone"],"mappings":"AAAA;;;;AAIA,GAEA,oFAAoF;AACpF,SAASA,QAAQ,QAAQ,uBAAsB"}

View File

@ -0,0 +1,31 @@
/*
Files in the rsc directory are meant to be packaged as part of the RSC graph using next-app-loader.
*/ import ReactDOM from "react-dom";
export function preloadStyle(href, crossOrigin) {
const opts = {
as: "style"
};
if (typeof crossOrigin === "string") {
opts.crossOrigin = crossOrigin;
}
ReactDOM.preload(href, opts);
}
export function preloadFont(href, type, crossOrigin) {
const opts = {
as: "font",
type
};
if (typeof crossOrigin === "string") {
opts.crossOrigin = crossOrigin;
}
ReactDOM.preload(href, opts);
}
export function preconnect(href, crossOrigin) {
ReactDOM.preconnect(href, typeof crossOrigin === "string" ? {
crossOrigin
} : undefined);
}
//# sourceMappingURL=preloads.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/rsc/preloads.ts"],"names":["ReactDOM","preloadStyle","href","crossOrigin","opts","as","preload","preloadFont","type","preconnect","undefined"],"mappings":"AAAA;;;;AAIA,GAEA,OAAOA,cAAc,YAAW;AAEhC,OAAO,SAASC,aAAaC,IAAY,EAAEC,WAAgC;IACzE,MAAMC,OAAY;QAAEC,IAAI;IAAQ;IAChC,IAAI,OAAOF,gBAAgB,UAAU;QACnCC,KAAKD,WAAW,GAAGA;IACrB;IACAH,SAASM,OAAO,CAACJ,MAAME;AACzB;AAEA,OAAO,SAASG,YACdL,IAAY,EACZM,IAAY,EACZL,WAAgC;IAEhC,MAAMC,OAAY;QAAEC,IAAI;QAAQG;IAAK;IACrC,IAAI,OAAOL,gBAAgB,UAAU;QACnCC,KAAKD,WAAW,GAAGA;IACrB;IACAH,SAASM,OAAO,CAACJ,MAAME;AACzB;AAEA,OAAO,SAASK,WAAWP,IAAY,EAAEC,WAAgC;IACrEH,SAAiBS,UAAU,CAC3BP,MACA,OAAOC,gBAAgB,WAAW;QAAEA;IAAY,IAAIO;AAExD"}

View File

@ -0,0 +1,12 @@
/*
Files in the rsc directory are meant to be packaged as part of the RSC graph using next-app-loader.
*/ import * as React from "react";
function notImplemented() {
throw new Error("Taint can only be used with the taint flag.");
}
export const taintObjectReference = process.env.__NEXT_EXPERIMENTAL_REACT ? React.experimental_taintObjectReference : notImplemented;
export const taintUniqueValue = process.env.__NEXT_EXPERIMENTAL_REACT ? React.experimental_taintUniqueValue : notImplemented;
//# sourceMappingURL=taint.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/rsc/taint.ts"],"names":["React","notImplemented","Error","taintObjectReference","process","env","__NEXT_EXPERIMENTAL_REACT","experimental_taintObjectReference","taintUniqueValue","experimental_taintUniqueValue"],"mappings":"AAAA;;;;AAIA,GAEA,YAAYA,WAAW,QAAO;AAK9B,SAASC;IACP,MAAM,IAAIC,MAAM;AAClB;AAEA,OAAO,MAAMC,uBAGDC,QAAQC,GAAG,CAACC,yBAAyB,GAE7CN,MAAMO,iCAAiC,GACvCN,eAAc;AAClB,OAAO,MAAMO,mBAIDJ,QAAQC,GAAG,CAACC,yBAAyB,GAE7CN,MAAMS,6BAA6B,GACnCR,eAAc"}

View File

@ -0,0 +1,26 @@
// Provider for the `useServerInsertedHTML` API to register callbacks to insert
// elements into the HTML stream.
import { jsx as _jsx } from "react/jsx-runtime";
import React from "react";
import { ServerInsertedHTMLContext } from "../../shared/lib/server-inserted-html.shared-runtime";
export function createServerInsertedHTML() {
const serverInsertedHTMLCallbacks = [];
const addInsertedHtml = (handler)=>{
serverInsertedHTMLCallbacks.push(handler);
};
return {
ServerInsertedHTMLProvider ({ children }) {
return /*#__PURE__*/ _jsx(ServerInsertedHTMLContext.Provider, {
value: addInsertedHtml,
children: children
});
},
renderServerInsertedHTML () {
return serverInsertedHTMLCallbacks.map((callback, index)=>/*#__PURE__*/ _jsx(React.Fragment, {
children: callback()
}, "__next_server_inserted__" + index));
}
};
}
//# sourceMappingURL=server-inserted-html.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/server-inserted-html.tsx"],"names":["React","ServerInsertedHTMLContext","createServerInsertedHTML","serverInsertedHTMLCallbacks","addInsertedHtml","handler","push","ServerInsertedHTMLProvider","children","Provider","value","renderServerInsertedHTML","map","callback","index","Fragment"],"mappings":"AAAA,+EAA+E;AAC/E,iCAAiC;;AAEjC,OAAOA,WAAW,QAAO;AACzB,SAASC,yBAAyB,QAAQ,uDAAsD;AAEhG,OAAO,SAASC;IACd,MAAMC,8BAAyD,EAAE;IACjE,MAAMC,kBAAkB,CAACC;QACvBF,4BAA4BG,IAAI,CAACD;IACnC;IAEA,OAAO;QACLE,4BAA2B,EAAEC,QAAQ,EAA6B;YAChE,qBACE,KAACP,0BAA0BQ,QAAQ;gBAACC,OAAON;0BACxCI;;QAGP;QACAG;YACE,OAAOR,4BAA4BS,GAAG,CAAC,CAACC,UAAUC,sBAChD,KAACd,MAAMe,QAAQ;8BACZF;mBADkB,6BAA6BC;QAItD;IACF;AACF"}

View File

@ -0,0 +1,123 @@
class StaticRenderer {
constructor(options){
this.options = options;
this.prerender = process.env.__NEXT_EXPERIMENTAL_REACT ? require("react-dom/static.edge").prerender : null;
}
async render(children) {
const { prelude, postponed } = await this.prerender(children, this.options);
return {
stream: prelude,
postponed
};
}
}
class StaticResumeRenderer {
constructor(postponed, options){
this.postponed = postponed;
this.options = options;
this.resume = require("react-dom/server.edge").resume;
}
async render(children) {
const stream = await this.resume(children, this.postponed, this.options);
return {
stream,
resumed: true
};
}
}
export class ServerRenderer {
constructor(options){
this.options = options;
this.renderToReadableStream = require("react-dom/server.edge").renderToReadableStream;
}
async render(children) {
const stream = await this.renderToReadableStream(children, this.options);
return {
stream
};
}
}
export class VoidRenderer {
async render(_children) {
return {
stream: new ReadableStream({
start (controller) {
// Close the stream immediately
controller.close();
}
}),
resumed: false
};
}
}
export const DYNAMIC_DATA = 1;
export const DYNAMIC_HTML = 2;
export function getDynamicHTMLPostponedState(data) {
return [
DYNAMIC_HTML,
data
];
}
export function getDynamicDataPostponedState() {
return DYNAMIC_DATA;
}
export function createStaticRenderer({ ppr, isStaticGeneration, postponed, streamOptions: { signal, onError, onPostpone, onHeaders, maxHeadersLength, nonce, bootstrapScripts, formState } }) {
if (ppr) {
if (isStaticGeneration) {
// This is a Prerender
return new StaticRenderer({
signal,
onError,
onPostpone,
// We want to capture headers because we may not end up with a shell
// and being able to send headers is the next best thing
onHeaders,
maxHeadersLength,
bootstrapScripts
});
} else {
// This is a Resume
if (postponed === DYNAMIC_DATA) {
// The HTML was complete, we don't actually need to render anything
return new VoidRenderer();
} else if (postponed) {
const reactPostponedState = postponed[1];
// The HTML had dynamic holes and we need to resume it
return new StaticResumeRenderer(reactPostponedState, {
signal,
onError,
onPostpone,
nonce
});
}
}
}
if (isStaticGeneration) {
// This is a static render (without PPR)
return new ServerRenderer({
signal,
onError,
// We don't pass onHeaders. In static builds we will either have no output
// or the entire page. In either case preload headers aren't necessary and could
// alter the prioritiy of relative loading of resources so we opt to keep them
// as tags exclusively.
nonce,
bootstrapScripts,
formState
});
}
// This is a dynamic render (without PPR)
return new ServerRenderer({
signal,
onError,
// Static renders are streamed in realtime so sending headers early is
// generally good because it will likely go out before the shell is ready.
onHeaders,
maxHeadersLength,
nonce,
bootstrapScripts,
formState
});
}
//# sourceMappingURL=static-renderer.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/static/static-renderer.ts"],"names":["StaticRenderer","constructor","options","prerender","process","env","__NEXT_EXPERIMENTAL_REACT","require","render","children","prelude","postponed","stream","StaticResumeRenderer","resume","resumed","ServerRenderer","renderToReadableStream","VoidRenderer","_children","ReadableStream","start","controller","close","DYNAMIC_DATA","DYNAMIC_HTML","getDynamicHTMLPostponedState","data","getDynamicDataPostponedState","createStaticRenderer","ppr","isStaticGeneration","streamOptions","signal","onError","onPostpone","onHeaders","maxHeadersLength","nonce","bootstrapScripts","formState","reactPostponedState"],"mappings":"AAgBA,MAAMA;IAMJC,YAAY,AAAiBC,OAAyB,CAAE;aAA3BA,UAAAA;aAJZC,YAAaC,QAAQC,GAAG,CAACC,yBAAyB,GAC/DC,QAAQ,yBAAyBJ,SAAS,GAC1C;IAEqD;IAEzD,MAAaK,OAAOC,QAAqB,EAAE;QACzC,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAE,GAAG,MAAM,IAAI,CAACR,SAAS,CAACM,UAAU,IAAI,CAACP,OAAO;QAE1E,OAAO;YAAEU,QAAQF;YAASC;QAAU;IACtC;AACF;AAEA,MAAME;IAIJZ,YACE,AAAiBU,SAAiB,EAClC,AAAiBT,OAAsB,CACvC;aAFiBS,YAAAA;aACAT,UAAAA;aALFY,SAASP,QAAQ,yBAC/BO,MAAM;IAKN;IAEH,MAAaN,OAAOC,QAAqB,EAAE;QACzC,MAAMG,SAAS,MAAM,IAAI,CAACE,MAAM,CAACL,UAAU,IAAI,CAACE,SAAS,EAAE,IAAI,CAACT,OAAO;QAEvE,OAAO;YAAEU;YAAQG,SAAS;QAAK;IACjC;AACF;AAEA,OAAO,MAAMC;IAIXf,YAAY,AAAiBC,OAAsC,CAAE;aAAxCA,UAAAA;aAHZe,yBAAyBV,QAAQ,yBAC/CU,sBAAsB;IAE6C;IAEtE,MAAaT,OAAOC,QAAqB,EAAyB;QAChE,MAAMG,SAAS,MAAM,IAAI,CAACK,sBAAsB,CAACR,UAAU,IAAI,CAACP,OAAO;QACvE,OAAO;YAAEU;QAAO;IAClB;AACF;AAEA,OAAO,MAAMM;IACX,MAAaV,OAAOW,SAAsB,EAAyB;QACjE,OAAO;YACLP,QAAQ,IAAIQ,eAAe;gBACzBC,OAAMC,UAAU;oBACd,+BAA+B;oBAC/BA,WAAWC,KAAK;gBAClB;YACF;YACAR,SAAS;QACX;IACF;AACF;AAqBA,OAAO,MAAMS,eAAe,EAAU;AACtC,OAAO,MAAMC,eAAe,EAAU;AAQtC,OAAO,SAASC,6BACdC,IAAY;IAEZ,OAAO;QAACF;QAAcE;KAAK;AAC7B;AAEA,OAAO,SAASC;IACd,OAAOJ;AACT;AA8BA,OAAO,SAASK,qBAAqB,EACnCC,GAAG,EACHC,kBAAkB,EAClBpB,SAAS,EACTqB,eAAe,EACbC,MAAM,EACNC,OAAO,EACPC,UAAU,EACVC,SAAS,EACTC,gBAAgB,EAChBC,KAAK,EACLC,gBAAgB,EAChBC,SAAS,EACV,EACO;IACR,IAAIV,KAAK;QACP,IAAIC,oBAAoB;YACtB,sBAAsB;YACtB,OAAO,IAAI/B,eAAe;gBACxBiC;gBACAC;gBACAC;gBACA,oEAAoE;gBACpE,wDAAwD;gBACxDC;gBACAC;gBACAE;YACF;QACF,OAAO;YACL,mBAAmB;YACnB,IAAI5B,cAAca,cAAc;gBAC9B,mEAAmE;gBACnE,OAAO,IAAIN;YACb,OAAO,IAAIP,WAAW;gBACpB,MAAM8B,sBAAsB9B,SAAS,CAAC,EAAE;gBACxC,sDAAsD;gBACtD,OAAO,IAAIE,qBAAqB4B,qBAAqB;oBACnDR;oBACAC;oBACAC;oBACAG;gBACF;YACF;QACF;IACF;IAEA,IAAIP,oBAAoB;QACtB,wCAAwC;QACxC,OAAO,IAAIf,eAAe;YACxBiB;YACAC;YACA,0EAA0E;YAC1E,gFAAgF;YAChF,8EAA8E;YAC9E,uBAAuB;YACvBI;YACAC;YACAC;QACF;IACF;IAEA,yCAAyC;IACzC,OAAO,IAAIxB,eAAe;QACxBiB;QACAC;QACA,sEAAsE;QACtE,0EAA0E;QAC1EE;QACAC;QACAC;QACAC;QACAC;IACF;AACF"}

View File

@ -0,0 +1,12 @@
import { FLIGHT_PARAMETERS } from "../../client/components/app-router-headers";
/**
* Removes the flight headers from the request.
*
* @param req the request to strip the headers from
*/ export function stripFlightHeaders(headers) {
for (const [header] of FLIGHT_PARAMETERS){
delete headers[header.toLowerCase()];
}
}
//# sourceMappingURL=strip-flight-headers.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/strip-flight-headers.ts"],"names":["FLIGHT_PARAMETERS","stripFlightHeaders","headers","header","toLowerCase"],"mappings":"AAEA,SAASA,iBAAiB,QAAQ,6CAA4C;AAE9E;;;;CAIC,GACD,OAAO,SAASC,mBAAmBC,OAA4B;IAC7D,KAAK,MAAM,CAACC,OAAO,IAAIH,kBAAmB;QACxC,OAAOE,OAAO,CAACC,OAAOC,WAAW,GAAG;IACtC;AACF"}

31
node_modules/next/dist/esm/server/app-render/types.js generated vendored Normal file
View File

@ -0,0 +1,31 @@
import s from "next/dist/compiled/superstruct";
const dynamicParamTypesSchema = s.enums([
"c",
"ci",
"oc",
"d",
"di"
]);
const segmentSchema = s.union([
s.string(),
s.tuple([
s.string(),
s.string(),
dynamicParamTypesSchema
])
]);
// unfortunately the tuple is not understood well by Describe so we have to
// use any here. This does not have any impact on the runtime type since the validation
// does work correctly.
export const flightRouterStateSchema = s.tuple([
segmentSchema,
s.record(s.string(), s.lazy(()=>flightRouterStateSchema)),
s.optional(s.nullable(s.string())),
s.optional(s.nullable(s.union([
s.literal("refetch"),
s.literal("refresh")
]))),
s.optional(s.boolean())
]);
//# sourceMappingURL=types.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/types.ts"],"names":["s","dynamicParamTypesSchema","enums","segmentSchema","union","string","tuple","flightRouterStateSchema","record","lazy","optional","nullable","literal","boolean"],"mappings":"AAWA,OAAOA,OAAO,iCAAgC;AAS9C,MAAMC,0BAA0BD,EAAEE,KAAK,CAAC;IAAC;IAAK;IAAM;IAAM;IAAK;CAAK;AAIpE,MAAMC,gBAAgBH,EAAEI,KAAK,CAAC;IAC5BJ,EAAEK,MAAM;IACRL,EAAEM,KAAK,CAAC;QAACN,EAAEK,MAAM;QAAIL,EAAEK,MAAM;QAAIJ;KAAwB;CAC1D;AAID,2EAA2E;AAC3E,uFAAuF;AACvF,uBAAuB;AACvB,OAAO,MAAMM,0BAA2CP,EAAEM,KAAK,CAAC;IAC9DH;IACAH,EAAEQ,MAAM,CACNR,EAAEK,MAAM,IACRL,EAAES,IAAI,CAAC,IAAMF;IAEfP,EAAEU,QAAQ,CAACV,EAAEW,QAAQ,CAACX,EAAEK,MAAM;IAC9BL,EAAEU,QAAQ,CAACV,EAAEW,QAAQ,CAACX,EAAEI,KAAK,CAAC;QAACJ,EAAEY,OAAO,CAAC;QAAYZ,EAAEY,OAAO,CAAC;KAAW;IAC1EZ,EAAEU,QAAQ,CAACV,EAAEa,OAAO;CACrB,EAAC"}

View File

@ -0,0 +1,119 @@
import { htmlEscapeJsonString } from "../htmlescape";
const isEdgeRuntime = process.env.NEXT_RUNTIME === "edge";
const INLINE_FLIGHT_PAYLOAD_BOOTSTRAP = 0;
const INLINE_FLIGHT_PAYLOAD_DATA = 1;
const INLINE_FLIGHT_PAYLOAD_FORM_STATE = 2;
const flightResponses = new WeakMap();
const encoder = new TextEncoder();
/**
* Render Flight stream.
* This is only used for renderToHTML, the Flight response does not need additional wrappers.
*/ export function useFlightStream(flightStream, clientReferenceManifest, nonce) {
const response = flightResponses.get(flightStream);
if (response) {
return response;
}
// react-server-dom-webpack/client.edge must not be hoisted for require cache clearing to work correctly
let createFromReadableStream;
// @TODO: investigate why the aliasing for turbopack doesn't pick this up, requiring this runtime check
if (process.env.TURBOPACK) {
createFromReadableStream = // eslint-disable-next-line import/no-extraneous-dependencies
require("react-server-dom-turbopack/client.edge").createFromReadableStream;
} else {
createFromReadableStream = // eslint-disable-next-line import/no-extraneous-dependencies
require("react-server-dom-webpack/client.edge").createFromReadableStream;
}
const newResponse = createFromReadableStream(flightStream, {
ssrManifest: {
moduleLoading: clientReferenceManifest.moduleLoading,
moduleMap: isEdgeRuntime ? clientReferenceManifest.edgeSSRModuleMapping : clientReferenceManifest.ssrModuleMapping
},
nonce
});
flightResponses.set(flightStream, newResponse);
return newResponse;
}
/**
* There are times when an SSR render may be finished but the RSC render
* is ongoing and we need to wait for it to complete to make some determination
* about how to handle the render. This function will drain the RSC reader and
* resolve when completed. This will generally require teeing the RSC stream and it
* should be noted that it will cause all the RSC chunks to queue in the underlying
* ReadableStream however given Flight currently is a push stream that doesn't respond
* to backpressure this shouldn't change how much memory is maximally consumed
*/ export async function flightRenderComplete(flightStream) {
const flightReader = flightStream.getReader();
while(true){
const { done } = await flightReader.read();
if (done) {
return;
}
}
}
/**
* Creates a ReadableStream provides inline script tag chunks for writing hydration
* data to the client outside the React render itself.
*
* @param flightStream The RSC render stream
* @param nonce optionally a nonce used during this particular render
* @param formState optionally the formState used with this particular render
* @returns a ReadableStream without the complete property. This signifies a lazy ReadableStream
*/ export function createInlinedDataReadableStream(flightStream, nonce, formState) {
const startScriptTag = nonce ? `<script nonce=${JSON.stringify(nonce)}>` : "<script>";
const decoder = new TextDecoder("utf-8", {
fatal: true
});
const decoderOptions = {
stream: true
};
const flightReader = flightStream.getReader();
const readable = new ReadableStream({
type: "bytes",
start (controller) {
try {
writeInitialInstructions(controller, startScriptTag, formState);
} catch (error) {
// during encoding or enqueueing forward the error downstream
controller.error(error);
}
},
async pull (controller) {
try {
const { done, value } = await flightReader.read();
if (done) {
const tail = decoder.decode(value, {
stream: false
});
if (tail.length) {
writeFlightDataInstruction(controller, startScriptTag, tail);
}
controller.close();
} else {
const chunkAsString = decoder.decode(value, decoderOptions);
writeFlightDataInstruction(controller, startScriptTag, chunkAsString);
}
} catch (error) {
// There was a problem in the upstream reader or during decoding or enqueuing
// forward the error downstream
controller.error(error);
}
}
});
return readable;
}
function writeInitialInstructions(controller, scriptStart, formState) {
controller.enqueue(encoder.encode(`${scriptStart}(self.__next_f=self.__next_f||[]).push(${htmlEscapeJsonString(JSON.stringify([
INLINE_FLIGHT_PAYLOAD_BOOTSTRAP
]))});self.__next_f.push(${htmlEscapeJsonString(JSON.stringify([
INLINE_FLIGHT_PAYLOAD_FORM_STATE,
formState
]))})</script>`));
}
function writeFlightDataInstruction(controller, scriptStart, chunkAsString) {
controller.enqueue(encoder.encode(`${scriptStart}self.__next_f.push(${htmlEscapeJsonString(JSON.stringify([
INLINE_FLIGHT_PAYLOAD_DATA,
chunkAsString
]))})</script>`));
}
//# sourceMappingURL=use-flight-response.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/use-flight-response.tsx"],"names":["htmlEscapeJsonString","isEdgeRuntime","process","env","NEXT_RUNTIME","INLINE_FLIGHT_PAYLOAD_BOOTSTRAP","INLINE_FLIGHT_PAYLOAD_DATA","INLINE_FLIGHT_PAYLOAD_FORM_STATE","flightResponses","WeakMap","encoder","TextEncoder","useFlightStream","flightStream","clientReferenceManifest","nonce","response","get","createFromReadableStream","TURBOPACK","require","newResponse","ssrManifest","moduleLoading","moduleMap","edgeSSRModuleMapping","ssrModuleMapping","set","flightRenderComplete","flightReader","getReader","done","read","createInlinedDataReadableStream","formState","startScriptTag","JSON","stringify","decoder","TextDecoder","fatal","decoderOptions","stream","readable","ReadableStream","type","start","controller","writeInitialInstructions","error","pull","value","tail","decode","length","writeFlightDataInstruction","close","chunkAsString","scriptStart","enqueue","encode"],"mappings":"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"}

View File

@ -0,0 +1,19 @@
const DUMMY_ORIGIN = "http://n";
const INVALID_URL_MESSAGE = "Invalid request URL";
export function validateURL(url) {
if (!url) {
throw new Error(INVALID_URL_MESSAGE);
}
try {
const parsed = new URL(url, DUMMY_ORIGIN);
// Avoid origin change by extra slashes in pathname
if (parsed.origin !== DUMMY_ORIGIN) {
throw new Error(INVALID_URL_MESSAGE);
}
return url;
} catch {
throw new Error(INVALID_URL_MESSAGE);
}
}
//# sourceMappingURL=validate-url.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/validate-url.tsx"],"names":["DUMMY_ORIGIN","INVALID_URL_MESSAGE","validateURL","url","Error","parsed","URL","origin"],"mappings":"AAAA,MAAMA,eAAe;AACrB,MAAMC,sBAAsB;AAE5B,OAAO,SAASC,YAAYC,GAAuB;IACjD,IAAI,CAACA,KAAK;QACR,MAAM,IAAIC,MAAMH;IAClB;IACA,IAAI;QACF,MAAMI,SAAS,IAAIC,IAAIH,KAAKH;QAC5B,mDAAmD;QACnD,IAAIK,OAAOE,MAAM,KAAKP,cAAc;YAClC,MAAM,IAAII,MAAMH;QAClB;QACA,OAAOE;IACT,EAAE,OAAM;QACN,MAAM,IAAIC,MAAMH;IAClB;AACF"}

View File

@ -0,0 +1,140 @@
import { canSegmentBeOverridden, matchSegment } from "../../client/components/match-segments";
import { getLinkAndScriptTags } from "./get-css-inlined-link-tags";
import { getPreloadableFonts } from "./get-preloadable-fonts";
import { addSearchParamsIfPageSegment, createFlightRouterStateFromLoaderTree } from "./create-flight-router-state-from-loader-tree";
import { hasLoadingComponentInTree } from "./has-loading-component-in-tree";
import { createComponentTree } from "./create-component-tree";
import { DEFAULT_SEGMENT_KEY } from "../../shared/lib/segment";
/**
* Use router state to decide at what common layout to render the page.
* This can either be the common layout between two pages or a specific place to start rendering from using the "refetch" marker in the tree.
*/ export async function walkTreeWithFlightRouterState({ createSegmentPath, loaderTreeToFilter, parentParams, isFirst, flightRouterState, parentRendered, rscPayloadHead, injectedCSS, injectedJS, injectedFontPreloadTags, rootLayoutIncluded, asNotFound, metadataOutlet, ctx }) {
const { renderOpts: { nextFontManifest, experimental }, query, isPrefetch, getDynamicParamFromSegment, componentMod: { tree: loaderTree } } = ctx;
const [segment, parallelRoutes, components] = loaderTreeToFilter;
const parallelRoutesKeys = Object.keys(parallelRoutes);
const { layout } = components;
const isLayout = typeof layout !== "undefined";
/**
* Checks if the current segment is a root layout.
*/ const rootLayoutAtThisLevel = isLayout && !rootLayoutIncluded;
/**
* Checks if the current segment or any level above it has a root layout.
*/ const rootLayoutIncludedAtThisLevelOrAbove = rootLayoutIncluded || rootLayoutAtThisLevel;
// Because this function walks to a deeper point in the tree to start rendering we have to track the dynamic parameters up to the point where rendering starts
const segmentParam = getDynamicParamFromSegment(segment);
const currentParams = // Handle null case where dynamic param is optional
segmentParam && segmentParam.value !== null ? {
...parentParams,
[segmentParam.param]: segmentParam.value
} : parentParams;
const actualSegment = addSearchParamsIfPageSegment(segmentParam ? segmentParam.treeSegment : segment, query);
/**
* Decide if the current segment is where rendering has to start.
*/ const renderComponentsOnThisLevel = // No further router state available
!flightRouterState || // Segment in router state does not match current segment
!matchSegment(actualSegment, flightRouterState[0]) || // Last item in the tree
parallelRoutesKeys.length === 0 || // Explicit refresh
flightRouterState[3] === "refetch";
const shouldSkipComponentTree = // loading.tsx has no effect on prefetching when PPR is enabled
!experimental.ppr && isPrefetch && !Boolean(components.loading) && (flightRouterState || // If there is no flightRouterState, we need to check the entire loader tree, as otherwise we'll be only checking the root
!hasLoadingComponentInTree(loaderTree));
if (!parentRendered && renderComponentsOnThisLevel) {
const overriddenSegment = flightRouterState && canSegmentBeOverridden(actualSegment, flightRouterState[0]) ? flightRouterState[0] : actualSegment;
const routerState = createFlightRouterStateFromLoaderTree(// Create router state using the slice of the loaderTree
loaderTreeToFilter, getDynamicParamFromSegment, query);
if (shouldSkipComponentTree) {
// Send only the router state
return [
[
overriddenSegment,
routerState,
null,
null
]
];
} else {
// Create component tree using the slice of the loaderTree
const seedData = await createComponentTree(// This ensures flightRouterPath is valid and filters down the tree
{
ctx,
createSegmentPath,
loaderTree: loaderTreeToFilter,
parentParams: currentParams,
firstItem: isFirst,
injectedCSS,
injectedJS,
injectedFontPreloadTags,
// This is intentionally not "rootLayoutIncludedAtThisLevelOrAbove" as createComponentTree starts at the current level and does a check for "rootLayoutAtThisLevel" too.
rootLayoutIncluded,
asNotFound,
metadataOutlet
});
return [
[
overriddenSegment,
routerState,
seedData,
rscPayloadHead
]
];
}
}
// If we are not rendering on this level we need to check if the current
// segment has a layout. If so, we need to track all the used CSS to make
// the result consistent.
const layoutPath = layout == null ? void 0 : layout[1];
const injectedCSSWithCurrentLayout = new Set(injectedCSS);
const injectedJSWithCurrentLayout = new Set(injectedJS);
const injectedFontPreloadTagsWithCurrentLayout = new Set(injectedFontPreloadTags);
if (layoutPath) {
getLinkAndScriptTags(ctx.clientReferenceManifest, layoutPath, injectedCSSWithCurrentLayout, injectedJSWithCurrentLayout, true);
getPreloadableFonts(nextFontManifest, layoutPath, injectedFontPreloadTagsWithCurrentLayout);
}
// Walk through all parallel routes.
const paths = (await Promise.all(parallelRoutesKeys.map(async (parallelRouteKey)=>{
// for (const parallelRouteKey of parallelRoutesKeys) {
const parallelRoute = parallelRoutes[parallelRouteKey];
const currentSegmentPath = isFirst ? [
parallelRouteKey
] : [
actualSegment,
parallelRouteKey
];
const path = await walkTreeWithFlightRouterState({
ctx,
createSegmentPath: (child)=>{
return createSegmentPath([
...currentSegmentPath,
...child
]);
},
loaderTreeToFilter: parallelRoute,
parentParams: currentParams,
flightRouterState: flightRouterState && flightRouterState[1][parallelRouteKey],
parentRendered: parentRendered || renderComponentsOnThisLevel,
isFirst: false,
rscPayloadHead,
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout,
injectedFontPreloadTags: injectedFontPreloadTagsWithCurrentLayout,
rootLayoutIncluded: rootLayoutIncludedAtThisLevelOrAbove,
asNotFound,
metadataOutlet
});
return path.map((item)=>{
// we don't need to send over default routes in the flight data
// because they are always ignored by the client, unless it's a refetch
if (item[0] === DEFAULT_SEGMENT_KEY && flightRouterState && !!flightRouterState[1][parallelRouteKey][0] && flightRouterState[1][parallelRouteKey][3] !== "refetch") {
return null;
}
return [
actualSegment,
parallelRouteKey,
...item
];
}).filter(Boolean);
}))).flat();
return paths;
}
//# sourceMappingURL=walk-tree-with-flight-router-state.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/server/app-render/walk-tree-with-flight-router-state.tsx"],"names":["canSegmentBeOverridden","matchSegment","getLinkAndScriptTags","getPreloadableFonts","addSearchParamsIfPageSegment","createFlightRouterStateFromLoaderTree","hasLoadingComponentInTree","createComponentTree","DEFAULT_SEGMENT_KEY","walkTreeWithFlightRouterState","createSegmentPath","loaderTreeToFilter","parentParams","isFirst","flightRouterState","parentRendered","rscPayloadHead","injectedCSS","injectedJS","injectedFontPreloadTags","rootLayoutIncluded","asNotFound","metadataOutlet","ctx","renderOpts","nextFontManifest","experimental","query","isPrefetch","getDynamicParamFromSegment","componentMod","tree","loaderTree","segment","parallelRoutes","components","parallelRoutesKeys","Object","keys","layout","isLayout","rootLayoutAtThisLevel","rootLayoutIncludedAtThisLevelOrAbove","segmentParam","currentParams","value","param","actualSegment","treeSegment","renderComponentsOnThisLevel","length","shouldSkipComponentTree","ppr","Boolean","loading","overriddenSegment","routerState","seedData","firstItem","layoutPath","injectedCSSWithCurrentLayout","Set","injectedJSWithCurrentLayout","injectedFontPreloadTagsWithCurrentLayout","clientReferenceManifest","paths","Promise","all","map","parallelRouteKey","parallelRoute","currentSegmentPath","path","child","item","filter","flat"],"mappings":"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"}