vinext 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -9
- package/dist/build/client-build-config.d.ts +10 -0
- package/dist/build/client-build-config.js +18 -2
- package/dist/build/pages-client-assets-module.d.ts +8 -0
- package/dist/build/pages-client-assets-module.js +21 -1
- package/dist/build/prerender-paths.js +5 -3
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/ssr-manifest.d.ts +2 -0
- package/dist/build/ssr-manifest.js +6 -2
- package/dist/check.js +7 -6
- package/dist/cli.js +2 -1
- package/dist/client/client-redirect-matcher.d.ts +14 -0
- package/dist/client/client-redirect-matcher.js +37 -0
- package/dist/client/client-redirects.d.ts +27 -0
- package/dist/client/client-redirects.js +28 -0
- package/dist/client/client-rewrites.d.ts +2 -1
- package/dist/client/client-rewrites.js +1 -1
- package/dist/config/config-matchers.d.ts +26 -11
- package/dist/config/config-matchers.js +78 -81
- package/dist/config/destination-params.d.ts +47 -0
- package/dist/config/destination-params.js +116 -0
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +3 -0
- package/dist/entries/app-rsc-entry.d.ts +4 -0
- package/dist/entries/app-rsc-entry.js +20 -6
- package/dist/entries/pages-client-entry.js +3 -1
- package/dist/entries/pages-server-entry.js +13 -37
- package/dist/index.d.ts +3 -1
- package/dist/index.js +134 -43
- package/dist/init-cloudflare.d.ts +9 -0
- package/dist/init-cloudflare.js +107 -31
- package/dist/init-platform.d.ts +4 -0
- package/dist/init-platform.js +27 -2
- package/dist/init.d.ts +1 -0
- package/dist/init.js +67 -3
- package/dist/plugins/ast-scope.d.ts +7 -0
- package/dist/plugins/ast-scope.js +59 -3
- package/dist/plugins/cache-flight-codec.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +9 -8
- package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +3 -4
- package/dist/plugins/middleware-server-only.d.ts +5 -4
- package/dist/plugins/middleware-server-only.js +8 -5
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
- package/dist/plugins/rsc-scan-glob-imports.js +50 -0
- package/dist/plugins/strip-server-exports.js +262 -98
- package/dist/plugins/transform-result.d.ts +9 -5
- package/dist/plugins/transitive-externals.js +1 -1
- package/dist/plugins/typeof-window.d.ts +2 -2
- package/dist/plugins/use-cache-callable.js +8 -2
- package/dist/plugins/worker-server-only-imports.d.ts +20 -0
- package/dist/plugins/worker-server-only-imports.js +31 -0
- package/dist/plugins/worker-use-server.d.ts +25 -0
- package/dist/plugins/worker-use-server.js +129 -0
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +2 -1
- package/dist/server/app-browser-action-result.d.ts +1 -1
- package/dist/server/app-browser-action-result.js +9 -2
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +17 -2
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +3 -1
- package/dist/server/app-page-dispatch.js +4 -3
- package/dist/server/app-page-ppr-runtime.js +1 -1
- package/dist/server/app-page-render-observation.js +1 -1
- package/dist/server/app-page-request.js +53 -15
- package/dist/server/app-page-route-wiring.js +2 -2
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -3
- package/dist/server/app-prerender-endpoints.js +9 -6
- package/dist/server/app-request-stage-dispatch.js +6 -2
- package/dist/server/app-request-stage-independent-entry.js +25 -5
- package/dist/server/app-response-stage-entry.js +10 -2
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +5 -2
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +45 -24
- package/dist/server/app-router-entry.js +24 -5
- package/dist/server/app-rsc-cache-busting.js +1 -1
- package/dist/server/app-rsc-errors.js +20 -16
- package/dist/server/app-rsc-handler.d.ts +7 -0
- package/dist/server/app-rsc-handler.js +85 -35
- package/dist/server/app-rsc-response-stage.js +4 -2
- package/dist/server/app-segment-config.d.ts +2 -1
- package/dist/server/app-server-action-execution.d.ts +2 -1
- package/dist/server/app-server-action-execution.js +61 -22
- package/dist/server/app-ssr-entry.js +2 -1
- package/dist/server/app-worker-stages.d.ts +5 -0
- package/dist/server/app-worker-stages.js +1 -1
- package/dist/server/cacheability-request.js +2 -2
- package/dist/server/client-build-files.d.ts +16 -0
- package/dist/server/client-build-files.js +36 -0
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/dev-server.js +38 -27
- package/dist/server/dev-stack-sourcemap.js +18 -23
- package/dist/server/document-initial-head.d.ts +0 -11
- package/dist/server/document-initial-head.js +1 -1
- package/dist/server/forwarded-middleware-context.d.ts +5 -0
- package/dist/server/forwarded-middleware-context.js +22 -0
- package/dist/server/headers.d.ts +4 -1
- package/dist/server/headers.js +4 -1
- package/dist/server/http-conditional.d.ts +11 -0
- package/dist/server/http-conditional.js +10 -1
- package/dist/server/http-error-responses.d.ts +1 -1
- package/dist/server/image-optimization.d.ts +38 -0
- package/dist/server/image-optimization.js +93 -4
- package/dist/server/isr-cache.d.ts +10 -0
- package/dist/server/isr-cache.js +41 -6
- package/dist/server/metadata-route-response.js +9 -8
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +33 -20
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +3 -1
- package/dist/server/multi-stage.d.ts +11 -0
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/pages-api-route.d.ts +3 -2
- package/dist/server/pages-api-route.js +4 -3
- package/dist/server/pages-cache-tag.d.ts +12 -0
- package/dist/server/pages-cache-tag.js +19 -0
- package/dist/server/pages-client-assets.d.ts +2 -0
- package/dist/server/pages-data-route.d.ts +10 -0
- package/dist/server/pages-data-route.js +19 -2
- package/dist/server/pages-document-asset-props.d.ts +5 -1
- package/dist/server/pages-document-asset-props.js +13 -5
- package/dist/server/pages-document-splice.d.ts +19 -0
- package/dist/server/pages-document-splice.js +55 -0
- package/dist/server/pages-i18n.d.ts +12 -1
- package/dist/server/pages-i18n.js +18 -4
- package/dist/server/pages-node-compat.d.ts +16 -5
- package/dist/server/pages-node-compat.js +20 -12
- package/dist/server/pages-page-data.d.ts +32 -24
- package/dist/server/pages-page-data.js +50 -120
- package/dist/server/pages-page-handler.d.ts +0 -6
- package/dist/server/pages-page-handler.js +188 -126
- package/dist/server/pages-page-response.d.ts +12 -6
- package/dist/server/pages-page-response.js +41 -34
- package/dist/server/pages-request-pipeline.d.ts +10 -2
- package/dist/server/pages-request-pipeline.js +37 -18
- package/dist/server/pages-request-stage-entry.d.ts +6 -0
- package/dist/server/pages-request-stage-entry.js +71 -12
- package/dist/server/pages-response-stage-entry.js +4 -0
- package/dist/server/pages-revalidate.js +1 -1
- package/dist/server/pages-router-entry.js +4 -3
- package/dist/server/prerender-manifest.d.ts +3 -3
- package/dist/server/prerender-manifest.js +4 -3
- package/dist/server/prerender-work-unit-setup.js +4 -0
- package/dist/server/prod-server.d.ts +12 -0
- package/dist/server/prod-server.js +199 -69
- package/dist/server/proper-error.d.ts +4 -0
- package/dist/server/proper-error.js +31 -0
- package/dist/server/request-pipeline.d.ts +4 -1
- package/dist/server/request-pipeline.js +3 -2
- package/dist/server/revalidation-request.d.ts +1 -0
- package/dist/server/revalidation-request.js +1 -1
- package/dist/server/rsc-stream-hints.js +31 -2
- package/dist/server/seed-cache.d.ts +1 -0
- package/dist/server/seed-cache.js +5 -4
- package/dist/server/server-reference-loader.d.ts +4 -0
- package/dist/server/server-reference-loader.js +29 -0
- package/dist/server/socket-error-backstop.d.ts +9 -1
- package/dist/server/socket-error-backstop.js +46 -17
- package/dist/server/static-file-signal.d.ts +15 -4
- package/dist/server/static-file-signal.js +46 -12
- package/dist/server/worker-image-optimization.d.ts +34 -0
- package/dist/server/worker-image-optimization.js +86 -0
- package/dist/server/worker-stages.d.ts +1 -1
- package/dist/server/worker-stages.js +2 -2
- package/dist/server/worker-utils.d.ts +8 -3
- package/dist/server/worker-utils.js +12 -7
- package/dist/shims/app-router-scroll.js +4 -1
- package/dist/shims/app-router-tree-context.d.ts +5 -0
- package/dist/shims/app-router-tree-context.js +27 -0
- package/dist/shims/cache-callable-runtime.d.ts +4 -2
- package/dist/shims/cache-callable-runtime.js +21 -12
- package/dist/shims/cache-handler.js +1 -9
- package/dist/shims/cache-runtime.d.ts +6 -1
- package/dist/shims/cache-runtime.js +2 -1
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +40 -13
- package/dist/shims/cdn-cache.d.ts +8 -0
- package/dist/shims/cdn-cache.js +17 -1
- package/dist/shims/disable-smooth-scroll.d.ts +3 -0
- package/dist/shims/disable-smooth-scroll.js +36 -0
- package/dist/shims/document-placeholders.d.ts +19 -0
- package/dist/shims/document-placeholders.js +45 -0
- package/dist/shims/document.js +21 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
- package/dist/shims/dynamic-preload-chunks.js +13 -9
- package/dist/shims/dynamic.d.ts +1 -1
- package/dist/shims/dynamic.js +60 -8
- package/dist/shims/fetch-cache-state.d.ts +66 -0
- package/dist/shims/fetch-cache-state.js +92 -0
- package/dist/shims/fetch-cache.d.ts +3 -67
- package/dist/shims/fetch-cache.js +160 -125
- package/dist/shims/head.d.ts +10 -6
- package/dist/shims/head.js +15 -13
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/work-store-scope.d.ts +5 -0
- package/dist/shims/internal/work-store-scope.js +24 -0
- package/dist/shims/navigation.js +31 -5
- package/dist/shims/request-context.d.ts +2 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/router.js +12 -20
- package/dist/shims/server.d.ts +16 -0
- package/dist/shims/server.js +24 -4
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/url-utils.d.ts +2 -0
- package/dist/shims/url-utils.js +3 -1
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/hash.d.ts +7 -0
- package/dist/utils/hash.js +11 -1
- package/dist/utils/package-name.d.ts +6 -0
- package/dist/utils/package-name.js +12 -1
- package/dist/utils/plugin-rsc-version.d.ts +4 -0
- package/dist/utils/plugin-rsc-version.js +15 -0
- package/dist/utils/prerender-output-paths.js +15 -4
- package/dist/utils/public-file-path.d.ts +10 -2
- package/dist/utils/public-file-path.js +13 -9
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.d.ts +3 -0
- package/dist/utils/react-version.js +1 -1
- package/package.json +7 -3
|
@@ -81,7 +81,7 @@ function isAppWorkerResponseStageProps(value) {
|
|
|
81
81
|
if (!value || typeof value !== "object") return false;
|
|
82
82
|
const props = value;
|
|
83
83
|
if (props.protocolVersion !== 11 || props.buildId !== null && typeof props.buildId !== "string" || !isResponseStageCacheability(props.cacheability) || props.draftModeCookie !== null && typeof props.draftModeCookie !== "string" || props.middlewareCookieOverlay !== null && typeof props.middlewareCookieOverlay !== "string" || !isCanonicalHttpOrigin(props.requestOrigin) || props.scriptNonce !== null && typeof props.scriptNonce !== "string") return false;
|
|
84
|
-
if (props.kind === "app-full-request") return typeof props.prerenderDiscovery === "boolean" && typeof props.staticFileSignalToken === "string" && STATIC_FILE_SIGNAL_TOKEN_RE.test(props.staticFileSignalToken) && (props.trustedPrerenderState === null || isTrustedPrerenderState(props.trustedPrerenderState));
|
|
84
|
+
if (props.kind === "app-full-request") return typeof props.headRequest === "boolean" && typeof props.prerenderDiscovery === "boolean" && typeof props.staticFileSignalToken === "string" && STATIC_FILE_SIGNAL_TOKEN_RE.test(props.staticFileSignalToken) && (props.trustedPrerenderState === null || isTrustedPrerenderState(props.trustedPrerenderState));
|
|
85
85
|
if (props.kind === "hybrid-pages") {
|
|
86
86
|
const hybrid = props;
|
|
87
87
|
const appRouteMatch = hybrid.appRouteMatch;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../utils/protocol-headers.js";
|
|
2
2
|
import { isVinextRscVaryField } from "./app-rsc-vary.js";
|
|
3
3
|
import { VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_ROUTE_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
|
|
4
|
-
import { isNonCacheableCacheControl } from "../shims/cdn-cache.js";
|
|
4
|
+
import { hasSharedCacheCredentials, isNonCacheableCacheControl } from "../shims/cdn-cache.js";
|
|
5
5
|
import { CACHEABILITY_REQUEST_STATE, recordConfigCdnCachePolicyHeader } from "../shims/cacheability-classification.js";
|
|
6
6
|
import { NO_STORE_CACHE_CONTROL, applyCdnResponseBuildIdentityHeaders, applyCdnResponseHeaders, hasExplicitNonCacheableResponsePolicy, isCdnResponsePolicyHeader, readCdnResponseCacheControl, readCdnResponsePolicyHeaderName } from "./cache-control.js";
|
|
7
7
|
import { cacheabilityManifestPageState, cacheabilityManifestRouteState, cacheabilityRepresentationMatchesPageRoute, cacheabilityRequestIdentity, cacheabilityRoutePathname, findCacheabilityManifestRoute, parseCacheabilityManifest, resolveCacheabilityRepresentation } from "./cacheability-manifest.js";
|
|
@@ -70,7 +70,7 @@ function readBoundManifest(raw, buildId) {
|
|
|
70
70
|
}
|
|
71
71
|
function createWorkerCacheabilityAdmissionContext(base, request, rawManifest, buildId, requiresCompletedResponseAdmission = rawManifest != null, responseVary, resolvedRoutePathname, trustedRepresentation, options) {
|
|
72
72
|
const identity = cacheabilityRequestIdentity(request, trustedRepresentation);
|
|
73
|
-
const credentialedRequest =
|
|
73
|
+
const credentialedRequest = hasSharedCacheCredentials(request.headers);
|
|
74
74
|
const routePathname = identity ? cacheabilityRoutePathname(resolvedRoutePathname ?? new URL(request.url).pathname, identity.representation) : void 0;
|
|
75
75
|
if (!rawManifest) {
|
|
76
76
|
if (!requiresCompletedResponseAdmission) return base;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/server/client-build-files.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Return the URL pathname of the client build file a request pathname names,
|
|
4
|
+
* or null. Client build files are the files the client build emits outside
|
|
5
|
+
* `_next/static` (see `collectClientBuildFiles`). Workers Static Assets serves
|
|
6
|
+
* them before the Worker unless the Worker runs first, so servers handle them
|
|
7
|
+
* before middleware and routing.
|
|
8
|
+
*
|
|
9
|
+
* `pathname` is the raw request pathname. The list holds file names and
|
|
10
|
+
* `basePath` is the configured string, so each segment is decoded exactly once
|
|
11
|
+
* before matching; a segment that decodes to a `/` names no file. The result
|
|
12
|
+
* is the file's segment-encoded pathname below `basePath`, so a server that
|
|
13
|
+
* decodes it once gets the file name back.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveClientBuildFile(pathname: string, basePath: string, clientBuildFiles: ReadonlySet<string>): string | null;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/server/client-build-files.ts
|
|
2
|
+
/**
|
|
3
|
+
* Return the URL pathname of the client build file a request pathname names,
|
|
4
|
+
* or null. Client build files are the files the client build emits outside
|
|
5
|
+
* `_next/static` (see `collectClientBuildFiles`). Workers Static Assets serves
|
|
6
|
+
* them before the Worker unless the Worker runs first, so servers handle them
|
|
7
|
+
* before middleware and routing.
|
|
8
|
+
*
|
|
9
|
+
* `pathname` is the raw request pathname. The list holds file names and
|
|
10
|
+
* `basePath` is the configured string, so each segment is decoded exactly once
|
|
11
|
+
* before matching; a segment that decodes to a `/` names no file. The result
|
|
12
|
+
* is the file's segment-encoded pathname below `basePath`, so a server that
|
|
13
|
+
* decodes it once gets the file name back.
|
|
14
|
+
*/
|
|
15
|
+
function resolveClientBuildFile(pathname, basePath, clientBuildFiles) {
|
|
16
|
+
if (clientBuildFiles.size === 0) return null;
|
|
17
|
+
let filePath = pathname;
|
|
18
|
+
if (filePath.includes("%")) {
|
|
19
|
+
let segments;
|
|
20
|
+
try {
|
|
21
|
+
segments = filePath.split("/").map(decodeURIComponent);
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
if (segments.some((segment) => segment.includes("/"))) return null;
|
|
26
|
+
filePath = segments.join("/");
|
|
27
|
+
}
|
|
28
|
+
if (basePath) {
|
|
29
|
+
if (!filePath.startsWith(`${basePath}/`)) return null;
|
|
30
|
+
filePath = filePath.slice(basePath.length);
|
|
31
|
+
}
|
|
32
|
+
if (!clientBuildFiles.has(filePath)) return null;
|
|
33
|
+
return filePath.split("/").map(encodeURIComponent).join("/");
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { resolveClientBuildFile };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isUnknownRecord } from "../utils/record.js";
|
|
2
|
-
import { fnv1a64 } from "../utils/hash.js";
|
|
3
2
|
import { parseAppElementsWireElementKey } from "./app-elements-wire-key.js";
|
|
3
|
+
import { fnv1a64 } from "../utils/hash.js";
|
|
4
4
|
import { parseArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
|
|
5
5
|
import { isNonNegativeSafeInteger } from "../utils/number.js";
|
|
6
6
|
//#region src/server/client-reuse-manifest.ts
|
|
@@ -18,7 +18,9 @@ import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
|
|
|
18
18
|
import "../shims/router-state.js";
|
|
19
19
|
import { withScriptNonce } from "../shims/script-nonce-context.js";
|
|
20
20
|
import { createInlineScriptTag, createNonceAttribute, safeJsonStringify } from "./html.js";
|
|
21
|
+
import { createDocumentPlaceholderToken, getDocumentHeadOpenMarker } from "../shims/document-placeholders.js";
|
|
21
22
|
import { applyDocumentAssetProps, extractDocumentAssetProps, markDocumentAssetPropsProtectedTags, stripDocumentAssetPropsProtectionMarkers } from "./pages-document-asset-props.js";
|
|
23
|
+
import { spliceDocumentHeadClose, spliceDocumentHeadOpen, spliceDocumentScripts, splitDocumentAtMain } from "./pages-document-splice.js";
|
|
22
24
|
import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
|
|
23
25
|
import { getScriptNonceFromNodeHeaderSources } from "./csp.js";
|
|
24
26
|
import { stripViteModuleQuery } from "../utils/path.js";
|
|
@@ -31,7 +33,7 @@ import { callDocumentGetInitialProps } from "./document-initial-head.js";
|
|
|
31
33
|
import { hasPagesGetInitialProps, loadDevAppInitialProps, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
|
|
32
34
|
import { isSerializableProps } from "./pages-serializable-props.js";
|
|
33
35
|
import { traceFindPageComponents, tracePagesData, tracePagesDocument, tracePagesDocumentStream } from "./pages-execution-tracing.js";
|
|
34
|
-
import { assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds } from "./pages-page-data.js";
|
|
36
|
+
import { assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds, resolvePagesStatusPageRenderPath } from "./pages-page-data.js";
|
|
35
37
|
import { createPagesDevModuleUrl } from "./pages-dev-module-url.js";
|
|
36
38
|
import { collectPagesDevInitialStylesheetHeadHTML } from "./pages-dev-stylesheets.js";
|
|
37
39
|
import { createPagesDevHydrationScript } from "./pages-dev-hydration.js";
|
|
@@ -142,8 +144,6 @@ function writeGsspRedirect(res, redirect, isDataReq, props, options) {
|
|
|
142
144
|
});
|
|
143
145
|
res.end(location);
|
|
144
146
|
}
|
|
145
|
-
/** Body placeholder used to split the document shell for streaming. */
|
|
146
|
-
const STREAM_BODY_MARKER = "<!--VINEXT_STREAM_BODY-->";
|
|
147
147
|
function stripDevPagesNotFoundFramingHeaders(res) {
|
|
148
148
|
res.removeHeader("Content-Length");
|
|
149
149
|
res.removeHeader("Transfer-Encoding");
|
|
@@ -171,7 +171,7 @@ function toHtmlTransformPath(url) {
|
|
|
171
171
|
* shell sooner).
|
|
172
172
|
*/
|
|
173
173
|
async function streamPageToResponseImpl(routePattern, res, element, options) {
|
|
174
|
-
const { url, server, fontHeadHTML, assetHeadHTML = "", scripts, DocumentComponent, statusCode, extraHeaders, getHeadHTML, getTailHeadHTML, enhancePageElement, scriptNonce, documentContext, setDocumentInitialHead, crossOrigin, bufferBodyBeforeHeaders = false, preserveExistingContentType = false, onDocumentBody } = options;
|
|
174
|
+
const { url, server, runner, fontHeadHTML, assetHeadHTML = "", scripts, DocumentComponent, statusCode, extraHeaders, getHeadHTML, getTailHeadHTML, enhancePageElement, scriptNonce, documentContext, setDocumentInitialHead, crossOrigin, bufferBodyBeforeHeaders = false, preserveExistingContentType = false, onDocumentBody } = options;
|
|
175
175
|
const renderDocument = async () => {
|
|
176
176
|
const documentRenderPage = await runDocumentRenderPage({
|
|
177
177
|
DocumentComponent,
|
|
@@ -211,6 +211,8 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
|
|
|
211
211
|
const ssrHeadMarkerId = randomUUID();
|
|
212
212
|
const ssrHeadStartMarker = `<!--VINEXT_SSR_HEAD_START:${ssrHeadMarkerId}-->`;
|
|
213
213
|
const ssrHeadEndMarker = `<!--VINEXT_SSR_HEAD_END:${ssrHeadMarkerId}-->`;
|
|
214
|
+
const streamBodyMarker = `<!--VINEXT_STREAM_BODY:${ssrHeadMarkerId}-->`;
|
|
215
|
+
const documentToken = createDocumentPlaceholderToken();
|
|
214
216
|
let tailHeadHTML = getTailHeadHTML?.() ?? "";
|
|
215
217
|
if (documentRenderPage.status === "rendered" && documentRenderPage.stylesHTML) {
|
|
216
218
|
if (tailHeadHTML) tailHeadHTML += "\n ";
|
|
@@ -227,29 +229,29 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
|
|
|
227
229
|
if (DocumentComponent) {
|
|
228
230
|
const docProps = documentRenderPage.status === "skipped" ? await loadUserDocumentInitialProps(DocumentComponent) : documentRenderPage.docProps;
|
|
229
231
|
const docElement = docProps ? React.createElement(DocumentComponent, docProps) : React.createElement(DocumentComponent);
|
|
230
|
-
const
|
|
232
|
+
const { withDocumentPlaceholders } = await runner.import("vinext/document-placeholders");
|
|
233
|
+
const renderedDocument = extractDocumentAssetProps(await renderToStringAsync(withDocumentPlaceholders(docElement, documentToken)), documentToken);
|
|
231
234
|
documentAssetProps = renderedDocument.props;
|
|
232
235
|
let docHtml = protectAssetTags(renderedDocument.html);
|
|
233
236
|
const generatedScripts = applyGeneratedAssetProps(scripts, renderedDocument.props, "next-script");
|
|
234
237
|
const generatedAssetHeadHTML = applyGeneratedAssetProps(assetHeadHTML, renderedDocument.props, "next-script");
|
|
235
|
-
docHtml = docHtml
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
shellTemplate = docHtml;
|
|
238
|
+
docHtml = spliceDocumentHeadClose(docHtml, documentToken, headHTML || fontHeadHTML || generatedAssetHeadHTML || tailHeadHTML ? `${ssrHeadStartMarker}${protectAssetTags(headHTML)}${ssrHeadEndMarker} ${protectAssetTags(fontHeadHTML)}\n ${generatedAssetHeadHTML}\n ${protectAssetTags(tailHeadHTML)}\n` : "");
|
|
239
|
+
docHtml = spliceDocumentScripts(docHtml, documentToken, generatedScripts);
|
|
240
|
+
const main = splitDocumentAtMain(docHtml, documentToken);
|
|
241
|
+
shellTemplate = main.prefix + streamBodyMarker + main.suffix;
|
|
240
242
|
} else {
|
|
241
243
|
const generatedScripts = applyGeneratedAssetProps(scripts, {}, "next-script");
|
|
242
244
|
const generatedAssetHeadHTML = applyGeneratedAssetProps(assetHeadHTML, {}, "next-script");
|
|
243
245
|
shellTemplate = `<!DOCTYPE html>
|
|
244
246
|
<html>
|
|
245
|
-
<head>
|
|
247
|
+
<head${getDocumentHeadOpenMarker(documentToken)}>
|
|
246
248
|
${ssrHeadStartMarker}${protectAssetTags(headHTML)}${ssrHeadEndMarker}
|
|
247
249
|
${protectAssetTags(fontHeadHTML)}
|
|
248
250
|
${generatedAssetHeadHTML}
|
|
249
251
|
${protectAssetTags(tailHeadHTML)}
|
|
250
252
|
</head>
|
|
251
253
|
<body>
|
|
252
|
-
<div id="__next">${
|
|
254
|
+
<div id="__next">${streamBodyMarker}</div>
|
|
253
255
|
${generatedScripts}
|
|
254
256
|
</body>
|
|
255
257
|
</html>`;
|
|
@@ -262,14 +264,17 @@ async function streamPageToResponseImpl(routePattern, res, element, options) {
|
|
|
262
264
|
}), protectedAssetMarker);
|
|
263
265
|
const ssrHeadStart = transformedShell.indexOf(ssrHeadStartMarker);
|
|
264
266
|
const ssrHeadEnd = transformedShell.indexOf(ssrHeadEndMarker);
|
|
267
|
+
let transformedHeadHTML = "";
|
|
265
268
|
if (ssrHeadStart !== -1 && ssrHeadEnd > ssrHeadStart) {
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
+
const ssrHeadHTML = transformedShell.slice(ssrHeadStart + ssrHeadStartMarker.length, ssrHeadEnd);
|
|
270
|
+
const moveToHeadOpen = transformedShell.includes(getDocumentHeadOpenMarker(documentToken));
|
|
271
|
+
if (moveToHeadOpen) transformedHeadHTML = ssrHeadHTML;
|
|
272
|
+
transformedShell = transformedShell.slice(0, ssrHeadStart) + (moveToHeadOpen ? "" : ssrHeadHTML) + transformedShell.slice(ssrHeadEnd + ssrHeadEndMarker.length);
|
|
269
273
|
}
|
|
270
|
-
|
|
274
|
+
transformedShell = spliceDocumentHeadOpen(transformedShell, documentToken, transformedHeadHTML);
|
|
275
|
+
const markerIdx = transformedShell.indexOf(streamBodyMarker);
|
|
271
276
|
const prefix = transformedShell.slice(0, markerIdx);
|
|
272
|
-
const suffix = transformedShell.slice(markerIdx +
|
|
277
|
+
const suffix = transformedShell.slice(markerIdx + streamBodyMarker.length);
|
|
273
278
|
const bufferedBody = bufferBodyBeforeHeaders ? await new Response(bodyStream).text() : null;
|
|
274
279
|
const headers = { "Transfer-Encoding": "chunked" };
|
|
275
280
|
if (!preserveExistingContentType || !res.hasHeader("Content-Type")) headers["Content-Type"] = "text/html; charset=utf-8";
|
|
@@ -384,7 +389,9 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
384
389
|
locale: locale ?? currentDefaultLocale,
|
|
385
390
|
locales: i18nConfig?.locales,
|
|
386
391
|
defaultLocale: currentDefaultLocale,
|
|
387
|
-
crossOrigin
|
|
392
|
+
crossOrigin,
|
|
393
|
+
trailingSlash,
|
|
394
|
+
requestPathname: new URL(originalUrl, "http://vinext.local").pathname
|
|
388
395
|
};
|
|
389
396
|
const match = matchRoute(localeStrippedUrl, routes);
|
|
390
397
|
if (!match) {
|
|
@@ -452,7 +459,8 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
452
459
|
isStaticPropsRender = typeof pageModule.getStaticProps === "function" && typeof pageModule.getServerSideProps !== "function";
|
|
453
460
|
if (isStaticPropsRender) {
|
|
454
461
|
query = mergeRouteParamsIntoQuery({}, params);
|
|
455
|
-
|
|
462
|
+
const routePattern = patternToNextFormat(route.pattern);
|
|
463
|
+
requestAsPath = routePattern === "/404" || routePattern === "/500" ? resolvePagesStatusPageRenderPath(routePattern, trailingSlash, errorPageContext.requestPathname) : localeStrippedUrl.split("?")[0];
|
|
456
464
|
}
|
|
457
465
|
const requestPreview = typeof pageModule.getStaticProps === "function" || typeof pageModule.getServerSideProps === "function" ? getPagesPreviewState(req.headers.cookie, { isOnDemandRevalidate: isOnDemandRevalidateRequest(req.headers[PRERENDER_REVALIDATE_HEADER]) }) : {
|
|
458
466
|
data: false,
|
|
@@ -864,6 +872,7 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
864
872
|
await streamPageToResponse(route.pattern, res, withScriptNonce(element, scriptNonce), {
|
|
865
873
|
url,
|
|
866
874
|
server,
|
|
875
|
+
runner,
|
|
867
876
|
fontHeadHTML,
|
|
868
877
|
assetHeadHTML,
|
|
869
878
|
scripts: allScripts,
|
|
@@ -963,10 +972,11 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
963
972
|
if (!ErrorComponent) continue;
|
|
964
973
|
const createElement = React.createElement;
|
|
965
974
|
res.statusCode = statusCode;
|
|
975
|
+
const renderUrl = errorPage !== "/_error" && typeof errorModule.getStaticProps === "function" ? resolvePagesStatusPageRenderPath(errorPage, context.trailingSlash === true, context.requestPathname ?? url.split("?")[0]) : url;
|
|
966
976
|
const errorRouter = {
|
|
967
977
|
pathname: errorPage,
|
|
968
|
-
query: parseQueryString(
|
|
969
|
-
asPath:
|
|
978
|
+
query: parseQueryString(renderUrl),
|
|
979
|
+
asPath: renderUrl
|
|
970
980
|
};
|
|
971
981
|
try {
|
|
972
982
|
errorRouterShim = await importModule(runner, "next/router");
|
|
@@ -983,7 +993,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
983
993
|
err,
|
|
984
994
|
pathname: errorPage,
|
|
985
995
|
query: errorRouter.query,
|
|
986
|
-
asPath:
|
|
996
|
+
asPath: renderUrl
|
|
987
997
|
});
|
|
988
998
|
if (res.headersSent || res.writableEnded) return;
|
|
989
999
|
let errorProps = {
|
|
@@ -1004,7 +1014,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1004
1014
|
writeGsspRedirect(res, staticResult.redirect, false, { pageProps: errorProps }, {
|
|
1005
1015
|
basePath: context.basePath,
|
|
1006
1016
|
method: "getStaticProps",
|
|
1007
|
-
routeUrl:
|
|
1017
|
+
routeUrl: renderUrl
|
|
1008
1018
|
});
|
|
1009
1019
|
return;
|
|
1010
1020
|
}
|
|
@@ -1035,7 +1045,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1035
1045
|
err,
|
|
1036
1046
|
pathname: errorPage,
|
|
1037
1047
|
query: errorRouter.query,
|
|
1038
|
-
asPath:
|
|
1048
|
+
asPath: renderUrl
|
|
1039
1049
|
}
|
|
1040
1050
|
});
|
|
1041
1051
|
if (res.headersSent || res.writableEnded) return;
|
|
@@ -1068,7 +1078,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1068
1078
|
const errorScripts = `${`<script id="__NEXT_DATA__" type="application/json"${nonceAttr}>${safeJsonStringify({
|
|
1069
1079
|
props: renderProps,
|
|
1070
1080
|
page: errorPage,
|
|
1071
|
-
query: parseQueryString(
|
|
1081
|
+
query: parseQueryString(renderUrl),
|
|
1072
1082
|
buildId: context.buildId ?? process.env.__VINEXT_BUILD_ID ?? "development",
|
|
1073
1083
|
isFallback: false,
|
|
1074
1084
|
locale: context.locale,
|
|
@@ -1095,6 +1105,7 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1095
1105
|
if (DocumentComponent) await streamPageToResponse(errorPage, res, element, {
|
|
1096
1106
|
url,
|
|
1097
1107
|
server,
|
|
1108
|
+
runner,
|
|
1098
1109
|
fontHeadHTML: "",
|
|
1099
1110
|
assetHeadHTML,
|
|
1100
1111
|
scripts: errorScripts,
|
|
@@ -1103,8 +1114,8 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1103
1114
|
documentContext: {
|
|
1104
1115
|
err,
|
|
1105
1116
|
pathname: errorPage,
|
|
1106
|
-
query: parseQueryString(
|
|
1107
|
-
asPath:
|
|
1117
|
+
query: parseQueryString(renderUrl),
|
|
1118
|
+
asPath: renderUrl,
|
|
1108
1119
|
req,
|
|
1109
1120
|
res
|
|
1110
1121
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
1
|
+
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { VINEXT_ORIGINAL_STACK_TRACE_ENDPOINT } from "../utils/dev-stack-sourcemap-endpoint.js";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { isFileLoadingAllowed } from "vite";
|
|
5
5
|
//#region src/server/dev-stack-sourcemap.ts
|
|
6
6
|
const MAX_ORIGINAL_STACK_TRACE_BODY_BYTES = 1048576;
|
|
7
7
|
const V8_PAREN_STACK_LINE = /^(\s*at\s+.*?\()(.+):(\d+):(\d+)(\)\s*)$/;
|
|
@@ -162,7 +162,7 @@ async function mapGeneratedFrame(server, file, line, column, methodName, request
|
|
|
162
162
|
const original = traceOriginalPositionFor(sourceMap, generatedLine, generatedColumn);
|
|
163
163
|
if (!original) return null;
|
|
164
164
|
const originalFile = resolveSourceFile(original.source, sourceMap, generatedFrame.sourceMapBaseUrl);
|
|
165
|
-
const codeFrame =
|
|
165
|
+
const codeFrame = createStackCodeFrame({
|
|
166
166
|
file: originalFile,
|
|
167
167
|
line: original.line,
|
|
168
168
|
column: original.column,
|
|
@@ -224,11 +224,12 @@ function getLocalSourcePath(server, file) {
|
|
|
224
224
|
}
|
|
225
225
|
localPath = stripQuery(localPath);
|
|
226
226
|
if (!isAbsolutePath(localPath)) return null;
|
|
227
|
+
localPath = path.resolve(localPath);
|
|
227
228
|
const localPathForCompare = normalizeLocalPathForCompare(localPath);
|
|
228
229
|
if (localPathForCompare.includes("/node_modules/")) return null;
|
|
229
230
|
const root = server.config?.root;
|
|
230
231
|
if (!root) return null;
|
|
231
|
-
const rootForCompare = normalizeLocalPathForCompare(root);
|
|
232
|
+
const rootForCompare = normalizeLocalPathForCompare(path.resolve(root));
|
|
232
233
|
return localPathForCompare === rootForCompare || localPathForCompare.startsWith(`${rootForCompare}/`) ? localPath : null;
|
|
233
234
|
}
|
|
234
235
|
function isAbsolutePath(value) {
|
|
@@ -242,18 +243,18 @@ function normalizeLocalPathForCompare(value) {
|
|
|
242
243
|
return /^[A-Za-z]:\//.test(normalized) ? normalized.toLowerCase() : normalized;
|
|
243
244
|
}
|
|
244
245
|
function normalizeIgnoreListPath(value) {
|
|
245
|
-
let
|
|
246
|
-
if (
|
|
247
|
-
|
|
246
|
+
let normalized = devirtualizeReactServerFrame(value);
|
|
247
|
+
if (normalized.startsWith("file://")) try {
|
|
248
|
+
normalized = fileURLToPath(normalized);
|
|
248
249
|
} catch {}
|
|
249
250
|
else try {
|
|
250
|
-
const url = new URL(
|
|
251
|
-
if (url.protocol === "http:" || url.protocol === "https:")
|
|
251
|
+
const url = new URL(normalized);
|
|
252
|
+
if (url.protocol === "http:" || url.protocol === "https:") normalized = `${url.pathname}${url.search}`;
|
|
252
253
|
} catch {}
|
|
253
254
|
try {
|
|
254
|
-
|
|
255
|
+
normalized = decodeURIComponent(normalized);
|
|
255
256
|
} catch {}
|
|
256
|
-
return toSlash(
|
|
257
|
+
return toSlash(normalized).toLowerCase();
|
|
257
258
|
}
|
|
258
259
|
function isExternalHttpFrame(file, requestHost) {
|
|
259
260
|
if (!/^https?:\/\//i.test(file) || !requestHost) return false;
|
|
@@ -274,10 +275,9 @@ function isIgnoreListedOriginalFrame(file) {
|
|
|
274
275
|
function isSourceMapIgnored(sourceMap, sourceIndex) {
|
|
275
276
|
return sourceMap.ignoreList?.includes(sourceIndex) ?? false;
|
|
276
277
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const sourceLines = source.split(/\r\n|\r|\n/);
|
|
278
|
+
function createStackCodeFrame({ file, line, column, methodName, sourceContent }) {
|
|
279
|
+
if (!sourceContent) return null;
|
|
280
|
+
const sourceLines = sourceContent.split(/\r\n|\r|\n/);
|
|
281
281
|
if (line < 1 || line > sourceLines.length) return null;
|
|
282
282
|
const start = Math.max(1, line - 2);
|
|
283
283
|
const end = Math.min(sourceLines.length, line + 3);
|
|
@@ -295,14 +295,6 @@ async function createStackCodeFrame({ file, line, column, methodName, sourceCont
|
|
|
295
295
|
lines
|
|
296
296
|
};
|
|
297
297
|
}
|
|
298
|
-
async function readSourceFileForCodeFrame(file) {
|
|
299
|
-
if (!file.startsWith("file://")) return null;
|
|
300
|
-
try {
|
|
301
|
-
return await readFile(fileURLToPath(file), "utf8");
|
|
302
|
-
} catch {
|
|
303
|
-
return null;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
298
|
function getMappableClientGeneratedUrl(file, requestHost) {
|
|
307
299
|
const isAbsoluteHttpUrl = /^https?:\/\//i.test(file);
|
|
308
300
|
let url;
|
|
@@ -335,6 +327,9 @@ async function loadServerSourceMapForLocalPath(server, localPath) {
|
|
|
335
327
|
const environment = server.environments[environmentName];
|
|
336
328
|
if (!environment) continue;
|
|
337
329
|
try {
|
|
330
|
+
const resolved = await environment.pluginContainer.resolveId(localPath);
|
|
331
|
+
if (!resolved || resolved.external || resolved.id.startsWith("\0")) continue;
|
|
332
|
+
if (!isFileLoadingAllowed(server.config, stripQuery(resolved.id))) continue;
|
|
338
333
|
const sourceMap = normalizeSourceMapPayload((await environment.transformRequest(localPath))?.map);
|
|
339
334
|
if (sourceMap) return sourceMap;
|
|
340
335
|
} catch {}
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
//#region src/server/document-initial-head.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* True when `_document` supplies its own `getInitialProps`, rather than
|
|
5
|
-
* exposing none or inheriting the shim's default. Comparing against the
|
|
6
|
-
* captured `DEFAULT_GET_INITIAL_PROPS` reference is what distinguishes a user
|
|
7
|
-
* override from the default — extending the shim's `Document` without
|
|
8
|
-
* overriding inherits the same static function.
|
|
9
|
-
*
|
|
10
|
-
* Callers use this to decide whether the render pipeline owes `_document` the
|
|
11
|
-
* full `getInitialProps` contract, since only an override can observe it.
|
|
12
|
-
*/
|
|
13
|
-
export declare function hasUserDocumentGetInitialProps(DocumentComponent: React.ComponentType | null | undefined): boolean;
|
|
14
3
|
export declare function callDocumentGetInitialProps(DocumentComponent: React.ComponentType | null | undefined, setDocumentInitialHead: ((head: React.ReactNode[]) => void) | undefined): Promise<void>;
|
|
15
4
|
//#endregion
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/server/forwarded-middleware-context.d.ts
|
|
2
|
+
export declare function sealForwardedMiddlewareContext(key: string, context: string): string;
|
|
3
|
+
/** Returns the forwarded context JSON, or null unless it carries `key`. */
|
|
4
|
+
export declare function openForwardedMiddlewareContext(value: string | null, key: string | null | undefined): string | null;
|
|
5
|
+
//#endregion
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { safeEqual } from "./revalidation-request.js";
|
|
2
|
+
//#region src/server/forwarded-middleware-context.ts
|
|
3
|
+
/**
|
|
4
|
+
* Hybrid app+pages dev runs middleware once in the Pages connect handler and
|
|
5
|
+
* forwards the result to the App Router in x-vinext-mw-ctx. The value is
|
|
6
|
+
* prefixed with a per-dev-server key that only vinext's generated RSC entry
|
|
7
|
+
* knows, so a client-supplied copy can never stand in for running middleware,
|
|
8
|
+
* whichever plugin builds the App Router request first.
|
|
9
|
+
*/
|
|
10
|
+
const KEY_SEPARATOR = ".";
|
|
11
|
+
function sealForwardedMiddlewareContext(key, context) {
|
|
12
|
+
return key + KEY_SEPARATOR + context;
|
|
13
|
+
}
|
|
14
|
+
/** Returns the forwarded context JSON, or null unless it carries `key`. */
|
|
15
|
+
function openForwardedMiddlewareContext(value, key) {
|
|
16
|
+
if (value === null || !key) return null;
|
|
17
|
+
const separatorIndex = value.indexOf(KEY_SEPARATOR);
|
|
18
|
+
if (separatorIndex === -1 || !safeEqual(value.slice(0, separatorIndex), key)) return null;
|
|
19
|
+
return value.slice(separatorIndex + 1);
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { openForwardedMiddlewareContext, sealForwardedMiddlewareContext };
|
package/dist/server/headers.d.ts
CHANGED
|
@@ -48,7 +48,10 @@ export declare const VINEXT_PRERENDER_READINESS_PATH = "/__vinext/prerender/read
|
|
|
48
48
|
export declare const VINEXT_PRERENDER_READINESS_HEADER = "X-Vinext-Prerender-Readiness";
|
|
49
49
|
/** TPR (Tailored Per-Request) revalidation interval in seconds. */
|
|
50
50
|
export declare const VINEXT_REVALIDATE_HEADER = "x-vinext-revalidate";
|
|
51
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Actual Pages cache tag regenerated by an authenticated on-demand request.
|
|
53
|
+
* URI-encoded, because a decoded path can end in whitespace that Headers trims.
|
|
54
|
+
*/
|
|
52
55
|
export declare const VINEXT_REVALIDATED_CACHE_TAG_HEADER = "x-vinext-revalidated-cache-tag";
|
|
53
56
|
/** Marker on cached ISR entries indicating RSC payload (value "1"). */
|
|
54
57
|
export declare const VINEXT_RSC_MARKER_HEADER = "x-vinext-rsc";
|
package/dist/server/headers.js
CHANGED
|
@@ -48,7 +48,10 @@ const VINEXT_PRERENDER_READINESS_PATH = "/__vinext/prerender/readiness";
|
|
|
48
48
|
const VINEXT_PRERENDER_READINESS_HEADER = "X-Vinext-Prerender-Readiness";
|
|
49
49
|
/** TPR (Tailored Per-Request) revalidation interval in seconds. */
|
|
50
50
|
const VINEXT_REVALIDATE_HEADER = "x-vinext-revalidate";
|
|
51
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Actual Pages cache tag regenerated by an authenticated on-demand request.
|
|
53
|
+
* URI-encoded, because a decoded path can end in whitespace that Headers trims.
|
|
54
|
+
*/
|
|
52
55
|
const VINEXT_REVALIDATED_CACHE_TAG_HEADER = "x-vinext-revalidated-cache-tag";
|
|
53
56
|
/** Marker on cached ISR entries indicating RSC payload (value "1"). */
|
|
54
57
|
const VINEXT_RSC_MARKER_HEADER = "x-vinext-rsc";
|
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
* validator with the same opaque tag compare equal.
|
|
7
7
|
*/
|
|
8
8
|
export declare function matchesIfNoneMatch(ifNoneMatch: string | undefined, etag: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Whether a page answers its request with a 304, as Next.js's
|
|
11
|
+
* `sendEtagResponse` does with `fresh(req.headers, { etag })`. Next.js gives a
|
|
12
|
+
* page no Last-Modified, so a request with If-Modified-Since gets the page, and
|
|
13
|
+
* a request `Cache-Control: no-cache` always does.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isPageNotModified(request: {
|
|
16
|
+
cacheControl?: string;
|
|
17
|
+
ifModifiedSince?: string;
|
|
18
|
+
ifNoneMatch?: string;
|
|
19
|
+
}, etag: string): boolean;
|
|
9
20
|
/** Test an If-Match field using Next.js's weak/strong-equivalent comparison. */
|
|
10
21
|
export declare function matchesIfMatch(ifMatch: string | undefined, etag: string | undefined): boolean;
|
|
11
22
|
type StaticConditionalHeaders = {
|
|
@@ -31,6 +31,15 @@ function matchesIfNoneMatch(ifNoneMatch, etag) {
|
|
|
31
31
|
}
|
|
32
32
|
return sawTag && matched;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Whether a page answers its request with a 304, as Next.js's
|
|
36
|
+
* `sendEtagResponse` does with `fresh(req.headers, { etag })`. Next.js gives a
|
|
37
|
+
* page no Last-Modified, so a request with If-Modified-Since gets the page, and
|
|
38
|
+
* a request `Cache-Control: no-cache` always does.
|
|
39
|
+
*/
|
|
40
|
+
function isPageNotModified(request, etag) {
|
|
41
|
+
return !request.ifModifiedSince && !/(?:^|,)\s*no-cache\s*(?:,|$)/.test(request.cacheControl ?? "") && matchesIfNoneMatch(request.ifNoneMatch, etag);
|
|
42
|
+
}
|
|
34
43
|
/** Test an If-Match field using Next.js's weak/strong-equivalent comparison. */
|
|
35
44
|
function matchesIfMatch(ifMatch, etag) {
|
|
36
45
|
if (!ifMatch) return false;
|
|
@@ -114,4 +123,4 @@ function joinHeader(value) {
|
|
|
114
123
|
return Array.isArray(value) ? value.join(", ") : value;
|
|
115
124
|
}
|
|
116
125
|
//#endregion
|
|
117
|
-
export { evaluateStaticPreconditions, matchesIfMatch, matchesIfNoneMatch };
|
|
126
|
+
export { evaluateStaticPreconditions, isPageNotModified, matchesIfMatch, matchesIfNoneMatch };
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `new Response(...)` boilerplate.
|
|
10
10
|
*
|
|
11
11
|
* Sites with route-specific bodies (e.g. `"404 - API route not found"`,
|
|
12
|
-
*
|
|
12
|
+
* generated worker templates) intentionally remain inline
|
|
13
13
|
* because their bodies are either tested-against fixtures or run inside template
|
|
14
14
|
* strings that have no access to runtime imports.
|
|
15
15
|
*
|
|
@@ -82,6 +82,44 @@ export type ParseImageParamsOptions = {
|
|
|
82
82
|
isDev?: boolean;
|
|
83
83
|
};
|
|
84
84
|
export declare function resolveDevImageRedirect(requestUrl: URL, allowedWidths?: number[], allowedQualities?: number[], options?: ParseImageParamsOptions): string | null;
|
|
85
|
+
export type ImageOptimizationSignal = {
|
|
86
|
+
/** Middleware response headers to send with the image. */
|
|
87
|
+
middlewareHeaders: Headers;
|
|
88
|
+
/** The request headers after middleware's overrides, when it set any. */
|
|
89
|
+
requestHeaders: Headers | null;
|
|
90
|
+
/** The image query after middleware and rewrites. */
|
|
91
|
+
search: string;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Mark the App Router's image endpoint response once the request has passed
|
|
95
|
+
* middleware and rewrites. A host that serves images itself (the Node
|
|
96
|
+
* production server) replaces the response with the image; other hosts send
|
|
97
|
+
* the response unchanged. The symbol carries the signal across the built RSC
|
|
98
|
+
* module boundary, so response headers cannot forge it.
|
|
99
|
+
*/
|
|
100
|
+
export declare function markImageOptimizationSignal(response: Response, signal: ImageOptimizationSignal): Response;
|
|
101
|
+
/** Return the signal of a framework-created image endpoint response. */
|
|
102
|
+
export declare function readImageOptimizationSignal(response: Response): ImageOptimizationSignal | null;
|
|
103
|
+
/**
|
|
104
|
+
* Carry a signal through the response-stage transport, which drops the
|
|
105
|
+
* symbol. The signal rides in the body of the bodiless carrier, with the
|
|
106
|
+
* carrier's status in the token-authenticated marker.
|
|
107
|
+
*/
|
|
108
|
+
export declare function serializeImageOptimizationSignalForTransport(response: Response, token: string): Response;
|
|
109
|
+
/** Restore and consume a signal returned by the trusted response-stage wrapper. */
|
|
110
|
+
export declare function restoreImageOptimizationSignalFromTransport(response: Response, token: string): Promise<Response>;
|
|
111
|
+
/**
|
|
112
|
+
* Whether a local source's pipeline status carries the file's bytes. A no-body
|
|
113
|
+
* success such as 204 serves no file, which Next.js rejects as an invalid
|
|
114
|
+
* image.
|
|
115
|
+
*/
|
|
116
|
+
export declare function isImageSourceBodyStatus(status: number): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Body Next.js answers, with a 400, for a local source that yields no image:
|
|
119
|
+
* a missing file, or anything middleware or routing answers in its place.
|
|
120
|
+
*/
|
|
121
|
+
export declare const INVALID_IMAGE_SOURCE_MESSAGE = "The requested resource isn't a valid image.";
|
|
122
|
+
export declare function invalidImageSourceResponse(): Response;
|
|
85
123
|
/**
|
|
86
124
|
* Parse and validate image optimization query parameters.
|
|
87
125
|
* Returns null if the request is malformed.
|