vinext 0.1.1 → 0.1.3
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 +2 -5
- package/dist/build/client-build-config.d.ts +7 -1
- package/dist/build/client-build-config.js +9 -1
- package/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/check.js +4 -3
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/navigation-runtime.d.ts +3 -2
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +8 -5
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.d.ts +11 -4
- package/dist/config/config-matchers.js +88 -16
- package/dist/config/next-config.d.ts +59 -4
- package/dist/config/next-config.js +149 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +189 -101
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +71 -6
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +54 -9
- package/dist/entries/pages-server-entry.js +48 -11
- package/dist/index.d.ts +0 -2
- package/dist/index.js +285 -139
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +10 -5
- package/dist/plugins/optimize-imports.js +27 -21
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +25 -2
- package/dist/routing/app-route-graph.js +91 -22
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +23 -2
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +269 -297
- package/dist/server/app-browser-error.d.ts +10 -3
- package/dist/server/app-browser-error.js +47 -6
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +7 -4
- package/dist/server/app-browser-navigation-controller.js +33 -9
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-state.js +4 -7
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +3 -1
- package/dist/server/app-fallback-renderer.js +6 -2
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +24 -3
- package/dist/server/app-page-boundary-render.d.ts +3 -1
- package/dist/server/app-page-boundary-render.js +31 -16
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +71 -8
- package/dist/server/app-page-dispatch.d.ts +34 -0
- package/dist/server/app-page-dispatch.js +167 -97
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +42 -10
- package/dist/server/app-page-execution.d.ts +7 -2
- package/dist/server/app-page-execution.js +53 -18
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +13 -2
- package/dist/server/app-page-render.js +48 -17
- package/dist/server/app-page-request.d.ts +3 -0
- package/dist/server/app-page-request.js +5 -3
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +5 -1
- package/dist/server/app-page-route-wiring.js +21 -11
- package/dist/server/app-page-stream.d.ts +16 -9
- package/dist/server/app-page-stream.js +12 -9
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.js +12 -1
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +153 -53
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +12 -0
- package/dist/server/app-server-action-execution.js +47 -15
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +81 -8
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +287 -63
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +186 -22
- package/dist/server/navigation-planner.js +302 -0
- package/dist/server/navigation-trace.d.ts +18 -1
- package/dist/server/navigation-trace.js +18 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +20 -3
- package/dist/server/pages-api-route.js +19 -3
- package/dist/server/pages-asset-tags.d.ts +16 -4
- package/dist/server/pages-asset-tags.js +22 -12
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +16 -3
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.d.ts +3 -11
- package/dist/server/pages-node-compat.js +175 -122
- package/dist/server/pages-page-data.d.ts +39 -2
- package/dist/server/pages-page-data.js +261 -46
- package/dist/server/pages-page-handler.d.ts +5 -2
- package/dist/server/pages-page-handler.js +78 -25
- package/dist/server/pages-page-response.d.ts +47 -2
- package/dist/server/pages-page-response.js +73 -9
- package/dist/server/pages-readiness.d.ts +1 -1
- package/dist/server/pages-request-pipeline.d.ts +16 -1
- package/dist/server/pages-request-pipeline.js +96 -38
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.d.ts +39 -1
- package/dist/server/prod-server.js +107 -37
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +12 -4
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +79 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +6 -4
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +38 -11
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +11 -1
- package/dist/shims/fetch-cache.js +55 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +66 -5
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +18 -23
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +14 -17
- package/dist/shims/navigation.js +93 -46
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +434 -116
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +33 -2
- package/dist/shims/server.js +75 -18
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/client-build-manifest.js +15 -5
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +8 -1
- package/dist/utils/path.js +13 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -8,17 +8,14 @@ import { isUnknownRecord } from "../utils/record.js";
|
|
|
8
8
|
import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
9
9
|
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath, isSafeImageContentType, parseImageParams } from "./image-optimization.js";
|
|
10
10
|
import { installSocketErrorBackstop } from "./socket-error-backstop.js";
|
|
11
|
-
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix
|
|
11
|
+
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
12
12
|
import { CONTENT_TYPES, StaticFileCache, etagFromFilenameHash } from "./static-file-cache.js";
|
|
13
13
|
import { buildNextDataNotFoundResponse, isNextDataPathname, parseNextDataPathname } from "./pages-data-route.js";
|
|
14
14
|
import { collectInlineCssManifest } from "../build/inline-css.js";
|
|
15
15
|
import { mergeHeaders } from "./worker-utils.js";
|
|
16
|
-
import { runPagesRequest } from "./pages-request-pipeline.js";
|
|
17
|
-
import { manifestFileWithBase } from "../utils/manifest-paths.js";
|
|
16
|
+
import { runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pipeline.js";
|
|
18
17
|
import { readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
19
|
-
import {
|
|
20
|
-
import { findClientEntryFile, findPagesClientEntryFile, readClientBuildManifest } from "../utils/client-build-manifest.js";
|
|
21
|
-
import { findClientEntryFileFromVinextManifest, findPagesClientEntryFileFromVinextManifest, readClientEntryManifest } from "../utils/client-entry-manifest.js";
|
|
18
|
+
import { computeClientRuntimeMetadata } from "../utils/client-runtime-metadata.js";
|
|
22
19
|
import { readPrerenderSecret } from "../build/server-manifest.js";
|
|
23
20
|
import { seedMemoryCacheFromPrerender } from "./seed-cache.js";
|
|
24
21
|
import fs from "node:fs";
|
|
@@ -48,6 +45,68 @@ import { Readable, pipeline } from "node:stream";
|
|
|
48
45
|
* - dist/server/index.js — RSC entry (default export: handler(Request) → Response)
|
|
49
46
|
* - dist/server/ssr/index.js — SSR entry (imported by RSC entry at runtime)
|
|
50
47
|
*/
|
|
48
|
+
/**
|
|
49
|
+
* mtime of the build each bare (query-less) server-entry URL was first
|
|
50
|
+
* imported from in this process. Node's ESM cache pins a bare URL to that
|
|
51
|
+
* build forever, so rebuilds to the same path must be detected and loaded
|
|
52
|
+
* through a cache-busted URL instead.
|
|
53
|
+
*/
|
|
54
|
+
const bareServerEntryMtimes = /* @__PURE__ */ new Map();
|
|
55
|
+
/**
|
|
56
|
+
* Import a built server entry module (App Router RSC entry or Pages Router
|
|
57
|
+
* server entry) by absolute file path.
|
|
58
|
+
*
|
|
59
|
+
* The first import of a given path uses the plain file:// URL with NO query
|
|
60
|
+
* string. This is load-bearing: code-split builds emit lazy chunks that
|
|
61
|
+
* import the entry back by bare specifier (default Vite builds on both
|
|
62
|
+
* supported majors — Rollup on Vite 7 and Rolldown on Vite 8 — hoist modules
|
|
63
|
+
* shared between the entry's static graph and lazy route chunks into the
|
|
64
|
+
* entry chunk, which the chunks then import as e.g. "../../index.js").
|
|
65
|
+
* Node keys its ESM cache on the full URL including the query string, so if
|
|
66
|
+
* the server imported the entry as `index.js?t=<mtime>`, a chunk's bare
|
|
67
|
+
* back-import would evaluate the entire server bundle a second time and
|
|
68
|
+
* module-level singletons (db pools, service registries) would silently
|
|
69
|
+
* diverge between the two copies. See
|
|
70
|
+
* https://github.com/cloudflare/vinext/issues/1923.
|
|
71
|
+
*
|
|
72
|
+
* A `?t=<mtime>` query string is appended only when the same path is
|
|
73
|
+
* imported again after a rebuild (different mtime) — e.g. test suites that
|
|
74
|
+
* rebuild a fixture to the same output path within one process — where the
|
|
75
|
+
* bare URL's cache entry would return the stale previous build. Note this
|
|
76
|
+
* rebuild branch trades the single-instance guarantee back: chunks that
|
|
77
|
+
* import the entry by bare path still resolve to the FIRST build's cache
|
|
78
|
+
* entry, so freshness and single-instance only hold together on the first
|
|
79
|
+
* import of a path. Production processes import each entry path exactly
|
|
80
|
+
* once and always get both.
|
|
81
|
+
*
|
|
82
|
+
* The entry is imported via its canonical real path: the bundler
|
|
83
|
+
* canonicalizes module ids with fs.realpathSync.native, so chunks evaluate
|
|
84
|
+
* under realpath-based URLs and their relative imports resolve to realpath
|
|
85
|
+
* URLs too. Importing the entry through a symlinked path (macOS /var/...
|
|
86
|
+
* tmpdirs, symlinked deploy directories) would otherwise create a second
|
|
87
|
+
* instance keyed on the symlinked URL.
|
|
88
|
+
*
|
|
89
|
+
* Exported for direct unit testing of the URL choice.
|
|
90
|
+
*/
|
|
91
|
+
function resolveServerEntryImportUrl(entryPath) {
|
|
92
|
+
let canonicalEntryPath;
|
|
93
|
+
try {
|
|
94
|
+
canonicalEntryPath = fs.realpathSync.native(entryPath);
|
|
95
|
+
} catch {
|
|
96
|
+
canonicalEntryPath = entryPath;
|
|
97
|
+
}
|
|
98
|
+
const href = pathToFileURL(canonicalEntryPath).href;
|
|
99
|
+
const mtime = fs.statSync(canonicalEntryPath).mtimeMs;
|
|
100
|
+
const bareMtime = bareServerEntryMtimes.get(href);
|
|
101
|
+
if (bareMtime === void 0 || bareMtime === mtime) {
|
|
102
|
+
bareServerEntryMtimes.set(href, mtime);
|
|
103
|
+
return href;
|
|
104
|
+
}
|
|
105
|
+
return `${href}?t=${mtime}`;
|
|
106
|
+
}
|
|
107
|
+
async function importServerEntryModule(entryPath) {
|
|
108
|
+
return import(resolveServerEntryImportUrl(entryPath));
|
|
109
|
+
}
|
|
51
110
|
/** Convert a Node.js IncomingMessage into a ReadableStream for Web Request body. */
|
|
52
111
|
function readNodeStream(req) {
|
|
53
112
|
return new ReadableStream({ start(controller) {
|
|
@@ -142,6 +201,7 @@ function toWebHeaders(headersRecord) {
|
|
|
142
201
|
}
|
|
143
202
|
function appendWebHeader(headers, key, value) {
|
|
144
203
|
if (value === void 0) return;
|
|
204
|
+
if (key.startsWith(":")) return;
|
|
145
205
|
if (Array.isArray(value)) {
|
|
146
206
|
for (const item of value) headers.append(key, item);
|
|
147
207
|
return;
|
|
@@ -158,8 +218,14 @@ const NO_BODY_RESPONSE_STATUSES = new Set([
|
|
|
158
218
|
205,
|
|
159
219
|
304
|
|
160
220
|
]);
|
|
161
|
-
|
|
162
|
-
|
|
221
|
+
const OMIT_BODY_HEADERS = new Set(["content-length", "content-type"]);
|
|
222
|
+
const OMIT_STATIC_RESPONSE_HEADERS = new Set([
|
|
223
|
+
VINEXT_STATIC_FILE_HEADER,
|
|
224
|
+
"content-encoding",
|
|
225
|
+
"content-length",
|
|
226
|
+
"content-type"
|
|
227
|
+
]);
|
|
228
|
+
function omitHeadersCaseInsensitive(headersRecord, targets) {
|
|
163
229
|
const filtered = {};
|
|
164
230
|
for (const [key, value] of Object.entries(headersRecord)) {
|
|
165
231
|
if (targets.has(key.toLowerCase())) continue;
|
|
@@ -172,6 +238,15 @@ function matchesIfNoneMatchHeader(ifNoneMatch, etag) {
|
|
|
172
238
|
if (ifNoneMatch === "*") return true;
|
|
173
239
|
return ifNoneMatch.split(",").map((value) => value.trim()).some((value) => value === etag);
|
|
174
240
|
}
|
|
241
|
+
function installClientBuildManifestGlobals(clientDir, assetBase, assetPrefix) {
|
|
242
|
+
const metadata = computeClientRuntimeMetadata({
|
|
243
|
+
clientDir,
|
|
244
|
+
assetBase,
|
|
245
|
+
assetPrefix
|
|
246
|
+
});
|
|
247
|
+
globalThis.__VINEXT_LAZY_CHUNKS__ = metadata.lazyChunks;
|
|
248
|
+
globalThis.__VINEXT_DYNAMIC_PRELOADS__ = metadata.dynamicPreloads;
|
|
249
|
+
}
|
|
175
250
|
function isNoBodyResponseStatus(status) {
|
|
176
251
|
return NO_BODY_RESPONSE_STATUSES.has(status);
|
|
177
252
|
}
|
|
@@ -212,7 +287,7 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
212
287
|
const buf = typeof body === "string" ? Buffer.from(body) : body;
|
|
213
288
|
const baseType = contentType.split(";")[0].trim();
|
|
214
289
|
const encoding = compress ? negotiateEncoding(req) : null;
|
|
215
|
-
const headersWithoutBodyHeaders = omitHeadersCaseInsensitive(extraHeaders,
|
|
290
|
+
const headersWithoutBodyHeaders = omitHeadersCaseInsensitive(extraHeaders, OMIT_BODY_HEADERS);
|
|
216
291
|
const writeHead = (headers) => {
|
|
217
292
|
if (statusText) res.writeHead(statusCode, statusText, headers);
|
|
218
293
|
else res.writeHead(statusCode, headers);
|
|
@@ -619,19 +694,15 @@ function readSsrManifest(clientDir) {
|
|
|
619
694
|
function installPagesClientAssetGlobals(options) {
|
|
620
695
|
const ssrManifest = readSsrManifest(options.clientDir);
|
|
621
696
|
globalThis.__VINEXT_SSR_MANIFEST__ = Object.keys(ssrManifest).length > 0 ? ssrManifest : void 0;
|
|
622
|
-
const
|
|
623
|
-
const clientEntryManifest = readClientEntryManifest(options.clientDir);
|
|
624
|
-
const entryOptions = {
|
|
697
|
+
const metadata = computeClientRuntimeMetadata({
|
|
625
698
|
clientDir: options.clientDir,
|
|
626
|
-
assetsSubdir: options.assetsSubdir,
|
|
627
699
|
assetBase: options.assetBase,
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
} else globalThis.__VINEXT_LAZY_CHUNKS__ = void 0;
|
|
700
|
+
assetPrefix: options.assetPrefix,
|
|
701
|
+
includeClientEntry: options.clientEntryLookup === "pages-client-entry" ? "pages-client-entry" : true
|
|
702
|
+
});
|
|
703
|
+
globalThis.__VINEXT_CLIENT_ENTRY__ = metadata.clientEntryFile;
|
|
704
|
+
globalThis.__VINEXT_LAZY_CHUNKS__ = metadata.lazyChunks;
|
|
705
|
+
globalThis.__VINEXT_DYNAMIC_PRELOADS__ = metadata.dynamicPreloads;
|
|
635
706
|
return ssrManifest;
|
|
636
707
|
}
|
|
637
708
|
/**
|
|
@@ -659,8 +730,7 @@ async function startAppRouterServer(options) {
|
|
|
659
730
|
imageConfig = JSON.parse(fs.readFileSync(imageConfigPath, "utf-8"));
|
|
660
731
|
} catch {}
|
|
661
732
|
const prerenderSecret = readPrerenderSecret(path.dirname(rscEntryPath));
|
|
662
|
-
const
|
|
663
|
-
const rscModule = await import(`${pathToFileURL(rscEntryPath).href}?t=${rscMtime}`);
|
|
733
|
+
const rscModule = await importServerEntryModule(rscEntryPath);
|
|
664
734
|
const rscHandler = resolveAppRouterHandler(rscModule.default);
|
|
665
735
|
const appRouterAssetPrefix = typeof rscModule.__assetPrefix === "string" ? rscModule.__assetPrefix : "";
|
|
666
736
|
const appRouterBasePath = typeof rscModule.__basePath === "string" ? rscModule.__basePath : "";
|
|
@@ -671,10 +741,11 @@ async function startAppRouterServer(options) {
|
|
|
671
741
|
const appAssetBase = appRouterBasePath ? `${appRouterBasePath}/` : "/";
|
|
672
742
|
if (appRouterHasPagesDir) installPagesClientAssetGlobals({
|
|
673
743
|
clientDir,
|
|
674
|
-
|
|
744
|
+
assetPrefix: appRouterAssetPrefix,
|
|
675
745
|
assetBase: appAssetBase,
|
|
676
746
|
clientEntryLookup: "pages-client-entry"
|
|
677
747
|
});
|
|
748
|
+
else installClientBuildManifestGlobals(clientDir, appAssetBase, appRouterAssetPrefix);
|
|
678
749
|
const seededRoutes = await resolveAppRouterPrerenderSeeder(rscModule)(path.dirname(rscEntryPath));
|
|
679
750
|
if (seededRoutes > 0) console.log(`[vinext] Seeded ${seededRoutes} pre-rendered route${seededRoutes !== 1 ? "s" : ""} into memory cache`);
|
|
680
751
|
const staticCache = await StaticFileCache.create(clientDir);
|
|
@@ -713,7 +784,7 @@ async function startAppRouterServer(options) {
|
|
|
713
784
|
}
|
|
714
785
|
}
|
|
715
786
|
if (isImageOptimizationPath(pathname)) {
|
|
716
|
-
const params = parseImageParams(new URL(rawUrl, "http://localhost"), [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES]);
|
|
787
|
+
const params = parseImageParams(new URL(rawUrl, "http://localhost"), [...imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], imageConfig?.qualities);
|
|
717
788
|
if (!params) {
|
|
718
789
|
res.writeHead(400);
|
|
719
790
|
res.end("Bad Request");
|
|
@@ -745,12 +816,7 @@ async function startAppRouterServer(options) {
|
|
|
745
816
|
} catch {
|
|
746
817
|
staticFilePath = staticFileSignal;
|
|
747
818
|
}
|
|
748
|
-
const staticResponseHeaders = omitHeadersCaseInsensitive(mergeResponseHeaders({}, response),
|
|
749
|
-
VINEXT_STATIC_FILE_HEADER,
|
|
750
|
-
"content-encoding",
|
|
751
|
-
"content-length",
|
|
752
|
-
"content-type"
|
|
753
|
-
]);
|
|
819
|
+
const staticResponseHeaders = omitHeadersCaseInsensitive(mergeResponseHeaders({}, response), OMIT_STATIC_RESPONSE_HEADERS);
|
|
754
820
|
const served = await tryServeStatic(req, res, clientDir, staticFilePath, compress, staticCache, staticResponseHeaders, response.status);
|
|
755
821
|
cancelResponseBody(response);
|
|
756
822
|
if (served) return;
|
|
@@ -804,8 +870,7 @@ function readPagesServerEntryPageRoutes(value) {
|
|
|
804
870
|
*/
|
|
805
871
|
async function startPagesRouterServer(options) {
|
|
806
872
|
const { port, host, clientDir, serverEntryPath, compress, purpose } = options;
|
|
807
|
-
const
|
|
808
|
-
const serverEntry = await import(`${pathToFileURL(serverEntryPath).href}?t=${serverMtime}`);
|
|
873
|
+
const serverEntry = await importServerEntryModule(serverEntryPath);
|
|
809
874
|
const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig, buildId: pagesBuildId } = serverEntry;
|
|
810
875
|
const matchPageRoute = typeof serverEntry.matchPageRoute === "function" ? serverEntry.matchPageRoute : void 0;
|
|
811
876
|
const pageRoutes = readPagesServerEntryPageRoutes(serverEntry.pageRoutes);
|
|
@@ -827,12 +892,13 @@ async function startPagesRouterServer(options) {
|
|
|
827
892
|
const pagesImageConfig = vinextConfig?.images ? {
|
|
828
893
|
dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
|
|
829
894
|
dangerouslyAllowLocalIP: vinextConfig.images.dangerouslyAllowLocalIP,
|
|
895
|
+
qualities: vinextConfig.images.qualities,
|
|
830
896
|
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
831
897
|
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy
|
|
832
898
|
} : void 0;
|
|
833
899
|
const ssrManifest = installPagesClientAssetGlobals({
|
|
834
900
|
clientDir,
|
|
835
|
-
|
|
901
|
+
assetPrefix,
|
|
836
902
|
assetBase,
|
|
837
903
|
clientEntryLookup: "any-client-entry"
|
|
838
904
|
});
|
|
@@ -896,7 +962,7 @@ async function startPagesRouterServer(options) {
|
|
|
896
962
|
return;
|
|
897
963
|
}
|
|
898
964
|
if (isImageOptimizationPath(pathname) || isImageOptimizationPath(staticLookupPath)) {
|
|
899
|
-
const params = parseImageParams(new URL(rawUrl, "http://localhost"), allowedImageWidths);
|
|
965
|
+
const params = parseImageParams(new URL(rawUrl, "http://localhost"), allowedImageWidths, pagesImageConfig?.qualities);
|
|
900
966
|
if (!params) {
|
|
901
967
|
res.writeHead(400);
|
|
902
968
|
res.end("Bad Request");
|
|
@@ -927,6 +993,7 @@ async function startPagesRouterServer(options) {
|
|
|
927
993
|
}
|
|
928
994
|
}
|
|
929
995
|
let isDataReq = false;
|
|
996
|
+
const originalRenderUrl = url;
|
|
930
997
|
if (isNextDataPathname(pathname)) {
|
|
931
998
|
const dataMatch = pagesBuildId ? parseNextDataPathname(pathname, pagesBuildId) : null;
|
|
932
999
|
if (!dataMatch) {
|
|
@@ -963,8 +1030,11 @@ async function startPagesRouterServer(options) {
|
|
|
963
1030
|
ctx: void 0,
|
|
964
1031
|
rawSearch: rawQs,
|
|
965
1032
|
matchPageRoute: matchPageRoute ?? null,
|
|
966
|
-
runMiddleware: typeof runMiddleware === "function" ? runMiddleware : null,
|
|
967
|
-
renderPage: typeof renderPage === "function" ? (request, resolvedUrl, options, stagedHeaders) => renderPage(request, resolvedUrl, ssrManifest, void 0, stagedHeaders,
|
|
1033
|
+
runMiddleware: typeof runMiddleware === "function" ? wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath) : null,
|
|
1034
|
+
renderPage: typeof renderPage === "function" ? (request, resolvedUrl, options, stagedHeaders) => renderPage(request, resolvedUrl, ssrManifest, void 0, stagedHeaders, {
|
|
1035
|
+
...options,
|
|
1036
|
+
originalUrl: originalRenderUrl
|
|
1037
|
+
}) : null,
|
|
968
1038
|
handleApi: typeof handleApi === "function" ? (request, apiUrl) => handleApi(request, apiUrl, createNodeExecutionContext()) : null,
|
|
969
1039
|
serveStaticFile: async (requestPathname, stagedHeaders) => {
|
|
970
1040
|
if (requestPathname === "/" || requestPathname.startsWith("/api/") || requestPathname.startsWith(`/_next/static/`)) return false;
|
|
@@ -1018,4 +1088,4 @@ async function startPagesRouterServer(options) {
|
|
|
1018
1088
|
};
|
|
1019
1089
|
}
|
|
1020
1090
|
//#endregion
|
|
1021
|
-
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
|
|
1091
|
+
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, importServerEntryModule, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
|
|
@@ -76,7 +76,8 @@ type ApplyConfigHeadersOptions = {
|
|
|
76
76
|
* (basePath: true) rule for backward compatibility — callers that need to
|
|
77
77
|
* support `basePath: false` headers must pass this in.
|
|
78
78
|
*/
|
|
79
|
-
basePathState?: BasePathMatchState;
|
|
79
|
+
basePathState?: BasePathMatchState; /** Existing framework-generated headers that matching config rules may replace. */
|
|
80
|
+
overwriteExisting?: ReadonlySet<string>;
|
|
80
81
|
};
|
|
81
82
|
type StaticFileSignalContext = {
|
|
82
83
|
headers: Headers | null;
|
|
@@ -157,19 +158,6 @@ declare function validateCsrfOrigin(request: Request, allowedOrigins?: string[])
|
|
|
157
158
|
*/
|
|
158
159
|
declare function validateServerActionPayload(body: string | FormData): Promise<Response | null>;
|
|
159
160
|
declare function isOriginAllowed(origin: string, allowed: string[]): boolean;
|
|
160
|
-
/**
|
|
161
|
-
* Validate an image optimization URL parameter.
|
|
162
|
-
*
|
|
163
|
-
* Ensures the URL is a relative path that doesn't escape the origin:
|
|
164
|
-
* - Must start with "/" but not "//"
|
|
165
|
-
* - Backslashes are normalized (browsers treat `\` as `/`)
|
|
166
|
-
* - Origin validation as defense-in-depth
|
|
167
|
-
*
|
|
168
|
-
* @param rawUrl - The raw `url` query parameter value
|
|
169
|
-
* @param requestUrl - The full request URL for origin comparison
|
|
170
|
-
* @returns An error Response if validation fails, or the normalized image URL
|
|
171
|
-
*/
|
|
172
|
-
declare function validateImageUrl(rawUrl: string | null, requestUrl: string): Response | string;
|
|
173
161
|
/**
|
|
174
162
|
* Strip internal `x-middleware-*` headers from a Headers object.
|
|
175
163
|
*
|
|
@@ -219,4 +207,4 @@ declare function cloneRequestWithHeaders(request: Request, headers: Headers): Re
|
|
|
219
207
|
*/
|
|
220
208
|
declare function cloneRequestWithUrl(request: Request, url: string): Request;
|
|
221
209
|
//#endregion
|
|
222
|
-
export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin,
|
|
210
|
+
export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
@@ -122,7 +122,7 @@ function applyConfigHeadersToResponse(responseHeaders, options) {
|
|
|
122
122
|
for (const header of matched) {
|
|
123
123
|
const lowerName = header.key.toLowerCase();
|
|
124
124
|
if (lowerName === "vary" || lowerName === "set-cookie") responseHeaders.append(header.key, header.value);
|
|
125
|
-
else if (!responseHeaders.has(lowerName)) responseHeaders.set(header.key, header.value);
|
|
125
|
+
else if (options.overwriteExisting?.has(lowerName) || !responseHeaders.has(lowerName)) responseHeaders.set(header.key, header.value);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
@@ -197,9 +197,10 @@ function normalizeTrailingSlash(pathname, basePath, trailingSlash, search) {
|
|
|
197
197
|
if (isOpenRedirectShaped(pathname)) return notFoundResponse();
|
|
198
198
|
const normalizedPathname = normalizeTrailingSlashPathname(pathname, trailingSlash);
|
|
199
199
|
if (normalizedPathname === null) return null;
|
|
200
|
+
const encodedPathname = normalizedPathname.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@/%]/gu, encodeURIComponent);
|
|
200
201
|
return new Response(null, {
|
|
201
202
|
status: 308,
|
|
202
|
-
headers: { Location: basePath +
|
|
203
|
+
headers: { Location: basePath + encodedPathname + search }
|
|
203
204
|
});
|
|
204
205
|
}
|
|
205
206
|
/**
|
|
@@ -246,45 +247,74 @@ function validateCsrfOrigin(request, allowedOrigins = []) {
|
|
|
246
247
|
* Regular user form fields are ignored entirely.
|
|
247
248
|
*/
|
|
248
249
|
async function validateServerActionPayload(body) {
|
|
249
|
-
const
|
|
250
|
+
const maxNumericFields = 4096;
|
|
251
|
+
const maxContainerReferences = 16384;
|
|
252
|
+
const maxContainerDepth = 1024;
|
|
253
|
+
const containerRefRe = /"\$([QWi])([0-9a-f]+)(?=[:"])/gi;
|
|
250
254
|
const fieldRefs = /* @__PURE__ */ new Map();
|
|
255
|
+
let referenceCount = 0;
|
|
256
|
+
const invalidPayloadResponse = () => new Response("Invalid server action payload", {
|
|
257
|
+
status: 400,
|
|
258
|
+
headers: { "Content-Type": "text/plain" }
|
|
259
|
+
});
|
|
251
260
|
const collectRefs = (fieldKey, text) => {
|
|
261
|
+
if (fieldRefs.has(fieldKey)) return true;
|
|
262
|
+
if (fieldRefs.size >= maxNumericFields) return false;
|
|
252
263
|
const refs = /* @__PURE__ */ new Set();
|
|
253
264
|
let match;
|
|
254
265
|
containerRefRe.lastIndex = 0;
|
|
255
|
-
while ((match = containerRefRe.exec(text)) !== null)
|
|
266
|
+
while ((match = containerRefRe.exec(text)) !== null) {
|
|
267
|
+
const previousSize = refs.size;
|
|
268
|
+
refs.add(String(Number.parseInt(match[2], 16)));
|
|
269
|
+
if (refs.size !== previousSize && ++referenceCount > maxContainerReferences) return false;
|
|
270
|
+
}
|
|
256
271
|
fieldRefs.set(fieldKey, refs);
|
|
272
|
+
return true;
|
|
257
273
|
};
|
|
258
|
-
if (typeof body === "string")
|
|
259
|
-
|
|
274
|
+
if (typeof body === "string") {
|
|
275
|
+
if (!collectRefs("0", body)) return invalidPayloadResponse();
|
|
276
|
+
} else for (const [key, value] of body.entries()) {
|
|
260
277
|
if (!/^\d+$/.test(key)) continue;
|
|
261
278
|
if (typeof value === "string") {
|
|
262
|
-
collectRefs(key, value);
|
|
279
|
+
if (!collectRefs(key, value)) return invalidPayloadResponse();
|
|
263
280
|
continue;
|
|
264
281
|
}
|
|
265
|
-
if (typeof value?.text === "function")
|
|
282
|
+
if (typeof value?.text === "function") {
|
|
283
|
+
if (!collectRefs(key, await value.text())) return invalidPayloadResponse();
|
|
284
|
+
}
|
|
266
285
|
}
|
|
267
286
|
if (fieldRefs.size === 0) return null;
|
|
268
287
|
const knownFields = new Set(fieldRefs.keys());
|
|
269
|
-
for (const refs of fieldRefs.values()) for (const ref of refs) if (!knownFields.has(ref)) return
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
stack.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
for (const refs of fieldRefs.values()) for (const ref of refs) if (!knownFields.has(ref)) return invalidPayloadResponse();
|
|
289
|
+
const state = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const root of fieldRefs.keys()) {
|
|
291
|
+
if (state.has(root)) continue;
|
|
292
|
+
const stack = [{
|
|
293
|
+
node: root,
|
|
294
|
+
refs: [...fieldRefs.get(root) ?? []],
|
|
295
|
+
nextRef: 0
|
|
296
|
+
}];
|
|
297
|
+
state.set(root, "visiting");
|
|
298
|
+
while (stack.length > 0) {
|
|
299
|
+
if (stack.length > maxContainerDepth) return invalidPayloadResponse();
|
|
300
|
+
const frame = stack[stack.length - 1];
|
|
301
|
+
const ref = frame.refs[frame.nextRef++];
|
|
302
|
+
if (ref === void 0) {
|
|
303
|
+
state.set(frame.node, "visited");
|
|
304
|
+
stack.pop();
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const refState = state.get(ref);
|
|
308
|
+
if (refState === "visiting") return invalidPayloadResponse();
|
|
309
|
+
if (refState === "visited") continue;
|
|
310
|
+
state.set(ref, "visiting");
|
|
311
|
+
stack.push({
|
|
312
|
+
node: ref,
|
|
313
|
+
refs: [...fieldRefs.get(ref) ?? []],
|
|
314
|
+
nextRef: 0
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
288
318
|
return null;
|
|
289
319
|
}
|
|
290
320
|
/**
|
|
@@ -329,25 +359,6 @@ function isOriginAllowed(origin, allowed) {
|
|
|
329
359
|
return false;
|
|
330
360
|
}
|
|
331
361
|
/**
|
|
332
|
-
* Validate an image optimization URL parameter.
|
|
333
|
-
*
|
|
334
|
-
* Ensures the URL is a relative path that doesn't escape the origin:
|
|
335
|
-
* - Must start with "/" but not "//"
|
|
336
|
-
* - Backslashes are normalized (browsers treat `\` as `/`)
|
|
337
|
-
* - Origin validation as defense-in-depth
|
|
338
|
-
*
|
|
339
|
-
* @param rawUrl - The raw `url` query parameter value
|
|
340
|
-
* @param requestUrl - The full request URL for origin comparison
|
|
341
|
-
* @returns An error Response if validation fails, or the normalized image URL
|
|
342
|
-
*/
|
|
343
|
-
function validateImageUrl(rawUrl, requestUrl) {
|
|
344
|
-
const imgUrl = rawUrl?.replaceAll("\\", "/") ?? null;
|
|
345
|
-
if (!imgUrl || !imgUrl.startsWith("/") || imgUrl.startsWith("//")) return new Response(!rawUrl ? "Missing url parameter" : "Only relative URLs allowed", { status: 400 });
|
|
346
|
-
const url = new URL(requestUrl);
|
|
347
|
-
if (new URL(imgUrl, url.origin).origin !== url.origin) return new Response("Only relative URLs allowed", { status: 400 });
|
|
348
|
-
return imgUrl;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
362
|
* Strip internal `x-middleware-*` headers from a Headers object.
|
|
352
363
|
*
|
|
353
364
|
* Middleware uses `x-middleware-*` headers as internal signals (e.g.
|
|
@@ -465,4 +476,4 @@ function cloneRequestWithUrl(request, url) {
|
|
|
465
476
|
return cloned;
|
|
466
477
|
}
|
|
467
478
|
//#endregion
|
|
468
|
-
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin,
|
|
479
|
+
export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
//#region src/server/rsc-stream-hints.d.ts
|
|
2
2
|
declare function normalizeReactFlightPreloadHints(stream: ReadableStream<Uint8Array>): ReadableStream<Uint8Array>;
|
|
3
3
|
type RscRawRenderer = (model: unknown, options?: unknown) => ReadableStream<Uint8Array>;
|
|
4
|
+
type RscRawPrerenderer = (model: unknown, options?: unknown) => Promise<{
|
|
5
|
+
prelude: ReadableStream<Uint8Array>;
|
|
6
|
+
}>;
|
|
4
7
|
declare function createRscRenderer(render: RscRawRenderer): RscRawRenderer;
|
|
8
|
+
declare function createRscPrerenderer(prerender: RscRawPrerenderer): RscRawPrerenderer;
|
|
5
9
|
//#endregion
|
|
6
|
-
export { createRscRenderer, normalizeReactFlightPreloadHints };
|
|
10
|
+
export { RscRawPrerenderer, RscRawRenderer, createRscPrerenderer, createRscRenderer, normalizeReactFlightPreloadHints };
|
|
@@ -32,5 +32,10 @@ function normalizeReactFlightPreloadHints(stream) {
|
|
|
32
32
|
function createRscRenderer(render) {
|
|
33
33
|
return (model, options) => normalizeReactFlightPreloadHints(render(model, options));
|
|
34
34
|
}
|
|
35
|
+
function createRscPrerenderer(prerender) {
|
|
36
|
+
return async (model, options) => {
|
|
37
|
+
return { prelude: normalizeReactFlightPreloadHints((await prerender(model, options)).prelude) };
|
|
38
|
+
};
|
|
39
|
+
}
|
|
35
40
|
//#endregion
|
|
36
|
-
export { createRscRenderer, normalizeReactFlightPreloadHints };
|
|
41
|
+
export { createRscPrerenderer, createRscRenderer, normalizeReactFlightPreloadHints };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { normalizePathnameForRouteMatch } from "../routing/utils.js";
|
|
2
|
-
import { normalizePath } from "./normalize-path.js";
|
|
3
1
|
import { isrCacheKey, isrSetPrerenderedAppPage } from "./isr-cache.js";
|
|
4
2
|
import { buildAppPageCacheTags } from "./app-page-cache.js";
|
|
5
3
|
import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
|
|
4
|
+
import { addPregeneratedConcretePath, clearPregeneratedConcretePaths, normalizePregeneratedPathname } from "./pregenerated-concrete-paths.js";
|
|
5
|
+
import { getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
//#region src/server/seed-cache.ts
|
|
@@ -46,26 +46,21 @@ import path from "node:path";
|
|
|
46
46
|
* @returns The number of routes seeded (0 if no manifest or no renderable routes).
|
|
47
47
|
*/
|
|
48
48
|
async function seedMemoryCacheFromPrerender(serverDir, options) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
54
|
-
} catch (err) {
|
|
55
|
-
console.warn("[vinext] Failed to parse vinext-prerender.json, skipping cache seeding:", err);
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
49
|
+
clearPregeneratedConcretePaths();
|
|
50
|
+
const manifest = readPrerenderManifest(path.join(serverDir, "vinext-prerender.json"));
|
|
51
|
+
if (!manifest) return 0;
|
|
58
52
|
const { buildId, routes } = manifest;
|
|
59
53
|
if (!buildId || !Array.isArray(routes)) return 0;
|
|
60
54
|
const trailingSlash = manifest.trailingSlash ?? false;
|
|
61
55
|
const prerenderDir = path.join(serverDir, "prerendered-routes");
|
|
62
56
|
const writeAppPageEntry = options?.writeAppPageEntry ?? createDefaultAppPageEntryWriter();
|
|
63
57
|
let seeded = 0;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
const appRoutes = getRenderedAppRoutes(routes);
|
|
59
|
+
for (const route of appRoutes) {
|
|
60
|
+
const concretePathname = route.path ?? route.route;
|
|
61
|
+
if (!isFallbackShellArtifactPath(concretePathname, route)) addPregeneratedConcretePath(route.route, concretePathname);
|
|
67
62
|
const artifactPathname = route.path ?? route.route;
|
|
68
|
-
const cachePathname =
|
|
63
|
+
const cachePathname = normalizePregeneratedPathname(artifactPathname);
|
|
69
64
|
const baseKey = isrCacheKey("app", cachePathname, buildId);
|
|
70
65
|
const htmlKey = options?.buildAppPageHtmlKey?.(cachePathname) ?? baseKey + ":html";
|
|
71
66
|
const rscKey = options?.buildAppPageRscKey?.(cachePathname) ?? baseKey + ":rsc";
|
|
@@ -79,9 +74,6 @@ async function seedMemoryCacheFromPrerender(serverDir, options) {
|
|
|
79
74
|
}
|
|
80
75
|
return seeded;
|
|
81
76
|
}
|
|
82
|
-
function normalizePrerenderCachePathname(pathname) {
|
|
83
|
-
return normalizePath(normalizePathnameForRouteMatch(pathname));
|
|
84
|
-
}
|
|
85
77
|
function createDefaultAppPageEntryWriter() {
|
|
86
78
|
return (key, data, metadata) => isrSetPrerenderedAppPage(key, data, metadata);
|
|
87
79
|
}
|
|
@@ -3,11 +3,13 @@ type AppRouterScrollIntent = Readonly<{
|
|
|
3
3
|
commitId: number | null;
|
|
4
4
|
hash: string | null;
|
|
5
5
|
id: number;
|
|
6
|
+
targetHoistedInHead: boolean;
|
|
6
7
|
}>;
|
|
7
8
|
declare function beginAppRouterScrollIntent(hash: string | null): AppRouterScrollIntent;
|
|
8
9
|
declare function clearAppRouterScrollIntent(): void;
|
|
9
10
|
declare function getPendingAppRouterScrollIntent(): AppRouterScrollIntent | null;
|
|
10
11
|
declare function claimAppRouterScrollIntentForCommit(expected: AppRouterScrollIntent | null | undefined, commitId: number): void;
|
|
12
|
+
declare function markAppRouterScrollIntentHeadHoisted(expected: AppRouterScrollIntent | null | undefined, commitId: number): void;
|
|
11
13
|
declare function consumeAppRouterScrollIntent(expected: AppRouterScrollIntent | null | undefined, commitId?: number): AppRouterScrollIntent | null;
|
|
12
14
|
//#endregion
|
|
13
|
-
export { AppRouterScrollIntent, beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent };
|
|
15
|
+
export { AppRouterScrollIntent, beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent, markAppRouterScrollIntentHeadHoisted };
|
|
@@ -14,7 +14,8 @@ function beginAppRouterScrollIntent(hash) {
|
|
|
14
14
|
const intent = {
|
|
15
15
|
commitId: null,
|
|
16
16
|
hash,
|
|
17
|
-
id: store.nextId
|
|
17
|
+
id: store.nextId,
|
|
18
|
+
targetHoistedInHead: false
|
|
18
19
|
};
|
|
19
20
|
store.pending = intent;
|
|
20
21
|
return intent;
|
|
@@ -35,6 +36,17 @@ function claimAppRouterScrollIntentForCommit(expected, commitId) {
|
|
|
35
36
|
commitId
|
|
36
37
|
};
|
|
37
38
|
}
|
|
39
|
+
function markAppRouterScrollIntentHeadHoisted(expected, commitId) {
|
|
40
|
+
const store = getScrollIntentStore();
|
|
41
|
+
const intent = store.pending;
|
|
42
|
+
if (expected === null || expected === void 0 || intent === null) return;
|
|
43
|
+
if (intent.id !== expected.id) return;
|
|
44
|
+
if (intent.commitId !== commitId) return;
|
|
45
|
+
store.pending = {
|
|
46
|
+
...intent,
|
|
47
|
+
targetHoistedInHead: true
|
|
48
|
+
};
|
|
49
|
+
}
|
|
38
50
|
function consumeAppRouterScrollIntent(expected, commitId) {
|
|
39
51
|
if (expected === null || expected === void 0) return null;
|
|
40
52
|
const store = getScrollIntentStore();
|
|
@@ -46,4 +58,4 @@ function consumeAppRouterScrollIntent(expected, commitId) {
|
|
|
46
58
|
return intent;
|
|
47
59
|
}
|
|
48
60
|
//#endregion
|
|
49
|
-
export { beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent };
|
|
61
|
+
export { beginAppRouterScrollIntent, claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent, markAppRouterScrollIntentHeadHoisted };
|
|
@@ -5,9 +5,12 @@ declare class AppRouterScrollTargetInner extends React$1.Component<{
|
|
|
5
5
|
children: React$1.ReactNode;
|
|
6
6
|
commitId: number | null;
|
|
7
7
|
}> {
|
|
8
|
+
scheduledCommitId: number | null;
|
|
9
|
+
schedulePotentialScroll: () => void;
|
|
8
10
|
handlePotentialScroll: () => void;
|
|
9
11
|
componentDidMount(): void;
|
|
10
12
|
componentDidUpdate(): void;
|
|
13
|
+
componentWillUnmount(): void;
|
|
11
14
|
render(): React$1.ReactNode;
|
|
12
15
|
}
|
|
13
16
|
declare function AppRouterScrollCommitProvider({
|