vinext 0.0.49 → 0.0.50
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/client-build-config.js.map +1 -1
- package/dist/build/google-fonts/build-url.js.map +1 -1
- package/dist/build/google-fonts/get-axes.js.map +1 -1
- package/dist/build/google-fonts/sort-variants.js.map +1 -1
- package/dist/build/google-fonts/validate.js.map +1 -1
- package/dist/build/layout-classification.js.map +1 -1
- package/dist/build/nitro-route-rules.js.map +1 -1
- package/dist/build/precompress.js.map +1 -1
- package/dist/build/prerender.d.ts +17 -1
- package/dist/build/prerender.js +77 -16
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/report.js.map +1 -1
- package/dist/build/route-classification-injector.js.map +1 -1
- package/dist/build/route-classification-manifest.js.map +1 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/server-manifest.js.map +1 -1
- package/dist/build/ssr-manifest.js.map +1 -1
- package/dist/build/standalone.js.map +1 -1
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.js +1 -1
- package/dist/check.js.map +1 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +8 -4
- package/dist/cli.js.map +1 -1
- package/dist/client/instrumentation-client-state.js.map +1 -1
- package/dist/client/validate-module-path.js.map +1 -1
- package/dist/client/vinext-next-data.d.ts +5 -1
- package/dist/client/window-next.d.ts +149 -0
- package/dist/client/window-next.js +48 -0
- package/dist/client/window-next.js.map +1 -0
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.js +2 -1
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.d.ts +3 -1
- package/dist/config/config-matchers.js +5 -4
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/dotenv.js.map +1 -1
- package/dist/config/next-config.d.ts +6 -3
- package/dist/config/next-config.js +13 -2
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +13 -5
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +3 -1
- package/dist/entries/app-browser-entry.js +11 -2
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +11 -0
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/app-ssr-entry.js.map +1 -1
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-entry-helpers.js.map +1 -1
- package/dist/entries/pages-server-entry.js +15 -0
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +76 -18
- package/dist/index.js.map +1 -1
- package/dist/init.js.map +1 -1
- package/dist/plugins/async-hooks-stub.js.map +1 -1
- package/dist/plugins/client-reference-dedup.js.map +1 -1
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/instrumentation-client.js.map +1 -1
- package/dist/plugins/og-assets.js.map +1 -1
- package/dist/plugins/optimize-imports.js.map +1 -1
- package/dist/plugins/postcss.js.map +1 -1
- package/dist/plugins/rsc-client-reference-loaders.d.ts +7 -0
- package/dist/plugins/rsc-client-reference-loaders.js +48 -0
- package/dist/plugins/rsc-client-reference-loaders.js.map +1 -0
- package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
- package/dist/plugins/server-externals-manifest.js.map +1 -1
- package/dist/plugins/strip-server-exports.js.map +1 -1
- package/dist/routing/app-route-graph.d.ts +48 -5
- package/dist/routing/app-route-graph.js +159 -15
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-matching.js.map +1 -1
- package/dist/routing/route-pattern.js.map +1 -1
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-action-result.d.ts +19 -0
- package/dist/server/app-browser-action-result.js +18 -0
- package/dist/server/app-browser-action-result.js.map +1 -0
- package/dist/server/app-browser-entry.js +91 -48
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-error.js.map +1 -1
- package/dist/server/app-browser-hydration.d.ts +19 -0
- package/dist/server/app-browser-hydration.js +22 -0
- package/dist/server/app-browser-hydration.js.map +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +6 -3
- package/dist/server/app-browser-navigation-controller.js +67 -19
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +17 -17
- package/dist/server/app-browser-state.js +122 -36
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-stream.d.ts +4 -0
- package/dist/server/app-browser-stream.js +24 -2
- package/dist/server/app-browser-stream.js.map +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +6 -1
- package/dist/server/app-browser-visible-commit.js +34 -19
- package/dist/server/app-browser-visible-commit.js.map +1 -1
- package/dist/server/app-client-reference-preloader.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +17 -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.js.map +1 -1
- package/dist/server/app-hook-warning-suppression.js.map +1 -1
- package/dist/server/app-middleware.d.ts +1 -1
- package/dist/server/app-middleware.js +4 -9
- package/dist/server/app-middleware.js.map +1 -1
- package/dist/server/app-mounted-slots-header.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +14 -13
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +1 -0
- package/dist/server/app-page-boundary.js +7 -5
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +10 -3
- package/dist/server/app-page-cache.js +42 -23
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +6 -1
- package/dist/server/app-page-dispatch.js +21 -7
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +3 -1
- package/dist/server/app-page-element-builder.js +6 -2
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.js +4 -0
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-method.js.map +1 -1
- package/dist/server/app-page-params.js.map +1 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +7 -1
- package/dist/server/app-page-render.js +11 -4
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.js +2 -1
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +2 -0
- package/dist/server/app-page-response.js +15 -5
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +6 -2
- package/dist/server/app-page-route-wiring.js +50 -49
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-segment-state.d.ts +10 -0
- package/dist/server/app-page-segment-state.js +87 -0
- package/dist/server/app-page-segment-state.js.map +1 -0
- package/dist/server/app-page-stream.d.ts +7 -2
- package/dist/server/app-page-stream.js +3 -1
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-post-middleware-context.js.map +1 -1
- package/dist/server/app-prerender-endpoints.js.map +1 -1
- package/dist/server/app-prerender-static-params.js.map +1 -1
- package/dist/server/app-render-dependency.js.map +1 -1
- package/dist/server/app-request-context.js.map +1 -1
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.js +3 -1
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-policy.js +1 -0
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.js +4 -3
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-router-entry.js +6 -2
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +5 -2
- package/dist/server/app-rsc-cache-busting.js +40 -19
- package/dist/server/app-rsc-cache-busting.js.map +1 -1
- package/dist/server/app-rsc-error-handler.js.map +1 -1
- package/dist/server/app-rsc-errors.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +51 -17
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-render-mode.d.ts +11 -0
- package/dist/server/app-rsc-render-mode.js +21 -0
- package/dist/server/app-rsc-render-mode.js.map +1 -0
- package/dist/server/app-rsc-request-normalization.d.ts +4 -1
- package/dist/server/app-rsc-request-normalization.js +7 -2
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -1
- package/dist/server/app-rsc-response-finalizer.js +6 -1
- package/dist/server/app-rsc-response-finalizer.js.map +1 -1
- package/dist/server/app-rsc-route-matching.js.map +1 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +16 -2
- package/dist/server/app-server-action-execution.js +79 -23
- 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 +10 -4
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.js.map +1 -1
- package/dist/server/artifact-compatibility.js.map +1 -1
- package/dist/server/cache-control.js +1 -0
- package/dist/server/cache-control.js.map +1 -1
- package/dist/server/cache-proof.js.map +1 -1
- package/dist/server/csp.js.map +1 -1
- package/dist/server/dev-error-overlay-store.js.map +1 -1
- package/dist/server/dev-error-overlay.js +5 -0
- package/dist/server/dev-error-overlay.js.map +1 -1
- package/dist/server/dev-module-runner.js.map +1 -1
- package/dist/server/dev-origin-check.js.map +1 -1
- package/dist/server/dev-route-files.js.map +1 -1
- package/dist/server/dev-server.js +8 -5
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/file-based-metadata.js.map +1 -1
- package/dist/server/headers.d.ts +79 -0
- package/dist/server/headers.js +101 -0
- package/dist/server/headers.js.map +1 -0
- package/dist/server/html.js.map +1 -1
- package/dist/server/http-error-responses.js.map +1 -1
- package/dist/server/image-optimization.d.ts +11 -1
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/implicit-tags.js +2 -1
- package/dist/server/implicit-tags.js.map +1 -1
- package/dist/server/instrumentation-runtime.js.map +1 -1
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +10 -1
- package/dist/server/isr-cache.js +12 -3
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-route-build-data.js.map +1 -1
- package/dist/server/metadata-route-response.js.map +1 -1
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-matcher.js.map +1 -1
- package/dist/server/middleware-request-headers.d.ts +4 -1
- package/dist/server/middleware-request-headers.js +15 -8
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware-response-headers.d.ts +2 -1
- package/dist/server/middleware-response-headers.js +1 -1
- package/dist/server/middleware-response-headers.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +1 -0
- package/dist/server/middleware-runtime.js +6 -3
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/navigation-planner.d.ts +119 -0
- package/dist/server/navigation-planner.js +171 -0
- package/dist/server/navigation-planner.js.map +1 -0
- package/dist/server/navigation-trace.d.ts +12 -2
- package/dist/server/navigation-trace.js +13 -1
- package/dist/server/navigation-trace.js.map +1 -1
- package/dist/server/next-error-digest.d.ts +3 -2
- package/dist/server/next-error-digest.js +4 -2
- package/dist/server/next-error-digest.js.map +1 -1
- package/dist/server/normalize-path.js.map +1 -1
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/pages-media-type.js.map +1 -1
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-data.js +5 -2
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prerender-work-unit-setup.js +1 -1
- package/dist/server/prerender-work-unit-setup.js.map +1 -1
- package/dist/server/prod-server.js +35 -13
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-log.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +1 -13
- package/dist/server/request-pipeline.js +3 -25
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/rsc-stream-hints.js.map +1 -1
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.js +3 -3
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/socket-error-backstop.js.map +1 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/server/worker-utils.d.ts +0 -7
- package/dist/server/worker-utils.js +3 -2
- package/dist/server/worker-utils.js.map +1 -1
- package/dist/shims/amp.js.map +1 -1
- package/dist/shims/app.d.ts +37 -4
- package/dist/shims/app.js +50 -1
- package/dist/shims/app.js.map +1 -0
- package/dist/shims/cache-for-request.js.map +1 -1
- package/dist/shims/cache-runtime.js +20 -8
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +15 -3
- package/dist/shims/cache.js +99 -15
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/client-hook-error.js.map +1 -1
- package/dist/shims/compat-router.js.map +1 -1
- package/dist/shims/config.js.map +1 -1
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/dynamic.d.ts +18 -10
- package/dist/shims/dynamic.js +107 -51
- package/dist/shims/dynamic.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +35 -6
- package/dist/shims/error-boundary.js +118 -33
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +22 -1
- package/dist/shims/fetch-cache.js +124 -13
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/form.js +3 -1
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +3 -1
- package/dist/shims/head.js +28 -16
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +4 -2
- package/dist/shims/headers.js +24 -7
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.js.map +1 -1
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/image-config.d.ts +14 -1
- package/dist/shims/image-config.js +24 -1
- package/dist/shims/image-config.js.map +1 -1
- package/dist/shims/image.js +15 -2
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/als-registry.js.map +1 -1
- package/dist/shims/internal/app-router-context.d.ts +1 -0
- package/dist/shims/internal/app-router-context.js.map +1 -1
- package/dist/shims/internal/cookie-serialize.js.map +1 -1
- package/dist/shims/internal/make-hanging-promise.d.ts +1 -1
- package/dist/shims/internal/make-hanging-promise.js +1 -1
- package/dist/shims/internal/make-hanging-promise.js.map +1 -1
- package/dist/shims/internal/parse-cookie-header.js.map +1 -1
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/internal/work-unit-async-storage.js +2 -2
- package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
- package/dist/shims/layout-segment-context.js.map +1 -1
- package/dist/shims/legacy-image.js.map +1 -1
- package/dist/shims/link-prefetch.d.ts +34 -0
- package/dist/shims/link-prefetch.js +40 -0
- package/dist/shims/link-prefetch.js.map +1 -0
- package/dist/shims/link.d.ts +27 -4
- package/dist/shims/link.js +91 -27
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +22 -1
- package/dist/shims/navigation.js +30 -15
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.js.map +1 -1
- package/dist/shims/offline.js.map +1 -1
- package/dist/shims/readonly-url-search-params.js.map +1 -1
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/root-params.js.map +1 -1
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +38 -2
- package/dist/shims/router.js +45 -17
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script-nonce-context.js.map +1 -1
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.js +10 -14
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +6 -1
- package/dist/shims/slot.js +20 -7
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/thenable-params.js.map +1 -1
- package/dist/shims/unified-request-context.js +3 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/shims/url-utils.d.ts +2 -1
- package/dist/shims/url-utils.js +10 -1
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/shims/use-merged-ref.js.map +1 -1
- package/dist/shims/web-vitals.d.ts +4 -21
- package/dist/shims/web-vitals.js +19 -6
- package/dist/shims/web-vitals.js.map +1 -1
- package/dist/utils/base-path.js.map +1 -1
- package/dist/utils/cache-control-metadata.js.map +1 -1
- package/dist/utils/domain-locale.js.map +1 -1
- package/dist/utils/encode-cache-tag.d.ts +31 -0
- package/dist/utils/encode-cache-tag.js +38 -0
- package/dist/utils/encode-cache-tag.js.map +1 -0
- package/dist/utils/error-cause.js.map +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/dist/utils/manifest-paths.js.map +1 -1
- package/dist/utils/mdx-scan.js.map +1 -1
- package/dist/utils/navigation-signal.d.ts +6 -0
- package/dist/utils/navigation-signal.js +14 -0
- package/dist/utils/navigation-signal.js.map +1 -0
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/public-routes.js.map +1 -1
- package/dist/utils/query.js.map +1 -1
- package/dist/utils/safe-json-file.js.map +1 -1
- package/dist/utils/text-stream.js.map +1 -1
- package/dist/utils/vinext-root.js.map +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-middleware.js","names":[],"sources":["../../src/server/app-middleware.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport { isExternalUrl, proxyExternalRequest } from \"../config/config-matchers.js\";\nimport { applyMiddlewareRequestHeaders, setHeadersContext } from \"vinext/shims/headers\";\nimport { setNavigationContext } from \"vinext/shims/navigation\";\nimport { buildRequestHeadersFromMiddlewareResponse } from \"./middleware-request-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { executeMiddleware, type MiddlewareModule } from \"./middleware-runtime.js\";\nimport { cloneRequestWithHeaders, processMiddlewareHeaders } from \"./request-pipeline.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\n\nexport type AppMiddlewareContext = {\n headers: Headers | null;\n requestHeaders: Headers | null;\n status: number | null;\n};\n\nexport type ApplyAppMiddlewareOptions = {\n basePath?: string;\n cleanPathname: string;\n context: AppMiddlewareContext;\n i18nConfig?: NextI18nConfig | null;\n isProxy: boolean;\n module: MiddlewareModule;\n request: Request;\n};\n\nexport type ApplyAppMiddlewareResult =\n | {\n kind: \"continue\";\n cleanPathname: string;\n search: string | null;\n }\n | {\n kind: \"response\";\n response: Response;\n };\n\ntype ForwardedMiddlewareContext = {\n h?: unknown;\n r?: unknown;\n s?: unknown;\n};\n\nexport const FLIGHT_HEADERS: readonly string[] = [\n \"rsc\",\n \"next-router-state-tree\",\n \"next-router-prefetch\",\n \"next-hmr-refresh\",\n \"next-router-segment-prefetch\",\n];\n\nconst FLIGHT_HEADER_SET = new Set(FLIGHT_HEADERS);\n\nfunction isForwardedMiddlewareContext(value: unknown): value is ForwardedMiddlewareContext {\n return !!value && typeof value === \"object\";\n}\n\nfunction requestWithoutFlightHeaders(request: Request): Request {\n let hasFlightHeader = false;\n const headers = new Headers();\n\n for (const [key, value] of request.headers) {\n if (FLIGHT_HEADER_SET.has(key.toLowerCase())) {\n hasFlightHeader = true;\n } else {\n headers.append(key, value);\n }\n }\n\n if (!hasFlightHeader) return request;\n const source = request.body ? request.clone() : request;\n return cloneRequestWithHeaders(source, headers);\n}\n\nfunction appendForwardedHeader(headers: Headers, value: unknown): void {\n if (!Array.isArray(value) || value.length < 2) return;\n const key = value[0];\n const headerValue = value[1];\n if (typeof key === \"string\" && typeof headerValue === \"string\") {\n headers.append(key, headerValue);\n }\n}\n\nfunction responseFromMiddlewareRedirect(result: {\n redirectStatus?: number;\n redirectUrl?: string;\n response?: Response;\n responseHeaders?: Headers;\n}): Response {\n if (result.response) return result.response;\n\n const headers = new Headers(result.responseHeaders);\n if (result.redirectUrl) {\n headers.set(\"Location\", result.redirectUrl);\n }\n return new Response(null, {\n status: result.redirectStatus ?? 307,\n headers,\n });\n}\n\nexport function isExternalMiddlewareRewrite(rewriteUrl: string, request: Request): boolean {\n const rewriteParsed = new URL(rewriteUrl, request.url);\n return rewriteParsed.origin !== new URL(request.url).origin;\n}\n\nfunction requestWithMiddlewareRequestHeaders(\n request: Request,\n middlewareHeaders: Headers | null,\n): Request {\n const nextHeaders = middlewareHeaders\n ? buildRequestHeadersFromMiddlewareResponse(request.headers, middlewareHeaders)\n : null;\n if (!nextHeaders) return request;\n\n const init: RequestInit = {\n method: request.method,\n headers: nextHeaders,\n body: request.body,\n };\n if (request.body) {\n Object.defineProperty(init, \"duplex\", { value: \"half\", enumerable: true });\n }\n\n return new Request(request.url, init);\n}\n\nexport async function proxyExternalMiddlewareRewrite(\n request: Request,\n rewriteUrl: string,\n context: AppMiddlewareContext,\n): Promise<Response> {\n const proxyRequest = requestWithMiddlewareRequestHeaders(\n request,\n context.requestHeaders ?? context.headers,\n );\n setHeadersContext(null);\n setNavigationContext(null);\n\n const proxyResponse = await proxyExternalRequest(proxyRequest, rewriteUrl);\n const headers = new Headers(proxyResponse.headers);\n processMiddlewareHeaders(headers);\n\n if (!context.headers) {\n return new Response(proxyResponse.body, {\n status: proxyResponse.status,\n statusText: proxyResponse.statusText,\n headers,\n });\n }\n\n const middlewareHeaders = new Headers(context.headers);\n processMiddlewareHeaders(middlewareHeaders);\n mergeMiddlewareResponseHeaders(headers, middlewareHeaders);\n return new Response(proxyResponse.body, {\n status: proxyResponse.status,\n statusText: proxyResponse.statusText,\n headers,\n });\n}\n\nfunction applyForwardedMiddlewareContext(\n request: Request,\n context: AppMiddlewareContext,\n): { applied: boolean; rewriteUrl?: string } {\n if (process.env.NODE_ENV === \"production\") {\n return { applied: false };\n }\n\n const header = request.headers.get(\"x-vinext-mw-ctx\");\n if (!header) return { applied: false };\n\n try {\n const data = JSON.parse(header);\n if (!isForwardedMiddlewareContext(data)) return { applied: false };\n\n if (Array.isArray(data.h) && data.h.length > 0) {\n context.headers = new Headers();\n for (const entry of data.h) {\n appendForwardedHeader(context.headers, entry);\n }\n }\n if (typeof data.s === \"number\") {\n context.status = data.s;\n }\n if (typeof data.r === \"string\" && data.r.length > 0) {\n return { applied: true, rewriteUrl: data.r };\n }\n return { applied: true };\n } catch (e) {\n console.error(\"[vinext] Failed to parse forwarded middleware context:\", e);\n return { applied: false };\n }\n}\n\nexport async function applyAppMiddleware(\n options: ApplyAppMiddlewareOptions,\n): Promise<ApplyAppMiddlewareResult> {\n const forwarded = applyForwardedMiddlewareContext(options.request, options.context);\n const middlewareRequest = requestWithoutFlightHeaders(options.request);\n let cleanPathname = options.cleanPathname;\n let search: string | null = null;\n\n if (forwarded.rewriteUrl) {\n try {\n if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, middlewareRequest)) {\n return {\n kind: \"response\",\n response: await proxyExternalMiddlewareRewrite(\n middlewareRequest,\n forwarded.rewriteUrl,\n options.context,\n ),\n };\n }\n const rewriteParsed = new URL(forwarded.rewriteUrl, middlewareRequest.url);\n cleanPathname = rewriteParsed.pathname;\n search = rewriteParsed.search;\n } catch (e) {\n console.error(\"[vinext] Failed to apply forwarded middleware rewrite:\", e);\n forwarded.applied = false;\n }\n }\n\n if (!forwarded.applied) {\n const result = await executeMiddleware({\n basePath: options.basePath,\n i18nConfig: options.i18nConfig,\n isProxy: options.isProxy,\n module: options.module,\n normalizedPathname: cleanPathname,\n request: middlewareRequest,\n });\n\n if (!result.continue) {\n if (result.redirectUrl) {\n return { kind: \"response\", response: responseFromMiddlewareRedirect(result) };\n }\n if (result.response) {\n return { kind: \"response\", response: result.response };\n }\n return { kind: \"response\", response: internalServerErrorResponse() };\n }\n\n if (result.responseHeaders) {\n options.context.headers = new Headers(result.responseHeaders);\n }\n\n if (result.rewriteUrl) {\n if (result.rewriteStatus !== undefined) {\n options.context.status = result.rewriteStatus;\n }\n if (isExternalUrl(result.rewriteUrl)) {\n return {\n kind: \"response\",\n response: await proxyExternalMiddlewareRewrite(\n middlewareRequest,\n result.rewriteUrl,\n options.context,\n ),\n };\n }\n const rewriteParsed = new URL(result.rewriteUrl, middlewareRequest.url);\n cleanPathname = rewriteParsed.pathname;\n search = rewriteParsed.search;\n }\n }\n\n if (options.context.headers) {\n options.context.requestHeaders = new Headers(options.context.headers);\n applyMiddlewareRequestHeaders(options.context.headers);\n processMiddlewareHeaders(options.context.headers);\n }\n\n return { kind: \"continue\", cleanPathname, search };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-middleware.js","names":[],"sources":["../../src/server/app-middleware.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport { isExternalUrl, proxyExternalRequest } from \"../config/config-matchers.js\";\nimport { applyMiddlewareRequestHeaders, setHeadersContext } from \"vinext/shims/headers\";\nimport { setNavigationContext } from \"vinext/shims/navigation\";\nimport { FLIGHT_HEADERS, VINEXT_MW_CTX_HEADER } from \"./headers.js\";\nimport { buildRequestHeadersFromMiddlewareResponse } from \"./middleware-request-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { executeMiddleware, type MiddlewareModule } from \"./middleware-runtime.js\";\nimport { cloneRequestWithHeaders, processMiddlewareHeaders } from \"./request-pipeline.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\n\nexport type AppMiddlewareContext = {\n headers: Headers | null;\n requestHeaders: Headers | null;\n status: number | null;\n};\n\nexport type ApplyAppMiddlewareOptions = {\n basePath?: string;\n cleanPathname: string;\n context: AppMiddlewareContext;\n i18nConfig?: NextI18nConfig | null;\n isProxy: boolean;\n module: MiddlewareModule;\n request: Request;\n};\n\nexport type ApplyAppMiddlewareResult =\n | {\n kind: \"continue\";\n cleanPathname: string;\n search: string | null;\n }\n | {\n kind: \"response\";\n response: Response;\n };\n\ntype ForwardedMiddlewareContext = {\n h?: unknown;\n r?: unknown;\n s?: unknown;\n};\n\n// Re-exported from headers.ts for backward compatibility.\nexport { FLIGHT_HEADERS } from \"./headers.js\";\n\nconst FLIGHT_HEADER_SET = new Set(FLIGHT_HEADERS);\n\nfunction isForwardedMiddlewareContext(value: unknown): value is ForwardedMiddlewareContext {\n return !!value && typeof value === \"object\";\n}\n\nfunction requestWithoutFlightHeaders(request: Request): Request {\n let hasFlightHeader = false;\n const headers = new Headers();\n\n for (const [key, value] of request.headers) {\n if (FLIGHT_HEADER_SET.has(key.toLowerCase())) {\n hasFlightHeader = true;\n } else {\n headers.append(key, value);\n }\n }\n\n if (!hasFlightHeader) return request;\n const source = request.body ? request.clone() : request;\n return cloneRequestWithHeaders(source, headers);\n}\n\nfunction appendForwardedHeader(headers: Headers, value: unknown): void {\n if (!Array.isArray(value) || value.length < 2) return;\n const key = value[0];\n const headerValue = value[1];\n if (typeof key === \"string\" && typeof headerValue === \"string\") {\n headers.append(key, headerValue);\n }\n}\n\nfunction responseFromMiddlewareRedirect(result: {\n redirectStatus?: number;\n redirectUrl?: string;\n response?: Response;\n responseHeaders?: Headers;\n}): Response {\n if (result.response) return result.response;\n\n const headers = new Headers(result.responseHeaders);\n if (result.redirectUrl) {\n headers.set(\"Location\", result.redirectUrl);\n }\n return new Response(null, {\n status: result.redirectStatus ?? 307,\n headers,\n });\n}\n\nexport function isExternalMiddlewareRewrite(rewriteUrl: string, request: Request): boolean {\n const rewriteParsed = new URL(rewriteUrl, request.url);\n return rewriteParsed.origin !== new URL(request.url).origin;\n}\n\nfunction requestWithMiddlewareRequestHeaders(\n request: Request,\n middlewareHeaders: Headers | null,\n): Request {\n const nextHeaders = middlewareHeaders\n ? buildRequestHeadersFromMiddlewareResponse(request.headers, middlewareHeaders, {\n preserveCredentialHeaders: true,\n })\n : null;\n if (!nextHeaders) return request;\n\n const init: RequestInit = {\n method: request.method,\n headers: nextHeaders,\n body: request.body,\n };\n if (request.body) {\n Object.defineProperty(init, \"duplex\", { value: \"half\", enumerable: true });\n }\n\n return new Request(request.url, init);\n}\n\nexport async function proxyExternalMiddlewareRewrite(\n request: Request,\n rewriteUrl: string,\n context: AppMiddlewareContext,\n): Promise<Response> {\n const proxyRequest = requestWithMiddlewareRequestHeaders(\n request,\n context.requestHeaders ?? context.headers,\n );\n setHeadersContext(null);\n setNavigationContext(null);\n\n const proxyResponse = await proxyExternalRequest(proxyRequest, rewriteUrl);\n const headers = new Headers(proxyResponse.headers);\n processMiddlewareHeaders(headers);\n\n if (!context.headers) {\n return new Response(proxyResponse.body, {\n status: proxyResponse.status,\n statusText: proxyResponse.statusText,\n headers,\n });\n }\n\n const middlewareHeaders = new Headers(context.headers);\n processMiddlewareHeaders(middlewareHeaders);\n mergeMiddlewareResponseHeaders(headers, middlewareHeaders);\n return new Response(proxyResponse.body, {\n status: proxyResponse.status,\n statusText: proxyResponse.statusText,\n headers,\n });\n}\n\nfunction applyForwardedMiddlewareContext(\n request: Request,\n context: AppMiddlewareContext,\n): { applied: boolean; rewriteUrl?: string } {\n if (process.env.NODE_ENV === \"production\") {\n return { applied: false };\n }\n\n const header = request.headers.get(VINEXT_MW_CTX_HEADER);\n if (!header) return { applied: false };\n\n try {\n const data = JSON.parse(header);\n if (!isForwardedMiddlewareContext(data)) return { applied: false };\n\n if (Array.isArray(data.h) && data.h.length > 0) {\n context.headers = new Headers();\n for (const entry of data.h) {\n appendForwardedHeader(context.headers, entry);\n }\n }\n if (typeof data.s === \"number\") {\n context.status = data.s;\n }\n if (typeof data.r === \"string\" && data.r.length > 0) {\n return { applied: true, rewriteUrl: data.r };\n }\n return { applied: true };\n } catch (e) {\n console.error(\"[vinext] Failed to parse forwarded middleware context:\", e);\n return { applied: false };\n }\n}\n\nexport async function applyAppMiddleware(\n options: ApplyAppMiddlewareOptions,\n): Promise<ApplyAppMiddlewareResult> {\n const forwarded = applyForwardedMiddlewareContext(options.request, options.context);\n const middlewareRequest = requestWithoutFlightHeaders(options.request);\n let cleanPathname = options.cleanPathname;\n let search: string | null = null;\n\n if (forwarded.rewriteUrl) {\n try {\n if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, middlewareRequest)) {\n return {\n kind: \"response\",\n response: await proxyExternalMiddlewareRewrite(\n middlewareRequest,\n forwarded.rewriteUrl,\n options.context,\n ),\n };\n }\n const rewriteParsed = new URL(forwarded.rewriteUrl, middlewareRequest.url);\n cleanPathname = rewriteParsed.pathname;\n search = rewriteParsed.search;\n } catch (e) {\n console.error(\"[vinext] Failed to apply forwarded middleware rewrite:\", e);\n forwarded.applied = false;\n }\n }\n\n if (!forwarded.applied) {\n const result = await executeMiddleware({\n basePath: options.basePath,\n i18nConfig: options.i18nConfig,\n isProxy: options.isProxy,\n module: options.module,\n normalizedPathname: cleanPathname,\n request: middlewareRequest,\n });\n\n if (!result.continue) {\n if (result.redirectUrl) {\n return { kind: \"response\", response: responseFromMiddlewareRedirect(result) };\n }\n if (result.response) {\n return { kind: \"response\", response: result.response };\n }\n return { kind: \"response\", response: internalServerErrorResponse() };\n }\n\n if (result.responseHeaders) {\n options.context.headers = new Headers(result.responseHeaders);\n }\n\n if (result.status !== undefined) {\n options.context.status = result.status;\n }\n\n if (result.rewriteUrl) {\n if (result.rewriteStatus !== undefined) {\n options.context.status = result.rewriteStatus;\n }\n if (isExternalUrl(result.rewriteUrl)) {\n return {\n kind: \"response\",\n response: await proxyExternalMiddlewareRewrite(\n middlewareRequest,\n result.rewriteUrl,\n options.context,\n ),\n };\n }\n const rewriteParsed = new URL(result.rewriteUrl, middlewareRequest.url);\n cleanPathname = rewriteParsed.pathname;\n search = rewriteParsed.search;\n }\n }\n\n if (options.context.headers) {\n options.context.requestHeaders = new Headers(options.context.headers);\n applyMiddlewareRequestHeaders(options.context.headers);\n processMiddlewareHeaders(options.context.headers);\n }\n\n return { kind: \"continue\", cleanPathname, search };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-mounted-slots-header.js","names":[],"sources":["../../src/server/app-mounted-slots-header.ts"],"sourcesContent":["/**\n * Normalize the `x-vinext-mounted-slots` header for request handling and cache keying.\n *\n * The browser sends mounted slot ids as a space-separated list in the order slots were\n * rendered, which changes across navigations. This normalizes to a canonical form\n * (sorted, deduplicated) so equivalent slot sets map to the same RSC cache entry.\n *\n * Consumed by:\n * - app-rsc-request-normalization (request lifecycle, reads incoming header)\n * - app-elements (outgoing x-vinext-mounted-slots construction)\n * - isr-cache (RSC cache key generation)\n */\nexport function normalizeMountedSlotsHeader(raw: string | null | undefined): string | null {\n if (!raw) return null;\n const normalized = Array.from(new Set(raw.split(/\\s+/).filter(Boolean)))\n .sort()\n .join(\" \");\n return normalized || null;\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,4BAA4B,KAA+C;
|
|
1
|
+
{"version":3,"file":"app-mounted-slots-header.js","names":[],"sources":["../../src/server/app-mounted-slots-header.ts"],"sourcesContent":["/**\n * Normalize the `x-vinext-mounted-slots` header for request handling and cache keying.\n *\n * The browser sends mounted slot ids as a space-separated list in the order slots were\n * rendered, which changes across navigations. This normalizes to a canonical form\n * (sorted, deduplicated) so equivalent slot sets map to the same RSC cache entry.\n *\n * Consumed by:\n * - app-rsc-request-normalization (request lifecycle, reads incoming header)\n * - app-elements (outgoing x-vinext-mounted-slots construction)\n * - isr-cache (RSC cache key generation)\n */\nexport function normalizeMountedSlotsHeader(raw: string | null | undefined): string | null {\n if (!raw) return null;\n const normalized = Array.from(new Set(raw.split(/\\s+/).filter(Boolean)))\n .sort()\n .join(\" \");\n return normalized || null;\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,4BAA4B,KAA+C;CACzF,IAAI,CAAC,KAAK,OAAO;CAIjB,OAHmB,MAAM,KAAK,IAAI,IAAI,IAAI,MAAM,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC,CACrE,MAAM,CACN,KAAK,IACS,IAAI"}
|
|
@@ -14,6 +14,7 @@ type AppPageModule = Record<string, unknown> & {
|
|
|
14
14
|
type AppPageBoundaryOnError = (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;
|
|
15
15
|
type AppPageBoundaryRoute<TModule extends AppPageModule = AppPageModule> = {
|
|
16
16
|
error?: TModule | null;
|
|
17
|
+
errorPaths?: readonly TModule[] | null;
|
|
17
18
|
errors?: readonly (TModule | null | undefined)[] | null;
|
|
18
19
|
forbidden?: TModule | null;
|
|
19
20
|
layoutTreePositions?: readonly number[] | null;
|
|
@@ -44,18 +44,15 @@ function wrapRenderedBoundaryElement(options) {
|
|
|
44
44
|
skipLayoutWrapping: options.skipLayoutWrapping
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
-
function
|
|
48
|
-
if (route
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (rootLayoutEntry) return rootLayoutEntry.treePath;
|
|
57
|
-
}
|
|
58
|
-
return null;
|
|
47
|
+
function createAppPageBoundaryLayoutEntries(route, layoutModules) {
|
|
48
|
+
if (!route || layoutModules.length === 0) return [];
|
|
49
|
+
return createAppPageLayoutEntries({
|
|
50
|
+
errors: route.errors,
|
|
51
|
+
layoutTreePositions: route.layoutTreePositions,
|
|
52
|
+
layouts: layoutModules,
|
|
53
|
+
notFounds: null,
|
|
54
|
+
routeSegments: route.routeSegments
|
|
55
|
+
});
|
|
59
56
|
}
|
|
60
57
|
function resolveHttpAccessFallbackHeadRouteSegments(route, layoutModules) {
|
|
61
58
|
if (!route?.routeSegments) return;
|
|
@@ -71,10 +68,12 @@ function resolveHttpAccessFallbackHeadLayoutTreePositions(route, layoutModules)
|
|
|
71
68
|
}
|
|
72
69
|
function createAppPageBoundaryRscPayload(options) {
|
|
73
70
|
const routeId = AppElementsWire.encodeRouteId(options.pathname, null);
|
|
71
|
+
const layoutEntries = createAppPageBoundaryLayoutEntries(options.route, options.layoutModules);
|
|
74
72
|
return {
|
|
75
73
|
...AppElementsWire.createMetadataEntries({
|
|
76
74
|
interceptionContext: null,
|
|
77
|
-
|
|
75
|
+
layoutIds: layoutEntries.map((entry) => entry.id),
|
|
76
|
+
rootLayoutTreePath: layoutEntries[0]?.treePath ?? null,
|
|
78
77
|
routeId
|
|
79
78
|
}),
|
|
80
79
|
[routeId]: options.element
|
|
@@ -107,6 +106,7 @@ async function renderAppPageBoundaryElementResponse(options) {
|
|
|
107
106
|
},
|
|
108
107
|
element: createAppPageBoundaryRscPayload({
|
|
109
108
|
element: options.element,
|
|
109
|
+
layoutModules: options.layoutModules,
|
|
110
110
|
pathname,
|
|
111
111
|
route: options.route
|
|
112
112
|
}),
|
|
@@ -178,6 +178,7 @@ async function renderAppPageHttpAccessFallback(options) {
|
|
|
178
178
|
async function renderAppPageErrorBoundary(options) {
|
|
179
179
|
const errorBoundary = resolveAppPageErrorBoundary({
|
|
180
180
|
getDefaultExport,
|
|
181
|
+
errorModules: options.route?.errorPaths,
|
|
181
182
|
globalErrorModule: options.globalErrorModule,
|
|
182
183
|
layoutErrorModules: options.route?.errors,
|
|
183
184
|
pageErrorModule: options.route?.error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-boundary-render.js","names":[],"sources":["../../src/server/app-page-boundary-render.ts"],"sourcesContent":["import { Fragment, createElement, type ComponentType, type ReactNode } from \"react\";\nimport { buildClientHookErrorMessage } from \"vinext/shims/client-hook-error\";\nimport { ErrorBoundary } from \"vinext/shims/error-boundary\";\nimport { LayoutSegmentProvider } from \"vinext/shims/layout-segment-context\";\nimport { MetadataHead, ViewportHead } from \"vinext/shims/metadata\";\nimport type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { AppPageMiddlewareContext } from \"./app-page-response.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport { resolveAppPageHead } from \"./app-page-head.js\";\nimport {\n renderAppPageBoundaryResponse,\n resolveAppPageErrorBoundary,\n resolveAppPageHttpAccessBoundaryComponent,\n wrapAppPageBoundaryElement,\n type AppPageParams,\n} from \"./app-page-boundary.js\";\nimport {\n createAppPageFontData,\n renderAppPageHtmlResponse,\n type AppPageSsrHandler,\n} from \"./app-page-stream.js\";\nimport { AppElementsWire, type AppElements } from \"./app-elements.js\";\nimport { createAppPageLayoutEntries } from \"./app-page-route-wiring.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AppPageComponent = ComponentType<any>;\ntype AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype AppPageBoundaryRscPayloadOptions<TModule extends AppPageModule = AppPageModule> = {\n element: ReactNode;\n pathname: string;\n route?: AppPageBoundaryRoute<TModule> | null;\n};\n\nexport type AppPageBoundaryRoute<TModule extends AppPageModule = AppPageModule> = {\n error?: TModule | null;\n errors?: readonly (TModule | null | undefined)[] | null;\n forbidden?: TModule | null;\n layoutTreePositions?: readonly number[] | null;\n layouts?: readonly (TModule | null | undefined)[];\n notFound?: TModule | null;\n params?: AppPageParams;\n pattern?: string;\n routeSegments?: readonly string[];\n unauthorized?: TModule | null;\n};\n\ntype AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageModule> = {\n buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;\n clearRequestContext: () => void;\n createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;\n getFontLinks: () => string[];\n getFontPreloads: () => AppPageFontPreload[];\n getFontStyles: () => string[];\n getNavigationContext: () => unknown;\n globalErrorModule?: TModule | null;\n isRscRequest: boolean;\n loadSsrHandler: () => Promise<AppPageSsrHandler>;\n makeThenableParams: (params: AppPageParams) => unknown;\n middlewareContext: AppPageMiddlewareContext;\n metadataRoutes: MetadataFileRoute[];\n renderToReadableStream: (\n element: ReactNode | AppElements,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n requestUrl: string;\n resolveChildSegments: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => string[];\n rootLayouts: readonly (TModule | null | undefined)[];\n scriptNonce?: string;\n};\n\ntype RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppPageModule> = {\n boundaryComponent?: AppPageComponent | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n matchedParams: AppPageParams;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n statusCode: number;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\ntype RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {\n error: unknown;\n matchedParams?: AppPageParams | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n sanitizeErrorForClient: (error: Error) => Error;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\nfunction getDefaultExport<TModule extends AppPageModule>(\n module: TModule | null | undefined,\n): AppPageComponent | null {\n return module?.default ?? null;\n}\n\nfunction wrapRenderedBoundaryElement<TModule extends AppPageModule>(\n options: Pick<\n AppPageBoundaryRenderCommonOptions<TModule>,\n \"globalErrorModule\" | \"isRscRequest\" | \"makeThenableParams\" | \"resolveChildSegments\"\n > & {\n element: ReactNode;\n includeGlobalErrorBoundary: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n matchedParams: AppPageParams;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n },\n): ReactNode {\n return wrapAppPageBoundaryElement({\n element: options.element,\n getDefaultExport,\n globalErrorComponent: getDefaultExport(options.globalErrorModule),\n includeGlobalErrorBoundary: options.includeGlobalErrorBoundary,\n isRscRequest: options.isRscRequest,\n layoutModules: options.layoutModules,\n layoutTreePositions: options.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n renderErrorBoundary(GlobalErrorComponent, children) {\n return createElement(ErrorBoundary, {\n fallback: GlobalErrorComponent,\n // oxlint-disable-next-line react/no-children-prop\n children,\n });\n },\n renderLayout(LayoutComponent, children, asyncParams) {\n return createElement(LayoutComponent as AppPageComponent, {\n // oxlint-disable-next-line react/no-children-prop\n children,\n params: asyncParams,\n });\n },\n renderLayoutSegmentProvider(segmentMap, children) {\n return createElement(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n LayoutSegmentProvider as ComponentType<any>,\n { segmentMap },\n children,\n );\n },\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.routeSegments ?? [],\n skipLayoutWrapping: options.skipLayoutWrapping,\n });\n}\n\nfunction resolveAppPageBoundaryRootLayoutTreePath<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n): string | null {\n if (route?.layouts) {\n const rootLayoutEntry = createAppPageLayoutEntries({\n errors: route.errors,\n layoutTreePositions: route.layoutTreePositions,\n layouts: route.layouts,\n notFounds: null,\n routeSegments: route.routeSegments,\n })[0];\n\n if (rootLayoutEntry) {\n return rootLayoutEntry.treePath;\n }\n }\n\n // Without route tree metadata we cannot derive a canonical root layout tree path.\n // Returning null keeps boundary payloads soft-navigation compatible.\n return null;\n}\n\nfunction resolveHttpAccessFallbackHeadRouteSegments<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly string[] | undefined {\n if (!route?.routeSegments) {\n return undefined;\n }\n\n if (!route.layouts || layoutModules.length >= route.layouts.length) {\n return route.routeSegments;\n }\n\n const lastIncludedLayoutIndex = layoutModules.length - 1;\n if (lastIncludedLayoutIndex < 0) {\n return [];\n }\n\n const segmentCount = route.layoutTreePositions?.[lastIncludedLayoutIndex] ?? 0;\n return route.routeSegments.slice(0, segmentCount);\n}\n\nfunction resolveHttpAccessFallbackHeadLayoutTreePositions<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly number[] | null | undefined {\n if (!route?.layouts || layoutModules.length >= route.layouts.length) {\n return route?.layoutTreePositions;\n }\n\n return route.layoutTreePositions?.slice(0, layoutModules.length);\n}\n\nfunction createAppPageBoundaryRscPayload<TModule extends AppPageModule>(\n options: AppPageBoundaryRscPayloadOptions<TModule>,\n): AppElements {\n const routeId = AppElementsWire.encodeRouteId(options.pathname, null);\n\n return {\n ...AppElementsWire.createMetadataEntries({\n interceptionContext: null,\n rootLayoutTreePath: resolveAppPageBoundaryRootLayoutTreePath(options.route),\n routeId,\n }),\n [routeId]: options.element,\n };\n}\n\nasync function renderAppPageBoundaryElementResponse<TModule extends AppPageModule>(\n options: AppPageBoundaryRenderCommonOptions<TModule> & {\n element: ReactNode;\n layoutModules: readonly (TModule | null | undefined)[];\n route?: AppPageBoundaryRoute<TModule> | null;\n routePattern?: string;\n status: number;\n },\n): Promise<Response> {\n const pathname = new URL(options.requestUrl).pathname;\n const payload = createAppPageBoundaryRscPayload({\n element: options.element,\n pathname,\n route: options.route,\n });\n\n return renderAppPageBoundaryResponse({\n async createHtmlResponse(rscStream, responseStatus) {\n const fontData = createAppPageFontData({\n getLinks: options.getFontLinks,\n getPreloads: options.getFontPreloads,\n getStyles: options.getFontStyles,\n });\n const ssrHandler = await options.loadSsrHandler();\n return renderAppPageHtmlResponse({\n clearRequestContext: options.clearRequestContext,\n fontData,\n fontLinkHeader: options.buildFontLinkHeader(fontData.preloads),\n middlewareHeaders: options.middlewareContext.headers,\n navigationContext: options.getNavigationContext(),\n rscStream,\n scriptNonce: options.scriptNonce,\n ssrHandler,\n status: responseStatus,\n });\n },\n createRscOnErrorHandler() {\n return options.createRscOnErrorHandler(pathname, options.routePattern ?? pathname);\n },\n element: payload,\n isRscRequest: options.isRscRequest,\n middlewareHeaders: options.middlewareContext.headers,\n renderToReadableStream: options.renderToReadableStream,\n status: options.status,\n });\n}\n\nexport async function renderAppPageHttpAccessFallback<TModule extends AppPageModule>(\n options: RenderAppPageHttpAccessFallbackOptions<TModule>,\n): Promise<Response | null> {\n const boundaryComponent =\n options.boundaryComponent ??\n resolveAppPageHttpAccessBoundaryComponent({\n getDefaultExport,\n rootForbiddenModule: options.rootForbiddenModule,\n rootNotFoundModule: options.rootNotFoundModule,\n rootUnauthorizedModule: options.rootUnauthorizedModule,\n routeForbiddenModule: options.route?.forbidden,\n routeNotFoundModule: options.route?.notFound,\n routeUnauthorizedModule: options.route?.unauthorized,\n statusCode: options.statusCode,\n });\n if (!boundaryComponent) {\n return null;\n }\n\n const layoutModules = options.layoutModules ?? options.route?.layouts ?? options.rootLayouts;\n const routeSegments = resolveHttpAccessFallbackHeadRouteSegments(options.route, layoutModules);\n const { metadata, viewport } = await resolveAppPageHead({\n layoutModules,\n layoutTreePositions: resolveHttpAccessFallbackHeadLayoutTreePositions(\n options.route,\n layoutModules,\n ),\n metadataRoutes: options.metadataRoutes,\n params: options.matchedParams,\n routePath: options.route?.pattern ?? new URL(options.requestUrl).pathname,\n routeSegments,\n });\n\n const headElements: ReactNode[] = [\n createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" }),\n createElement(\"meta\", { content: \"noindex\", key: \"robots\", name: \"robots\" }),\n ];\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(Fragment, null, ...headElements, createElement(boundaryComponent)),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: true,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: options.statusCode,\n });\n}\n\nexport async function renderAppPageErrorBoundary<TModule extends AppPageModule>(\n options: RenderAppPageErrorBoundaryOptions<TModule>,\n): Promise<Response | null> {\n const errorBoundary = resolveAppPageErrorBoundary({\n getDefaultExport,\n globalErrorModule: options.globalErrorModule,\n layoutErrorModules: options.route?.errors,\n pageErrorModule: options.route?.error,\n });\n if (!errorBoundary.component) {\n return null;\n }\n\n const rawError =\n options.error instanceof Error ? options.error : new Error(String(options.error));\n rewriteClientHookError(rawError);\n const errorObject = options.sanitizeErrorForClient(rawError);\n const matchedParams = options.matchedParams ?? options.route?.params ?? {};\n const layoutModules = options.route?.layouts ?? options.rootLayouts;\n const pathname = new URL(options.requestUrl).pathname;\n\n const headElements: ReactNode[] = [createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" })];\n if (!errorBoundary.isGlobalError) {\n try {\n const { metadata, viewport } = await resolveAppPageHead({\n fallbackOnFileMetadataError: true,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n metadataRoutes: options.metadataRoutes,\n params: matchedParams,\n routePath: options.route?.pattern ?? pathname,\n routeSegments: options.route?.routeSegments,\n });\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n } catch (error) {\n console.error(\n `[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`,\n error,\n );\n }\n }\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(\n Fragment,\n null,\n ...headElements,\n createElement(errorBoundary.component, {\n error: errorObject,\n }),\n ),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: !errorBoundary.isGlobalError,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n skipLayoutWrapping: errorBoundary.isGlobalError,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: 200,\n });\n}\n\n// React client-only hooks that are absent from the `react-server` export\n// condition. When called in a Server Component they produce a TypeError like\n// \"useState is not a function\". Rewrite into an actionable message matching\n// the format used by the next/navigation shims (see client-hook-error.ts).\nconst _clientHookPattern =\n /\\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\\b.*is not a function/;\n\nfunction rewriteClientHookError(error: Error): void {\n const match = error.message.match(_clientHookPattern);\n if (match) {\n error.message = buildClientHookErrorMessage(`${match[1]}()`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-page-boundary-render.js","names":[],"sources":["../../src/server/app-page-boundary-render.ts"],"sourcesContent":["import { Fragment, createElement, type ComponentType, type ReactNode } from \"react\";\nimport { buildClientHookErrorMessage } from \"vinext/shims/client-hook-error\";\nimport { ErrorBoundary } from \"vinext/shims/error-boundary\";\nimport { LayoutSegmentProvider } from \"vinext/shims/layout-segment-context\";\nimport { MetadataHead, ViewportHead } from \"vinext/shims/metadata\";\nimport type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { AppPageMiddlewareContext } from \"./app-page-response.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport { resolveAppPageHead } from \"./app-page-head.js\";\nimport {\n renderAppPageBoundaryResponse,\n resolveAppPageErrorBoundary,\n resolveAppPageHttpAccessBoundaryComponent,\n wrapAppPageBoundaryElement,\n type AppPageParams,\n} from \"./app-page-boundary.js\";\nimport {\n createAppPageFontData,\n renderAppPageHtmlResponse,\n type AppPageSsrHandler,\n} from \"./app-page-stream.js\";\nimport { AppElementsWire, type AppElements } from \"./app-elements.js\";\nimport { createAppPageLayoutEntries } from \"./app-page-route-wiring.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AppPageComponent = ComponentType<any>;\ntype AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype AppPageBoundaryRscPayloadOptions<TModule extends AppPageModule = AppPageModule> = {\n element: ReactNode;\n layoutModules: readonly (TModule | null | undefined)[];\n pathname: string;\n route?: AppPageBoundaryRoute<TModule> | null;\n};\n\ntype AppPageBoundaryLayoutEntry = {\n id: string;\n treePath: string;\n};\n\nexport type AppPageBoundaryRoute<TModule extends AppPageModule = AppPageModule> = {\n error?: TModule | null;\n errorPaths?: readonly TModule[] | null;\n errors?: readonly (TModule | null | undefined)[] | null;\n forbidden?: TModule | null;\n layoutTreePositions?: readonly number[] | null;\n layouts?: readonly (TModule | null | undefined)[];\n notFound?: TModule | null;\n params?: AppPageParams;\n pattern?: string;\n routeSegments?: readonly string[];\n unauthorized?: TModule | null;\n};\n\ntype AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageModule> = {\n buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;\n clearRequestContext: () => void;\n createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;\n getFontLinks: () => string[];\n getFontPreloads: () => AppPageFontPreload[];\n getFontStyles: () => string[];\n getNavigationContext: () => unknown;\n globalErrorModule?: TModule | null;\n isRscRequest: boolean;\n loadSsrHandler: () => Promise<AppPageSsrHandler>;\n makeThenableParams: (params: AppPageParams) => unknown;\n middlewareContext: AppPageMiddlewareContext;\n metadataRoutes: MetadataFileRoute[];\n renderToReadableStream: (\n element: ReactNode | AppElements,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n requestUrl: string;\n resolveChildSegments: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => string[];\n rootLayouts: readonly (TModule | null | undefined)[];\n scriptNonce?: string;\n};\n\ntype RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppPageModule> = {\n boundaryComponent?: AppPageComponent | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n matchedParams: AppPageParams;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n statusCode: number;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\ntype RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {\n error: unknown;\n matchedParams?: AppPageParams | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n sanitizeErrorForClient: (error: Error) => Error;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\nfunction getDefaultExport<TModule extends AppPageModule>(\n module: TModule | null | undefined,\n): AppPageComponent | null {\n return module?.default ?? null;\n}\n\nfunction wrapRenderedBoundaryElement<TModule extends AppPageModule>(\n options: Pick<\n AppPageBoundaryRenderCommonOptions<TModule>,\n \"globalErrorModule\" | \"isRscRequest\" | \"makeThenableParams\" | \"resolveChildSegments\"\n > & {\n element: ReactNode;\n includeGlobalErrorBoundary: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n matchedParams: AppPageParams;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n },\n): ReactNode {\n return wrapAppPageBoundaryElement({\n element: options.element,\n getDefaultExport,\n globalErrorComponent: getDefaultExport(options.globalErrorModule),\n includeGlobalErrorBoundary: options.includeGlobalErrorBoundary,\n isRscRequest: options.isRscRequest,\n layoutModules: options.layoutModules,\n layoutTreePositions: options.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n renderErrorBoundary(GlobalErrorComponent, children) {\n return createElement(ErrorBoundary, {\n fallback: GlobalErrorComponent,\n // oxlint-disable-next-line react/no-children-prop\n children,\n });\n },\n renderLayout(LayoutComponent, children, asyncParams) {\n return createElement(LayoutComponent as AppPageComponent, {\n // oxlint-disable-next-line react/no-children-prop\n children,\n params: asyncParams,\n });\n },\n renderLayoutSegmentProvider(segmentMap, children) {\n return createElement(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n LayoutSegmentProvider as ComponentType<any>,\n { segmentMap },\n children,\n );\n },\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.routeSegments ?? [],\n skipLayoutWrapping: options.skipLayoutWrapping,\n });\n}\n\nfunction createAppPageBoundaryLayoutEntries<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly AppPageBoundaryLayoutEntry[] {\n if (!route || layoutModules.length === 0) return [];\n\n return createAppPageLayoutEntries({\n errors: route.errors,\n layoutTreePositions: route.layoutTreePositions,\n layouts: layoutModules,\n notFounds: null,\n routeSegments: route.routeSegments,\n });\n}\n\nfunction resolveHttpAccessFallbackHeadRouteSegments<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly string[] | undefined {\n if (!route?.routeSegments) {\n return undefined;\n }\n\n if (!route.layouts || layoutModules.length >= route.layouts.length) {\n return route.routeSegments;\n }\n\n const lastIncludedLayoutIndex = layoutModules.length - 1;\n if (lastIncludedLayoutIndex < 0) {\n return [];\n }\n\n const segmentCount = route.layoutTreePositions?.[lastIncludedLayoutIndex] ?? 0;\n return route.routeSegments.slice(0, segmentCount);\n}\n\nfunction resolveHttpAccessFallbackHeadLayoutTreePositions<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly number[] | null | undefined {\n if (!route?.layouts || layoutModules.length >= route.layouts.length) {\n return route?.layoutTreePositions;\n }\n\n return route.layoutTreePositions?.slice(0, layoutModules.length);\n}\n\nfunction createAppPageBoundaryRscPayload<TModule extends AppPageModule>(\n options: AppPageBoundaryRscPayloadOptions<TModule>,\n): AppElements {\n const routeId = AppElementsWire.encodeRouteId(options.pathname, null);\n const layoutEntries = createAppPageBoundaryLayoutEntries(options.route, options.layoutModules);\n\n return {\n ...AppElementsWire.createMetadataEntries({\n interceptionContext: null,\n layoutIds: layoutEntries.map((entry) => entry.id),\n rootLayoutTreePath: layoutEntries[0]?.treePath ?? null,\n routeId,\n }),\n [routeId]: options.element,\n };\n}\n\nasync function renderAppPageBoundaryElementResponse<TModule extends AppPageModule>(\n options: AppPageBoundaryRenderCommonOptions<TModule> & {\n element: ReactNode;\n layoutModules: readonly (TModule | null | undefined)[];\n route?: AppPageBoundaryRoute<TModule> | null;\n routePattern?: string;\n status: number;\n },\n): Promise<Response> {\n const pathname = new URL(options.requestUrl).pathname;\n const payload = createAppPageBoundaryRscPayload({\n element: options.element,\n layoutModules: options.layoutModules,\n pathname,\n route: options.route,\n });\n\n return renderAppPageBoundaryResponse({\n async createHtmlResponse(rscStream, responseStatus) {\n const fontData = createAppPageFontData({\n getLinks: options.getFontLinks,\n getPreloads: options.getFontPreloads,\n getStyles: options.getFontStyles,\n });\n const ssrHandler = await options.loadSsrHandler();\n return renderAppPageHtmlResponse({\n clearRequestContext: options.clearRequestContext,\n fontData,\n fontLinkHeader: options.buildFontLinkHeader(fontData.preloads),\n middlewareHeaders: options.middlewareContext.headers,\n navigationContext: options.getNavigationContext(),\n rscStream,\n scriptNonce: options.scriptNonce,\n ssrHandler,\n status: responseStatus,\n });\n },\n createRscOnErrorHandler() {\n return options.createRscOnErrorHandler(pathname, options.routePattern ?? pathname);\n },\n element: payload,\n isRscRequest: options.isRscRequest,\n middlewareHeaders: options.middlewareContext.headers,\n renderToReadableStream: options.renderToReadableStream,\n status: options.status,\n });\n}\n\nexport async function renderAppPageHttpAccessFallback<TModule extends AppPageModule>(\n options: RenderAppPageHttpAccessFallbackOptions<TModule>,\n): Promise<Response | null> {\n const boundaryComponent =\n options.boundaryComponent ??\n resolveAppPageHttpAccessBoundaryComponent({\n getDefaultExport,\n rootForbiddenModule: options.rootForbiddenModule,\n rootNotFoundModule: options.rootNotFoundModule,\n rootUnauthorizedModule: options.rootUnauthorizedModule,\n routeForbiddenModule: options.route?.forbidden,\n routeNotFoundModule: options.route?.notFound,\n routeUnauthorizedModule: options.route?.unauthorized,\n statusCode: options.statusCode,\n });\n if (!boundaryComponent) {\n return null;\n }\n\n const layoutModules = options.layoutModules ?? options.route?.layouts ?? options.rootLayouts;\n const routeSegments = resolveHttpAccessFallbackHeadRouteSegments(options.route, layoutModules);\n const { metadata, viewport } = await resolveAppPageHead({\n layoutModules,\n layoutTreePositions: resolveHttpAccessFallbackHeadLayoutTreePositions(\n options.route,\n layoutModules,\n ),\n metadataRoutes: options.metadataRoutes,\n params: options.matchedParams,\n routePath: options.route?.pattern ?? new URL(options.requestUrl).pathname,\n routeSegments,\n });\n\n const headElements: ReactNode[] = [\n createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" }),\n createElement(\"meta\", { content: \"noindex\", key: \"robots\", name: \"robots\" }),\n ];\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(Fragment, null, ...headElements, createElement(boundaryComponent)),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: true,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: options.statusCode,\n });\n}\n\nexport async function renderAppPageErrorBoundary<TModule extends AppPageModule>(\n options: RenderAppPageErrorBoundaryOptions<TModule>,\n): Promise<Response | null> {\n const errorBoundary = resolveAppPageErrorBoundary({\n getDefaultExport,\n errorModules: options.route?.errorPaths,\n globalErrorModule: options.globalErrorModule,\n layoutErrorModules: options.route?.errors,\n pageErrorModule: options.route?.error,\n });\n if (!errorBoundary.component) {\n return null;\n }\n\n const rawError =\n options.error instanceof Error ? options.error : new Error(String(options.error));\n rewriteClientHookError(rawError);\n const errorObject = options.sanitizeErrorForClient(rawError);\n const matchedParams = options.matchedParams ?? options.route?.params ?? {};\n const layoutModules = options.route?.layouts ?? options.rootLayouts;\n const pathname = new URL(options.requestUrl).pathname;\n\n const headElements: ReactNode[] = [createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" })];\n if (!errorBoundary.isGlobalError) {\n try {\n const { metadata, viewport } = await resolveAppPageHead({\n fallbackOnFileMetadataError: true,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n metadataRoutes: options.metadataRoutes,\n params: matchedParams,\n routePath: options.route?.pattern ?? pathname,\n routeSegments: options.route?.routeSegments,\n });\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n } catch (error) {\n console.error(\n `[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`,\n error,\n );\n }\n }\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(\n Fragment,\n null,\n ...headElements,\n createElement(errorBoundary.component, {\n error: errorObject,\n }),\n ),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: !errorBoundary.isGlobalError,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n skipLayoutWrapping: errorBoundary.isGlobalError,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: 200,\n });\n}\n\n// React client-only hooks that are absent from the `react-server` export\n// condition. When called in a Server Component they produce a TypeError like\n// \"useState is not a function\". Rewrite into an actionable message matching\n// the format used by the next/navigation shims (see client-hook-error.ts).\nconst _clientHookPattern =\n /\\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\\b.*is not a function/;\n\nfunction rewriteClientHookError(error: Error): void {\n const match = error.message.match(_clientHookPattern);\n if (match) {\n error.message = buildClientHookErrorMessage(`${match[1]}()`);\n }\n}\n"],"mappings":"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"}
|
|
@@ -23,6 +23,7 @@ type ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule> = {
|
|
|
23
23
|
type ResolveAppPageErrorBoundaryOptions<TModule, TComponent> = {
|
|
24
24
|
getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;
|
|
25
25
|
globalErrorModule?: TModule | null;
|
|
26
|
+
errorModules?: readonly (TModule | null | undefined)[] | null;
|
|
26
27
|
layoutErrorModules?: readonly (TModule | null | undefined)[] | null;
|
|
27
28
|
pageErrorModule?: TModule | null;
|
|
28
29
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runWithFetchDedupe } from "../shims/fetch-cache.js";
|
|
1
2
|
import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-cache-busting.js";
|
|
2
3
|
import { resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
3
4
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
@@ -31,10 +32,11 @@ function resolveAppPageErrorBoundary(options) {
|
|
|
31
32
|
component: pageErrorComponent,
|
|
32
33
|
isGlobalError: false
|
|
33
34
|
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
const segmentErrorModules = options.errorModules ?? options.layoutErrorModules;
|
|
36
|
+
if (segmentErrorModules) for (let index = segmentErrorModules.length - 1; index >= 0; index--) {
|
|
37
|
+
const segmentErrorComponent = options.getDefaultExport(segmentErrorModules[index]);
|
|
38
|
+
if (segmentErrorComponent) return {
|
|
39
|
+
component: segmentErrorComponent,
|
|
38
40
|
isGlobalError: false
|
|
39
41
|
};
|
|
40
42
|
}
|
|
@@ -61,7 +63,7 @@ function wrapAppPageBoundaryElement(options) {
|
|
|
61
63
|
return element;
|
|
62
64
|
}
|
|
63
65
|
async function renderAppPageBoundaryResponse(options) {
|
|
64
|
-
const rscStream = options.renderToReadableStream(options.element, { onError: options.createRscOnErrorHandler() });
|
|
66
|
+
const rscStream = runWithFetchDedupe(() => options.renderToReadableStream(options.element, { onError: options.createRscOnErrorHandler() }));
|
|
65
67
|
if (options.isRscRequest) {
|
|
66
68
|
const headers = new Headers({
|
|
67
69
|
"Content-Type": "text/x-component; charset=utf-8",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-boundary.js","names":[],"sources":["../../src/server/app-page-boundary.ts"],"sourcesContent":["import { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { VINEXT_RSC_VARY_HEADER } from \"./app-rsc-cache-busting.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\n\nexport type AppPageParams = Record<string, string | string[]>;\n\ntype ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModule?: TModule | null;\n routeNotFoundModule?: TModule | null;\n routeUnauthorizedModule?: TModule | null;\n statusCode: number;\n};\n\ntype ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule> = {\n layoutIndex: number;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModules?: readonly (TModule | null | undefined)[] | null;\n routeNotFoundModules?: readonly (TModule | null | undefined)[] | null;\n routeUnauthorizedModules?: readonly (TModule | null | undefined)[] | null;\n statusCode: number;\n};\n\ntype ResolveAppPageErrorBoundaryOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n globalErrorModule?: TModule | null;\n layoutErrorModules?: readonly (TModule | null | undefined)[] | null;\n pageErrorModule?: TModule | null;\n};\n\ntype ResolveAppPageErrorBoundaryResult<TComponent> = {\n component: TComponent | null;\n isGlobalError: boolean;\n};\n\ntype WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n> = {\n element: TElement;\n getDefaultExport: (\n module: TLayoutModule | null | undefined,\n ) => TLayoutComponent | null | undefined;\n globalErrorComponent?: TGlobalErrorComponent | null;\n includeGlobalErrorBoundary: boolean;\n isRscRequest: boolean;\n layoutModules: readonly (TLayoutModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n matchedParams: AppPageParams;\n renderErrorBoundary: (component: TGlobalErrorComponent, children: TElement) => TElement;\n renderLayout: (component: TLayoutComponent, children: TElement, params: unknown) => TElement;\n renderLayoutSegmentProvider?: (\n segmentMap: { children: TChildSegments },\n children: TElement,\n ) => TElement;\n resolveChildSegments?: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => TChildSegments;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n};\n\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype RenderAppPageBoundaryResponseOptions<TElement> = {\n createHtmlResponse: (rscStream: ReadableStream<Uint8Array>, status: number) => Promise<Response>;\n createRscOnErrorHandler: () => AppPageBoundaryOnError;\n element: TElement;\n isRscRequest: boolean;\n middlewareHeaders?: Headers | null;\n renderToReadableStream: (\n element: TElement,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n status: number;\n};\n\nexport function resolveAppPageHttpAccessBoundaryComponent<TModule, TComponent>(\n options: ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent>,\n): TComponent | null {\n let boundaryModule: TModule | null | undefined;\n\n if (options.statusCode === 403) {\n boundaryModule = options.routeForbiddenModule ?? options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n boundaryModule = options.routeUnauthorizedModule ?? options.rootUnauthorizedModule;\n } else {\n boundaryModule = options.routeNotFoundModule ?? options.rootNotFoundModule;\n }\n\n return options.getDefaultExport(boundaryModule) ?? null;\n}\n\nexport function resolveAppPageParentHttpAccessBoundaryModule<TModule>(\n options: ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule>,\n): TModule | null {\n let routeModules = options.routeNotFoundModules;\n let rootModule = options.rootNotFoundModule;\n\n if (options.statusCode === 403) {\n routeModules = options.routeForbiddenModules;\n rootModule = options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n routeModules = options.routeUnauthorizedModules;\n rootModule = options.rootUnauthorizedModule;\n }\n\n if (routeModules) {\n for (let index = options.layoutIndex - 1; index >= 0; index--) {\n const module = routeModules[index];\n if (module) {\n return module;\n }\n }\n }\n\n return rootModule ?? null;\n}\n\nexport function resolveAppPageErrorBoundary<TModule, TComponent>(\n options: ResolveAppPageErrorBoundaryOptions<TModule, TComponent>,\n): ResolveAppPageErrorBoundaryResult<TComponent> {\n const pageErrorComponent = options.getDefaultExport(options.pageErrorModule);\n if (pageErrorComponent) {\n return {\n component: pageErrorComponent,\n isGlobalError: false,\n };\n }\n\n if (options.layoutErrorModules) {\n for (let index = options.layoutErrorModules.length - 1; index >= 0; index--) {\n const layoutErrorComponent = options.getDefaultExport(options.layoutErrorModules[index]);\n if (layoutErrorComponent) {\n return {\n component: layoutErrorComponent,\n isGlobalError: false,\n };\n }\n }\n }\n\n const globalErrorComponent = options.getDefaultExport(options.globalErrorModule);\n return {\n component: globalErrorComponent ?? null,\n isGlobalError: Boolean(globalErrorComponent),\n };\n}\n\nexport function wrapAppPageBoundaryElement<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n>(\n options: WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent\n >,\n): TElement {\n let element = options.element;\n\n if (!options.skipLayoutWrapping) {\n for (let index = options.layoutModules.length - 1; index >= 0; index--) {\n const layoutComponent = options.getDefaultExport(options.layoutModules[index]);\n if (!layoutComponent) {\n continue;\n }\n\n const treePosition = options.layoutTreePositions ? options.layoutTreePositions[index] : 0;\n const asyncParams = options.makeThenableParams(\n resolveAppPageSegmentParams(options.routeSegments, treePosition, options.matchedParams),\n );\n element = options.renderLayout(layoutComponent, element, asyncParams);\n\n if (\n options.isRscRequest &&\n options.renderLayoutSegmentProvider &&\n options.resolveChildSegments\n ) {\n const childSegments = options.resolveChildSegments(\n options.routeSegments ?? [],\n treePosition,\n options.matchedParams,\n );\n element = options.renderLayoutSegmentProvider({ children: childSegments }, element);\n }\n }\n }\n\n if (options.isRscRequest && options.includeGlobalErrorBoundary && options.globalErrorComponent) {\n element = options.renderErrorBoundary(options.globalErrorComponent, element);\n }\n\n return element;\n}\n\nexport async function renderAppPageBoundaryResponse<TElement>(\n options: RenderAppPageBoundaryResponseOptions<TElement>,\n): Promise<Response> {\n const rscStream = options.renderToReadableStream(options.element, {\n onError: options.createRscOnErrorHandler(),\n });\n\n if (options.isRscRequest) {\n // Do NOT clear request-scoped context here. RSC responses are consumed lazily\n // by the client, so headers()/cookies() and async server components still need\n // their ALS-backed state while the stream is being read.\n const headers = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return new Response(rscStream, {\n status: options.status,\n headers,\n });\n }\n\n return options.createHtmlResponse(rscStream, options.status);\n}\n"],"mappings":";;;;AA4FA,SAAgB,0CACd,SACmB;CACnB,IAAI;AAEJ,KAAI,QAAQ,eAAe,IACzB,kBAAiB,QAAQ,wBAAwB,QAAQ;UAChD,QAAQ,eAAe,IAChC,kBAAiB,QAAQ,2BAA2B,QAAQ;KAE5D,kBAAiB,QAAQ,uBAAuB,QAAQ;AAG1D,QAAO,QAAQ,iBAAiB,eAAe,IAAI;;AAGrD,SAAgB,6CACd,SACgB;CAChB,IAAI,eAAe,QAAQ;CAC3B,IAAI,aAAa,QAAQ;AAEzB,KAAI,QAAQ,eAAe,KAAK;AAC9B,iBAAe,QAAQ;AACvB,eAAa,QAAQ;YACZ,QAAQ,eAAe,KAAK;AACrC,iBAAe,QAAQ;AACvB,eAAa,QAAQ;;AAGvB,KAAI,aACF,MAAK,IAAI,QAAQ,QAAQ,cAAc,GAAG,SAAS,GAAG,SAAS;EAC7D,MAAM,SAAS,aAAa;AAC5B,MAAI,OACF,QAAO;;AAKb,QAAO,cAAc;;AAGvB,SAAgB,4BACd,SAC+C;CAC/C,MAAM,qBAAqB,QAAQ,iBAAiB,QAAQ,gBAAgB;AAC5E,KAAI,mBACF,QAAO;EACL,WAAW;EACX,eAAe;EAChB;AAGH,KAAI,QAAQ,mBACV,MAAK,IAAI,QAAQ,QAAQ,mBAAmB,SAAS,GAAG,SAAS,GAAG,SAAS;EAC3E,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,mBAAmB,OAAO;AACxF,MAAI,qBACF,QAAO;GACL,WAAW;GACX,eAAe;GAChB;;CAKP,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,kBAAkB;AAChF,QAAO;EACL,WAAW,wBAAwB;EACnC,eAAe,QAAQ,qBAAqB;EAC7C;;AAGH,SAAgB,2BAOd,SAOU;CACV,IAAI,UAAU,QAAQ;AAEtB,KAAI,CAAC,QAAQ,mBACX,MAAK,IAAI,QAAQ,QAAQ,cAAc,SAAS,GAAG,SAAS,GAAG,SAAS;EACtE,MAAM,kBAAkB,QAAQ,iBAAiB,QAAQ,cAAc,OAAO;AAC9E,MAAI,CAAC,gBACH;EAGF,MAAM,eAAe,QAAQ,sBAAsB,QAAQ,oBAAoB,SAAS;EACxF,MAAM,cAAc,QAAQ,mBAC1B,4BAA4B,QAAQ,eAAe,cAAc,QAAQ,cAAc,CACxF;AACD,YAAU,QAAQ,aAAa,iBAAiB,SAAS,YAAY;AAErE,MACE,QAAQ,gBACR,QAAQ,+BACR,QAAQ,sBACR;GACA,MAAM,gBAAgB,QAAQ,qBAC5B,QAAQ,iBAAiB,EAAE,EAC3B,cACA,QAAQ,cACT;AACD,aAAU,QAAQ,4BAA4B,EAAE,UAAU,eAAe,EAAE,QAAQ;;;AAKzF,KAAI,QAAQ,gBAAgB,QAAQ,8BAA8B,QAAQ,qBACxE,WAAU,QAAQ,oBAAoB,QAAQ,sBAAsB,QAAQ;AAG9E,QAAO;;AAGT,eAAsB,8BACpB,SACmB;CACnB,MAAM,YAAY,QAAQ,uBAAuB,QAAQ,SAAS,EAChE,SAAS,QAAQ,yBAAyB,EAC3C,CAAC;AAEF,KAAI,QAAQ,cAAc;EAIxB,MAAM,UAAU,IAAI,QAAQ;GAC1B,gBAAgB;GAChB,MAAM;GACP,CAAC;AACF,iCAA+B,SAAS,QAAQ,qBAAqB,KAAK;AAE1E,SAAO,IAAI,SAAS,WAAW;GAC7B,QAAQ,QAAQ;GAChB;GACD,CAAC;;AAGJ,QAAO,QAAQ,mBAAmB,WAAW,QAAQ,OAAO"}
|
|
1
|
+
{"version":3,"file":"app-page-boundary.js","names":[],"sources":["../../src/server/app-page-boundary.ts"],"sourcesContent":["import { runWithFetchDedupe } from \"vinext/shims/fetch-cache\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { VINEXT_RSC_VARY_HEADER } from \"./app-rsc-cache-busting.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\n\nexport type AppPageParams = Record<string, string | string[]>;\n\ntype ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModule?: TModule | null;\n routeNotFoundModule?: TModule | null;\n routeUnauthorizedModule?: TModule | null;\n statusCode: number;\n};\n\ntype ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule> = {\n layoutIndex: number;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModules?: readonly (TModule | null | undefined)[] | null;\n routeNotFoundModules?: readonly (TModule | null | undefined)[] | null;\n routeUnauthorizedModules?: readonly (TModule | null | undefined)[] | null;\n statusCode: number;\n};\n\ntype ResolveAppPageErrorBoundaryOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n globalErrorModule?: TModule | null;\n errorModules?: readonly (TModule | null | undefined)[] | null;\n layoutErrorModules?: readonly (TModule | null | undefined)[] | null;\n pageErrorModule?: TModule | null;\n};\n\ntype ResolveAppPageErrorBoundaryResult<TComponent> = {\n component: TComponent | null;\n isGlobalError: boolean;\n};\n\ntype WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n> = {\n element: TElement;\n getDefaultExport: (\n module: TLayoutModule | null | undefined,\n ) => TLayoutComponent | null | undefined;\n globalErrorComponent?: TGlobalErrorComponent | null;\n includeGlobalErrorBoundary: boolean;\n isRscRequest: boolean;\n layoutModules: readonly (TLayoutModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n matchedParams: AppPageParams;\n renderErrorBoundary: (component: TGlobalErrorComponent, children: TElement) => TElement;\n renderLayout: (component: TLayoutComponent, children: TElement, params: unknown) => TElement;\n renderLayoutSegmentProvider?: (\n segmentMap: { children: TChildSegments },\n children: TElement,\n ) => TElement;\n resolveChildSegments?: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => TChildSegments;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n};\n\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype RenderAppPageBoundaryResponseOptions<TElement> = {\n createHtmlResponse: (rscStream: ReadableStream<Uint8Array>, status: number) => Promise<Response>;\n createRscOnErrorHandler: () => AppPageBoundaryOnError;\n element: TElement;\n isRscRequest: boolean;\n middlewareHeaders?: Headers | null;\n renderToReadableStream: (\n element: TElement,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n status: number;\n};\n\nexport function resolveAppPageHttpAccessBoundaryComponent<TModule, TComponent>(\n options: ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent>,\n): TComponent | null {\n let boundaryModule: TModule | null | undefined;\n\n if (options.statusCode === 403) {\n boundaryModule = options.routeForbiddenModule ?? options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n boundaryModule = options.routeUnauthorizedModule ?? options.rootUnauthorizedModule;\n } else {\n boundaryModule = options.routeNotFoundModule ?? options.rootNotFoundModule;\n }\n\n return options.getDefaultExport(boundaryModule) ?? null;\n}\n\nexport function resolveAppPageParentHttpAccessBoundaryModule<TModule>(\n options: ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule>,\n): TModule | null {\n let routeModules = options.routeNotFoundModules;\n let rootModule = options.rootNotFoundModule;\n\n if (options.statusCode === 403) {\n routeModules = options.routeForbiddenModules;\n rootModule = options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n routeModules = options.routeUnauthorizedModules;\n rootModule = options.rootUnauthorizedModule;\n }\n\n if (routeModules) {\n for (let index = options.layoutIndex - 1; index >= 0; index--) {\n const module = routeModules[index];\n if (module) {\n return module;\n }\n }\n }\n\n return rootModule ?? null;\n}\n\nexport function resolveAppPageErrorBoundary<TModule, TComponent>(\n options: ResolveAppPageErrorBoundaryOptions<TModule, TComponent>,\n): ResolveAppPageErrorBoundaryResult<TComponent> {\n const pageErrorComponent = options.getDefaultExport(options.pageErrorModule);\n if (pageErrorComponent) {\n return {\n component: pageErrorComponent,\n isGlobalError: false,\n };\n }\n\n const segmentErrorModules = options.errorModules ?? options.layoutErrorModules;\n if (segmentErrorModules) {\n for (let index = segmentErrorModules.length - 1; index >= 0; index--) {\n const segmentErrorComponent = options.getDefaultExport(segmentErrorModules[index]);\n if (segmentErrorComponent) {\n return {\n component: segmentErrorComponent,\n isGlobalError: false,\n };\n }\n }\n }\n\n const globalErrorComponent = options.getDefaultExport(options.globalErrorModule);\n return {\n component: globalErrorComponent ?? null,\n isGlobalError: Boolean(globalErrorComponent),\n };\n}\n\nexport function wrapAppPageBoundaryElement<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n>(\n options: WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent\n >,\n): TElement {\n let element = options.element;\n\n if (!options.skipLayoutWrapping) {\n for (let index = options.layoutModules.length - 1; index >= 0; index--) {\n const layoutComponent = options.getDefaultExport(options.layoutModules[index]);\n if (!layoutComponent) {\n continue;\n }\n\n const treePosition = options.layoutTreePositions ? options.layoutTreePositions[index] : 0;\n const asyncParams = options.makeThenableParams(\n resolveAppPageSegmentParams(options.routeSegments, treePosition, options.matchedParams),\n );\n element = options.renderLayout(layoutComponent, element, asyncParams);\n\n if (\n options.isRscRequest &&\n options.renderLayoutSegmentProvider &&\n options.resolveChildSegments\n ) {\n const childSegments = options.resolveChildSegments(\n options.routeSegments ?? [],\n treePosition,\n options.matchedParams,\n );\n element = options.renderLayoutSegmentProvider({ children: childSegments }, element);\n }\n }\n }\n\n if (options.isRscRequest && options.includeGlobalErrorBoundary && options.globalErrorComponent) {\n element = options.renderErrorBoundary(options.globalErrorComponent, element);\n }\n\n return element;\n}\n\nexport async function renderAppPageBoundaryResponse<TElement>(\n options: RenderAppPageBoundaryResponseOptions<TElement>,\n): Promise<Response> {\n // Defensive wrap for standalone callers; idempotent under dispatchAppPage.\n // The async stream consumption that follows relies on the surrounding\n // runWithRequestContext to keep ALS state alive after this synchronous call\n // returns. See app-page-render.ts for the same pattern.\n const rscStream = runWithFetchDedupe(() =>\n options.renderToReadableStream(options.element, {\n onError: options.createRscOnErrorHandler(),\n }),\n );\n\n if (options.isRscRequest) {\n // Do NOT clear request-scoped context here. RSC responses are consumed lazily\n // by the client, so headers()/cookies() and async server components still need\n // their ALS-backed state while the stream is being read.\n const headers = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return new Response(rscStream, {\n status: options.status,\n headers,\n });\n }\n\n return options.createHtmlResponse(rscStream, options.status);\n}\n"],"mappings":";;;;;AA8FA,SAAgB,0CACd,SACmB;CACnB,IAAI;CAEJ,IAAI,QAAQ,eAAe,KACzB,iBAAiB,QAAQ,wBAAwB,QAAQ;MACpD,IAAI,QAAQ,eAAe,KAChC,iBAAiB,QAAQ,2BAA2B,QAAQ;MAE5D,iBAAiB,QAAQ,uBAAuB,QAAQ;CAG1D,OAAO,QAAQ,iBAAiB,eAAe,IAAI;;AAGrD,SAAgB,6CACd,SACgB;CAChB,IAAI,eAAe,QAAQ;CAC3B,IAAI,aAAa,QAAQ;CAEzB,IAAI,QAAQ,eAAe,KAAK;EAC9B,eAAe,QAAQ;EACvB,aAAa,QAAQ;QAChB,IAAI,QAAQ,eAAe,KAAK;EACrC,eAAe,QAAQ;EACvB,aAAa,QAAQ;;CAGvB,IAAI,cACF,KAAK,IAAI,QAAQ,QAAQ,cAAc,GAAG,SAAS,GAAG,SAAS;EAC7D,MAAM,SAAS,aAAa;EAC5B,IAAI,QACF,OAAO;;CAKb,OAAO,cAAc;;AAGvB,SAAgB,4BACd,SAC+C;CAC/C,MAAM,qBAAqB,QAAQ,iBAAiB,QAAQ,gBAAgB;CAC5E,IAAI,oBACF,OAAO;EACL,WAAW;EACX,eAAe;EAChB;CAGH,MAAM,sBAAsB,QAAQ,gBAAgB,QAAQ;CAC5D,IAAI,qBACF,KAAK,IAAI,QAAQ,oBAAoB,SAAS,GAAG,SAAS,GAAG,SAAS;EACpE,MAAM,wBAAwB,QAAQ,iBAAiB,oBAAoB,OAAO;EAClF,IAAI,uBACF,OAAO;GACL,WAAW;GACX,eAAe;GAChB;;CAKP,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,kBAAkB;CAChF,OAAO;EACL,WAAW,wBAAwB;EACnC,eAAe,QAAQ,qBAAqB;EAC7C;;AAGH,SAAgB,2BAOd,SAOU;CACV,IAAI,UAAU,QAAQ;CAEtB,IAAI,CAAC,QAAQ,oBACX,KAAK,IAAI,QAAQ,QAAQ,cAAc,SAAS,GAAG,SAAS,GAAG,SAAS;EACtE,MAAM,kBAAkB,QAAQ,iBAAiB,QAAQ,cAAc,OAAO;EAC9E,IAAI,CAAC,iBACH;EAGF,MAAM,eAAe,QAAQ,sBAAsB,QAAQ,oBAAoB,SAAS;EACxF,MAAM,cAAc,QAAQ,mBAC1B,4BAA4B,QAAQ,eAAe,cAAc,QAAQ,cAAc,CACxF;EACD,UAAU,QAAQ,aAAa,iBAAiB,SAAS,YAAY;EAErE,IACE,QAAQ,gBACR,QAAQ,+BACR,QAAQ,sBACR;GACA,MAAM,gBAAgB,QAAQ,qBAC5B,QAAQ,iBAAiB,EAAE,EAC3B,cACA,QAAQ,cACT;GACD,UAAU,QAAQ,4BAA4B,EAAE,UAAU,eAAe,EAAE,QAAQ;;;CAKzF,IAAI,QAAQ,gBAAgB,QAAQ,8BAA8B,QAAQ,sBACxE,UAAU,QAAQ,oBAAoB,QAAQ,sBAAsB,QAAQ;CAG9E,OAAO;;AAGT,eAAsB,8BACpB,SACmB;CAKnB,MAAM,YAAY,yBAChB,QAAQ,uBAAuB,QAAQ,SAAS,EAC9C,SAAS,QAAQ,yBAAyB,EAC3C,CAAC,CACH;CAED,IAAI,QAAQ,cAAc;EAIxB,MAAM,UAAU,IAAI,QAAQ;GAC1B,gBAAgB;GAChB,MAAM;GACP,CAAC;EACF,+BAA+B,SAAS,QAAQ,qBAAqB,KAAK;EAE1E,OAAO,IAAI,SAAS,WAAW;GAC7B,QAAQ,QAAQ;GAChB;GACD,CAAC;;CAGJ,OAAO,QAAQ,mBAAmB,WAAW,QAAQ,OAAO"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CacheControlMetadata, CachedAppPageValue } from "../shims/cache.js";
|
|
2
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
2
3
|
import { ISRCacheEntry } from "./isr-cache.js";
|
|
3
4
|
|
|
4
5
|
//#region src/server/app-page-cache.d.ts
|
|
@@ -21,6 +22,8 @@ type BuildAppPageCachedResponseOptions = {
|
|
|
21
22
|
cacheState: "HIT" | "STALE";
|
|
22
23
|
expireSeconds?: number;
|
|
23
24
|
isRscRequest: boolean;
|
|
25
|
+
middlewareHeaders?: Headers | null;
|
|
26
|
+
middlewareStatus?: number | null;
|
|
24
27
|
mountedSlotsHeader?: string | null;
|
|
25
28
|
revalidateSeconds: number;
|
|
26
29
|
};
|
|
@@ -31,9 +34,12 @@ type ReadAppPageCacheResponseOptions = {
|
|
|
31
34
|
isrDebug?: AppPageDebugLogger;
|
|
32
35
|
isrGet: AppPageCacheGetter;
|
|
33
36
|
isrHtmlKey: (pathname: string) => string;
|
|
34
|
-
isrRscKey: (pathname: string, mountedSlotsHeader?: string | null) => string;
|
|
37
|
+
isrRscKey: (pathname: string, mountedSlotsHeader?: string | null, renderMode?: AppRscRenderMode) => string;
|
|
35
38
|
isrSet: AppPageCacheSetter;
|
|
39
|
+
middlewareHeaders?: Headers | null;
|
|
40
|
+
middlewareStatus?: number | null;
|
|
36
41
|
mountedSlotsHeader?: string | null;
|
|
42
|
+
renderMode?: AppRscRenderMode;
|
|
37
43
|
expireSeconds?: number;
|
|
38
44
|
revalidateSeconds: number;
|
|
39
45
|
renderFreshPageForCache: () => Promise<AppPageCacheRenderResult>;
|
|
@@ -48,7 +54,7 @@ type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
|
48
54
|
getRequestCacheLife?: () => AppPageRequestCacheLife | null;
|
|
49
55
|
isrDebug?: AppPageDebugLogger;
|
|
50
56
|
isrHtmlKey: (pathname: string) => string;
|
|
51
|
-
isrRscKey: (pathname: string, mountedSlotsHeader?: string | null) => string;
|
|
57
|
+
isrRscKey: (pathname: string, mountedSlotsHeader?: string | null, renderMode?: AppRscRenderMode) => string;
|
|
52
58
|
isrSet: AppPageCacheSetter;
|
|
53
59
|
preserveClientResponseHeaders?: boolean;
|
|
54
60
|
expireSeconds?: number;
|
|
@@ -63,9 +69,10 @@ type ScheduleAppPageRscCacheWriteOptions = {
|
|
|
63
69
|
getPageTags: () => string[];
|
|
64
70
|
getRequestCacheLife?: () => AppPageRequestCacheLife | null;
|
|
65
71
|
isrDebug?: AppPageDebugLogger;
|
|
66
|
-
isrRscKey: (pathname: string, mountedSlotsHeader?: string | null) => string;
|
|
72
|
+
isrRscKey: (pathname: string, mountedSlotsHeader?: string | null, renderMode?: AppRscRenderMode) => string;
|
|
67
73
|
isrSet: AppPageCacheSetter;
|
|
68
74
|
mountedSlotsHeader?: string | null;
|
|
75
|
+
renderMode?: AppRscRenderMode;
|
|
69
76
|
preserveClientResponseHeaders?: boolean;
|
|
70
77
|
expireSeconds?: number;
|
|
71
78
|
revalidateSeconds: number | null;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { VINEXT_CACHE_HEADER, VINEXT_MOUNTED_SLOTS_HEADER } from "./headers.js";
|
|
2
|
+
import { encodeCacheTag } from "../utils/encode-cache-tag.js";
|
|
1
3
|
import { buildAppPageCacheValue } from "./isr-cache.js";
|
|
2
4
|
import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-cache-busting.js";
|
|
3
|
-
import { buildCachedRevalidateCacheControl } from "./cache-control.js";
|
|
4
5
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
6
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
7
|
+
import { buildCachedRevalidateCacheControl } from "./cache-control.js";
|
|
5
8
|
//#region src/server/app-page-cache.ts
|
|
6
9
|
const NO_STORE_CACHE_CONTROL = "no-store, must-revalidate";
|
|
7
10
|
function buildAppPageCacheTags(pathname, extraTags) {
|
|
@@ -21,11 +24,22 @@ function buildAppPageCacheTags(pathname, extraTags) {
|
|
|
21
24
|
}
|
|
22
25
|
tags.push(`_N_T_${built}/page`);
|
|
23
26
|
for (const tag of extraTags) if (!tags.includes(tag)) tags.push(tag);
|
|
24
|
-
return tags;
|
|
27
|
+
return tags.map(encodeCacheTag);
|
|
25
28
|
}
|
|
26
29
|
function buildAppPageCacheControl(cacheState, revalidateSeconds, expireSeconds) {
|
|
27
30
|
return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);
|
|
28
31
|
}
|
|
32
|
+
function buildAppPageCachedHeaders(options) {
|
|
33
|
+
const headers = new Headers({
|
|
34
|
+
"Cache-Control": options.cacheControl,
|
|
35
|
+
"Content-Type": options.contentType,
|
|
36
|
+
Vary: VINEXT_RSC_VARY_HEADER,
|
|
37
|
+
[VINEXT_CACHE_HEADER]: options.cacheState
|
|
38
|
+
});
|
|
39
|
+
if (options.mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);
|
|
40
|
+
mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
|
|
41
|
+
return headers;
|
|
42
|
+
}
|
|
29
43
|
function getCachedAppPageValue(entry) {
|
|
30
44
|
return entry?.value.value && entry.value.value.kind === "APP_PAGE" ? entry.value.value : null;
|
|
31
45
|
}
|
|
@@ -42,37 +56,38 @@ function resolveAppPageCacheWritePolicy(options) {
|
|
|
42
56
|
};
|
|
43
57
|
}
|
|
44
58
|
function buildAppPageCachedResponse(cachedValue, options) {
|
|
45
|
-
const status = cachedValue.status || 200;
|
|
59
|
+
const status = options.middlewareStatus ?? (cachedValue.status || 200);
|
|
46
60
|
const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;
|
|
47
61
|
const expireSeconds = options.cacheControl === void 0 ? void 0 : options.cacheControl.expire ?? options.expireSeconds;
|
|
48
|
-
const
|
|
49
|
-
"Cache-Control": buildAppPageCacheControl(options.cacheState, revalidateSeconds, expireSeconds),
|
|
50
|
-
Vary: VINEXT_RSC_VARY_HEADER,
|
|
51
|
-
"X-Vinext-Cache": options.cacheState
|
|
52
|
-
};
|
|
62
|
+
const cacheControl = buildAppPageCacheControl(options.cacheState, revalidateSeconds, expireSeconds);
|
|
53
63
|
if (options.isRscRequest) {
|
|
54
64
|
if (!cachedValue.rscData) return null;
|
|
55
|
-
const rscHeaders = {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
65
|
+
const rscHeaders = buildAppPageCachedHeaders({
|
|
66
|
+
cacheControl,
|
|
67
|
+
cacheState: options.cacheState,
|
|
68
|
+
contentType: "text/x-component; charset=utf-8",
|
|
69
|
+
middlewareHeaders: options.middlewareHeaders,
|
|
70
|
+
mountedSlotsHeader: options.mountedSlotsHeader
|
|
71
|
+
});
|
|
60
72
|
return new Response(cachedValue.rscData, {
|
|
61
73
|
status,
|
|
62
74
|
headers: rscHeaders
|
|
63
75
|
});
|
|
64
76
|
}
|
|
65
77
|
if (typeof cachedValue.html !== "string" || cachedValue.html.length === 0) return null;
|
|
78
|
+
const htmlHeaders = buildAppPageCachedHeaders({
|
|
79
|
+
cacheControl,
|
|
80
|
+
cacheState: options.cacheState,
|
|
81
|
+
contentType: "text/html; charset=utf-8",
|
|
82
|
+
middlewareHeaders: options.middlewareHeaders
|
|
83
|
+
});
|
|
66
84
|
return new Response(cachedValue.html, {
|
|
67
85
|
status,
|
|
68
|
-
headers:
|
|
69
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
70
|
-
...headers
|
|
71
|
-
}
|
|
86
|
+
headers: htmlHeaders
|
|
72
87
|
});
|
|
73
88
|
}
|
|
74
89
|
async function readAppPageCacheResponse(options) {
|
|
75
|
-
const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader) : options.isrHtmlKey(options.cleanPathname);
|
|
90
|
+
const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode) : options.isrHtmlKey(options.cleanPathname);
|
|
76
91
|
try {
|
|
77
92
|
const cached = await options.isrGet(isrKey);
|
|
78
93
|
const cachedValue = getCachedAppPageValue(cached);
|
|
@@ -82,6 +97,8 @@ async function readAppPageCacheResponse(options) {
|
|
|
82
97
|
cacheControl: cached?.value.cacheControl,
|
|
83
98
|
expireSeconds: options.expireSeconds,
|
|
84
99
|
isRscRequest: options.isRscRequest,
|
|
100
|
+
middlewareHeaders: options.middlewareHeaders,
|
|
101
|
+
middlewareStatus: options.middlewareStatus,
|
|
85
102
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
86
103
|
revalidateSeconds: options.revalidateSeconds
|
|
87
104
|
});
|
|
@@ -93,12 +110,12 @@ async function readAppPageCacheResponse(options) {
|
|
|
93
110
|
options.isrDebug?.("MISS (empty cached entry)", options.cleanPathname);
|
|
94
111
|
}
|
|
95
112
|
if (cached?.isStale && cachedValue) {
|
|
96
|
-
const regenerationKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader) : options.isrHtmlKey(options.cleanPathname);
|
|
113
|
+
const regenerationKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode) : options.isrHtmlKey(options.cleanPathname);
|
|
97
114
|
options.scheduleBackgroundRegeneration(regenerationKey, async () => {
|
|
98
115
|
const revalidatedPage = await options.renderFreshPageForCache();
|
|
99
116
|
const revalidateSeconds = revalidatedPage.cacheControl?.revalidate ?? options.revalidateSeconds;
|
|
100
117
|
const expireSeconds = revalidatedPage.cacheControl?.expire ?? options.expireSeconds;
|
|
101
|
-
const writes = [options.isrSet(options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader), buildAppPageCacheValue("", revalidatedPage.rscData, 200), revalidateSeconds, revalidatedPage.tags, expireSeconds)];
|
|
118
|
+
const writes = [options.isrSet(options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode), buildAppPageCacheValue("", revalidatedPage.rscData, 200), revalidateSeconds, revalidatedPage.tags, expireSeconds)];
|
|
102
119
|
if (!options.isRscRequest) writes.push(options.isrSet(options.isrHtmlKey(options.cleanPathname), buildAppPageCacheValue(revalidatedPage.html, void 0, 200), revalidateSeconds, revalidatedPage.tags, expireSeconds));
|
|
103
120
|
await Promise.all(writes);
|
|
104
121
|
options.isrDebug?.("regen complete", options.cleanPathname);
|
|
@@ -108,6 +125,8 @@ async function readAppPageCacheResponse(options) {
|
|
|
108
125
|
cacheControl: cached.value.cacheControl,
|
|
109
126
|
expireSeconds: options.expireSeconds,
|
|
110
127
|
isRscRequest: options.isRscRequest,
|
|
128
|
+
middlewareHeaders: options.middlewareHeaders,
|
|
129
|
+
middlewareStatus: options.middlewareStatus,
|
|
111
130
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
112
131
|
revalidateSeconds: options.revalidateSeconds
|
|
113
132
|
});
|
|
@@ -132,7 +151,7 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
|
|
|
132
151
|
const clientHeaders = new Headers(response.headers);
|
|
133
152
|
if (options.preserveClientResponseHeaders !== true) {
|
|
134
153
|
clientHeaders.set("Cache-Control", NO_STORE_CACHE_CONTROL);
|
|
135
|
-
clientHeaders.set(
|
|
154
|
+
clientHeaders.set(VINEXT_CACHE_HEADER, "MISS");
|
|
136
155
|
}
|
|
137
156
|
const cachePromise = (async () => {
|
|
138
157
|
try {
|
|
@@ -171,7 +190,7 @@ function finalizeAppPageRscCacheResponse(response, options) {
|
|
|
171
190
|
if (options.preserveClientResponseHeaders === true) return response;
|
|
172
191
|
const clientHeaders = new Headers(response.headers);
|
|
173
192
|
clientHeaders.set("Cache-Control", NO_STORE_CACHE_CONTROL);
|
|
174
|
-
clientHeaders.set(
|
|
193
|
+
clientHeaders.set(VINEXT_CACHE_HEADER, "MISS");
|
|
175
194
|
return new Response(response.body, {
|
|
176
195
|
status: response.status,
|
|
177
196
|
statusText: response.statusText,
|
|
@@ -181,7 +200,7 @@ function finalizeAppPageRscCacheResponse(response, options) {
|
|
|
181
200
|
function scheduleAppPageRscCacheWrite(options) {
|
|
182
201
|
const capturedRscDataPromise = options.capturedRscDataPromise;
|
|
183
202
|
if (!capturedRscDataPromise || options.dynamicUsedDuringBuild) return false;
|
|
184
|
-
const rscKey = options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader);
|
|
203
|
+
const rscKey = options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode);
|
|
185
204
|
const cachePromise = (async () => {
|
|
186
205
|
try {
|
|
187
206
|
const rscData = await capturedRscDataPromise;
|