vinext 0.0.53 → 0.0.54
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/dist/build/inline-css.d.ts +7 -0
- package/dist/build/inline-css.js +50 -0
- package/dist/build/inline-css.js.map +1 -0
- package/dist/build/prerender.js +2 -1
- package/dist/build/prerender.js.map +1 -1
- package/dist/check.js +4 -0
- package/dist/check.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +2 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/client/window-next.d.ts +7 -0
- package/dist/client/window-next.js.map +1 -1
- package/dist/config/next-config.d.ts +83 -1
- package/dist/config/next-config.js +131 -2
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +13 -0
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +11 -1
- package/dist/entries/app-browser-entry.js +16 -6
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +8 -1
- package/dist/entries/app-rsc-entry.js +18 -5
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +21 -1
- package/dist/entries/app-rsc-manifest.js +6 -4
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +4 -1
- package/dist/entries/pages-client-entry.js +18 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +82 -4
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +1 -10
- package/dist/entries/runtime-entry-module.js +2 -12
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +63 -5
- package/dist/index.js.map +1 -1
- package/dist/plugins/remove-console.d.ts +16 -0
- package/dist/plugins/remove-console.js +176 -0
- package/dist/plugins/remove-console.js.map +1 -0
- package/dist/routing/app-route-graph.d.ts +24 -1
- package/dist/routing/app-route-graph.js +52 -4
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -2
- package/dist/routing/app-router.js +2 -2
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +21 -1
- package/dist/routing/file-matcher.js +39 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +1 -1
- package/dist/routing/pages-router.js +10 -3
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-browser-entry.js +25 -16
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-navigation-controller.d.ts +2 -0
- package/dist/server/app-browser-navigation-controller.js +4 -0
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +13 -4
- package/dist/server/app-elements-wire.js +10 -1
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +15 -5
- package/dist/server/app-fallback-renderer.js +10 -4
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-inline-css-client.d.ts +7 -0
- package/dist/server/app-inline-css-client.js +37 -0
- package/dist/server/app-inline-css-client.js.map +1 -0
- package/dist/server/app-page-boundary.d.ts +21 -1
- package/dist/server/app-page-boundary.js +28 -3
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +7 -3
- package/dist/server/app-page-cache.js +7 -7
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +126 -79
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.js +12 -28
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-render-identity.d.ts +22 -0
- package/dist/server/app-page-render-identity.js +42 -0
- package/dist/server/app-page-render-identity.js.map +1 -0
- package/dist/server/app-page-render.d.ts +8 -1
- package/dist/server/app-page-render.js +4 -1
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +6 -3
- package/dist/server/app-page-request.js +5 -2
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +15 -0
- package/dist/server/app-page-route-wiring.js +7 -5
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +11 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-response.js +37 -5
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +14 -3
- package/dist/server/app-rsc-handler.js +45 -5
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +2 -1
- package/dist/server/app-rsc-request-normalization.js +3 -2
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +21 -3
- package/dist/server/app-server-action-execution.js +42 -7
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +22 -7
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-error-meta.js +3 -3
- package/dist/server/app-ssr-error-meta.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +2 -1
- package/dist/server/app-ssr-stream.js +176 -31
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/client-trace-metadata.d.ts +31 -0
- package/dist/server/client-trace-metadata.js +83 -0
- package/dist/server/client-trace-metadata.js.map +1 -0
- package/dist/server/cookie-utils.d.ts +13 -0
- package/dist/server/cookie-utils.js +20 -0
- package/dist/server/cookie-utils.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -1
- package/dist/server/dev-server.js +34 -5
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/html.d.ts +2 -1
- package/dist/server/html.js +6 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/isr-cache.d.ts +7 -5
- package/dist/server/isr-cache.js +17 -6
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.js +1 -2
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/pages-document-initial-props.d.ts +7 -0
- package/dist/server/pages-document-initial-props.js +14 -0
- package/dist/server/pages-document-initial-props.js.map +1 -0
- package/dist/server/pages-page-data.js +3 -0
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-method.d.ts +48 -0
- package/dist/server/pages-page-method.js +19 -0
- package/dist/server/pages-page-method.js.map +1 -0
- package/dist/server/pages-page-response.d.ts +6 -0
- package/dist/server/pages-page-response.js +10 -3
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/pages-serializable-props.d.ts +25 -0
- package/dist/server/pages-serializable-props.js +69 -0
- package/dist/server/pages-serializable-props.js.map +1 -0
- package/dist/server/prod-server.js +3 -0
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/server-action-not-found.js +3 -2
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/static-file-cache.js +2 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/shims/app-router-scroll-state.d.ts +4 -2
- package/dist/shims/app-router-scroll-state.js +16 -3
- package/dist/shims/app-router-scroll-state.js.map +1 -1
- package/dist/shims/app-router-scroll.d.ts +16 -2
- package/dist/shims/app-router-scroll.js +18 -3
- package/dist/shims/app-router-scroll.js.map +1 -1
- package/dist/shims/cache.d.ts +6 -0
- package/dist/shims/cache.js +7 -0
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/error.js +3 -0
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/headers.d.ts +7 -0
- package/dist/shims/headers.js +9 -1
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/internal/app-route-detection.d.ts +37 -0
- package/dist/shims/internal/app-route-detection.js +69 -0
- package/dist/shims/internal/app-route-detection.js.map +1 -0
- package/dist/shims/link.d.ts +18 -2
- package/dist/shims/link.js +70 -6
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +7 -6
- package/dist/shims/metadata.js +9 -5
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +1 -2
- package/dist/shims/navigation.js +63 -12
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts +5 -0
- package/dist/shims/router.js +14 -4
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +11 -1
- package/dist/shims/script.js +75 -6
- package/dist/shims/script.js.map +1 -1
- package/dist/utils/path.d.ts +13 -0
- package/dist/utils/path.js +16 -0
- package/dist/utils/path.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-response.js","names":[],"sources":["../../src/server/app-page-response.ts"],"sourcesContent":["import {\n buildRevalidateCacheControl,\n NO_STORE_CACHE_CONTROL,\n STATIC_CACHE_CONTROL,\n} from \"./cache-control.js\";\nimport {\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_PARAMS_HEADER,\n VINEXT_TIMING_HEADER,\n} from \"./headers.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport {\n VINEXT_RSC_CONTENT_TYPE,\n VINEXT_RSC_VARY_HEADER,\n applyRscCompatibilityIdHeader,\n} from \"./app-rsc-cache-busting.js\";\n\nexport type AppPageMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\nexport type AppPageResponseTiming = {\n compileEnd?: number;\n handlerStart: number;\n renderEnd?: number;\n responseKind: \"html\" | \"rsc\";\n};\n\ntype AppPageResponsePolicy = {\n cacheControl?: string;\n cacheState?: \"MISS\" | \"STATIC\";\n};\n\ntype ResolveAppPageResponsePolicyBaseOptions = {\n isDraftMode: boolean;\n isDynamicError: boolean;\n isForceDynamic: boolean;\n isForceStatic: boolean;\n isProduction: boolean;\n expireSeconds?: number;\n revalidateSeconds: number | null;\n};\n\ntype ResolveAppPageRscResponsePolicyOptions = {\n dynamicUsedDuringBuild: boolean;\n} & ResolveAppPageResponsePolicyBaseOptions;\n\ntype ResolveAppPageHtmlResponsePolicyOptions = {\n dynamicUsedDuringRender: boolean;\n isProgressiveActionRender?: boolean;\n hasScriptNonce: boolean;\n} & ResolveAppPageResponsePolicyBaseOptions;\n\ntype AppPageHtmlResponsePolicy = {\n shouldWriteToCache: boolean;\n} & AppPageResponsePolicy;\n\ntype BuildAppPageRscResponseOptions = {\n isEdgeRuntime?: boolean;\n middlewareContext: AppPageMiddlewareContext;\n mountedSlotsHeader?: string | null;\n params?: Record<string, unknown>;\n policy: AppPageResponsePolicy;\n timing?: AppPageResponseTiming;\n};\n\ntype BuildAppPageHtmlResponseOptions = {\n draftCookie?: string | null;\n fontLinkHeader?: string;\n isEdgeRuntime?: boolean;\n middlewareContext: AppPageMiddlewareContext;\n policy: AppPageResponsePolicy;\n timing?: AppPageResponseTiming;\n};\n\nfunction applyTimingHeader(headers: Headers, timing?: AppPageResponseTiming): void {\n if (!timing) {\n return;\n }\n\n const handlerStart = Math.round(timing.handlerStart);\n const compileMs =\n timing.compileEnd !== undefined ? Math.round(timing.compileEnd - timing.handlerStart) : -1;\n const renderMs =\n timing.responseKind === \"html\" &&\n timing.renderEnd !== undefined &&\n timing.compileEnd !== undefined\n ? Math.round(timing.renderEnd - timing.compileEnd)\n : -1;\n\n headers.set(VINEXT_TIMING_HEADER, `${handlerStart},${compileMs},${renderMs}`);\n}\n\nexport function resolveAppPageRscResponsePolicy(\n options: ResolveAppPageRscResponsePolicyOptions,\n): AppPageResponsePolicy {\n if (options.isDraftMode) {\n return { cacheControl: NO_STORE_CACHE_CONTROL };\n }\n\n if (options.isForceDynamic || options.dynamicUsedDuringBuild) {\n return { cacheControl: NO_STORE_CACHE_CONTROL };\n }\n\n // revalidate = 0 means \"always dynamic, never cache\" — equivalent to\n // force-dynamic for caching purposes. Must be checked before the\n // isForceStatic/isDynamicError branch below, which uses !revalidateSeconds\n // and would incorrectly catch 0 as a falsy value.\n if (options.revalidateSeconds === 0) {\n return { cacheControl: NO_STORE_CACHE_CONTROL };\n }\n\n if (\n ((options.isForceStatic || options.isDynamicError) && !options.revalidateSeconds) ||\n options.revalidateSeconds === Infinity\n ) {\n return {\n cacheControl: STATIC_CACHE_CONTROL,\n cacheState: \"STATIC\",\n };\n }\n\n if (options.revalidateSeconds) {\n return {\n cacheControl: buildRevalidateCacheControl(options.revalidateSeconds, options.expireSeconds),\n // Emit MISS as part of the initial RSC response shape rather than bolting\n // it on later in the cache-write block so response construction stays\n // centralized in this helper. This matches the eventual write path: the\n // first ISR-eligible production response is a cache miss.\n cacheState: options.isProduction ? \"MISS\" : undefined,\n };\n }\n\n return {};\n}\n\nexport function resolveAppPageHtmlResponsePolicy(\n options: ResolveAppPageHtmlResponsePolicyOptions,\n): AppPageHtmlResponsePolicy {\n if (options.isDraftMode) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (options.isForceDynamic) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (options.hasScriptNonce) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (options.isProgressiveActionRender) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n // revalidate = 0 means \"always dynamic, never cache\" — equivalent to\n // force-dynamic for caching purposes. Must be checked before the\n // isForceStatic/isDynamicError branch below, which matches revalidateSeconds\n // === 0 and would incorrectly return a static Cache-Control.\n if (options.revalidateSeconds === 0) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if ((options.isForceStatic || options.isDynamicError) && options.revalidateSeconds === null) {\n return {\n cacheControl: STATIC_CACHE_CONTROL,\n cacheState: \"STATIC\",\n shouldWriteToCache: false,\n };\n }\n\n if (options.dynamicUsedDuringRender) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (\n options.revalidateSeconds !== null &&\n options.revalidateSeconds > 0 &&\n options.revalidateSeconds !== Infinity\n ) {\n return {\n cacheControl: buildRevalidateCacheControl(options.revalidateSeconds, options.expireSeconds),\n cacheState: options.isProduction ? \"MISS\" : undefined,\n shouldWriteToCache: options.isProduction,\n };\n }\n\n if (options.revalidateSeconds === Infinity) {\n return {\n cacheControl: STATIC_CACHE_CONTROL,\n cacheState: \"STATIC\",\n shouldWriteToCache: false,\n };\n }\n\n return { shouldWriteToCache: false };\n}\n\nexport { mergeMiddlewareResponseHeaders };\n\n/**\n * Mirror Next.js' edge-runtime marker (set in edge-ssr-app.ts). Only routes\n * whose resolved segment config is `runtime = \"edge\"` should advertise it —\n * nodejs-runtime routes must not, otherwise downstream consumers can't tell\n * the configured runtime from the response. Centralized so every response\n * construction site can opt in without re-deriving the header name.\n */\nexport function applyEdgeRuntimeHeader(headers: Headers, isEdgeRuntime: boolean | undefined): void {\n if (isEdgeRuntime) {\n headers.set(\"x-edge-runtime\", \"1\");\n }\n}\n\nexport function buildAppPageRscResponse(\n body: ReadableStream,\n options: BuildAppPageRscResponseOptions,\n): Response {\n const headers = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n\n applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);\n\n if (options.params && Object.keys(options.params).length > 0) {\n // encodeURIComponent so non-ASCII params (e.g. Korean slugs) survive the\n // HTTP ByteString constraint — Headers.set() rejects chars above U+00FF.\n headers.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(options.params)));\n }\n if (options.mountedSlotsHeader) {\n headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);\n }\n if (options.policy.cacheControl) {\n headers.set(\"Cache-Control\", options.policy.cacheControl);\n }\n if (options.policy.cacheState) {\n setCacheStateHeaders(headers, options.policy.cacheState);\n }\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);\n applyRscCompatibilityIdHeader(headers);\n\n applyTimingHeader(headers, options.timing);\n\n return new Response(body, {\n status: options.middlewareContext.status ?? 200,\n headers,\n });\n}\n\nexport function buildAppPageHtmlResponse(\n body: ReadableStream,\n options: BuildAppPageHtmlResponseOptions,\n): Response {\n const headers = new Headers({\n \"Content-Type\": \"text/html; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n\n applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);\n\n if (options.policy.cacheControl) {\n headers.set(\"Cache-Control\", options.policy.cacheControl);\n }\n if (options.policy.cacheState) {\n setCacheStateHeaders(headers, options.policy.cacheState);\n }\n if (options.draftCookie) {\n headers.append(\"Set-Cookie\", options.draftCookie);\n }\n if (options.fontLinkHeader) {\n headers.set(\"Link\", options.fontLinkHeader);\n }\n\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);\n\n applyTimingHeader(headers, options.timing);\n\n return new Response(body, {\n status: options.middlewareContext.status ?? 200,\n headers,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-page-response.js","names":[],"sources":["../../src/server/app-page-response.ts"],"sourcesContent":["import {\n buildRevalidateCacheControl,\n NO_STORE_CACHE_CONTROL,\n STATIC_CACHE_CONTROL,\n} from \"./cache-control.js\";\nimport {\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_PARAMS_HEADER,\n VINEXT_TIMING_HEADER,\n} from \"./headers.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport {\n VINEXT_RSC_CONTENT_TYPE,\n VINEXT_RSC_VARY_HEADER,\n applyRscCompatibilityIdHeader,\n} from \"./app-rsc-cache-busting.js\";\n\nexport type AppPageMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\nexport type AppPageResponseTiming = {\n compileEnd?: number;\n handlerStart: number;\n renderEnd?: number;\n responseKind: \"html\" | \"rsc\";\n};\n\ntype AppPageResponsePolicy = {\n cacheControl?: string;\n cacheState?: \"MISS\" | \"STATIC\";\n};\n\ntype ResolveAppPageResponsePolicyBaseOptions = {\n isDraftMode: boolean;\n isDynamicError: boolean;\n isForceDynamic: boolean;\n isForceStatic: boolean;\n isProduction: boolean;\n expireSeconds?: number;\n revalidateSeconds: number | null;\n};\n\ntype ResolveAppPageRscResponsePolicyOptions = {\n dynamicUsedDuringBuild: boolean;\n} & ResolveAppPageResponsePolicyBaseOptions;\n\ntype ResolveAppPageHtmlResponsePolicyOptions = {\n dynamicUsedDuringRender: boolean;\n isProgressiveActionRender?: boolean;\n hasScriptNonce: boolean;\n} & ResolveAppPageResponsePolicyBaseOptions;\n\ntype AppPageHtmlResponsePolicy = {\n shouldWriteToCache: boolean;\n} & AppPageResponsePolicy;\n\ntype BuildAppPageRscResponseOptions = {\n isEdgeRuntime?: boolean;\n middlewareContext: AppPageMiddlewareContext;\n mountedSlotsHeader?: string | null;\n params?: Record<string, unknown>;\n policy: AppPageResponsePolicy;\n timing?: AppPageResponseTiming;\n};\n\ntype BuildAppPageHtmlResponseOptions = {\n draftCookie?: string | null;\n fontLinkHeader?: string;\n isEdgeRuntime?: boolean;\n middlewareContext: AppPageMiddlewareContext;\n policy: AppPageResponsePolicy;\n timing?: AppPageResponseTiming;\n};\n\nfunction applyTimingHeader(headers: Headers, timing?: AppPageResponseTiming): void {\n if (!timing) {\n return;\n }\n\n const handlerStart = Math.round(timing.handlerStart);\n const compileMs =\n timing.compileEnd !== undefined ? Math.round(timing.compileEnd - timing.handlerStart) : -1;\n const renderMs =\n timing.responseKind === \"html\" &&\n timing.renderEnd !== undefined &&\n timing.compileEnd !== undefined\n ? Math.round(timing.renderEnd - timing.compileEnd)\n : -1;\n\n headers.set(VINEXT_TIMING_HEADER, `${handlerStart},${compileMs},${renderMs}`);\n}\n\nexport function resolveAppPageRscResponsePolicy(\n options: ResolveAppPageRscResponsePolicyOptions,\n): AppPageResponsePolicy {\n if (options.isDraftMode) {\n return { cacheControl: NO_STORE_CACHE_CONTROL };\n }\n\n if (options.isForceDynamic || options.dynamicUsedDuringBuild) {\n return { cacheControl: NO_STORE_CACHE_CONTROL };\n }\n\n // revalidate = 0 means \"always dynamic, never cache\" — equivalent to\n // force-dynamic for caching purposes. Must be checked before the\n // isForceStatic/isDynamicError branch below, which uses !revalidateSeconds\n // and would incorrectly catch 0 as a falsy value.\n if (options.revalidateSeconds === 0) {\n return { cacheControl: NO_STORE_CACHE_CONTROL };\n }\n\n if (\n ((options.isForceStatic || options.isDynamicError) && !options.revalidateSeconds) ||\n options.revalidateSeconds === Infinity\n ) {\n return {\n cacheControl: STATIC_CACHE_CONTROL,\n cacheState: \"STATIC\",\n };\n }\n\n if (options.revalidateSeconds) {\n return {\n cacheControl: buildRevalidateCacheControl(options.revalidateSeconds, options.expireSeconds),\n // Emit MISS as part of the initial RSC response shape rather than bolting\n // it on later in the cache-write block so response construction stays\n // centralized in this helper. This matches the eventual write path: the\n // first ISR-eligible production response is a cache miss.\n cacheState: options.isProduction ? \"MISS\" : undefined,\n };\n }\n\n return {};\n}\n\nexport function resolveAppPageHtmlResponsePolicy(\n options: ResolveAppPageHtmlResponsePolicyOptions,\n): AppPageHtmlResponsePolicy {\n if (options.isDraftMode) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (options.isForceDynamic) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (options.hasScriptNonce) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (options.isProgressiveActionRender) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n // revalidate = 0 means \"always dynamic, never cache\" — equivalent to\n // force-dynamic for caching purposes. Must be checked before the\n // isForceStatic/isDynamicError branch below, which matches revalidateSeconds\n // === 0 and would incorrectly return a static Cache-Control.\n if (options.revalidateSeconds === 0) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if ((options.isForceStatic || options.isDynamicError) && options.revalidateSeconds === null) {\n return {\n cacheControl: STATIC_CACHE_CONTROL,\n cacheState: \"STATIC\",\n shouldWriteToCache: false,\n };\n }\n\n if (options.dynamicUsedDuringRender) {\n return {\n cacheControl: NO_STORE_CACHE_CONTROL,\n shouldWriteToCache: false,\n };\n }\n\n if (\n options.revalidateSeconds !== null &&\n options.revalidateSeconds > 0 &&\n options.revalidateSeconds !== Infinity\n ) {\n return {\n cacheControl: buildRevalidateCacheControl(options.revalidateSeconds, options.expireSeconds),\n cacheState: options.isProduction ? \"MISS\" : undefined,\n shouldWriteToCache: options.isProduction,\n };\n }\n\n if (options.revalidateSeconds === Infinity) {\n // `revalidate = false` / `revalidate = Infinity` ask for indefinite caching.\n // The downstream Cache-Control header remains STATIC (1y s-maxage), but we\n // also write to the ISR cache so repeated requests inside the same vinext\n // process return identical bytes instead of re-rendering on every hit.\n // This matches Next.js: indefinite-revalidate pages cache their rendered\n // output and only re-render when their tags are explicitly invalidated.\n return {\n cacheControl: STATIC_CACHE_CONTROL,\n cacheState: options.isProduction ? \"MISS\" : \"STATIC\",\n shouldWriteToCache: options.isProduction,\n };\n }\n\n return { shouldWriteToCache: false };\n}\n\nexport { mergeMiddlewareResponseHeaders };\n\n/**\n * Mirror Next.js' edge-runtime marker (set in edge-ssr-app.ts). Only routes\n * whose resolved segment config is `runtime = \"edge\"` should advertise it —\n * nodejs-runtime routes must not, otherwise downstream consumers can't tell\n * the configured runtime from the response. Centralized so every response\n * construction site can opt in without re-deriving the header name.\n */\nexport function applyEdgeRuntimeHeader(headers: Headers, isEdgeRuntime: boolean | undefined): void {\n if (isEdgeRuntime) {\n headers.set(\"x-edge-runtime\", \"1\");\n }\n}\n\nexport function buildAppPageRscResponse(\n body: ReadableStream,\n options: BuildAppPageRscResponseOptions,\n): Response {\n const headers = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n\n applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);\n\n if (options.params && Object.keys(options.params).length > 0) {\n // encodeURIComponent so non-ASCII params (e.g. Korean slugs) survive the\n // HTTP ByteString constraint — Headers.set() rejects chars above U+00FF.\n headers.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(options.params)));\n }\n if (options.mountedSlotsHeader) {\n headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);\n }\n if (options.policy.cacheControl) {\n headers.set(\"Cache-Control\", options.policy.cacheControl);\n }\n if (options.policy.cacheState) {\n setCacheStateHeaders(headers, options.policy.cacheState);\n }\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);\n applyRscCompatibilityIdHeader(headers);\n\n applyTimingHeader(headers, options.timing);\n\n return new Response(body, {\n status: options.middlewareContext.status ?? 200,\n headers,\n });\n}\n\nexport function buildAppPageHtmlResponse(\n body: ReadableStream,\n options: BuildAppPageHtmlResponseOptions,\n): Response {\n const headers = new Headers({\n \"Content-Type\": \"text/html; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n\n applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);\n\n if (options.policy.cacheControl) {\n headers.set(\"Cache-Control\", options.policy.cacheControl);\n }\n if (options.policy.cacheState) {\n setCacheStateHeaders(headers, options.policy.cacheState);\n }\n if (options.draftCookie) {\n headers.append(\"Set-Cookie\", options.draftCookie);\n }\n if (options.fontLinkHeader) {\n headers.set(\"Link\", options.fontLinkHeader);\n }\n\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);\n\n applyTimingHeader(headers, options.timing);\n\n return new Response(body, {\n status: options.middlewareContext.status ?? 200,\n headers,\n });\n}\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { AppElements, AppElementsInterception } from "./app-elements-wire.js";
|
|
|
3
3
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
4
4
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
5
5
|
import { Metadata, Viewport } from "../shims/metadata.js";
|
|
6
|
+
import { AppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
6
7
|
import { resolveAppPageChildSegments } from "./app-page-segment-state.js";
|
|
7
8
|
import { ComponentType, ReactNode } from "react";
|
|
8
9
|
|
|
@@ -63,6 +64,19 @@ type AppPageRouteWiringRoute<TModule extends AppPageModule = AppPageModule, TErr
|
|
|
63
64
|
* Keyed by stable slot id (name + owner path), not necessarily the slot prop name.
|
|
64
65
|
*/
|
|
65
66
|
slots?: Readonly<Record<string, AppPageRouteWiringSlot<TModule, TErrorModule>>> | null;
|
|
67
|
+
/**
|
|
68
|
+
* Static sibling segment names at each dynamic URL level for this route. Used
|
|
69
|
+
* by the client router to determine if a cached prefetch of the dynamic
|
|
70
|
+
* route can be reused when navigating to a static sibling URL.
|
|
71
|
+
*
|
|
72
|
+
* Mirrors Next.js's `staticSiblings` tuple element on the loader-tree
|
|
73
|
+
* dynamic segments — see `.nextjs-ref/packages/next/src/shared/lib/app-router-types.ts`
|
|
74
|
+
* (DynamicSegmentTuple) and the loader emit in
|
|
75
|
+
* `packages/next/src/build/webpack/loaders/next-app-loader/index.ts`.
|
|
76
|
+
*
|
|
77
|
+
* Issue: https://github.com/cloudflare/vinext/issues/1525
|
|
78
|
+
*/
|
|
79
|
+
staticSiblings?: readonly string[] | null;
|
|
66
80
|
templateTreePositions?: readonly number[] | null;
|
|
67
81
|
templates?: readonly (TModule | null | undefined)[] | null;
|
|
68
82
|
};
|
|
@@ -107,6 +121,7 @@ type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule,
|
|
|
107
121
|
interceptionContext?: string | null;
|
|
108
122
|
isRscRequest?: boolean;
|
|
109
123
|
mountedSlotIds?: ReadonlySet<string> | null;
|
|
124
|
+
renderIdentity?: AppPageRenderIdentity;
|
|
110
125
|
renderMode?: AppRscRenderMode;
|
|
111
126
|
routePath: string;
|
|
112
127
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
1
|
+
import { APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
2
2
|
import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
|
|
3
3
|
import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY } from "./app-elements.js";
|
|
4
4
|
import { ErrorBoundary, ForbiddenBoundary, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
@@ -119,12 +119,13 @@ function createAppPageRouteBodyMetadata(metadata, pathname, metadataPlacement) {
|
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
function buildAppPageElements(options) {
|
|
122
|
-
const
|
|
122
|
+
const renderIdentity = options.renderIdentity;
|
|
123
|
+
const interceptionContext = renderIdentity?.interceptionContext ?? options.interceptionContext ?? null;
|
|
123
124
|
const renderMode = options.renderMode ?? "navigation";
|
|
124
125
|
const routeSegments = options.route.routeSegments ?? [];
|
|
125
126
|
const routeResetKey = resolveAppPageRouteStateKey(routeSegments, options.matchedParams);
|
|
126
|
-
const routeId = AppElementsWire.encodeRouteId(options.routePath, interceptionContext);
|
|
127
|
-
const pageId = AppElementsWire.encodePageId(options.routePath, interceptionContext);
|
|
127
|
+
const routeId = renderIdentity?.routeId ?? AppElementsWire.encodeRouteId(options.routePath, interceptionContext);
|
|
128
|
+
const pageId = renderIdentity?.pageId ?? AppElementsWire.encodePageId(options.routePath, interceptionContext);
|
|
128
129
|
const layoutEntries = createAppPageLayoutEntries(options.route);
|
|
129
130
|
const templateEntries = createAppPageTemplateEntries(options.route);
|
|
130
131
|
const errorEntries = createAppPageErrorEntries(options.route);
|
|
@@ -160,13 +161,14 @@ function buildAppPageElements(options) {
|
|
|
160
161
|
if (slotKey === slotName || (slotNameCounts.get(slotName) ?? 0) === 1) return options.slotOverrides?.[slotName];
|
|
161
162
|
};
|
|
162
163
|
const elements = { ...AppElementsWire.createMetadataEntries({
|
|
163
|
-
interception: options.interception ?? null,
|
|
164
|
+
interception: renderIdentity?.interception ?? options.interception ?? null,
|
|
164
165
|
interceptionContext,
|
|
165
166
|
layoutIds: options.route.ids?.layouts ?? layoutEntries.map((entry) => entry.id),
|
|
166
167
|
rootLayoutTreePath,
|
|
167
168
|
routeId,
|
|
168
169
|
slotBindings: createAppPageSlotBindings(options.route, layoutEntries, resolveSlotOverride)
|
|
169
170
|
}) };
|
|
171
|
+
if (options.route.staticSiblings && options.route.staticSiblings.length > 0) elements[APP_STATIC_SIBLINGS_KEY] = options.route.staticSiblings;
|
|
170
172
|
const getEffectiveSlotParams = (slotKey, slotName) => resolveSlotOverride(slotKey, slotName)?.params ?? options.matchedParams;
|
|
171
173
|
for (const treePosition of orderedTreePositions) {
|
|
172
174
|
const layoutIndex = layoutIndicesByTreePosition.get(treePosition);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-route-wiring.js","names":["Children","SlotComponent","InterceptLayoutComponent","SlotLayoutComponent","SlotLoadingComponent","RouteLoadingComponent","NotFoundComponent","ForbiddenComponent","UnauthorizedComponent","LayoutNotFoundComponent","LayoutForbiddenComponent","LayoutUnauthorizedComponent"],"sources":["../../src/server/app-page-route-wiring.tsx"],"sourcesContent":["import { Suspense, type ComponentType, type ReactNode } from \"react\";\nimport {\n AppElementsWire,\n APP_PREFETCH_LOADING_SHELL_MARKER_KEY,\n normalizeAppElementsSlotBindings,\n type AppElements,\n type AppElementsInterception,\n type AppElementsSlotBinding,\n} from \"./app-elements.js\";\nimport {\n ErrorBoundary,\n ForbiddenBoundary,\n NotFoundBoundary,\n RedirectBoundary,\n UnauthorizedBoundary,\n} from \"vinext/shims/error-boundary\";\nimport { AppRouterScrollTarget } from \"vinext/shims/app-router-scroll\";\nimport type { AppRouteSemanticIds } from \"../routing/app-route-graph.js\";\nimport { LayoutSegmentProvider } from \"vinext/shims/layout-segment-context\";\nimport {\n MetadataHead,\n ViewportHead,\n renderMetadataToHtml,\n type Metadata,\n type Viewport,\n} from \"vinext/shims/metadata\";\nimport { Children, ParallelSlot, Slot } from \"vinext/shims/slot\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport {\n createAppRenderDependency,\n renderAfterAppDependencies,\n renderWithAppDependencyBarrier,\n type AppRenderDependency,\n} from \"./app-render-dependency.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\nimport {\n APP_RSC_RENDER_MODE_NAVIGATION,\n APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL,\n shouldSuppressLoadingBoundaries,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.js\";\nimport {\n resolveAppPageChildSegments,\n resolveAppPageRouteStateKey,\n resolveAppPageSegmentStateKey,\n} from \"./app-page-segment-state.js\";\n\nexport { resolveAppPageChildSegments } from \"./app-page-segment-state.js\";\n\ntype AppPageComponentProps = {\n children?: ReactNode;\n error?: unknown;\n params?: unknown;\n reset?: () => void;\n} & Record<string, unknown>;\n\ntype AppPageComponent = ComponentType<AppPageComponentProps>;\ntype AppPageErrorComponent = ComponentType<{ error: unknown; reset: () => void }>;\n\nexport type AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\n\nexport type AppPageErrorModule = Record<string, unknown> & {\n default?: AppPageErrorComponent | null | undefined;\n};\n\ntype AppPageRouteWiringSlot<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n /** Graph-owned semantic slot identity. */\n id?: string | null;\n /** Slot prop name passed to the owning layout (e.g. \"modal\" from @modal). */\n name: string;\n default?: TModule | null;\n error?: TErrorModule | null;\n layout?: TModule | null;\n layoutIndex: number;\n loading?: TModule | null;\n page?: TModule | null;\n routeSegments?: readonly string[] | null;\n /**\n * Full URL pattern parts for the slot's mirrored sub-page. Set when the\n * slot's params may differ from the route's (e.g. inherited slot whose\n * dynamic markers have different names than the route's). The runtime\n * matches the request URL against these parts to extract slot params.\n */\n slotPatternParts?: readonly string[] | null;\n /** Param names captured by `slotPatternParts`, in order. */\n slotParamNames?: readonly string[] | null;\n};\n\nexport type AppPageRouteWiringRoute<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n ids?: AppRouteSemanticIds | null;\n error?: TErrorModule | null;\n errorPaths?: readonly TErrorModule[] | null;\n errors?: readonly (TErrorModule | null | undefined)[] | null;\n errorTreePositions?: readonly number[] | null;\n layoutTreePositions?: readonly number[] | null;\n layouts: readonly (TModule | null | undefined)[];\n loading?: TModule | null;\n notFound?: TModule | null;\n notFounds?: readonly (TModule | null | undefined)[] | null;\n forbidden?: TModule | null;\n forbiddens?: readonly (TModule | null | undefined)[] | null;\n unauthorized?: TModule | null;\n unauthorizeds?: readonly (TModule | null | undefined)[] | null;\n routeSegments?: readonly string[];\n /**\n * Keyed by stable slot id (name + owner path), not necessarily the slot prop name.\n */\n slots?: Readonly<Record<string, AppPageRouteWiringSlot<TModule, TErrorModule>>> | null;\n templateTreePositions?: readonly number[] | null;\n templates?: readonly (TModule | null | undefined)[] | null;\n};\n\nexport type AppPageSlotOverride<TModule extends AppPageModule = AppPageModule> = {\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n /**\n * The page module to render for this slot. Optional — when omitted, the\n * slot's existing `page` is used (e.g. when the override only changes the\n * slot's `params` for an inherited mirror with distinct param names).\n */\n pageModule?: TModule | null;\n params?: AppPageParams;\n props?: Readonly<Record<string, unknown>>;\n};\n\ntype AppPageLayoutEntry<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n errorModule?: TErrorModule | null | undefined;\n forbiddenModule?: TModule | null | undefined;\n id: string;\n layoutModule?: TModule | null | undefined;\n notFoundModule?: TModule | null | undefined;\n unauthorizedModule?: TModule | null | undefined;\n treePath: string;\n treePosition: number;\n};\n\ntype BuildAppPageRouteElementOptions<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n element: ReactNode;\n globalErrorModule?: TErrorModule | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n matchedParams: AppPageParams;\n metadataPlacement?: \"body\" | \"head\";\n resolvedMetadata: Metadata | null;\n resolvedMetadataPathname?: string;\n resolvedViewport: Viewport;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n route: AppPageRouteWiringRoute<TModule, TErrorModule>;\n slotOverrides?: Readonly<Record<string, AppPageSlotOverride<TModule>>> | null;\n};\n\ntype BuildAppPageElementsOptions<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = BuildAppPageRouteElementOptions<TModule, TErrorModule> & {\n interception?: AppElementsInterception | null;\n interceptionContext?: string | null;\n isRscRequest?: boolean;\n mountedSlotIds?: ReadonlySet<string> | null;\n renderMode?: AppRscRenderMode;\n routePath: string;\n};\n\ntype AppPageTemplateEntry<TModule extends AppPageModule = AppPageModule> = {\n id: string;\n templateModule?: TModule | null | undefined;\n treePath: string;\n treePosition: number;\n};\n\ntype AppPageErrorEntry<TErrorModule extends AppPageErrorModule = AppPageErrorModule> = {\n errorModule?: TErrorModule | null | undefined;\n treePosition: number;\n};\n\nfunction getDefaultExport<TModule extends AppPageModule>(\n module: TModule | null | undefined,\n): AppPageComponent | null {\n return module?.default ?? null;\n}\n\nfunction getErrorBoundaryExport<TModule extends AppPageErrorModule>(\n module: TModule | null | undefined,\n): AppPageErrorComponent | null {\n return module?.default ?? null;\n}\n\nexport function createAppPageTreePath(\n routeSegments: readonly string[] | null | undefined,\n treePosition: number,\n): string {\n const treePathSegments = routeSegments?.slice(0, treePosition) ?? [];\n if (treePathSegments.length === 0) {\n return \"/\";\n }\n return `/${treePathSegments.join(\"/\")}`;\n}\n\nexport function createAppPageLayoutEntries<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(\n route: Pick<\n AppPageRouteWiringRoute<TModule, TErrorModule>,\n | \"errors\"\n | \"errorTreePositions\"\n | \"layoutTreePositions\"\n | \"layouts\"\n | \"notFounds\"\n | \"routeSegments\"\n > & {\n forbiddens?: readonly (TModule | null | undefined)[] | null;\n unauthorizeds?: readonly (TModule | null | undefined)[] | null;\n },\n): AppPageLayoutEntry<TModule, TErrorModule>[] {\n return route.layouts.map((layoutModule, index) => {\n const treePosition = route.layoutTreePositions?.[index] ?? 0;\n const treePath = createAppPageTreePath(route.routeSegments, treePosition);\n return {\n errorModule: route.errorTreePositions ? null : (route.errors?.[index] ?? null),\n forbiddenModule: route.forbiddens?.[index] ?? null,\n id: AppElementsWire.encodeLayoutId(treePath),\n layoutModule,\n notFoundModule: route.notFounds?.[index] ?? null,\n unauthorizedModule: route.unauthorizeds?.[index] ?? null,\n treePath,\n treePosition,\n };\n });\n}\n\nfunction createAppPageTemplateEntries<TModule extends AppPageModule>(\n route: Pick<\n AppPageRouteWiringRoute<TModule>,\n \"routeSegments\" | \"templateTreePositions\" | \"templates\"\n >,\n): AppPageTemplateEntry<TModule>[] {\n return (route.templates ?? []).map((templateModule, index) => {\n const treePosition = route.templateTreePositions?.[index] ?? 0;\n const treePath = createAppPageTreePath(route.routeSegments, treePosition);\n return {\n id: AppElementsWire.encodeTemplateId(treePath),\n templateModule,\n treePath,\n treePosition,\n };\n });\n}\n\nfunction createAppPageErrorEntries<TErrorModule extends AppPageErrorModule>(\n route: Pick<\n AppPageRouteWiringRoute<AppPageModule, TErrorModule>,\n \"errorPaths\" | \"errors\" | \"errorTreePositions\"\n >,\n): AppPageErrorEntry<TErrorModule>[] {\n return (route.errorPaths ?? route.errors ?? []).flatMap((errorModule, index) => {\n if (!errorModule) return [];\n const treePosition = route.errorTreePositions?.[index];\n if (treePosition === undefined) return [];\n return [{ errorModule, treePosition }];\n });\n}\n\nfunction createAppPageParallelSlotEntries<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(\n layoutIndex: number,\n layoutEntries: readonly AppPageLayoutEntry<TModule, TErrorModule>[],\n route: AppPageRouteWiringRoute<TModule, TErrorModule>,\n getEffectiveSlotParams: (slotKey: string, slotName: string) => AppPageParams,\n): Readonly<Record<string, ReactNode>> | undefined {\n const parallelSlots: Record<string, ReactNode> = {};\n\n for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n if (targetIndex !== layoutIndex) {\n continue;\n }\n\n const layoutEntry = layoutEntries[targetIndex];\n const treePath = layoutEntry?.treePath ?? \"/\";\n const slotId = resolveAppPageSlotId(slot, treePath);\n const slotParams = getEffectiveSlotParams(slotKey, slotName);\n const slotSegments = slot.routeSegments\n ? resolveAppPageChildSegments(slot.routeSegments, 0, slotParams)\n : [];\n parallelSlots[slotName] = (\n <LayoutSegmentProvider segmentMap={{ children: slotSegments }}>\n <Slot id={slotId} />\n </LayoutSegmentProvider>\n );\n }\n\n return Object.keys(parallelSlots).length > 0 ? parallelSlots : undefined;\n}\n\nfunction resolveAppPageSlotId(slot: AppPageRouteWiringSlot, treePath: string): string {\n const slotId = AppElementsWire.encodeSlotId(slot.name, treePath);\n if (slot.id && slot.id !== slotId) {\n throw new Error(\n `[vinext] App Router slot id mismatch for @${slot.name}: graph id ${slot.id} does not match wire id ${slotId}`,\n );\n }\n return slotId;\n}\n\nfunction resolveAppPageSlotBindingState(\n slot: AppPageRouteWiringSlot,\n override: AppPageSlotOverride | undefined,\n): AppElementsSlotBinding[\"state\"] {\n const pageComponent = getDefaultExport(override?.pageModule) ?? getDefaultExport(slot.page);\n if (pageComponent) return \"active\";\n if (getDefaultExport(slot.default)) return \"default\";\n return \"unmatched\";\n}\n\nfunction createAppPageSlotBindings<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(\n route: AppPageRouteWiringRoute<TModule, TErrorModule>,\n layoutEntries: readonly AppPageLayoutEntry<TModule, TErrorModule>[],\n resolveSlotOverride: (\n slotKey: string,\n slotName: string,\n ) => AppPageSlotOverride<TModule> | undefined,\n): readonly AppElementsSlotBinding[] {\n const bindings: AppElementsSlotBinding[] = [];\n for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n const layoutEntry = layoutEntries[targetIndex] ?? null;\n const ownerLayoutId = layoutEntry?.id ?? null;\n const override = resolveSlotOverride(slotKey, slot.name);\n bindings.push({\n ownerLayoutId,\n slotId: resolveAppPageSlotId(slot, layoutEntry?.treePath ?? \"/\"),\n state: resolveAppPageSlotBindingState(slot, override),\n });\n }\n return normalizeAppElementsSlotBindings(bindings, {\n layoutIds: layoutEntries.map((entry) => entry.id),\n });\n}\n\nfunction createAppPageRouteHead(\n metadata: Metadata | null,\n viewport: Viewport,\n pathname: string,\n metadataPlacement: \"body\" | \"head\",\n): ReactNode {\n return (\n <>\n <meta charSet=\"utf-8\" />\n {metadata && metadataPlacement === \"head\" ? (\n <MetadataHead metadata={metadata} pathname={pathname} />\n ) : null}\n <ViewportHead viewport={viewport} />\n </>\n );\n}\n\nfunction createAppPageRouteBodyMetadata(\n metadata: Metadata | null,\n pathname: string,\n metadataPlacement: \"body\" | \"head\",\n): ReactNode {\n if (!metadata || metadataPlacement !== \"body\") return null;\n return (\n <div hidden dangerouslySetInnerHTML={{ __html: renderMetadataToHtml(metadata, pathname) }} />\n );\n}\n\nexport function buildAppPageElements<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(options: BuildAppPageElementsOptions<TModule, TErrorModule>): AppElements {\n const interceptionContext = options.interceptionContext ?? null;\n const renderMode = options.renderMode ?? APP_RSC_RENDER_MODE_NAVIGATION;\n const routeSegments = options.route.routeSegments ?? [];\n const routeResetKey = resolveAppPageRouteStateKey(routeSegments, options.matchedParams);\n const routeId = AppElementsWire.encodeRouteId(options.routePath, interceptionContext);\n const pageId = AppElementsWire.encodePageId(options.routePath, interceptionContext);\n const layoutEntries = createAppPageLayoutEntries(options.route);\n const templateEntries = createAppPageTemplateEntries(options.route);\n const errorEntries = createAppPageErrorEntries(options.route);\n const metadataPlacement = options.metadataPlacement ?? \"head\";\n const layoutEntriesByTreePosition = new Map<number, AppPageLayoutEntry<TModule, TErrorModule>>();\n const templateEntriesByTreePosition = new Map<number, AppPageTemplateEntry<TModule>>();\n const errorEntriesByTreePosition = new Map<number, AppPageErrorEntry<TErrorModule>>();\n for (const layoutEntry of layoutEntries) {\n layoutEntriesByTreePosition.set(layoutEntry.treePosition, layoutEntry);\n }\n for (const templateEntry of templateEntries) {\n templateEntriesByTreePosition.set(templateEntry.treePosition, templateEntry);\n }\n for (const errorEntry of errorEntries) {\n errorEntriesByTreePosition.set(errorEntry.treePosition, errorEntry);\n }\n const layoutIndicesByTreePosition = new Map<number, number>();\n for (let index = 0; index < layoutEntries.length; index++) {\n layoutIndicesByTreePosition.set(layoutEntries[index].treePosition, index);\n }\n const layoutDependenciesByIndex = new Map<number, AppRenderDependency>();\n const layoutDependenciesBefore: AppRenderDependency[][] = [];\n const slotDependenciesByLayoutIndex: AppRenderDependency[][] = [];\n const templateDependenciesById = new Map<string, AppRenderDependency>();\n const templateDependenciesBeforeById = new Map<string, AppRenderDependency[]>();\n const pageDependencies: AppRenderDependency[] = [];\n const rootLayoutTreePath = layoutEntries[0]?.treePath ?? null;\n const slotNameCounts = new Map<string, number>();\n for (const slot of Object.values(options.route.slots ?? {})) {\n const slotName = slot.name;\n slotNameCounts.set(slotName, (slotNameCounts.get(slotName) ?? 0) + 1);\n }\n const orderedTreePositions = Array.from(\n new Set<number>([\n ...layoutEntries.map((entry) => entry.treePosition),\n ...templateEntries.map((entry) => entry.treePosition),\n ...errorEntries.map((entry) => entry.treePosition),\n ]),\n ).sort((left, right) => left - right);\n const resolveSlotOverride = (slotKey: string, slotName: string) => {\n const overrideByKey = options.slotOverrides?.[slotKey];\n if (overrideByKey) {\n return overrideByKey;\n }\n\n // Legacy callers may still provide overrides by slot prop name.\n // Only allow that fallback when it is unambiguous.\n if (slotKey === slotName || (slotNameCounts.get(slotName) ?? 0) === 1) {\n return options.slotOverrides?.[slotName];\n }\n\n return undefined;\n };\n const elements: Record<\n string,\n ReactNode | string | null | AppElementsInterception | readonly AppElementsSlotBinding[]\n > = {\n ...AppElementsWire.createMetadataEntries({\n interception: options.interception ?? null,\n interceptionContext,\n layoutIds: options.route.ids?.layouts ?? layoutEntries.map((entry) => entry.id),\n rootLayoutTreePath,\n routeId,\n slotBindings: createAppPageSlotBindings(options.route, layoutEntries, resolveSlotOverride),\n }),\n };\n const getEffectiveSlotParams = (slotKey: string, slotName: string): AppPageParams =>\n resolveSlotOverride(slotKey, slotName)?.params ?? options.matchedParams;\n\n for (const treePosition of orderedTreePositions) {\n const layoutIndex = layoutIndicesByTreePosition.get(treePosition);\n if (layoutIndex !== undefined) {\n const layoutEntry = layoutEntries[layoutIndex];\n layoutDependenciesBefore[layoutIndex] = [...pageDependencies];\n if (getDefaultExport(layoutEntry.layoutModule)) {\n const layoutDependency = createAppRenderDependency();\n layoutDependenciesByIndex.set(layoutIndex, layoutDependency);\n pageDependencies.push(layoutDependency);\n }\n slotDependenciesByLayoutIndex[layoutIndex] = [...pageDependencies];\n }\n\n const templateEntry = templateEntriesByTreePosition.get(treePosition);\n if (!templateEntry || !getDefaultExport(templateEntry.templateModule)) {\n continue;\n }\n\n const templateDependency = createAppRenderDependency();\n templateDependenciesById.set(templateEntry.id, templateDependency);\n templateDependenciesBeforeById.set(templateEntry.id, [...pageDependencies]);\n pageDependencies.push(templateDependency);\n }\n\n const routeLoadingComponent = getDefaultExport(options.route.loading);\n const isPrefetchLoadingShell = renderMode === APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;\n const shouldRenderPrefetchLoadingShell = isPrefetchLoadingShell && routeLoadingComponent !== null;\n if (shouldRenderPrefetchLoadingShell) {\n // Client loading components serialize as module references in Flight. Keep\n // a durable marker in the shell payload so external router tests and\n // diagnostics can recognize this as a loading-boundary response without\n // requiring source text to appear in client component references.\n elements[APP_PREFETCH_LOADING_SHELL_MARKER_KEY] = \"LoadingBoundary\";\n }\n\n elements[pageId] = isPrefetchLoadingShell\n ? null\n : renderAfterAppDependencies(options.element, pageDependencies);\n\n for (const templateEntry of templateEntries) {\n const templateComponent = getDefaultExport(templateEntry.templateModule);\n if (!templateComponent) {\n continue;\n }\n const TemplateComponent = templateComponent;\n const templateDependency = templateDependenciesById.get(templateEntry.id);\n const templateElement = templateDependency ? (\n renderWithAppDependencyBarrier(\n <TemplateComponent params={options.matchedParams}>\n <Children />\n </TemplateComponent>,\n templateDependency,\n )\n ) : (\n <TemplateComponent params={options.matchedParams}>\n <Children />\n </TemplateComponent>\n );\n elements[templateEntry.id] = renderAfterAppDependencies(\n templateElement,\n templateDependenciesBeforeById.get(templateEntry.id) ?? [],\n );\n }\n\n for (let index = 0; index < layoutEntries.length; index++) {\n const layoutEntry = layoutEntries[index];\n const layoutComponent = getDefaultExport(layoutEntry.layoutModule);\n if (!layoutComponent) {\n continue;\n }\n\n const layoutProps: Record<string, unknown> = {\n params: options.makeThenableParams(\n resolveAppPageSegmentParams(\n options.route.routeSegments,\n layoutEntry.treePosition,\n options.matchedParams,\n ),\n ),\n };\n\n for (const slot of Object.values(options.route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n if (targetIndex !== index) {\n continue;\n }\n layoutProps[slotName] = <ParallelSlot name={slotName} />;\n }\n\n const LayoutComponent = layoutComponent;\n const layoutDependency = layoutDependenciesByIndex.get(index);\n const layoutElement = layoutDependency ? (\n renderWithAppDependencyBarrier(\n <LayoutComponent {...layoutProps}>\n <Children />\n </LayoutComponent>,\n layoutDependency,\n )\n ) : (\n <LayoutComponent {...layoutProps}>\n <Children />\n </LayoutComponent>\n );\n elements[layoutEntry.id] = renderAfterAppDependencies(\n layoutElement,\n layoutDependenciesBefore[index] ?? [],\n );\n }\n\n for (const [slotKey, slot] of Object.entries(options.route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n const treePath = layoutEntries[targetIndex]?.treePath ?? \"/\";\n const slotId = resolveAppPageSlotId(slot, treePath);\n const slotOverride = resolveSlotOverride(slotKey, slotName);\n const slotParams = getEffectiveSlotParams(slotKey, slotName);\n const slotRouteSegments = slot.routeSegments ?? [];\n const slotResetKey = resolveAppPageRouteStateKey(slotRouteSegments, slotParams);\n const overrideOrPageComponent =\n getDefaultExport(slotOverride?.pageModule) ?? getDefaultExport(slot.page);\n const defaultComponent = getDefaultExport(slot.default);\n\n // On soft nav (RSC): omit key when only default.tsx exists and the slot is\n // already mounted on the client. Absent key means the browser retains prior\n // slot content rather than replacing it. When the slot is not yet mounted\n // (first entry into this layout), include the key so default.tsx renders.\n if (\n !overrideOrPageComponent &&\n defaultComponent &&\n options.isRscRequest &&\n options.mountedSlotIds?.has(slotId)\n ) {\n continue;\n }\n\n const slotComponent = overrideOrPageComponent ?? defaultComponent;\n\n if (!slotComponent) {\n elements[slotId] = AppElementsWire.unmatchedSlotValue;\n continue;\n }\n\n const slotThenableParams = options.makeThenableParams(slotParams);\n const slotProps: Record<string, unknown> = {\n params: slotThenableParams,\n };\n if (slotOverride?.props) {\n Object.assign(slotProps, slotOverride.props);\n }\n\n const SlotComponent = slotComponent;\n let slotElement: ReactNode = <SlotComponent {...slotProps} />;\n const interceptLayouts = slotOverride?.layoutModules ?? [];\n\n for (let layoutIndex = interceptLayouts.length - 1; layoutIndex >= 0; layoutIndex--) {\n const interceptLayoutComponent = getDefaultExport(interceptLayouts[layoutIndex]);\n if (!interceptLayoutComponent) {\n continue;\n }\n const InterceptLayoutComponent = interceptLayoutComponent;\n slotElement = (\n <InterceptLayoutComponent params={slotThenableParams}>\n {slotElement}\n </InterceptLayoutComponent>\n );\n }\n\n const slotLayoutComponent = getDefaultExport(slot.layout);\n if (slotLayoutComponent) {\n const SlotLayoutComponent = slotLayoutComponent;\n slotElement = (\n <SlotLayoutComponent params={slotThenableParams}>{slotElement}</SlotLayoutComponent>\n );\n }\n\n const slotLoadingComponent = getDefaultExport(slot.loading);\n if (slotLoadingComponent && !shouldSuppressLoadingBoundaries(renderMode)) {\n const SlotLoadingComponent = slotLoadingComponent;\n slotElement = (\n <Suspense key={slotResetKey} fallback={<SlotLoadingComponent />}>\n {slotElement}\n </Suspense>\n );\n }\n\n const slotErrorComponent = getErrorBoundaryExport(slot.error);\n if (slotErrorComponent) {\n slotElement = (\n <ErrorBoundary resetKey={slotResetKey} fallback={slotErrorComponent}>\n {slotElement}\n </ErrorBoundary>\n );\n }\n\n elements[slotId] = renderAfterAppDependencies(\n slotElement,\n targetIndex >= 0 ? (slotDependenciesByLayoutIndex[targetIndex] ?? []) : [],\n );\n }\n\n let routeChildren: ReactNode = (\n <LayoutSegmentProvider segmentMap={{ children: [] }}>\n <AppRouterScrollTarget>\n <Slot id={pageId} />\n </AppRouterScrollTarget>\n </LayoutSegmentProvider>\n );\n\n if (isPrefetchLoadingShell) {\n if (routeLoadingComponent === null) {\n routeChildren = null;\n } else {\n const RouteLoadingComponent = routeLoadingComponent;\n routeChildren = <RouteLoadingComponent />;\n }\n } else {\n // Wrap the page slot in a per-segment RedirectBoundary so that a\n // redirect() thrown from a server component (or a client component\n // within the page subtree) is caught here — below the route's layouts —\n // rather than at the top-level boundary in app-browser-entry. Catching\n // at the top level unmounts the entire route tree including layouts,\n // which destroys client-side state in layout-hosted components\n // (counters, theme toggles, form drafts). Here, only the page subtree\n // is unmounted; the surrounding layouts stay mounted across the\n // boundary's null-render → router.replace transition, and segment\n // reuse keeps their React state intact.\n //\n // Placed inside the Suspense (loading) boundary to match Next.js nesting\n // for the redirect boundary specifically:\n // Error > AccessFallback > Loading (Suspense) > Redirect > content\n // (Note: Next.js places AccessFallback inside Loading, not outside — that\n // is a pre-existing nesting divergence tracked separately.)\n // This keeps the loading fallback visible during redirect-driven\n // transitions rather than unmounting it.\n routeChildren = <RedirectBoundary>{routeChildren}</RedirectBoundary>;\n\n if (routeLoadingComponent && !shouldSuppressLoadingBoundaries(renderMode)) {\n const RouteLoadingComponent = routeLoadingComponent;\n // Route-level wrappers cover the full page branch in vinext's flat element\n // transport, so their reset key includes the visible segment-state path.\n // Dynamic param changes reset the pending boundary, while search-only changes\n // preserve it.\n routeChildren = (\n <Suspense key={routeResetKey} fallback={<RouteLoadingComponent />}>\n {routeChildren}\n </Suspense>\n );\n }\n }\n\n const lastLayoutErrorModule =\n errorEntries.length > 0 ? errorEntries[errorEntries.length - 1].errorModule : null;\n // Next.js nesting (outer to inner): Error > Unauthorized > Forbidden > NotFound > children.\n // Building bottom-up means NotFoundBoundary must wrap first, then Forbidden, Unauthorized, Error.\n const notFoundComponent =\n getDefaultExport(options.route.notFound) ?? getDefaultExport(options.rootNotFoundModule);\n if (notFoundComponent) {\n const NotFoundComponent = notFoundComponent;\n routeChildren = (\n <NotFoundBoundary resetKey={routeResetKey} fallback={<NotFoundComponent />}>\n {routeChildren}\n </NotFoundBoundary>\n );\n }\n\n const forbiddenComponent =\n getDefaultExport(options.route.forbidden) ?? getDefaultExport(options.rootForbiddenModule);\n if (forbiddenComponent) {\n const ForbiddenComponent = forbiddenComponent;\n routeChildren = (\n <ForbiddenBoundary resetKey={routeResetKey} fallback={<ForbiddenComponent />}>\n {routeChildren}\n </ForbiddenBoundary>\n );\n }\n\n const unauthorizedComponent =\n getDefaultExport(options.route.unauthorized) ??\n getDefaultExport(options.rootUnauthorizedModule);\n if (unauthorizedComponent) {\n const UnauthorizedComponent = unauthorizedComponent;\n routeChildren = (\n <UnauthorizedBoundary resetKey={routeResetKey} fallback={<UnauthorizedComponent />}>\n {routeChildren}\n </UnauthorizedBoundary>\n );\n }\n\n const pageErrorComponent = getErrorBoundaryExport(options.route.error);\n if (pageErrorComponent && options.route.error !== lastLayoutErrorModule) {\n routeChildren = (\n <ErrorBoundary resetKey={routeResetKey} fallback={pageErrorComponent}>\n {routeChildren}\n </ErrorBoundary>\n );\n }\n\n for (let index = orderedTreePositions.length - 1; index >= 0; index--) {\n const treePosition = orderedTreePositions[index];\n const segmentResetKey = resolveAppPageSegmentStateKey(\n routeSegments,\n treePosition,\n options.matchedParams,\n );\n let segmentChildren: ReactNode = routeChildren;\n const layoutEntry = layoutEntriesByTreePosition.get(treePosition);\n const templateEntry = templateEntriesByTreePosition.get(treePosition);\n const errorEntry = errorEntriesByTreePosition.get(treePosition);\n\n // Next.js nesting per segment (outer to inner): Layout > Template > Error > Unauthorized > Forbidden > NotFound > children.\n // Building bottom-up means NotFoundBoundary must wrap the leaf subtree first,\n // then ErrorBoundary, then Template, with the Layout slot outermost.\n if (layoutEntry) {\n const layoutNotFoundComponent = getDefaultExport(layoutEntry.notFoundModule);\n if (layoutNotFoundComponent) {\n const LayoutNotFoundComponent = layoutNotFoundComponent;\n segmentChildren = (\n <NotFoundBoundary resetKey={segmentResetKey} fallback={<LayoutNotFoundComponent />}>\n {segmentChildren}\n </NotFoundBoundary>\n );\n }\n\n const layoutForbiddenComponent = getDefaultExport(layoutEntry.forbiddenModule);\n if (layoutForbiddenComponent) {\n const LayoutForbiddenComponent = layoutForbiddenComponent;\n segmentChildren = (\n <ForbiddenBoundary resetKey={segmentResetKey} fallback={<LayoutForbiddenComponent />}>\n {segmentChildren}\n </ForbiddenBoundary>\n );\n }\n\n const layoutUnauthorizedComponent = getDefaultExport(layoutEntry.unauthorizedModule);\n if (layoutUnauthorizedComponent) {\n const LayoutUnauthorizedComponent = layoutUnauthorizedComponent;\n segmentChildren = (\n <UnauthorizedBoundary\n resetKey={segmentResetKey}\n fallback={<LayoutUnauthorizedComponent />}\n >\n {segmentChildren}\n </UnauthorizedBoundary>\n );\n }\n }\n\n const segmentErrorComponent = getErrorBoundaryExport(\n errorEntry?.errorModule ?? layoutEntry?.errorModule,\n );\n if (segmentErrorComponent) {\n segmentChildren = (\n <ErrorBoundary resetKey={segmentResetKey} fallback={segmentErrorComponent}>\n {segmentChildren}\n </ErrorBoundary>\n );\n }\n\n if (templateEntry && getDefaultExport(templateEntry.templateModule)) {\n segmentChildren = (\n <Slot id={templateEntry.id} key={segmentResetKey}>\n {segmentChildren}\n </Slot>\n );\n }\n\n if (!layoutEntry) {\n routeChildren = segmentChildren;\n continue;\n }\n const layoutHasElement = getDefaultExport(layoutEntry.layoutModule) !== null;\n const layoutIndex = layoutIndicesByTreePosition.get(treePosition) ?? -1;\n const segmentMap: { children: string[] } & Record<string, string[]> = {\n children: resolveAppPageChildSegments(\n routeSegments,\n layoutEntry.treePosition,\n options.matchedParams,\n ),\n };\n for (const [slotKey, slot] of Object.entries(options.route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n if (targetIndex !== layoutIndex) {\n continue;\n }\n const slotParams = getEffectiveSlotParams(slotKey, slotName);\n segmentMap[slotName] = slot.routeSegments\n ? resolveAppPageChildSegments(slot.routeSegments, 0, slotParams)\n : [];\n }\n\n routeChildren = (\n <LayoutSegmentProvider segmentMap={segmentMap}>\n {layoutHasElement ? (\n <Slot\n id={layoutEntry.id}\n parallelSlots={createAppPageParallelSlotEntries(\n layoutIndex,\n layoutEntries,\n options.route,\n getEffectiveSlotParams,\n )}\n >\n {segmentChildren}\n </Slot>\n ) : (\n segmentChildren\n )}\n </LayoutSegmentProvider>\n );\n }\n\n const globalErrorComponent = getErrorBoundaryExport(options.globalErrorModule);\n if (globalErrorComponent) {\n routeChildren = <ErrorBoundary fallback={globalErrorComponent}>{routeChildren}</ErrorBoundary>;\n }\n\n elements[routeId] = (\n <>\n {createAppPageRouteHead(\n options.resolvedMetadata,\n options.resolvedViewport,\n options.resolvedMetadataPathname ?? options.routePath,\n metadataPlacement,\n )}\n {routeChildren}\n {createAppPageRouteBodyMetadata(\n options.resolvedMetadata,\n options.resolvedMetadataPathname ?? options.routePath,\n metadataPlacement,\n )}\n </>\n );\n\n return elements;\n}\n"],"mappings":";;;;;;;;;;;;;;AA6LA,SAAS,iBACP,QACyB;CACzB,OAAO,QAAQ,WAAW;;AAG5B,SAAS,uBACP,QAC8B;CAC9B,OAAO,QAAQ,WAAW;;AAG5B,SAAgB,sBACd,eACA,cACQ;CACR,MAAM,mBAAmB,eAAe,MAAM,GAAG,aAAa,IAAI,EAAE;CACpE,IAAI,iBAAiB,WAAW,GAC9B,OAAO;CAET,OAAO,IAAI,iBAAiB,KAAK,IAAI;;AAGvC,SAAgB,2BAId,OAY6C;CAC7C,OAAO,MAAM,QAAQ,KAAK,cAAc,UAAU;EAChD,MAAM,eAAe,MAAM,sBAAsB,UAAU;EAC3D,MAAM,WAAW,sBAAsB,MAAM,eAAe,aAAa;EACzE,OAAO;GACL,aAAa,MAAM,qBAAqB,OAAQ,MAAM,SAAS,UAAU;GACzE,iBAAiB,MAAM,aAAa,UAAU;GAC9C,IAAI,gBAAgB,eAAe,SAAS;GAC5C;GACA,gBAAgB,MAAM,YAAY,UAAU;GAC5C,oBAAoB,MAAM,gBAAgB,UAAU;GACpD;GACA;GACD;GACD;;AAGJ,SAAS,6BACP,OAIiC;CACjC,QAAQ,MAAM,aAAa,EAAE,EAAE,KAAK,gBAAgB,UAAU;EAC5D,MAAM,eAAe,MAAM,wBAAwB,UAAU;EAC7D,MAAM,WAAW,sBAAsB,MAAM,eAAe,aAAa;EACzE,OAAO;GACL,IAAI,gBAAgB,iBAAiB,SAAS;GAC9C;GACA;GACA;GACD;GACD;;AAGJ,SAAS,0BACP,OAImC;CACnC,QAAQ,MAAM,cAAc,MAAM,UAAU,EAAE,EAAE,SAAS,aAAa,UAAU;EAC9E,IAAI,CAAC,aAAa,OAAO,EAAE;EAC3B,MAAM,eAAe,MAAM,qBAAqB;EAChD,IAAI,iBAAiB,KAAA,GAAW,OAAO,EAAE;EACzC,OAAO,CAAC;GAAE;GAAa;GAAc,CAAC;GACtC;;AAGJ,SAAS,iCAIP,aACA,eACA,OACA,wBACiD;CACjD,MAAM,gBAA2C,EAAE;CAEnD,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO,QAAQ,MAAM,SAAS,EAAE,CAAC,EAAE;EAC/D,MAAM,WAAW,KAAK;EACtB,MAAM,cAAc,KAAK,eAAe,IAAI,KAAK,cAAc,cAAc,SAAS;EACtF,IAAI,gBAAgB,aAClB;EAKF,MAAM,SAAS,qBAAqB,MAFhB,cAAc,cACJ,YAAY,IACS;EACnD,MAAM,aAAa,uBAAuB,SAAS,SAAS;EAI5D,cAAc,YACZ,oBAAC,uBAAD;GAAuB,YAAY,EAAE,UAJlB,KAAK,gBACtB,4BAA4B,KAAK,eAAe,GAAG,WAAW,GAC9D,EAAE,EAEyD;aAC3D,oBAAC,MAAD,EAAM,IAAI,QAAU,CAAA;GACE,CAAA;;CAI5B,OAAO,OAAO,KAAK,cAAc,CAAC,SAAS,IAAI,gBAAgB,KAAA;;AAGjE,SAAS,qBAAqB,MAA8B,UAA0B;CACpF,MAAM,SAAS,gBAAgB,aAAa,KAAK,MAAM,SAAS;CAChE,IAAI,KAAK,MAAM,KAAK,OAAO,QACzB,MAAM,IAAI,MACR,6CAA6C,KAAK,KAAK,aAAa,KAAK,GAAG,0BAA0B,SACvG;CAEH,OAAO;;AAGT,SAAS,+BACP,MACA,UACiC;CAEjC,IADsB,iBAAiB,UAAU,WAAW,IAAI,iBAAiB,KAAK,KAAK,EACxE,OAAO;CAC1B,IAAI,iBAAiB,KAAK,QAAQ,EAAE,OAAO;CAC3C,OAAO;;AAGT,SAAS,0BAIP,OACA,eACA,qBAImC;CACnC,MAAM,WAAqC,EAAE;CAC7C,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO,QAAQ,MAAM,SAAS,EAAE,CAAC,EAAE;EAE/D,MAAM,cAAc,cADA,KAAK,eAAe,IAAI,KAAK,cAAc,cAAc,SAAS,MACpC;EAClD,MAAM,gBAAgB,aAAa,MAAM;EACzC,MAAM,WAAW,oBAAoB,SAAS,KAAK,KAAK;EACxD,SAAS,KAAK;GACZ;GACA,QAAQ,qBAAqB,MAAM,aAAa,YAAY,IAAI;GAChE,OAAO,+BAA+B,MAAM,SAAS;GACtD,CAAC;;CAEJ,OAAO,iCAAiC,UAAU,EAChD,WAAW,cAAc,KAAK,UAAU,MAAM,GAAG,EAClD,CAAC;;AAGJ,SAAS,uBACP,UACA,UACA,UACA,mBACW;CACX,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,QAAD,EAAM,SAAQ,SAAU,CAAA;EACvB,YAAY,sBAAsB,SACjC,oBAAC,cAAD;GAAwB;GAAoB;GAAY,CAAA,GACtD;EACJ,oBAAC,cAAD,EAAwB,UAAY,CAAA;EACnC,EAAA,CAAA;;AAIP,SAAS,+BACP,UACA,UACA,mBACW;CACX,IAAI,CAAC,YAAY,sBAAsB,QAAQ,OAAO;CACtD,OACE,oBAAC,OAAD;EAAK,QAAA;EAAO,yBAAyB,EAAE,QAAQ,qBAAqB,UAAU,SAAS,EAAE;EAAI,CAAA;;AAIjG,SAAgB,qBAGd,SAA0E;CAC1E,MAAM,sBAAsB,QAAQ,uBAAuB;CAC3D,MAAM,aAAa,QAAQ,cAAA;CAC3B,MAAM,gBAAgB,QAAQ,MAAM,iBAAiB,EAAE;CACvD,MAAM,gBAAgB,4BAA4B,eAAe,QAAQ,cAAc;CACvF,MAAM,UAAU,gBAAgB,cAAc,QAAQ,WAAW,oBAAoB;CACrF,MAAM,SAAS,gBAAgB,aAAa,QAAQ,WAAW,oBAAoB;CACnF,MAAM,gBAAgB,2BAA2B,QAAQ,MAAM;CAC/D,MAAM,kBAAkB,6BAA6B,QAAQ,MAAM;CACnE,MAAM,eAAe,0BAA0B,QAAQ,MAAM;CAC7D,MAAM,oBAAoB,QAAQ,qBAAqB;CACvD,MAAM,8CAA8B,IAAI,KAAwD;CAChG,MAAM,gDAAgC,IAAI,KAA4C;CACtF,MAAM,6CAA6B,IAAI,KAA8C;CACrF,KAAK,MAAM,eAAe,eACxB,4BAA4B,IAAI,YAAY,cAAc,YAAY;CAExE,KAAK,MAAM,iBAAiB,iBAC1B,8BAA8B,IAAI,cAAc,cAAc,cAAc;CAE9E,KAAK,MAAM,cAAc,cACvB,2BAA2B,IAAI,WAAW,cAAc,WAAW;CAErE,MAAM,8CAA8B,IAAI,KAAqB;CAC7D,KAAK,IAAI,QAAQ,GAAG,QAAQ,cAAc,QAAQ,SAChD,4BAA4B,IAAI,cAAc,OAAO,cAAc,MAAM;CAE3E,MAAM,4CAA4B,IAAI,KAAkC;CACxE,MAAM,2BAAoD,EAAE;CAC5D,MAAM,gCAAyD,EAAE;CACjE,MAAM,2CAA2B,IAAI,KAAkC;CACvE,MAAM,iDAAiC,IAAI,KAAoC;CAC/E,MAAM,mBAA0C,EAAE;CAClD,MAAM,qBAAqB,cAAc,IAAI,YAAY;CACzD,MAAM,iCAAiB,IAAI,KAAqB;CAChD,KAAK,MAAM,QAAQ,OAAO,OAAO,QAAQ,MAAM,SAAS,EAAE,CAAC,EAAE;EAC3D,MAAM,WAAW,KAAK;EACtB,eAAe,IAAI,WAAW,eAAe,IAAI,SAAS,IAAI,KAAK,EAAE;;CAEvE,MAAM,uBAAuB,MAAM,KACjC,IAAI,IAAY;EACd,GAAG,cAAc,KAAK,UAAU,MAAM,aAAa;EACnD,GAAG,gBAAgB,KAAK,UAAU,MAAM,aAAa;EACrD,GAAG,aAAa,KAAK,UAAU,MAAM,aAAa;EACnD,CAAC,CACH,CAAC,MAAM,MAAM,UAAU,OAAO,MAAM;CACrC,MAAM,uBAAuB,SAAiB,aAAqB;EACjE,MAAM,gBAAgB,QAAQ,gBAAgB;EAC9C,IAAI,eACF,OAAO;EAKT,IAAI,YAAY,aAAa,eAAe,IAAI,SAAS,IAAI,OAAO,GAClE,OAAO,QAAQ,gBAAgB;;CAKnC,MAAM,WAGF,EACF,GAAG,gBAAgB,sBAAsB;EACvC,cAAc,QAAQ,gBAAgB;EACtC;EACA,WAAW,QAAQ,MAAM,KAAK,WAAW,cAAc,KAAK,UAAU,MAAM,GAAG;EAC/E;EACA;EACA,cAAc,0BAA0B,QAAQ,OAAO,eAAe,oBAAoB;EAC3F,CAAC,EACH;CACD,MAAM,0BAA0B,SAAiB,aAC/C,oBAAoB,SAAS,SAAS,EAAE,UAAU,QAAQ;CAE5D,KAAK,MAAM,gBAAgB,sBAAsB;EAC/C,MAAM,cAAc,4BAA4B,IAAI,aAAa;EACjE,IAAI,gBAAgB,KAAA,GAAW;GAC7B,MAAM,cAAc,cAAc;GAClC,yBAAyB,eAAe,CAAC,GAAG,iBAAiB;GAC7D,IAAI,iBAAiB,YAAY,aAAa,EAAE;IAC9C,MAAM,mBAAmB,2BAA2B;IACpD,0BAA0B,IAAI,aAAa,iBAAiB;IAC5D,iBAAiB,KAAK,iBAAiB;;GAEzC,8BAA8B,eAAe,CAAC,GAAG,iBAAiB;;EAGpE,MAAM,gBAAgB,8BAA8B,IAAI,aAAa;EACrE,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,cAAc,eAAe,EACnE;EAGF,MAAM,qBAAqB,2BAA2B;EACtD,yBAAyB,IAAI,cAAc,IAAI,mBAAmB;EAClE,+BAA+B,IAAI,cAAc,IAAI,CAAC,GAAG,iBAAiB,CAAC;EAC3E,iBAAiB,KAAK,mBAAmB;;CAG3C,MAAM,wBAAwB,iBAAiB,QAAQ,MAAM,QAAQ;CACrE,MAAM,yBAAyB,eAAe;CAE9C,IADyC,0BAA0B,0BAA0B,MAM3F,SAAS,yCAAyC;CAGpD,SAAS,UAAU,yBACf,OACA,2BAA2B,QAAQ,SAAS,iBAAiB;CAEjE,KAAK,MAAM,iBAAiB,iBAAiB;EAC3C,MAAM,oBAAoB,iBAAiB,cAAc,eAAe;EACxE,IAAI,CAAC,mBACH;EAEF,MAAM,oBAAoB;EAC1B,MAAM,qBAAqB,yBAAyB,IAAI,cAAc,GAAG;EACzE,MAAM,kBAAkB,qBACtB,+BACE,oBAAC,mBAAD;GAAmB,QAAQ,QAAQ;aACjC,oBAACA,YAAD,EAAY,CAAA;GACM,CAAA,EACpB,mBACD,GAED,oBAAC,mBAAD;GAAmB,QAAQ,QAAQ;aACjC,oBAACA,YAAD,EAAY,CAAA;GACM,CAAA;EAEtB,SAAS,cAAc,MAAM,2BAC3B,iBACA,+BAA+B,IAAI,cAAc,GAAG,IAAI,EAAE,CAC3D;;CAGH,KAAK,IAAI,QAAQ,GAAG,QAAQ,cAAc,QAAQ,SAAS;EACzD,MAAM,cAAc,cAAc;EAClC,MAAM,kBAAkB,iBAAiB,YAAY,aAAa;EAClE,IAAI,CAAC,iBACH;EAGF,MAAM,cAAuC,EAC3C,QAAQ,QAAQ,mBACd,4BACE,QAAQ,MAAM,eACd,YAAY,cACZ,QAAQ,cACT,CACF,EACF;EAED,KAAK,MAAM,QAAQ,OAAO,OAAO,QAAQ,MAAM,SAAS,EAAE,CAAC,EAAE;GAC3D,MAAM,WAAW,KAAK;GAEtB,KADoB,KAAK,eAAe,IAAI,KAAK,cAAc,cAAc,SAAS,OAClE,OAClB;GAEF,YAAY,YAAY,oBAAC,cAAD,EAAc,MAAM,UAAY,CAAA;;EAG1D,MAAM,kBAAkB;EACxB,MAAM,mBAAmB,0BAA0B,IAAI,MAAM;EAC7D,MAAM,gBAAgB,mBACpB,+BACE,oBAAC,iBAAD;GAAiB,GAAI;aACnB,oBAACA,YAAD,EAAY,CAAA;GACI,CAAA,EAClB,iBACD,GAED,oBAAC,iBAAD;GAAiB,GAAI;aACnB,oBAACA,YAAD,EAAY,CAAA;GACI,CAAA;EAEpB,SAAS,YAAY,MAAM,2BACzB,eACA,yBAAyB,UAAU,EAAE,CACtC;;CAGH,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO,QAAQ,QAAQ,MAAM,SAAS,EAAE,CAAC,EAAE;EACvE,MAAM,WAAW,KAAK;EACtB,MAAM,cAAc,KAAK,eAAe,IAAI,KAAK,cAAc,cAAc,SAAS;EAEtF,MAAM,SAAS,qBAAqB,MADnB,cAAc,cAAc,YAAY,IACN;EACnD,MAAM,eAAe,oBAAoB,SAAS,SAAS;EAC3D,MAAM,aAAa,uBAAuB,SAAS,SAAS;EAE5D,MAAM,eAAe,4BADK,KAAK,iBAAiB,EAAE,EACkB,WAAW;EAC/E,MAAM,0BACJ,iBAAiB,cAAc,WAAW,IAAI,iBAAiB,KAAK,KAAK;EAC3E,MAAM,mBAAmB,iBAAiB,KAAK,QAAQ;EAMvD,IACE,CAAC,2BACD,oBACA,QAAQ,gBACR,QAAQ,gBAAgB,IAAI,OAAO,EAEnC;EAGF,MAAM,gBAAgB,2BAA2B;EAEjD,IAAI,CAAC,eAAe;GAClB,SAAS,UAAU,gBAAgB;GACnC;;EAGF,MAAM,qBAAqB,QAAQ,mBAAmB,WAAW;EACjE,MAAM,YAAqC,EACzC,QAAQ,oBACT;EACD,IAAI,cAAc,OAChB,OAAO,OAAO,WAAW,aAAa,MAAM;EAI9C,IAAI,cAAyB,oBAACC,eAAD,EAAe,GAAI,WAAa,CAAA;EAC7D,MAAM,mBAAmB,cAAc,iBAAiB,EAAE;EAE1D,KAAK,IAAI,cAAc,iBAAiB,SAAS,GAAG,eAAe,GAAG,eAAe;GACnF,MAAM,2BAA2B,iBAAiB,iBAAiB,aAAa;GAChF,IAAI,CAAC,0BACH;GAGF,cACE,oBAACC,0BAAD;IAA0B,QAAQ;cAC/B;IACwB,CAAA;;EAI/B,MAAM,sBAAsB,iBAAiB,KAAK,OAAO;EACzD,IAAI,qBAEF,cACE,oBAACC,qBAAD;GAAqB,QAAQ;aAAqB;GAAkC,CAAA;EAIxF,MAAM,uBAAuB,iBAAiB,KAAK,QAAQ;EAC3D,IAAI,wBAAwB,CAAC,gCAAgC,WAAW,EAEtE,cACE,oBAAC,UAAD;GAA6B,UAAU,oBAACC,sBAAD,EAAwB,CAAA;aAC5D;GACQ,EAFI,aAEJ;EAIf,MAAM,qBAAqB,uBAAuB,KAAK,MAAM;EAC7D,IAAI,oBACF,cACE,oBAAC,eAAD;GAAe,UAAU;GAAc,UAAU;aAC9C;GACa,CAAA;EAIpB,SAAS,UAAU,2BACjB,aACA,eAAe,IAAK,8BAA8B,gBAAgB,EAAE,GAAI,EAAE,CAC3E;;CAGH,IAAI,gBACF,oBAAC,uBAAD;EAAuB,YAAY,EAAE,UAAU,EAAE,EAAE;YACjD,oBAAC,uBAAD,EAAA,UACE,oBAAC,MAAD,EAAM,IAAI,QAAU,CAAA,EACE,CAAA;EACF,CAAA;CAG1B,IAAI,wBACF,IAAI,0BAA0B,MAC5B,gBAAgB;MAGhB,gBAAgB,oBAACC,uBAAD,EAAyB,CAAA;MAEtC;EAmBL,gBAAgB,oBAAC,kBAAD,EAAA,UAAmB,eAAiC,CAAA;EAEpE,IAAI,yBAAyB,CAAC,gCAAgC,WAAW,EAMvE,gBACE,oBAAC,UAAD;GAA8B,UAAU,oBAACA,uBAAD,EAAyB,CAAA;aAC9D;GACQ,EAFI,cAEJ;;CAKjB,MAAM,wBACJ,aAAa,SAAS,IAAI,aAAa,aAAa,SAAS,GAAG,cAAc;CAGhF,MAAM,oBACJ,iBAAiB,QAAQ,MAAM,SAAS,IAAI,iBAAiB,QAAQ,mBAAmB;CAC1F,IAAI,mBAEF,gBACE,oBAAC,kBAAD;EAAkB,UAAU;EAAe,UAAU,oBAACC,mBAAD,EAAqB,CAAA;YACvE;EACgB,CAAA;CAIvB,MAAM,qBACJ,iBAAiB,QAAQ,MAAM,UAAU,IAAI,iBAAiB,QAAQ,oBAAoB;CAC5F,IAAI,oBAEF,gBACE,oBAAC,mBAAD;EAAmB,UAAU;EAAe,UAAU,oBAACC,oBAAD,EAAsB,CAAA;YACzE;EACiB,CAAA;CAIxB,MAAM,wBACJ,iBAAiB,QAAQ,MAAM,aAAa,IAC5C,iBAAiB,QAAQ,uBAAuB;CAClD,IAAI,uBAEF,gBACE,oBAAC,sBAAD;EAAsB,UAAU;EAAe,UAAU,oBAACC,uBAAD,EAAyB,CAAA;YAC/E;EACoB,CAAA;CAI3B,MAAM,qBAAqB,uBAAuB,QAAQ,MAAM,MAAM;CACtE,IAAI,sBAAsB,QAAQ,MAAM,UAAU,uBAChD,gBACE,oBAAC,eAAD;EAAe,UAAU;EAAe,UAAU;YAC/C;EACa,CAAA;CAIpB,KAAK,IAAI,QAAQ,qBAAqB,SAAS,GAAG,SAAS,GAAG,SAAS;EACrE,MAAM,eAAe,qBAAqB;EAC1C,MAAM,kBAAkB,8BACtB,eACA,cACA,QAAQ,cACT;EACD,IAAI,kBAA6B;EACjC,MAAM,cAAc,4BAA4B,IAAI,aAAa;EACjE,MAAM,gBAAgB,8BAA8B,IAAI,aAAa;EACrE,MAAM,aAAa,2BAA2B,IAAI,aAAa;EAK/D,IAAI,aAAa;GACf,MAAM,0BAA0B,iBAAiB,YAAY,eAAe;GAC5E,IAAI,yBAEF,kBACE,oBAAC,kBAAD;IAAkB,UAAU;IAAiB,UAAU,oBAACC,yBAAD,EAA2B,CAAA;cAC/E;IACgB,CAAA;GAIvB,MAAM,2BAA2B,iBAAiB,YAAY,gBAAgB;GAC9E,IAAI,0BAEF,kBACE,oBAAC,mBAAD;IAAmB,UAAU;IAAiB,UAAU,oBAACC,0BAAD,EAA4B,CAAA;cACjF;IACiB,CAAA;GAIxB,MAAM,8BAA8B,iBAAiB,YAAY,mBAAmB;GACpF,IAAI,6BAEF,kBACE,oBAAC,sBAAD;IACE,UAAU;IACV,UAAU,oBAACC,6BAAD,EAA+B,CAAA;cAExC;IACoB,CAAA;;EAK7B,MAAM,wBAAwB,uBAC5B,YAAY,eAAe,aAAa,YACzC;EACD,IAAI,uBACF,kBACE,oBAAC,eAAD;GAAe,UAAU;GAAiB,UAAU;aACjD;GACa,CAAA;EAIpB,IAAI,iBAAiB,iBAAiB,cAAc,eAAe,EACjE,kBACE,oBAAC,MAAD;GAAM,IAAI,cAAc;aACrB;GACI,EAF0B,gBAE1B;EAIX,IAAI,CAAC,aAAa;GAChB,gBAAgB;GAChB;;EAEF,MAAM,mBAAmB,iBAAiB,YAAY,aAAa,KAAK;EACxE,MAAM,cAAc,4BAA4B,IAAI,aAAa,IAAI;EACrE,MAAM,aAAgE,EACpE,UAAU,4BACR,eACA,YAAY,cACZ,QAAQ,cACT,EACF;EACD,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO,QAAQ,QAAQ,MAAM,SAAS,EAAE,CAAC,EAAE;GACvE,MAAM,WAAW,KAAK;GAEtB,KADoB,KAAK,eAAe,IAAI,KAAK,cAAc,cAAc,SAAS,OAClE,aAClB;GAEF,MAAM,aAAa,uBAAuB,SAAS,SAAS;GAC5D,WAAW,YAAY,KAAK,gBACxB,4BAA4B,KAAK,eAAe,GAAG,WAAW,GAC9D,EAAE;;EAGR,gBACE,oBAAC,uBAAD;GAAmC;aAChC,mBACC,oBAAC,MAAD;IACE,IAAI,YAAY;IAChB,eAAe,iCACb,aACA,eACA,QAAQ,OACR,uBACD;cAEA;IACI,CAAA,GAEP;GAEoB,CAAA;;CAI5B,MAAM,uBAAuB,uBAAuB,QAAQ,kBAAkB;CAC9E,IAAI,sBACF,gBAAgB,oBAAC,eAAD;EAAe,UAAU;YAAuB;EAA8B,CAAA;CAGhG,SAAS,WACP,qBAAA,YAAA,EAAA,UAAA;EACG,uBACC,QAAQ,kBACR,QAAQ,kBACR,QAAQ,4BAA4B,QAAQ,WAC5C,kBACD;EACA;EACA,+BACC,QAAQ,kBACR,QAAQ,4BAA4B,QAAQ,WAC5C,kBACD;EACA,EAAA,CAAA;CAGL,OAAO"}
|
|
1
|
+
{"version":3,"file":"app-page-route-wiring.js","names":["Children","SlotComponent","InterceptLayoutComponent","SlotLayoutComponent","SlotLoadingComponent","RouteLoadingComponent","NotFoundComponent","ForbiddenComponent","UnauthorizedComponent","LayoutNotFoundComponent","LayoutForbiddenComponent","LayoutUnauthorizedComponent"],"sources":["../../src/server/app-page-route-wiring.tsx"],"sourcesContent":["import { Suspense, type ComponentType, type ReactNode } from \"react\";\nimport {\n AppElementsWire,\n APP_PREFETCH_LOADING_SHELL_MARKER_KEY,\n APP_STATIC_SIBLINGS_KEY,\n normalizeAppElementsSlotBindings,\n type AppElements,\n type AppElementsInterception,\n type AppElementsSlotBinding,\n} from \"./app-elements.js\";\nimport {\n ErrorBoundary,\n ForbiddenBoundary,\n NotFoundBoundary,\n RedirectBoundary,\n UnauthorizedBoundary,\n} from \"vinext/shims/error-boundary\";\nimport { AppRouterScrollTarget } from \"vinext/shims/app-router-scroll\";\nimport type { AppRouteSemanticIds } from \"../routing/app-route-graph.js\";\nimport { LayoutSegmentProvider } from \"vinext/shims/layout-segment-context\";\nimport {\n MetadataHead,\n ViewportHead,\n renderMetadataToHtml,\n type Metadata,\n type Viewport,\n} from \"vinext/shims/metadata\";\nimport { Children, ParallelSlot, Slot } from \"vinext/shims/slot\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport {\n createAppRenderDependency,\n renderAfterAppDependencies,\n renderWithAppDependencyBarrier,\n type AppRenderDependency,\n} from \"./app-render-dependency.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\nimport {\n APP_RSC_RENDER_MODE_NAVIGATION,\n APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL,\n shouldSuppressLoadingBoundaries,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.js\";\nimport {\n resolveAppPageChildSegments,\n resolveAppPageRouteStateKey,\n resolveAppPageSegmentStateKey,\n} from \"./app-page-segment-state.js\";\nimport type { AppPageRenderIdentity } from \"./app-page-render-identity.js\";\n\nexport { resolveAppPageChildSegments } from \"./app-page-segment-state.js\";\n\ntype AppPageComponentProps = {\n children?: ReactNode;\n error?: unknown;\n params?: unknown;\n reset?: () => void;\n} & Record<string, unknown>;\n\ntype AppPageComponent = ComponentType<AppPageComponentProps>;\ntype AppPageErrorComponent = ComponentType<{ error: unknown; reset: () => void }>;\n\nexport type AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\n\nexport type AppPageErrorModule = Record<string, unknown> & {\n default?: AppPageErrorComponent | null | undefined;\n};\n\ntype AppPageRouteWiringSlot<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n /** Graph-owned semantic slot identity. */\n id?: string | null;\n /** Slot prop name passed to the owning layout (e.g. \"modal\" from @modal). */\n name: string;\n default?: TModule | null;\n error?: TErrorModule | null;\n layout?: TModule | null;\n layoutIndex: number;\n loading?: TModule | null;\n page?: TModule | null;\n routeSegments?: readonly string[] | null;\n /**\n * Full URL pattern parts for the slot's mirrored sub-page. Set when the\n * slot's params may differ from the route's (e.g. inherited slot whose\n * dynamic markers have different names than the route's). The runtime\n * matches the request URL against these parts to extract slot params.\n */\n slotPatternParts?: readonly string[] | null;\n /** Param names captured by `slotPatternParts`, in order. */\n slotParamNames?: readonly string[] | null;\n};\n\nexport type AppPageRouteWiringRoute<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n ids?: AppRouteSemanticIds | null;\n error?: TErrorModule | null;\n errorPaths?: readonly TErrorModule[] | null;\n errors?: readonly (TErrorModule | null | undefined)[] | null;\n errorTreePositions?: readonly number[] | null;\n layoutTreePositions?: readonly number[] | null;\n layouts: readonly (TModule | null | undefined)[];\n loading?: TModule | null;\n notFound?: TModule | null;\n notFounds?: readonly (TModule | null | undefined)[] | null;\n forbidden?: TModule | null;\n forbiddens?: readonly (TModule | null | undefined)[] | null;\n unauthorized?: TModule | null;\n unauthorizeds?: readonly (TModule | null | undefined)[] | null;\n routeSegments?: readonly string[];\n /**\n * Keyed by stable slot id (name + owner path), not necessarily the slot prop name.\n */\n slots?: Readonly<Record<string, AppPageRouteWiringSlot<TModule, TErrorModule>>> | null;\n /**\n * Static sibling segment names at each dynamic URL level for this route. Used\n * by the client router to determine if a cached prefetch of the dynamic\n * route can be reused when navigating to a static sibling URL.\n *\n * Mirrors Next.js's `staticSiblings` tuple element on the loader-tree\n * dynamic segments — see `.nextjs-ref/packages/next/src/shared/lib/app-router-types.ts`\n * (DynamicSegmentTuple) and the loader emit in\n * `packages/next/src/build/webpack/loaders/next-app-loader/index.ts`.\n *\n * Issue: https://github.com/cloudflare/vinext/issues/1525\n */\n staticSiblings?: readonly string[] | null;\n templateTreePositions?: readonly number[] | null;\n templates?: readonly (TModule | null | undefined)[] | null;\n};\n\nexport type AppPageSlotOverride<TModule extends AppPageModule = AppPageModule> = {\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n /**\n * The page module to render for this slot. Optional — when omitted, the\n * slot's existing `page` is used (e.g. when the override only changes the\n * slot's `params` for an inherited mirror with distinct param names).\n */\n pageModule?: TModule | null;\n params?: AppPageParams;\n props?: Readonly<Record<string, unknown>>;\n};\n\ntype AppPageLayoutEntry<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n errorModule?: TErrorModule | null | undefined;\n forbiddenModule?: TModule | null | undefined;\n id: string;\n layoutModule?: TModule | null | undefined;\n notFoundModule?: TModule | null | undefined;\n unauthorizedModule?: TModule | null | undefined;\n treePath: string;\n treePosition: number;\n};\n\ntype BuildAppPageRouteElementOptions<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n element: ReactNode;\n globalErrorModule?: TErrorModule | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n matchedParams: AppPageParams;\n metadataPlacement?: \"body\" | \"head\";\n resolvedMetadata: Metadata | null;\n resolvedMetadataPathname?: string;\n resolvedViewport: Viewport;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n route: AppPageRouteWiringRoute<TModule, TErrorModule>;\n slotOverrides?: Readonly<Record<string, AppPageSlotOverride<TModule>>> | null;\n};\n\ntype BuildAppPageElementsOptions<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = BuildAppPageRouteElementOptions<TModule, TErrorModule> & {\n interception?: AppElementsInterception | null;\n interceptionContext?: string | null;\n isRscRequest?: boolean;\n mountedSlotIds?: ReadonlySet<string> | null;\n renderIdentity?: AppPageRenderIdentity;\n renderMode?: AppRscRenderMode;\n routePath: string;\n};\n\ntype AppPageTemplateEntry<TModule extends AppPageModule = AppPageModule> = {\n id: string;\n templateModule?: TModule | null | undefined;\n treePath: string;\n treePosition: number;\n};\n\ntype AppPageErrorEntry<TErrorModule extends AppPageErrorModule = AppPageErrorModule> = {\n errorModule?: TErrorModule | null | undefined;\n treePosition: number;\n};\n\nfunction getDefaultExport<TModule extends AppPageModule>(\n module: TModule | null | undefined,\n): AppPageComponent | null {\n return module?.default ?? null;\n}\n\nfunction getErrorBoundaryExport<TModule extends AppPageErrorModule>(\n module: TModule | null | undefined,\n): AppPageErrorComponent | null {\n return module?.default ?? null;\n}\n\nexport function createAppPageTreePath(\n routeSegments: readonly string[] | null | undefined,\n treePosition: number,\n): string {\n const treePathSegments = routeSegments?.slice(0, treePosition) ?? [];\n if (treePathSegments.length === 0) {\n return \"/\";\n }\n return `/${treePathSegments.join(\"/\")}`;\n}\n\nexport function createAppPageLayoutEntries<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(\n route: Pick<\n AppPageRouteWiringRoute<TModule, TErrorModule>,\n | \"errors\"\n | \"errorTreePositions\"\n | \"layoutTreePositions\"\n | \"layouts\"\n | \"notFounds\"\n | \"routeSegments\"\n > & {\n forbiddens?: readonly (TModule | null | undefined)[] | null;\n unauthorizeds?: readonly (TModule | null | undefined)[] | null;\n },\n): AppPageLayoutEntry<TModule, TErrorModule>[] {\n return route.layouts.map((layoutModule, index) => {\n const treePosition = route.layoutTreePositions?.[index] ?? 0;\n const treePath = createAppPageTreePath(route.routeSegments, treePosition);\n return {\n errorModule: route.errorTreePositions ? null : (route.errors?.[index] ?? null),\n forbiddenModule: route.forbiddens?.[index] ?? null,\n id: AppElementsWire.encodeLayoutId(treePath),\n layoutModule,\n notFoundModule: route.notFounds?.[index] ?? null,\n unauthorizedModule: route.unauthorizeds?.[index] ?? null,\n treePath,\n treePosition,\n };\n });\n}\n\nfunction createAppPageTemplateEntries<TModule extends AppPageModule>(\n route: Pick<\n AppPageRouteWiringRoute<TModule>,\n \"routeSegments\" | \"templateTreePositions\" | \"templates\"\n >,\n): AppPageTemplateEntry<TModule>[] {\n return (route.templates ?? []).map((templateModule, index) => {\n const treePosition = route.templateTreePositions?.[index] ?? 0;\n const treePath = createAppPageTreePath(route.routeSegments, treePosition);\n return {\n id: AppElementsWire.encodeTemplateId(treePath),\n templateModule,\n treePath,\n treePosition,\n };\n });\n}\n\nfunction createAppPageErrorEntries<TErrorModule extends AppPageErrorModule>(\n route: Pick<\n AppPageRouteWiringRoute<AppPageModule, TErrorModule>,\n \"errorPaths\" | \"errors\" | \"errorTreePositions\"\n >,\n): AppPageErrorEntry<TErrorModule>[] {\n return (route.errorPaths ?? route.errors ?? []).flatMap((errorModule, index) => {\n if (!errorModule) return [];\n const treePosition = route.errorTreePositions?.[index];\n if (treePosition === undefined) return [];\n return [{ errorModule, treePosition }];\n });\n}\n\nfunction createAppPageParallelSlotEntries<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(\n layoutIndex: number,\n layoutEntries: readonly AppPageLayoutEntry<TModule, TErrorModule>[],\n route: AppPageRouteWiringRoute<TModule, TErrorModule>,\n getEffectiveSlotParams: (slotKey: string, slotName: string) => AppPageParams,\n): Readonly<Record<string, ReactNode>> | undefined {\n const parallelSlots: Record<string, ReactNode> = {};\n\n for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n if (targetIndex !== layoutIndex) {\n continue;\n }\n\n const layoutEntry = layoutEntries[targetIndex];\n const treePath = layoutEntry?.treePath ?? \"/\";\n const slotId = resolveAppPageSlotId(slot, treePath);\n const slotParams = getEffectiveSlotParams(slotKey, slotName);\n const slotSegments = slot.routeSegments\n ? resolveAppPageChildSegments(slot.routeSegments, 0, slotParams)\n : [];\n parallelSlots[slotName] = (\n <LayoutSegmentProvider segmentMap={{ children: slotSegments }}>\n <Slot id={slotId} />\n </LayoutSegmentProvider>\n );\n }\n\n return Object.keys(parallelSlots).length > 0 ? parallelSlots : undefined;\n}\n\nfunction resolveAppPageSlotId(slot: AppPageRouteWiringSlot, treePath: string): string {\n const slotId = AppElementsWire.encodeSlotId(slot.name, treePath);\n if (slot.id && slot.id !== slotId) {\n throw new Error(\n `[vinext] App Router slot id mismatch for @${slot.name}: graph id ${slot.id} does not match wire id ${slotId}`,\n );\n }\n return slotId;\n}\n\nfunction resolveAppPageSlotBindingState(\n slot: AppPageRouteWiringSlot,\n override: AppPageSlotOverride | undefined,\n): AppElementsSlotBinding[\"state\"] {\n const pageComponent = getDefaultExport(override?.pageModule) ?? getDefaultExport(slot.page);\n if (pageComponent) return \"active\";\n if (getDefaultExport(slot.default)) return \"default\";\n return \"unmatched\";\n}\n\nfunction createAppPageSlotBindings<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(\n route: AppPageRouteWiringRoute<TModule, TErrorModule>,\n layoutEntries: readonly AppPageLayoutEntry<TModule, TErrorModule>[],\n resolveSlotOverride: (\n slotKey: string,\n slotName: string,\n ) => AppPageSlotOverride<TModule> | undefined,\n): readonly AppElementsSlotBinding[] {\n const bindings: AppElementsSlotBinding[] = [];\n for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n const layoutEntry = layoutEntries[targetIndex] ?? null;\n const ownerLayoutId = layoutEntry?.id ?? null;\n const override = resolveSlotOverride(slotKey, slot.name);\n bindings.push({\n ownerLayoutId,\n slotId: resolveAppPageSlotId(slot, layoutEntry?.treePath ?? \"/\"),\n state: resolveAppPageSlotBindingState(slot, override),\n });\n }\n return normalizeAppElementsSlotBindings(bindings, {\n layoutIds: layoutEntries.map((entry) => entry.id),\n });\n}\n\nfunction createAppPageRouteHead(\n metadata: Metadata | null,\n viewport: Viewport,\n pathname: string,\n metadataPlacement: \"body\" | \"head\",\n): ReactNode {\n return (\n <>\n <meta charSet=\"utf-8\" />\n {metadata && metadataPlacement === \"head\" ? (\n <MetadataHead metadata={metadata} pathname={pathname} />\n ) : null}\n <ViewportHead viewport={viewport} />\n </>\n );\n}\n\nfunction createAppPageRouteBodyMetadata(\n metadata: Metadata | null,\n pathname: string,\n metadataPlacement: \"body\" | \"head\",\n): ReactNode {\n if (!metadata || metadataPlacement !== \"body\") return null;\n return (\n <div hidden dangerouslySetInnerHTML={{ __html: renderMetadataToHtml(metadata, pathname) }} />\n );\n}\n\nexport function buildAppPageElements<\n TModule extends AppPageModule,\n TErrorModule extends AppPageErrorModule,\n>(options: BuildAppPageElementsOptions<TModule, TErrorModule>): AppElements {\n const renderIdentity = options.renderIdentity;\n const interceptionContext =\n renderIdentity?.interceptionContext ?? options.interceptionContext ?? null;\n const renderMode = options.renderMode ?? APP_RSC_RENDER_MODE_NAVIGATION;\n const routeSegments = options.route.routeSegments ?? [];\n const routeResetKey = resolveAppPageRouteStateKey(routeSegments, options.matchedParams);\n const routeId =\n renderIdentity?.routeId ??\n AppElementsWire.encodeRouteId(options.routePath, interceptionContext);\n const pageId =\n renderIdentity?.pageId ?? AppElementsWire.encodePageId(options.routePath, interceptionContext);\n const layoutEntries = createAppPageLayoutEntries(options.route);\n const templateEntries = createAppPageTemplateEntries(options.route);\n const errorEntries = createAppPageErrorEntries(options.route);\n const metadataPlacement = options.metadataPlacement ?? \"head\";\n const layoutEntriesByTreePosition = new Map<number, AppPageLayoutEntry<TModule, TErrorModule>>();\n const templateEntriesByTreePosition = new Map<number, AppPageTemplateEntry<TModule>>();\n const errorEntriesByTreePosition = new Map<number, AppPageErrorEntry<TErrorModule>>();\n for (const layoutEntry of layoutEntries) {\n layoutEntriesByTreePosition.set(layoutEntry.treePosition, layoutEntry);\n }\n for (const templateEntry of templateEntries) {\n templateEntriesByTreePosition.set(templateEntry.treePosition, templateEntry);\n }\n for (const errorEntry of errorEntries) {\n errorEntriesByTreePosition.set(errorEntry.treePosition, errorEntry);\n }\n const layoutIndicesByTreePosition = new Map<number, number>();\n for (let index = 0; index < layoutEntries.length; index++) {\n layoutIndicesByTreePosition.set(layoutEntries[index].treePosition, index);\n }\n const layoutDependenciesByIndex = new Map<number, AppRenderDependency>();\n const layoutDependenciesBefore: AppRenderDependency[][] = [];\n const slotDependenciesByLayoutIndex: AppRenderDependency[][] = [];\n const templateDependenciesById = new Map<string, AppRenderDependency>();\n const templateDependenciesBeforeById = new Map<string, AppRenderDependency[]>();\n const pageDependencies: AppRenderDependency[] = [];\n const rootLayoutTreePath = layoutEntries[0]?.treePath ?? null;\n const slotNameCounts = new Map<string, number>();\n for (const slot of Object.values(options.route.slots ?? {})) {\n const slotName = slot.name;\n slotNameCounts.set(slotName, (slotNameCounts.get(slotName) ?? 0) + 1);\n }\n const orderedTreePositions = Array.from(\n new Set<number>([\n ...layoutEntries.map((entry) => entry.treePosition),\n ...templateEntries.map((entry) => entry.treePosition),\n ...errorEntries.map((entry) => entry.treePosition),\n ]),\n ).sort((left, right) => left - right);\n const resolveSlotOverride = (slotKey: string, slotName: string) => {\n const overrideByKey = options.slotOverrides?.[slotKey];\n if (overrideByKey) {\n return overrideByKey;\n }\n\n // Legacy callers may still provide overrides by slot prop name.\n // Only allow that fallback when it is unambiguous.\n if (slotKey === slotName || (slotNameCounts.get(slotName) ?? 0) === 1) {\n return options.slotOverrides?.[slotName];\n }\n\n return undefined;\n };\n const elements: Record<\n string,\n | ReactNode\n | string\n | null\n | AppElementsInterception\n | readonly AppElementsSlotBinding[]\n | readonly string[]\n > = {\n ...AppElementsWire.createMetadataEntries({\n interception: renderIdentity?.interception ?? options.interception ?? null,\n interceptionContext,\n layoutIds: options.route.ids?.layouts ?? layoutEntries.map((entry) => entry.id),\n rootLayoutTreePath,\n routeId,\n slotBindings: createAppPageSlotBindings(options.route, layoutEntries, resolveSlotOverride),\n }),\n };\n // Surface static-sibling info on the wire so the client router can decide\n // whether a cached dynamic-route prefetch can be reused when navigating to a\n // static sibling URL. Mirrors Next.js's loader-tree `staticSiblings` tuple\n // element (issue cloudflare/vinext#1525). Only included when the route has\n // dynamic segments with static siblings — keeps the payload lean for\n // fully-static routes.\n if (options.route.staticSiblings && options.route.staticSiblings.length > 0) {\n elements[APP_STATIC_SIBLINGS_KEY] = options.route.staticSiblings;\n }\n const getEffectiveSlotParams = (slotKey: string, slotName: string): AppPageParams =>\n resolveSlotOverride(slotKey, slotName)?.params ?? options.matchedParams;\n\n for (const treePosition of orderedTreePositions) {\n const layoutIndex = layoutIndicesByTreePosition.get(treePosition);\n if (layoutIndex !== undefined) {\n const layoutEntry = layoutEntries[layoutIndex];\n layoutDependenciesBefore[layoutIndex] = [...pageDependencies];\n if (getDefaultExport(layoutEntry.layoutModule)) {\n const layoutDependency = createAppRenderDependency();\n layoutDependenciesByIndex.set(layoutIndex, layoutDependency);\n pageDependencies.push(layoutDependency);\n }\n slotDependenciesByLayoutIndex[layoutIndex] = [...pageDependencies];\n }\n\n const templateEntry = templateEntriesByTreePosition.get(treePosition);\n if (!templateEntry || !getDefaultExport(templateEntry.templateModule)) {\n continue;\n }\n\n const templateDependency = createAppRenderDependency();\n templateDependenciesById.set(templateEntry.id, templateDependency);\n templateDependenciesBeforeById.set(templateEntry.id, [...pageDependencies]);\n pageDependencies.push(templateDependency);\n }\n\n const routeLoadingComponent = getDefaultExport(options.route.loading);\n const isPrefetchLoadingShell = renderMode === APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;\n const shouldRenderPrefetchLoadingShell = isPrefetchLoadingShell && routeLoadingComponent !== null;\n if (shouldRenderPrefetchLoadingShell) {\n // Client loading components serialize as module references in Flight. Keep\n // a durable marker in the shell payload so external router tests and\n // diagnostics can recognize this as a loading-boundary response without\n // requiring source text to appear in client component references.\n elements[APP_PREFETCH_LOADING_SHELL_MARKER_KEY] = \"LoadingBoundary\";\n }\n\n elements[pageId] = isPrefetchLoadingShell\n ? null\n : renderAfterAppDependencies(options.element, pageDependencies);\n\n for (const templateEntry of templateEntries) {\n const templateComponent = getDefaultExport(templateEntry.templateModule);\n if (!templateComponent) {\n continue;\n }\n const TemplateComponent = templateComponent;\n const templateDependency = templateDependenciesById.get(templateEntry.id);\n const templateElement = templateDependency ? (\n renderWithAppDependencyBarrier(\n <TemplateComponent params={options.matchedParams}>\n <Children />\n </TemplateComponent>,\n templateDependency,\n )\n ) : (\n <TemplateComponent params={options.matchedParams}>\n <Children />\n </TemplateComponent>\n );\n elements[templateEntry.id] = renderAfterAppDependencies(\n templateElement,\n templateDependenciesBeforeById.get(templateEntry.id) ?? [],\n );\n }\n\n for (let index = 0; index < layoutEntries.length; index++) {\n const layoutEntry = layoutEntries[index];\n const layoutComponent = getDefaultExport(layoutEntry.layoutModule);\n if (!layoutComponent) {\n continue;\n }\n\n const layoutProps: Record<string, unknown> = {\n params: options.makeThenableParams(\n resolveAppPageSegmentParams(\n options.route.routeSegments,\n layoutEntry.treePosition,\n options.matchedParams,\n ),\n ),\n };\n\n for (const slot of Object.values(options.route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n if (targetIndex !== index) {\n continue;\n }\n layoutProps[slotName] = <ParallelSlot name={slotName} />;\n }\n\n const LayoutComponent = layoutComponent;\n const layoutDependency = layoutDependenciesByIndex.get(index);\n const layoutElement = layoutDependency ? (\n renderWithAppDependencyBarrier(\n <LayoutComponent {...layoutProps}>\n <Children />\n </LayoutComponent>,\n layoutDependency,\n )\n ) : (\n <LayoutComponent {...layoutProps}>\n <Children />\n </LayoutComponent>\n );\n elements[layoutEntry.id] = renderAfterAppDependencies(\n layoutElement,\n layoutDependenciesBefore[index] ?? [],\n );\n }\n\n for (const [slotKey, slot] of Object.entries(options.route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n const treePath = layoutEntries[targetIndex]?.treePath ?? \"/\";\n const slotId = resolveAppPageSlotId(slot, treePath);\n const slotOverride = resolveSlotOverride(slotKey, slotName);\n const slotParams = getEffectiveSlotParams(slotKey, slotName);\n const slotRouteSegments = slot.routeSegments ?? [];\n const slotResetKey = resolveAppPageRouteStateKey(slotRouteSegments, slotParams);\n const overrideOrPageComponent =\n getDefaultExport(slotOverride?.pageModule) ?? getDefaultExport(slot.page);\n const defaultComponent = getDefaultExport(slot.default);\n\n // On soft nav (RSC): omit key when only default.tsx exists and the slot is\n // already mounted on the client. Absent key means the browser retains prior\n // slot content rather than replacing it. When the slot is not yet mounted\n // (first entry into this layout), include the key so default.tsx renders.\n if (\n !overrideOrPageComponent &&\n defaultComponent &&\n options.isRscRequest &&\n options.mountedSlotIds?.has(slotId)\n ) {\n continue;\n }\n\n const slotComponent = overrideOrPageComponent ?? defaultComponent;\n\n if (!slotComponent) {\n elements[slotId] = AppElementsWire.unmatchedSlotValue;\n continue;\n }\n\n const slotThenableParams = options.makeThenableParams(slotParams);\n const slotProps: Record<string, unknown> = {\n params: slotThenableParams,\n };\n if (slotOverride?.props) {\n Object.assign(slotProps, slotOverride.props);\n }\n\n const SlotComponent = slotComponent;\n let slotElement: ReactNode = <SlotComponent {...slotProps} />;\n const interceptLayouts = slotOverride?.layoutModules ?? [];\n\n for (let layoutIndex = interceptLayouts.length - 1; layoutIndex >= 0; layoutIndex--) {\n const interceptLayoutComponent = getDefaultExport(interceptLayouts[layoutIndex]);\n if (!interceptLayoutComponent) {\n continue;\n }\n const InterceptLayoutComponent = interceptLayoutComponent;\n slotElement = (\n <InterceptLayoutComponent params={slotThenableParams}>\n {slotElement}\n </InterceptLayoutComponent>\n );\n }\n\n const slotLayoutComponent = getDefaultExport(slot.layout);\n if (slotLayoutComponent) {\n const SlotLayoutComponent = slotLayoutComponent;\n slotElement = (\n <SlotLayoutComponent params={slotThenableParams}>{slotElement}</SlotLayoutComponent>\n );\n }\n\n const slotLoadingComponent = getDefaultExport(slot.loading);\n if (slotLoadingComponent && !shouldSuppressLoadingBoundaries(renderMode)) {\n const SlotLoadingComponent = slotLoadingComponent;\n slotElement = (\n <Suspense key={slotResetKey} fallback={<SlotLoadingComponent />}>\n {slotElement}\n </Suspense>\n );\n }\n\n const slotErrorComponent = getErrorBoundaryExport(slot.error);\n if (slotErrorComponent) {\n slotElement = (\n <ErrorBoundary resetKey={slotResetKey} fallback={slotErrorComponent}>\n {slotElement}\n </ErrorBoundary>\n );\n }\n\n elements[slotId] = renderAfterAppDependencies(\n slotElement,\n targetIndex >= 0 ? (slotDependenciesByLayoutIndex[targetIndex] ?? []) : [],\n );\n }\n\n let routeChildren: ReactNode = (\n <LayoutSegmentProvider segmentMap={{ children: [] }}>\n <AppRouterScrollTarget>\n <Slot id={pageId} />\n </AppRouterScrollTarget>\n </LayoutSegmentProvider>\n );\n\n if (isPrefetchLoadingShell) {\n if (routeLoadingComponent === null) {\n routeChildren = null;\n } else {\n const RouteLoadingComponent = routeLoadingComponent;\n routeChildren = <RouteLoadingComponent />;\n }\n } else {\n // Wrap the page slot in a per-segment RedirectBoundary so that a\n // redirect() thrown from a server component (or a client component\n // within the page subtree) is caught here — below the route's layouts —\n // rather than at the top-level boundary in app-browser-entry. Catching\n // at the top level unmounts the entire route tree including layouts,\n // which destroys client-side state in layout-hosted components\n // (counters, theme toggles, form drafts). Here, only the page subtree\n // is unmounted; the surrounding layouts stay mounted across the\n // boundary's null-render → router.replace transition, and segment\n // reuse keeps their React state intact.\n //\n // Placed inside the Suspense (loading) boundary to match Next.js nesting\n // for the redirect boundary specifically:\n // Error > AccessFallback > Loading (Suspense) > Redirect > content\n // (Note: Next.js places AccessFallback inside Loading, not outside — that\n // is a pre-existing nesting divergence tracked separately.)\n // This keeps the loading fallback visible during redirect-driven\n // transitions rather than unmounting it.\n routeChildren = <RedirectBoundary>{routeChildren}</RedirectBoundary>;\n\n if (routeLoadingComponent && !shouldSuppressLoadingBoundaries(renderMode)) {\n const RouteLoadingComponent = routeLoadingComponent;\n // Route-level wrappers cover the full page branch in vinext's flat element\n // transport, so their reset key includes the visible segment-state path.\n // Dynamic param changes reset the pending boundary, while search-only changes\n // preserve it.\n routeChildren = (\n <Suspense key={routeResetKey} fallback={<RouteLoadingComponent />}>\n {routeChildren}\n </Suspense>\n );\n }\n }\n\n const lastLayoutErrorModule =\n errorEntries.length > 0 ? errorEntries[errorEntries.length - 1].errorModule : null;\n // Next.js nesting (outer to inner): Error > Unauthorized > Forbidden > NotFound > children.\n // Building bottom-up means NotFoundBoundary must wrap first, then Forbidden, Unauthorized, Error.\n const notFoundComponent =\n getDefaultExport(options.route.notFound) ?? getDefaultExport(options.rootNotFoundModule);\n if (notFoundComponent) {\n const NotFoundComponent = notFoundComponent;\n routeChildren = (\n <NotFoundBoundary resetKey={routeResetKey} fallback={<NotFoundComponent />}>\n {routeChildren}\n </NotFoundBoundary>\n );\n }\n\n const forbiddenComponent =\n getDefaultExport(options.route.forbidden) ?? getDefaultExport(options.rootForbiddenModule);\n if (forbiddenComponent) {\n const ForbiddenComponent = forbiddenComponent;\n routeChildren = (\n <ForbiddenBoundary resetKey={routeResetKey} fallback={<ForbiddenComponent />}>\n {routeChildren}\n </ForbiddenBoundary>\n );\n }\n\n const unauthorizedComponent =\n getDefaultExport(options.route.unauthorized) ??\n getDefaultExport(options.rootUnauthorizedModule);\n if (unauthorizedComponent) {\n const UnauthorizedComponent = unauthorizedComponent;\n routeChildren = (\n <UnauthorizedBoundary resetKey={routeResetKey} fallback={<UnauthorizedComponent />}>\n {routeChildren}\n </UnauthorizedBoundary>\n );\n }\n\n const pageErrorComponent = getErrorBoundaryExport(options.route.error);\n if (pageErrorComponent && options.route.error !== lastLayoutErrorModule) {\n routeChildren = (\n <ErrorBoundary resetKey={routeResetKey} fallback={pageErrorComponent}>\n {routeChildren}\n </ErrorBoundary>\n );\n }\n\n for (let index = orderedTreePositions.length - 1; index >= 0; index--) {\n const treePosition = orderedTreePositions[index];\n const segmentResetKey = resolveAppPageSegmentStateKey(\n routeSegments,\n treePosition,\n options.matchedParams,\n );\n let segmentChildren: ReactNode = routeChildren;\n const layoutEntry = layoutEntriesByTreePosition.get(treePosition);\n const templateEntry = templateEntriesByTreePosition.get(treePosition);\n const errorEntry = errorEntriesByTreePosition.get(treePosition);\n\n // Next.js nesting per segment (outer to inner): Layout > Template > Error > Unauthorized > Forbidden > NotFound > children.\n // Building bottom-up means NotFoundBoundary must wrap the leaf subtree first,\n // then ErrorBoundary, then Template, with the Layout slot outermost.\n if (layoutEntry) {\n const layoutNotFoundComponent = getDefaultExport(layoutEntry.notFoundModule);\n if (layoutNotFoundComponent) {\n const LayoutNotFoundComponent = layoutNotFoundComponent;\n segmentChildren = (\n <NotFoundBoundary resetKey={segmentResetKey} fallback={<LayoutNotFoundComponent />}>\n {segmentChildren}\n </NotFoundBoundary>\n );\n }\n\n const layoutForbiddenComponent = getDefaultExport(layoutEntry.forbiddenModule);\n if (layoutForbiddenComponent) {\n const LayoutForbiddenComponent = layoutForbiddenComponent;\n segmentChildren = (\n <ForbiddenBoundary resetKey={segmentResetKey} fallback={<LayoutForbiddenComponent />}>\n {segmentChildren}\n </ForbiddenBoundary>\n );\n }\n\n const layoutUnauthorizedComponent = getDefaultExport(layoutEntry.unauthorizedModule);\n if (layoutUnauthorizedComponent) {\n const LayoutUnauthorizedComponent = layoutUnauthorizedComponent;\n segmentChildren = (\n <UnauthorizedBoundary\n resetKey={segmentResetKey}\n fallback={<LayoutUnauthorizedComponent />}\n >\n {segmentChildren}\n </UnauthorizedBoundary>\n );\n }\n }\n\n const segmentErrorComponent = getErrorBoundaryExport(\n errorEntry?.errorModule ?? layoutEntry?.errorModule,\n );\n if (segmentErrorComponent) {\n segmentChildren = (\n <ErrorBoundary resetKey={segmentResetKey} fallback={segmentErrorComponent}>\n {segmentChildren}\n </ErrorBoundary>\n );\n }\n\n if (templateEntry && getDefaultExport(templateEntry.templateModule)) {\n segmentChildren = (\n <Slot id={templateEntry.id} key={segmentResetKey}>\n {segmentChildren}\n </Slot>\n );\n }\n\n if (!layoutEntry) {\n routeChildren = segmentChildren;\n continue;\n }\n const layoutHasElement = getDefaultExport(layoutEntry.layoutModule) !== null;\n const layoutIndex = layoutIndicesByTreePosition.get(treePosition) ?? -1;\n const segmentMap: { children: string[] } & Record<string, string[]> = {\n children: resolveAppPageChildSegments(\n routeSegments,\n layoutEntry.treePosition,\n options.matchedParams,\n ),\n };\n for (const [slotKey, slot] of Object.entries(options.route.slots ?? {})) {\n const slotName = slot.name;\n const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;\n if (targetIndex !== layoutIndex) {\n continue;\n }\n const slotParams = getEffectiveSlotParams(slotKey, slotName);\n segmentMap[slotName] = slot.routeSegments\n ? resolveAppPageChildSegments(slot.routeSegments, 0, slotParams)\n : [];\n }\n\n routeChildren = (\n <LayoutSegmentProvider segmentMap={segmentMap}>\n {layoutHasElement ? (\n <Slot\n id={layoutEntry.id}\n parallelSlots={createAppPageParallelSlotEntries(\n layoutIndex,\n layoutEntries,\n options.route,\n getEffectiveSlotParams,\n )}\n >\n {segmentChildren}\n </Slot>\n ) : (\n segmentChildren\n )}\n </LayoutSegmentProvider>\n );\n }\n\n const globalErrorComponent = getErrorBoundaryExport(options.globalErrorModule);\n if (globalErrorComponent) {\n routeChildren = <ErrorBoundary fallback={globalErrorComponent}>{routeChildren}</ErrorBoundary>;\n }\n\n elements[routeId] = (\n <>\n {createAppPageRouteHead(\n options.resolvedMetadata,\n options.resolvedViewport,\n options.resolvedMetadataPathname ?? options.routePath,\n metadataPlacement,\n )}\n {routeChildren}\n {createAppPageRouteBodyMetadata(\n options.resolvedMetadata,\n options.resolvedMetadataPathname ?? options.routePath,\n metadataPlacement,\n )}\n </>\n );\n\n return elements;\n}\n"],"mappings":"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"}
|
|
@@ -18,6 +18,11 @@ type AppPageSsrHandler = {
|
|
|
18
18
|
formState?: ReactFormState | null;
|
|
19
19
|
scriptNonce?: string;
|
|
20
20
|
basePath?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Allow-list of OpenTelemetry propagation keys to emit as `<meta>` tags
|
|
23
|
+
* in the SSR head. Sourced from `experimental.clientTraceMetadata`.
|
|
24
|
+
*/
|
|
25
|
+
clientTraceMetadata?: readonly string[];
|
|
21
26
|
rootParams?: RootParams;
|
|
22
27
|
sideStream?: ReadableStream<Uint8Array>;
|
|
23
28
|
capturedRscDataRef?: {
|
|
@@ -33,6 +38,12 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
33
38
|
rscStream: ReadableStream<Uint8Array>;
|
|
34
39
|
scriptNonce?: string;
|
|
35
40
|
basePath?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Allow-list of OpenTelemetry propagation keys (from
|
|
43
|
+
* `experimental.clientTraceMetadata`) to surface as `<meta>` tags in
|
|
44
|
+
* the SSR head. Undefined or empty disables emission.
|
|
45
|
+
*/
|
|
46
|
+
clientTraceMetadata?: readonly string[];
|
|
36
47
|
rootParams?: RootParams;
|
|
37
48
|
ssrHandler: AppPageSsrHandler;
|
|
38
49
|
/** Pre-split side stream for fused embed+capture (#981). When set,
|
|
@@ -14,6 +14,7 @@ async function renderAppPageHtmlStream(options) {
|
|
|
14
14
|
formState: options.formState ?? null,
|
|
15
15
|
scriptNonce: options.scriptNonce,
|
|
16
16
|
basePath: options.basePath,
|
|
17
|
+
clientTraceMetadata: options.clientTraceMetadata,
|
|
17
18
|
rootParams: options.rootParams,
|
|
18
19
|
sideStream: options.sideStream,
|
|
19
20
|
capturedRscDataRef: options.capturedRscDataRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-stream.js","names":[],"sources":["../../src/server/app-page-stream.ts"],"sourcesContent":["import type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport { VINEXT_RSC_VARY_HEADER } from \"./app-rsc-cache-busting.js\";\nimport { applyEdgeRuntimeHeader } from \"./app-page-response.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport type { RootParams } from \"vinext/shims/root-params\";\n\nexport type AppPageFontData = {\n links: string[];\n preloads: readonly AppPageFontPreload[];\n styles: string[];\n};\n\ntype CreateAppPageFontDataOptions = {\n getLinks: () => string[];\n getPreloads: () => AppPageFontPreload[];\n getStyles: () => string[];\n};\n\nexport type AppPageSsrHandler = {\n handleSsr: (\n rscStream: ReadableStream<Uint8Array>,\n navigationContext: unknown,\n fontData: AppPageFontData,\n options?: {\n formState?: ReactFormState | null;\n scriptNonce?: string;\n basePath?: string;\n rootParams?: RootParams;\n sideStream?: ReadableStream<Uint8Array>;\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n /** When true, wait for the full React tree before emitting bytes. */\n waitForAllReady?: boolean;\n },\n ) => Promise<ReadableStream<Uint8Array>>;\n};\n\ntype RenderAppPageHtmlStreamOptions = {\n fontData: AppPageFontData;\n formState?: ReactFormState | null;\n navigationContext: unknown;\n rscStream: ReadableStream<Uint8Array>;\n scriptNonce?: string;\n basePath?: string;\n rootParams?: RootParams;\n ssrHandler: AppPageSsrHandler;\n /** Pre-split side stream for fused embed+capture (#981). When set,\n * handleSsr skips its internal tee and accumulates raw RSC bytes. */\n sideStream?: ReadableStream<Uint8Array>;\n /** Out-parameter filled with accumulated raw RSC bytes after stream consumption. */\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n /** When true, wait for the full React tree before emitting bytes. */\n waitForAllReady?: boolean;\n};\n\ntype RenderAppPageHtmlResponseOptions = {\n clearRequestContext: () => void;\n fontLinkHeader?: string;\n isEdgeRuntime?: boolean;\n middlewareHeaders?: Headers | null;\n status: number;\n} & RenderAppPageHtmlStreamOptions;\n\ntype AppPageHtmlStreamRecoveryResult = {\n htmlStream: ReadableStream<Uint8Array> | null;\n response: Response | null;\n};\n\ntype RenderAppPageHtmlStreamWithRecoveryOptions<TSpecialError> = {\n onShellRendered?: () => void;\n renderErrorBoundaryResponse: (error: unknown) => Promise<Response | null>;\n renderHtmlStream: () => Promise<ReadableStream<Uint8Array>>;\n renderSpecialErrorResponse: (specialError: TSpecialError) => Promise<Response>;\n resolveSpecialError: (error: unknown) => TSpecialError | null;\n};\n\ntype AppPageRscErrorTracker = {\n getCapturedError: () => unknown;\n /**\n * Returns a NEXT_REDIRECT or NEXT_HTTP_ERROR_FALLBACK error captured during\n * the RSC render. Read after the SSR shell promise resolves to swap a\n * 307/404 in place of the streamed body when redirect()/notFound() throws\n * synchronously inside a route-level Suspense boundary (loading.tsx).\n */\n getCapturedSpecialError: () => unknown;\n onRenderError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;\n};\n\ntype ShouldRerenderAppPageWithGlobalErrorOptions = {\n capturedError: unknown;\n hasLocalBoundary: boolean;\n};\n\nexport function createAppPageFontData(options: CreateAppPageFontDataOptions): AppPageFontData {\n return {\n links: options.getLinks(),\n preloads: options.getPreloads(),\n styles: options.getStyles(),\n };\n}\n\nexport async function renderAppPageHtmlStream(\n options: RenderAppPageHtmlStreamOptions,\n): Promise<ReadableStream<Uint8Array>> {\n const ssrOptions = {\n formState: options.formState ?? null,\n scriptNonce: options.scriptNonce,\n basePath: options.basePath,\n rootParams: options.rootParams,\n sideStream: options.sideStream,\n capturedRscDataRef: options.capturedRscDataRef,\n waitForAllReady: options.waitForAllReady,\n };\n\n return options.ssrHandler.handleSsr(\n options.rscStream,\n options.navigationContext,\n options.fontData,\n ssrOptions,\n );\n}\n\n/**\n * Wraps a stream so that `onFlush` is called when the last byte has been read\n * by the downstream consumer (i.e. when the HTTP layer finishes draining the\n * response body). This is the correct place to clear per-request context,\n * because the RSC/SSR pipeline is lazy — components execute while the stream\n * is being consumed, not when the stream handle is first obtained.\n */\nexport function deferUntilStreamConsumed(\n stream: ReadableStream<Uint8Array>,\n onFlush: () => void,\n): ReadableStream<Uint8Array> {\n let called = false;\n const once = () => {\n if (!called) {\n called = true;\n onFlush();\n }\n };\n\n const cleanup = new TransformStream<Uint8Array, Uint8Array>({\n flush() {\n once();\n },\n });\n\n const piped = stream.pipeThrough(cleanup);\n\n // Wrap with a ReadableStream so we can intercept cancel() — the TransformStream\n // Transformer interface does not expose a cancel hook in the Web Streams spec.\n const reader = piped.getReader();\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n return reader.read().then(\n ({ done, value }) => {\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n },\n (error) => {\n once();\n controller.error(error);\n },\n );\n },\n cancel(reason) {\n // Stream cancelled before fully consumed (e.g. client disconnected).\n // Still clear per-request context to avoid leaks.\n once();\n return reader.cancel(reason);\n },\n });\n}\n\nexport async function renderAppPageHtmlResponse(\n options: RenderAppPageHtmlResponseOptions,\n): Promise<Response> {\n const htmlStream = await renderAppPageHtmlStream(options);\n\n // Defer clearRequestContext() until the stream is fully consumed by the HTTP\n // layer. Calling it synchronously here would race the lazy RSC/SSR pipeline:\n // components execute while the stream is being pulled, not when the handle\n // is first returned. See: https://github.com/cloudflare/vinext/issues/660\n const safeStream = deferUntilStreamConsumed(htmlStream, () => {\n options.clearRequestContext();\n });\n\n const headers = new Headers({\n \"Content-Type\": \"text/html; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n\n applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);\n\n if (options.fontLinkHeader) {\n headers.set(\"Link\", options.fontLinkHeader);\n }\n\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return new Response(safeStream, {\n status: options.status,\n headers,\n });\n}\n\nexport async function renderAppPageHtmlStreamWithRecovery<TSpecialError>(\n options: RenderAppPageHtmlStreamWithRecoveryOptions<TSpecialError>,\n): Promise<AppPageHtmlStreamRecoveryResult> {\n try {\n const htmlStream = await options.renderHtmlStream();\n options.onShellRendered?.();\n return {\n htmlStream,\n response: null,\n };\n } catch (error) {\n const specialError = options.resolveSpecialError(error);\n if (specialError) {\n return {\n htmlStream: null,\n response: await options.renderSpecialErrorResponse(specialError),\n };\n }\n\n const boundaryResponse = await options.renderErrorBoundaryResponse(error);\n if (boundaryResponse) {\n return {\n htmlStream: null,\n response: boundaryResponse,\n };\n }\n\n throw error;\n }\n}\n\nexport function createAppPageRscErrorTracker(\n baseOnError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown,\n): AppPageRscErrorTracker {\n let capturedError: unknown = null;\n let capturedSpecialError: unknown = null;\n\n return {\n getCapturedError() {\n return capturedError;\n },\n getCapturedSpecialError() {\n return capturedSpecialError;\n },\n onRenderError(error, requestInfo, errorContext) {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n // Errors with a digest are signal throws (NEXT_REDIRECT,\n // NEXT_NOT_FOUND, NEXT_HTTP_ERROR_FALLBACK). They're not real\n // failures — keep the first one so the lifecycle can swap a\n // 307/404 in place of a streamed \"Switched to client rendering\"\n // body for routes with a route-level Suspense boundary.\n if (capturedSpecialError === null) {\n capturedSpecialError = error;\n }\n } else {\n capturedError = error;\n }\n return baseOnError(error, requestInfo, errorContext);\n },\n };\n}\n\nexport function shouldRerenderAppPageWithGlobalError(\n options: ShouldRerenderAppPageWithGlobalErrorOptions,\n): boolean {\n return Boolean(options.capturedError) && !options.hasLocalBoundary;\n}\n"],"mappings":";;;;AA6FA,SAAgB,sBAAsB,SAAwD;CAC5F,OAAO;EACL,OAAO,QAAQ,UAAU;EACzB,UAAU,QAAQ,aAAa;EAC/B,QAAQ,QAAQ,WAAW;EAC5B;;AAGH,eAAsB,wBACpB,SACqC;CACrC,MAAM,aAAa;EACjB,WAAW,QAAQ,aAAa;EAChC,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,YAAY,QAAQ;EACpB,YAAY,QAAQ;EACpB,oBAAoB,QAAQ;EAC5B,iBAAiB,QAAQ;EAC1B;CAED,OAAO,QAAQ,WAAW,UACxB,QAAQ,WACR,QAAQ,mBACR,QAAQ,UACR,WACD;;;;;;;;;AAUH,SAAgB,yBACd,QACA,SAC4B;CAC5B,IAAI,SAAS;CACb,MAAM,aAAa;EACjB,IAAI,CAAC,QAAQ;GACX,SAAS;GACT,SAAS;;;CAIb,MAAM,UAAU,IAAI,gBAAwC,EAC1D,QAAQ;EACN,MAAM;IAET,CAAC;CAMF,MAAM,SAJQ,OAAO,YAAY,QAIb,CAAC,WAAW;CAChC,OAAO,IAAI,eAA2B;EACpC,KAAK,YAAY;GACf,OAAO,OAAO,MAAM,CAAC,MAClB,EAAE,MAAM,YAAY;IACnB,IAAI,MACF,WAAW,OAAO;SAElB,WAAW,QAAQ,MAAM;OAG5B,UAAU;IACT,MAAM;IACN,WAAW,MAAM,MAAM;KAE1B;;EAEH,OAAO,QAAQ;GAGb,MAAM;GACN,OAAO,OAAO,OAAO,OAAO;;EAE/B,CAAC;;AAGJ,eAAsB,0BACpB,SACmB;CAOnB,MAAM,aAAa,yBAAyB,MANnB,wBAAwB,QAAQ,QAMK;EAC5D,QAAQ,qBAAqB;GAC7B;CAEF,MAAM,UAAU,IAAI,QAAQ;EAC1B,gBAAgB;EAChB,MAAM;EACP,CAAC;CAEF,uBAAuB,SAAS,QAAQ,cAAc;CAEtD,IAAI,QAAQ,gBACV,QAAQ,IAAI,QAAQ,QAAQ,eAAe;CAG7C,+BAA+B,SAAS,QAAQ,qBAAqB,KAAK;CAE1E,OAAO,IAAI,SAAS,YAAY;EAC9B,QAAQ,QAAQ;EAChB;EACD,CAAC;;AAGJ,eAAsB,oCACpB,SAC0C;CAC1C,IAAI;EACF,MAAM,aAAa,MAAM,QAAQ,kBAAkB;EACnD,QAAQ,mBAAmB;EAC3B,OAAO;GACL;GACA,UAAU;GACX;UACM,OAAO;EACd,MAAM,eAAe,QAAQ,oBAAoB,MAAM;EACvD,IAAI,cACF,OAAO;GACL,YAAY;GACZ,UAAU,MAAM,QAAQ,2BAA2B,aAAa;GACjE;EAGH,MAAM,mBAAmB,MAAM,QAAQ,4BAA4B,MAAM;EACzE,IAAI,kBACF,OAAO;GACL,YAAY;GACZ,UAAU;GACX;EAGH,MAAM;;;AAIV,SAAgB,6BACd,aACwB;CACxB,IAAI,gBAAyB;CAC7B,IAAI,uBAAgC;CAEpC,OAAO;EACL,mBAAmB;GACjB,OAAO;;EAET,0BAA0B;GACxB,OAAO;;EAET,cAAc,OAAO,aAAa,cAAc;GAC9C,IAAI,SAAS,OAAO,UAAU,YAAY,YAAY;QAMhD,yBAAyB,MAC3B,uBAAuB;UAGzB,gBAAgB;GAElB,OAAO,YAAY,OAAO,aAAa,aAAa;;EAEvD;;AAGH,SAAgB,qCACd,SACS;CACT,OAAO,QAAQ,QAAQ,cAAc,IAAI,CAAC,QAAQ"}
|
|
1
|
+
{"version":3,"file":"app-page-stream.js","names":[],"sources":["../../src/server/app-page-stream.ts"],"sourcesContent":["import type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport { VINEXT_RSC_VARY_HEADER } from \"./app-rsc-cache-busting.js\";\nimport { applyEdgeRuntimeHeader } from \"./app-page-response.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport type { RootParams } from \"vinext/shims/root-params\";\n\nexport type AppPageFontData = {\n links: string[];\n preloads: readonly AppPageFontPreload[];\n styles: string[];\n};\n\ntype CreateAppPageFontDataOptions = {\n getLinks: () => string[];\n getPreloads: () => AppPageFontPreload[];\n getStyles: () => string[];\n};\n\nexport type AppPageSsrHandler = {\n handleSsr: (\n rscStream: ReadableStream<Uint8Array>,\n navigationContext: unknown,\n fontData: AppPageFontData,\n options?: {\n formState?: ReactFormState | null;\n scriptNonce?: string;\n basePath?: string;\n /**\n * Allow-list of OpenTelemetry propagation keys to emit as `<meta>` tags\n * in the SSR head. Sourced from `experimental.clientTraceMetadata`.\n */\n clientTraceMetadata?: readonly string[];\n rootParams?: RootParams;\n sideStream?: ReadableStream<Uint8Array>;\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n /** When true, wait for the full React tree before emitting bytes. */\n waitForAllReady?: boolean;\n },\n ) => Promise<ReadableStream<Uint8Array>>;\n};\n\ntype RenderAppPageHtmlStreamOptions = {\n fontData: AppPageFontData;\n formState?: ReactFormState | null;\n navigationContext: unknown;\n rscStream: ReadableStream<Uint8Array>;\n scriptNonce?: string;\n basePath?: string;\n /**\n * Allow-list of OpenTelemetry propagation keys (from\n * `experimental.clientTraceMetadata`) to surface as `<meta>` tags in\n * the SSR head. Undefined or empty disables emission.\n */\n clientTraceMetadata?: readonly string[];\n rootParams?: RootParams;\n ssrHandler: AppPageSsrHandler;\n /** Pre-split side stream for fused embed+capture (#981). When set,\n * handleSsr skips its internal tee and accumulates raw RSC bytes. */\n sideStream?: ReadableStream<Uint8Array>;\n /** Out-parameter filled with accumulated raw RSC bytes after stream consumption. */\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n /** When true, wait for the full React tree before emitting bytes. */\n waitForAllReady?: boolean;\n};\n\ntype RenderAppPageHtmlResponseOptions = {\n clearRequestContext: () => void;\n fontLinkHeader?: string;\n isEdgeRuntime?: boolean;\n middlewareHeaders?: Headers | null;\n status: number;\n} & RenderAppPageHtmlStreamOptions;\n\ntype AppPageHtmlStreamRecoveryResult = {\n htmlStream: ReadableStream<Uint8Array> | null;\n response: Response | null;\n};\n\ntype RenderAppPageHtmlStreamWithRecoveryOptions<TSpecialError> = {\n onShellRendered?: () => void;\n renderErrorBoundaryResponse: (error: unknown) => Promise<Response | null>;\n renderHtmlStream: () => Promise<ReadableStream<Uint8Array>>;\n renderSpecialErrorResponse: (specialError: TSpecialError) => Promise<Response>;\n resolveSpecialError: (error: unknown) => TSpecialError | null;\n};\n\ntype AppPageRscErrorTracker = {\n getCapturedError: () => unknown;\n /**\n * Returns a NEXT_REDIRECT or NEXT_HTTP_ERROR_FALLBACK error captured during\n * the RSC render. Read after the SSR shell promise resolves to swap a\n * 307/404 in place of the streamed body when redirect()/notFound() throws\n * synchronously inside a route-level Suspense boundary (loading.tsx).\n */\n getCapturedSpecialError: () => unknown;\n onRenderError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;\n};\n\ntype ShouldRerenderAppPageWithGlobalErrorOptions = {\n capturedError: unknown;\n hasLocalBoundary: boolean;\n};\n\nexport function createAppPageFontData(options: CreateAppPageFontDataOptions): AppPageFontData {\n return {\n links: options.getLinks(),\n preloads: options.getPreloads(),\n styles: options.getStyles(),\n };\n}\n\nexport async function renderAppPageHtmlStream(\n options: RenderAppPageHtmlStreamOptions,\n): Promise<ReadableStream<Uint8Array>> {\n const ssrOptions = {\n formState: options.formState ?? null,\n scriptNonce: options.scriptNonce,\n basePath: options.basePath,\n clientTraceMetadata: options.clientTraceMetadata,\n rootParams: options.rootParams,\n sideStream: options.sideStream,\n capturedRscDataRef: options.capturedRscDataRef,\n waitForAllReady: options.waitForAllReady,\n };\n\n return options.ssrHandler.handleSsr(\n options.rscStream,\n options.navigationContext,\n options.fontData,\n ssrOptions,\n );\n}\n\n/**\n * Wraps a stream so that `onFlush` is called when the last byte has been read\n * by the downstream consumer (i.e. when the HTTP layer finishes draining the\n * response body). This is the correct place to clear per-request context,\n * because the RSC/SSR pipeline is lazy — components execute while the stream\n * is being consumed, not when the stream handle is first obtained.\n */\nexport function deferUntilStreamConsumed(\n stream: ReadableStream<Uint8Array>,\n onFlush: () => void,\n): ReadableStream<Uint8Array> {\n let called = false;\n const once = () => {\n if (!called) {\n called = true;\n onFlush();\n }\n };\n\n const cleanup = new TransformStream<Uint8Array, Uint8Array>({\n flush() {\n once();\n },\n });\n\n const piped = stream.pipeThrough(cleanup);\n\n // Wrap with a ReadableStream so we can intercept cancel() — the TransformStream\n // Transformer interface does not expose a cancel hook in the Web Streams spec.\n const reader = piped.getReader();\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n return reader.read().then(\n ({ done, value }) => {\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n },\n (error) => {\n once();\n controller.error(error);\n },\n );\n },\n cancel(reason) {\n // Stream cancelled before fully consumed (e.g. client disconnected).\n // Still clear per-request context to avoid leaks.\n once();\n return reader.cancel(reason);\n },\n });\n}\n\nexport async function renderAppPageHtmlResponse(\n options: RenderAppPageHtmlResponseOptions,\n): Promise<Response> {\n const htmlStream = await renderAppPageHtmlStream(options);\n\n // Defer clearRequestContext() until the stream is fully consumed by the HTTP\n // layer. Calling it synchronously here would race the lazy RSC/SSR pipeline:\n // components execute while the stream is being pulled, not when the handle\n // is first returned. See: https://github.com/cloudflare/vinext/issues/660\n const safeStream = deferUntilStreamConsumed(htmlStream, () => {\n options.clearRequestContext();\n });\n\n const headers = new Headers({\n \"Content-Type\": \"text/html; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n\n applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);\n\n if (options.fontLinkHeader) {\n headers.set(\"Link\", options.fontLinkHeader);\n }\n\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return new Response(safeStream, {\n status: options.status,\n headers,\n });\n}\n\nexport async function renderAppPageHtmlStreamWithRecovery<TSpecialError>(\n options: RenderAppPageHtmlStreamWithRecoveryOptions<TSpecialError>,\n): Promise<AppPageHtmlStreamRecoveryResult> {\n try {\n const htmlStream = await options.renderHtmlStream();\n options.onShellRendered?.();\n return {\n htmlStream,\n response: null,\n };\n } catch (error) {\n const specialError = options.resolveSpecialError(error);\n if (specialError) {\n return {\n htmlStream: null,\n response: await options.renderSpecialErrorResponse(specialError),\n };\n }\n\n const boundaryResponse = await options.renderErrorBoundaryResponse(error);\n if (boundaryResponse) {\n return {\n htmlStream: null,\n response: boundaryResponse,\n };\n }\n\n throw error;\n }\n}\n\nexport function createAppPageRscErrorTracker(\n baseOnError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown,\n): AppPageRscErrorTracker {\n let capturedError: unknown = null;\n let capturedSpecialError: unknown = null;\n\n return {\n getCapturedError() {\n return capturedError;\n },\n getCapturedSpecialError() {\n return capturedSpecialError;\n },\n onRenderError(error, requestInfo, errorContext) {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n // Errors with a digest are signal throws (NEXT_REDIRECT,\n // NEXT_NOT_FOUND, NEXT_HTTP_ERROR_FALLBACK). They're not real\n // failures — keep the first one so the lifecycle can swap a\n // 307/404 in place of a streamed \"Switched to client rendering\"\n // body for routes with a route-level Suspense boundary.\n if (capturedSpecialError === null) {\n capturedSpecialError = error;\n }\n } else {\n capturedError = error;\n }\n return baseOnError(error, requestInfo, errorContext);\n },\n };\n}\n\nexport function shouldRerenderAppPageWithGlobalError(\n options: ShouldRerenderAppPageWithGlobalErrorOptions,\n): boolean {\n return Boolean(options.capturedError) && !options.hasLocalBoundary;\n}\n"],"mappings":";;;;AAwGA,SAAgB,sBAAsB,SAAwD;CAC5F,OAAO;EACL,OAAO,QAAQ,UAAU;EACzB,UAAU,QAAQ,aAAa;EAC/B,QAAQ,QAAQ,WAAW;EAC5B;;AAGH,eAAsB,wBACpB,SACqC;CACrC,MAAM,aAAa;EACjB,WAAW,QAAQ,aAAa;EAChC,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,qBAAqB,QAAQ;EAC7B,YAAY,QAAQ;EACpB,YAAY,QAAQ;EACpB,oBAAoB,QAAQ;EAC5B,iBAAiB,QAAQ;EAC1B;CAED,OAAO,QAAQ,WAAW,UACxB,QAAQ,WACR,QAAQ,mBACR,QAAQ,UACR,WACD;;;;;;;;;AAUH,SAAgB,yBACd,QACA,SAC4B;CAC5B,IAAI,SAAS;CACb,MAAM,aAAa;EACjB,IAAI,CAAC,QAAQ;GACX,SAAS;GACT,SAAS;;;CAIb,MAAM,UAAU,IAAI,gBAAwC,EAC1D,QAAQ;EACN,MAAM;IAET,CAAC;CAMF,MAAM,SAJQ,OAAO,YAAY,QAIb,CAAC,WAAW;CAChC,OAAO,IAAI,eAA2B;EACpC,KAAK,YAAY;GACf,OAAO,OAAO,MAAM,CAAC,MAClB,EAAE,MAAM,YAAY;IACnB,IAAI,MACF,WAAW,OAAO;SAElB,WAAW,QAAQ,MAAM;OAG5B,UAAU;IACT,MAAM;IACN,WAAW,MAAM,MAAM;KAE1B;;EAEH,OAAO,QAAQ;GAGb,MAAM;GACN,OAAO,OAAO,OAAO,OAAO;;EAE/B,CAAC;;AAGJ,eAAsB,0BACpB,SACmB;CAOnB,MAAM,aAAa,yBAAyB,MANnB,wBAAwB,QAAQ,QAMK;EAC5D,QAAQ,qBAAqB;GAC7B;CAEF,MAAM,UAAU,IAAI,QAAQ;EAC1B,gBAAgB;EAChB,MAAM;EACP,CAAC;CAEF,uBAAuB,SAAS,QAAQ,cAAc;CAEtD,IAAI,QAAQ,gBACV,QAAQ,IAAI,QAAQ,QAAQ,eAAe;CAG7C,+BAA+B,SAAS,QAAQ,qBAAqB,KAAK;CAE1E,OAAO,IAAI,SAAS,YAAY;EAC9B,QAAQ,QAAQ;EAChB;EACD,CAAC;;AAGJ,eAAsB,oCACpB,SAC0C;CAC1C,IAAI;EACF,MAAM,aAAa,MAAM,QAAQ,kBAAkB;EACnD,QAAQ,mBAAmB;EAC3B,OAAO;GACL;GACA,UAAU;GACX;UACM,OAAO;EACd,MAAM,eAAe,QAAQ,oBAAoB,MAAM;EACvD,IAAI,cACF,OAAO;GACL,YAAY;GACZ,UAAU,MAAM,QAAQ,2BAA2B,aAAa;GACjE;EAGH,MAAM,mBAAmB,MAAM,QAAQ,4BAA4B,MAAM;EACzE,IAAI,kBACF,OAAO;GACL,YAAY;GACZ,UAAU;GACX;EAGH,MAAM;;;AAIV,SAAgB,6BACd,aACwB;CACxB,IAAI,gBAAyB;CAC7B,IAAI,uBAAgC;CAEpC,OAAO;EACL,mBAAmB;GACjB,OAAO;;EAET,0BAA0B;GACxB,OAAO;;EAET,cAAc,OAAO,aAAa,cAAc;GAC9C,IAAI,SAAS,OAAO,UAAU,YAAY,YAAY;QAMhD,yBAAyB,MAC3B,uBAAuB;UAGzB,gBAAgB;GAElB,OAAO,YAAY,OAAO,aAAa,aAAa;;EAEvD;;AAGH,SAAgB,qCACd,SACS;CACT,OAAO,QAAQ,QAAQ,cAAc,IAAI,CAAC,QAAQ"}
|
|
@@ -3,6 +3,7 @@ import { processMiddlewareHeaders } from "./request-pipeline.js";
|
|
|
3
3
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
4
4
|
import { NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildCachedRevalidateCacheControl } from "./cache-control.js";
|
|
5
5
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
6
|
+
import { getSetCookieName } from "./cookie-utils.js";
|
|
6
7
|
//#region src/server/app-route-handler-response.ts
|
|
7
8
|
const APP_ROUTE_REWRITE_ERROR = "NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.";
|
|
8
9
|
const APP_ROUTE_NEXT_ERROR = "NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler";
|
|
@@ -48,10 +49,41 @@ function applyRouteHandlerRevalidateHeader(response, revalidateSeconds, expireSe
|
|
|
48
49
|
function markRouteHandlerCacheMiss(response) {
|
|
49
50
|
setCacheStateHeaders(response.headers, "MISS");
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Returns true when the given Set-Cookie string already declares any of the
|
|
54
|
+
* attributes that follow the first `;` (case-insensitively). Used to detect
|
|
55
|
+
* whether a user-emitted Set-Cookie line already carries an explicit `Path=`,
|
|
56
|
+
* matching Next.js's `appendMutableCookies` which re-runs every cookie through
|
|
57
|
+
* `ResponseCookies.set` (and therefore picks up the `Path=/` default for any
|
|
58
|
+
* cookie that didn't supply one).
|
|
59
|
+
*/
|
|
60
|
+
function hasCookieAttribute(cookie, attributeName) {
|
|
61
|
+
const target = attributeName.toLowerCase();
|
|
62
|
+
let i = cookie.indexOf(";");
|
|
63
|
+
while (i !== -1) {
|
|
64
|
+
let start = i + 1;
|
|
65
|
+
while (start < cookie.length && cookie[start] === " ") start++;
|
|
66
|
+
const next = cookie.indexOf(";", start);
|
|
67
|
+
const end = next === -1 ? cookie.length : next;
|
|
68
|
+
const eq = cookie.indexOf("=", start);
|
|
69
|
+
const attrEnd = eq === -1 || eq > end ? end : eq;
|
|
70
|
+
if (cookie.slice(start, attrEnd).trim().toLowerCase() === target) return true;
|
|
71
|
+
i = next;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Ensure each Set-Cookie line carries `Path=/` by default — Next.js's
|
|
77
|
+
* `appendMutableCookies` re-runs every returned cookie through
|
|
78
|
+
* `ResponseCookies.set`, which normalises a missing `path` to `/`. Without
|
|
79
|
+
* this, a raw `new Response(..., { headers: [['Set-Cookie', 'bar=bar2']] })`
|
|
80
|
+
* lands without `Path=/` and tests that assert on the full attribute set
|
|
81
|
+
* (e.g. Next.js's `app-action.test.ts` route-handler-overrides case, see
|
|
82
|
+
* issue #1484) break.
|
|
83
|
+
*/
|
|
84
|
+
function normalizeReturnedCookie(cookie) {
|
|
85
|
+
if (hasCookieAttribute(cookie, "Path")) return cookie;
|
|
86
|
+
return `${cookie}; Path=/`;
|
|
55
87
|
}
|
|
56
88
|
function applyMutableCookieFallbacks(headers, pendingCookies) {
|
|
57
89
|
if (pendingCookies.length === 0) return;
|
|
@@ -74,7 +106,7 @@ function applyMutableCookieFallbacks(headers, pendingCookies) {
|
|
|
74
106
|
headers.delete("Set-Cookie");
|
|
75
107
|
for (const cookie of unkeyedFallbackCookies) headers.append("Set-Cookie", cookie);
|
|
76
108
|
for (const cookie of fallbackCookies.values()) headers.append("Set-Cookie", cookie);
|
|
77
|
-
for (const cookie of returnedCookies) headers.append("Set-Cookie", cookie);
|
|
109
|
+
for (const cookie of returnedCookies) headers.append("Set-Cookie", normalizeReturnedCookie(cookie));
|
|
78
110
|
}
|
|
79
111
|
async function buildAppRouteCacheValue(response) {
|
|
80
112
|
const body = await response.arrayBuffer();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-route-handler-response.js","names":[],"sources":["../../src/server/app-route-handler-response.ts"],"sourcesContent":["import type { CachedRouteValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport {\n buildCachedRevalidateCacheControl,\n NEVER_CACHE_CONTROL,\n STATIC_CACHE_CONTROL,\n} from \"./cache-control.js\";\nimport {\n MIDDLEWARE_HEADER_PREFIX,\n MIDDLEWARE_NEXT_HEADER,\n MIDDLEWARE_REWRITE_HEADER,\n NEXTJS_CACHE_HEADER,\n VINEXT_CACHE_HEADER,\n} from \"./headers.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\n\nexport type RouteHandlerMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\ntype BuildRouteHandlerCachedResponseOptions = {\n cacheControl?: CacheControlMetadata;\n cacheState: \"HIT\" | \"STALE\";\n expireSeconds?: number;\n isHead: boolean;\n revalidateSeconds: number;\n};\n\ntype FinalizeRouteHandlerResponseOptions = {\n pendingCookies: string[];\n draftCookie?: string | null;\n isHead: boolean;\n};\n\nconst APP_ROUTE_REWRITE_ERROR =\n \"NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.\";\nconst APP_ROUTE_NEXT_ERROR =\n \"NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler\";\n\nfunction hasMiddlewareHeader(headers: Headers): boolean {\n for (const key of headers.keys()) {\n if (key.startsWith(MIDDLEWARE_HEADER_PREFIX)) return true;\n }\n return false;\n}\n\nfunction buildRouteHandlerCacheControl(\n cacheState: BuildRouteHandlerCachedResponseOptions[\"cacheState\"],\n revalidateSeconds: number,\n expireSeconds?: number,\n): string {\n if (revalidateSeconds === 0) {\n // A cached response is never produced for revalidate = 0 (the ISR write\n // path skips it), so only the HIT/STALE->fresh rewrite can arrive here\n // with a 0 value, via applyRouteHandlerRevalidateHeader. In all such\n // cases the author opted out of caching entirely.\n return NEVER_CACHE_CONTROL;\n }\n\n if (revalidateSeconds === Infinity) {\n // revalidate = false / Infinity means \"cache indefinitely\" — emit the\n // same static Cache-Control used by pages, not a dynamic SWR value.\n return STATIC_CACHE_CONTROL;\n }\n\n return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);\n}\n\nexport function applyRouteHandlerMiddlewareContext(\n response: Response,\n middlewareContext: RouteHandlerMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const responseHeaders = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(responseHeaders, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n}\n\nexport function assertSupportedAppRouteHandlerResponse(response: Response): void {\n // NextResponse.next() and rewrite() are middleware control-flow signals.\n // Once an App Route handler has returned, Next.js rejects those responses.\n if (response.headers.has(MIDDLEWARE_REWRITE_HEADER)) {\n throw new Error(APP_ROUTE_REWRITE_ERROR);\n }\n\n if (response.headers.get(MIDDLEWARE_NEXT_HEADER) === \"1\") {\n throw new Error(APP_ROUTE_NEXT_ERROR);\n }\n}\n\nexport function buildRouteHandlerCachedResponse(\n cachedValue: CachedRouteValue,\n options: BuildRouteHandlerCachedResponseOptions,\n): Response {\n const headers = new Headers();\n for (const [key, value] of Object.entries(cachedValue.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) {\n headers.append(key, entry);\n }\n } else {\n headers.set(key, value);\n }\n }\n setCacheStateHeaders(headers, options.cacheState);\n const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;\n const expireSeconds =\n options.cacheControl === undefined\n ? undefined\n : (options.cacheControl.expire ?? options.expireSeconds);\n headers.set(\n \"Cache-Control\",\n buildRouteHandlerCacheControl(options.cacheState, revalidateSeconds, expireSeconds),\n );\n\n return new Response(options.isHead ? null : cachedValue.body, {\n status: cachedValue.status,\n headers,\n });\n}\n\nexport function applyRouteHandlerRevalidateHeader(\n response: Response,\n revalidateSeconds: number,\n expireSeconds?: number,\n): void {\n response.headers.set(\n \"cache-control\",\n buildRouteHandlerCacheControl(\"HIT\", revalidateSeconds, expireSeconds),\n );\n}\n\nexport function markRouteHandlerCacheMiss(response: Response): void {\n setCacheStateHeaders(response.headers, \"MISS\");\n}\n\nfunction getSetCookieName(cookie: string): string | null {\n const equalsIndex = cookie.indexOf(\"=\");\n if (equalsIndex <= 0) {\n return null;\n }\n return cookie.slice(0, equalsIndex);\n}\n\nfunction applyMutableCookieFallbacks(headers: Headers, pendingCookies: string[]): void {\n if (pendingCookies.length === 0) {\n return;\n }\n\n const returnedCookies = headers.getSetCookie();\n const returnedCookieNames = new Set<string>();\n for (const cookie of returnedCookies) {\n const name = getSetCookieName(cookie);\n if (name) {\n returnedCookieNames.add(name);\n }\n }\n\n const fallbackCookies = new Map<string, string>();\n const unkeyedFallbackCookies: string[] = [];\n for (const cookie of pendingCookies) {\n const name = getSetCookieName(cookie);\n if (!name) {\n unkeyedFallbackCookies.push(cookie);\n continue;\n }\n\n if (!returnedCookieNames.has(name)) {\n fallbackCookies.set(name, cookie);\n }\n }\n\n headers.delete(\"Set-Cookie\");\n for (const cookie of unkeyedFallbackCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of fallbackCookies.values()) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of returnedCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n}\n\nexport async function buildAppRouteCacheValue(response: Response): Promise<CachedRouteValue> {\n const body = await response.arrayBuffer();\n const headers: CachedRouteValue[\"headers\"] = {};\n\n response.headers.forEach((value, key) => {\n if (\n key === \"set-cookie\" ||\n key === VINEXT_CACHE_HEADER.toLowerCase() ||\n key === NEXTJS_CACHE_HEADER.toLowerCase() ||\n key === \"cache-control\" ||\n key.startsWith(MIDDLEWARE_HEADER_PREFIX)\n ) {\n return;\n }\n headers[key] = value;\n });\n const setCookies = response.headers.getSetCookie?.() ?? [];\n if (setCookies.length > 0) {\n headers[\"set-cookie\"] = setCookies;\n }\n\n return {\n kind: \"APP_ROUTE\",\n body,\n status: response.status,\n headers,\n };\n}\n\nexport function finalizeRouteHandlerResponse(\n response: Response,\n options: FinalizeRouteHandlerResponseOptions,\n): Response {\n const { pendingCookies, draftCookie, isHead } = options;\n if (\n pendingCookies.length === 0 &&\n !draftCookie &&\n !isHead &&\n !hasMiddlewareHeader(response.headers)\n ) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n applyMutableCookieFallbacks(headers, pendingCookies);\n if (draftCookie) {\n headers.append(\"Set-Cookie\", draftCookie);\n }\n\n return new Response(isHead ? null : response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-route-handler-response.js","names":[],"sources":["../../src/server/app-route-handler-response.ts"],"sourcesContent":["import type { CachedRouteValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport {\n buildCachedRevalidateCacheControl,\n NEVER_CACHE_CONTROL,\n STATIC_CACHE_CONTROL,\n} from \"./cache-control.js\";\nimport {\n MIDDLEWARE_HEADER_PREFIX,\n MIDDLEWARE_NEXT_HEADER,\n MIDDLEWARE_REWRITE_HEADER,\n NEXTJS_CACHE_HEADER,\n VINEXT_CACHE_HEADER,\n} from \"./headers.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\nimport { getSetCookieName } from \"./cookie-utils.js\";\n\nexport type RouteHandlerMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\ntype BuildRouteHandlerCachedResponseOptions = {\n cacheControl?: CacheControlMetadata;\n cacheState: \"HIT\" | \"STALE\";\n expireSeconds?: number;\n isHead: boolean;\n revalidateSeconds: number;\n};\n\ntype FinalizeRouteHandlerResponseOptions = {\n pendingCookies: string[];\n draftCookie?: string | null;\n isHead: boolean;\n};\n\nconst APP_ROUTE_REWRITE_ERROR =\n \"NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.\";\nconst APP_ROUTE_NEXT_ERROR =\n \"NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler\";\n\nfunction hasMiddlewareHeader(headers: Headers): boolean {\n for (const key of headers.keys()) {\n if (key.startsWith(MIDDLEWARE_HEADER_PREFIX)) return true;\n }\n return false;\n}\n\nfunction buildRouteHandlerCacheControl(\n cacheState: BuildRouteHandlerCachedResponseOptions[\"cacheState\"],\n revalidateSeconds: number,\n expireSeconds?: number,\n): string {\n if (revalidateSeconds === 0) {\n // A cached response is never produced for revalidate = 0 (the ISR write\n // path skips it), so only the HIT/STALE->fresh rewrite can arrive here\n // with a 0 value, via applyRouteHandlerRevalidateHeader. In all such\n // cases the author opted out of caching entirely.\n return NEVER_CACHE_CONTROL;\n }\n\n if (revalidateSeconds === Infinity) {\n // revalidate = false / Infinity means \"cache indefinitely\" — emit the\n // same static Cache-Control used by pages, not a dynamic SWR value.\n return STATIC_CACHE_CONTROL;\n }\n\n return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);\n}\n\nexport function applyRouteHandlerMiddlewareContext(\n response: Response,\n middlewareContext: RouteHandlerMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const responseHeaders = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(responseHeaders, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n}\n\nexport function assertSupportedAppRouteHandlerResponse(response: Response): void {\n // NextResponse.next() and rewrite() are middleware control-flow signals.\n // Once an App Route handler has returned, Next.js rejects those responses.\n if (response.headers.has(MIDDLEWARE_REWRITE_HEADER)) {\n throw new Error(APP_ROUTE_REWRITE_ERROR);\n }\n\n if (response.headers.get(MIDDLEWARE_NEXT_HEADER) === \"1\") {\n throw new Error(APP_ROUTE_NEXT_ERROR);\n }\n}\n\nexport function buildRouteHandlerCachedResponse(\n cachedValue: CachedRouteValue,\n options: BuildRouteHandlerCachedResponseOptions,\n): Response {\n const headers = new Headers();\n for (const [key, value] of Object.entries(cachedValue.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) {\n headers.append(key, entry);\n }\n } else {\n headers.set(key, value);\n }\n }\n setCacheStateHeaders(headers, options.cacheState);\n const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;\n const expireSeconds =\n options.cacheControl === undefined\n ? undefined\n : (options.cacheControl.expire ?? options.expireSeconds);\n headers.set(\n \"Cache-Control\",\n buildRouteHandlerCacheControl(options.cacheState, revalidateSeconds, expireSeconds),\n );\n\n return new Response(options.isHead ? null : cachedValue.body, {\n status: cachedValue.status,\n headers,\n });\n}\n\nexport function applyRouteHandlerRevalidateHeader(\n response: Response,\n revalidateSeconds: number,\n expireSeconds?: number,\n): void {\n response.headers.set(\n \"cache-control\",\n buildRouteHandlerCacheControl(\"HIT\", revalidateSeconds, expireSeconds),\n );\n}\n\nexport function markRouteHandlerCacheMiss(response: Response): void {\n setCacheStateHeaders(response.headers, \"MISS\");\n}\n\n/**\n * Returns true when the given Set-Cookie string already declares any of the\n * attributes that follow the first `;` (case-insensitively). Used to detect\n * whether a user-emitted Set-Cookie line already carries an explicit `Path=`,\n * matching Next.js's `appendMutableCookies` which re-runs every cookie through\n * `ResponseCookies.set` (and therefore picks up the `Path=/` default for any\n * cookie that didn't supply one).\n */\nfunction hasCookieAttribute(cookie: string, attributeName: string): boolean {\n const target = attributeName.toLowerCase();\n // Skip past the first '=' (the cookie value separator) so we don't match\n // `attributeName=` inside the cookie value itself.\n let i = cookie.indexOf(\";\");\n while (i !== -1) {\n // Trim leading whitespace after the ';'\n let start = i + 1;\n while (start < cookie.length && cookie[start] === \" \") start++;\n const next = cookie.indexOf(\";\", start);\n const end = next === -1 ? cookie.length : next;\n const eq = cookie.indexOf(\"=\", start);\n const attrEnd = eq === -1 || eq > end ? end : eq;\n const attr = cookie.slice(start, attrEnd).trim().toLowerCase();\n if (attr === target) {\n return true;\n }\n i = next;\n }\n return false;\n}\n\n/**\n * Ensure each Set-Cookie line carries `Path=/` by default — Next.js's\n * `appendMutableCookies` re-runs every returned cookie through\n * `ResponseCookies.set`, which normalises a missing `path` to `/`. Without\n * this, a raw `new Response(..., { headers: [['Set-Cookie', 'bar=bar2']] })`\n * lands without `Path=/` and tests that assert on the full attribute set\n * (e.g. Next.js's `app-action.test.ts` route-handler-overrides case, see\n * issue #1484) break.\n */\nfunction normalizeReturnedCookie(cookie: string): string {\n if (hasCookieAttribute(cookie, \"Path\")) {\n return cookie;\n }\n return `${cookie}; Path=/`;\n}\n\nfunction applyMutableCookieFallbacks(headers: Headers, pendingCookies: string[]): void {\n if (pendingCookies.length === 0) {\n return;\n }\n\n const returnedCookies = headers.getSetCookie();\n const returnedCookieNames = new Set<string>();\n for (const cookie of returnedCookies) {\n const name = getSetCookieName(cookie);\n if (name) {\n returnedCookieNames.add(name);\n }\n }\n\n const fallbackCookies = new Map<string, string>();\n const unkeyedFallbackCookies: string[] = [];\n for (const cookie of pendingCookies) {\n const name = getSetCookieName(cookie);\n if (!name) {\n unkeyedFallbackCookies.push(cookie);\n continue;\n }\n\n if (!returnedCookieNames.has(name)) {\n fallbackCookies.set(name, cookie);\n }\n }\n\n headers.delete(\"Set-Cookie\");\n for (const cookie of unkeyedFallbackCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of fallbackCookies.values()) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of returnedCookies) {\n headers.append(\"Set-Cookie\", normalizeReturnedCookie(cookie));\n }\n}\n\nexport async function buildAppRouteCacheValue(response: Response): Promise<CachedRouteValue> {\n const body = await response.arrayBuffer();\n const headers: CachedRouteValue[\"headers\"] = {};\n\n response.headers.forEach((value, key) => {\n if (\n key === \"set-cookie\" ||\n key === VINEXT_CACHE_HEADER.toLowerCase() ||\n key === NEXTJS_CACHE_HEADER.toLowerCase() ||\n key === \"cache-control\" ||\n key.startsWith(MIDDLEWARE_HEADER_PREFIX)\n ) {\n return;\n }\n headers[key] = value;\n });\n const setCookies = response.headers.getSetCookie?.() ?? [];\n if (setCookies.length > 0) {\n headers[\"set-cookie\"] = setCookies;\n }\n\n return {\n kind: \"APP_ROUTE\",\n body,\n status: response.status,\n headers,\n };\n}\n\nexport function finalizeRouteHandlerResponse(\n response: Response,\n options: FinalizeRouteHandlerResponseOptions,\n): Response {\n const { pendingCookies, draftCookie, isHead } = options;\n if (\n pendingCookies.length === 0 &&\n !draftCookie &&\n !isHead &&\n !hasMiddlewareHeader(response.headers)\n ) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n applyMutableCookieFallbacks(headers, pendingCookies);\n if (draftCookie) {\n headers.append(\"Set-Cookie\", draftCookie);\n }\n\n return new Response(isHead ? null : response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":"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"}
|
|
@@ -67,15 +67,26 @@ type HandleProgressiveActionRequestOptions = {
|
|
|
67
67
|
middlewareContext: AppRscMiddlewareContext;
|
|
68
68
|
request: Request;
|
|
69
69
|
};
|
|
70
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Side-effect headers captured during a progressive (no-JS) server action's
|
|
72
|
+
* non-redirect execution. Forwarded onto the page render response so that
|
|
73
|
+
* `cookies().set(...)` and revalidation kinds reach the browser. See
|
|
74
|
+
* `app-server-action-execution.ts` and issue #1483 for the full rationale.
|
|
75
|
+
*/
|
|
76
|
+
type ProgressiveActionSideEffects = {
|
|
77
|
+
pendingCookies: string[];
|
|
78
|
+
draftCookie: string | null | undefined; /** Numeric revalidation kind: `0` (none), `1` (static+dynamic), etc. */
|
|
79
|
+
revalidationKind: number;
|
|
80
|
+
};
|
|
81
|
+
type ProgressiveActionFormStateResult = ({
|
|
71
82
|
formState: ReactFormState | null;
|
|
72
83
|
kind: "form-state";
|
|
73
|
-
} | {
|
|
84
|
+
} & ProgressiveActionSideEffects) | ({
|
|
74
85
|
actionError: unknown;
|
|
75
86
|
actionFailed: true;
|
|
76
87
|
formState: null;
|
|
77
88
|
kind: "form-state";
|
|
78
|
-
};
|
|
89
|
+
} & ProgressiveActionSideEffects);
|
|
79
90
|
type HandleServerActionRequestOptions = {
|
|
80
91
|
actionId: string | null;
|
|
81
92
|
cleanPathname: string;
|