vinext 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -10
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- package/dist/build/client-build-config.d.ts +10 -0
- package/dist/build/client-build-config.js +18 -2
- package/dist/build/pages-client-assets-module.d.ts +8 -0
- package/dist/build/pages-client-assets-module.js +21 -1
- package/dist/build/prerender-paths.js +8 -81
- package/dist/build/prerender.js +33 -8
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/server-manifest.d.ts +7 -0
- package/dist/build/server-manifest.js +11 -1
- package/dist/build/ssr-manifest.d.ts +2 -0
- package/dist/build/ssr-manifest.js +6 -2
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +3 -3
- package/dist/check.js +7 -6
- package/dist/cli.js +2 -1
- package/dist/client/client-redirect-matcher.d.ts +14 -0
- package/dist/client/client-redirect-matcher.js +37 -0
- package/dist/client/client-redirects.d.ts +27 -0
- package/dist/client/client-redirects.js +28 -0
- package/dist/client/client-rewrites.d.ts +2 -1
- package/dist/client/client-rewrites.js +1 -1
- package/dist/client/navigation-runtime.d.ts +11 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.d.ts +26 -11
- package/dist/config/config-matchers.js +81 -82
- package/dist/config/destination-params.d.ts +47 -0
- package/dist/config/destination-params.js +116 -0
- package/dist/config/next-config.d.ts +14 -0
- package/dist/config/next-config.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +6 -0
- package/dist/entries/app-rsc-entry.js +84 -49
- package/dist/entries/pages-client-entry.js +3 -1
- package/dist/entries/pages-server-entry.js +13 -37
- package/dist/index.d.ts +7 -2
- package/dist/index.js +193 -73
- package/dist/init-cloudflare.d.ts +9 -0
- package/dist/init-cloudflare.js +107 -31
- package/dist/init-platform.d.ts +4 -0
- package/dist/init-platform.js +27 -2
- package/dist/init.d.ts +1 -0
- package/dist/init.js +67 -3
- package/dist/plugins/ast-scope.d.ts +7 -0
- package/dist/plugins/ast-scope.js +59 -3
- package/dist/plugins/cache-flight-codec.d.ts +19 -0
- package/dist/plugins/cache-flight-codec.js +68 -0
- package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
- package/dist/plugins/commonjs-esm-facade.js +80 -0
- package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
- package/dist/plugins/dynamic-preload-metadata.js +9 -8
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +3 -4
- package/dist/plugins/middleware-server-only.d.ts +5 -4
- package/dist/plugins/middleware-server-only.js +8 -5
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
- package/dist/plugins/rsc-scan-glob-imports.js +50 -0
- package/dist/plugins/strip-server-exports.js +262 -98
- package/dist/plugins/transform-result.d.ts +9 -5
- package/dist/plugins/transitive-externals.js +1 -1
- package/dist/plugins/typeof-window.d.ts +2 -2
- package/dist/plugins/use-cache-callable.js +8 -2
- package/dist/plugins/worker-server-only-imports.d.ts +20 -0
- package/dist/plugins/worker-server-only-imports.js +31 -0
- package/dist/plugins/worker-use-server.d.ts +25 -0
- package/dist/plugins/worker-use-server.js +129 -0
- package/dist/routing/file-matcher.d.ts +1 -0
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/api-handler.d.ts +1 -0
- package/dist/server/api-handler.js +19 -8
- package/dist/server/app-browser-action-result.d.ts +1 -1
- package/dist/server/app-browser-action-result.js +9 -2
- package/dist/server/app-browser-entry.js +11 -7
- package/dist/server/app-browser-history-controller.d.ts +2 -0
- package/dist/server/app-browser-history-controller.js +8 -0
- package/dist/server/app-browser-interception-context.js +26 -2
- package/dist/server/app-browser-navigation-controller.d.ts +7 -1
- package/dist/server/app-browser-navigation-controller.js +94 -11
- package/dist/server/app-browser-server-action-client.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +2 -0
- package/dist/server/app-fallback-renderer.js +1 -0
- package/dist/server/app-history-state.d.ts +3 -0
- package/dist/server/app-history-state.js +7 -0
- package/dist/server/app-middleware.d.ts +11 -0
- package/dist/server/app-middleware.js +19 -3
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +5 -0
- package/dist/server/app-page-boundary-render.js +6 -4
- package/dist/server/app-page-cache-finalizer.d.ts +11 -0
- package/dist/server/app-page-cache-finalizer.js +41 -7
- package/dist/server/app-page-cache-render.d.ts +18 -0
- package/dist/server/app-page-cache-render.js +63 -43
- package/dist/server/app-page-cache.d.ts +6 -1
- package/dist/server/app-page-cache.js +28 -8
- package/dist/server/app-page-dispatch.d.ts +12 -2
- package/dist/server/app-page-dispatch.js +51 -33
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +27 -42
- package/dist/server/app-page-execution.d.ts +15 -12
- package/dist/server/app-page-execution.js +30 -40
- package/dist/server/app-page-head.d.ts +5 -0
- package/dist/server/app-page-head.js +9 -3
- package/dist/server/app-page-ppr-runtime.js +1 -1
- package/dist/server/app-page-probe.d.ts +0 -109
- package/dist/server/app-page-probe.js +3 -136
- package/dist/server/app-page-render-identity.d.ts +0 -1
- package/dist/server/app-page-render-identity.js +1 -1
- package/dist/server/app-page-render-observation.js +3 -3
- package/dist/server/app-page-render.d.ts +13 -5
- package/dist/server/app-page-render.js +219 -119
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +54 -17
- package/dist/server/app-page-response.d.ts +4 -3
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-route-wiring.d.ts +17 -5
- package/dist/server/app-page-route-wiring.js +57 -35
- package/dist/server/app-page-rsc-render-status.d.ts +48 -0
- package/dist/server/app-page-rsc-render-status.js +54 -0
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +6 -0
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -3
- package/dist/server/app-prerender-endpoints.js +9 -6
- package/dist/server/app-request-stage-dispatch.js +7 -3
- package/dist/server/app-request-stage-independent-entry.js +29 -9
- package/dist/server/app-response-header-provenance.d.ts +2 -0
- package/dist/server/app-response-header-provenance.js +10 -4
- package/dist/server/app-response-stage-entry.js +10 -2
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +6 -3
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +45 -24
- package/dist/server/app-router-entry.js +27 -8
- package/dist/server/app-rsc-cache-busting.js +1 -1
- package/dist/server/app-rsc-errors.js +20 -16
- package/dist/server/app-rsc-handler.d.ts +11 -0
- package/dist/server/app-rsc-handler.js +291 -125
- package/dist/server/app-rsc-request-normalization.d.ts +3 -1
- package/dist/server/app-rsc-request-normalization.js +4 -2
- package/dist/server/app-rsc-response-stage.d.ts +1 -1
- package/dist/server/app-rsc-response-stage.js +10 -6
- package/dist/server/app-rsc-route-matching.d.ts +9 -1
- package/dist/server/app-rsc-route-matching.js +36 -19
- package/dist/server/app-segment-config.d.ts +2 -1
- package/dist/server/app-server-action-execution.d.ts +2 -1
- package/dist/server/app-server-action-execution.js +62 -23
- package/dist/server/app-ssr-entry.d.ts +3 -2
- package/dist/server/app-ssr-entry.js +8 -5
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +34 -15
- package/dist/server/app-worker-stages.d.ts +7 -2
- package/dist/server/app-worker-stages.js +4 -4
- package/dist/server/cacheability-request.js +11 -7
- package/dist/server/client-build-files.d.ts +16 -0
- package/dist/server/client-build-files.js +36 -0
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/config-headers.js +2 -0
- package/dist/server/dev-server.js +50 -29
- package/dist/server/dev-stack-sourcemap.js +18 -23
- package/dist/server/document-initial-head.d.ts +0 -11
- package/dist/server/document-initial-head.js +1 -1
- package/dist/server/forwarded-middleware-context.d.ts +5 -0
- package/dist/server/forwarded-middleware-context.js +22 -0
- package/dist/server/headers.d.ts +18 -1
- package/dist/server/headers.js +19 -2
- package/dist/server/http-conditional.d.ts +11 -0
- package/dist/server/http-conditional.js +10 -1
- package/dist/server/http-error-responses.d.ts +1 -1
- package/dist/server/image-optimization.d.ts +54 -0
- package/dist/server/image-optimization.js +118 -9
- package/dist/server/isr-cache.d.ts +10 -0
- package/dist/server/isr-cache.js +43 -8
- package/dist/server/metadata-route-response.js +9 -8
- package/dist/server/middleware-matcher-pattern.js +8 -4
- package/dist/server/middleware-matcher.d.ts +2 -0
- package/dist/server/middleware-matcher.js +23 -2
- package/dist/server/middleware-response-headers.js +2 -0
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +33 -20
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +3 -1
- package/dist/server/multi-stage.d.ts +19 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/node-response-signal.d.ts +16 -0
- package/dist/server/node-response-signal.js +26 -0
- package/dist/server/normalize-path.d.ts +0 -13
- package/dist/server/normalize-path.js +1 -34
- package/dist/server/open-redirect.d.ts +47 -0
- package/dist/server/open-redirect.js +74 -1
- package/dist/server/pages-api-route.d.ts +3 -2
- package/dist/server/pages-api-route.js +4 -3
- package/dist/server/pages-cache-tag.d.ts +12 -0
- package/dist/server/pages-cache-tag.js +19 -0
- package/dist/server/pages-client-assets.d.ts +2 -0
- package/dist/server/pages-data-route.d.ts +10 -0
- package/dist/server/pages-data-route.js +19 -2
- package/dist/server/pages-document-asset-props.d.ts +5 -1
- package/dist/server/pages-document-asset-props.js +13 -5
- package/dist/server/pages-document-splice.d.ts +19 -0
- package/dist/server/pages-document-splice.js +55 -0
- package/dist/server/pages-i18n.d.ts +12 -1
- package/dist/server/pages-i18n.js +18 -4
- package/dist/server/pages-node-compat.d.ts +16 -5
- package/dist/server/pages-node-compat.js +20 -12
- package/dist/server/pages-page-data.d.ts +32 -24
- package/dist/server/pages-page-data.js +50 -120
- package/dist/server/pages-page-handler.d.ts +0 -6
- package/dist/server/pages-page-handler.js +209 -130
- package/dist/server/pages-page-response.d.ts +12 -6
- package/dist/server/pages-page-response.js +41 -34
- package/dist/server/pages-request-pipeline.d.ts +10 -2
- package/dist/server/pages-request-pipeline.js +37 -18
- package/dist/server/pages-request-stage-entry.d.ts +6 -0
- package/dist/server/pages-request-stage-entry.js +79 -16
- package/dist/server/pages-response-stage-entry.js +4 -0
- package/dist/server/pages-revalidate.js +1 -1
- package/dist/server/pages-router-entry.js +4 -3
- package/dist/server/prerender-manifest.d.ts +3 -3
- package/dist/server/prerender-manifest.js +4 -3
- package/dist/server/prerender-work-unit-setup.js +4 -0
- package/dist/server/prod-server.d.ts +20 -7
- package/dist/server/prod-server.js +343 -129
- package/dist/server/proper-error.d.ts +4 -0
- package/dist/server/proper-error.js +31 -0
- package/dist/server/request-pipeline.d.ts +24 -9
- package/dist/server/request-pipeline.js +24 -9
- package/dist/server/response-compression.d.ts +43 -0
- package/dist/server/response-compression.js +111 -0
- package/dist/server/revalidation-request.d.ts +1 -0
- package/dist/server/revalidation-request.js +1 -1
- package/dist/server/rsc-stream-hints.js +31 -2
- package/dist/server/seed-cache.d.ts +1 -0
- package/dist/server/seed-cache.js +15 -11
- package/dist/server/server-reference-loader.d.ts +4 -0
- package/dist/server/server-reference-loader.js +29 -0
- package/dist/server/socket-error-backstop.d.ts +23 -1
- package/dist/server/socket-error-backstop.js +69 -17
- package/dist/server/static-file-signal.d.ts +15 -4
- package/dist/server/static-file-signal.js +46 -12
- package/dist/server/worker-image-optimization.d.ts +34 -0
- package/dist/server/worker-image-optimization.js +86 -0
- package/dist/server/worker-stages.d.ts +1 -1
- package/dist/server/worker-stages.js +2 -2
- package/dist/server/worker-utils.d.ts +8 -3
- package/dist/server/worker-utils.js +12 -7
- package/dist/shims/app-router-scroll.js +4 -1
- package/dist/shims/app-router-tree-context.d.ts +5 -0
- package/dist/shims/app-router-tree-context.js +27 -0
- package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
- package/dist/shims/cache-adapter-instantiate.js +118 -0
- package/dist/shims/cache-callable-runtime.d.ts +6 -42
- package/dist/shims/cache-callable-runtime.js +65 -174
- package/dist/shims/cache-flight-arguments.d.ts +22 -0
- package/dist/shims/cache-flight-arguments.js +56 -0
- package/dist/shims/cache-handler.js +1 -9
- package/dist/shims/cache-request-state.d.ts +15 -0
- package/dist/shims/cache-request-state.js +31 -8
- package/dist/shims/cache-runtime.d.ts +12 -20
- package/dist/shims/cache-runtime.js +166 -225
- package/dist/shims/cache.d.ts +4 -4
- package/dist/shims/cache.js +44 -16
- package/dist/shims/cacheability-classification.d.ts +7 -0
- package/dist/shims/cdn-cache.d.ts +8 -0
- package/dist/shims/cdn-cache.js +17 -1
- package/dist/shims/disable-smooth-scroll.d.ts +3 -0
- package/dist/shims/disable-smooth-scroll.js +36 -0
- package/dist/shims/document-placeholders.d.ts +19 -0
- package/dist/shims/document-placeholders.js +45 -0
- package/dist/shims/document.js +21 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
- package/dist/shims/dynamic-preload-chunks.js +13 -9
- package/dist/shims/dynamic.d.ts +1 -1
- package/dist/shims/dynamic.js +60 -8
- package/dist/shims/error-boundary-navigation.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.js +19 -1
- package/dist/shims/error-boundary.d.ts +10 -10
- package/dist/shims/error-boundary.js +26 -7
- package/dist/shims/fetch-cache-state.d.ts +66 -0
- package/dist/shims/fetch-cache-state.js +92 -0
- package/dist/shims/fetch-cache.d.ts +3 -61
- package/dist/shims/fetch-cache.js +161 -108
- package/dist/shims/form.js +1 -1
- package/dist/shims/head.d.ts +10 -6
- package/dist/shims/head.js +15 -13
- package/dist/shims/headers.d.ts +13 -0
- package/dist/shims/headers.js +47 -4
- package/dist/shims/image.js +2 -1
- package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
- package/dist/shims/internal/app-page-props-cache-key.js +24 -15
- package/dist/shims/internal/headers-state.d.ts +0 -1
- package/dist/shims/internal/work-store-scope.d.ts +5 -0
- package/dist/shims/internal/work-store-scope.js +24 -0
- package/dist/shims/metadata.js +3 -3
- package/dist/shims/navigation-errors.d.ts +6 -0
- package/dist/shims/navigation-errors.js +11 -1
- package/dist/shims/navigation.d.ts +7 -0
- package/dist/shims/navigation.js +45 -9
- package/dist/shims/request-context.d.ts +11 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/router.js +12 -20
- package/dist/shims/server.d.ts +16 -0
- package/dist/shims/server.js +24 -4
- package/dist/shims/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/shims/url-utils.d.ts +2 -0
- package/dist/shims/url-utils.js +3 -1
- package/dist/utils/client-runtime-metadata.js +1 -1
- package/dist/utils/hash.d.ts +7 -0
- package/dist/utils/hash.js +11 -1
- package/dist/utils/mdx-scan.d.ts +5 -0
- package/dist/utils/mdx-scan.js +8 -1
- package/dist/utils/package-name.d.ts +6 -0
- package/dist/utils/package-name.js +12 -1
- package/dist/utils/plugin-rsc-version.d.ts +4 -0
- package/dist/utils/plugin-rsc-version.js +15 -0
- package/dist/utils/prerender-output-paths.js +15 -4
- package/dist/utils/public-file-path.d.ts +10 -2
- package/dist/utils/public-file-path.js +13 -9
- package/dist/utils/public-routes.js +2 -2
- package/dist/utils/react-version.d.ts +3 -0
- package/dist/utils/react-version.js +1 -1
- package/dist/utils/regex-safety.d.ts +10 -0
- package/dist/utils/regex-safety.js +70 -18
- package/package.json +9 -5
|
@@ -35,7 +35,9 @@ export type NormalizedRscRequest = {
|
|
|
35
35
|
*
|
|
36
36
|
* 1. Parse URL
|
|
37
37
|
* 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses
|
|
38
|
-
* `//` to `/`.
|
|
38
|
+
* `//` to `/`. Literal repeated slashes / backslashes get Next.js's 308 to the
|
|
39
|
+
* collapsed path; encoded leading `%2F` / `%5C` get a 404. If the guard ran after
|
|
40
|
+
* normalization, `//evil.com` → `/evil.com`
|
|
39
41
|
* would bypass the check and reach the trailing-slash redirector, which echoes the
|
|
40
42
|
* path into a `Location` header that browsers interpret as protocol-relative.
|
|
41
43
|
* 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must
|
|
@@ -69,7 +69,9 @@ function tryNormalizeComparablePathAndSearch(value, basePath, baseUrl) {
|
|
|
69
69
|
*
|
|
70
70
|
* 1. Parse URL
|
|
71
71
|
* 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses
|
|
72
|
-
* `//` to `/`.
|
|
72
|
+
* `//` to `/`. Literal repeated slashes / backslashes get Next.js's 308 to the
|
|
73
|
+
* collapsed path; encoded leading `%2F` / `%5C` get a 404. If the guard ran after
|
|
74
|
+
* normalization, `//evil.com` → `/evil.com`
|
|
73
75
|
* would bypass the check and reach the trailing-slash redirector, which echoes the
|
|
74
76
|
* path into a `Location` header that browsers interpret as protocol-relative.
|
|
75
77
|
* 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must
|
|
@@ -91,7 +93,7 @@ function tryNormalizeComparablePathAndSearch(value, basePath, baseUrl) {
|
|
|
91
93
|
*/
|
|
92
94
|
function normalizeRscRequest(request, basePath, allowOutsideBasePath = false, assetPrefix = "") {
|
|
93
95
|
const url = new URL(request.url);
|
|
94
|
-
const protoGuard = guardProtocolRelativeUrl(url.pathname);
|
|
96
|
+
const protoGuard = guardProtocolRelativeUrl(url.pathname, url.search);
|
|
95
97
|
if (protoGuard) return protoGuard;
|
|
96
98
|
let decoded;
|
|
97
99
|
try {
|
|
@@ -2,5 +2,5 @@ import { VinextResponseStageDispatchOptions } from "./multi-stage.js";
|
|
|
2
2
|
import { AppWorkerResponseStageProps } from "./app-worker-stages.js";
|
|
3
3
|
import { AppRscHandlerRoute, CreateAppRscHandlerOptions } from "./app-rsc-handler.js";
|
|
4
4
|
//#region src/server/app-rsc-response-stage.d.ts
|
|
5
|
-
export declare function renderAppWorkerResponseStage<TRoute extends AppRscHandlerRoute>(options: CreateAppRscHandlerOptions<TRoute>, rawRequest: Request, ctx: unknown, props: AppWorkerResponseStageProps,
|
|
5
|
+
export declare function renderAppWorkerResponseStage<TRoute extends AppRscHandlerRoute>(options: CreateAppRscHandlerOptions<TRoute>, rawRequest: Request, ctx: unknown, props: AppWorkerResponseStageProps, stageOptions?: VinextResponseStageDispatchOptions): Promise<Response>;
|
|
6
6
|
//#endregion
|
|
@@ -3,6 +3,7 @@ import { closeAfterResponse, closeAfterResponseWithBody, createRequestContext, r
|
|
|
3
3
|
import { VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
|
|
4
4
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
5
5
|
import "./headers.js";
|
|
6
|
+
import { runOutsideWorkStoreScope } from "../shims/internal/work-store-scope.js";
|
|
6
7
|
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders } from "./request-pipeline.js";
|
|
7
8
|
import { applyEffectiveRequestCookieHeader, getDraftModeCookieHeader, headersContextFromRequest, restoreDraftModeTransition } from "../shims/headers.js";
|
|
8
9
|
import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
|
|
@@ -60,14 +61,15 @@ function rematchAppWorkerResponseStageRoute(options, normalized, props) {
|
|
|
60
61
|
let match = null;
|
|
61
62
|
if (props.matchKind === "interception") {
|
|
62
63
|
if (normalized.interceptionContextHeader !== null) match = options.matchInterceptRoute?.(props.routePathname, normalized.interceptionContextHeader, props.interceptionId) ?? null;
|
|
63
|
-
} else if (props.matchKind === "request") match = options.
|
|
64
|
+
} else if (props.matchKind === "raw-request") match = options.matchRawRequestRoute?.(props.routePathname) ?? null;
|
|
65
|
+
else if (props.matchKind === "request") match = options.matchRequestRoute?.(props.routePathname) ?? null;
|
|
64
66
|
else match = options.matchRoute(props.routePathname);
|
|
65
67
|
if (!match) return null;
|
|
66
68
|
if (match.route.pattern !== props.routePattern || !haveSamePageParams(match.params, props.params)) return null;
|
|
67
69
|
return match;
|
|
68
70
|
}
|
|
69
|
-
async function renderAppWorkerResponseStage(options, rawRequest, ctx, props,
|
|
70
|
-
if (props.protocolVersion !==
|
|
71
|
+
async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, stageOptions) {
|
|
72
|
+
if (props.protocolVersion !== 11 || props.buildId !== options.buildId) return new Response("Incompatible vinext App response stage", { status: 409 });
|
|
71
73
|
if (props.kind === "app-full-request") return new Response("Invalid vinext App response stage", { status: 400 });
|
|
72
74
|
options.registerCacheAdapters();
|
|
73
75
|
await options.ensureInstrumentation?.();
|
|
@@ -152,7 +154,8 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, _st
|
|
|
152
154
|
const pageRequest = props.isDataRequest ? cloneRequestWithUrl(request, new URL(props.resolvedUrl, request.url).toString()) : request;
|
|
153
155
|
const preHandlerHeaders = props.preHandlerHeaders === null ? void 0 : new Headers(props.preHandlerHeaders);
|
|
154
156
|
preHandlerHeaders?.delete("Content-Length");
|
|
155
|
-
|
|
157
|
+
const renderPagesFallback = options.renderPagesFallback;
|
|
158
|
+
let pagesResponse = await runOutsideWorkStoreScope(() => renderPagesFallback({
|
|
156
159
|
allowRscDocumentFallback: props.allowRscDocumentFallback,
|
|
157
160
|
appRouteMatch: props.appRouteMatch ? { route: {
|
|
158
161
|
isDynamic: props.appRouteMatch.isDynamic,
|
|
@@ -167,7 +170,7 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, _st
|
|
|
167
170
|
pagesDataRequest: props.isDataRequest ? request : null,
|
|
168
171
|
request: pageRequest,
|
|
169
172
|
url: new URL(props.requestUrl)
|
|
170
|
-
});
|
|
173
|
+
}));
|
|
171
174
|
if (!pagesResponse) return new Response("Invalid vinext App response stage", { status: 404 });
|
|
172
175
|
if (preHandlerHeaders) pagesResponse = stripInheritedResponseStageCookies(pagesResponse, preHandlerHeaders);
|
|
173
176
|
return pagesResponse;
|
|
@@ -232,7 +235,8 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, _st
|
|
|
232
235
|
route,
|
|
233
236
|
searchParams,
|
|
234
237
|
scriptNonce: props.scriptNonce ?? void 0,
|
|
235
|
-
renderMode: normalized.renderMode
|
|
238
|
+
renderMode: normalized.renderMode,
|
|
239
|
+
renderWholeDocument: stageOptions?.renderWholeDocument === true
|
|
236
240
|
});
|
|
237
241
|
}, {
|
|
238
242
|
cacheComponents: options.createPprFallbackShells !== void 0,
|
|
@@ -120,7 +120,11 @@ type AppRscInterceptLookupEntry = {
|
|
|
120
120
|
slotId: string | null;
|
|
121
121
|
targetRouteGraphId: string | null;
|
|
122
122
|
};
|
|
123
|
-
|
|
123
|
+
/**
|
|
124
|
+
* @param decodedPathnamePatterns Static page patterns that answer their
|
|
125
|
+
* segment-decoded pathname (built by `buildAppDecodedPathnamePatterns`).
|
|
126
|
+
*/
|
|
127
|
+
export declare function createAppRscRouteMatcher<Route extends AppRscRouteForMatching>(routes: Route[], decodedPathnamePatterns?: readonly string[]): {
|
|
124
128
|
hasInterceptionId(interceptionId: string): boolean;
|
|
125
129
|
matchRoute(url: string): {
|
|
126
130
|
route: Route;
|
|
@@ -130,6 +134,10 @@ export declare function createAppRscRouteMatcher<Route extends AppRscRouteForMat
|
|
|
130
134
|
route: Route;
|
|
131
135
|
params: AppRscRouteParams;
|
|
132
136
|
} | null;
|
|
137
|
+
matchRawRequestRoute(url: string): {
|
|
138
|
+
route: Route;
|
|
139
|
+
params: AppRscRouteParams;
|
|
140
|
+
} | null;
|
|
133
141
|
findIntercept(pathname: string, sourcePathname?: string | null, interceptionId?: string | null): AppRscInterceptMatch | null;
|
|
134
142
|
};
|
|
135
143
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeMatchedParams, splitPathSegments, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
1
|
+
import { decodeMatchedParams, decodeRouteSegment, splitPathSegments, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
2
2
|
import { createAppRouteGraphInterceptionId } from "../routing/app-route-ids.js";
|
|
3
3
|
import { buildRouteTrie, trieMatchRaw } from "../routing/route-trie.js";
|
|
4
4
|
import { extractRawRoutePatternParams, matchRoutePatternPrefix, matchRoutePatternRaw } from "../routing/route-pattern.js";
|
|
@@ -18,17 +18,6 @@ function appRscPathnameParts(pathname, isNormalized = false) {
|
|
|
18
18
|
const normalizedPathname = pathOnly === "/" ? "/" : pathOnly.replace(/\/$/, "");
|
|
19
19
|
return isNormalized ? splitPathSegments(normalizedPathname) : splitPathnameForRouteMatch(normalizedPathname);
|
|
20
20
|
}
|
|
21
|
-
function appRscInterceptionSourcePathnameParts(pathname) {
|
|
22
|
-
const pathOnly = pathname.split("?")[0];
|
|
23
|
-
const normalizedPathname = pathOnly === "/" ? "/" : pathOnly.replace(/\/$/, "");
|
|
24
|
-
return splitPathSegments(normalizedPathname).map((segment) => {
|
|
25
|
-
try {
|
|
26
|
-
return decodeURIComponent(segment);
|
|
27
|
-
} catch {
|
|
28
|
-
return segment;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
21
|
function isAppRouteHandlerRoute(route) {
|
|
33
22
|
return route.routeHandler != null || typeof route.__loadRouteHandler === "function";
|
|
34
23
|
}
|
|
@@ -36,11 +25,38 @@ function normalizeMatchedParamsForRoute(result) {
|
|
|
36
25
|
if (isAppRouteHandlerRoute(result.route)) decodeMatchedParams(result.params);
|
|
37
26
|
else canonicalizeAppPageParams(result.params);
|
|
38
27
|
}
|
|
39
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @param decodedPathnamePatterns Static page patterns that answer their
|
|
30
|
+
* segment-decoded pathname (built by `buildAppDecodedPathnamePatterns`).
|
|
31
|
+
*/
|
|
32
|
+
function createAppRscRouteMatcher(routes, decodedPathnamePatterns = []) {
|
|
40
33
|
const routeTrie = buildRouteTrie(routes);
|
|
41
34
|
const interceptLookup = createInterceptLookup(routes);
|
|
42
35
|
const interceptionIds = new Set(interceptLookup.flatMap((entry) => entry.interceptionId === null ? [] : [entry.interceptionId]));
|
|
43
36
|
const routeIndexes = new Map(routes.map((route, index) => [route, index]));
|
|
37
|
+
const decodedPathnamePatternSet = new Set(decodedPathnamePatterns);
|
|
38
|
+
const decodedPathnameRoutes = /* @__PURE__ */ new Map();
|
|
39
|
+
for (const route of routes) {
|
|
40
|
+
const key = route.patternParts.join("/");
|
|
41
|
+
if (decodedPathnamePatternSet.has(route.pattern) && !decodedPathnameRoutes.has(key)) decodedPathnameRoutes.set(key, route);
|
|
42
|
+
}
|
|
43
|
+
function matchRawRequestParts(rawParts) {
|
|
44
|
+
const result = trieMatchRaw(routeTrie, rawParts);
|
|
45
|
+
if (result) normalizeMatchedParamsForRoute(result);
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
function matchRequestParts(rawParts) {
|
|
49
|
+
const result = matchRawRequestParts(rawParts);
|
|
50
|
+
if (!result) return null;
|
|
51
|
+
if (decodedPathnameRoutes.size > 0 && result.route.patternParts.some((part) => part.startsWith(":")) && !isAppRouteHandlerRoute(result.route) && rawParts.some((part) => part.includes("%"))) {
|
|
52
|
+
const route = decodedPathnameRoutes.get(rawParts.map(decodeRouteSegment).join("/"));
|
|
53
|
+
if (route && route !== result.route) return {
|
|
54
|
+
route,
|
|
55
|
+
params: createRouteParams()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
44
60
|
return {
|
|
45
61
|
hasInterceptionId(interceptionId) {
|
|
46
62
|
return interceptionIds.has(interceptionId);
|
|
@@ -54,16 +70,16 @@ function createAppRscRouteMatcher(routes) {
|
|
|
54
70
|
return result;
|
|
55
71
|
},
|
|
56
72
|
matchRequestRoute(url) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return
|
|
73
|
+
return matchRequestParts(appRscPathnameParts(url, true));
|
|
74
|
+
},
|
|
75
|
+
matchRawRequestRoute(url) {
|
|
76
|
+
return matchRawRequestParts(appRscPathnameParts(url, true));
|
|
61
77
|
},
|
|
62
78
|
findIntercept(pathname, sourcePathname = null, interceptionId = null) {
|
|
63
79
|
if (sourcePathname === null) return null;
|
|
64
80
|
const urlParts = appRscPathnameParts(pathname, true);
|
|
65
|
-
const sourceParts =
|
|
66
|
-
const matchedSourceRoute =
|
|
81
|
+
const sourceParts = appRscPathnameParts(sourcePathname, true);
|
|
82
|
+
const matchedSourceRoute = matchRawRequestParts(sourceParts);
|
|
67
83
|
for (const entry of interceptLookup) {
|
|
68
84
|
if (interceptionId !== null && entry.interceptionId !== interceptionId) continue;
|
|
69
85
|
if (!matchInterceptSource(sourceParts, entry)) continue;
|
|
@@ -75,6 +91,7 @@ function createAppRscRouteMatcher(routes) {
|
|
|
75
91
|
const sourceRoute = routes[concreteSourceRouteIndex];
|
|
76
92
|
if (sourceRoute && isAppRouteHandlerRoute(sourceRoute)) continue;
|
|
77
93
|
const matchedSourceParams = concreteSourceRoute ? concreteSourceRoute.params : sourceRoute ? matchSlotOwnerSourceParams(sourceParts, sourceRoute.patternParts, entry.sourceMatchPatternParts !== null) : null;
|
|
94
|
+
if (!concreteSourceRoute && matchedSourceParams) canonicalizeAppPageParams(matchedSourceParams);
|
|
78
95
|
if (matchedSourceParams === null && entry.sourceMatchPatternParts === null) continue;
|
|
79
96
|
const sourceParams = matchedSourceParams && entry.sourceMatchPatternParts !== null ? pickPatternParams(matchedSourceParams, entry.sourceMatchPatternParts) : matchedSourceParams ?? createRouteParams();
|
|
80
97
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { FetchCacheMode } from "../shims/fetch-cache.js";
|
|
1
|
+
import { FetchCacheMode } from "../shims/fetch-cache-state.js";
|
|
2
|
+
import "../shims/fetch-cache.js";
|
|
2
3
|
//#region src/server/app-segment-config.d.ts
|
|
3
4
|
type AppRouteSegmentDynamic = "auto" | "error" | "force-dynamic" | "force-static";
|
|
4
5
|
type AppRouteSegmentConfigModule = {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
2
2
|
import { ActionRevalidationKind } from "../shims/cache-request-state.js";
|
|
3
3
|
import { AppRenderErrorContextOverrides } from "./app-rsc-error-handler.js";
|
|
4
|
-
import { FetchCacheMode } from "../shims/fetch-cache.js";
|
|
4
|
+
import { FetchCacheMode } from "../shims/fetch-cache-state.js";
|
|
5
|
+
import "../shims/fetch-cache.js";
|
|
5
6
|
import { HeadersAccessPhase } from "../shims/internal/headers-state.js";
|
|
6
7
|
import "../shims/headers.js";
|
|
7
8
|
import { ReactFormState } from "react-dom/client";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runOutsideRequestScopes } from "../shims/internal/als-registry.js";
|
|
1
2
|
import { VINEXT_MW_CTX_HEADER } from "../utils/protocol-headers.js";
|
|
2
3
|
import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
|
|
3
4
|
import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
|
|
@@ -18,16 +19,34 @@ import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, createRscReques
|
|
|
18
19
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
19
20
|
import { applyEdgeRuntimeHeader } from "./app-page-response.js";
|
|
20
21
|
import { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
|
|
22
|
+
import { hasDigest } from "./app-rsc-errors.js";
|
|
21
23
|
import { buildAppPageTags } from "./implicit-tags.js";
|
|
24
|
+
import "./app-page-stream.js";
|
|
22
25
|
import { getSetCookieName } from "./cookie-utils.js";
|
|
23
26
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage, isServerActionNotFoundError } from "./server-action-not-found.js";
|
|
24
27
|
import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
|
|
25
|
-
import "./app-page-stream.js";
|
|
26
28
|
import { resolveAppPageActionRerenderTarget } from "./app-page-request.js";
|
|
27
29
|
import { createRootParamsUsageController, runWithRootParamsUsage } from "../shims/root-params.js";
|
|
28
30
|
import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
|
|
29
31
|
import { markAppRscResponseConfigHeadersApplied } from "./app-rsc-response-finalizer.js";
|
|
30
32
|
//#region src/server/app-server-action-execution.ts
|
|
33
|
+
/**
|
|
34
|
+
* Run a server-reference load or decode outside every request scope.
|
|
35
|
+
*
|
|
36
|
+
* Server reference modules are imported on the first request that names them
|
|
37
|
+
* — `loadServerAction()` imports the action's module, and the decoders import
|
|
38
|
+
* any reference the body carries — and a dynamic `import()` carries
|
|
39
|
+
* AsyncLocalStorage into the module's top-level evaluation. Module-scope
|
|
40
|
+
* `cookies()`/`headers()` would then capture that first caller's request for
|
|
41
|
+
* every later caller in the isolate. Next.js evaluates action modules outside
|
|
42
|
+
* the request store, where those calls throw.
|
|
43
|
+
*
|
|
44
|
+
* The result is awaited inside the callback because `decodeReply()` returns a
|
|
45
|
+
* lazy thenable that only resolves (and imports) its references once awaited.
|
|
46
|
+
*/
|
|
47
|
+
function loadOutsideRequestScopes(load) {
|
|
48
|
+
return runOutsideRequestScopes(async () => await load());
|
|
49
|
+
}
|
|
31
50
|
function parseBoundProgressiveActionReference(body, referencePrefix) {
|
|
32
51
|
const fieldPrefix = `$ACTION_${referencePrefix}:`;
|
|
33
52
|
const chunks = /* @__PURE__ */ new Map();
|
|
@@ -473,6 +492,25 @@ function shouldUseForwardedActionRedirectStatus(options) {
|
|
|
473
492
|
if (!options.currentRoute || !options.targetRoute || !options.resolveRouteRuntime) return false;
|
|
474
493
|
return normalizeRuntime(options.resolveRouteRuntime(options.currentRoute)) !== normalizeRuntime(options.resolveRouteRuntime(options.targetRoute));
|
|
475
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* A failed fetch action's result, as Next.js sends it: a rejected promise.
|
|
497
|
+
* React's Flight error channel reports the rejection through the render's
|
|
498
|
+
* onError and gives the client error its digest, where an Error value would
|
|
499
|
+
* reach the client without one.
|
|
500
|
+
*/
|
|
501
|
+
function createRejectedActionResult(error) {
|
|
502
|
+
const result = Promise.reject(error);
|
|
503
|
+
result.catch(() => {});
|
|
504
|
+
return result;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* In development the render's onError logs a rejected action result unless it
|
|
508
|
+
* already has a digest; log those here, so each failure is logged once. As in
|
|
509
|
+
* Next.js, a thrown string is not logged in development.
|
|
510
|
+
*/
|
|
511
|
+
function logRejectedActionResult(error) {
|
|
512
|
+
if (process.env.NODE_ENV === "production" || hasDigest(error)) console.error("[vinext] Server action error:", error);
|
|
513
|
+
}
|
|
476
514
|
function getActionHttpFallbackStatus(error) {
|
|
477
515
|
const digest = getNextErrorDigest(error);
|
|
478
516
|
if (!digest) return null;
|
|
@@ -559,7 +597,7 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
559
597
|
clearRequestContext: options.clearRequestContext,
|
|
560
598
|
getAndClearPendingCookies: options.getAndClearPendingCookies
|
|
561
599
|
});
|
|
562
|
-
const action = await options.decodeAction(body);
|
|
600
|
+
const action = await loadOutsideRequestScopes(() => options.decodeAction(body));
|
|
563
601
|
if (!isAppServerActionFunction(action)) {
|
|
564
602
|
if (options.hasPageRoute) return createActionNotFoundResponse(null, {
|
|
565
603
|
clearRequestContext: options.clearRequestContext,
|
|
@@ -579,6 +617,7 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
579
617
|
let actionRedirect = null;
|
|
580
618
|
let actionError = void 0;
|
|
581
619
|
let actionFailed = false;
|
|
620
|
+
let actionFailedWithError = false;
|
|
582
621
|
let actionThrew = false;
|
|
583
622
|
let actionResult;
|
|
584
623
|
const rootParamsUsage = createRootParamsUsageController();
|
|
@@ -591,7 +630,8 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
591
630
|
if (!actionRedirect) {
|
|
592
631
|
actionError = error;
|
|
593
632
|
actionFailed = true;
|
|
594
|
-
|
|
633
|
+
actionFailedWithError = getActionHttpFallbackStatus(error) === null && !isServerActionNotFoundError(error, null);
|
|
634
|
+
if (actionFailedWithError) {
|
|
595
635
|
console.error("[vinext] Server action error:", error);
|
|
596
636
|
options.reportRequestError(error, {
|
|
597
637
|
path: options.cleanPathname,
|
|
@@ -616,6 +656,15 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
616
656
|
const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());
|
|
617
657
|
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
618
658
|
const revalidationKind = resolveActionRevalidationKind(actionPendingCookies.length > 0 || Boolean(actionDraftCookie));
|
|
659
|
+
if (actionFailedWithError) {
|
|
660
|
+
options.clearRequestContext();
|
|
661
|
+
const headers = new Headers();
|
|
662
|
+
mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders);
|
|
663
|
+
headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
|
|
664
|
+
for (const cookie of actionPendingCookies) headers.append("Set-Cookie", cookie);
|
|
665
|
+
if (actionDraftCookie) headers.append("Set-Cookie", actionDraftCookie);
|
|
666
|
+
return internalServerErrorResponse(process.env.NODE_ENV === "production" ? void 0 : "Server action failed: " + getServerActionFailureMessage(actionError), { headers });
|
|
667
|
+
}
|
|
619
668
|
if (actionFailed) return {
|
|
620
669
|
kind: "form-state",
|
|
621
670
|
formState: null,
|
|
@@ -627,7 +676,7 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
627
676
|
};
|
|
628
677
|
return {
|
|
629
678
|
kind: "form-state",
|
|
630
|
-
formState: await options.decodeFormState(actionResult, body) ?? null,
|
|
679
|
+
formState: await loadOutsideRequestScopes(() => options.decodeFormState(actionResult, body)) ?? null,
|
|
631
680
|
pendingCookies: actionPendingCookies,
|
|
632
681
|
draftCookie: actionDraftCookie,
|
|
633
682
|
revalidationKind
|
|
@@ -680,29 +729,18 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
680
729
|
* with status 500 carrying the rejected action result, so the nearest client
|
|
681
730
|
* error boundary catches it (see action-handler.ts, the `isFetchAction` branch
|
|
682
731
|
* of the generic error path). vinext mirrors that by rendering a Flight stream
|
|
683
|
-
* with `returnValue: { ok: false }` and no page root (the action never ran, so
|
|
732
|
+
* with a rejected `returnValue: { ok: false }` and no page root (the action never ran, so
|
|
684
733
|
* nothing was revalidated and the page render is skipped). A bare 413 plain
|
|
685
734
|
* response would bypass the boundary and surface the wrong status/content-type.
|
|
686
735
|
*/
|
|
687
736
|
async function renderFetchActionBodyExceededResponse(options) {
|
|
688
737
|
const error = createBodyExceededError(options.maxActionBodySizeLabel);
|
|
689
|
-
|
|
690
|
-
options.reportRequestError(error, {
|
|
691
|
-
path: options.cleanPathname,
|
|
692
|
-
method: options.request.method,
|
|
693
|
-
headers: Object.fromEntries(options.request.headers.entries())
|
|
694
|
-
}, {
|
|
695
|
-
routerKind: "App Router",
|
|
696
|
-
routePath: options.currentRouteMatch?.route.pattern ?? options.cleanPathname,
|
|
697
|
-
routeType: "action",
|
|
698
|
-
renderSource: "react-server-components-payload",
|
|
699
|
-
revalidateReason: void 0
|
|
700
|
-
});
|
|
738
|
+
logRejectedActionResult(error);
|
|
701
739
|
getAndClearActionRevalidationKind();
|
|
702
740
|
options.getAndClearPendingCookies();
|
|
703
741
|
const returnValue = {
|
|
704
742
|
ok: false,
|
|
705
|
-
data: options.sanitizeErrorForClient(error)
|
|
743
|
+
data: createRejectedActionResult(options.sanitizeErrorForClient(error))
|
|
706
744
|
};
|
|
707
745
|
const temporaryReferences = options.createTemporaryReferenceSet();
|
|
708
746
|
const onRenderError = options.createRscOnErrorHandler(options.request, options.cleanPathname, options.currentRouteMatch?.route.pattern ?? options.cleanPathname, {
|
|
@@ -727,6 +765,7 @@ async function renderFetchActionBodyExceededResponse(options) {
|
|
|
727
765
|
}
|
|
728
766
|
async function handleServerActionRscRequest(options) {
|
|
729
767
|
if (options.request.method.toUpperCase() !== "POST" || !options.actionId) return null;
|
|
768
|
+
const actionId = options.actionId;
|
|
730
769
|
const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);
|
|
731
770
|
if (csrfResponse) return csrfResponse;
|
|
732
771
|
if (parseInt(options.request.headers.get("content-length") || "0", 10) > options.maxActionBodySize) {
|
|
@@ -738,7 +777,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
738
777
|
if (options.contentType.startsWith("multipart/form-data")) {
|
|
739
778
|
let loadedAction;
|
|
740
779
|
try {
|
|
741
|
-
loadedAction = await options.loadServerAction(
|
|
780
|
+
loadedAction = await loadOutsideRequestScopes(() => options.loadServerAction(actionId));
|
|
742
781
|
} catch (error) {
|
|
743
782
|
if (isServerActionNotFoundError(error, options.actionId)) return createActionNotFoundResponse(options.actionId, {
|
|
744
783
|
clearRequestContext: options.clearRequestContext,
|
|
@@ -768,7 +807,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
768
807
|
if (action === void 0) {
|
|
769
808
|
let loadedAction;
|
|
770
809
|
try {
|
|
771
|
-
loadedAction = await options.loadServerAction(
|
|
810
|
+
loadedAction = await loadOutsideRequestScopes(() => options.loadServerAction(actionId));
|
|
772
811
|
} catch (error) {
|
|
773
812
|
if (isServerActionNotFoundError(error, options.actionId)) return createActionNotFoundResponse(options.actionId, {
|
|
774
813
|
clearRequestContext: options.clearRequestContext,
|
|
@@ -783,7 +822,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
783
822
|
action = loadedAction;
|
|
784
823
|
}
|
|
785
824
|
const temporaryReferences = options.createTemporaryReferenceSet();
|
|
786
|
-
const args = await options.decodeReply(body, { temporaryReferences });
|
|
825
|
+
const args = await loadOutsideRequestScopes(() => options.decodeReply(body, { temporaryReferences }));
|
|
787
826
|
let returnValue;
|
|
788
827
|
let actionRedirect = null;
|
|
789
828
|
let actionStatus = 200;
|
|
@@ -815,10 +854,10 @@ async function handleServerActionRscRequest(options) {
|
|
|
815
854
|
};
|
|
816
855
|
} else {
|
|
817
856
|
actionStatus = 500;
|
|
818
|
-
|
|
857
|
+
logRejectedActionResult(error);
|
|
819
858
|
returnValue = {
|
|
820
859
|
ok: false,
|
|
821
|
-
data: options.sanitizeErrorForClient(error)
|
|
860
|
+
data: createRejectedActionResult(options.sanitizeErrorForClient(error))
|
|
822
861
|
};
|
|
823
862
|
}
|
|
824
863
|
}
|
|
@@ -46,8 +46,9 @@ export declare function handleSsr(rscStream: ReadableStream<Uint8Array>, navCont
|
|
|
46
46
|
initialDevServerError?: unknown;
|
|
47
47
|
/** Report an SSR/Fizz render failure through instrumentation. */
|
|
48
48
|
onSsrError?: (error: unknown) => unknown;
|
|
49
|
-
/** Mirror inline Flight chunks into Next.js's `self.__next_f` transport
|
|
50
|
-
|
|
49
|
+
/** Mirror inline Flight chunks into Next.js's `self.__next_f` transport, or start
|
|
50
|
+
* mirroring once a function returns true. */
|
|
51
|
+
mirrorNextFlight?: boolean | (() => boolean);
|
|
51
52
|
/** When true, wait for the full React tree (including Suspense boundaries)
|
|
52
53
|
* to resolve before returning the HTML stream. Used for static prerender
|
|
53
54
|
* and ISR cache writes to avoid caching fallback content. */
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import "./server-globals.js";
|
|
2
2
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
3
|
-
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
4
|
-
import { AppElementsWire } from "./app-elements-wire.js";
|
|
5
|
-
import "./app-elements.js";
|
|
3
|
+
import { isOpenRedirectShaped, repeatedSlashRedirectResponse } from "./open-redirect.js";
|
|
6
4
|
import { isPprFallbackShellAbortError } from "../shims/ppr-fallback-shell.js";
|
|
7
5
|
import { onRenderDynamicLatched } from "../shims/internal/headers-state.js";
|
|
8
6
|
import { AppRouterContext } from "../shims/internal/app-router-context.js";
|
|
@@ -12,21 +10,24 @@ import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonSt
|
|
|
12
10
|
import { getClientTraceMetadataHTML, markClientTraceMetadataBlock } from "./client-trace-metadata.js";
|
|
13
11
|
import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
|
|
14
12
|
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
13
|
+
import { AppElementsWire } from "./app-elements-wire.js";
|
|
14
|
+
import "./app-elements.js";
|
|
15
15
|
import { ServerInsertedHTMLContext, clearServerInsertedHTML, getBfcacheIdMapContext, registerServerInsertedHTMLCallback, renderServerInsertedHTML, setNavigationContext } from "../shims/navigation-context-state.js";
|
|
16
16
|
import "../shims/navigation-server.js";
|
|
17
17
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
18
18
|
import { BfcacheIdentityMapContext, ElementsContext, Slot } from "../shims/slot.js";
|
|
19
19
|
import { getNextErrorDigest } from "./next-error-digest.js";
|
|
20
20
|
import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
|
|
21
|
-
import { createClientPageSsrSearchParamsSource } from "./app-page-search-params-observation.js";
|
|
22
21
|
import { isAppRenderAbortError } from "./app-render-abort-error.js";
|
|
23
22
|
import { RSC_FORM_STATE_GLOBAL } from "../client/browser-globals.js";
|
|
24
23
|
import { createNavigationRuntimeRenderedSearchScript, createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, waitAtLeastOneReactRenderTask } from "./app-ssr-stream.js";
|
|
25
24
|
import { createInitialBfcacheMaps } from "./app-bfcache-identity.js";
|
|
26
25
|
import { createClientReferencePreloader } from "./app-client-reference-preloader.js";
|
|
26
|
+
import { createClientPageSsrSearchParamsSource } from "./app-page-search-params-observation.js";
|
|
27
27
|
import { runWithRootParamsScope } from "../shims/root-params.js";
|
|
28
28
|
import { runWithNavigationContext } from "../shims/navigation-state.js";
|
|
29
29
|
import { startCandidateSearchParamsGate } from "./app-ssr-search-params-gate.js";
|
|
30
|
+
import { withAppRouterTree } from "../shims/app-router-tree-context.js";
|
|
30
31
|
import { BeforeInteractiveContext } from "../shims/before-interactive-context.js";
|
|
31
32
|
import { renderBeforeInteractiveInlineScripts } from "./before-interactive-head.js";
|
|
32
33
|
import { createInitialDevServerErrorScript } from "./dev-initial-server-error.js";
|
|
@@ -246,7 +247,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
246
247
|
beforeInteractiveInlineScripts.push(script);
|
|
247
248
|
};
|
|
248
249
|
const treeWithBeforeInteractive = createElement(BeforeInteractiveContext.Provider, { value: registerBeforeInteractiveInlineScript }, ssrTree);
|
|
249
|
-
const ssrRoot = withScriptNonce(treeWithBeforeInteractive, options?.scriptNonce);
|
|
250
|
+
const ssrRoot = withScriptNonce(withAppRouterTree(treeWithBeforeInteractive), options?.scriptNonce);
|
|
250
251
|
const bootstrapModuleUrl = extractBootstrapModuleUrl(await import.meta.viteRsc.loadBootstrapScriptContent("index"));
|
|
251
252
|
const errorMetaRenderer = createSsrErrorMetaRenderer({ basePath: options?.basePath });
|
|
252
253
|
const pprFallbackShellSignal = options?.pprFallbackShellSignal;
|
|
@@ -357,6 +358,8 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
357
358
|
}
|
|
358
359
|
var app_ssr_entry_default = { async fetch(request) {
|
|
359
360
|
const url = new URL(request.url);
|
|
361
|
+
const slashRedirect = repeatedSlashRedirectResponse(url.pathname + url.search);
|
|
362
|
+
if (slashRedirect) return slashRedirect;
|
|
360
363
|
if (isOpenRedirectShaped(url.pathname)) return notFoundResponse();
|
|
361
364
|
const result = await (await import.meta.viteRsc.loadModule("rsc", "index")).default(request);
|
|
362
365
|
if (result instanceof Response) return result;
|
|
@@ -6,7 +6,12 @@ type RscEmbedTransform = {
|
|
|
6
6
|
getRawBuffer(): Promise<ArrayBuffer>;
|
|
7
7
|
};
|
|
8
8
|
type RscEmbedTransformOptions = {
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Mirror inline Flight chunks into Next.js's `self.__next_f` transport. A
|
|
11
|
+
* function is checked at each flush; once it returns true, the chunks
|
|
12
|
+
* already embedded are mirrored first.
|
|
13
|
+
*/
|
|
14
|
+
mirrorNextFlight?: boolean | (() => boolean);
|
|
10
15
|
scriptNonce?: string;
|
|
11
16
|
getInitialNavigationCacheMetadata?: () => InitialNavigationCacheMetadata;
|
|
12
17
|
};
|
|
@@ -49,12 +49,36 @@ function createRscEmbedTransform(embedStream, optionsOrNonce = {}) {
|
|
|
49
49
|
const reader = embedStream.getReader();
|
|
50
50
|
let pendingChunks = [];
|
|
51
51
|
const rawChunks = [];
|
|
52
|
+
let embeddedRawChunkCount = 0;
|
|
53
|
+
let rawBufferTaken = false;
|
|
54
|
+
let finalized = false;
|
|
52
55
|
let reading = false;
|
|
53
56
|
let mirroredNextFlightBootstrap = false;
|
|
54
57
|
const textDecoder = new TextDecoder("utf-8", {
|
|
55
58
|
fatal: true,
|
|
56
59
|
ignoreBOM: true
|
|
57
60
|
});
|
|
61
|
+
function decodeChunk(bytes) {
|
|
62
|
+
try {
|
|
63
|
+
return textDecoder.decode(bytes);
|
|
64
|
+
} catch {
|
|
65
|
+
return [3, bytesToBase64(bytes)];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function releaseRawChunks() {
|
|
69
|
+
const mayStartMirror = typeof options.mirrorNextFlight === "function" && !mirroredNextFlightBootstrap && !finalized;
|
|
70
|
+
if (rawBufferTaken && !mayStartMirror) rawChunks.length = 0;
|
|
71
|
+
}
|
|
72
|
+
function startNextFlightMirror() {
|
|
73
|
+
if (mirroredNextFlightBootstrap) return "";
|
|
74
|
+
const mirror = options.mirrorNextFlight;
|
|
75
|
+
if (mirror !== true && (typeof mirror !== "function" || !mirror())) return "";
|
|
76
|
+
mirroredNextFlightBootstrap = true;
|
|
77
|
+
let scripts = createInlineScriptTag(createNextFlightBootstrapScript(), options.scriptNonce) + createInlineScriptTag(createNextFlightCleanupScript(), options.scriptNonce);
|
|
78
|
+
for (let index = 0; index < embeddedRawChunkCount; index++) scripts += createInlineScriptTag(createNextFlightChunkScript(decodeChunk(rawChunks[index])), options.scriptNonce);
|
|
79
|
+
releaseRawChunks();
|
|
80
|
+
return scripts;
|
|
81
|
+
}
|
|
58
82
|
async function pumpReader() {
|
|
59
83
|
if (reading) return;
|
|
60
84
|
reading = true;
|
|
@@ -63,11 +87,7 @@ function createRscEmbedTransform(embedStream, optionsOrNonce = {}) {
|
|
|
63
87
|
const result = await reader.read();
|
|
64
88
|
if (result.done) break;
|
|
65
89
|
rawChunks.push(result.value);
|
|
66
|
-
|
|
67
|
-
pendingChunks.push(textDecoder.decode(result.value));
|
|
68
|
-
} catch {
|
|
69
|
-
pendingChunks.push([3, bytesToBase64(result.value)]);
|
|
70
|
-
}
|
|
90
|
+
pendingChunks.push(decodeChunk(result.value));
|
|
71
91
|
}
|
|
72
92
|
} catch (error) {
|
|
73
93
|
if (process.env.NODE_ENV !== "production") console.warn("[vinext] RSC embed stream read error:", error);
|
|
@@ -80,8 +100,10 @@ function createRscEmbedTransform(embedStream, optionsOrNonce = {}) {
|
|
|
80
100
|
return {
|
|
81
101
|
flush() {
|
|
82
102
|
if (pendingChunks.length === 0) return "";
|
|
103
|
+
const mirrorScripts = startNextFlightMirror();
|
|
83
104
|
const chunks = pendingChunks;
|
|
84
105
|
pendingChunks = [];
|
|
106
|
+
embeddedRawChunkCount += chunks.length;
|
|
85
107
|
const embeddedChunks = [];
|
|
86
108
|
let textChunks = [];
|
|
87
109
|
let textLength = 0;
|
|
@@ -100,30 +122,27 @@ function createRscEmbedTransform(embedStream, optionsOrNonce = {}) {
|
|
|
100
122
|
embeddedChunks.push(chunk);
|
|
101
123
|
}
|
|
102
124
|
flushTextChunks();
|
|
103
|
-
let scripts =
|
|
125
|
+
let scripts = mirrorScripts;
|
|
104
126
|
for (const chunk of embeddedChunks) {
|
|
105
127
|
scripts += createInlineScriptTag(createNavigationRuntimeRscChunkScript(chunk), options.scriptNonce);
|
|
106
|
-
if (options.
|
|
107
|
-
if (!mirroredNextFlightBootstrap) {
|
|
108
|
-
scripts += createInlineScriptTag(createNextFlightBootstrapScript(), options.scriptNonce);
|
|
109
|
-
scripts += createInlineScriptTag(createNextFlightCleanupScript(), options.scriptNonce);
|
|
110
|
-
mirroredNextFlightBootstrap = true;
|
|
111
|
-
}
|
|
112
|
-
scripts += createInlineScriptTag(createNextFlightChunkScript(chunk), options.scriptNonce);
|
|
113
|
-
}
|
|
128
|
+
if (mirroredNextFlightBootstrap) scripts += createInlineScriptTag(createNextFlightChunkScript(chunk), options.scriptNonce);
|
|
114
129
|
}
|
|
115
130
|
return scripts;
|
|
116
131
|
},
|
|
117
132
|
async finalize() {
|
|
118
133
|
await pumpPromise;
|
|
119
134
|
let scripts = this.flush();
|
|
135
|
+
scripts += startNextFlightMirror();
|
|
136
|
+
finalized = true;
|
|
137
|
+
releaseRawChunks();
|
|
120
138
|
scripts += createInlineScriptTag(createNavigationRuntimeRscDoneScript(options.getInitialNavigationCacheMetadata?.()), options.scriptNonce);
|
|
121
139
|
return scripts;
|
|
122
140
|
},
|
|
123
141
|
async getRawBuffer() {
|
|
124
142
|
await pumpPromise;
|
|
125
143
|
const buffer = concatUint8Arrays(rawChunks);
|
|
126
|
-
|
|
144
|
+
rawBufferTaken = true;
|
|
145
|
+
releaseRawChunks();
|
|
127
146
|
return buffer.buffer;
|
|
128
147
|
}
|
|
129
148
|
};
|
|
@@ -3,7 +3,7 @@ import { VinextResponseStageCacheability, VinextResponseStageDispatchOptions, Vi
|
|
|
3
3
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
4
4
|
import { TrustedPrerenderState } from "./prerender-route-params.js";
|
|
5
5
|
//#region src/server/app-worker-stages.d.ts
|
|
6
|
-
export declare const APP_WORKER_RESPONSE_STAGE_PROTOCOL_VERSION =
|
|
6
|
+
export declare const APP_WORKER_RESPONSE_STAGE_PROTOCOL_VERSION = 11;
|
|
7
7
|
export declare const APP_METADATA_RESPONSE_STAGE_NO_MATCH_HEADER = "x-vinext-app-metadata-stage-no-match";
|
|
8
8
|
type AppPageParams = Record<string, string | string[]>;
|
|
9
9
|
type AppWorkerResponseStageEnvelope = {
|
|
@@ -18,6 +18,11 @@ type AppWorkerResponseStageEnvelope = {
|
|
|
18
18
|
};
|
|
19
19
|
type AppFullRequestWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
|
|
20
20
|
kind: "app-full-request";
|
|
21
|
+
/**
|
|
22
|
+
* The public request is HEAD. It is dispatched as GET so a transport that
|
|
23
|
+
* applies HEAD semantics cannot drop the static-file signal's body.
|
|
24
|
+
*/
|
|
25
|
+
headRequest: boolean;
|
|
21
26
|
prerenderDiscovery: boolean;
|
|
22
27
|
staticFileSignalToken: string;
|
|
23
28
|
trustedPrerenderState: TrustedPrerenderState | null;
|
|
@@ -34,7 +39,7 @@ export type AppMatchedWorkerResponseStageProps = AppWorkerResponseStageEnvelope
|
|
|
34
39
|
interceptionContext: string | null;
|
|
35
40
|
interceptionId: string | null;
|
|
36
41
|
isRscRequest: boolean;
|
|
37
|
-
matchKind: "interception" | "request" | "resolved";
|
|
42
|
+
matchKind: "interception" | "raw-request" | "request" | "resolved";
|
|
38
43
|
mountedSlotsHeader: string | null;
|
|
39
44
|
params: AppPageParams;
|
|
40
45
|
resolvedUrl: string;
|