vinext 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -21
- package/dist/build/action-owner-manifest.js +1 -0
- package/dist/build/prerender.js +3 -2
- package/dist/check.js +4 -7
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +19 -3
- package/dist/config/config-matchers.js +4 -2
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +55 -2
- package/dist/config/next-config.d.ts +22 -1
- package/dist/config/next-config.js +49 -4
- package/dist/entries/app-rsc-entry.js +41 -19
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/pages-server-entry.js +5 -1
- package/dist/index.js +44 -32
- package/dist/init-cloudflare.js +18 -2
- package/dist/plugins/css-target.d.ts +18 -0
- package/dist/plugins/css-target.js +93 -0
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/routing/app-route-graph.d.ts +10 -0
- package/dist/routing/app-route-graph.js +15 -1
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +5 -6
- package/dist/server/app-action-forwarding.js +3 -1
- package/dist/server/app-browser-entry.js +28 -7
- package/dist/server/app-browser-rsc-redirect.js +3 -3
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-visible-commit.js +2 -2
- package/dist/server/app-elements.d.ts +3 -0
- package/dist/server/app-elements.js +14 -1
- package/dist/server/app-fallback-renderer.js +2 -2
- package/dist/server/app-optimistic-routing.d.ts +12 -1
- package/dist/server/app-optimistic-routing.js +40 -19
- package/dist/server/app-page-boundary-render.js +7 -12
- package/dist/server/app-page-cache-render.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -2
- package/dist/server/app-page-dispatch.js +73 -31
- package/dist/server/app-page-element-builder.d.ts +9 -20
- package/dist/server/app-page-element-builder.js +40 -52
- package/dist/server/app-page-execution.js +9 -6
- package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
- package/dist/server/app-page-intercept-segment-config.js +90 -0
- package/dist/server/app-page-navigation-params.d.ts +23 -0
- package/dist/server/app-page-navigation-params.js +49 -0
- package/dist/server/app-page-render.d.ts +5 -3
- package/dist/server/app-page-render.js +31 -17
- package/dist/server/app-page-request.d.ts +24 -2
- package/dist/server/app-page-request.js +10 -10
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +10 -0
- package/dist/server/app-page-route-wiring.js +34 -13
- package/dist/server/app-page-segment-plan.js +9 -1
- package/dist/server/app-page-segment-state.d.ts +9 -0
- package/dist/server/app-page-segment-state.js +54 -1
- package/dist/server/app-page-stream.d.ts +10 -8
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-response-stage-entry.js +1 -0
- package/dist/server/app-route-handler-execution.js +3 -2
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +11 -7
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +10 -10
- package/dist/server/app-rsc-cache-busting.js +27 -68
- package/dist/server/app-rsc-error-handler.js +1 -1
- package/dist/server/app-rsc-errors.js +4 -1
- package/dist/server/app-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +126 -103
- package/dist/server/app-rsc-request-normalization.d.ts +10 -12
- package/dist/server/app-rsc-request-normalization.js +11 -14
- package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
- package/dist/server/app-rsc-response-finalizer.js +11 -1
- package/dist/server/app-rsc-response-stage.js +4 -12
- package/dist/server/app-rsc-route-matching.d.ts +14 -0
- package/dist/server/app-rsc-route-matching.js +42 -18
- package/dist/server/app-server-action-execution.js +24 -14
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +13 -8
- package/dist/server/app-worker-stages.d.ts +12 -3
- package/dist/server/app-worker-stages.js +37 -4
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cache-control.d.ts +2 -0
- package/dist/server/cache-control.js +3 -1
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +2 -1
- package/dist/server/image-local-patterns.d.ts +21 -0
- package/dist/server/image-local-patterns.js +59 -0
- package/dist/server/image-optimization.d.ts +28 -22
- package/dist/server/image-optimization.js +17 -2
- package/dist/server/isr-cache.js +4 -1
- package/dist/server/metadata-route-response.js +25 -7
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +7 -3
- package/dist/server/nitro-public-files-plugin.js +20 -8
- package/dist/server/pages-data-route.d.ts +5 -1
- package/dist/server/pages-data-route.js +14 -6
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +2 -0
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +17 -6
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-pipeline.js +6 -5
- package/dist/server/pages-request-stage-entry.js +25 -4
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +59 -17
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +14 -4
- package/dist/server/request-pipeline.js +33 -15
- package/dist/server/response-stage-cacheability.d.ts +7 -0
- package/dist/server/response-stage-cacheability.js +6 -5
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/server/worker-image-optimization.d.ts +2 -2
- package/dist/server/worker-image-optimization.js +18 -3
- package/dist/server/worker-utils.d.ts +8 -0
- package/dist/server/worker-utils.js +19 -2
- package/dist/shims/cache-request-state.d.ts +6 -6
- package/dist/shims/cache-request-state.js +6 -36
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +77 -47
- package/dist/shims/cache.d.ts +10 -5
- package/dist/shims/cache.js +35 -22
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/fetch-cache.js +6 -2
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.js +5 -3
- package/dist/shims/image-props.d.ts +6 -0
- package/dist/shims/image-props.js +39 -3
- package/dist/shims/image.js +3 -3
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/link.js +5 -10
- package/dist/shims/navigation.js +2 -3
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/slot.d.ts +9 -2
- package/dist/shims/slot.js +76 -11
- package/dist/shims/unified-request-context.d.ts +6 -0
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/base-path.d.ts +7 -0
- package/dist/utils/base-path.js +11 -1
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/package.json +1 -1
|
@@ -86,7 +86,8 @@ async function renderAppPageHtmlStream(options) {
|
|
|
86
86
|
initialDevServerError: options.initialDevServerError,
|
|
87
87
|
onSsrError: options.onSsrError,
|
|
88
88
|
mirrorNextFlight: options.mirrorNextFlight,
|
|
89
|
-
fallbackToErrorDocumentOnShellError: options.fallbackToErrorDocumentOnShellError
|
|
89
|
+
fallbackToErrorDocumentOnShellError: options.fallbackToErrorDocumentOnShellError,
|
|
90
|
+
isServerComponentError: options.isServerComponentError,
|
|
90
91
|
resolveCaughtNotFoundBoundaries: options.resolveCaughtNotFoundBoundaries,
|
|
91
92
|
dynamicStaleTimeSeconds: options.dynamicStaleTimeSeconds,
|
|
92
93
|
getInitialNavigationCacheMetadata: options.getInitialNavigationCacheMetadata
|
|
@@ -32,7 +32,7 @@ function handleRequestStage(request, env, ctx, dispatchResponseStage) {
|
|
|
32
32
|
callback: () => handleRequest(request, env, ctx, dispatchResponseStage, ctx?.assets).then((response) => applyCdnResponseIdentityHeaders(response, originalRequest)),
|
|
33
33
|
getStatus: (response) => response?.status,
|
|
34
34
|
headers: request.headers,
|
|
35
|
-
isRsc:
|
|
35
|
+
isRsc: request.headers.get("RSC") === "1",
|
|
36
36
|
method: request.method,
|
|
37
37
|
target: url.pathname + url.search
|
|
38
38
|
});
|
|
@@ -58,6 +58,7 @@ async function handleResponseStage(request, env, platformCtx, props, dispatchReq
|
|
|
58
58
|
probeMode: props.cacheability.probeMode,
|
|
59
59
|
rawManifest: __cacheabilityManifest,
|
|
60
60
|
recomposesRequestScopedHeaders: props.kind === "app-page" && props.isRscRequest,
|
|
61
|
+
keepsParamsHeader: props.kind === "app-page" && props.interceptionContext !== null,
|
|
61
62
|
registerCacheAdapters: () => registerConfiguredCacheAdapters(env),
|
|
62
63
|
request,
|
|
63
64
|
representation: props.cacheability.representation,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isFullyBufferedBody } from "./fully-buffered-response.js";
|
|
2
2
|
import { patternToNextFormat } from "../routing/route-validation.js";
|
|
3
3
|
import { frameworkTracer } from "./tracer.js";
|
|
4
|
+
import { logRequestError } from "./request-error-log.js";
|
|
4
5
|
import { getRouteCacheabilityCaptureOptions, getRouteCacheabilityDynamicReason, isRouteCacheabilityEvaluation, markRouteCacheabilityExplicitResponsePolicy, markRouteCacheabilityResponseBodyComplete, recordRouteCacheability } from "../shims/cacheability-classification.js";
|
|
5
6
|
import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, hasExplicitNonCacheableResponsePolicy } from "./cache-control.js";
|
|
6
7
|
import { buildAppRouteMissIsrCacheControl } from "./isr-decision.js";
|
|
@@ -117,7 +118,7 @@ async function runAppRouteHandler(options) {
|
|
|
117
118
|
onDynamicAccess() {
|
|
118
119
|
options.markDynamicUsage();
|
|
119
120
|
},
|
|
120
|
-
requestMode: options.dynamicConfig === "force-static" || options.dynamicConfig === "error" ? options.dynamicConfig : "auto",
|
|
121
|
+
requestMode: options.dynamicConfig === "force-dynamic" || options.dynamicConfig === "force-static" || options.dynamicConfig === "error" ? options.dynamicConfig : "auto",
|
|
121
122
|
signal: options.requestSignal,
|
|
122
123
|
staticGenerationErrorMessage(expression) {
|
|
123
124
|
return getAppRouteStaticGenerationErrorMessage(options.routePattern, expression);
|
|
@@ -339,7 +340,7 @@ async function executeAppRouteHandlerImpl(options) {
|
|
|
339
340
|
}), options.middlewareContext, middlewareMergeOptions), shouldApplyDraftPolicy);
|
|
340
341
|
return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(new Response(null, { status: specialError.statusCode }), options.middlewareContext, middlewareMergeOptions), shouldApplyDraftPolicy);
|
|
341
342
|
}
|
|
342
|
-
|
|
343
|
+
logRequestError("[vinext] Route handler error:", error);
|
|
343
344
|
await options.reportRequestError(error, {
|
|
344
345
|
path: options.cleanPathname,
|
|
345
346
|
method: options.request.method,
|
|
@@ -21,7 +21,7 @@ type NextUrlDynamicAccess = "nextUrl.search" | "nextUrl.searchParams" | "nextUrl
|
|
|
21
21
|
type HostDerivedNextUrlDynamicAccess = "nextUrl.protocol" | "nextUrl.username" | "nextUrl.password" | "nextUrl.host" | "nextUrl.hostname" | "nextUrl.port" | DomainLocaleNextUrlDynamicAccess;
|
|
22
22
|
type DomainLocaleNextUrlDynamicAccess = "nextUrl.locale" | "nextUrl.defaultLocale" | "nextUrl.domainLocale";
|
|
23
23
|
type AppRouteDynamicRequestAccess = RequestDynamicAccess | NextUrlDynamicAccess;
|
|
24
|
-
type AppRouteRequestMode = "auto" | "force-static" | "error";
|
|
24
|
+
type AppRouteRequestMode = "auto" | "force-dynamic" | "force-static" | "error";
|
|
25
25
|
type TrackedAppRouteRequestOptions = {
|
|
26
26
|
basePath?: string;
|
|
27
27
|
i18n?: NextI18nConfig | null;
|
|
@@ -2,6 +2,7 @@ import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-r
|
|
|
2
2
|
import { addBasePathToPathname } from "../utils/base-path.js";
|
|
3
3
|
import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
|
|
4
4
|
import { NextRequest, RequestCookies, sealRequestCookies, sealRequestHeaders } from "../shims/server.js";
|
|
5
|
+
import { throwIfInsideCacheScope } from "../shims/internal/headers-state.js";
|
|
5
6
|
import { BUILT_IN_REQUEST_PROPERTIES } from "./app-route-request-built-ins.js";
|
|
6
7
|
//#region src/server/app-route-handler-runtime.ts
|
|
7
8
|
const BUILT_IN_REQUEST_PROPERTY_MAP = new Map(BUILT_IN_REQUEST_PROPERTIES.map((property) => [property.key, property]));
|
|
@@ -150,7 +151,8 @@ function createTrackedAppRouteRequest(request, options = {}) {
|
|
|
150
151
|
let didAccessDynamicRequest = false;
|
|
151
152
|
const requestMode = options.requestMode ?? "auto";
|
|
152
153
|
const nextConfig = buildNextConfig(options);
|
|
153
|
-
const markDynamicAccess = (access) => {
|
|
154
|
+
const markDynamicAccess = (access, trackedByNext) => {
|
|
155
|
+
if (trackedByNext && requestMode !== "force-dynamic") throwIfInsideCacheScope(access);
|
|
154
156
|
didAccessDynamicRequest = true;
|
|
155
157
|
options.onDynamicAccess?.(access);
|
|
156
158
|
};
|
|
@@ -184,7 +186,7 @@ function createTrackedAppRouteRequest(request, options = {}) {
|
|
|
184
186
|
const wrapNextUrl = (nextUrl) => {
|
|
185
187
|
return new Proxy(nextUrl, { get(target, prop) {
|
|
186
188
|
if (isNextDynamicNextUrlProperty(prop) || isHostDerivedNextUrlProperty(prop)) {
|
|
187
|
-
markDynamicAccess(`nextUrl.${String(prop)}
|
|
189
|
+
markDynamicAccess(`nextUrl.${String(prop)}`, isNextDynamicNextUrlProperty(prop));
|
|
188
190
|
return bindMethodIfNeeded(Reflect.get(target, prop, target), target);
|
|
189
191
|
}
|
|
190
192
|
if (prop === "clone") return () => wrapNextUrl(target.clone());
|
|
@@ -252,7 +254,7 @@ function createTrackedAppRouteRequest(request, options = {}) {
|
|
|
252
254
|
const accessCf = (read, forceStaticValue) => {
|
|
253
255
|
if (requestMode === "force-static") return forceStaticValue;
|
|
254
256
|
if (requestMode === "error") return throwStaticGenerationError("request.cf");
|
|
255
|
-
markDynamicAccess("request.cf");
|
|
257
|
+
markDynamicAccess("request.cf", false);
|
|
256
258
|
return read();
|
|
257
259
|
};
|
|
258
260
|
const controlledCfGetter = () => accessCf(sourceCfAccessor ? () => Reflect.apply(sourceCfAccessor, requestWithOverrides, []) : () => rawCfMetadata, void 0);
|
|
@@ -354,17 +356,19 @@ function createTrackedAppRouteRequest(request, options = {}) {
|
|
|
354
356
|
return proxiedNextUrl;
|
|
355
357
|
case "headers":
|
|
356
358
|
case "cookies":
|
|
357
|
-
case "ip":
|
|
358
|
-
case "geo":
|
|
359
359
|
case "url":
|
|
360
360
|
case "body":
|
|
361
361
|
case "blob":
|
|
362
|
-
case "bytes":
|
|
363
362
|
case "json":
|
|
364
363
|
case "text":
|
|
365
364
|
case "arrayBuffer":
|
|
366
365
|
case "formData":
|
|
367
|
-
markDynamicAccess(`request.${String(prop)}
|
|
366
|
+
markDynamicAccess(`request.${String(prop)}`, true);
|
|
367
|
+
return bindMethodIfNeeded(Reflect.get(target, prop, target), target);
|
|
368
|
+
case "ip":
|
|
369
|
+
case "geo":
|
|
370
|
+
case "bytes":
|
|
371
|
+
markDynamicAccess(`request.${String(prop)}`, false);
|
|
368
372
|
return bindMethodIfNeeded(Reflect.get(target, prop, target), target);
|
|
369
373
|
case "clone": return cloneTrackedRequest;
|
|
370
374
|
default: return getTrackedRequestProperty(target, prop, receiver);
|
|
@@ -67,6 +67,7 @@ type LazyLoadableSlot = {
|
|
|
67
67
|
loading?: unknown;
|
|
68
68
|
loadings?: readonly unknown[];
|
|
69
69
|
error?: unknown;
|
|
70
|
+
errors?: readonly unknown[];
|
|
70
71
|
notFound?: unknown;
|
|
71
72
|
notFounds?: readonly unknown[];
|
|
72
73
|
__loadPage?: LazyModuleThunk | null;
|
|
@@ -76,6 +77,7 @@ type LazyLoadableSlot = {
|
|
|
76
77
|
__loadLoading?: LazyModuleThunk | null;
|
|
77
78
|
__loadLoadings?: LazyModuleLoaderArray | null;
|
|
78
79
|
__loadError?: LazyModuleThunk | null;
|
|
80
|
+
__loadErrors?: LazyModuleLoaderArray | null;
|
|
79
81
|
__loadNotFound?: LazyModuleThunk | null;
|
|
80
82
|
__loadNotFounds?: LazyModuleLoaderArray | null;
|
|
81
83
|
/** Hydrated only after an intercept matches, not with the slot's base modules. */
|
|
@@ -145,6 +145,7 @@ function ensureAppRouteModulesLoaded(route) {
|
|
|
145
145
|
pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
|
|
146
146
|
pushArrayLoads(loads, slot.loadings, slot.__loadLoadings);
|
|
147
147
|
pushFieldLoad(loads, slot, "error", slot.__loadError);
|
|
148
|
+
pushArrayLoads(loads, slot.errors, slot.__loadErrors);
|
|
148
149
|
pushFieldLoad(loads, slot, "notFound", slot.__loadNotFound);
|
|
149
150
|
pushArrayLoads(loads, slot.notFounds, slot.__loadNotFounds);
|
|
150
151
|
}
|
|
@@ -37,7 +37,7 @@ var app_router_entry_default = {
|
|
|
37
37
|
callback: async () => applyCdnResponseIdentityHeaders(await handleRequest(request, env, ctx), request),
|
|
38
38
|
getStatus: (response) => response?.status,
|
|
39
39
|
headers: request.headers,
|
|
40
|
-
isRsc:
|
|
40
|
+
isRsc: request.headers.get("RSC") === "1",
|
|
41
41
|
method: request.method,
|
|
42
42
|
target: url.pathname + url.search
|
|
43
43
|
});
|
|
@@ -68,11 +68,6 @@ export declare function stripRscCacheBustingSearchParam(url: URL): void;
|
|
|
68
68
|
* are dropped. Other requests keep no `_rsc`, because it selects nothing there.
|
|
69
69
|
*/
|
|
70
70
|
export declare function keepOnlyValidatedRscCacheBustingSearchParam(url: URL, isRscRequest: boolean): void;
|
|
71
|
-
/**
|
|
72
|
-
* Remove a trailing `.rsc` suffix from a pathname. Returns the pathname
|
|
73
|
-
* unchanged when the suffix is absent.
|
|
74
|
-
*/
|
|
75
|
-
export declare function stripRscSuffix(pathname: string): string;
|
|
76
71
|
export declare function createCanonicalRscRequestHeaders(deploymentId?: string | null | undefined): Headers;
|
|
77
72
|
/** Headers for the deterministic loading-boundary prefetch representation. */
|
|
78
73
|
export declare function createCanonicalLoadingShellRscRequestHeaders(deploymentId?: string | null | undefined): Headers;
|
|
@@ -96,13 +91,18 @@ export declare function canonicalizeLoadingShellRscRequestHeaders(headers: Heade
|
|
|
96
91
|
* appended to the base instead of resolved against it.
|
|
97
92
|
*/
|
|
98
93
|
export declare function parseRscRequestPath(href: string): URL;
|
|
94
|
+
/**
|
|
95
|
+
* A pathname as the start of a path-absolute reference. One that begins with
|
|
96
|
+
* "//" would serialize as a protocol-relative URL naming another host, so it
|
|
97
|
+
* keeps a "/." prefix, as the WHATWG URL serializer does. URL resolution drops
|
|
98
|
+
* the dot segment, so the reference still targets the same pathname on the
|
|
99
|
+
* origin it is resolved against.
|
|
100
|
+
*/
|
|
101
|
+
export declare function toPathAbsolutePathname(pathname: string): string;
|
|
99
102
|
/**
|
|
100
103
|
* Serialize the path-absolute reference callers fetch against the app origin.
|
|
101
|
-
* A pathname
|
|
102
|
-
*
|
|
103
|
-
* WHATWG URL serializer does. URL resolution drops the dot segment, so the
|
|
104
|
-
* request still targets the same pathname on the app origin, as Next.js's
|
|
105
|
-
* full-URL fetch does.
|
|
104
|
+
* A "//" pathname keeps its "/." prefix so the request still targets the same
|
|
105
|
+
* pathname on the app origin, as Next.js's full-URL fetch does.
|
|
106
106
|
*/
|
|
107
107
|
export declare function formatRscRequestPath(url: URL): string;
|
|
108
108
|
export declare function createRscRequestUrl(href: string, headers: Headers): Promise<string>;
|
|
@@ -22,8 +22,10 @@ function encodeBase64Url(bytes) {
|
|
|
22
22
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
23
23
|
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
25
|
+
function serializeHeaderValue(value) {
|
|
26
|
+
if (value === null) return "0";
|
|
27
|
+
if (value === "0") return "\\0";
|
|
28
|
+
return value.replaceAll("\\", "\\\\").replaceAll(",", "\\,");
|
|
27
29
|
}
|
|
28
30
|
function normalizeCompatibilityId(value) {
|
|
29
31
|
return value && value.length > 0 ? value : null;
|
|
@@ -57,9 +59,9 @@ function resolveHardNavigationTargetFromRscResponse(responseUrl, currentHref, or
|
|
|
57
59
|
const parsed = new URL(responseUrl, origin);
|
|
58
60
|
stripRscCacheBustingSearchParam(parsed);
|
|
59
61
|
const origUrl = new URL(currentHref, origin);
|
|
60
|
-
let pathname =
|
|
62
|
+
let pathname = parsed.pathname;
|
|
61
63
|
if (origUrl.pathname.length > 1 && origUrl.pathname.endsWith("/") && !pathname.endsWith("/")) pathname += "/";
|
|
62
|
-
let hardNavigationTarget = pathname + parsed.search;
|
|
64
|
+
let hardNavigationTarget = toPathAbsolutePathname(pathname) + parsed.search;
|
|
63
65
|
if (origUrl.hash) hardNavigationTarget += origUrl.hash;
|
|
64
66
|
return hardNavigationTarget;
|
|
65
67
|
}
|
|
@@ -74,21 +76,21 @@ function normalizeRenderModeHeaderValue(value) {
|
|
|
74
76
|
const renderMode = parseAppRscRenderMode(value);
|
|
75
77
|
return renderMode === "navigation" ? null : renderMode;
|
|
76
78
|
}
|
|
77
|
-
function createCacheBustingInput(headers
|
|
79
|
+
function createCacheBustingInput(headers) {
|
|
78
80
|
const values = [
|
|
79
81
|
headers.get(NEXT_ROUTER_PREFETCH_HEADER),
|
|
80
82
|
headers.get(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER),
|
|
81
83
|
headers.get(NEXT_ROUTER_STATE_TREE_HEADER),
|
|
82
84
|
headers.get(NEXT_URL_HEADER),
|
|
83
85
|
headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER),
|
|
84
|
-
|
|
86
|
+
headers.get(VINEXT_INTERCEPTION_ID_HEADER),
|
|
85
87
|
headers.get(VINEXT_MOUNTED_SLOTS_HEADER),
|
|
86
|
-
|
|
88
|
+
normalizeRenderModeHeaderValue(headers.get(VINEXT_RSC_RENDER_MODE_HEADER))
|
|
87
89
|
];
|
|
88
90
|
const stateFingerprint = headers.get(VINEXT_RSC_STATE_FINGERPRINT_HEADER);
|
|
89
|
-
if (
|
|
91
|
+
if (stateFingerprint !== null) values.push(stateFingerprint);
|
|
90
92
|
if (values.every((value) => value === null)) return null;
|
|
91
|
-
return values.map(
|
|
93
|
+
return values.map(serializeHeaderValue).join(",");
|
|
92
94
|
}
|
|
93
95
|
async function sha256CacheBustingHash(input) {
|
|
94
96
|
const subtle = globalThis.crypto?.subtle;
|
|
@@ -147,13 +149,6 @@ function keepOnlyValidatedRscCacheBustingSearchParam(url, isRscRequest) {
|
|
|
147
149
|
url.search = "";
|
|
148
150
|
if (hash !== null) setRscCacheBustingSearchParam(url, hash);
|
|
149
151
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Remove a trailing `.rsc` suffix from a pathname. Returns the pathname
|
|
152
|
-
* unchanged when the suffix is absent.
|
|
153
|
-
*/
|
|
154
|
-
function stripRscSuffix(pathname) {
|
|
155
|
-
return pathname.endsWith(".rsc") ? pathname.slice(0, -4) : pathname;
|
|
156
|
-
}
|
|
157
152
|
function createCanonicalRscRequestHeaders(deploymentId = getDeploymentId()) {
|
|
158
153
|
const headers = new Headers({
|
|
159
154
|
Accept: VINEXT_RSC_CONTENT_TYPE,
|
|
@@ -232,15 +227,22 @@ function parseRscRequestPath(href) {
|
|
|
232
227
|
return new URL(beforeHash, RSC_REQUEST_URL_BASE);
|
|
233
228
|
}
|
|
234
229
|
/**
|
|
230
|
+
* A pathname as the start of a path-absolute reference. One that begins with
|
|
231
|
+
* "//" would serialize as a protocol-relative URL naming another host, so it
|
|
232
|
+
* keeps a "/." prefix, as the WHATWG URL serializer does. URL resolution drops
|
|
233
|
+
* the dot segment, so the reference still targets the same pathname on the
|
|
234
|
+
* origin it is resolved against.
|
|
235
|
+
*/
|
|
236
|
+
function toPathAbsolutePathname(pathname) {
|
|
237
|
+
return pathname.startsWith("//") ? `/.${pathname}` : pathname;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
235
240
|
* Serialize the path-absolute reference callers fetch against the app origin.
|
|
236
|
-
* A pathname
|
|
237
|
-
*
|
|
238
|
-
* WHATWG URL serializer does. URL resolution drops the dot segment, so the
|
|
239
|
-
* request still targets the same pathname on the app origin, as Next.js's
|
|
240
|
-
* full-URL fetch does.
|
|
241
|
+
* A "//" pathname keeps its "/." prefix so the request still targets the same
|
|
242
|
+
* pathname on the app origin, as Next.js's full-URL fetch does.
|
|
241
243
|
*/
|
|
242
244
|
function formatRscRequestPath(url) {
|
|
243
|
-
return `${url.pathname
|
|
245
|
+
return `${toPathAbsolutePathname(url.pathname)}${url.search}`;
|
|
244
246
|
}
|
|
245
247
|
async function createRscRequestUrl(href, headers) {
|
|
246
248
|
const url = parseRscRequestPath(href);
|
|
@@ -275,55 +277,12 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
275
277
|
const url = new URL(options.request.url);
|
|
276
278
|
const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
|
|
277
279
|
const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);
|
|
278
|
-
if (actualHash
|
|
279
|
-
const acceptedHashes = /* @__PURE__ */ new Set([expectedHash]);
|
|
280
|
-
if (actualHash !== null && actualHash !== expectedHash) {
|
|
281
|
-
acceptedHashes.add(computeLegacyRscCacheBustingSearchParam(options.request.headers));
|
|
282
|
-
const compatibilityInputs = [];
|
|
283
|
-
const hasInterceptionId = options.request.headers.has(VINEXT_INTERCEPTION_ID_HEADER);
|
|
284
|
-
const hasStateFingerprint = options.request.headers.has(VINEXT_RSC_STATE_FINGERPRINT_HEADER);
|
|
285
|
-
const hasNormalRenderMode = normalizeRenderModeHeaderValue(options.request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) === null;
|
|
286
|
-
if (!hasInterceptionId) compatibilityInputs.push({ includeInterceptionIdHeader: false });
|
|
287
|
-
if (hasStateFingerprint) {
|
|
288
|
-
compatibilityInputs.push({ includeStateFingerprintHeader: false });
|
|
289
|
-
if (!hasInterceptionId) compatibilityInputs.push({
|
|
290
|
-
includeInterceptionIdHeader: false,
|
|
291
|
-
includeStateFingerprintHeader: false
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
if (hasNormalRenderMode) {
|
|
295
|
-
compatibilityInputs.push({ includeRenderModeHeader: false });
|
|
296
|
-
if (!hasInterceptionId) compatibilityInputs.push({
|
|
297
|
-
includeInterceptionIdHeader: false,
|
|
298
|
-
includeRenderModeHeader: false
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
if (hasStateFingerprint && hasNormalRenderMode) {
|
|
302
|
-
compatibilityInputs.push({
|
|
303
|
-
includeRenderModeHeader: false,
|
|
304
|
-
includeStateFingerprintHeader: false
|
|
305
|
-
});
|
|
306
|
-
if (!hasInterceptionId) compatibilityInputs.push({
|
|
307
|
-
includeInterceptionIdHeader: false,
|
|
308
|
-
includeRenderModeHeader: false,
|
|
309
|
-
includeStateFingerprintHeader: false
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
for (const compatibilityOptions of compatibilityInputs) {
|
|
313
|
-
const input = createCacheBustingInput(options.request.headers, compatibilityOptions);
|
|
314
|
-
if (input === null) acceptedHashes.add("");
|
|
315
|
-
else {
|
|
316
|
-
acceptedHashes.add(await sha256CacheBustingHash(input));
|
|
317
|
-
acceptedHashes.add(fnv1a64(input));
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
if (actualHash !== null && acceptedHashes.has(actualHash)) return null;
|
|
280
|
+
if (actualHash !== null && (actualHash === expectedHash || actualHash === computeLegacyRscCacheBustingSearchParam(options.request.headers))) return null;
|
|
322
281
|
setRscCacheBustingSearchParam(url, expectedHash);
|
|
323
282
|
return new Response(null, {
|
|
324
283
|
status: 307,
|
|
325
|
-
headers: { Location:
|
|
284
|
+
headers: { Location: formatRscRequestPath(url) }
|
|
326
285
|
});
|
|
327
286
|
}
|
|
328
287
|
//#endregion
|
|
329
|
-
export { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam,
|
|
288
|
+
export { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, toPathAbsolutePathname };
|
|
@@ -23,7 +23,7 @@ function createAppRscOnErrorHandler(reportRequestError, request, pathname, route
|
|
|
23
23
|
routerKind: "App Router",
|
|
24
24
|
routePath: routePath || pathname,
|
|
25
25
|
routeType: overrides?.routeType ?? "render",
|
|
26
|
-
renderSource: overrides?.renderSource ?? (request.headers.get("RSC") === "1"
|
|
26
|
+
renderSource: overrides?.renderSource ?? (request.headers.get("RSC") === "1" ? "react-server-components-payload" : "react-server-components"),
|
|
27
27
|
revalidateReason: isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) ? "on-demand" : overrides?.revalidateReason
|
|
28
28
|
};
|
|
29
29
|
let loggedErrors = loggedErrorsByRequest.get(request);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
2
|
+
import { logRequestError } from "./request-error-log.js";
|
|
3
|
+
import { rewriteClientHookError } from "../shims/client-hook-error.js";
|
|
2
4
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
3
5
|
import { isAppRenderAbortError } from "./app-render-abort-error.js";
|
|
4
6
|
import { getProperError } from "./proper-error.js";
|
|
@@ -87,6 +89,7 @@ function createRscOnErrorHandler(options) {
|
|
|
87
89
|
if (!hasDigest(properError) && (properError !== reportableError || options.attachDigest !== false)) try {
|
|
88
90
|
Object.assign(properError, { digest });
|
|
89
91
|
} catch {}
|
|
92
|
+
if (nodeEnv !== "production") rewriteClientHookError(properError);
|
|
90
93
|
if (options.requestInfo && options.errorContext) options.reportRequestError(properError, options.requestInfo, options.errorContext);
|
|
91
94
|
if (process.env.VINEXT_PRERENDER === "1" && error) {
|
|
92
95
|
if (!loggedPrerenderErrors?.has(reportableError)) {
|
|
@@ -94,7 +97,7 @@ function createRscOnErrorHandler(options) {
|
|
|
94
97
|
const route = options.requestInfo?.path ?? options.errorContext?.routePath ?? "<unknown>";
|
|
95
98
|
console.error(`[vinext] Error prerendering route ${JSON.stringify(route)}:`, reportableError);
|
|
96
99
|
}
|
|
97
|
-
} else if (!(reportableError !== error && thrownHasDigest) && !wasLogged(reportableError))
|
|
100
|
+
} else if (!(reportableError !== error && thrownHasDigest) && !wasLogged(reportableError)) logRequestError("[vinext] Server render error:", properError);
|
|
98
101
|
return digest;
|
|
99
102
|
};
|
|
100
103
|
}
|
|
@@ -6,6 +6,7 @@ import { ExecutionContextLike } from "../shims/request-context.js";
|
|
|
6
6
|
import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware.js";
|
|
7
7
|
import { RootParams } from "../shims/root-params.js";
|
|
8
8
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
9
|
+
import { AppPageNavigationParamSlot } from "./app-page-navigation-params.js";
|
|
9
10
|
import { PagesRouteDataKind } from "./pages-route-data-kind.js";
|
|
10
11
|
import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
|
|
11
12
|
import { TrustedPrerenderState } from "./prerender-route-params.js";
|
|
@@ -41,9 +42,17 @@ export type AppRscHandlerRoute = {
|
|
|
41
42
|
rootParamNames?: readonly string[];
|
|
42
43
|
routeHandler?: unknown;
|
|
43
44
|
routeSegments: readonly string[];
|
|
44
|
-
slots?: AppRouteTreePrefetchRoute["slots"];
|
|
45
|
+
slots?: Readonly<Record<string, NonNullable<AppRouteTreePrefetchRoute["slots"]>[string] & AppPageNavigationParamSlot>> | null;
|
|
45
46
|
};
|
|
46
47
|
type AppRscRouteMatch<TRoute> = {
|
|
48
|
+
/**
|
|
49
|
+
* For an interception match, the source route and params the interception
|
|
50
|
+
* context names, when they differ from the rendered `route` and `params`:
|
|
51
|
+
* a sibling intercept opened from a deeper source renders the intercepting
|
|
52
|
+
* route itself, while the deeper source is what gets authorized.
|
|
53
|
+
*/
|
|
54
|
+
authorizationParams?: AppPageParams;
|
|
55
|
+
authorizationRoute?: TRoute;
|
|
47
56
|
interceptionSourceIsConcrete?: boolean;
|
|
48
57
|
params: AppPageParams;
|
|
49
58
|
route: TRoute;
|