vinext 1.1.0 → 1.2.1
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 +22 -10
- package/dist/build/client-build-config.d.ts +10 -0
- package/dist/build/client-build-config.js +18 -2
- package/dist/build/output-root-externals.d.ts +21 -0
- package/dist/build/output-root-externals.js +40 -0
- 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 +6 -4
- package/dist/build/prerender.js +1 -1
- 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 +12 -12
- package/dist/cli-dev-config.js +3 -3
- package/dist/cli.js +3 -2
- 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 +90 -88
- 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 +246 -136
- 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 +2 -1
- package/dist/init.js +153 -9
- package/dist/plugins/ast-scope.d.ts +7 -0
- package/dist/plugins/ast-scope.js +59 -3
- package/dist/plugins/ast-utils.d.ts +53 -2
- package/dist/plugins/ast-utils.js +90 -2
- package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
- package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
- package/dist/plugins/commonjs-esm-facade.js +2 -2
- package/dist/plugins/css-module-imports.js +13 -20
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +11 -11
- package/dist/plugins/extensionless-dynamic-import.js +2 -3
- package/dist/plugins/fonts.d.ts +1 -1
- package/dist/plugins/fonts.js +3 -3
- package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +5 -7
- package/dist/plugins/import-meta-url.js +3 -4
- package/dist/plugins/instrumentation-client.js +3 -2
- package/dist/plugins/middleware-export-validation.js +2 -3
- package/dist/plugins/middleware-server-only.d.ts +5 -4
- package/dist/plugins/middleware-server-only.js +8 -5
- package/dist/plugins/og-harfbuzz.js +2 -3
- package/dist/plugins/optimize-imports.js +3 -4
- package/dist/plugins/pages-node-externals.js +3 -4
- package/dist/plugins/remove-console.js +2 -18
- package/dist/plugins/require-condition-resolution.js +3 -3
- package/dist/plugins/require-context.js +2 -3
- 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 +265 -102
- package/dist/plugins/styled-jsx.js +2 -3
- 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.d.ts +21 -2
- package/dist/plugins/use-cache-callable.js +84 -35
- package/dist/plugins/worker-image-imports.js +30 -33
- 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 +153 -0
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +3 -2
- package/dist/server/app-action-forwarding.js +2 -2
- 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 +3 -3
- package/dist/server/app-browser-interception-context.js +1 -1
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-prefetch-response.js +2 -2
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-supplemental-refresh.js +1 -1
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +17 -2
- package/dist/server/app-optimistic-routing.js +1 -1
- 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 +5 -4
- 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-render.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 +3 -4
- package/dist/server/app-prerender-endpoints.js +9 -6
- package/dist/server/app-render-abort-error.d.ts +19 -0
- package/dist/server/app-render-abort-error.js +31 -1
- package/dist/server/app-request-stage-dispatch.js +6 -2
- package/dist/server/app-request-stage-independent-entry.js +29 -9
- package/dist/server/app-response-stage-entry.js +11 -3
- 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 +46 -25
- package/dist/server/app-router-entry.js +29 -10
- package/dist/server/app-rsc-cache-busting.d.ts +16 -0
- package/dist/server/app-rsc-cache-busting.js +30 -13
- 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 +89 -39
- package/dist/server/app-rsc-request-normalization.js +3 -3
- package/dist/server/app-rsc-response-stage.js +5 -3
- 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.js +7 -5
- package/dist/server/app-visited-response-cache.js +2 -2
- 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/config-headers.js +1 -1
- package/dist/server/defer-until-stream-consumed.d.ts +2 -1
- package/dist/server/defer-until-stream-consumed.js +3 -1
- package/dist/server/dev-server.js +39 -28
- 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 +94 -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 +11 -10
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-path-to-regexp.js +1 -1
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +38 -25
- 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/navigation-planner.js +1 -1
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/open-redirect.d.ts +11 -4
- package/dist/server/open-redirect.js +11 -4
- package/dist/server/pages-api-route.d.ts +3 -2
- package/dist/server/pages-api-route.js +6 -5
- 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 +21 -3
- 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 +51 -121
- package/dist/server/pages-page-handler.d.ts +0 -6
- package/dist/server/pages-page-handler.js +189 -127
- package/dist/server/pages-page-response.d.ts +12 -6
- package/dist/server/pages-page-response.js +42 -35
- package/dist/server/pages-request-pipeline.d.ts +10 -2
- package/dist/server/pages-request-pipeline.js +41 -22
- package/dist/server/pages-request-stage-entry.d.ts +6 -0
- package/dist/server/pages-request-stage-entry.js +75 -16
- package/dist/server/pages-response-stage-entry.js +4 -0
- package/dist/server/pages-revalidate.js +3 -3
- package/dist/server/pages-router-entry.js +5 -4
- 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 +204 -74
- 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.d.ts +1 -1
- package/dist/server/rsc-stream-hints.js +52 -5
- 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 +99 -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 +16 -14
- package/dist/shims/headers.js +2 -2
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/hybrid-client-route-owner-direct.js +1 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +1 -0
- package/dist/shims/internal/work-store-scope.d.ts +5 -0
- package/dist/shims/internal/work-store-scope.js +24 -0
- package/dist/shims/link-prefetch.js +5 -4
- package/dist/shims/link.js +2 -2
- package/dist/shims/navigation.js +34 -9
- package/dist/shims/request-context.d.ts +2 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/router.js +21 -32
- package/dist/shims/server.d.ts +27 -4
- package/dist/shims/server.js +65 -9
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/url-utils.d.ts +9 -0
- package/dist/shims/url-utils.js +15 -4
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/domain-locale.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 +6 -0
- package/dist/utils/plugin-rsc-version.js +41 -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 +10 -0
- package/dist/utils/react-version.js +39 -16
- package/package.json +11 -7
- package/dist/build/nitro-route-rules.d.ts +0 -47
- package/dist/build/nitro-route-rules.js +0 -79
- package/dist/plugins/cache-flight-codec.d.ts +0 -19
- package/dist/plugins/cache-flight-codec.js +0 -68
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { isUnknownRecord } from "../utils/record.js";
|
|
3
3
|
import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
4
|
-
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
5
|
-
import { StaticFileCache, contentTypeForPath, etagFromFilenameHash } from "./static-file-cache.js";
|
|
6
|
-
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
7
4
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
8
5
|
import { VINEXT_PRERENDER_RENDER_ERROR_HEADER, VINEXT_PRERENDER_SPECIAL_ERROR_HEADER } from "./headers.js";
|
|
9
|
-
import { normalizePath } from "./normalize-path.js";
|
|
10
6
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
11
|
-
import { isOpenRedirectShaped, sendRepeatedSlashRedirect } from "./open-redirect.js";
|
|
7
|
+
import { getRepeatedSlashRedirect, isOpenRedirectShaped, sendRepeatedSlashRedirect } from "./open-redirect.js";
|
|
12
8
|
import { readStaticFileSignal } from "./static-file-signal.js";
|
|
13
9
|
import { canonicalizeRequestPathname, filterInternalHeaders } from "./request-pipeline.js";
|
|
10
|
+
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
11
|
+
import { StaticFileCache, contentTypeForPath, etagFromFilenameHash } from "./static-file-cache.js";
|
|
12
|
+
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
13
|
+
import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
14
|
+
import { normalizePath } from "./normalize-path.js";
|
|
15
|
+
import { buildNextDataNotFoundResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath } from "./pages-data-route.js";
|
|
14
16
|
import { buildCacheStateHeaders } from "./cache-headers.js";
|
|
15
17
|
import { parseHttpDate } from "./http-date.js";
|
|
16
18
|
import { evaluateStaticPreconditions } from "./http-conditional.js";
|
|
17
|
-
import { buildNextDataNotFoundResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath } from "./pages-data-route.js";
|
|
18
19
|
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
19
|
-
import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
20
20
|
import { signalFromNodeResponse } from "./node-response-signal.js";
|
|
21
|
-
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_RESPONSE_CACHE_STATE, isImageOptimizationPath, isSafeImageContentType, parseImageParams } from "./image-optimization.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";
|
|
22
22
|
import { installSocketErrorBackstop } from "./socket-error-backstop.js";
|
|
23
23
|
import { collectInlineCssManifest } from "../build/inline-css.js";
|
|
24
24
|
import { readTrustedRevalidationHostname } from "./revalidation-host.js";
|
|
@@ -28,6 +28,7 @@ import { runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pip
|
|
|
28
28
|
import { computeClientRuntimeMetadata } from "../utils/client-runtime-metadata.js";
|
|
29
29
|
import { readPrerenderSecret, readServerCompress } from "../build/server-manifest.js";
|
|
30
30
|
import { readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
31
|
+
import { resolveClientBuildFile } from "./client-build-files.js";
|
|
31
32
|
import { registerPrerenderCloudflareLoader } from "../build/prerender-cloudflare-loader.js";
|
|
32
33
|
import { seedMemoryCacheFromPrerender } from "./seed-cache.js";
|
|
33
34
|
import { negotiateEncoding, parseAcceptedEncodings, selectContentEncoding } from "./accept-encoding.js";
|
|
@@ -335,10 +336,15 @@ function installClientBuildManifestGlobals(clientDir, assetBase, assetPrefix, cr
|
|
|
335
336
|
function isNoBodyResponseStatus(status) {
|
|
336
337
|
return NO_BODY_RESPONSE_STATUSES.has(status);
|
|
337
338
|
}
|
|
338
|
-
|
|
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) {
|
|
339
345
|
const body = response.body;
|
|
340
346
|
if (!body || body.locked) return;
|
|
341
|
-
body.cancel().catch(() => {});
|
|
347
|
+
body.cancel(reason).catch(() => {});
|
|
342
348
|
}
|
|
343
349
|
/**
|
|
344
350
|
* Buffer a response body, cancelling it if the client disconnects first so a
|
|
@@ -433,6 +439,21 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
433
439
|
res.end(buf);
|
|
434
440
|
}
|
|
435
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
|
+
}
|
|
436
457
|
/**
|
|
437
458
|
* Try to serve a static file from the client build directory.
|
|
438
459
|
*
|
|
@@ -456,18 +477,8 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
|
|
|
456
477
|
const rawIfRange = req.headers["if-range"];
|
|
457
478
|
const ifRange = typeof rawIfRange === "string" ? rawIfRange : void 0;
|
|
458
479
|
if (cache) {
|
|
459
|
-
|
|
460
|
-
if (
|
|
461
|
-
try {
|
|
462
|
-
lookupPath = decodeURIComponent(pathname);
|
|
463
|
-
} catch {
|
|
464
|
-
return false;
|
|
465
|
-
}
|
|
466
|
-
if (lookupPath.startsWith("/.vite/") || lookupPath === "/.vite") return false;
|
|
467
|
-
} else {
|
|
468
|
-
if (pathname.startsWith("/.vite/") || pathname === "/.vite") return false;
|
|
469
|
-
lookupPath = pathname;
|
|
470
|
-
}
|
|
480
|
+
const lookupPath = staticCacheLookupPath(pathname);
|
|
481
|
+
if (lookupPath === null) return false;
|
|
471
482
|
const entry = cache.lookup(lookupPath);
|
|
472
483
|
if (!entry) return false;
|
|
473
484
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
@@ -878,7 +889,7 @@ function waitForNodeResponseCompletion(res) {
|
|
|
878
889
|
* Pages Router (dist/server/entry.js) and configures the appropriate handler.
|
|
879
890
|
*/
|
|
880
891
|
async function startProdServer(options = {}) {
|
|
881
|
-
installSocketErrorBackstop();
|
|
892
|
+
installSocketErrorBackstop({ runningServer: options.purpose !== "prerender" });
|
|
882
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;
|
|
883
894
|
if (purpose === "prerender") registerPrerenderCloudflareLoader();
|
|
884
895
|
const compress = !noCompression;
|
|
@@ -1110,6 +1121,59 @@ async function startAppRouterServer(options) {
|
|
|
1110
1121
|
const seededRoutes = await runWithServerEntryRequire(rscEntryRequire, () => seedPrerenderedRoutes(serverDir));
|
|
1111
1122
|
if (seededRoutes > 0) console.log(`[vinext] Seeded ${seededRoutes} pre-rendered route${seededRoutes !== 1 ? "s" : ""} into memory cache`);
|
|
1112
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 : []);
|
|
1113
1177
|
const handleRequestImpl = async (req, res) => {
|
|
1114
1178
|
const rawUrl = req.url ?? "/";
|
|
1115
1179
|
const rawPathname = rawUrl.split("?")[0];
|
|
@@ -1142,29 +1206,9 @@ async function startAppRouterServer(options) {
|
|
|
1142
1206
|
if (await tryServeStatic(req, res, clientDir, assetLookupPath, compress, staticCache)) return;
|
|
1143
1207
|
}
|
|
1144
1208
|
}
|
|
1145
|
-
if (
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1148
|
-
if (!params) {
|
|
1149
|
-
res.writeHead(400);
|
|
1150
|
-
res.end("Bad Request");
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
|
-
const ct = contentTypeForPath(params.imageUrl);
|
|
1154
|
-
if (!isSafeImageContentType(ct, imageConfig?.dangerouslyAllowSVG)) {
|
|
1155
|
-
res.writeHead(400);
|
|
1156
|
-
res.end("The requested resource is not an allowed image type");
|
|
1157
|
-
return;
|
|
1158
|
-
}
|
|
1159
|
-
const imageSecurityHeaders = {
|
|
1160
|
-
"Content-Security-Policy": imageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
1161
|
-
"X-Content-Type-Options": "nosniff",
|
|
1162
|
-
"Content-Disposition": imageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1163
|
-
};
|
|
1164
|
-
if (await tryServeStatic(req, res, clientDir, params.imageUrl, false, staticCache, imageSecurityHeaders, void 0, IMAGE_REPRESENTATION_HEADERS)) return;
|
|
1165
|
-
res.writeHead(404);
|
|
1166
|
-
res.end("Image not found");
|
|
1167
|
-
return;
|
|
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;
|
|
1168
1212
|
}
|
|
1169
1213
|
try {
|
|
1170
1214
|
const request = nodeToWebRequest(req, rawUrl, prerenderSecret, appRouterI18nConfig, appRouterAuthorizeOnDemandRevalidate, signalFromNodeResponse(res));
|
|
@@ -1175,7 +1219,13 @@ async function startAppRouterServer(options) {
|
|
|
1175
1219
|
};
|
|
1176
1220
|
const response = await rscHandler(request, ctx);
|
|
1177
1221
|
if (request.signal.aborted) {
|
|
1222
|
+
cancelResponseBody(response, request.signal.reason);
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
const imageSignal = readImageOptimizationSignal(response);
|
|
1226
|
+
if (imageSignal) {
|
|
1178
1227
|
cancelResponseBody(response);
|
|
1228
|
+
await serveImageOptimization(req, res, request, imageSignal);
|
|
1179
1229
|
return;
|
|
1180
1230
|
}
|
|
1181
1231
|
const staticFileSignal = readStaticFileSignal(response);
|
|
@@ -1270,7 +1320,45 @@ function readPagesServerEntryPageRoutes(value) {
|
|
|
1270
1320
|
* - vinextConfig — embedded next.config.js settings
|
|
1271
1321
|
*/
|
|
1272
1322
|
async function startPagesRouterServer(options) {
|
|
1273
|
-
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;
|
|
1274
1362
|
const serverEntry = await importServerEntryModule(serverEntryPath);
|
|
1275
1363
|
const serverEntryRequire = createServerEntryRequire(serverEntryPath);
|
|
1276
1364
|
const { renderPage, handleApiRoute: handleApi, authorizeOnDemandRevalidate, runMiddleware, vinextConfig, buildId: pagesBuildId } = serverEntry;
|
|
@@ -1286,6 +1374,7 @@ async function startPagesRouterServer(options) {
|
|
|
1286
1374
|
const pagesAssetPathPrefix = assetPrefixPathname(assetPrefix);
|
|
1287
1375
|
const assetBase = basePath ? `${basePath}/` : "/";
|
|
1288
1376
|
const trailingSlash = vinextConfig?.trailingSlash ?? false;
|
|
1377
|
+
const skipTrailingSlashRedirect = vinextConfig?.skipTrailingSlashRedirect ?? false;
|
|
1289
1378
|
const skipProxyUrlNormalize = vinextConfig?.skipProxyUrlNormalize ?? false;
|
|
1290
1379
|
const i18nConfig = vinextConfig?.i18n ?? null;
|
|
1291
1380
|
const configRedirects = vinextConfig?.redirects ?? [];
|
|
@@ -1445,7 +1534,8 @@ async function startPagesRouterServer(options) {
|
|
|
1445
1534
|
const method = req.method ?? "GET";
|
|
1446
1535
|
const signal = signalFromNodeResponse(res);
|
|
1447
1536
|
const hasBody = method !== "GET" && method !== "HEAD" && !signal.aborted;
|
|
1448
|
-
const
|
|
1537
|
+
const requestOrigin = `${protocol}://${revalidationHostname ?? hostHeader}`;
|
|
1538
|
+
const webRequest = new Request(new URL(url, requestOrigin), {
|
|
1449
1539
|
method,
|
|
1450
1540
|
headers: reqHeaders,
|
|
1451
1541
|
signal,
|
|
@@ -1453,10 +1543,44 @@ async function startPagesRouterServer(options) {
|
|
|
1453
1543
|
duplex: hasBody ? "half" : void 0
|
|
1454
1544
|
});
|
|
1455
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
|
+
};
|
|
1456
1579
|
const deps = {
|
|
1457
1580
|
assetPrefix,
|
|
1458
1581
|
basePath,
|
|
1459
1582
|
trailingSlash,
|
|
1583
|
+
skipTrailingSlashRedirect,
|
|
1460
1584
|
i18nConfig,
|
|
1461
1585
|
configRedirects,
|
|
1462
1586
|
configRewrites,
|
|
@@ -1479,8 +1603,8 @@ async function startPagesRouterServer(options) {
|
|
|
1479
1603
|
originalUrl: originalRenderUrl
|
|
1480
1604
|
}, stagedHeaders?.has("Cache-Control") ? new Headers({ "Cache-Control": stagedHeaders.get("Cache-Control") }) : void 0) : null,
|
|
1481
1605
|
handleApi: typeof handleApi === "function" ? (request, apiUrl) => handleApi(request, apiUrl, createNodeExecutionContext(), resolveTrustedNodeRevalidateOrigin(req, host, port), "node") : null,
|
|
1482
|
-
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl) => {
|
|
1483
|
-
if (isImageOptimizationPath(requestPathname)) {
|
|
1606
|
+
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl, _request, resolvedPathnameHasBasePath) => {
|
|
1607
|
+
if (resolvedPathnameHasBasePath && isImageOptimizationPath(requestPathname)) {
|
|
1484
1608
|
for (const [name, value] of Object.entries(stagedHeaders)) res.setHeader(name, value);
|
|
1485
1609
|
const parsedUrl = new URL(resolvedUrl, "http://localhost");
|
|
1486
1610
|
const params = parseImageParams(parsedUrl, allowedImageWidths, pagesImageConfig?.qualities);
|
|
@@ -1489,23 +1613,42 @@ async function startPagesRouterServer(options) {
|
|
|
1489
1613
|
res.end("Bad Request");
|
|
1490
1614
|
return true;
|
|
1491
1615
|
}
|
|
1492
|
-
const
|
|
1493
|
-
if (!isSafeImageContentType(ct, pagesImageConfig?.dangerouslyAllowSVG)) {
|
|
1616
|
+
const sendUnsafeContentType = () => {
|
|
1494
1617
|
res.writeHead(400);
|
|
1495
1618
|
res.end("The requested resource is not an allowed image type");
|
|
1496
|
-
|
|
1497
|
-
|
|
1619
|
+
};
|
|
1620
|
+
const isSafeSourcePath = (sourcePath) => isSafeImageContentType(contentTypeForPath(sourcePath), pagesImageConfig?.dangerouslyAllowSVG);
|
|
1498
1621
|
const imageSecurityHeaders = {
|
|
1499
1622
|
"Content-Security-Policy": pagesImageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
1500
1623
|
"X-Content-Type-Options": "nosniff",
|
|
1501
1624
|
"Content-Disposition": pagesImageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1502
1625
|
};
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
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);
|
|
1506
1649
|
return true;
|
|
1507
1650
|
}
|
|
1508
|
-
if (requestPathname
|
|
1651
|
+
if (isPagesFilesystemExcludedPath(requestPathname, phase)) return false;
|
|
1509
1652
|
return tryServeStatic(req, res, clientDir, requestPathname, compress, staticCache, stagedHeaders);
|
|
1510
1653
|
}
|
|
1511
1654
|
};
|
|
@@ -1514,7 +1657,7 @@ async function startPagesRouterServer(options) {
|
|
|
1514
1657
|
if (result.type === "response") {
|
|
1515
1658
|
const { response } = result;
|
|
1516
1659
|
if (webRequest.signal.aborted) {
|
|
1517
|
-
cancelResponseBody(response);
|
|
1660
|
+
cancelResponseBody(response, webRequest.signal.reason);
|
|
1518
1661
|
return;
|
|
1519
1662
|
}
|
|
1520
1663
|
const streamedApi = isVinextStreamedApiResponse(response);
|
|
@@ -1548,22 +1691,9 @@ async function startPagesRouterServer(options) {
|
|
|
1548
1691
|
}
|
|
1549
1692
|
}
|
|
1550
1693
|
};
|
|
1551
|
-
|
|
1694
|
+
return (req, res) => {
|
|
1552
1695
|
runWithServerEntryRequire(serverEntryRequire, () => handleRequest(req, res));
|
|
1553
|
-
});
|
|
1554
|
-
await new Promise((resolve) => {
|
|
1555
|
-
server.listen(port, host, () => {
|
|
1556
|
-
const addr = server.address();
|
|
1557
|
-
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
1558
|
-
if (!silent) logProdServerStarted(host, actualPort, purpose);
|
|
1559
|
-
resolve();
|
|
1560
|
-
});
|
|
1561
|
-
});
|
|
1562
|
-
const addr = server.address();
|
|
1563
|
-
return {
|
|
1564
|
-
server,
|
|
1565
|
-
port: typeof addr === "object" && addr ? addr.port : port
|
|
1566
1696
|
};
|
|
1567
1697
|
}
|
|
1568
1698
|
//#endregion
|
|
1569
|
-
export { COMPRESS_THRESHOLD, importServerEntryModule, isCompressibleContentType, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, readNodeStream, rememberCurrentServerEntryImportMtime, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic, waitForNodeResponseCompletion };
|
|
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 };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/server/proper-error.ts
|
|
2
|
+
function isPlainObject(value) {
|
|
3
|
+
if (Object.prototype.toString.call(value) !== "[object Object]") return false;
|
|
4
|
+
const prototype = Object.getPrototypeOf(value);
|
|
5
|
+
return prototype === null || Object.prototype.hasOwnProperty.call(prototype, "isPrototypeOf");
|
|
6
|
+
}
|
|
7
|
+
/** JSON.stringify that replaces circular references with "[Circular]". */
|
|
8
|
+
function safeStringifyLite(value) {
|
|
9
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
10
|
+
return JSON.stringify(value, (_key, nested) => {
|
|
11
|
+
if (typeof nested === "object" && nested !== null) {
|
|
12
|
+
if (seen.has(nested)) return "[Circular]";
|
|
13
|
+
seen.add(nested);
|
|
14
|
+
}
|
|
15
|
+
return nested;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function isError(value) {
|
|
19
|
+
return typeof value === "object" && value !== null && "name" in value && "message" in value;
|
|
20
|
+
}
|
|
21
|
+
/** Turn a thrown value into an Error, as Next.js does before reporting it. */
|
|
22
|
+
function getProperError(error) {
|
|
23
|
+
if (isError(error)) return error;
|
|
24
|
+
if (process.env.NODE_ENV === "development") {
|
|
25
|
+
if (typeof error === "undefined") return /* @__PURE__ */ new Error("An undefined error was thrown, see here for more info: https://nextjs.org/docs/messages/threw-undefined");
|
|
26
|
+
if (error === null) return /* @__PURE__ */ new Error("A null error was thrown, see here for more info: https://nextjs.org/docs/messages/threw-undefined");
|
|
27
|
+
}
|
|
28
|
+
return new Error(isPlainObject(error) ? safeStringifyLite(error) : String(error));
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { getProperError };
|
|
@@ -69,7 +69,10 @@ export declare function guardProtocolRelativeUrl(rawPathname: string, search?: s
|
|
|
69
69
|
export type HeaderRecord = Record<string, string | string[]>;
|
|
70
70
|
type ResolvePublicFileRouteOptions = {
|
|
71
71
|
cleanPathname: string;
|
|
72
|
-
|
|
72
|
+
/** `requestHeaders` holds middleware's request-header override instructions. */
|
|
73
|
+
middlewareContext: StaticFileSignalContext & {
|
|
74
|
+
requestHeaders?: Headers | null;
|
|
75
|
+
};
|
|
73
76
|
pathname: string;
|
|
74
77
|
publicFiles: ReadonlySet<string>;
|
|
75
78
|
request: Request;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../utils/protocol-headers.js";
|
|
2
|
-
import { getUnconsumedMiddlewareRequestHeaders } from "../utils/middleware-request-headers.js";
|
|
2
|
+
import { buildRequestHeadersFromMiddlewareResponse, getUnconsumedMiddlewareRequestHeaders } from "../utils/middleware-request-headers.js";
|
|
3
3
|
import { hasBasePath, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
|
|
4
4
|
import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS } from "./headers.js";
|
|
5
5
|
import { forbiddenResponse, methodNotAllowedResponse, notFoundResponse } from "./http-error-responses.js";
|
|
@@ -100,7 +100,8 @@ function resolvePublicFileRoute(options) {
|
|
|
100
100
|
if (options.pathname.endsWith(".rsc")) return null;
|
|
101
101
|
if (!options.publicFiles.has(options.cleanPathname)) return null;
|
|
102
102
|
if (options.request.method !== "GET" && options.request.method !== "HEAD") return methodNotAllowedResponse("GET, HEAD", { headers: options.middlewareContext.headers ?? void 0 });
|
|
103
|
-
|
|
103
|
+
const { requestHeaders } = options.middlewareContext;
|
|
104
|
+
return createStaticFileSignal(options.cleanPathname, options.middlewareContext, requestHeaders ? buildRequestHeadersFromMiddlewareResponse(options.request.headers, requestHeaders) : null);
|
|
104
105
|
}
|
|
105
106
|
function normalizeTrailingSlashPathname(pathname, trailingSlash) {
|
|
106
107
|
if (pathname === "/" || pathname === "/api" || pathname.startsWith("/api/")) return null;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PRERENDER_REVALIDATE_HEADER } from "../utils/protocol-headers.js";
|
|
2
2
|
//#region src/server/revalidation-request.d.ts
|
|
3
3
|
export declare function getRevalidateSecret(): string;
|
|
4
|
+
export declare function safeEqual(first: string, second: string): boolean;
|
|
4
5
|
export declare function isRevalidateSecret(value: string | null | undefined): boolean;
|
|
5
6
|
/** Match Next.js: the header value must equal the preview/revalidation secret. */
|
|
6
7
|
export declare function isOnDemandRevalidateRequest(headerValue: string | string[] | null | undefined): boolean;
|
|
@@ -34,4 +34,4 @@ function isOnDemandRevalidateRequest(headerValue) {
|
|
|
34
34
|
return typeof headerValue === "string" && isRevalidateSecret(headerValue);
|
|
35
35
|
}
|
|
36
36
|
//#endregion
|
|
37
|
-
export { PRERENDER_REVALIDATE_HEADER, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret };
|
|
37
|
+
export { PRERENDER_REVALIDATE_HEADER, getRevalidateSecret, isOnDemandRevalidateRequest, isRevalidateSecret, safeEqual };
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* tag is `HL` are decoded and inspected. Length-prefixed bodies remain separate
|
|
12
12
|
* so binary bytes do not force adjacent text through the embed's base64 path.
|
|
13
13
|
*/
|
|
14
|
-
export declare function normalizeReactFlightPreloadHints(stream: ReadableStream<Uint8Array
|
|
14
|
+
export declare function normalizeReactFlightPreloadHints(stream: ReadableStream<Uint8Array>, onCancel?: (reason: unknown) => void): ReadableStream<Uint8Array>;
|
|
15
15
|
export type RscRawRenderer = (model: unknown, options?: unknown) => ReadableStream<Uint8Array>;
|
|
16
16
|
export type RscRawPrerenderer = (model: unknown, options?: unknown) => Promise<{
|
|
17
17
|
prelude: ReadableStream<Uint8Array>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRenderStreamCancellation } from "./app-render-abort-error.js";
|
|
1
2
|
//#region src/server/rsc-stream-hints.ts
|
|
2
3
|
const REACT_FLIGHT_STYLESHEET_PRELOAD_HINT = /^([0-9a-f]*:HL\[.*?),"stylesheet"(\]|,)/;
|
|
3
4
|
const STYLESHEET_TO_STYLE_JSON_PADDING = " ".repeat(5);
|
|
@@ -55,6 +56,15 @@ function indexOfByte(bytes, byte, from) {
|
|
|
55
56
|
for (let index = from; index < bytes.byteLength; index++) if (bytes[index] === byte) return index;
|
|
56
57
|
return -1;
|
|
57
58
|
}
|
|
59
|
+
function utf8CompleteEnd(bytes, from) {
|
|
60
|
+
const length = bytes.byteLength;
|
|
61
|
+
for (let index = length - 1; index >= from && index >= length - 3; index--) {
|
|
62
|
+
const byte = bytes[index];
|
|
63
|
+
if ((byte & 192) === 128) continue;
|
|
64
|
+
return index + (byte >= 240 ? 4 : byte >= 224 ? 3 : byte >= 192 ? 2 : 1) > length ? index : length;
|
|
65
|
+
}
|
|
66
|
+
return length;
|
|
67
|
+
}
|
|
58
68
|
function parseHexBytes(bytes, start, end) {
|
|
59
69
|
if (start === end) return null;
|
|
60
70
|
let value = 0;
|
|
@@ -97,20 +107,34 @@ function isTagInTable(table, byte) {
|
|
|
97
107
|
* tag is `HL` are decoded and inspected. Length-prefixed bodies remain separate
|
|
98
108
|
* so binary bytes do not force adjacent text through the embed's base64 path.
|
|
99
109
|
*/
|
|
100
|
-
function normalizeReactFlightPreloadHints(stream) {
|
|
110
|
+
function normalizeReactFlightPreloadHints(stream, onCancel) {
|
|
101
111
|
let carry = null;
|
|
102
112
|
let rawBytesRemaining = 0;
|
|
103
113
|
let passThrough = false;
|
|
114
|
+
let inPlainRow = false;
|
|
104
115
|
return stream.pipeThrough(new TransformStream({
|
|
105
116
|
transform(chunk, controller) {
|
|
106
117
|
if (passThrough) {
|
|
107
118
|
controller.enqueue(chunk);
|
|
108
119
|
return;
|
|
109
120
|
}
|
|
121
|
+
let start = 0;
|
|
122
|
+
if (inPlainRow) {
|
|
123
|
+
const end = indexOfByte(chunk, NEWLINE_BYTE, 0);
|
|
124
|
+
if (end === -1) {
|
|
125
|
+
const bytes = carry === null ? chunk : concatBytes(carry, chunk);
|
|
126
|
+
const complete = utf8CompleteEnd(bytes, 0);
|
|
127
|
+
carry = complete === bytes.byteLength ? null : bytes.slice(complete);
|
|
128
|
+
if (complete > 0) controller.enqueue(complete === bytes.byteLength ? bytes : bytes.subarray(0, complete));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
inPlainRow = false;
|
|
132
|
+
start = (carry === null ? 0 : carry.byteLength) + end + 1;
|
|
133
|
+
}
|
|
110
134
|
const bytes = carry === null ? chunk : concatBytes(carry, chunk);
|
|
111
135
|
carry = null;
|
|
112
136
|
const byteLength = bytes.byteLength;
|
|
113
|
-
let offset =
|
|
137
|
+
let offset = start;
|
|
114
138
|
let emittedThrough = 0;
|
|
115
139
|
let output = bytes;
|
|
116
140
|
let ownsOutput = bytes !== chunk;
|
|
@@ -146,7 +170,13 @@ function normalizeReactFlightPreloadHints(stream) {
|
|
|
146
170
|
break;
|
|
147
171
|
}
|
|
148
172
|
const newline = indexOfByte(bytes, NEWLINE_BYTE, offset);
|
|
149
|
-
if (newline === -1)
|
|
173
|
+
if (newline === -1) {
|
|
174
|
+
if (!(tagByte === HINT_TAG_BYTE && (colon + 2 === byteLength || bytes[colon + 2] === LINK_HINT_CODE_BYTE))) {
|
|
175
|
+
inPlainRow = true;
|
|
176
|
+
offset = utf8CompleteEnd(bytes, offset);
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
150
180
|
if (tagByte === HINT_TAG_BYTE && bytes[colon + 2] === LINK_HINT_CODE_BYTE) {
|
|
151
181
|
const line = bytes.subarray(offset, newline + 1);
|
|
152
182
|
const normalized = normalizeReactFlightHintLine(line);
|
|
@@ -165,11 +195,28 @@ function normalizeReactFlightPreloadHints(stream) {
|
|
|
165
195
|
},
|
|
166
196
|
flush(controller) {
|
|
167
197
|
if (carry !== null && carry.byteLength > 0) controller.enqueue(rawBytesRemaining > 0 ? carry : normalizeReactFlightHintLine(carry));
|
|
168
|
-
}
|
|
198
|
+
},
|
|
199
|
+
cancel: onCancel
|
|
169
200
|
}));
|
|
170
201
|
}
|
|
171
202
|
function createRscRenderer(render) {
|
|
172
|
-
return (model, options) =>
|
|
203
|
+
return (model, options) => {
|
|
204
|
+
const cancellation = createRenderStreamCancellation();
|
|
205
|
+
return normalizeReactFlightPreloadHints(render(model, ignoreCancellationErrors(options, cancellation)), cancellation.record);
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** A consumer cancelling the payload is not a render failure. */
|
|
209
|
+
function ignoreCancellationErrors(options, cancellation) {
|
|
210
|
+
if (!options || typeof options !== "object") return options;
|
|
211
|
+
const onError = Reflect.get(options, "onError");
|
|
212
|
+
if (typeof onError !== "function") return options;
|
|
213
|
+
return {
|
|
214
|
+
...options,
|
|
215
|
+
onError(error, ...rest) {
|
|
216
|
+
if (cancellation.isReason(error)) return void 0;
|
|
217
|
+
return Reflect.apply(onError, options, [error, ...rest]);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
173
220
|
}
|
|
174
221
|
function createRscPrerenderer(prerender) {
|
|
175
222
|
return async (model, options) => {
|
|
@@ -14,6 +14,7 @@ type PrerenderCacheSeedMetadata = {
|
|
|
14
14
|
};
|
|
15
15
|
type PrerenderCacheSeedOptions = {
|
|
16
16
|
buildAppPageHtmlKey?: (pathname: string) => string;
|
|
17
|
+
buildAppPageFallbackShellKey?: (pathname: string, suffix: "html" | "rsc") => string;
|
|
17
18
|
buildAppPageRscKey?: (pathname: string) => string;
|
|
18
19
|
buildAppRouteKey?: (pathname: string) => string;
|
|
19
20
|
writeAppPageEntry?: (key: string, data: CachedAppPageValue, metadata: PrerenderCacheSeedMetadata) => Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { appIsrCacheKey, isrSet, isrSetPrerenderedAppPage } from "./isr-cache.js";
|
|
2
|
+
import { appIsrCacheKey, appIsrFallbackShellKey, isrSet, isrSetPrerenderedAppPage } from "./isr-cache.js";
|
|
3
3
|
import { addPregeneratedConcretePath, addPregeneratedRoute, clearPregeneratedConcretePaths, normalizePregeneratedPathname } from "./pregenerated-concrete-paths.js";
|
|
4
4
|
import { getRenderedAppRoutes, getRenderedMetadataRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
|
|
5
5
|
import { buildAppPageCacheTags, buildAppRouteCacheTags } from "./app-page-cache.js";
|
|
@@ -61,11 +61,12 @@ async function seedMemoryCacheFromPrerender(serverDir, options) {
|
|
|
61
61
|
const appRoutes = getRenderedAppRoutes(routes);
|
|
62
62
|
for (const route of appRoutes) {
|
|
63
63
|
const concretePathname = route.path ?? route.route;
|
|
64
|
-
|
|
64
|
+
const isFallbackShell = isFallbackShellArtifactPath(concretePathname, route);
|
|
65
|
+
if (!isFallbackShell) addPregeneratedConcretePath(route.route, concretePathname);
|
|
65
66
|
const artifactPathname = route.path ?? route.route;
|
|
66
67
|
const cachePathname = normalizePregeneratedPathname(artifactPathname);
|
|
67
|
-
const htmlKey = options?.buildAppPageHtmlKey?.(cachePathname) ?? appIsrCacheKey(cachePathname, "html", buildId);
|
|
68
|
-
const rscKey = options?.buildAppPageRscKey?.(cachePathname) ?? appIsrCacheKey(cachePathname, "rsc", buildId);
|
|
68
|
+
const htmlKey = isFallbackShell ? options?.buildAppPageFallbackShellKey?.(cachePathname, "html") ?? appIsrFallbackShellKey(cachePathname, "html", buildId) : options?.buildAppPageHtmlKey?.(cachePathname) ?? appIsrCacheKey(cachePathname, "html", buildId);
|
|
69
|
+
const rscKey = isFallbackShell ? options?.buildAppPageFallbackShellKey?.(cachePathname, "rsc") ?? appIsrFallbackShellKey(cachePathname, "rsc", buildId) : options?.buildAppPageRscKey?.(cachePathname) ?? appIsrCacheKey(cachePathname, "rsc", buildId);
|
|
69
70
|
const revalidateSeconds = typeof route.revalidate === "number" ? route.revalidate : void 0;
|
|
70
71
|
const expireSeconds = typeof route.expire === "number" ? route.expire : void 0;
|
|
71
72
|
const staleSeconds = typeof route.stale === "number" && route.stale >= 0 ? route.stale : void 0;
|