vinext 1.0.1 → 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 +93 -10
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- 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 +8 -81
- package/dist/build/prerender.js +33 -8
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/server-manifest.d.ts +7 -0
- package/dist/build/server-manifest.js +11 -1
- package/dist/build/ssr-manifest.d.ts +2 -0
- package/dist/build/ssr-manifest.js +6 -2
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +3 -3
- 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/client/navigation-runtime.d.ts +11 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.d.ts +26 -11
- package/dist/config/config-matchers.js +81 -82
- package/dist/config/destination-params.d.ts +47 -0
- package/dist/config/destination-params.js +116 -0
- package/dist/config/next-config.d.ts +14 -0
- package/dist/config/next-config.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +6 -0
- package/dist/entries/app-rsc-entry.js +84 -49
- package/dist/entries/pages-client-entry.js +3 -1
- package/dist/entries/pages-server-entry.js +13 -37
- package/dist/index.d.ts +7 -2
- package/dist/index.js +193 -73
- 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 +19 -0
- package/dist/plugins/cache-flight-codec.js +68 -0
- package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
- package/dist/plugins/commonjs-esm-facade.js +80 -0
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +9 -8
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- 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/routing/file-matcher.d.ts +1 -0
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +19 -8
- 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-entry.js +11 -7
- package/dist/server/app-browser-history-controller.d.ts +2 -0
- package/dist/server/app-browser-history-controller.js +8 -0
- package/dist/server/app-browser-interception-context.js +26 -2
- package/dist/server/app-browser-navigation-controller.d.ts +7 -1
- package/dist/server/app-browser-navigation-controller.js +94 -11
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +2 -0
- package/dist/server/app-fallback-renderer.js +1 -0
- package/dist/server/app-history-state.d.ts +3 -0
- package/dist/server/app-history-state.js +7 -0
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +19 -3
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +5 -0
- package/dist/server/app-page-boundary-render.js +6 -4
- package/dist/server/app-page-cache-finalizer.d.ts +11 -0
- package/dist/server/app-page-cache-finalizer.js +41 -7
- package/dist/server/app-page-cache-render.d.ts +18 -0
- package/dist/server/app-page-cache-render.js +63 -43
- package/dist/server/app-page-cache.d.ts +6 -1
- package/dist/server/app-page-cache.js +28 -8
- package/dist/server/app-page-dispatch.d.ts +12 -2
- package/dist/server/app-page-dispatch.js +51 -33
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +27 -42
- package/dist/server/app-page-execution.d.ts +15 -12
- package/dist/server/app-page-execution.js +30 -40
- package/dist/server/app-page-head.d.ts +5 -0
- package/dist/server/app-page-head.js +9 -3
- package/dist/server/app-page-ppr-runtime.js +1 -1
- package/dist/server/app-page-probe.d.ts +0 -109
- package/dist/server/app-page-probe.js +3 -136
- package/dist/server/app-page-render-identity.d.ts +0 -1
- package/dist/server/app-page-render-identity.js +1 -1
- package/dist/server/app-page-render-observation.js +3 -3
- package/dist/server/app-page-render.d.ts +13 -5
- package/dist/server/app-page-render.js +219 -119
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +54 -17
- package/dist/server/app-page-response.d.ts +4 -3
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-route-wiring.d.ts +17 -5
- package/dist/server/app-page-route-wiring.js +57 -35
- package/dist/server/app-page-rsc-render-status.d.ts +48 -0
- package/dist/server/app-page-rsc-render-status.js +54 -0
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +6 -0
- 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 +7 -3
- package/dist/server/app-request-stage-independent-entry.js +29 -9
- package/dist/server/app-response-header-provenance.d.ts +2 -0
- package/dist/server/app-response-header-provenance.js +10 -4
- 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 +6 -3
- 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 +27 -8
- 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 +11 -0
- package/dist/server/app-rsc-handler.js +291 -125
- package/dist/server/app-rsc-request-normalization.d.ts +3 -1
- package/dist/server/app-rsc-request-normalization.js +4 -2
- package/dist/server/app-rsc-response-stage.d.ts +1 -1
- package/dist/server/app-rsc-response-stage.js +10 -6
- package/dist/server/app-rsc-route-matching.d.ts +9 -1
- package/dist/server/app-rsc-route-matching.js +36 -19
- 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 +62 -23
- package/dist/server/app-ssr-entry.d.ts +3 -2
- package/dist/server/app-ssr-entry.js +8 -5
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +34 -15
- package/dist/server/app-worker-stages.d.ts +7 -2
- package/dist/server/app-worker-stages.js +4 -4
- package/dist/server/cacheability-request.js +11 -7
- 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/config-headers.js +2 -0
- package/dist/server/dev-server.js +50 -29
- 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 +18 -1
- package/dist/server/headers.js +19 -2
- 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 +54 -0
- package/dist/server/image-optimization.js +118 -9
- package/dist/server/isr-cache.d.ts +10 -0
- package/dist/server/isr-cache.js +43 -8
- package/dist/server/metadata-route-response.js +9 -8
- package/dist/server/middleware-matcher-pattern.js +8 -4
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-response-headers.js +2 -0
- 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 +19 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/node-response-signal.d.ts +16 -0
- package/dist/server/node-response-signal.js +26 -0
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/open-redirect.d.ts +47 -0
- package/dist/server/open-redirect.js +74 -1
- 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 +209 -130
- 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 +79 -16
- 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 +20 -7
- package/dist/server/prod-server.js +343 -129
- package/dist/server/proper-error.d.ts +4 -0
- package/dist/server/proper-error.js +31 -0
- package/dist/server/request-pipeline.d.ts +24 -9
- package/dist/server/request-pipeline.js +24 -9
- package/dist/server/response-compression.d.ts +43 -0
- package/dist/server/response-compression.js +111 -0
- 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 +15 -11
- 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 +23 -1
- package/dist/server/socket-error-backstop.js +69 -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-adapter-instantiate.d.ts +50 -0
- package/dist/shims/cache-adapter-instantiate.js +118 -0
- package/dist/shims/cache-callable-runtime.d.ts +6 -42
- package/dist/shims/cache-callable-runtime.js +65 -174
- package/dist/shims/cache-flight-arguments.d.ts +22 -0
- package/dist/shims/cache-flight-arguments.js +56 -0
- package/dist/shims/cache-handler.js +1 -9
- package/dist/shims/cache-request-state.d.ts +15 -0
- package/dist/shims/cache-request-state.js +31 -8
- package/dist/shims/cache-runtime.d.ts +12 -20
- package/dist/shims/cache-runtime.js +166 -225
- package/dist/shims/cache.d.ts +4 -4
- package/dist/shims/cache.js +44 -16
- package/dist/shims/cacheability-classification.d.ts +7 -0
- 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/error-boundary-navigation.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.js +19 -1
- package/dist/shims/error-boundary.d.ts +10 -10
- package/dist/shims/error-boundary.js +26 -7
- 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 -61
- package/dist/shims/fetch-cache.js +161 -108
- package/dist/shims/form.js +1 -1
- package/dist/shims/head.d.ts +10 -6
- package/dist/shims/head.js +15 -13
- package/dist/shims/headers.d.ts +13 -0
- package/dist/shims/headers.js +47 -4
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
- package/dist/shims/internal/app-page-props-cache-key.js +24 -15
- package/dist/shims/internal/headers-state.d.ts +0 -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/metadata.js +3 -3
- package/dist/shims/navigation-errors.d.ts +6 -0
- package/dist/shims/navigation-errors.js +11 -1
- package/dist/shims/navigation.d.ts +7 -0
- package/dist/shims/navigation.js +45 -9
- package/dist/shims/request-context.d.ts +11 -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/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- 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/mdx-scan.d.ts +5 -0
- package/dist/utils/mdx-scan.js +8 -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/dist/utils/regex-safety.d.ts +10 -0
- package/dist/utils/regex-safety.js +70 -18
- package/package.json +9 -5
|
@@ -5,18 +5,20 @@ import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from
|
|
|
5
5
|
import { StaticFileCache, contentTypeForPath, etagFromFilenameHash } from "./static-file-cache.js";
|
|
6
6
|
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
7
7
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
8
|
-
import { VINEXT_PRERENDER_RENDER_ERROR_HEADER } from "./headers.js";
|
|
8
|
+
import { VINEXT_PRERENDER_RENDER_ERROR_HEADER, VINEXT_PRERENDER_SPECIAL_ERROR_HEADER } from "./headers.js";
|
|
9
9
|
import { normalizePath } from "./normalize-path.js";
|
|
10
10
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
11
|
-
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
11
|
+
import { getRepeatedSlashRedirect, isOpenRedirectShaped, sendRepeatedSlashRedirect } from "./open-redirect.js";
|
|
12
12
|
import { readStaticFileSignal } from "./static-file-signal.js";
|
|
13
13
|
import { canonicalizeRequestPathname, filterInternalHeaders } from "./request-pipeline.js";
|
|
14
|
+
import { buildNextDataNotFoundResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath } from "./pages-data-route.js";
|
|
15
|
+
import { buildCacheStateHeaders } from "./cache-headers.js";
|
|
14
16
|
import { parseHttpDate } from "./http-date.js";
|
|
15
17
|
import { evaluateStaticPreconditions } from "./http-conditional.js";
|
|
16
|
-
import { buildNextDataNotFoundResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath } from "./pages-data-route.js";
|
|
17
18
|
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
18
19
|
import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
19
|
-
import {
|
|
20
|
+
import { signalFromNodeResponse } from "./node-response-signal.js";
|
|
21
|
+
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_RESPONSE_CACHE_STATE, INVALID_IMAGE_SOURCE_MESSAGE, isImageOptimizationPath, isImageSourceBodyStatus, isSafeImageContentType, parseImageParams, readImageOptimizationSignal } from "./image-optimization.js";
|
|
20
22
|
import { installSocketErrorBackstop } from "./socket-error-backstop.js";
|
|
21
23
|
import { collectInlineCssManifest } from "../build/inline-css.js";
|
|
22
24
|
import { readTrustedRevalidationHostname } from "./revalidation-host.js";
|
|
@@ -24,11 +26,13 @@ import { traceFrameworkRequest } from "./request-tracing.js";
|
|
|
24
26
|
import { mergeHeaders } from "./worker-utils.js";
|
|
25
27
|
import { runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pipeline.js";
|
|
26
28
|
import { computeClientRuntimeMetadata } from "../utils/client-runtime-metadata.js";
|
|
27
|
-
import { readPrerenderSecret } from "../build/server-manifest.js";
|
|
29
|
+
import { readPrerenderSecret, readServerCompress } from "../build/server-manifest.js";
|
|
28
30
|
import { readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
31
|
+
import { resolveClientBuildFile } from "./client-build-files.js";
|
|
29
32
|
import { registerPrerenderCloudflareLoader } from "../build/prerender-cloudflare-loader.js";
|
|
30
33
|
import { seedMemoryCacheFromPrerender } from "./seed-cache.js";
|
|
31
34
|
import { negotiateEncoding, parseAcceptedEncodings, selectContentEncoding } from "./accept-encoding.js";
|
|
35
|
+
import { COMPRESS_THRESHOLD, hasNoTransform, isCompressibleContentType, parseContentLengthHeader, resolveResponseCompression } from "./response-compression.js";
|
|
32
36
|
import { ifRangeAllowsRange, parseByteRange } from "./http-range.js";
|
|
33
37
|
import { createRequire } from "node:module";
|
|
34
38
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -192,25 +196,6 @@ function readNodeStream(req) {
|
|
|
192
196
|
}
|
|
193
197
|
});
|
|
194
198
|
}
|
|
195
|
-
/** Content types that benefit from compression. */
|
|
196
|
-
const COMPRESSIBLE_TYPES = /* @__PURE__ */ new Set([
|
|
197
|
-
"text/html",
|
|
198
|
-
"text/css",
|
|
199
|
-
"text/plain",
|
|
200
|
-
"text/xml",
|
|
201
|
-
"text/javascript",
|
|
202
|
-
"application/javascript",
|
|
203
|
-
"application/json",
|
|
204
|
-
"application/xml",
|
|
205
|
-
"application/xhtml+xml",
|
|
206
|
-
"application/rss+xml",
|
|
207
|
-
"application/atom+xml",
|
|
208
|
-
"image/svg+xml",
|
|
209
|
-
"application/manifest+json",
|
|
210
|
-
"application/wasm"
|
|
211
|
-
]);
|
|
212
|
-
/** Minimum size threshold for compression (in bytes). Below this, compression overhead isn't worth it. */
|
|
213
|
-
const COMPRESS_THRESHOLD = 1024;
|
|
214
199
|
/**
|
|
215
200
|
* Create a compression stream for the given encoding.
|
|
216
201
|
*/
|
|
@@ -276,12 +261,14 @@ const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
|
|
|
276
261
|
205,
|
|
277
262
|
304
|
|
278
263
|
]);
|
|
264
|
+
const IMAGE_REPRESENTATION_HEADERS = buildCacheStateHeaders(IMAGE_RESPONSE_CACHE_STATE);
|
|
279
265
|
const OMIT_BODY_HEADERS = /* @__PURE__ */ new Set(["content-length", "content-type"]);
|
|
280
266
|
const OMIT_STATIC_RESPONSE_HEADERS = /* @__PURE__ */ new Set([
|
|
281
267
|
"content-encoding",
|
|
282
268
|
"content-length",
|
|
283
269
|
"content-range",
|
|
284
|
-
"content-type"
|
|
270
|
+
"content-type",
|
|
271
|
+
VINEXT_PRERENDER_SPECIAL_ERROR_HEADER
|
|
285
272
|
]);
|
|
286
273
|
function omitHeadersCaseInsensitive(headersRecord, targets) {
|
|
287
274
|
const filtered = {};
|
|
@@ -291,6 +278,23 @@ function omitHeadersCaseInsensitive(headersRecord, targets) {
|
|
|
291
278
|
}
|
|
292
279
|
return filtered;
|
|
293
280
|
}
|
|
281
|
+
function readHeaderCaseInsensitive(headersRecord, name) {
|
|
282
|
+
const key = Object.keys(headersRecord).find((entry) => entry.toLowerCase() === name);
|
|
283
|
+
if (key === void 0) return void 0;
|
|
284
|
+
const value = headersRecord[key];
|
|
285
|
+
return Array.isArray(value) ? value.join(", ") : value;
|
|
286
|
+
}
|
|
287
|
+
/** Remove one field name from a Vary header, dropping the header if it empties. */
|
|
288
|
+
function omitVaryToken(headers, token) {
|
|
289
|
+
const varyKey = Object.keys(headers).find((key) => key.toLowerCase() === "vary");
|
|
290
|
+
if (varyKey === void 0) return headers;
|
|
291
|
+
const rawVary = headers[varyKey];
|
|
292
|
+
const remaining = (Array.isArray(rawVary) ? rawVary.join(",") : rawVary).split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0 && entry.toLowerCase() !== token.toLowerCase());
|
|
293
|
+
const result = { ...headers };
|
|
294
|
+
delete result[varyKey];
|
|
295
|
+
if (remaining.length > 0) result[varyKey] = remaining.join(", ");
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
294
298
|
function mergeVaryHeader(headers, value) {
|
|
295
299
|
const merged = { ...headers };
|
|
296
300
|
const existingKey = Object.keys(merged).find((key) => key.toLowerCase() === "vary");
|
|
@@ -332,10 +336,41 @@ function installClientBuildManifestGlobals(clientDir, assetBase, assetPrefix, cr
|
|
|
332
336
|
function isNoBodyResponseStatus(status) {
|
|
333
337
|
return NO_BODY_RESPONSE_STATUSES.has(status);
|
|
334
338
|
}
|
|
335
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Discard a response body nobody will read. When the client is gone, pass the
|
|
341
|
+
* request signal's reason: React reports a reasonless cancel of a pending
|
|
342
|
+
* render as a server error, but recognizes `ResponseAborted` as a disconnect.
|
|
343
|
+
*/
|
|
344
|
+
function cancelResponseBody(response, reason) {
|
|
336
345
|
const body = response.body;
|
|
337
346
|
if (!body || body.locked) return;
|
|
338
|
-
body.cancel().catch(() => {});
|
|
347
|
+
body.cancel(reason).catch(() => {});
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Buffer a response body, cancelling it if the client disconnects first so a
|
|
351
|
+
* stalled stream does not outlive the connection. Resolves null when aborted.
|
|
352
|
+
*/
|
|
353
|
+
async function bufferResponseBodyUntilAborted(response, signal) {
|
|
354
|
+
const body = response.body;
|
|
355
|
+
if (!body) return Buffer.alloc(0);
|
|
356
|
+
const reader = body.getReader();
|
|
357
|
+
const cancel = () => {
|
|
358
|
+
reader.cancel(signal.reason).catch(() => {});
|
|
359
|
+
};
|
|
360
|
+
if (signal.aborted) cancel();
|
|
361
|
+
else signal.addEventListener("abort", cancel, { once: true });
|
|
362
|
+
const chunks = [];
|
|
363
|
+
try {
|
|
364
|
+
while (true) {
|
|
365
|
+
const result = await reader.read();
|
|
366
|
+
if (result.done) break;
|
|
367
|
+
chunks.push(result.value);
|
|
368
|
+
}
|
|
369
|
+
} finally {
|
|
370
|
+
signal.removeEventListener("abort", cancel);
|
|
371
|
+
reader.releaseLock();
|
|
372
|
+
}
|
|
373
|
+
return signal.aborted ? null : Buffer.concat(chunks);
|
|
339
374
|
}
|
|
340
375
|
function isVinextStreamedHtmlResponse(response) {
|
|
341
376
|
return response.__vinextStreamedHtmlResponse === true;
|
|
@@ -370,24 +405,23 @@ function mergeWebResponse(middlewareHeaders, response, statusOverride) {
|
|
|
370
405
|
*/
|
|
371
406
|
function sendCompressed(req, res, body, contentType, statusCode, extraHeaders = {}, compress = true, statusText) {
|
|
372
407
|
const buf = typeof body === "string" ? Buffer.from(body) : body;
|
|
373
|
-
const baseType = contentType.split(";")[0].trim();
|
|
374
|
-
const varyByEncoding = compress && COMPRESSIBLE_TYPES.has(baseType);
|
|
375
|
-
const encoding = compress ? negotiateEncoding(req) : "identity";
|
|
376
408
|
const headersWithoutBodyHeaders = omitHeadersCaseInsensitive(extraHeaders, OMIT_BODY_HEADERS);
|
|
409
|
+
const { varyAcceptEncoding: varyByEncoding, encoding } = resolveResponseCompression(req, compress, {
|
|
410
|
+
contentType,
|
|
411
|
+
cacheControl: readHeaderCaseInsensitive(extraHeaders, "cache-control"),
|
|
412
|
+
contentEncoding: readHeaderCaseInsensitive(extraHeaders, "content-encoding"),
|
|
413
|
+
contentLength: buf.length
|
|
414
|
+
});
|
|
377
415
|
const writeHead = (headers, responseStatus = statusCode, responseStatusText = statusText) => {
|
|
378
416
|
if (responseStatusText) res.writeHead(responseStatus, responseStatusText, headers);
|
|
379
417
|
else res.writeHead(responseStatus, headers);
|
|
380
418
|
};
|
|
381
|
-
if (encoding !== "identity"
|
|
419
|
+
if (encoding !== "identity") {
|
|
382
420
|
writeHead(mergeVaryHeader({
|
|
383
421
|
...headersWithoutBodyHeaders,
|
|
384
422
|
"Content-Type": contentType,
|
|
385
423
|
"Content-Encoding": encoding
|
|
386
424
|
}, "Accept-Encoding"));
|
|
387
|
-
if (req.method === "HEAD") {
|
|
388
|
-
res.end();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
425
|
const compressor = createCompressor(encoding);
|
|
392
426
|
compressor.end(buf);
|
|
393
427
|
pipeline(compressor, res, () => {});
|
|
@@ -405,6 +439,21 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
405
439
|
res.end(buf);
|
|
406
440
|
}
|
|
407
441
|
}
|
|
442
|
+
/** The StaticFileCache key for a request pathname, or null when it is never served. */
|
|
443
|
+
function staticCacheLookupPath(pathname) {
|
|
444
|
+
let lookupPath = pathname;
|
|
445
|
+
if (pathname.includes("%")) try {
|
|
446
|
+
lookupPath = decodeURIComponent(pathname);
|
|
447
|
+
} catch {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
if (lookupPath.startsWith("/.vite/") || lookupPath === "/.vite") return null;
|
|
451
|
+
return lookupPath;
|
|
452
|
+
}
|
|
453
|
+
/** Pathnames the Pages Router serves from routes rather than the client directory. */
|
|
454
|
+
function isPagesFilesystemExcludedPath(pathname, phase) {
|
|
455
|
+
return pathname === "/" || pathname === "/api" || pathname.startsWith("/api/") || phase === "direct" && pathname.startsWith(`/_next/static/`);
|
|
456
|
+
}
|
|
408
457
|
/**
|
|
409
458
|
* Try to serve a static file from the client build directory.
|
|
410
459
|
*
|
|
@@ -415,8 +464,12 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
415
464
|
*
|
|
416
465
|
* Without a cache, falls back to async filesystem probing (still non-blocking,
|
|
417
466
|
* unlike the old sync existsSync/statSync approach).
|
|
467
|
+
*
|
|
468
|
+
* `extraHeaders` go on every response for the file. `representationHeaders` go
|
|
469
|
+
* only on responses that carry the file's bytes (200 and 206), never on a 304,
|
|
470
|
+
* 412, 416 or 405.
|
|
418
471
|
*/
|
|
419
|
-
async function tryServeStatic(req, res, clientDir, pathname, compress, cache, extraHeaders, statusCode) {
|
|
472
|
+
async function tryServeStatic(req, res, clientDir, pathname, compress, cache, extraHeaders, statusCode, representationHeaders) {
|
|
420
473
|
if (pathname === "/") return false;
|
|
421
474
|
const responseStatus = statusCode ?? 200;
|
|
422
475
|
const omitBody = isNoBodyResponseStatus(responseStatus);
|
|
@@ -424,41 +477,35 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
424
477
|
const rawIfRange = req.headers["if-range"];
|
|
425
478
|
const ifRange = typeof rawIfRange === "string" ? rawIfRange : void 0;
|
|
426
479
|
if (cache) {
|
|
427
|
-
|
|
428
|
-
if (
|
|
429
|
-
try {
|
|
430
|
-
lookupPath = decodeURIComponent(pathname);
|
|
431
|
-
} catch {
|
|
432
|
-
return false;
|
|
433
|
-
}
|
|
434
|
-
if (lookupPath.startsWith("/.vite/") || lookupPath === "/.vite") return false;
|
|
435
|
-
} else {
|
|
436
|
-
if (pathname.startsWith("/.vite/") || pathname === "/.vite") return false;
|
|
437
|
-
lookupPath = pathname;
|
|
438
|
-
}
|
|
480
|
+
const lookupPath = staticCacheLookupPath(pathname);
|
|
481
|
+
if (lookupPath === null) return false;
|
|
439
482
|
const entry = cache.lookup(lookupPath);
|
|
440
483
|
if (!entry) return false;
|
|
441
484
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
442
485
|
sendStaticMethodNotAllowed(res, extraHeaders);
|
|
443
486
|
return true;
|
|
444
487
|
}
|
|
445
|
-
const
|
|
488
|
+
const encodingAllowed = compress && !hasNoTransform((extraHeaders && readHeaderCaseInsensitive(extraHeaders, "cache-control")) ?? entry.original.headers["Cache-Control"]);
|
|
489
|
+
const rawAe = encodingAllowed ? req.headers["accept-encoding"] : void 0;
|
|
446
490
|
const parsed = typeof rawAe === "string" ? parseAcceptedEncodings(rawAe) : void 0;
|
|
447
491
|
const availableVariants = [
|
|
448
492
|
...entry.zst ? ["zstd"] : [],
|
|
449
493
|
...entry.br ? ["br"] : [],
|
|
450
494
|
...entry.gz ? ["gzip"] : []
|
|
451
495
|
];
|
|
452
|
-
const variesByEncoding =
|
|
496
|
+
const variesByEncoding = encodingAllowed && availableVariants.length > 0;
|
|
453
497
|
const selected = parsed ? selectContentEncoding(parsed, availableVariants) : "identity";
|
|
454
498
|
const variant = selected === "zstd" ? entry.zst : selected === "br" ? entry.br : selected === "gzip" ? entry.gz : entry.original;
|
|
499
|
+
const notModifiedBaseHeaders = encodingAllowed ? entry.notModifiedHeaders : omitVaryToken(entry.notModifiedHeaders, "Accept-Encoding");
|
|
500
|
+
const originalHeaders = encodingAllowed ? entry.original.headers : omitVaryToken(entry.original.headers, "Accept-Encoding");
|
|
501
|
+
const variantHeaders = variant === entry.original ? originalHeaders : variant.headers;
|
|
455
502
|
const validators = extraHeaders ? resolveStaticValidators(entry.etag, entry.mtimeMs, extraHeaders) : void 0;
|
|
456
503
|
const effectiveEtag = validators ? validators.etag : entry.etag;
|
|
457
504
|
const effectiveMtimeMs = validators ? validators.mtimeMs : entry.mtimeMs;
|
|
458
505
|
const preconditionResult = responseStatus === 200 ? evaluateRequestPreconditions(req, effectiveEtag, effectiveMtimeMs) : "proceed";
|
|
459
506
|
if (preconditionResult === "precondition-failed") {
|
|
460
507
|
res.writeHead(412, {
|
|
461
|
-
...
|
|
508
|
+
...notModifiedBaseHeaders,
|
|
462
509
|
...extraHeaders,
|
|
463
510
|
"Content-Type": entry.original.headers["Content-Type"],
|
|
464
511
|
"Accept-Ranges": "bytes"
|
|
@@ -468,10 +515,10 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
468
515
|
}
|
|
469
516
|
if (preconditionResult === "not-modified") {
|
|
470
517
|
const notModifiedHeaders = variesByEncoding ? mergeVaryHeader({
|
|
471
|
-
...
|
|
518
|
+
...notModifiedBaseHeaders,
|
|
472
519
|
...extraHeaders
|
|
473
520
|
}, "Accept-Encoding") : {
|
|
474
|
-
...
|
|
521
|
+
...notModifiedBaseHeaders,
|
|
475
522
|
...extraHeaders
|
|
476
523
|
};
|
|
477
524
|
if (selected !== "identity") notModifiedHeaders["Content-Encoding"] = selected;
|
|
@@ -482,7 +529,7 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
482
529
|
const range = resolveRequestedRange(requestRange, ifRange, entry.original.size, effectiveEtag ?? "", effectiveMtimeMs, responseStatus);
|
|
483
530
|
if (range.kind === "unsatisfiable") {
|
|
484
531
|
res.writeHead(416, {
|
|
485
|
-
...
|
|
532
|
+
...notModifiedBaseHeaders,
|
|
486
533
|
...extraHeaders,
|
|
487
534
|
"Content-Type": entry.original.headers["Content-Type"],
|
|
488
535
|
"Accept-Ranges": "bytes",
|
|
@@ -494,8 +541,9 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
494
541
|
if (range.kind === "range") {
|
|
495
542
|
const length = range.end - range.start + 1;
|
|
496
543
|
const rangeHeaders = {
|
|
497
|
-
...
|
|
544
|
+
...originalHeaders,
|
|
498
545
|
...extraHeaders,
|
|
546
|
+
...representationHeaders,
|
|
499
547
|
"Accept-Ranges": "bytes",
|
|
500
548
|
"Content-Length": String(length),
|
|
501
549
|
"Content-Range": `bytes ${range.start}-${range.end}/${entry.original.size}`
|
|
@@ -510,8 +558,9 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
510
558
|
return true;
|
|
511
559
|
}
|
|
512
560
|
const responseHeaders = {
|
|
513
|
-
...
|
|
561
|
+
...variantHeaders,
|
|
514
562
|
...extraHeaders,
|
|
563
|
+
...representationHeaders,
|
|
515
564
|
"Accept-Ranges": "bytes"
|
|
516
565
|
};
|
|
517
566
|
res.writeHead(responseStatus, variesByEncoding ? mergeVaryHeader(responseHeaders, "Accept-Encoding") : responseHeaders);
|
|
@@ -549,8 +598,6 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
549
598
|
const isHashed = pathname.includes(`/${ASSET_PREFIX_URL_DIR}/`);
|
|
550
599
|
const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
|
|
551
600
|
const etag = isHashed && etagFromFilenameHash(resolved.path, ext) || `W/"${resolved.size}-${Math.floor(resolved.mtimeMs / 1e3)}"`;
|
|
552
|
-
const baseType = ct.split(";")[0].trim();
|
|
553
|
-
const isCompressible = compress && COMPRESSIBLE_TYPES.has(baseType);
|
|
554
601
|
const baseHeaders = {
|
|
555
602
|
"Content-Type": ct,
|
|
556
603
|
"Cache-Control": cacheControl,
|
|
@@ -559,7 +606,12 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
559
606
|
"Accept-Ranges": "bytes",
|
|
560
607
|
...extraHeaders
|
|
561
608
|
};
|
|
562
|
-
const
|
|
609
|
+
const { varyAcceptEncoding: isCompressible, encoding } = resolveResponseCompression(req, compress, {
|
|
610
|
+
contentType: ct,
|
|
611
|
+
cacheControl: (extraHeaders && readHeaderCaseInsensitive(extraHeaders, "cache-control")) ?? cacheControl,
|
|
612
|
+
contentEncoding: extraHeaders && readHeaderCaseInsensitive(extraHeaders, "content-encoding"),
|
|
613
|
+
contentLength: resolved.size
|
|
614
|
+
});
|
|
563
615
|
const validators = extraHeaders ? resolveStaticValidators(etag, resolved.mtimeMs, extraHeaders) : void 0;
|
|
564
616
|
const effectiveEtag = validators ? validators.etag : etag;
|
|
565
617
|
const effectiveMtimeMs = validators ? validators.mtimeMs : resolved.mtimeMs;
|
|
@@ -595,6 +647,7 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
595
647
|
const length = range.end - range.start + 1;
|
|
596
648
|
const rangeHeaders = {
|
|
597
649
|
...baseHeaders,
|
|
650
|
+
...representationHeaders,
|
|
598
651
|
"Content-Length": String(length),
|
|
599
652
|
"Content-Range": `bytes ${range.start}-${range.end}/${resolved.size}`
|
|
600
653
|
};
|
|
@@ -609,6 +662,7 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
609
662
|
if (isCompressible && encoding !== "identity") {
|
|
610
663
|
res.writeHead(responseStatus, mergeVaryHeader({
|
|
611
664
|
...baseHeaders,
|
|
665
|
+
...representationHeaders,
|
|
612
666
|
"Content-Encoding": encoding
|
|
613
667
|
}, "Accept-Encoding"));
|
|
614
668
|
if (omitBody || req.method === "HEAD") {
|
|
@@ -626,6 +680,7 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
626
680
|
}
|
|
627
681
|
const identityHeaders = {
|
|
628
682
|
...baseHeaders,
|
|
683
|
+
...representationHeaders,
|
|
629
684
|
"Content-Length": String(resolved.size)
|
|
630
685
|
};
|
|
631
686
|
res.writeHead(responseStatus, isCompressible ? mergeVaryHeader(identityHeaders, "Accept-Encoding") : identityHeaders);
|
|
@@ -734,7 +789,7 @@ async function statIfFile(filePath) {
|
|
|
734
789
|
* When `urlOverride` is provided, it is used as the path + query string
|
|
735
790
|
* instead of `req.url`.
|
|
736
791
|
*/
|
|
737
|
-
function nodeToWebRequest(req, urlOverride, prerenderSecret, i18nConfig, authorizeOnDemandRevalidate) {
|
|
792
|
+
function nodeToWebRequest(req, urlOverride, prerenderSecret, i18nConfig, authorizeOnDemandRevalidate, signal) {
|
|
738
793
|
const proto = resolveRequestProtocol(req);
|
|
739
794
|
const rawHeaders = nodeHeadersToWebHeaders(req.headers);
|
|
740
795
|
const revalidationHostname = readTrustedRevalidationHostname(rawHeaders, i18nConfig, authorizeOnDemandRevalidate);
|
|
@@ -751,9 +806,10 @@ function nodeToWebRequest(req, urlOverride, prerenderSecret, i18nConfig, authori
|
|
|
751
806
|
const hasBody = method !== "GET" && method !== "HEAD";
|
|
752
807
|
const init = {
|
|
753
808
|
method,
|
|
754
|
-
headers
|
|
809
|
+
headers,
|
|
810
|
+
signal
|
|
755
811
|
};
|
|
756
|
-
if (hasBody) {
|
|
812
|
+
if (hasBody && !signal?.aborted) {
|
|
757
813
|
init.body = readNodeStream(req);
|
|
758
814
|
init.duplex = "half";
|
|
759
815
|
}
|
|
@@ -776,22 +832,23 @@ async function sendWebResponse(webResponse, req, res, compress) {
|
|
|
776
832
|
if (existing !== void 0) nodeHeaders[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
777
833
|
else nodeHeaders[key] = value;
|
|
778
834
|
});
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
}
|
|
785
|
-
const
|
|
786
|
-
const varyByEncoding = compress && !alreadyEncoded && COMPRESSIBLE_TYPES.has(baseType);
|
|
787
|
-
const encoding = compress && !alreadyEncoded ? negotiateEncoding(req) : "identity";
|
|
788
|
-
const shouldCompress = encoding !== "identity" && COMPRESSIBLE_TYPES.has(baseType);
|
|
835
|
+
const { varyAcceptEncoding: varyByEncoding, encoding } = resolveResponseCompression(req, compress, {
|
|
836
|
+
contentType: webResponse.headers.get("content-type"),
|
|
837
|
+
cacheControl: webResponse.headers.get("cache-control"),
|
|
838
|
+
contentEncoding: webResponse.headers.get("content-encoding"),
|
|
839
|
+
contentLength: webResponse.body ? parseContentLengthHeader(webResponse.headers.get("content-length")) : 0
|
|
840
|
+
});
|
|
841
|
+
const shouldCompress = encoding !== "identity";
|
|
789
842
|
if (shouldCompress) {
|
|
790
843
|
delete nodeHeaders["content-length"];
|
|
791
|
-
delete nodeHeaders["
|
|
844
|
+
delete nodeHeaders["content-encoding"];
|
|
792
845
|
nodeHeaders["Content-Encoding"] = encoding;
|
|
793
846
|
}
|
|
794
847
|
writeHead(varyByEncoding ? mergeVaryHeader(nodeHeaders, "Accept-Encoding") : nodeHeaders);
|
|
848
|
+
if (!webResponse.body) {
|
|
849
|
+
res.end();
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
795
852
|
if (req.method === "HEAD") {
|
|
796
853
|
cancelResponseBody(webResponse);
|
|
797
854
|
res.end();
|
|
@@ -832,7 +889,7 @@ function waitForNodeResponseCompletion(res) {
|
|
|
832
889
|
* Pages Router (dist/server/entry.js) and configures the appropriate handler.
|
|
833
890
|
*/
|
|
834
891
|
async function startProdServer(options = {}) {
|
|
835
|
-
installSocketErrorBackstop();
|
|
892
|
+
installSocketErrorBackstop({ runningServer: options.purpose !== "prerender" });
|
|
836
893
|
const { port = process.env.PORT ? parseInt(process.env.PORT) : 3e3, host = "0.0.0.0", outDir = path.resolve("dist"), rscEntryPath: explicitRscEntryPath, serverDir: explicitServerDir, serverEntryPath: explicitServerEntryPath, noCompression = false, purpose, silent = false } = options;
|
|
837
894
|
if (purpose === "prerender") registerPrerenderCloudflareLoader();
|
|
838
895
|
const compress = !noCompression;
|
|
@@ -861,6 +918,7 @@ async function startProdServer(options = {}) {
|
|
|
861
918
|
port,
|
|
862
919
|
host,
|
|
863
920
|
clientDir,
|
|
921
|
+
serverDir,
|
|
864
922
|
serverEntryPath,
|
|
865
923
|
compress,
|
|
866
924
|
purpose,
|
|
@@ -877,6 +935,23 @@ function createNodeExecutionContext(trustedRevalidateOrigin) {
|
|
|
877
935
|
trustedRevalidateOrigin
|
|
878
936
|
};
|
|
879
937
|
}
|
|
938
|
+
/**
|
|
939
|
+
* Sets the prerender special-error marker only from the page's recorded
|
|
940
|
+
* special error, which middleware, route handlers and external rewrites can't
|
|
941
|
+
* reach, and drops one they set.
|
|
942
|
+
*/
|
|
943
|
+
function markPrerenderSpecialError(response, marker) {
|
|
944
|
+
const trusted = marker !== void 0 && marker.status === response.status;
|
|
945
|
+
if (!trusted && !response.headers.has("x-vinext-prerender-special-error")) return response;
|
|
946
|
+
const headers = new Headers(response.headers);
|
|
947
|
+
headers.delete(VINEXT_PRERENDER_SPECIAL_ERROR_HEADER);
|
|
948
|
+
if (trusted) headers.set(VINEXT_PRERENDER_SPECIAL_ERROR_HEADER, JSON.stringify(marker.headers));
|
|
949
|
+
return new Response(response.body, {
|
|
950
|
+
headers,
|
|
951
|
+
status: response.status,
|
|
952
|
+
statusText: response.statusText
|
|
953
|
+
});
|
|
954
|
+
}
|
|
880
955
|
function resolveTrustedNodeRevalidateOrigin(req, configuredHost, configuredPort) {
|
|
881
956
|
const port = req.socket.localPort ?? configuredPort;
|
|
882
957
|
return `http://${normalizeInternalFetchHost(configuredHost)}:${port}`;
|
|
@@ -1008,8 +1083,9 @@ function installPagesClientAssets(options) {
|
|
|
1008
1083
|
* 4. Stream the Web Response back (with optional compression)
|
|
1009
1084
|
*/
|
|
1010
1085
|
async function startAppRouterServer(options) {
|
|
1011
|
-
const { port, host, clientDir, serverDir, rscEntryPath, compress, purpose, silent } = options;
|
|
1086
|
+
const { port, host, clientDir, serverDir, rscEntryPath, compress: compressOption, purpose, silent } = options;
|
|
1012
1087
|
const prerenderSecret = readPrerenderSecret(serverDir);
|
|
1088
|
+
const compress = compressOption && readServerCompress(serverDir);
|
|
1013
1089
|
const rscModule = await importServerEntryModule(rscEntryPath);
|
|
1014
1090
|
const rscEntryRequire = createServerEntryRequire(rscEntryPath);
|
|
1015
1091
|
const rscHandler = resolveAppRouterHandler(rscModule.default);
|
|
@@ -1045,9 +1121,63 @@ async function startAppRouterServer(options) {
|
|
|
1045
1121
|
const seededRoutes = await runWithServerEntryRequire(rscEntryRequire, () => seedPrerenderedRoutes(serverDir));
|
|
1046
1122
|
if (seededRoutes > 0) console.log(`[vinext] Seeded ${seededRoutes} pre-rendered route${seededRoutes !== 1 ? "s" : ""} into memory cache`);
|
|
1047
1123
|
const staticCache = await StaticFileCache.create(clientDir);
|
|
1124
|
+
const serveImageOptimization = async (req, res, request, signal) => {
|
|
1125
|
+
const stagedHeaders = omitHeadersCaseInsensitive(mergeResponseHeaders({}, new Response(null, { headers: signal.middlewareHeaders })), OMIT_STATIC_RESPONSE_HEADERS);
|
|
1126
|
+
for (const [name, value] of Object.entries(stagedHeaders)) res.setHeader(name, value);
|
|
1127
|
+
const parsedUrl = new URL(`/${signal.search}`, "http://localhost");
|
|
1128
|
+
const params = parseImageParams(parsedUrl, appImageAllowedWidths, imageConfig?.qualities);
|
|
1129
|
+
if (!params) {
|
|
1130
|
+
res.writeHead(400);
|
|
1131
|
+
res.end("Bad Request");
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
const sendUnsafeContentType = () => {
|
|
1135
|
+
res.writeHead(400);
|
|
1136
|
+
res.end("The requested resource is not an allowed image type");
|
|
1137
|
+
};
|
|
1138
|
+
const isSafeSourcePath = (sourcePath) => isSafeImageContentType(contentTypeForPath(sourcePath), imageConfig?.dangerouslyAllowSVG);
|
|
1139
|
+
const imageSecurityHeaders = {
|
|
1140
|
+
"Content-Security-Policy": imageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
1141
|
+
"X-Content-Type-Options": "nosniff",
|
|
1142
|
+
"Content-Disposition": imageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1143
|
+
};
|
|
1144
|
+
const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, imageSecurityHeaders, void 0, IMAGE_REPRESENTATION_HEADERS);
|
|
1145
|
+
const sourceUrl = new URL(params.imageUrl, request.url);
|
|
1146
|
+
let sourcePathname = null;
|
|
1147
|
+
try {
|
|
1148
|
+
sourcePathname = normalizePath(normalizePathnameForRouteMatchStrict(sourceUrl.pathname));
|
|
1149
|
+
} catch {}
|
|
1150
|
+
if (!isSafeSourcePath(sourcePathname ?? params.imageUrl)) {
|
|
1151
|
+
sendUnsafeContentType();
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
const assetLookupPath = sourcePathname !== null ? resolveAppRouterAssetPath(sourcePathname, appAssetPathPrefix, appRouterAssetPrefix) : null;
|
|
1155
|
+
if (assetLookupPath && await serveSource(assetLookupPath)) return;
|
|
1156
|
+
if (sourcePathname !== null) {
|
|
1157
|
+
const sourceResponse = await rscHandler(new Request(sourceUrl, { signal: request.signal }), createNodeExecutionContext(resolveTrustedNodeRevalidateOrigin(req, host, port)));
|
|
1158
|
+
const sourceSignal = isImageSourceBodyStatus(sourceResponse.status) ? readStaticFileSignal(sourceResponse) : null;
|
|
1159
|
+
cancelResponseBody(sourceResponse, request.signal.reason);
|
|
1160
|
+
if (request.signal.aborted) return;
|
|
1161
|
+
if (sourceSignal !== null) {
|
|
1162
|
+
let sourcePath = sourceSignal;
|
|
1163
|
+
try {
|
|
1164
|
+
sourcePath = decodeURIComponent(sourceSignal);
|
|
1165
|
+
} catch {}
|
|
1166
|
+
if (!isSafeSourcePath(sourcePath)) {
|
|
1167
|
+
sendUnsafeContentType();
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
if (await serveSource(sourcePath)) return;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
res.writeHead(400);
|
|
1174
|
+
res.end(INVALID_IMAGE_SOURCE_MESSAGE);
|
|
1175
|
+
};
|
|
1176
|
+
const clientBuildFiles = new Set(Array.isArray(rscModule.__clientBuildFiles) ? rscModule.__clientBuildFiles : []);
|
|
1048
1177
|
const handleRequestImpl = async (req, res) => {
|
|
1049
1178
|
const rawUrl = req.url ?? "/";
|
|
1050
1179
|
const rawPathname = rawUrl.split("?")[0];
|
|
1180
|
+
if (sendRepeatedSlashRedirect(rawUrl, res)) return;
|
|
1051
1181
|
if (isOpenRedirectShaped(rawPathname)) {
|
|
1052
1182
|
res.writeHead(404);
|
|
1053
1183
|
res.end("This page could not be found");
|
|
@@ -1076,33 +1206,28 @@ async function startAppRouterServer(options) {
|
|
|
1076
1206
|
if (await tryServeStatic(req, res, clientDir, assetLookupPath, compress, staticCache)) return;
|
|
1077
1207
|
}
|
|
1078
1208
|
}
|
|
1079
|
-
if (
|
|
1080
|
-
const
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1209
|
+
if (req.method === "GET" || req.method === "HEAD") {
|
|
1210
|
+
const clientBuildFile = resolveClientBuildFile(normalizedRawPathname, appRouterBasePath, clientBuildFiles);
|
|
1211
|
+
if (clientBuildFile && await tryServeStatic(req, res, clientDir, clientBuildFile, compress, staticCache)) return;
|
|
1212
|
+
}
|
|
1213
|
+
try {
|
|
1214
|
+
const request = nodeToWebRequest(req, rawUrl, prerenderSecret, appRouterI18nConfig, appRouterAuthorizeOnDemandRevalidate, signalFromNodeResponse(res));
|
|
1215
|
+
const ctx = createNodeExecutionContext(resolveTrustedNodeRevalidateOrigin(req, host, port));
|
|
1216
|
+
const recorded = {};
|
|
1217
|
+
if (purpose === "prerender") ctx.recordPrerenderSpecialError = (marker) => {
|
|
1218
|
+
recorded.marker = marker;
|
|
1219
|
+
};
|
|
1220
|
+
const response = await rscHandler(request, ctx);
|
|
1221
|
+
if (request.signal.aborted) {
|
|
1222
|
+
cancelResponseBody(response, request.signal.reason);
|
|
1085
1223
|
return;
|
|
1086
1224
|
}
|
|
1087
|
-
const
|
|
1088
|
-
if (
|
|
1089
|
-
|
|
1090
|
-
|
|
1225
|
+
const imageSignal = readImageOptimizationSignal(response);
|
|
1226
|
+
if (imageSignal) {
|
|
1227
|
+
cancelResponseBody(response);
|
|
1228
|
+
await serveImageOptimization(req, res, request, imageSignal);
|
|
1091
1229
|
return;
|
|
1092
1230
|
}
|
|
1093
|
-
const imageSecurityHeaders = {
|
|
1094
|
-
"Content-Security-Policy": imageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
1095
|
-
"X-Content-Type-Options": "nosniff",
|
|
1096
|
-
"Content-Disposition": imageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1097
|
-
};
|
|
1098
|
-
if (await tryServeStatic(req, res, clientDir, params.imageUrl, false, staticCache, imageSecurityHeaders)) return;
|
|
1099
|
-
res.writeHead(404);
|
|
1100
|
-
res.end("Image not found");
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
try {
|
|
1104
|
-
const request = nodeToWebRequest(req, rawUrl, prerenderSecret, appRouterI18nConfig, appRouterAuthorizeOnDemandRevalidate);
|
|
1105
|
-
const response = await rscHandler(request, createNodeExecutionContext(resolveTrustedNodeRevalidateOrigin(req, host, port)));
|
|
1106
1231
|
const staticFileSignal = readStaticFileSignal(response);
|
|
1107
1232
|
if (staticFileSignal) {
|
|
1108
1233
|
let staticFilePath = "/";
|
|
@@ -1118,7 +1243,7 @@ async function startAppRouterServer(options) {
|
|
|
1118
1243
|
await sendWebResponse(notFoundResponse({ headers: toWebHeaders(staticResponseHeaders) }), req, res, compress);
|
|
1119
1244
|
return;
|
|
1120
1245
|
}
|
|
1121
|
-
await sendWebResponse(response, req, res, compress);
|
|
1246
|
+
await sendWebResponse(purpose === "prerender" ? markPrerenderSpecialError(response, recorded.marker) : response, req, res, compress);
|
|
1122
1247
|
} catch (e) {
|
|
1123
1248
|
console.error("[vinext] Server error:", e);
|
|
1124
1249
|
if (!res.headersSent) {
|
|
@@ -1149,7 +1274,7 @@ async function startAppRouterServer(options) {
|
|
|
1149
1274
|
},
|
|
1150
1275
|
getStatus: () => res.statusCode,
|
|
1151
1276
|
headers,
|
|
1152
|
-
isRsc:
|
|
1277
|
+
isRsc: target.split("?", 1)[0].endsWith(".rsc") || headers.get("RSC") === "1",
|
|
1153
1278
|
method: req.method ?? "GET",
|
|
1154
1279
|
target
|
|
1155
1280
|
});
|
|
@@ -1195,7 +1320,45 @@ function readPagesServerEntryPageRoutes(value) {
|
|
|
1195
1320
|
* - vinextConfig — embedded next.config.js settings
|
|
1196
1321
|
*/
|
|
1197
1322
|
async function startPagesRouterServer(options) {
|
|
1198
|
-
const { port, host,
|
|
1323
|
+
const { port, host, purpose, silent } = options;
|
|
1324
|
+
const handler = await createPagesRouterRequestHandler(options);
|
|
1325
|
+
const server = createServer(handler);
|
|
1326
|
+
await new Promise((resolve) => {
|
|
1327
|
+
server.listen(port, host, () => {
|
|
1328
|
+
const addr = server.address();
|
|
1329
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
1330
|
+
if (!silent) logProdServerStarted(host, actualPort, purpose);
|
|
1331
|
+
resolve();
|
|
1332
|
+
});
|
|
1333
|
+
});
|
|
1334
|
+
const addr = server.address();
|
|
1335
|
+
return {
|
|
1336
|
+
server,
|
|
1337
|
+
port: typeof addr === "object" && addr ? addr.port : port
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Create the Pages Router request handler for `vite preview`. Vite's preview
|
|
1342
|
+
* middleware (proxy, compression, `base`, static files) runs first, so this
|
|
1343
|
+
* handles only the requests Vite doesn't serve and leaves compression to Vite.
|
|
1344
|
+
* Resolves to null when the build has no Pages Router server entry.
|
|
1345
|
+
*/
|
|
1346
|
+
async function createPagesPreviewHandler(options) {
|
|
1347
|
+
const clientDir = path.resolve(options.clientDir);
|
|
1348
|
+
const serverDir = path.resolve(options.serverDir);
|
|
1349
|
+
const serverEntryPath = path.join(serverDir, "entry.js");
|
|
1350
|
+
if (!fs.existsSync(serverEntryPath)) return null;
|
|
1351
|
+
return createPagesRouterRequestHandler({
|
|
1352
|
+
port: options.port,
|
|
1353
|
+
host: options.host,
|
|
1354
|
+
clientDir,
|
|
1355
|
+
serverDir,
|
|
1356
|
+
serverEntryPath,
|
|
1357
|
+
compress: false
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
async function createPagesRouterRequestHandler(options) {
|
|
1361
|
+
const { port, host, clientDir, serverDir, serverEntryPath, compress: compressOption, purpose } = options;
|
|
1199
1362
|
const serverEntry = await importServerEntryModule(serverEntryPath);
|
|
1200
1363
|
const serverEntryRequire = createServerEntryRequire(serverEntryPath);
|
|
1201
1364
|
const { renderPage, handleApiRoute: handleApi, authorizeOnDemandRevalidate, runMiddleware, vinextConfig, buildId: pagesBuildId } = serverEntry;
|
|
@@ -1205,11 +1368,13 @@ async function startPagesRouterServer(options) {
|
|
|
1205
1368
|
const hasMiddleware = serverEntry.hasMiddleware === true;
|
|
1206
1369
|
const pageRoutes = readPagesServerEntryPageRoutes(serverEntry.pageRoutes);
|
|
1207
1370
|
const prerenderSecret = readPrerenderSecret(path.dirname(serverEntryPath));
|
|
1371
|
+
const compress = compressOption && readServerCompress(serverDir);
|
|
1208
1372
|
const basePath = vinextConfig?.basePath ?? "";
|
|
1209
1373
|
const assetPrefix = vinextConfig?.assetPrefix ?? "";
|
|
1210
1374
|
const pagesAssetPathPrefix = assetPrefixPathname(assetPrefix);
|
|
1211
1375
|
const assetBase = basePath ? `${basePath}/` : "/";
|
|
1212
1376
|
const trailingSlash = vinextConfig?.trailingSlash ?? false;
|
|
1377
|
+
const skipTrailingSlashRedirect = vinextConfig?.skipTrailingSlashRedirect ?? false;
|
|
1213
1378
|
const skipProxyUrlNormalize = vinextConfig?.skipProxyUrlNormalize ?? false;
|
|
1214
1379
|
const i18nConfig = vinextConfig?.i18n ?? null;
|
|
1215
1380
|
const configRedirects = vinextConfig?.redirects ?? [];
|
|
@@ -1261,6 +1426,7 @@ async function startPagesRouterServer(options) {
|
|
|
1261
1426
|
const handleRequestImpl = async (req, res) => {
|
|
1262
1427
|
const rawUrl = req.url ?? "/";
|
|
1263
1428
|
const rawPagesPathnameBeforeNormalize = rawUrl.split("?")[0];
|
|
1429
|
+
if (sendRepeatedSlashRedirect(rawUrl, res)) return;
|
|
1264
1430
|
if (isOpenRedirectShaped(rawPagesPathnameBeforeNormalize)) {
|
|
1265
1431
|
res.writeHead(404);
|
|
1266
1432
|
res.end("This page could not be found");
|
|
@@ -1366,18 +1532,55 @@ async function startPagesRouterServer(options) {
|
|
|
1366
1532
|
const reqHeaders = filterInternalHeaders(rawReqHeaders);
|
|
1367
1533
|
if (revalidationHostname) reqHeaders.set("host", revalidationHostname);
|
|
1368
1534
|
const method = req.method ?? "GET";
|
|
1369
|
-
const
|
|
1370
|
-
const
|
|
1535
|
+
const signal = signalFromNodeResponse(res);
|
|
1536
|
+
const hasBody = method !== "GET" && method !== "HEAD" && !signal.aborted;
|
|
1537
|
+
const requestOrigin = `${protocol}://${revalidationHostname ?? hostHeader}`;
|
|
1538
|
+
const webRequest = new Request(new URL(url, requestOrigin), {
|
|
1371
1539
|
method,
|
|
1372
1540
|
headers: reqHeaders,
|
|
1541
|
+
signal,
|
|
1373
1542
|
body: hasBody ? readNodeStream(req) : void 0,
|
|
1374
1543
|
duplex: hasBody ? "half" : void 0
|
|
1375
1544
|
});
|
|
1376
1545
|
const middlewareRequest = isDataReq && skipProxyUrlNormalize ? new Request(new URL(originalRenderUrl, webRequest.url), webRequest) : void 0;
|
|
1546
|
+
const resolvePublicImageSource = async (sourceUrl) => {
|
|
1547
|
+
const rawSourcePathname = sourceUrl.pathname;
|
|
1548
|
+
if (getRepeatedSlashRedirect(rawSourcePathname) || isOpenRedirectShaped(rawSourcePathname)) return null;
|
|
1549
|
+
const sourceRequestPathname = normalizePath(rawSourcePathname);
|
|
1550
|
+
const sourceHadBasePath = !basePath || hasBasePath(sourceRequestPathname, basePath);
|
|
1551
|
+
const strippedSourcePathname = stripBasePath(sourceRequestPathname, basePath);
|
|
1552
|
+
if (isNextDataPathname(strippedSourcePathname)) return null;
|
|
1553
|
+
let sourcePath = null;
|
|
1554
|
+
const result = await runPagesRequest(new Request(new URL(strippedSourcePathname + sourceUrl.search, sourceUrl), { signal: webRequest.signal }), {
|
|
1555
|
+
...deps,
|
|
1556
|
+
hadBasePath: sourceHadBasePath,
|
|
1557
|
+
isDataReq: false,
|
|
1558
|
+
isDataRequest: false,
|
|
1559
|
+
middlewareRequest: void 0,
|
|
1560
|
+
dataNotFoundResponse: null,
|
|
1561
|
+
recordCacheability: false,
|
|
1562
|
+
rawSearch: sourceUrl.search,
|
|
1563
|
+
configMatchPathname: strippedSourcePathname,
|
|
1564
|
+
runMiddleware: typeof runMiddleware === "function" ? wrapMiddlewareWithBasePath(runMiddleware, basePath, sourceHadBasePath) : null,
|
|
1565
|
+
renderPage: null,
|
|
1566
|
+
handleApi: null,
|
|
1567
|
+
serveFilesystemRoute: async (candidate, _stagedHeaders, phase) => {
|
|
1568
|
+
if (isImageOptimizationPath(candidate) || isPagesFilesystemExcludedPath(candidate, phase)) return false;
|
|
1569
|
+
const lookupPath = staticCacheLookupPath(candidate);
|
|
1570
|
+
if (lookupPath === null || lookupPath === "/" || !staticCache.lookup(lookupPath)) return false;
|
|
1571
|
+
sourcePath = candidate;
|
|
1572
|
+
return new Response(null);
|
|
1573
|
+
}
|
|
1574
|
+
});
|
|
1575
|
+
if (result.type !== "response") return null;
|
|
1576
|
+
cancelResponseBody(result.response);
|
|
1577
|
+
return isImageSourceBodyStatus(result.response.status) ? sourcePath : null;
|
|
1578
|
+
};
|
|
1377
1579
|
const deps = {
|
|
1378
1580
|
assetPrefix,
|
|
1379
1581
|
basePath,
|
|
1380
1582
|
trailingSlash,
|
|
1583
|
+
skipTrailingSlashRedirect,
|
|
1381
1584
|
i18nConfig,
|
|
1382
1585
|
configRedirects,
|
|
1383
1586
|
configRewrites,
|
|
@@ -1400,8 +1603,8 @@ async function startPagesRouterServer(options) {
|
|
|
1400
1603
|
originalUrl: originalRenderUrl
|
|
1401
1604
|
}, stagedHeaders?.has("Cache-Control") ? new Headers({ "Cache-Control": stagedHeaders.get("Cache-Control") }) : void 0) : null,
|
|
1402
1605
|
handleApi: typeof handleApi === "function" ? (request, apiUrl) => handleApi(request, apiUrl, createNodeExecutionContext(), resolveTrustedNodeRevalidateOrigin(req, host, port), "node") : null,
|
|
1403
|
-
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl) => {
|
|
1404
|
-
if (isImageOptimizationPath(requestPathname)) {
|
|
1606
|
+
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl, _request, resolvedPathnameHasBasePath) => {
|
|
1607
|
+
if (resolvedPathnameHasBasePath && isImageOptimizationPath(requestPathname)) {
|
|
1405
1608
|
for (const [name, value] of Object.entries(stagedHeaders)) res.setHeader(name, value);
|
|
1406
1609
|
const parsedUrl = new URL(resolvedUrl, "http://localhost");
|
|
1407
1610
|
const params = parseImageParams(parsedUrl, allowedImageWidths, pagesImageConfig?.qualities);
|
|
@@ -1410,23 +1613,42 @@ async function startPagesRouterServer(options) {
|
|
|
1410
1613
|
res.end("Bad Request");
|
|
1411
1614
|
return true;
|
|
1412
1615
|
}
|
|
1413
|
-
const
|
|
1414
|
-
if (!isSafeImageContentType(ct, pagesImageConfig?.dangerouslyAllowSVG)) {
|
|
1616
|
+
const sendUnsafeContentType = () => {
|
|
1415
1617
|
res.writeHead(400);
|
|
1416
1618
|
res.end("The requested resource is not an allowed image type");
|
|
1417
|
-
|
|
1418
|
-
|
|
1619
|
+
};
|
|
1620
|
+
const isSafeSourcePath = (sourcePath) => isSafeImageContentType(contentTypeForPath(sourcePath), pagesImageConfig?.dangerouslyAllowSVG);
|
|
1419
1621
|
const imageSecurityHeaders = {
|
|
1420
1622
|
"Content-Security-Policy": pagesImageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
1421
1623
|
"X-Content-Type-Options": "nosniff",
|
|
1422
1624
|
"Content-Disposition": pagesImageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1423
1625
|
};
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1626
|
+
const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, imageSecurityHeaders, void 0, IMAGE_REPRESENTATION_HEADERS);
|
|
1627
|
+
const sourceUrl = new URL(params.imageUrl, webRequest.url);
|
|
1628
|
+
let sourcePathname = null;
|
|
1629
|
+
try {
|
|
1630
|
+
sourcePathname = normalizePath(normalizePathnameForRouteMatchStrict(sourceUrl.pathname));
|
|
1631
|
+
} catch {}
|
|
1632
|
+
if (!isSafeSourcePath(sourcePathname ?? params.imageUrl)) {
|
|
1633
|
+
sendUnsafeContentType();
|
|
1634
|
+
return true;
|
|
1635
|
+
}
|
|
1636
|
+
const assetLookupPath = sourcePathname !== null ? resolveAppRouterAssetPath(sourcePathname, pagesAssetPathPrefix, assetPrefix) : null;
|
|
1637
|
+
if (assetLookupPath && await serveSource(assetLookupPath)) return true;
|
|
1638
|
+
const sourcePath = sourcePathname !== null ? await resolvePublicImageSource(sourceUrl) : null;
|
|
1639
|
+
if (webRequest.signal.aborted) return true;
|
|
1640
|
+
if (sourcePath !== null) {
|
|
1641
|
+
if (!isSafeSourcePath(staticCacheLookupPath(sourcePath) ?? sourcePath)) {
|
|
1642
|
+
sendUnsafeContentType();
|
|
1643
|
+
return true;
|
|
1644
|
+
}
|
|
1645
|
+
if (await serveSource(sourcePath)) return true;
|
|
1646
|
+
}
|
|
1647
|
+
res.writeHead(400);
|
|
1648
|
+
res.end(INVALID_IMAGE_SOURCE_MESSAGE);
|
|
1427
1649
|
return true;
|
|
1428
1650
|
}
|
|
1429
|
-
if (requestPathname
|
|
1651
|
+
if (isPagesFilesystemExcludedPath(requestPathname, phase)) return false;
|
|
1430
1652
|
return tryServeStatic(req, res, clientDir, requestPathname, compress, staticCache, stagedHeaders);
|
|
1431
1653
|
}
|
|
1432
1654
|
};
|
|
@@ -1434,13 +1656,18 @@ async function startPagesRouterServer(options) {
|
|
|
1434
1656
|
if (result.type === "handled") return;
|
|
1435
1657
|
if (result.type === "response") {
|
|
1436
1658
|
const { response } = result;
|
|
1659
|
+
if (webRequest.signal.aborted) {
|
|
1660
|
+
cancelResponseBody(response, webRequest.signal.reason);
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1437
1663
|
const streamedApi = isVinextStreamedApiResponse(response);
|
|
1438
1664
|
if (isVinextStreamedHtmlResponse(response) || streamedApi || !response.body || result.defaultContentType === void 0) {
|
|
1439
1665
|
if (streamedApi && result.defaultContentType !== void 0 && !response.headers.has("content-type")) response.headers.set("content-type", result.defaultContentType);
|
|
1440
1666
|
await sendWebResponse(response, req, res, compress);
|
|
1441
1667
|
return;
|
|
1442
1668
|
}
|
|
1443
|
-
const responseBody =
|
|
1669
|
+
const responseBody = await bufferResponseBodyUntilAborted(response, webRequest.signal);
|
|
1670
|
+
if (!responseBody) return;
|
|
1444
1671
|
const ct = response.headers.get("content-type") ?? result.defaultContentType;
|
|
1445
1672
|
const responseHeaders = {};
|
|
1446
1673
|
response.headers.forEach((v, k) => {
|
|
@@ -1464,22 +1691,9 @@ async function startPagesRouterServer(options) {
|
|
|
1464
1691
|
}
|
|
1465
1692
|
}
|
|
1466
1693
|
};
|
|
1467
|
-
|
|
1694
|
+
return (req, res) => {
|
|
1468
1695
|
runWithServerEntryRequire(serverEntryRequire, () => handleRequest(req, res));
|
|
1469
|
-
});
|
|
1470
|
-
await new Promise((resolve) => {
|
|
1471
|
-
server.listen(port, host, () => {
|
|
1472
|
-
const addr = server.address();
|
|
1473
|
-
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
1474
|
-
if (!silent) logProdServerStarted(host, actualPort, purpose);
|
|
1475
|
-
resolve();
|
|
1476
|
-
});
|
|
1477
|
-
});
|
|
1478
|
-
const addr = server.address();
|
|
1479
|
-
return {
|
|
1480
|
-
server,
|
|
1481
|
-
port: typeof addr === "object" && addr ? addr.port : port
|
|
1482
1696
|
};
|
|
1483
1697
|
}
|
|
1484
1698
|
//#endregion
|
|
1485
|
-
export {
|
|
1699
|
+
export { COMPRESS_THRESHOLD, createPagesPreviewHandler, importServerEntryModule, isCompressibleContentType, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, readNodeStream, rememberCurrentServerEntryImportMtime, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic, waitForNodeResponseCompletion };
|