vinext 0.0.54 → 0.0.55
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 +1 -0
- package/dist/check.js +15 -3
- package/dist/check.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +1 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/config/next-config.d.ts +14 -1
- package/dist/config/next-config.js +24 -4
- package/dist/config/next-config.js.map +1 -1
- package/dist/config/tsconfig-paths.d.ts +12 -3
- package/dist/config/tsconfig-paths.js +55 -24
- package/dist/config/tsconfig-paths.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +2 -1
- package/dist/entries/app-rsc-entry.js +12 -0
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.js +22 -5
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-server-entry.js +41 -4
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.js +81 -39
- package/dist/index.js.map +1 -1
- package/dist/plugins/import-meta-url.d.ts +16 -0
- package/dist/plugins/import-meta-url.js +193 -0
- package/dist/plugins/import-meta-url.js.map +1 -0
- package/dist/server/app-browser-action-result.d.ts +9 -16
- package/dist/server/app-browser-action-result.js +25 -14
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +171 -45
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-mpa-navigation.d.ts +16 -0
- package/dist/server/app-browser-mpa-navigation.js +36 -0
- package/dist/server/app-browser-mpa-navigation.js.map +1 -0
- package/dist/server/app-browser-popstate.d.ts +3 -1
- package/dist/server/app-browser-popstate.js +15 -1
- package/dist/server/app-browser-popstate.js.map +1 -1
- package/dist/server/app-browser-state.js +2 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-layout-param-observation.d.ts +30 -0
- package/dist/server/app-layout-param-observation.js +130 -0
- package/dist/server/app-layout-param-observation.js.map +1 -0
- package/dist/server/app-page-boundary-render.js +2 -2
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-dispatch.js +1 -1
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +14 -1
- package/dist/server/app-page-params.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +12 -1
- package/dist/server/app-page-probe.js +116 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +3 -2
- package/dist/server/app-rsc-cache-busting.js +9 -7
- package/dist/server/app-rsc-cache-busting.js.map +1 -1
- package/dist/server/app-rsc-handler.js +11 -1
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-segment-config.d.ts +1 -1
- package/dist/server/app-segment-config.js +4 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +5 -0
- package/dist/server/app-server-action-execution.js +198 -22
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +2 -1
- package/dist/server/artifact-compatibility.js +10 -1
- package/dist/server/artifact-compatibility.js.map +1 -1
- package/dist/server/client-reuse-manifest.d.ts +9 -4
- package/dist/server/client-reuse-manifest.js +2 -1
- package/dist/server/client-reuse-manifest.js.map +1 -1
- package/dist/server/dev-server.js +52 -10
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/document-initial-head.d.ts +7 -0
- package/dist/server/document-initial-head.js +35 -0
- package/dist/server/document-initial-head.js.map +1 -0
- package/dist/server/pages-document-initial-props.d.ts +84 -2
- package/dist/server/pages-document-initial-props.js +127 -1
- package/dist/server/pages-document-initial-props.js.map +1 -1
- package/dist/server/pages-node-compat.js +1 -1
- package/dist/server/pages-page-response.d.ts +14 -0
- package/dist/server/pages-page-response.js +31 -8
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.js +13 -6
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/skip-cache-proof.d.ts +23 -2
- package/dist/server/skip-cache-proof.js +81 -12
- package/dist/server/skip-cache-proof.js.map +1 -1
- package/dist/server/static-layout-client-reuse-proof.d.ts +16 -0
- package/dist/server/static-layout-client-reuse-proof.js +35 -0
- package/dist/server/static-layout-client-reuse-proof.js.map +1 -0
- package/dist/shims/cache.d.ts +21 -1
- package/dist/shims/cache.js +101 -6
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/document.d.ts +6 -0
- package/dist/shims/document.js +7 -8
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error-boundary.js +27 -28
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +16 -5
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/hash-scroll.d.ts +4 -1
- package/dist/shims/hash-scroll.js +13 -1
- package/dist/shims/hash-scroll.js.map +1 -1
- package/dist/shims/head-state.d.ts +1 -0
- package/dist/shims/head-state.js +18 -3
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +35 -1
- package/dist/shims/head.js +113 -14
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +56 -0
- package/dist/shims/internal/pages-data-fetch-dedup.js +70 -0
- package/dist/shims/internal/pages-data-fetch-dedup.js.map +1 -0
- package/dist/shims/link.js +28 -2
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/navigation.d.ts +39 -1
- package/dist/shims/navigation.js +61 -13
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.js +37 -17
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -2
- package/dist/shims/thenable-params.js +25 -1
- package/dist/shims/thenable-params.js.map +1 -1
- package/dist/shims/unified-request-context.js +3 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/utils/client-build-manifest.d.ts +15 -0
- package/dist/utils/client-build-manifest.js +54 -0
- package/dist/utils/client-build-manifest.js.map +1 -0
- package/dist/utils/hash.js +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/dist/utils/vite-version.d.ts +11 -0
- package/dist/utils/vite-version.js +36 -0
- package/dist/utils/vite-version.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n type BasePathMatchState,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport {\n ACTION_REVALIDATED_HEADER,\n NEXT_ACTION_HEADER,\n RSC_ACTION_HEADER,\n RSC_HEADER,\n VINEXT_MW_CTX_HEADER,\n VINEXT_PRERENDER_ROUTE_PARAMS_HEADER,\n} from \"./headers.js\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams, type RootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport {\n createRscRedirectLocation,\n resolveInvalidRscCacheBustingRequest,\n stripRscCacheBustingSearchParam,\n stripRscSuffix,\n} from \"./app-rsc-cache-busting.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { normalizeDefaultLocalePathname } from \"./pages-i18n.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { isImageOptimizationPath } from \"./image-optimization.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport type { AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport {\n cloneRequestWithHeaders,\n filterInternalHeaders,\n applyConfigHeadersToResponse,\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\nimport {\n prerenderRouteParamsPayloadMatchesRoute,\n readTrustedPrerenderRouteParams,\n serializePrerenderRouteParamsHeader,\n} from \"./prerender-route-params.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n isDynamic: boolean;\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n formState: ReactFormState | null;\n actionError?: unknown;\n actionFailed?: boolean;\n handlerStart: number;\n interceptionContext: string | null;\n isProgressiveActionRender: boolean;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n staticParamsValidationParams?: AppPageParams;\n rootParams?: RootParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n renderMode: AppRscRenderMode;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n /**\n * `null` for non-dynamic routes. Mirrors Next.js' route handler context\n * shape: user code that does `params ? await params : null` resolves to\n * `null` for routes without dynamic segments. Dynamic routes receive the\n * matched params object.\n */\n params: AppPageParams | null;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\n/**\n * Side-effect headers captured during a progressive (no-JS) server action's\n * non-redirect execution. Forwarded onto the page render response so that\n * `cookies().set(...)` and revalidation kinds reach the browser. See\n * `app-server-action-execution.ts` and issue #1483 for the full rationale.\n */\ntype ProgressiveActionSideEffects = {\n pendingCookies: string[];\n draftCookie: string | null | undefined;\n /** Numeric revalidation kind: `0` (none), `1` (static+dynamic), etc. */\n revalidationKind: number;\n};\n\ntype ProgressiveActionFormStateResult =\n | ({\n formState: ReactFormState | null;\n kind: \"form-state\";\n } & ProgressiveActionSideEffects)\n | ({\n actionError: unknown;\n actionFailed: true;\n formState: null;\n kind: \"form-state\";\n } & ProgressiveActionSideEffects);\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n draftModeSecret: string;\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | ProgressiveActionFormStateResult | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\n// TODO(#1333): once App Router supports `basePath: false` rules (see\n// `normalizeRscRequest` — it 404s out-of-basePath requests before they\n// reach this code), pass `hadBasePath` here and skip the prefix when\n// false, mirroring the same guard in `prod-server.ts` and `deploy.ts`.\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n basePathState: BasePathMatchState;\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(\n cleanPathname,\n options.rewrites,\n options.requestContext,\n options.basePathState,\n );\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nfunction applyConfigHeadersToMiddlewareRedirect(\n response: Response,\n options: {\n basePathState: BasePathMatchState;\n configHeaders: NextHeader[];\n pathname: string;\n requestContext: RequestContext;\n },\n): Response {\n // Non-redirect middleware responses still pass through finalization, where\n // config headers are applied once. Redirects skip finalization to avoid\n // mutating immutable redirect headers, so they need the earlier header layer here.\n if (response.status < 300 || response.status >= 400) return response;\n if (!options.configHeaders.length) return response;\n\n const headers = new Headers();\n applyConfigHeadersToResponse(headers, {\n configHeaders: options.configHeaders,\n pathname: options.pathname,\n requestContext: options.requestContext,\n basePathState: options.basePathState,\n });\n\n if (!headers.entries().next().done) {\n mergeMiddlewareResponseHeaders(headers, response.headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return response;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n isDataRequest: boolean,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode } =\n normalized;\n let { pathname, cleanPathname } = normalized;\n // Canonical (external) pathname the user requested. Middleware rewrites and\n // next.config.js rewrites mutate `cleanPathname` so internal route matching\n // can find the destination page, but hooks like `usePathname()` must reflect\n // the original URL the user sees in the address bar.\n // Matches Next.js: test/e2e/app-dir/hooks/hooks.test.ts —\n // \"should have the canonical url pathname on rewrite\"\n const canonicalPathname = cleanPathname;\n\n // The request reached this point so it was either under basePath (stripped\n // by normalizeRscRequest) or basePath is empty. In both cases the matcher\n // gating below treats default (basePath: true) rules as eligible. The App\n // Router does not yet support `basePath: false` rules — they would need a\n // pre-strip hook in normalizeRscRequest to fire. Tracked as follow-up to\n // issue #1333.\n const basePathState = { basePath: options.basePath, hadBasePath: true };\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n // Default-locale path normalisation (issue #1336, item 4). Next.js\n // splices in the (domain-aware) default locale on every request that\n // arrives without a locale prefix before running config redirect / rewrite\n // / header matching. Mirrors resolve-routes.ts lines ~250-263.\n //\n // Defined once here so the same helper is reused for the redirect match\n // below, the middleware-redirect config header match further down, and the\n // post-middleware rewrite matches. `i18nConfig` and `url.hostname` are\n // request-scoped constants from this point on.\n const matchPathname = (p: string): string =>\n normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });\n\n const redirectPathname = matchPathname(stripRscSuffix(pathname));\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n basePathState,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n const location =\n isRscRequest && request.headers.get(RSC_HEADER) === \"1\"\n ? await createRscRedirectLocation(destination, request)\n : destination;\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: location },\n });\n }\n\n const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({\n isRscRequest,\n request,\n });\n if (rscCacheBustingRedirect) return rscCacheBustingRedirect;\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isDataRequest,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n trailingSlash: options.trailingSlash,\n });\n if (middlewareResult.kind === \"response\") {\n return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {\n basePathState,\n configHeaders: options.configHeaders,\n pathname: matchPathname(cleanPathname),\n requestContext: preMiddlewareRequestContext,\n });\n }\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n // Rewrites (beforeFiles, afterFiles, fallback) use `matchPathname` from\n // above to splice in the default locale before matching. Route matching\n // itself continues to use the un-prefixed `cleanPathname` because App\n // Router files live under `app/...` with no locale segment. See issue\n // #1336 item 4 / pages-i18n.normalizeDefaultLocalePathname.\n const beforeFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n matchPathname(cleanPathname),\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (isImageOptimizationPath(cleanPathname)) {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) return metadataRouteResponse;\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n if (isRscRequest) {\n stripRscCacheBustingSearchParam(url);\n }\n\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n // Eagerly seed `setRootParams` from the current cleanPathname before any\n // action dispatch so that user code which reads `unstable_rootParams()`\n // inside route handlers, `\"use cache\"` functions, and the page rerender\n // that follows a successful server action observes the matched layout's\n // root params. Without this seeding the rootParams remain null until the\n // post-action match block below runs, which is too late for action\n // execution and route-handler dispatch (both happen earlier).\n //\n // The route is matched against the pre-rewrite cleanPathname here. If the\n // afterFiles / fallback rewrites further down land on a different route,\n // the second `setRootParams` call below replaces this value before the\n // page renders, so there is no stale-value risk for ordinary page renders.\n // For action requests we intentionally do not re-run rewrites — actions\n // are always processed against the cleanPathname they were posted to.\n const preActionMatch = options.matchRoute(cleanPathname);\n if (preActionMatch) {\n setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));\n }\n\n const actionId =\n request.headers.get(RSC_ACTION_HEADER) ?? request.headers.get(NEXT_ACTION_HEADER);\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResult = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResult instanceof Response) return progressiveActionResult;\n const isProgressiveActionRender = progressiveActionResult?.kind === \"form-state\";\n const formState = isProgressiveActionRender ? progressiveActionResult.formState : null;\n const failedProgressiveActionResult =\n isProgressiveActionRender && \"actionFailed\" in progressiveActionResult\n ? progressiveActionResult\n : null;\n const actionFailed = failedProgressiveActionResult !== null;\n const actionError = failedProgressiveActionResult?.actionError;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n let match = preActionMatch;\n if (!match || match.route.isDynamic) {\n const afterFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n matchPathname(cleanPathname),\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) {\n cleanPathname = afterFilesRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n matchPathname(cleanPathname),\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n // Dev-only favicon short-circuit: browsers auto-request /favicon.ico on\n // every page load. Don't compile/render the not-found page for it.\n // Check `canonicalPathname` (the original browser-requested URL) so a\n // middleware rewrite that lands on `/favicon.ico` still falls through to\n // the normal not-found render.\n // Matches Next.js: packages/next/src/server/lib/router-server.ts —\n // condition `parsedUrl.pathname === '/favicon.ico'`.\n if (process.env.NODE_ENV !== \"production\" && canonicalPathname === \"/favicon.ico\") {\n options.clearRequestContext();\n return new Response(\"\", { status: 404 });\n }\n\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const renderedNotFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (renderedNotFoundResponse) return renderedNotFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return notFoundResponse({ headers });\n }\n\n const { route, params } = match;\n const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);\n const prerenderRouteParams = prerenderRouteParamsPayloadMatchesRoute(\n prerenderRouteParamsPayload,\n route.pattern,\n params,\n )\n ? prerenderRouteParamsPayload.params\n : null;\n const renderParams = prerenderRouteParams ?? params;\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: renderParams,\n });\n const rootParams = pickRootParams(renderParams, route.rootParamNames);\n setRootParams(rootParams);\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n // Non-dynamic routes report params as `null` to match Next.js. Internal\n // bookkeeping above (navigation context, root params) keeps the matched\n // object (always `{}` for non-dynamic) so `useParams()` etc. still see\n // an object shape; only the user-facing handler context surfaces null.\n params: route.isDynamic ? renderParams : null,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n const pageResponse = await options.dispatchMatchedPage({\n cleanPathname,\n formState,\n actionError,\n actionFailed,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isProgressiveActionRender,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params: renderParams,\n staticParamsValidationParams: prerenderRouteParams === null ? undefined : params,\n rootParams,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n renderMode,\n });\n\n // No-JS progressive form actions write cookies via cookies().set() / draftMode()\n // *during action execution*, before the page rerender begins. Those writes only\n // exist on the request-scoped headers state; the page-render path never flushes\n // them. We attach them here so the rendered Response carries the action's\n // Set-Cookie headers and revalidation marker, mirroring Next.js'\n // res.setHeader('set-cookie', ...) flush in action-handler.ts / app-render.tsx.\n // Issue: https://github.com/cloudflare/vinext/issues/1483\n if (isProgressiveActionRender) {\n return applyProgressiveActionSideEffects(pageResponse, progressiveActionResult);\n }\n return pageResponse;\n}\n\n/**\n * Append `Set-Cookie` headers and the `x-action-revalidated` marker captured\n * during progressive (no-JS) server action execution to the page render\n * response. See issue #1483.\n *\n * Falls back to rebuilding the response when the headers object is immutable\n * (e.g. `Response.redirect()`), so cookies set by the action ride out on a\n * redirect issued during the rerender too.\n */\nfunction applyProgressiveActionSideEffects(\n response: Response,\n sideEffects: ProgressiveActionFormStateResult,\n): Response {\n const hasPendingCookies = sideEffects.pendingCookies.length > 0;\n const hasDraftCookie = Boolean(sideEffects.draftCookie);\n const hasRevalidationKind = sideEffects.revalidationKind !== 0;\n if (!hasPendingCookies && !hasDraftCookie && !hasRevalidationKind) {\n return response;\n }\n\n const applyTo = (headers: Headers): void => {\n for (const cookie of sideEffects.pendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n if (sideEffects.draftCookie) {\n headers.append(\"Set-Cookie\", sideEffects.draftCookie);\n }\n if (hasRevalidationKind) {\n headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(sideEffects.revalidationKind));\n }\n };\n\n try {\n applyTo(response.headers);\n return response;\n } catch {\n // Headers were immutable (Response.redirect()/Response.error()) — rebuild\n // with a fresh mutable Headers seeded from the original response.\n const headers = new Headers(response.headers);\n applyTo(headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(rawRequest, ctx) {\n await options.ensureInstrumentation?.();\n\n // Strip forged internal headers at the App Router request boundary.\n // Must happen BEFORE headersContextFromRequest() and\n // requestContextFromRequest() so the captured context never contains\n // attacker-controlled internal headers. This is the correct boundary\n // for pure App Router requests; in hybrid app+pages mode the connect\n // handler already filtered headers upstream and x-vinext-mw-ctx\n // (not in INTERNAL_HEADERS) carries the forwarded middleware context.\n // srvx's NodeRequestHeaders reads from rawHeaders for iteration but falls\n // back to req.headers for .get() / .has(). In the dev server we add\n // x-vinext-mw-ctx to req.headers after the Request is built, so it is\n // visible to .get() but lost when filterInternalHeaders iterates. Read it\n // BEFORE iterating so applyForwardedMiddlewareContext can skip middleware.\n const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);\n // Capture `x-nextjs-data` before filtering — the middleware redirect\n // protocol needs to know whether the inbound request was a `_next/data`\n // fetch to emit `x-nextjs-redirect` instead of an HTTP redirect.\n const isDataRequest = rawRequest.headers.get(\"x-nextjs-data\") === \"1\";\n // Read the trusted prerender route params before filtering strips the\n // route-params header (it IS in VINEXT_INTERNAL_HEADERS), then re-attach the\n // validated value below so the second read in handleAppRscRequest still sees\n // it. The secret was already verified upstream at prod-server's\n // nodeToWebRequest boundary; the surviving secret header (NOT in either\n // internal-header list) lets readTrustedPrerenderRouteParams's\n // VINEXT_PRERENDER gate pass on the reconstructed request. If the secret\n // header is ever added to VINEXT_INTERNAL_HEADERS, that second read breaks.\n const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);\n const filteredHeaders = filterInternalHeaders(rawRequest.headers);\n if (mwCtx !== null) {\n filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);\n }\n const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(\n prerenderRouteParamsPayload,\n );\n if (prerenderRouteParamsHeader !== null) {\n filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);\n }\n const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request, {\n draftModeSecret: options.draftModeSecret,\n });\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(\n options,\n request,\n preMiddlewareRequestContext,\n isDataRequest,\n );\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n i18nConfig: options.i18nConfig,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n type BasePathMatchState,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport {\n ACTION_REVALIDATED_HEADER,\n NEXT_ACTION_HEADER,\n RSC_ACTION_HEADER,\n RSC_HEADER,\n VINEXT_MW_CTX_HEADER,\n VINEXT_PRERENDER_ROUTE_PARAMS_HEADER,\n} from \"./headers.js\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams, type RootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport {\n createRscRedirectLocation,\n resolveInvalidRscCacheBustingRequest,\n stripRscCacheBustingSearchParam,\n stripRscSuffix,\n} from \"./app-rsc-cache-busting.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { normalizeDefaultLocalePathname } from \"./pages-i18n.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { isImageOptimizationPath } from \"./image-optimization.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport type { AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport {\n cloneRequestWithHeaders,\n filterInternalHeaders,\n applyConfigHeadersToResponse,\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\nimport {\n prerenderRouteParamsPayloadMatchesRoute,\n readTrustedPrerenderRouteParams,\n serializePrerenderRouteParamsHeader,\n} from \"./prerender-route-params.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n isDynamic: boolean;\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\nfunction applyMiddlewareContextToResponse(\n response: Response,\n middlewareContext: AppRscMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n formState: ReactFormState | null;\n actionError?: unknown;\n actionFailed?: boolean;\n handlerStart: number;\n interceptionContext: string | null;\n isProgressiveActionRender: boolean;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n staticParamsValidationParams?: AppPageParams;\n rootParams?: RootParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n renderMode: AppRscRenderMode;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n /**\n * `null` for non-dynamic routes. Mirrors Next.js' route handler context\n * shape: user code that does `params ? await params : null` resolves to\n * `null` for routes without dynamic segments. Dynamic routes receive the\n * matched params object.\n */\n params: AppPageParams | null;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\n/**\n * Side-effect headers captured during a progressive (no-JS) server action's\n * non-redirect execution. Forwarded onto the page render response so that\n * `cookies().set(...)` and revalidation kinds reach the browser. See\n * `app-server-action-execution.ts` and issue #1483 for the full rationale.\n */\ntype ProgressiveActionSideEffects = {\n pendingCookies: string[];\n draftCookie: string | null | undefined;\n /** Numeric revalidation kind: `0` (none), `1` (static+dynamic), etc. */\n revalidationKind: number;\n};\n\ntype ProgressiveActionFormStateResult =\n | ({\n formState: ReactFormState | null;\n kind: \"form-state\";\n } & ProgressiveActionSideEffects)\n | ({\n actionError: unknown;\n actionFailed: true;\n formState: null;\n kind: \"form-state\";\n } & ProgressiveActionSideEffects);\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n draftModeSecret: string;\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | ProgressiveActionFormStateResult | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\n// TODO(#1333): once App Router supports `basePath: false` rules (see\n// `normalizeRscRequest` — it 404s out-of-basePath requests before they\n// reach this code), pass `hadBasePath` here and skip the prefix when\n// false, mirroring the same guard in `prod-server.ts` and `deploy.ts`.\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n basePathState: BasePathMatchState;\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(\n cleanPathname,\n options.rewrites,\n options.requestContext,\n options.basePathState,\n );\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nfunction applyConfigHeadersToMiddlewareRedirect(\n response: Response,\n options: {\n basePathState: BasePathMatchState;\n configHeaders: NextHeader[];\n pathname: string;\n requestContext: RequestContext;\n },\n): Response {\n // Non-redirect middleware responses still pass through finalization, where\n // config headers are applied once. Redirects skip finalization to avoid\n // mutating immutable redirect headers, so they need the earlier header layer here.\n if (response.status < 300 || response.status >= 400) return response;\n if (!options.configHeaders.length) return response;\n\n const headers = new Headers();\n applyConfigHeadersToResponse(headers, {\n configHeaders: options.configHeaders,\n pathname: options.pathname,\n requestContext: options.requestContext,\n basePathState: options.basePathState,\n });\n\n if (!headers.entries().next().done) {\n mergeMiddlewareResponseHeaders(headers, response.headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return response;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n isDataRequest: boolean,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode } =\n normalized;\n let { pathname, cleanPathname } = normalized;\n // Canonical (external) pathname the user requested. Middleware rewrites and\n // next.config.js rewrites mutate `cleanPathname` so internal route matching\n // can find the destination page, but hooks like `usePathname()` must reflect\n // the original URL the user sees in the address bar.\n // Matches Next.js: test/e2e/app-dir/hooks/hooks.test.ts —\n // \"should have the canonical url pathname on rewrite\"\n const canonicalPathname = cleanPathname;\n\n // The request reached this point so it was either under basePath (stripped\n // by normalizeRscRequest) or basePath is empty. In both cases the matcher\n // gating below treats default (basePath: true) rules as eligible. The App\n // Router does not yet support `basePath: false` rules — they would need a\n // pre-strip hook in normalizeRscRequest to fire. Tracked as follow-up to\n // issue #1333.\n const basePathState = { basePath: options.basePath, hadBasePath: true };\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n // Default-locale path normalisation (issue #1336, item 4). Next.js\n // splices in the (domain-aware) default locale on every request that\n // arrives without a locale prefix before running config redirect / rewrite\n // / header matching. Mirrors resolve-routes.ts lines ~250-263.\n //\n // Defined once here so the same helper is reused for the redirect match\n // below, the middleware-redirect config header match further down, and the\n // post-middleware rewrite matches. `i18nConfig` and `url.hostname` are\n // request-scoped constants from this point on.\n const matchPathname = (p: string): string =>\n normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });\n\n const redirectPathname = matchPathname(stripRscSuffix(pathname));\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n basePathState,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n const location =\n isRscRequest && request.headers.get(RSC_HEADER) === \"1\"\n ? await createRscRedirectLocation(destination, request)\n : destination;\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: location },\n });\n }\n\n const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({\n isRscRequest,\n request,\n });\n if (rscCacheBustingRedirect) return rscCacheBustingRedirect;\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isDataRequest,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n trailingSlash: options.trailingSlash,\n });\n if (middlewareResult.kind === \"response\") {\n return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {\n basePathState,\n configHeaders: options.configHeaders,\n pathname: matchPathname(cleanPathname),\n requestContext: preMiddlewareRequestContext,\n });\n }\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n // Rewrites (beforeFiles, afterFiles, fallback) use `matchPathname` from\n // above to splice in the default locale before matching. Route matching\n // itself continues to use the un-prefixed `cleanPathname` because App\n // Router files live under `app/...` with no locale segment. See issue\n // #1336 item 4 / pages-i18n.normalizeDefaultLocalePathname.\n const beforeFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n matchPathname(cleanPathname),\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (isImageOptimizationPath(cleanPathname)) {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) {\n return applyMiddlewareContextToResponse(metadataRouteResponse, middlewareContext);\n }\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n if (isRscRequest) {\n stripRscCacheBustingSearchParam(url);\n }\n\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n // Eagerly seed `setRootParams` from the current cleanPathname before any\n // action dispatch so that user code which reads `unstable_rootParams()`\n // inside route handlers, `\"use cache\"` functions, and the page rerender\n // that follows a successful server action observes the matched layout's\n // root params. Without this seeding the rootParams remain null until the\n // post-action match block below runs, which is too late for action\n // execution and route-handler dispatch (both happen earlier).\n //\n // The route is matched against the pre-rewrite cleanPathname here. If the\n // afterFiles / fallback rewrites further down land on a different route,\n // the second `setRootParams` call below replaces this value before the\n // page renders, so there is no stale-value risk for ordinary page renders.\n // For action requests we intentionally do not re-run rewrites — actions\n // are always processed against the cleanPathname they were posted to.\n const preActionMatch = options.matchRoute(cleanPathname);\n if (preActionMatch) {\n setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));\n }\n\n const actionId =\n request.headers.get(RSC_ACTION_HEADER) ?? request.headers.get(NEXT_ACTION_HEADER);\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResult = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResult instanceof Response) return progressiveActionResult;\n const isProgressiveActionRender = progressiveActionResult?.kind === \"form-state\";\n const formState = isProgressiveActionRender ? progressiveActionResult.formState : null;\n const failedProgressiveActionResult =\n isProgressiveActionRender && \"actionFailed\" in progressiveActionResult\n ? progressiveActionResult\n : null;\n const actionFailed = failedProgressiveActionResult !== null;\n const actionError = failedProgressiveActionResult?.actionError;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n let match = preActionMatch;\n if (!match || match.route.isDynamic) {\n const afterFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n matchPathname(cleanPathname),\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) {\n cleanPathname = afterFilesRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n matchPathname(cleanPathname),\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n // Dev-only favicon short-circuit: browsers auto-request /favicon.ico on\n // every page load. Don't compile/render the not-found page for it.\n // Check `canonicalPathname` (the original browser-requested URL) so a\n // middleware rewrite that lands on `/favicon.ico` still falls through to\n // the normal not-found render.\n // Matches Next.js: packages/next/src/server/lib/router-server.ts —\n // condition `parsedUrl.pathname === '/favicon.ico'`.\n if (process.env.NODE_ENV !== \"production\" && canonicalPathname === \"/favicon.ico\") {\n options.clearRequestContext();\n return new Response(\"\", { status: 404 });\n }\n\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const renderedNotFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (renderedNotFoundResponse) return renderedNotFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return notFoundResponse({ headers });\n }\n\n const { route, params } = match;\n const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);\n const prerenderRouteParams = prerenderRouteParamsPayloadMatchesRoute(\n prerenderRouteParamsPayload,\n route.pattern,\n params,\n )\n ? prerenderRouteParamsPayload.params\n : null;\n const renderParams = prerenderRouteParams ?? params;\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: renderParams,\n });\n const rootParams = pickRootParams(renderParams, route.rootParamNames);\n setRootParams(rootParams);\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n // Non-dynamic routes report params as `null` to match Next.js. Internal\n // bookkeeping above (navigation context, root params) keeps the matched\n // object (always `{}` for non-dynamic) so `useParams()` etc. still see\n // an object shape; only the user-facing handler context surfaces null.\n params: route.isDynamic ? renderParams : null,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n const pageResponse = await options.dispatchMatchedPage({\n cleanPathname,\n formState,\n actionError,\n actionFailed,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isProgressiveActionRender,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params: renderParams,\n staticParamsValidationParams: prerenderRouteParams === null ? undefined : params,\n rootParams,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n renderMode,\n });\n\n // No-JS progressive form actions write cookies via cookies().set() / draftMode()\n // *during action execution*, before the page rerender begins. Those writes only\n // exist on the request-scoped headers state; the page-render path never flushes\n // them. We attach them here so the rendered Response carries the action's\n // Set-Cookie headers and revalidation marker, mirroring Next.js'\n // res.setHeader('set-cookie', ...) flush in action-handler.ts / app-render.tsx.\n // Issue: https://github.com/cloudflare/vinext/issues/1483\n if (isProgressiveActionRender) {\n return applyProgressiveActionSideEffects(pageResponse, progressiveActionResult);\n }\n return pageResponse;\n}\n\n/**\n * Append `Set-Cookie` headers and the `x-action-revalidated` marker captured\n * during progressive (no-JS) server action execution to the page render\n * response. See issue #1483.\n *\n * Falls back to rebuilding the response when the headers object is immutable\n * (e.g. `Response.redirect()`), so cookies set by the action ride out on a\n * redirect issued during the rerender too.\n */\nfunction applyProgressiveActionSideEffects(\n response: Response,\n sideEffects: ProgressiveActionFormStateResult,\n): Response {\n const hasPendingCookies = sideEffects.pendingCookies.length > 0;\n const hasDraftCookie = Boolean(sideEffects.draftCookie);\n const hasRevalidationKind = sideEffects.revalidationKind !== 0;\n if (!hasPendingCookies && !hasDraftCookie && !hasRevalidationKind) {\n return response;\n }\n\n const applyTo = (headers: Headers): void => {\n for (const cookie of sideEffects.pendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n if (sideEffects.draftCookie) {\n headers.append(\"Set-Cookie\", sideEffects.draftCookie);\n }\n if (hasRevalidationKind) {\n headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(sideEffects.revalidationKind));\n }\n };\n\n try {\n applyTo(response.headers);\n return response;\n } catch {\n // Headers were immutable (Response.redirect()/Response.error()) — rebuild\n // with a fresh mutable Headers seeded from the original response.\n const headers = new Headers(response.headers);\n applyTo(headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(rawRequest, ctx) {\n await options.ensureInstrumentation?.();\n\n // Strip forged internal headers at the App Router request boundary.\n // Must happen BEFORE headersContextFromRequest() and\n // requestContextFromRequest() so the captured context never contains\n // attacker-controlled internal headers. This is the correct boundary\n // for pure App Router requests; in hybrid app+pages mode the connect\n // handler already filtered headers upstream and x-vinext-mw-ctx\n // (not in INTERNAL_HEADERS) carries the forwarded middleware context.\n // srvx's NodeRequestHeaders reads from rawHeaders for iteration but falls\n // back to req.headers for .get() / .has(). In the dev server we add\n // x-vinext-mw-ctx to req.headers after the Request is built, so it is\n // visible to .get() but lost when filterInternalHeaders iterates. Read it\n // BEFORE iterating so applyForwardedMiddlewareContext can skip middleware.\n const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);\n // Capture `x-nextjs-data` before filtering — the middleware redirect\n // protocol needs to know whether the inbound request was a `_next/data`\n // fetch to emit `x-nextjs-redirect` instead of an HTTP redirect.\n const isDataRequest = rawRequest.headers.get(\"x-nextjs-data\") === \"1\";\n // Read the trusted prerender route params before filtering strips the\n // route-params header (it IS in VINEXT_INTERNAL_HEADERS), then re-attach the\n // validated value below so the second read in handleAppRscRequest still sees\n // it. The secret was already verified upstream at prod-server's\n // nodeToWebRequest boundary; the surviving secret header (NOT in either\n // internal-header list) lets readTrustedPrerenderRouteParams's\n // VINEXT_PRERENDER gate pass on the reconstructed request. If the secret\n // header is ever added to VINEXT_INTERNAL_HEADERS, that second read breaks.\n const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);\n const filteredHeaders = filterInternalHeaders(rawRequest.headers);\n if (mwCtx !== null) {\n filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);\n }\n const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(\n prerenderRouteParamsPayload,\n );\n if (prerenderRouteParamsHeader !== null) {\n filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);\n }\n const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request, {\n draftModeSecret: options.draftModeSecret,\n });\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(\n options,\n request,\n preMiddlewareRequestContext,\n isDataRequest,\n );\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n i18nConfig: options.i18nConfig,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA8FA,SAAS,iCACP,UACA,mBACU;CACV,IAAI,CAAC,kBAAkB,WAAW,kBAAkB,UAAU,MAC5D,OAAO;CAGT,MAAM,UAAU,IAAI,QAAQ,SAAS,QAAQ;CAC7C,+BAA+B,SAAS,kBAAkB,QAAQ;CAElE,OAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,kBAAkB,UAAU,SAAS;EAC7C,YAAY,SAAS;EACrB;EACD,CAAC;;AAiJJ,SAAS,YACP,OACA,KACyC;CACzC,OAAO,OAAO;;AAGhB,SAAS,uBAAuB,OAA+C;CAC7E,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAChD,OAAO,YAAY,OAAO,YAAY,IAAI,OAAO,MAAM,cAAc;;AAOvE,SAAS,gCAAgC,aAAqB,UAA0B;CACtF,IAAI,CAAC,YAAY,cAAc,YAAY,IAAI,YAAY,aAAa,SAAS,EAC/E,OAAO;CAET,OAAO,WAAW;;AAGpB,eAAe,aACb,SAOA,eACmC;CACnC,IAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO;CAErC,MAAM,YAAY,aAChB,eACA,QAAQ,UACR,QAAQ,gBACR,QAAQ,cACT;CACD,IAAI,CAAC,WAAW,OAAO;CAEvB,IAAI,cAAc,UAAU,EAAE;EAC5B,QAAQ,qBAAqB;EAC7B,OAAO,qBAAqB,QAAQ,SAAS,UAAU;;CAGzD,OAAO;;AAGT,SAAS,uCACP,UACA,SAMU;CAIV,IAAI,SAAS,SAAS,OAAO,SAAS,UAAU,KAAK,OAAO;CAC5D,IAAI,CAAC,QAAQ,cAAc,QAAQ,OAAO;CAE1C,MAAM,UAAU,IAAI,SAAS;CAC7B,6BAA6B,SAAS;EACpC,eAAe,QAAQ;EACvB,UAAU,QAAQ;EAClB,gBAAgB,QAAQ;EACxB,eAAe,QAAQ;EACxB,CAAC;CAEF,IAAI,CAAC,QAAQ,SAAS,CAAC,MAAM,CAAC,MAAM;EAClC,+BAA+B,SAAS,SAAS,QAAQ;EACzD,OAAO,IAAI,SAAS,SAAS,MAAM;GACjC,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB;GACD,CAAC;;CAGJ,OAAO;;AAGT,eAAe,oBACb,SACA,SACA,6BACA,eACmB;CACnB,MAAM,eAAe,QAAQ,IAAI,aAAa,eAAe,YAAY,KAAK,GAAG;CAEjF,IAAI,QAAQ,IAAI,aAAa,cAAc;EACzC,MAAM,cAAc,QAAQ,2BAA2B,QAAQ;EAC/D,IAAI,aAAa,OAAO;;CAG1B,MAAM,aAAa,oBAAoB,SAAS,QAAQ,SAAS;CACjE,IAAI,sBAAsB,UAAU,OAAO;CAE3C,MAAM,EAAE,KAAK,cAAc,2BAA2B,oBAAoB,eACxE;CACF,IAAI,EAAE,UAAU,kBAAkB;CAOlC,MAAM,oBAAoB;CAQ1B,MAAM,gBAAgB;EAAE,UAAU,QAAQ;EAAU,aAAa;EAAM;CAEvE,MAAM,4BAA4B,MAAM,2BAA2B,SAAS;EAC1E,qBAAqB;GACnB,OAAO,QAAQ,IAAI,qBAAqB;;EAE1C,iBAAiB,QAAQ;EACzB;EACA,yBAAyB,QAAQ;EACjC,iBAAiB,QAAQ;EAC1B,CAAC;CACF,IAAI,2BAA2B,OAAO;CAEtC,MAAM,wBAAwB,uBAC5B,UACA,QAAQ,UACR,QAAQ,eACR,IAAI,OACL;CACD,IAAI,uBAAuB,OAAO;CAWlC,MAAM,iBAAiB,MACrB,+BAA+B,GAAG,QAAQ,YAAY,EAAE,UAAU,IAAI,UAAU,CAAC;CAGnF,MAAM,WAAW,cADQ,cAAc,eAAe,SAAS,CAE7C,EAChB,QAAQ,iBACR,6BACA,cACD;CACD,IAAI,UAAU;EACZ,MAAM,cAAc,oBAClB,gCAAgC,SAAS,aAAa,QAAQ,SAAS,CACxE;EACD,MAAM,WACJ,gBAAgB,QAAQ,QAAQ,IAAA,MAAe,KAAK,MAChD,MAAM,0BAA0B,aAAa,QAAQ,GACrD;EACN,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ,SAAS,YAAY,MAAM;GACnC,SAAS,EAAE,UAAU,UAAU;GAChC,CAAC;;CAGJ,MAAM,0BAA0B,MAAM,qCAAqC;EACzE;EACA;EACD,CAAC;CACF,IAAI,yBAAyB,OAAO;CAEpC,MAAM,oBAA6C;EACjD,SAAS;EACT,gBAAgB;EAChB,QAAQ;EACT;CAED,IAAI,QAAQ,kBAAkB;EAC5B,MAAM,mBAAmB,MAAM,mBAAmB;GAChD,UAAU,QAAQ;GAClB;GACA,SAAS;GACT,YAAY,QAAQ;GACpB;GACA,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB;GACA,eAAe,QAAQ;GACxB,CAAC;EACF,IAAI,iBAAiB,SAAS,YAC5B,OAAO,uCAAuC,iBAAiB,UAAU;GACvE;GACA,eAAe,QAAQ;GACvB,UAAU,cAAc,cAAc;GACtC,gBAAgB;GACjB,CAAC;EAGJ,gBAAgB,iBAAiB;EACjC,IAAI,iBAAiB,WAAW,MAC9B,IAAI,SAAS,iBAAiB;;CAIlC,MAAM,cAAc,gCAAgC,QAAQ,SAAS,kBAAkB,QAAQ;CAC/F,MAAM,+BAA+B,0BAA0B,QAAQ;CAOvE,MAAM,qBAAqB,MAAM,aAC/B;EACE;EACA,qBAAqB,QAAQ;EAC7B;EACA,gBAAgB;EAChB,UAAU,QAAQ,eAAe;EAClC,EACD,cAAc,cAAc,CAC7B;CACD,IAAI,8BAA8B,UAAU,OAAO;CACnD,IAAI,oBAAoB,gBAAgB;CAExC,IAAI,wBAAwB,cAAc,EAAE;EAC1C,MAAM,iBAAiB,iBAAiB,IAAI,aAAa,IAAI,MAAM,EAAE,QAAQ,IAAI;EACjF,IAAI,0BAA0B,UAAU,OAAO;EAC/C,OAAO,SAAS,SAAS,IAAI,IAAI,gBAAgB,IAAI,OAAO,CAAC,MAAM,IAAI;;CAGzE,MAAM,wBAAwB,MAAM,2BAA2B;EAC7D,gBAAgB,QAAQ;EACxB;EACA,oBAAoB,QAAQ;EAC7B,CAAC;CACF,IAAI,uBACF,OAAO,iCAAiC,uBAAuB,kBAAkB;CAGnF,MAAM,qBAAqB,uBAAuB;EAChD;EACA;EACA;EACA,aAAa,QAAQ;EACrB;EACD,CAAC;CACF,IAAI,oBAAoB;EACtB,QAAQ,qBAAqB;EAC7B,OAAO;;CAGT,IAAI,cACF,gCAAgC,IAAI;CAGtC,QAAQ,qBAAqB;EAC3B,UAAU;EACV,cAAc,IAAI;EAClB,QAAQ,EAAE;EACX,CAAC;CAgBF,MAAM,iBAAiB,QAAQ,WAAW,cAAc;CACxD,IAAI,gBACF,cAAc,eAAe,eAAe,QAAQ,eAAe,MAAM,eAAe,CAAC;CAG3F,MAAM,WACJ,QAAQ,QAAQ,IAAA,eAAsB,IAAI,QAAQ,QAAQ,IAAA,cAAuB;CACnF,MAAM,cAAc,QAAQ,QAAQ,IAAI,eAAe,IAAI;CAE3D,MAAM,0BAA0B,MAAM,QAAQ,+BAA+B;EAC3E;EACA;EACA;EACA;EACA;EACD,CAAC;CACF,IAAI,mCAAmC,UAAU,OAAO;CACxD,MAAM,4BAA4B,yBAAyB,SAAS;CACpE,MAAM,YAAY,4BAA4B,wBAAwB,YAAY;CAClF,MAAM,gCACJ,6BAA6B,kBAAkB,0BAC3C,0BACA;CACN,MAAM,eAAe,kCAAkC;CACvD,MAAM,cAAc,+BAA+B;CAEnD,MAAM,uBAAuB,MAAM,QAAQ,0BAA0B;EACnE;EACA;EACA;EACA,qBAAqB;EACrB;EACA;EACA;EACA;EACA,cAAc,IAAI;EACnB,CAAC;CACF,IAAI,sBAAsB,OAAO;CAEjC,IAAI,QAAQ;CACZ,IAAI,CAAC,SAAS,MAAM,MAAM,WAAW;EACnC,MAAM,oBAAoB,MAAM,aAC9B;GACE;GACA,qBAAqB,QAAQ;GAC7B;GACA,gBAAgB;GAChB,UAAU,QAAQ,eAAe;GAClC,EACD,cAAc,cAAc,CAC7B;EACD,IAAI,6BAA6B,UAAU,OAAO;EAClD,IAAI,mBAAmB;GACrB,gBAAgB;GAChB,QAAQ,QAAQ,WAAW,cAAc;;;CAI7C,IAAI,CAAC,OAAO;EACV,MAAM,kBAAkB,MAAM,aAC5B;GACE;GACA,qBAAqB,QAAQ;GAC7B;GACA,gBAAgB;GAChB,UAAU,QAAQ,eAAe;GAClC,EACD,cAAc,cAAc,CAC7B;EACD,IAAI,2BAA2B,UAAU,OAAO;EAChD,IAAI,iBAAiB;GACnB,gBAAgB;GAChB,QAAQ,QAAQ,WAAW,cAAc;;;CAI7C,IAAI,CAAC,OAAO;EAQV,IAAI,QAAQ,IAAI,aAAa,gBAAgB,sBAAsB,gBAAgB;GACjF,QAAQ,qBAAqB;GAC7B,OAAO,IAAI,SAAS,IAAI,EAAE,QAAQ,KAAK,CAAC;;EAG1C,MAAM,wBAAwB,MAAM,QAAQ,sBAAsB;GAChE;GACA;GACA;GACA;GACD,CAAC;EACF,IAAI,uBAAuB;GACzB,QAAQ,qBAAqB;GAC7B,OAAO;;EAGT,MAAM,2BAA2B,MAAM,QAAQ,eAAe;GAC5D;GACA;GACA;GACA,OAAO;GACP;GACD,CAAC;EACF,IAAI,0BAA0B,OAAO;EAErC,QAAQ,qBAAqB;EAC7B,MAAM,UAAU,IAAI,SAAS;EAC7B,+BAA+B,SAAS,kBAAkB,QAAQ;EAClE,OAAO,iBAAiB,EAAE,SAAS,CAAC;;CAGtC,MAAM,EAAE,OAAO,WAAW;CAC1B,MAAM,8BAA8B,gCAAgC,QAAQ;CAC5E,MAAM,uBAAuB,wCAC3B,6BACA,MAAM,SACN,OACD,GACG,4BAA4B,SAC5B;CACJ,MAAM,eAAe,wBAAwB;CAC7C,QAAQ,qBAAqB;EAC3B,UAAU;EACV,cAAc,IAAI;EAClB,QAAQ;EACT,CAAC;CACF,MAAM,aAAa,eAAe,cAAc,MAAM,eAAe;CACrE,cAAc,WAAW;CAEzB,IAAI,MAAM,cAAc;EACtB,wBACE,mBAAmB,eAAe,EAAE,EAAE,CAAC,GAAG,MAAM,cAAc,EAAE,QAAQ,CACzE;EACD,OAAO,QAAQ,4BAA4B;GACzC;GACA;GAKA,QAAQ,MAAM,YAAY,eAAe;GACzC;GACA;GACA,cAAc,IAAI;GACnB,CAAC;;CAGJ,MAAM,eAAe,MAAM,QAAQ,oBAAoB;EACrD;EACA;EACA;EACA;EACA;EACA,qBAAqB;EACrB;EACA;EACA;EACA;EACA,QAAQ;EACR,8BAA8B,yBAAyB,OAAO,KAAA,IAAY;EAC1E;EACA;EACA;EACA;EACA,cAAc,IAAI;EAClB;EACD,CAAC;CASF,IAAI,2BACF,OAAO,kCAAkC,cAAc,wBAAwB;CAEjF,OAAO;;;;;;;;;;;AAYT,SAAS,kCACP,UACA,aACU;CACV,MAAM,oBAAoB,YAAY,eAAe,SAAS;CAC9D,MAAM,iBAAiB,QAAQ,YAAY,YAAY;CACvD,MAAM,sBAAsB,YAAY,qBAAqB;CAC7D,IAAI,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,qBAC5C,OAAO;CAGT,MAAM,WAAW,YAA2B;EAC1C,KAAK,MAAM,UAAU,YAAY,gBAC/B,QAAQ,OAAO,cAAc,OAAO;EAEtC,IAAI,YAAY,aACd,QAAQ,OAAO,cAAc,YAAY,YAAY;EAEvD,IAAI,qBACF,QAAQ,IAAI,2BAA2B,KAAK,UAAU,YAAY,iBAAiB,CAAC;;CAIxF,IAAI;EACF,QAAQ,SAAS,QAAQ;EACzB,OAAO;SACD;EAGN,MAAM,UAAU,IAAI,QAAQ,SAAS,QAAQ;EAC7C,QAAQ,QAAQ;EAChB,OAAO,IAAI,SAAS,SAAS,MAAM;GACjC,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB;GACD,CAAC;;;AAIN,SAAgB,oBACd,SACuD;CACvD,OAAO,eAAe,cAAc,YAAY,KAAK;EACnD,MAAM,QAAQ,yBAAyB;EAcvC,MAAM,QAAQ,WAAW,QAAQ,IAAI,qBAAqB;EAI1D,MAAM,gBAAgB,WAAW,QAAQ,IAAI,gBAAgB,KAAK;EASlE,MAAM,8BAA8B,gCAAgC,WAAW;EAC/E,MAAM,kBAAkB,sBAAsB,WAAW,QAAQ;EACjE,IAAI,UAAU,MACZ,gBAAgB,IAAI,sBAAsB,MAAM;EAElD,MAAM,6BAA6B,oCACjC,4BACD;EACD,IAAI,+BAA+B,MACjC,gBAAgB,IAAI,sCAAsC,2BAA2B;EAEvF,MAAM,UAAU,wBAAwB,YAAY,gBAAgB;EAEpE,MAAM,mBAAmB,uBAAuB,IAAI,GAChD,MACC,4BAA4B,IAAI;EAUrC,OAAO,sBANgB,qBAAqB;GAC1C,gBAJqB,0BAA0B,SAAS,EACxD,iBAAiB,QAAQ,iBAC1B,CAEe;GACd;GACA,2BAA2B;GAC5B,CAE0C,QACzC,yBACE,YAAY;GACV,kBAAkB;GAClB,MAAM,8BAA8B,0BAA0B,QAAQ;GACtE,IAAI;GAEJ,IAAI;IACF,WAAW,MAAM,oBACf,SACA,SACA,6BACA,cACD;YACM,OAAO;IACd,IAAI,QAAQ,IAAI,aAAa,cAC3B,mBAAmB,MAAM;IAE3B,MAAM;;GAGR,OAAO,uBAAuB,UAAU,SAAS;IAC/C,UAAU,QAAQ;IAClB,eAAe,QAAQ;IACvB,YAAY,QAAQ;IACpB,gBAAgB;IACjB,CAAC;KAEJ,EAAE,aAAa,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAC/C,CACF"}
|
|
@@ -14,7 +14,7 @@ type EffectiveAppPageSegmentConfig = {
|
|
|
14
14
|
dynamicParamsConfig?: boolean;
|
|
15
15
|
fetchCache?: FetchCacheMode;
|
|
16
16
|
revalidateSeconds: number | null;
|
|
17
|
-
runtime?:
|
|
17
|
+
runtime?: "edge" | "experimental-edge" | "nodejs";
|
|
18
18
|
};
|
|
19
19
|
type ResolveAppPageSegmentConfigOptions = {
|
|
20
20
|
layouts?: readonly (AppRouteSegmentConfigModule | null | undefined)[];
|
|
@@ -21,6 +21,9 @@ function isRouteSegmentDynamic(value) {
|
|
|
21
21
|
function isRouteSegmentFetchCache(value) {
|
|
22
22
|
return FETCH_CACHE_VALUES.has(value);
|
|
23
23
|
}
|
|
24
|
+
function isRouteSegmentRuntime(value) {
|
|
25
|
+
return value === "edge" || value === "experimental-edge" || value === "nodejs";
|
|
26
|
+
}
|
|
24
27
|
function resolveRevalidateSeconds(current, value) {
|
|
25
28
|
if (value === false) {
|
|
26
29
|
if (current === null) return Infinity;
|
|
@@ -55,6 +58,7 @@ function resolveAppPageSegmentConfig(options) {
|
|
|
55
58
|
for (const segment of segments) {
|
|
56
59
|
if (!segment) continue;
|
|
57
60
|
if (isRouteSegmentDynamic(segment.dynamic)) config.dynamicConfig = segment.dynamic;
|
|
61
|
+
if (isRouteSegmentRuntime(segment.runtime)) config.runtime = segment.runtime;
|
|
58
62
|
if (segment.dynamicParams === false) config.dynamicParamsConfig = false;
|
|
59
63
|
else if (segment.dynamicParams === true && config.dynamicParamsConfig !== false) config.dynamicParamsConfig = true;
|
|
60
64
|
if (isRouteSegmentFetchCache(segment.fetchCache)) {
|
|
@@ -73,7 +77,6 @@ function resolveAppPageSegmentConfig(options) {
|
|
|
73
77
|
else config.fetchCache = fetchCache;
|
|
74
78
|
}
|
|
75
79
|
config.revalidateSeconds = resolveRevalidateSeconds(config.revalidateSeconds, segment.revalidate);
|
|
76
|
-
if (typeof segment.runtime === "string") config.runtime = segment.runtime;
|
|
77
80
|
}
|
|
78
81
|
if (config.dynamicConfig === "force-dynamic") config.revalidateSeconds = 0;
|
|
79
82
|
if (config.fetchCache === void 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-segment-config.js","names":[],"sources":["../../src/server/app-segment-config.ts"],"sourcesContent":["import type { FetchCacheMode } from \"vinext/shims/fetch-cache\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\n\ntype AppRouteSegmentDynamic = \"auto\" | \"error\" | \"force-dynamic\" | \"force-static\";\n\ntype AppRouteSegmentConfigModule = {\n dynamic?: unknown;\n dynamicParams?: unknown;\n fetchCache?: unknown;\n revalidate?: unknown;\n runtime?: unknown;\n};\n\ntype EffectiveAppPageSegmentConfig = {\n dynamicConfig?: AppRouteSegmentDynamic;\n dynamicParamsConfig?: boolean;\n fetchCache?: FetchCacheMode;\n revalidateSeconds: number | null;\n runtime?:
|
|
1
|
+
{"version":3,"file":"app-segment-config.js","names":[],"sources":["../../src/server/app-segment-config.ts"],"sourcesContent":["import type { FetchCacheMode } from \"vinext/shims/fetch-cache\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\n\ntype AppRouteSegmentDynamic = \"auto\" | \"error\" | \"force-dynamic\" | \"force-static\";\n\ntype AppRouteSegmentConfigModule = {\n dynamic?: unknown;\n dynamicParams?: unknown;\n fetchCache?: unknown;\n revalidate?: unknown;\n runtime?: unknown;\n};\n\ntype EffectiveAppPageSegmentConfig = {\n dynamicConfig?: AppRouteSegmentDynamic;\n dynamicParamsConfig?: boolean;\n fetchCache?: FetchCacheMode;\n revalidateSeconds: number | null;\n runtime?: \"edge\" | \"experimental-edge\" | \"nodejs\";\n};\n\ntype ResolveAppPageSegmentConfigOptions = {\n layouts?: readonly (AppRouteSegmentConfigModule | null | undefined)[];\n page?: AppRouteSegmentConfigModule | null;\n};\n\nconst DYNAMIC_VALUES = new Set<unknown>([\"auto\", \"error\", \"force-dynamic\", \"force-static\"]);\nconst FETCH_CACHE_VALUES = new Set<unknown>([\n \"auto\",\n \"default-cache\",\n \"default-no-store\",\n \"force-cache\",\n \"force-no-store\",\n \"only-cache\",\n \"only-no-store\",\n]);\n\nfunction isRouteSegmentDynamic(value: unknown): value is AppRouteSegmentDynamic {\n return DYNAMIC_VALUES.has(value);\n}\n\nfunction isRouteSegmentFetchCache(value: unknown): value is FetchCacheMode {\n return FETCH_CACHE_VALUES.has(value);\n}\n\nfunction isRouteSegmentRuntime(value: unknown): value is EffectiveAppPageSegmentConfig[\"runtime\"] {\n return value === \"edge\" || value === \"experimental-edge\" || value === \"nodejs\";\n}\n\nfunction resolveRevalidateSeconds(current: number | null, value: unknown): number | null {\n // revalidate = false means \"cache indefinitely\" in Next.js segment config.\n // Represent it as Infinity so downstream code can distinguish \"never\n // revalidate\" (Infinity) from \"no config / unset\" (null).\n if (value === false) {\n if (current === null) return Infinity;\n // Shortest-wins: any finite interval is shorter than Infinity.\n return current === Infinity ? Infinity : current;\n }\n\n if (typeof value !== \"number\") {\n return current;\n }\n\n if (current === null) {\n return value;\n }\n\n return value < current ? value : current;\n}\n\nfunction isCacheFetchCacheMode(value: FetchCacheMode): boolean {\n return value === \"default-cache\" || value === \"force-cache\" || value === \"only-cache\";\n}\n\nfunction describeFetchCacheConflict(value: FetchCacheMode): string {\n return `Route segment config has incompatible fetchCache values including \"${value}\".`;\n}\n\n/**\n * Resolve the route segment config that applies to an App page route.\n *\n * Next.js collects config from every segment in the loader tree and reduces it\n * into the effective route config. The generated vinext entry already knows\n * the concrete layout/page modules for a route, so it should only describe\n * those modules and delegate the behavior to this helper.\n */\nexport function resolveAppPageSegmentConfig(\n options: ResolveAppPageSegmentConfigOptions,\n): EffectiveAppPageSegmentConfig {\n const segments = [...(options.layouts ?? []), options.page];\n // Reduction strategies differ by field:\n // - dynamic: child segments override parents.\n // - dynamicParams: false is sticky across the route tree.\n // - fetchCache: force/only modes take route-level precedence and reject conflicts.\n // - revalidate: the shortest numeric interval wins.\n const config: EffectiveAppPageSegmentConfig = {\n revalidateSeconds: null,\n };\n let hasForceCache = false;\n let hasForceNoStore = false;\n let hasOnlyCache = false;\n let hasOnlyNoStore = false;\n let hasParentDefaultNoStore = false;\n\n for (const segment of segments) {\n if (!segment) continue;\n\n if (isRouteSegmentDynamic(segment.dynamic)) {\n config.dynamicConfig = segment.dynamic;\n }\n\n if (isRouteSegmentRuntime(segment.runtime)) {\n config.runtime = segment.runtime;\n }\n\n if (segment.dynamicParams === false) {\n config.dynamicParamsConfig = false;\n } else if (segment.dynamicParams === true && config.dynamicParamsConfig !== false) {\n config.dynamicParamsConfig = true;\n }\n\n if (isRouteSegmentFetchCache(segment.fetchCache)) {\n const fetchCache = segment.fetchCache;\n\n if (hasParentDefaultNoStore && (fetchCache === \"auto\" || isCacheFetchCacheMode(fetchCache))) {\n throw new Error(describeFetchCacheConflict(fetchCache));\n }\n\n if (fetchCache === \"force-cache\") hasForceCache = true;\n if (fetchCache === \"force-no-store\") hasForceNoStore = true;\n if (fetchCache === \"only-cache\") hasOnlyCache = true;\n if (fetchCache === \"only-no-store\") hasOnlyNoStore = true;\n\n const hasCacheEnforcer = hasForceCache || hasOnlyCache;\n const hasNoStoreEnforcer = hasForceNoStore || hasOnlyNoStore;\n if (hasCacheEnforcer && hasNoStoreEnforcer) {\n throw new Error(describeFetchCacheConflict(fetchCache));\n }\n\n if (fetchCache === \"default-no-store\") {\n hasParentDefaultNoStore = true;\n }\n\n if (hasForceCache) {\n config.fetchCache = \"force-cache\";\n } else if (hasForceNoStore) {\n config.fetchCache = \"force-no-store\";\n } else if (hasOnlyCache) {\n config.fetchCache = \"only-cache\";\n } else if (hasOnlyNoStore) {\n config.fetchCache = \"only-no-store\";\n } else {\n config.fetchCache = fetchCache;\n }\n }\n\n config.revalidateSeconds = resolveRevalidateSeconds(\n config.revalidateSeconds,\n segment.revalidate,\n );\n }\n\n if (config.dynamicConfig === \"force-dynamic\") {\n config.revalidateSeconds = 0;\n }\n\n // Top-level dynamic modes supply fetchCache defaults unless a segment does.\n if (config.fetchCache === undefined) {\n if (config.dynamicConfig === \"force-dynamic\") {\n config.fetchCache = \"force-no-store\";\n } else if (config.dynamicConfig === \"error\") {\n config.fetchCache = \"only-cache\";\n }\n }\n\n // Static-only dynamic modes change the default, but explicit dynamicParams wins.\n if (\n config.dynamicParamsConfig === undefined &&\n (config.dynamicConfig === \"error\" || config.dynamicConfig === \"force-static\")\n ) {\n config.dynamicParamsConfig = false;\n }\n\n return config;\n}\n\nexport function resolveAppPageFetchCacheMode(\n options: ResolveAppPageSegmentConfigOptions,\n): FetchCacheMode | null {\n return resolveAppPageSegmentConfig(options).fetchCache ?? null;\n}\n\nexport function isEdgeRuntime(runtime: string | undefined): boolean {\n return isEdgeApiRuntime(runtime);\n}\n"],"mappings":";;AA0BA,MAAM,iBAAiB,IAAI,IAAa;CAAC;CAAQ;CAAS;CAAiB;CAAe,CAAC;AAC3F,MAAM,qBAAqB,IAAI,IAAa;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,sBAAsB,OAAiD;CAC9E,OAAO,eAAe,IAAI,MAAM;;AAGlC,SAAS,yBAAyB,OAAyC;CACzE,OAAO,mBAAmB,IAAI,MAAM;;AAGtC,SAAS,sBAAsB,OAAmE;CAChG,OAAO,UAAU,UAAU,UAAU,uBAAuB,UAAU;;AAGxE,SAAS,yBAAyB,SAAwB,OAA+B;CAIvF,IAAI,UAAU,OAAO;EACnB,IAAI,YAAY,MAAM,OAAO;EAE7B,OAAO,YAAY,WAAW,WAAW;;CAG3C,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,IAAI,YAAY,MACd,OAAO;CAGT,OAAO,QAAQ,UAAU,QAAQ;;AAGnC,SAAS,sBAAsB,OAAgC;CAC7D,OAAO,UAAU,mBAAmB,UAAU,iBAAiB,UAAU;;AAG3E,SAAS,2BAA2B,OAA+B;CACjE,OAAO,sEAAsE,MAAM;;;;;;;;;;AAWrF,SAAgB,4BACd,SAC+B;CAC/B,MAAM,WAAW,CAAC,GAAI,QAAQ,WAAW,EAAE,EAAG,QAAQ,KAAK;CAM3D,MAAM,SAAwC,EAC5C,mBAAmB,MACpB;CACD,IAAI,gBAAgB;CACpB,IAAI,kBAAkB;CACtB,IAAI,eAAe;CACnB,IAAI,iBAAiB;CACrB,IAAI,0BAA0B;CAE9B,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,CAAC,SAAS;EAEd,IAAI,sBAAsB,QAAQ,QAAQ,EACxC,OAAO,gBAAgB,QAAQ;EAGjC,IAAI,sBAAsB,QAAQ,QAAQ,EACxC,OAAO,UAAU,QAAQ;EAG3B,IAAI,QAAQ,kBAAkB,OAC5B,OAAO,sBAAsB;OACxB,IAAI,QAAQ,kBAAkB,QAAQ,OAAO,wBAAwB,OAC1E,OAAO,sBAAsB;EAG/B,IAAI,yBAAyB,QAAQ,WAAW,EAAE;GAChD,MAAM,aAAa,QAAQ;GAE3B,IAAI,4BAA4B,eAAe,UAAU,sBAAsB,WAAW,GACxF,MAAM,IAAI,MAAM,2BAA2B,WAAW,CAAC;GAGzD,IAAI,eAAe,eAAe,gBAAgB;GAClD,IAAI,eAAe,kBAAkB,kBAAkB;GACvD,IAAI,eAAe,cAAc,eAAe;GAChD,IAAI,eAAe,iBAAiB,iBAAiB;GAIrD,KAFyB,iBAAiB,kBACf,mBAAmB,iBAE5C,MAAM,IAAI,MAAM,2BAA2B,WAAW,CAAC;GAGzD,IAAI,eAAe,oBACjB,0BAA0B;GAG5B,IAAI,eACF,OAAO,aAAa;QACf,IAAI,iBACT,OAAO,aAAa;QACf,IAAI,cACT,OAAO,aAAa;QACf,IAAI,gBACT,OAAO,aAAa;QAEpB,OAAO,aAAa;;EAIxB,OAAO,oBAAoB,yBACzB,OAAO,mBACP,QAAQ,WACT;;CAGH,IAAI,OAAO,kBAAkB,iBAC3B,OAAO,oBAAoB;CAI7B,IAAI,OAAO,eAAe,KAAA;MACpB,OAAO,kBAAkB,iBAC3B,OAAO,aAAa;OACf,IAAI,OAAO,kBAAkB,SAClC,OAAO,aAAa;;CAKxB,IACE,OAAO,wBAAwB,KAAA,MAC9B,OAAO,kBAAkB,WAAW,OAAO,kBAAkB,iBAE9D,OAAO,sBAAsB;CAG/B,OAAO;;AAGT,SAAgB,6BACd,SACuB;CACvB,OAAO,4BAA4B,QAAQ,CAAC,cAAc;;AAG5D,SAAgB,cAAc,SAAsC;CAClE,OAAO,iBAAiB,QAAQ"}
|
|
@@ -27,7 +27,10 @@ type AppServerActionReturnValue = {
|
|
|
27
27
|
ok: false;
|
|
28
28
|
};
|
|
29
29
|
type AppServerActionRoute = {
|
|
30
|
+
page?: unknown;
|
|
30
31
|
pattern: string;
|
|
32
|
+
routeHandler?: unknown;
|
|
33
|
+
routeSegments?: readonly string[];
|
|
31
34
|
};
|
|
32
35
|
/**
|
|
33
36
|
* Side-effect headers captured during a progressive (no-JS) server action's
|
|
@@ -46,6 +49,7 @@ type ProgressiveServerActionSideEffects = {
|
|
|
46
49
|
draftCookie: string | null | undefined; /** Resolved revalidation kind to emit via `x-action-revalidated`. */
|
|
47
50
|
revalidationKind: ActionRevalidationKind;
|
|
48
51
|
};
|
|
52
|
+
type AppServerActionRouteRuntime = "edge" | "experimental-edge" | "nodejs" | null;
|
|
49
53
|
type ProgressiveServerActionResult = ({
|
|
50
54
|
formState: ReactFormState | null;
|
|
51
55
|
kind: "form-state";
|
|
@@ -142,6 +146,7 @@ type HandleServerActionRscRequestOptions<TElement, TRoute extends AppServerActio
|
|
|
142
146
|
renderToReadableStream: (model: AppServerActionRscModel<TElement>, options: RenderServerActionRscStreamOptions<TTemporaryReferences>) => BodyInit | null | Promise<BodyInit | null>;
|
|
143
147
|
reportRequestError: AppServerActionErrorReporter;
|
|
144
148
|
resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;
|
|
149
|
+
resolveRouteRuntime?: (route: TRoute) => AppServerActionRouteRuntime;
|
|
145
150
|
request: Request;
|
|
146
151
|
sanitizeErrorForClient: (error: unknown) => unknown;
|
|
147
152
|
searchParams: URLSearchParams;
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import { addBasePathToPathname, hasBasePath } from "../utils/base-path.js";
|
|
2
|
-
import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER } from "./headers.js";
|
|
1
|
+
import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
2
|
+
import { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER } from "./headers.js";
|
|
3
3
|
import { isExternalUrl } from "../config/config-matchers.js";
|
|
4
4
|
import { internalServerErrorResponse, payloadTooLargeResponse } from "./http-error-responses.js";
|
|
5
5
|
import { validateCsrfOrigin, validateServerActionPayload } from "./request-pipeline.js";
|
|
6
|
+
import { headersContextFromRequest, setHeadersContext } from "../shims/headers.js";
|
|
6
7
|
import { getAndClearActionRevalidationKind } from "../shims/cache.js";
|
|
7
8
|
import { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI } from "./app-rsc-render-mode.js";
|
|
8
|
-
import { setCurrentFetchCacheMode } from "../shims/fetch-cache.js";
|
|
9
|
+
import { setCurrentFetchCacheMode, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
|
|
9
10
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
10
11
|
import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
|
|
11
12
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage, isServerActionNotFoundError } from "./server-action-not-found.js";
|
|
12
13
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
13
14
|
import { applyEdgeRuntimeHeader } from "./app-page-response.js";
|
|
14
15
|
import { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
|
|
16
|
+
import { deferUntilStreamConsumed } from "./app-page-stream.js";
|
|
15
17
|
import { resolveAppPageActionRerenderTarget } from "./app-page-request.js";
|
|
18
|
+
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
16
19
|
import { getSetCookieName } from "./cookie-utils.js";
|
|
17
20
|
//#region src/server/app-server-action-execution.ts
|
|
18
21
|
/**
|
|
@@ -22,6 +25,16 @@ import { getSetCookieName } from "./cookie-utils.js";
|
|
|
22
25
|
const SERVER_ACTION_ARGS_LIMIT = 1e3;
|
|
23
26
|
const ACTION_DID_NOT_REVALIDATE = 0;
|
|
24
27
|
const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
|
|
28
|
+
const ACTION_REDIRECT_RENDER_STRIPPED_HEADERS = [
|
|
29
|
+
"accept",
|
|
30
|
+
"content-length",
|
|
31
|
+
"content-type",
|
|
32
|
+
"next-action",
|
|
33
|
+
"origin",
|
|
34
|
+
"rsc",
|
|
35
|
+
"x-action-forwarded",
|
|
36
|
+
"x-rsc-action"
|
|
37
|
+
];
|
|
25
38
|
function setActionRevalidatedHeader(headers, kind) {
|
|
26
39
|
if (kind === ACTION_DID_NOT_REVALIDATE) return;
|
|
27
40
|
headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(kind));
|
|
@@ -31,6 +44,67 @@ function resolveActionRevalidationKind(hasModifiedCookies) {
|
|
|
31
44
|
if (hasModifiedCookies) return ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC;
|
|
32
45
|
return revalidationKind;
|
|
33
46
|
}
|
|
47
|
+
function cloneActionRedirectHeaders(requestHeaders) {
|
|
48
|
+
const headers = new Headers(requestHeaders);
|
|
49
|
+
for (const header of ACTION_REDIRECT_RENDER_STRIPPED_HEADERS) headers.delete(header);
|
|
50
|
+
return headers;
|
|
51
|
+
}
|
|
52
|
+
function readSetCookieNameValue(setCookie) {
|
|
53
|
+
const equalsIndex = setCookie.indexOf("=");
|
|
54
|
+
if (equalsIndex <= 0) return null;
|
|
55
|
+
const name = setCookie.slice(0, equalsIndex).trim();
|
|
56
|
+
const valueEnd = setCookie.indexOf(";", equalsIndex + 1);
|
|
57
|
+
return {
|
|
58
|
+
name,
|
|
59
|
+
value: setCookie.slice(equalsIndex + 1, valueEnd === -1 ? void 0 : valueEnd)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function isExpiredSetCookie(setCookie) {
|
|
63
|
+
return /(?:^|;\s*)max-age=0(?:;|$)/i.test(setCookie) || /(?:^|;\s*)expires=Thu,\s*0?1[\s-]+Jan[\s-]+1970/i.test(setCookie);
|
|
64
|
+
}
|
|
65
|
+
function applySetCookieMutationsToRequestCookieHeader(cookieHeader, setCookies) {
|
|
66
|
+
const cookies = /* @__PURE__ */ new Map();
|
|
67
|
+
if (cookieHeader) for (const part of cookieHeader.split(";")) {
|
|
68
|
+
const trimmed = part.trim();
|
|
69
|
+
if (!trimmed) continue;
|
|
70
|
+
const equalsIndex = trimmed.indexOf("=");
|
|
71
|
+
if (equalsIndex <= 0) continue;
|
|
72
|
+
cookies.set(trimmed.slice(0, equalsIndex), trimmed.slice(equalsIndex + 1));
|
|
73
|
+
}
|
|
74
|
+
for (const setCookie of setCookies) {
|
|
75
|
+
const entry = readSetCookieNameValue(setCookie);
|
|
76
|
+
if (!entry) continue;
|
|
77
|
+
if (isExpiredSetCookie(setCookie)) cookies.delete(entry.name);
|
|
78
|
+
else cookies.set(entry.name, entry.value);
|
|
79
|
+
}
|
|
80
|
+
return cookies.size === 0 ? null : [...cookies].map(([name, value]) => `${name}=${value}`).join("; ");
|
|
81
|
+
}
|
|
82
|
+
function createActionRedirectRenderRequest(options) {
|
|
83
|
+
const headers = cloneActionRedirectHeaders(options.request.headers);
|
|
84
|
+
const cookieHeader = applySetCookieMutationsToRequestCookieHeader(headers.get("cookie"), options.pendingCookies);
|
|
85
|
+
if (cookieHeader === null) headers.delete("cookie");
|
|
86
|
+
else headers.set("cookie", cookieHeader);
|
|
87
|
+
return new Request(options.url, {
|
|
88
|
+
headers,
|
|
89
|
+
method: "GET"
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function withoutRscBodyHeaders(headers) {
|
|
93
|
+
const nextHeaders = new Headers(headers);
|
|
94
|
+
nextHeaders.delete("Content-Type");
|
|
95
|
+
nextHeaders.delete("Vary");
|
|
96
|
+
return nextHeaders;
|
|
97
|
+
}
|
|
98
|
+
function isReadableStreamBody(body) {
|
|
99
|
+
return typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
|
|
100
|
+
}
|
|
101
|
+
function createServerActionRscResponse(body, init, clearRequestContext) {
|
|
102
|
+
if (!isReadableStreamBody(body)) {
|
|
103
|
+
clearRequestContext();
|
|
104
|
+
return new Response(body, init);
|
|
105
|
+
}
|
|
106
|
+
return new Response(deferUntilStreamConsumed(body, clearRequestContext), init);
|
|
107
|
+
}
|
|
34
108
|
function isRequestBodyTooLarge(error) {
|
|
35
109
|
return error instanceof Error && error.message === "Request body too large";
|
|
36
110
|
}
|
|
@@ -147,6 +221,56 @@ function applyActionRedirectBasePath(url, basePath) {
|
|
|
147
221
|
const suffix = splitAt === -1 ? "" : url.slice(splitAt);
|
|
148
222
|
return `${addBasePathToPathname(pathname, basePath)}${suffix}`;
|
|
149
223
|
}
|
|
224
|
+
function buildServerActionPageTags(route, pathname) {
|
|
225
|
+
return buildPageCacheTags(pathname, [], [...route.routeSegments ?? []], "page");
|
|
226
|
+
}
|
|
227
|
+
function resolveInternalActionRedirectTarget(redirectUrl, requestUrl, basePath) {
|
|
228
|
+
if (isExternalUrl(redirectUrl)) {
|
|
229
|
+
const requestOrigin = new URL(requestUrl).origin;
|
|
230
|
+
const parsed = new URL(redirectUrl);
|
|
231
|
+
if (parsed.origin !== requestOrigin) return null;
|
|
232
|
+
if (basePath && !hasBasePath(parsed.pathname, basePath)) return null;
|
|
233
|
+
return parsed;
|
|
234
|
+
}
|
|
235
|
+
let resolvedBase = requestUrl;
|
|
236
|
+
if (!redirectUrl.startsWith("/") && !/^[a-z]+:/i.test(redirectUrl)) {
|
|
237
|
+
const parsedRequestUrl = new URL(requestUrl);
|
|
238
|
+
let pathname = parsedRequestUrl.pathname;
|
|
239
|
+
if (!pathname.endsWith("/")) pathname = pathname + "/";
|
|
240
|
+
resolvedBase = `${parsedRequestUrl.origin}${pathname}${parsedRequestUrl.search}`;
|
|
241
|
+
}
|
|
242
|
+
return new URL(redirectUrl, resolvedBase);
|
|
243
|
+
}
|
|
244
|
+
function isAncestorRouteRedirect(targetPathname, currentPathname) {
|
|
245
|
+
return targetPathname !== "/" && currentPathname.startsWith(`${targetPathname}/`);
|
|
246
|
+
}
|
|
247
|
+
function splitActionRedirectPathname(pathname) {
|
|
248
|
+
return pathname.split("/").filter(Boolean);
|
|
249
|
+
}
|
|
250
|
+
function isStaleChildSiblingRouteRedirect(targetPathname, currentPathname) {
|
|
251
|
+
const targetSegments = splitActionRedirectPathname(targetPathname);
|
|
252
|
+
const currentSegments = splitActionRedirectPathname(currentPathname);
|
|
253
|
+
if (targetSegments.length === 0 || currentSegments.length <= targetSegments.length) return false;
|
|
254
|
+
let commonPrefixLength = 0;
|
|
255
|
+
const maxPrefixLength = Math.min(targetSegments.length, currentSegments.length);
|
|
256
|
+
while (commonPrefixLength < maxPrefixLength && targetSegments[commonPrefixLength] === currentSegments[commonPrefixLength]) commonPrefixLength++;
|
|
257
|
+
return commonPrefixLength > 0 && commonPrefixLength < targetSegments.length;
|
|
258
|
+
}
|
|
259
|
+
function normalizeRuntime(runtime) {
|
|
260
|
+
if (runtime === "edge" || runtime === "experimental-edge") return "edge";
|
|
261
|
+
return "nodejs";
|
|
262
|
+
}
|
|
263
|
+
function shouldUseForwardedActionRedirectStatus(options) {
|
|
264
|
+
if (options.actionWasForwarded) return true;
|
|
265
|
+
if (isAncestorRouteRedirect(options.targetPathname, options.currentPathname)) return true;
|
|
266
|
+
if (isStaleChildSiblingRouteRedirect(options.targetPathname, options.currentPathname)) return true;
|
|
267
|
+
if (!options.currentRoute || !options.resolveRouteRuntime) return false;
|
|
268
|
+
return normalizeRuntime(options.resolveRouteRuntime(options.currentRoute)) !== normalizeRuntime(options.resolveRouteRuntime(options.targetRoute));
|
|
269
|
+
}
|
|
270
|
+
function canRenderActionRedirectTarget(route) {
|
|
271
|
+
if ("routeHandler" in route && route.routeHandler) return false;
|
|
272
|
+
return route.page !== null && route.page !== void 0;
|
|
273
|
+
}
|
|
150
274
|
function getActionHttpFallbackStatus(error) {
|
|
151
275
|
const digest = getNextErrorDigest(error);
|
|
152
276
|
if (!digest) return null;
|
|
@@ -180,10 +304,6 @@ function isProgressiveServerActionRequest(request, contentType, actionId) {
|
|
|
180
304
|
}
|
|
181
305
|
async function handleProgressiveServerActionRequest(options) {
|
|
182
306
|
if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) return null;
|
|
183
|
-
if (options.request.headers.get("x-action-forwarded")) return createActionNotFoundResponse(null, {
|
|
184
|
-
clearRequestContext: options.clearRequestContext,
|
|
185
|
-
getAndClearPendingCookies: options.getAndClearPendingCookies
|
|
186
|
-
});
|
|
187
307
|
const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);
|
|
188
308
|
if (csrfResponse) return csrfResponse;
|
|
189
309
|
if (parseInt(options.request.headers.get("content-length") || "0", 10) > options.maxActionBodySize) {
|
|
@@ -295,10 +415,6 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
295
415
|
}
|
|
296
416
|
async function handleServerActionRscRequest(options) {
|
|
297
417
|
if (options.request.method.toUpperCase() !== "POST" || !options.actionId) return null;
|
|
298
|
-
if (options.request.headers.get("x-action-forwarded")) return createActionNotFoundResponse(options.actionId, {
|
|
299
|
-
clearRequestContext: options.clearRequestContext,
|
|
300
|
-
getAndClearPendingCookies: options.getAndClearPendingCookies
|
|
301
|
-
});
|
|
302
418
|
const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);
|
|
303
419
|
if (csrfResponse) return csrfResponse;
|
|
304
420
|
if (parseInt(options.request.headers.get("content-length") || "0", 10) > options.maxActionBodySize) {
|
|
@@ -340,6 +456,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
340
456
|
let returnValue;
|
|
341
457
|
let actionRedirect = null;
|
|
342
458
|
let actionStatus = 200;
|
|
459
|
+
const actionWasForwarded = Boolean(options.request.headers.get(ACTION_FORWARDED_HEADER));
|
|
343
460
|
const previousHeadersPhase = options.setHeadersAccessPhase("action");
|
|
344
461
|
try {
|
|
345
462
|
try {
|
|
@@ -378,7 +495,6 @@ async function handleServerActionRscRequest(options) {
|
|
|
378
495
|
const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());
|
|
379
496
|
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
380
497
|
const actionRevalidationKind = resolveActionRevalidationKind(actionPendingCookies.length > 0 || Boolean(actionDraftCookie));
|
|
381
|
-
options.clearRequestContext();
|
|
382
498
|
const redirectHeaders = new Headers({
|
|
383
499
|
"Content-Type": VINEXT_RSC_CONTENT_TYPE,
|
|
384
500
|
Vary: VINEXT_RSC_VARY_HEADER
|
|
@@ -386,27 +502,83 @@ async function handleServerActionRscRequest(options) {
|
|
|
386
502
|
applyEdgeRuntimeHeader(redirectHeaders, options.isEdgeRuntime);
|
|
387
503
|
mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);
|
|
388
504
|
applyRscCompatibilityIdHeader(redirectHeaders);
|
|
389
|
-
|
|
505
|
+
const actionRedirectUrl = applyActionRedirectBasePath(actionRedirect.url, options.basePath ?? "");
|
|
506
|
+
redirectHeaders.set(ACTION_REDIRECT_HEADER, actionRedirectUrl);
|
|
390
507
|
redirectHeaders.set(ACTION_REDIRECT_TYPE_HEADER, actionRedirect.type);
|
|
391
508
|
redirectHeaders.set(ACTION_REDIRECT_STATUS_HEADER, String(actionRedirect.status));
|
|
392
509
|
for (const cookie of actionPendingCookies) redirectHeaders.append("Set-Cookie", cookie);
|
|
393
510
|
if (actionDraftCookie) redirectHeaders.append("Set-Cookie", actionDraftCookie);
|
|
394
511
|
setActionRevalidatedHeader(redirectHeaders, actionRevalidationKind);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
512
|
+
const redirectTarget = resolveInternalActionRedirectTarget(actionRedirectUrl, options.request.url, options.basePath ?? "");
|
|
513
|
+
if (!redirectTarget) {
|
|
514
|
+
options.clearRequestContext();
|
|
515
|
+
return new Response(null, {
|
|
516
|
+
status: 303,
|
|
517
|
+
headers: withoutRscBodyHeaders(redirectHeaders)
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
const targetPathname = stripBasePath(redirectTarget.pathname, options.basePath ?? "");
|
|
521
|
+
const targetMatch = options.matchRoute(targetPathname);
|
|
522
|
+
if (!targetMatch || !canRenderActionRedirectTarget(targetMatch.route)) {
|
|
523
|
+
options.clearRequestContext();
|
|
524
|
+
return new Response(null, {
|
|
525
|
+
status: 303,
|
|
526
|
+
headers: withoutRscBodyHeaders(redirectHeaders)
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
const currentMatch = options.matchRoute(options.cleanPathname);
|
|
530
|
+
const redirectRenderRequest = createActionRedirectRenderRequest({
|
|
531
|
+
pendingCookies: [...actionPendingCookies, ...actionDraftCookie ? [actionDraftCookie] : []],
|
|
532
|
+
request: options.request,
|
|
533
|
+
url: redirectTarget
|
|
398
534
|
});
|
|
535
|
+
setHeadersContext(headersContextFromRequest(redirectRenderRequest));
|
|
536
|
+
options.setNavigationContext({
|
|
537
|
+
pathname: targetPathname,
|
|
538
|
+
searchParams: redirectTarget.searchParams,
|
|
539
|
+
params: targetMatch.params
|
|
540
|
+
});
|
|
541
|
+
setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(targetMatch.route) ?? null);
|
|
542
|
+
setCurrentFetchSoftTags(buildServerActionPageTags(targetMatch.route, targetPathname));
|
|
543
|
+
const element = options.buildPageElement({
|
|
544
|
+
cleanPathname: targetPathname,
|
|
545
|
+
interceptOpts: void 0,
|
|
546
|
+
isRscRequest: true,
|
|
547
|
+
mountedSlotsHeader: null,
|
|
548
|
+
params: targetMatch.params,
|
|
549
|
+
request: redirectRenderRequest,
|
|
550
|
+
route: targetMatch.route,
|
|
551
|
+
searchParams: redirectTarget.searchParams,
|
|
552
|
+
renderMode: APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI
|
|
553
|
+
});
|
|
554
|
+
const onRenderError = options.createRscOnErrorHandler(redirectRenderRequest, targetPathname, targetMatch.route.pattern);
|
|
555
|
+
return createServerActionRscResponse(await options.renderToReadableStream({
|
|
556
|
+
root: element,
|
|
557
|
+
returnValue
|
|
558
|
+
}, {
|
|
559
|
+
temporaryReferences,
|
|
560
|
+
onError: onRenderError
|
|
561
|
+
}), {
|
|
562
|
+
status: shouldUseForwardedActionRedirectStatus({
|
|
563
|
+
actionWasForwarded,
|
|
564
|
+
currentPathname: options.cleanPathname,
|
|
565
|
+
currentRoute: currentMatch?.route ?? null,
|
|
566
|
+
resolveRouteRuntime: options.resolveRouteRuntime,
|
|
567
|
+
targetPathname,
|
|
568
|
+
targetRoute: targetMatch.route
|
|
569
|
+
}) ? 200 : 303,
|
|
570
|
+
headers: redirectHeaders
|
|
571
|
+
}, options.clearRequestContext);
|
|
399
572
|
}
|
|
400
573
|
const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());
|
|
401
574
|
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
402
575
|
const actionRevalidationKind = resolveActionRevalidationKind(actionPendingCookies.length > 0 || Boolean(actionDraftCookie));
|
|
403
|
-
if (actionRevalidationKind === ACTION_DID_NOT_REVALIDATE) {
|
|
576
|
+
if (actionWasForwarded || actionStatus === 200 && actionRevalidationKind === ACTION_DID_NOT_REVALIDATE) {
|
|
404
577
|
const onRenderError = options.createRscOnErrorHandler(options.request, options.cleanPathname, options.cleanPathname);
|
|
405
578
|
const rscStream = await options.renderToReadableStream({ returnValue }, {
|
|
406
579
|
temporaryReferences,
|
|
407
580
|
onError: onRenderError
|
|
408
581
|
});
|
|
409
|
-
options.clearRequestContext();
|
|
410
582
|
const actionHeaders = new Headers({
|
|
411
583
|
"Content-Type": VINEXT_RSC_CONTENT_TYPE,
|
|
412
584
|
Vary: VINEXT_RSC_VARY_HEADER
|
|
@@ -414,10 +586,13 @@ async function handleServerActionRscRequest(options) {
|
|
|
414
586
|
applyEdgeRuntimeHeader(actionHeaders, options.isEdgeRuntime);
|
|
415
587
|
mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);
|
|
416
588
|
applyRscCompatibilityIdHeader(actionHeaders);
|
|
417
|
-
|
|
589
|
+
for (const cookie of actionPendingCookies) actionHeaders.append("Set-Cookie", cookie);
|
|
590
|
+
if (actionDraftCookie) actionHeaders.append("Set-Cookie", actionDraftCookie);
|
|
591
|
+
setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);
|
|
592
|
+
return createServerActionRscResponse(rscStream, {
|
|
418
593
|
status: options.middlewareStatus ?? actionStatus,
|
|
419
594
|
headers: actionHeaders
|
|
420
|
-
});
|
|
595
|
+
}, options.clearRequestContext);
|
|
421
596
|
}
|
|
422
597
|
const match = options.matchRoute(options.cleanPathname);
|
|
423
598
|
let element;
|
|
@@ -440,6 +615,7 @@ async function handleServerActionRscRequest(options) {
|
|
|
440
615
|
params: actionRerenderTarget.navigationParams
|
|
441
616
|
});
|
|
442
617
|
setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(actionRerenderTarget.route) ?? null);
|
|
618
|
+
setCurrentFetchSoftTags(buildServerActionPageTags(actionRerenderTarget.route, options.cleanPathname));
|
|
443
619
|
element = options.buildPageElement({
|
|
444
620
|
cleanPathname: options.cleanPathname,
|
|
445
621
|
interceptOpts: actionRerenderTarget.interceptOpts,
|
|
@@ -472,10 +648,10 @@ async function handleServerActionRscRequest(options) {
|
|
|
472
648
|
mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);
|
|
473
649
|
applyRscCompatibilityIdHeader(actionHeaders);
|
|
474
650
|
setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);
|
|
475
|
-
const actionResponse =
|
|
651
|
+
const actionResponse = createServerActionRscResponse(rscStream, {
|
|
476
652
|
status: options.middlewareStatus ?? actionStatus,
|
|
477
653
|
headers: actionHeaders
|
|
478
|
-
});
|
|
654
|
+
}, options.clearRequestContext);
|
|
479
655
|
if (actionPendingCookies.length > 0 || actionDraftCookie) {
|
|
480
656
|
for (const cookie of actionPendingCookies) actionResponse.headers.append("Set-Cookie", cookie);
|
|
481
657
|
if (actionDraftCookie) actionResponse.headers.append("Set-Cookie", actionDraftCookie);
|