vinext 0.0.50 → 0.0.52
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/google-fonts/fallback-metrics-data.js +14031 -0
- package/dist/build/google-fonts/fallback-metrics-data.js.map +1 -0
- package/dist/build/google-fonts/fallback-metrics.d.ts +13 -0
- package/dist/build/google-fonts/fallback-metrics.js +46 -0
- package/dist/build/google-fonts/fallback-metrics.js.map +1 -0
- package/dist/build/precompress.d.ts +13 -2
- package/dist/build/precompress.js +23 -13
- package/dist/build/precompress.js.map +1 -1
- package/dist/build/prerender.d.ts +4 -15
- package/dist/build/prerender.js +83 -53
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/report.d.ts +5 -4
- package/dist/build/report.js +196 -348
- package/dist/build/report.js.map +1 -1
- package/dist/check.js +5 -0
- package/dist/check.js.map +1 -1
- package/dist/cli-args.d.ts +1 -0
- package/dist/cli-args.js +5 -0
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +99 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +47 -0
- package/dist/client/navigation-runtime.js +156 -0
- package/dist/client/navigation-runtime.js.map +1 -0
- package/dist/client/pages-router-link-navigation.d.ts +26 -0
- package/dist/client/pages-router-link-navigation.js +14 -0
- package/dist/client/pages-router-link-navigation.js.map +1 -0
- package/dist/client/vinext-next-data.d.ts +12 -2
- package/dist/client/vinext-next-data.js +50 -1
- package/dist/client/vinext-next-data.js.map +1 -0
- package/dist/client/window-next.d.ts +3 -1
- package/dist/client/window-next.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +2 -1
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/config/config-matchers.d.ts +63 -16
- package/dist/config/config-matchers.js +143 -8
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/dotenv.d.ts +11 -1
- package/dist/config/dotenv.js.map +1 -1
- package/dist/config/next-config.d.ts +107 -5
- package/dist/config/next-config.js +233 -7
- package/dist/config/next-config.js.map +1 -1
- package/dist/config/tsconfig-paths.d.ts +13 -0
- package/dist/config/tsconfig-paths.js +117 -0
- package/dist/config/tsconfig-paths.js.map +1 -0
- package/dist/deploy.js +104 -41
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +2 -2
- package/dist/entries/app-browser-entry.js +34 -3
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +19 -1
- package/dist/entries/app-rsc-entry.js +89 -23
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +10 -0
- package/dist/entries/app-rsc-manifest.js +57 -7
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/app-ssr-entry.d.ts +3 -3
- package/dist/entries/app-ssr-entry.js +4 -4
- package/dist/entries/app-ssr-entry.js.map +1 -1
- package/dist/entries/pages-client-entry.js +21 -7
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +77 -9
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +2 -1
- package/dist/entries/runtime-entry-module.js +9 -3
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +260 -75
- package/dist/index.js.map +1 -1
- package/dist/plugins/client-reference-dedup.d.ts +15 -2
- package/dist/plugins/client-reference-dedup.js +138 -16
- package/dist/plugins/client-reference-dedup.js.map +1 -1
- package/dist/plugins/css-data-url.d.ts +7 -0
- package/dist/plugins/css-data-url.js +81 -0
- package/dist/plugins/css-data-url.js.map +1 -0
- package/dist/plugins/fonts.d.ts +2 -2
- package/dist/plugins/fonts.js +20 -9
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/middleware-server-only.d.ts +54 -0
- package/dist/plugins/middleware-server-only.js +91 -0
- package/dist/plugins/middleware-server-only.js.map +1 -0
- package/dist/plugins/optimize-imports.js +4 -4
- package/dist/plugins/optimize-imports.js.map +1 -1
- package/dist/plugins/sass.d.ts +34 -0
- package/dist/plugins/sass.js +22 -0
- package/dist/plugins/sass.js.map +1 -0
- package/dist/plugins/strip-server-exports.js +5 -8
- package/dist/plugins/strip-server-exports.js.map +1 -1
- package/dist/routing/app-route-graph.d.ts +50 -2
- package/dist/routing/app-route-graph.js +140 -16
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -2
- package/dist/routing/app-router.js +2 -2
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/route-pattern.d.ts +56 -1
- package/dist/routing/route-pattern.js +60 -1
- package/dist/routing/route-pattern.js.map +1 -1
- package/dist/routing/utils.d.ts +2 -1
- package/dist/routing/utils.js +4 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js +139 -37
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-action-result.d.ts +27 -2
- package/dist/server/app-browser-action-result.js +63 -2
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +493 -195
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-hydration.d.ts +13 -1
- package/dist/server/app-browser-hydration.js +9 -1
- package/dist/server/app-browser-hydration.js.map +1 -1
- package/dist/server/app-browser-interception-context.d.ts +24 -0
- package/dist/server/app-browser-interception-context.js +32 -0
- package/dist/server/app-browser-interception-context.js.map +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +17 -2
- package/dist/server/app-browser-navigation-controller.js +33 -10
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-popstate.d.ts +16 -0
- package/dist/server/app-browser-popstate.js +17 -0
- package/dist/server/app-browser-popstate.js.map +1 -0
- package/dist/server/app-browser-rsc-redirect.d.ts +29 -0
- package/dist/server/app-browser-rsc-redirect.js +37 -0
- package/dist/server/app-browser-rsc-redirect.js.map +1 -0
- package/dist/server/app-browser-state.d.ts +28 -7
- package/dist/server/app-browser-state.js +63 -27
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-stream.d.ts +9 -17
- package/dist/server/app-browser-stream.js +18 -13
- package/dist/server/app-browser-stream.js.map +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +7 -1
- package/dist/server/app-browser-visible-commit.js +39 -5
- package/dist/server/app-browser-visible-commit.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +43 -6
- package/dist/server/app-elements-wire.js +189 -7
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +3 -2
- package/dist/server/app-elements.js +3 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +10 -1
- package/dist/server/app-fallback-renderer.js +41 -3
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-history-state.d.ts +26 -0
- package/dist/server/app-history-state.js +53 -0
- package/dist/server/app-history-state.js.map +1 -0
- package/dist/server/app-middleware.d.ts +13 -0
- package/dist/server/app-middleware.js +3 -1
- package/dist/server/app-middleware.js.map +1 -1
- package/dist/server/app-optimistic-routing.d.ts +54 -0
- package/dist/server/app-optimistic-routing.js +200 -0
- package/dist/server/app-optimistic-routing.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +10 -1
- package/dist/server/app-page-boundary-render.js +13 -6
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.js +3 -2
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +26 -1
- package/dist/server/app-page-cache.js +86 -14
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +7 -0
- package/dist/server/app-page-dispatch.js +96 -12
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +34 -5
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +28 -1
- package/dist/server/app-page-execution.js +91 -7
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +7 -0
- package/dist/server/app-page-head.js +23 -3
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +23 -1
- package/dist/server/app-page-probe.js +29 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render-observation.d.ts +35 -0
- package/dist/server/app-page-render-observation.js +68 -0
- package/dist/server/app-page-render-observation.js.map +1 -0
- package/dist/server/app-page-render.d.ts +7 -1
- package/dist/server/app-page-render.js +81 -4
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +1 -0
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +7 -5
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +59 -24
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +5 -0
- package/dist/server/app-page-stream.js +2 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-prerender-static-params.d.ts +2 -1
- package/dist/server/app-prerender-static-params.js +44 -8
- package/dist/server/app-prerender-static-params.js.map +1 -1
- package/dist/server/app-route-handler-cache.d.ts +2 -2
- package/dist/server/app-route-handler-cache.js +3 -2
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +6 -1
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-execution.d.ts +17 -2
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.js +5 -4
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-router-entry.js +7 -15
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +19 -1
- package/dist/server/app-rsc-cache-busting.js +36 -1
- package/dist/server/app-rsc-cache-busting.js.map +1 -1
- package/dist/server/app-rsc-embedded-chunks.d.ts +9 -0
- package/dist/server/app-rsc-embedded-chunks.js +34 -0
- package/dist/server/app-rsc-embedded-chunks.js.map +1 -0
- package/dist/server/app-rsc-errors.d.ts +4 -1
- package/dist/server/app-rsc-errors.js +1 -1
- package/dist/server/app-rsc-errors.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +21 -5
- package/dist/server/app-rsc-handler.js +38 -15
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-render-mode.d.ts +4 -3
- package/dist/server/app-rsc-render-mode.js +7 -1
- package/dist/server/app-rsc-render-mode.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +4 -1
- package/dist/server/app-rsc-request-normalization.js +4 -1
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
- package/dist/server/app-rsc-response-finalizer.js +10 -3
- package/dist/server/app-rsc-response-finalizer.js.map +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +23 -0
- package/dist/server/app-rsc-route-matching.js +47 -25
- package/dist/server/app-rsc-route-matching.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +35 -3
- package/dist/server/app-server-action-execution.js +87 -33
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -0
- package/dist/server/app-ssr-entry.js +83 -58
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-error-meta.d.ts +14 -0
- package/dist/server/app-ssr-error-meta.js +50 -0
- package/dist/server/app-ssr-error-meta.js.map +1 -0
- package/dist/server/app-ssr-stream.d.ts +7 -2
- package/dist/server/app-ssr-stream.js +26 -15
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +13 -3
- package/dist/server/artifact-compatibility.js +12 -8
- package/dist/server/artifact-compatibility.js.map +1 -1
- package/dist/server/cache-headers.d.ts +7 -0
- package/dist/server/cache-headers.js +19 -0
- package/dist/server/cache-headers.js.map +1 -0
- package/dist/server/cache-proof.d.ts +170 -5
- package/dist/server/cache-proof.js +472 -18
- package/dist/server/cache-proof.js.map +1 -1
- package/dist/server/client-reuse-manifest.d.ts +99 -0
- package/dist/server/client-reuse-manifest.js +212 -0
- package/dist/server/client-reuse-manifest.js.map +1 -0
- package/dist/server/default-global-error-module.d.ts +20 -0
- package/dist/server/default-global-error-module.js +20 -0
- package/dist/server/default-global-error-module.js.map +1 -0
- package/dist/server/dev-lockfile.d.ts +110 -0
- package/dist/server/dev-lockfile.js +180 -0
- package/dist/server/dev-lockfile.js.map +1 -0
- package/dist/server/dev-server.d.ts +9 -1
- package/dist/server/dev-server.js +76 -19
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/edge-api-runtime.d.ts +5 -0
- package/dist/server/edge-api-runtime.js +8 -0
- package/dist/server/edge-api-runtime.js.map +1 -0
- package/dist/server/file-based-metadata.d.ts +13 -0
- package/dist/server/file-based-metadata.js +49 -2
- package/dist/server/file-based-metadata.js.map +1 -1
- package/dist/server/headers.d.ts +20 -1
- package/dist/server/headers.js +22 -2
- package/dist/server/headers.js.map +1 -1
- package/dist/server/html.js +1 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/http-error-responses.d.ts +26 -1
- package/dist/server/http-error-responses.js +32 -2
- package/dist/server/http-error-responses.js.map +1 -1
- package/dist/server/isr-cache.d.ts +8 -3
- package/dist/server/isr-cache.js +24 -6
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-route-response.js +22 -5
- package/dist/server/metadata-route-response.js.map +1 -1
- package/dist/server/metadata-routes.js +27 -8
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +15 -0
- package/dist/server/middleware-runtime.js +60 -7
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/middleware.d.ts +13 -1
- package/dist/server/middleware.js +16 -2
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/navigation-planner.d.ts +26 -6
- package/dist/server/navigation-planner.js +358 -24
- package/dist/server/navigation-planner.js.map +1 -1
- package/dist/server/navigation-trace.d.ts +9 -1
- package/dist/server/navigation-trace.js +8 -0
- package/dist/server/navigation-trace.js.map +1 -1
- package/dist/server/normalize-path.d.ts +2 -1
- package/dist/server/normalize-path.js +4 -1
- package/dist/server/normalize-path.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +27 -1
- package/dist/server/pages-api-route.js +25 -3
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-data-route.d.ts +77 -0
- package/dist/server/pages-data-route.js +97 -0
- package/dist/server/pages-data-route.js.map +1 -0
- package/dist/server/pages-i18n.d.ts +51 -1
- package/dist/server/pages-i18n.js +61 -1
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +32 -4
- package/dist/server/pages-page-data.js +52 -19
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +11 -1
- package/dist/server/pages-page-response.js +6 -4
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.d.ts +26 -1
- package/dist/server/prod-server.js +150 -44
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +11 -2
- package/dist/server/request-pipeline.js +28 -11
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/seed-cache.d.ts +12 -31
- package/dist/server/seed-cache.js +22 -35
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.d.ts +16 -3
- package/dist/server/server-action-not-found.js +27 -4
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/server-globals.d.ts +5 -0
- package/dist/server/server-globals.js +37 -0
- package/dist/server/server-globals.js.map +1 -0
- package/dist/server/skip-cache-proof.d.ts +41 -0
- package/dist/server/skip-cache-proof.js +101 -0
- package/dist/server/skip-cache-proof.js.map +1 -0
- package/dist/server/static-file-cache.d.ts +1 -1
- package/dist/server/static-file-cache.js +7 -6
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +19 -2
- package/dist/shims/cache-runtime.js +67 -11
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +5 -18
- package/dist/shims/cache.js +2 -0
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/client-locale.d.ts +15 -0
- package/dist/shims/client-locale.js +13 -0
- package/dist/shims/client-locale.js.map +1 -0
- package/dist/shims/default-global-error.d.ts +32 -0
- package/dist/shims/default-global-error.js +181 -0
- package/dist/shims/default-global-error.js.map +1 -0
- package/dist/shims/document.d.ts +59 -3
- package/dist/shims/document.js +36 -5
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +2 -2
- package/dist/shims/error-boundary.js +6 -8
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.d.ts +18 -1
- package/dist/shims/error.js +56 -1
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +4 -1
- package/dist/shims/fetch-cache.js +40 -5
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +22 -8
- package/dist/shims/font-google-base.js +41 -71
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/font-local.d.ts +3 -20
- package/dist/shims/font-local.js +23 -75
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/font-utils.d.ts +51 -0
- package/dist/shims/font-utils.js +97 -0
- package/dist/shims/font-utils.js.map +1 -0
- package/dist/shims/form.js +13 -6
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/hash-scroll.d.ts +7 -0
- package/dist/shims/hash-scroll.js +30 -0
- package/dist/shims/hash-scroll.js.map +1 -0
- package/dist/shims/headers.d.ts +8 -11
- package/dist/shims/headers.js +22 -2
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.d.ts +1 -0
- package/dist/shims/image.js +144 -78
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/app-router-context.d.ts +6 -6
- package/dist/shims/internal/app-router-context.js +17 -6
- package/dist/shims/internal/app-router-context.js.map +1 -1
- package/dist/shims/link-prefetch.d.ts +9 -1
- package/dist/shims/link-prefetch.js +11 -6
- package/dist/shims/link-prefetch.js.map +1 -1
- package/dist/shims/link.d.ts +33 -5
- package/dist/shims/link.js +205 -50
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +16 -30
- package/dist/shims/metadata.js +91 -32
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +164 -17
- package/dist/shims/navigation.js +355 -84
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.d.ts +3 -2
- package/dist/shims/navigation.react-server.js +5 -2
- package/dist/shims/navigation.react-server.js.map +1 -1
- package/dist/shims/og.d.ts +18 -2
- package/dist/shims/og.js +49 -1
- package/dist/shims/og.js.map +1 -0
- package/dist/shims/pages-router-runtime.d.ts +7 -0
- package/dist/shims/pages-router-runtime.js +16 -0
- package/dist/shims/pages-router-runtime.js.map +1 -0
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/root-params.d.ts +3 -1
- package/dist/shims/root-params.js +11 -3
- package/dist/shims/root-params.js.map +1 -1
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +40 -7
- package/dist/shims/router.js +355 -250
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.js +110 -32
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.d.ts +21 -4
- package/dist/shims/server.js +31 -10
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +1 -0
- package/dist/shims/slot.js +45 -1
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/unrecognized-action-error.d.ts +35 -0
- package/dist/shims/unrecognized-action-error.js +41 -0
- package/dist/shims/unrecognized-action-error.js.map +1 -0
- package/dist/shims/url-safety.d.ts +23 -1
- package/dist/shims/url-safety.js +29 -2
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/shims/url-utils.d.ts +21 -1
- package/dist/shims/url-utils.js +67 -3
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/typegen.d.ts +10 -0
- package/dist/typegen.js +242 -0
- package/dist/typegen.js.map +1 -0
- package/dist/utils/asset-prefix.d.ts +97 -0
- package/dist/utils/asset-prefix.js +124 -0
- package/dist/utils/asset-prefix.js.map +1 -0
- package/dist/utils/base-path.d.ts +7 -1
- package/dist/utils/base-path.js +10 -1
- package/dist/utils/base-path.js.map +1 -1
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +1 -3
- package/dist/utils/cache-control-metadata.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +2 -1
- package/dist/utils/domain-locale.js +9 -1
- package/dist/utils/domain-locale.js.map +1 -1
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/dist/utils/navigation-signal.d.ts +1 -2
- package/dist/utils/navigation-signal.js +1 -1
- package/dist/utils/navigation-signal.js.map +1 -1
- package/dist/utils/prerender-output-paths.d.ts +15 -0
- package/dist/utils/prerender-output-paths.js +24 -0
- package/dist/utils/prerender-output-paths.js.map +1 -0
- package/dist/utils/query.d.ts +17 -1
- package/dist/utils/query.js +36 -1
- package/dist/utils/query.js.map +1 -1
- package/dist/utils/record.d.ts +5 -0
- package/dist/utils/record.js +8 -0
- package/dist/utils/record.js.map +1 -0
- package/dist/utils/sorted-array.d.ts +9 -0
- package/dist/utils/sorted-array.js +22 -0
- package/dist/utils/sorted-array.js.map +1 -0
- package/package.json +13 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n commitCurrent: \"NC_COMMIT\",\n prefetchOnly: \"NC_PREFETCH_ONLY\",\n requestWork: \"NC_REQUEST\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n commitCurrent: \"NC_COMMIT\";\n prefetchOnly: \"NC_PREFETCH_ONLY\";\n requestWork: \"NC_REQUEST\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"currentRootLayoutTreePath\"\n | \"currentVisibleCommitVersion\"\n | \"nextRootLayoutTreePath\"\n | \"eventKind\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\"\n | \"targetHref\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nexport function createNavigationLifecycleTraceFields(options: {\n activeNavigationId?: number;\n currentRootLayoutTreePath: string | null;\n currentVisibleCommitVersion: number;\n nextRootLayoutTreePath: string | null;\n startedNavigationId?: number;\n startedVisibleCommitVersion: number;\n}): NavigationTraceFields {\n return {\n ...(options.activeNavigationId !== undefined\n ? { activeNavigationId: options.activeNavigationId }\n : {}),\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.currentVisibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n ...(options.startedNavigationId !== undefined\n ? { startedNavigationId: options.startedNavigationId }\n : {}),\n startedVisibleCommitVersion: options.startedVisibleCommitVersion,\n };\n}\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,eAAe;CACf,cAAc;CACd,aAAa;CACb,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;
|
|
1
|
+
{"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n cacheProofRejected: \"NC_CACHE_REJECT\",\n commitCurrent: \"NC_COMMIT\",\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\",\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\",\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\",\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\",\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\",\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\",\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\",\n prefetchOnly: \"NC_PREFETCH_ONLY\",\n requestWork: \"NC_REQUEST\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n cacheProofRejected: \"NC_CACHE_REJECT\";\n commitCurrent: \"NC_COMMIT\";\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\";\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\";\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\";\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\";\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\";\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\";\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\";\n prefetchOnly: \"NC_PREFETCH_ONLY\";\n requestWork: \"NC_REQUEST\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"cacheProofCode\"\n | \"cacheProofMode\"\n | \"cacheProofReuseClass\"\n | \"cacheProofScope\"\n | \"currentRootLayoutTreePath\"\n | \"currentVisibleCommitVersion\"\n | \"nextRootLayoutTreePath\"\n | \"eventKind\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\"\n | \"targetHref\"\n | \"traverseDirection\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nexport function createNavigationLifecycleTraceFields(options: {\n activeNavigationId?: number;\n currentRootLayoutTreePath: string | null;\n currentVisibleCommitVersion: number;\n nextRootLayoutTreePath: string | null;\n startedNavigationId?: number;\n startedVisibleCommitVersion: number;\n}): NavigationTraceFields {\n return {\n ...(options.activeNavigationId !== undefined\n ? { activeNavigationId: options.activeNavigationId }\n : {}),\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.currentVisibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n ...(options.startedNavigationId !== undefined\n ? { startedNavigationId: options.startedNavigationId }\n : {}),\n startedVisibleCommitVersion: options.startedVisibleCommitVersion,\n };\n}\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,oBAAoB;CACpB,eAAe;CACf,0BAA0B;CAC1B,qCAAqC;CACrC,iCAAiC;CACjC,qCAAqC;CACrC,mCAAmC;CACnC,uCAAuC;CACvC,kCAAkC;CAClC,cAAc;CACd,aAAa;CACb,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;AAiBD,MAAa,kCAAkC;CAC7C,cAAc;CACd,UAAU;CACV,eAAe;CAChB;AA+CD,SAAgB,qCAAqC,SAO3B;CACxB,OAAO;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,oBAAoB,GAClD,EAAE;EACN,2BAA2B,QAAQ;EACnC,6BAA6B,QAAQ;EACrC,wBAAwB,QAAQ;EAChC,GAAI,QAAQ,wBAAwB,KAAA,IAChC,EAAE,qBAAqB,QAAQ,qBAAqB,GACpD,EAAE;EACN,6BAA6B,QAAQ;EACtC;;AAGH,SAAS,2BACP,MACA,SAAgC,EAAE,EACZ;CACtB,OAAO;EACL;EACA,QAAQ,EAAE,GAAG,QAAQ;EACtB;;AAGH,SAAgB,sBACd,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAA;EACA,SAAS,CAAC,2BAA2B,MAAM,OAAO,CAAC;EACpD;;AAGH,SAAgB,4BACd,OACA,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAe,MAAM;EACrB,SAAS,CAAC,2BAA2B,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EACtE"}
|
|
@@ -20,6 +20,7 @@ declare function escapePathDelimiters(segment: string, escapeEncoded?: boolean):
|
|
|
20
20
|
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts
|
|
21
21
|
*/
|
|
22
22
|
declare function decodePathParams(pathname: string): string;
|
|
23
|
+
declare function isInterceptionMatchedUrlPath(value: string): boolean;
|
|
23
24
|
/**
|
|
24
25
|
* Path normalization utility for request handling.
|
|
25
26
|
*
|
|
@@ -42,5 +43,5 @@ declare function decodePathParams(pathname: string): string;
|
|
|
42
43
|
*/
|
|
43
44
|
declare function normalizePath(pathname: string): string;
|
|
44
45
|
//#endregion
|
|
45
|
-
export { decodePathParams, escapePathDelimiters, normalizePath };
|
|
46
|
+
export { decodePathParams, escapePathDelimiters, isInterceptionMatchedUrlPath, normalizePath };
|
|
46
47
|
//# sourceMappingURL=normalize-path.d.ts.map
|
|
@@ -30,6 +30,9 @@ function decodePathParams(pathname) {
|
|
|
30
30
|
}
|
|
31
31
|
}).join("/");
|
|
32
32
|
}
|
|
33
|
+
function isInterceptionMatchedUrlPath(value) {
|
|
34
|
+
return value.startsWith("/") && !value.startsWith("//") && !value.includes("?") && !value.includes("#") && !value.includes("\0");
|
|
35
|
+
}
|
|
33
36
|
/**
|
|
34
37
|
* Path normalization utility for request handling.
|
|
35
38
|
*
|
|
@@ -62,6 +65,6 @@ function normalizePath(pathname) {
|
|
|
62
65
|
return "/" + resolved.join("/");
|
|
63
66
|
}
|
|
64
67
|
//#endregion
|
|
65
|
-
export { decodePathParams, escapePathDelimiters, normalizePath };
|
|
68
|
+
export { decodePathParams, escapePathDelimiters, isInterceptionMatchedUrlPath, normalizePath };
|
|
66
69
|
|
|
67
70
|
//# sourceMappingURL=normalize-path.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-path.js","names":[],"sources":["../../src/server/normalize-path.ts"],"sourcesContent":["/**\n * Re-encode path delimiter characters that were decoded by decodeURIComponent.\n * After decoding a URL segment, characters like / # ? \\ need to be re-encoded\n * so they don't change the path structure.\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n */\nexport function escapePathDelimiters(segment: string, escapeEncoded?: boolean): string {\n return segment.replace(\n new RegExp(`([/#?]${escapeEncoded ? \"|%(2f|23|3f|5c)\" : \"\"})`, \"gi\"),\n (char: string) => encodeURIComponent(char),\n );\n}\n\n/**\n * Decode a URL pathname segment-by-segment, preserving encoded path delimiters.\n * Non-ASCII characters (e.g. %C3%A9 -> e) are decoded, but structural characters\n * like %2F (/) %23 (#) %3F (?) %5C (\\) are re-encoded after decoding.\n *\n * This prevents encoded slashes from changing the path structure (e.g.\n * /admin%2Fpanel stays as a single segment, not /admin/panel).\n *\n * Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts\n */\nexport function decodePathParams(pathname: string): string {\n return pathname\n .split(\"/\")\n .map((seg) => {\n try {\n return escapePathDelimiters(decodeURIComponent(seg), true);\n } catch {\n return seg;\n }\n })\n .join(\"/\");\n}\n\n/**\n * Path normalization utility for request handling.\n *\n * Normalizes URL pathnames to a canonical form BEFORE any matching occurs\n * (middleware, routing, redirects, rewrites). This ensures middleware and\n * the router always see the same path, preventing path-confusion issues like\n * double-slash mismatches.\n *\n * Normalization rules:\n * 1. Collapse consecutive slashes: //foo///bar → /foo/bar\n * 2. Resolve single-dot segments: /foo/./bar → /foo/bar\n * 3. Resolve double-dot segments: /foo/../bar → /bar\n * 4. Ensure leading slash: foo/bar → /foo/bar\n * 5. Preserve root: / → /\n *\n * This function does NOT:\n * - Strip or add trailing slashes (handled separately by trailingSlash config)\n * - Decode percent-encoded characters (callers should decode before calling this)\n * - Lowercase the path (route matching is case-sensitive)\n */\nexport function normalizePath(pathname: string): string {\n // Fast path: already canonical (single leading /, no //, no /./, no /../)\n if (\n pathname === \"/\" ||\n (pathname.length > 1 &&\n pathname[0] === \"/\" &&\n !pathname.includes(\"//\") &&\n !pathname.includes(\"/./\") &&\n !pathname.includes(\"/../\") &&\n !pathname.endsWith(\"/.\") &&\n !pathname.endsWith(\"/..\"))\n ) {\n return pathname;\n }\n\n const segments = pathname.split(\"/\");\n const resolved: string[] = [];\n\n for (const segment of segments) {\n if (segment === \"\" || segment === \".\") {\n // Skip empty segments (from // or leading /) and single-dot segments\n continue;\n }\n if (segment === \"..\") {\n // Go up one level, but never above root\n resolved.pop();\n } else {\n resolved.push(segment);\n }\n }\n\n return \"/\" + resolved.join(\"/\");\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,qBAAqB,SAAiB,eAAiC;CACrF,OAAO,QAAQ,QACb,IAAI,OAAO,SAAS,gBAAgB,oBAAoB,GAAG,IAAI,KAAK,GACnE,SAAiB,mBAAmB,KAAK,CAC3C;;;;;;;;;;;;;AAcH,SAAgB,iBAAiB,UAA0B;CACzD,OAAO,SACJ,MAAM,IAAI,CACV,KAAK,QAAQ;EACZ,IAAI;GACF,OAAO,qBAAqB,mBAAmB,IAAI,EAAE,KAAK;UACpD;GACN,OAAO;;GAET,CACD,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"normalize-path.js","names":[],"sources":["../../src/server/normalize-path.ts"],"sourcesContent":["/**\n * Re-encode path delimiter characters that were decoded by decodeURIComponent.\n * After decoding a URL segment, characters like / # ? \\ need to be re-encoded\n * so they don't change the path structure.\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n */\nexport function escapePathDelimiters(segment: string, escapeEncoded?: boolean): string {\n return segment.replace(\n new RegExp(`([/#?]${escapeEncoded ? \"|%(2f|23|3f|5c)\" : \"\"})`, \"gi\"),\n (char: string) => encodeURIComponent(char),\n );\n}\n\n/**\n * Decode a URL pathname segment-by-segment, preserving encoded path delimiters.\n * Non-ASCII characters (e.g. %C3%A9 -> e) are decoded, but structural characters\n * like %2F (/) %23 (#) %3F (?) %5C (\\) are re-encoded after decoding.\n *\n * This prevents encoded slashes from changing the path structure (e.g.\n * /admin%2Fpanel stays as a single segment, not /admin/panel).\n *\n * Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts\n */\nexport function decodePathParams(pathname: string): string {\n return pathname\n .split(\"/\")\n .map((seg) => {\n try {\n return escapePathDelimiters(decodeURIComponent(seg), true);\n } catch {\n return seg;\n }\n })\n .join(\"/\");\n}\n\nexport function isInterceptionMatchedUrlPath(value: string): boolean {\n return (\n value.startsWith(\"/\") &&\n !value.startsWith(\"//\") &&\n !value.includes(\"?\") &&\n !value.includes(\"#\") &&\n !value.includes(\"\\0\")\n );\n}\n\n/**\n * Path normalization utility for request handling.\n *\n * Normalizes URL pathnames to a canonical form BEFORE any matching occurs\n * (middleware, routing, redirects, rewrites). This ensures middleware and\n * the router always see the same path, preventing path-confusion issues like\n * double-slash mismatches.\n *\n * Normalization rules:\n * 1. Collapse consecutive slashes: //foo///bar → /foo/bar\n * 2. Resolve single-dot segments: /foo/./bar → /foo/bar\n * 3. Resolve double-dot segments: /foo/../bar → /bar\n * 4. Ensure leading slash: foo/bar → /foo/bar\n * 5. Preserve root: / → /\n *\n * This function does NOT:\n * - Strip or add trailing slashes (handled separately by trailingSlash config)\n * - Decode percent-encoded characters (callers should decode before calling this)\n * - Lowercase the path (route matching is case-sensitive)\n */\nexport function normalizePath(pathname: string): string {\n // Fast path: already canonical (single leading /, no //, no /./, no /../)\n if (\n pathname === \"/\" ||\n (pathname.length > 1 &&\n pathname[0] === \"/\" &&\n !pathname.includes(\"//\") &&\n !pathname.includes(\"/./\") &&\n !pathname.includes(\"/../\") &&\n !pathname.endsWith(\"/.\") &&\n !pathname.endsWith(\"/..\"))\n ) {\n return pathname;\n }\n\n const segments = pathname.split(\"/\");\n const resolved: string[] = [];\n\n for (const segment of segments) {\n if (segment === \"\" || segment === \".\") {\n // Skip empty segments (from // or leading /) and single-dot segments\n continue;\n }\n if (segment === \"..\") {\n // Go up one level, but never above root\n resolved.pop();\n } else {\n resolved.push(segment);\n }\n }\n\n return \"/\" + resolved.join(\"/\");\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,qBAAqB,SAAiB,eAAiC;CACrF,OAAO,QAAQ,QACb,IAAI,OAAO,SAAS,gBAAgB,oBAAoB,GAAG,IAAI,KAAK,GACnE,SAAiB,mBAAmB,KAAK,CAC3C;;;;;;;;;;;;;AAcH,SAAgB,iBAAiB,UAA0B;CACzD,OAAO,SACJ,MAAM,IAAI,CACV,KAAK,QAAQ;EACZ,IAAI;GACF,OAAO,qBAAqB,mBAAmB,IAAI,EAAE,KAAK;UACpD;GACN,OAAO;;GAET,CACD,KAAK,IAAI;;AAGd,SAAgB,6BAA6B,OAAwB;CACnE,OACE,MAAM,WAAW,IAAI,IACrB,CAAC,MAAM,WAAW,KAAK,IACvB,CAAC,MAAM,SAAS,IAAI,IACpB,CAAC,MAAM,SAAS,IAAI,IACpB,CAAC,MAAM,SAAS,KAAK;;;;;;;;;;;;;;;;;;;;;;AAwBzB,SAAgB,cAAc,UAA0B;CAEtD,IACE,aAAa,OACZ,SAAS,SAAS,KACjB,SAAS,OAAO,OAChB,CAAC,SAAS,SAAS,KAAK,IACxB,CAAC,SAAS,SAAS,MAAM,IACzB,CAAC,SAAS,SAAS,OAAO,IAC1B,CAAC,SAAS,SAAS,KAAK,IACxB,CAAC,SAAS,SAAS,MAAM,EAE3B,OAAO;CAGT,MAAM,WAAW,SAAS,MAAM,IAAI;CACpC,MAAM,WAAqB,EAAE;CAE7B,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,YAAY,MAAM,YAAY,KAEhC;EAEF,IAAI,YAAY,MAEd,SAAS,KAAK;OAEd,SAAS,KAAK,QAAQ;;CAI1B,OAAO,MAAM,SAAS,KAAK,IAAI"}
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import { Route } from "../routing/pages-router.js";
|
|
2
|
+
import { ExecutionContextLike } from "../shims/request-context.js";
|
|
2
3
|
import { PagesReqResRequest, PagesReqResResponse, PagesRequestQuery } from "./pages-node-compat.js";
|
|
3
4
|
|
|
4
5
|
//#region src/server/pages-api-route.d.ts
|
|
6
|
+
type PagesApiRouteConfig = {
|
|
7
|
+
runtime?: string;
|
|
8
|
+
};
|
|
9
|
+
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;
|
|
10
|
+
type PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;
|
|
5
11
|
type PagesApiRouteModule = {
|
|
6
|
-
|
|
12
|
+
/**
|
|
13
|
+
* `export const config = { runtime: 'edge' }` — historical Pages Router form.
|
|
14
|
+
*/
|
|
15
|
+
config?: PagesApiRouteConfig;
|
|
16
|
+
/**
|
|
17
|
+
* `export const runtime = 'edge'` — bare export form. Next.js resolves the
|
|
18
|
+
* effective runtime as `config.runtime ?? config.config?.runtime`, so a
|
|
19
|
+
* top-level `runtime` export takes precedence over the nested config form.
|
|
20
|
+
*
|
|
21
|
+
* @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/analysis/get-page-static-info.ts
|
|
22
|
+
*/
|
|
23
|
+
runtime?: string;
|
|
24
|
+
default?: PagesNodeApiRouteHandler | PagesEdgeApiRouteHandler;
|
|
7
25
|
};
|
|
8
26
|
type PagesApiRouteMatch = {
|
|
9
27
|
params: PagesRequestQuery;
|
|
@@ -12,6 +30,14 @@ type PagesApiRouteMatch = {
|
|
|
12
30
|
};
|
|
13
31
|
};
|
|
14
32
|
type HandlePagesApiRouteOptions = {
|
|
33
|
+
/**
|
|
34
|
+
* Per-request Cloudflare Workers `ExecutionContext`. When provided, the
|
|
35
|
+
* API route runs inside `runWithExecutionContext(ctx, ...)` so any
|
|
36
|
+
* `after()` (or other shim) call inside the handler can reach
|
|
37
|
+
* `ctx.waitUntil()` via the ALS and keep the isolate alive past the
|
|
38
|
+
* response. Omit on Node.js dev where no Workers lifecycle exists.
|
|
39
|
+
*/
|
|
40
|
+
ctx?: ExecutionContextLike;
|
|
15
41
|
match: PagesApiRouteMatch | null;
|
|
16
42
|
reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;
|
|
17
43
|
request: Request;
|
|
@@ -1,17 +1,39 @@
|
|
|
1
|
+
import "./server-globals.js";
|
|
2
|
+
import { runWithExecutionContext } from "../shims/request-context.js";
|
|
3
|
+
import { NextRequest } from "../shims/server.js";
|
|
1
4
|
import { internalServerErrorResponse } from "./http-error-responses.js";
|
|
2
5
|
import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
|
|
3
6
|
import { PagesBodyParseError } from "./pages-media-type.js";
|
|
7
|
+
import { isEdgeApiRuntime } from "./edge-api-runtime.js";
|
|
4
8
|
import { createPagesReqRes, parsePagesApiBody } from "./pages-node-compat.js";
|
|
5
9
|
//#region src/server/pages-api-route.ts
|
|
10
|
+
function resolveModuleRuntime(module) {
|
|
11
|
+
return module.runtime ?? module.config?.runtime;
|
|
12
|
+
}
|
|
6
13
|
function buildPagesApiQuery(url, params) {
|
|
7
14
|
return mergeRouteParamsIntoQuery(parseQueryString(url), params);
|
|
8
15
|
}
|
|
16
|
+
function isEdgeApiRouteModule(module) {
|
|
17
|
+
return typeof module.default === "function" && isEdgeApiRuntime(resolveModuleRuntime(module));
|
|
18
|
+
}
|
|
19
|
+
function isNodeApiRouteModule(module) {
|
|
20
|
+
return typeof module.default === "function" && !isEdgeApiRuntime(resolveModuleRuntime(module));
|
|
21
|
+
}
|
|
9
22
|
async function handlePagesApiRoute(options) {
|
|
23
|
+
if (options.ctx) return runWithExecutionContext(options.ctx, () => _handlePagesApiRoute(options));
|
|
24
|
+
return _handlePagesApiRoute(options);
|
|
25
|
+
}
|
|
26
|
+
async function _handlePagesApiRoute(options) {
|
|
10
27
|
if (!options.match) return new Response("404 - API route not found", { status: 404 });
|
|
11
28
|
const { route, params } = options.match;
|
|
12
|
-
const handler = route.module.default;
|
|
13
|
-
if (typeof handler !== "function") return new Response("API route does not export a default function", { status: 500 });
|
|
14
29
|
try {
|
|
30
|
+
if (isEdgeApiRouteModule(route.module)) {
|
|
31
|
+
const nextRequest = new NextRequest(options.request);
|
|
32
|
+
const response = await route.module.default(nextRequest);
|
|
33
|
+
if (response instanceof Response) return response;
|
|
34
|
+
throw new Error("Edge API route did not return a Response");
|
|
35
|
+
}
|
|
36
|
+
if (!isNodeApiRouteModule(route.module)) return new Response("API route does not export a default function", { status: 500 });
|
|
15
37
|
const query = buildPagesApiQuery(options.url, params);
|
|
16
38
|
const { req, res, responsePromise } = createPagesReqRes({
|
|
17
39
|
body: await parsePagesApiBody(options.request),
|
|
@@ -19,7 +41,7 @@ async function handlePagesApiRoute(options) {
|
|
|
19
41
|
request: options.request,
|
|
20
42
|
url: options.url
|
|
21
43
|
});
|
|
22
|
-
await
|
|
44
|
+
await route.module.default(req, res);
|
|
23
45
|
res.end();
|
|
24
46
|
return await responsePromise;
|
|
25
47
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import type { Route } from \"../routing/pages-router.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\n\ntype
|
|
1
|
+
{"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import \"./server-globals.js\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\nimport { runWithExecutionContext, type ExecutionContextLike } from \"vinext/shims/request-context\";\nimport { NextRequest } from \"vinext/shims/server\";\n\ntype PagesApiRouteConfig = {\n runtime?: string;\n};\n\ntype PagesNodeApiRouteHandler = (\n req: PagesReqResRequest,\n res: PagesReqResResponse,\n) => void | Promise<void>;\n\ntype PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;\n\ntype PagesApiRouteModule = {\n /**\n * `export const config = { runtime: 'edge' }` — historical Pages Router form.\n */\n config?: PagesApiRouteConfig;\n /**\n * `export const runtime = 'edge'` — bare export form. Next.js resolves the\n * effective runtime as `config.runtime ?? config.config?.runtime`, so a\n * top-level `runtime` export takes precedence over the nested config form.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/analysis/get-page-static-info.ts\n */\n runtime?: string;\n default?: PagesNodeApiRouteHandler | PagesEdgeApiRouteHandler;\n};\n\nfunction resolveModuleRuntime(module: PagesApiRouteModule): string | undefined {\n return module.runtime ?? module.config?.runtime;\n}\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n /**\n * Per-request Cloudflare Workers `ExecutionContext`. When provided, the\n * API route runs inside `runWithExecutionContext(ctx, ...)` so any\n * `after()` (or other shim) call inside the handler can reach\n * `ctx.waitUntil()` via the ALS and keep the isolate alive past the\n * response. Omit on Node.js dev where no Workers lifecycle exists.\n */\n ctx?: ExecutionContextLike;\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n return mergeRouteParamsIntoQuery(parseQueryString(url), params);\n}\n\nfunction isEdgeApiRouteModule(\n module: PagesApiRouteModule,\n): module is PagesApiRouteModule & { default: PagesEdgeApiRouteHandler } {\n return typeof module.default === \"function\" && isEdgeApiRuntime(resolveModuleRuntime(module));\n}\n\nfunction isNodeApiRouteModule(\n module: PagesApiRouteModule,\n): module is PagesApiRouteModule & { default: PagesNodeApiRouteHandler } {\n return typeof module.default === \"function\" && !isEdgeApiRuntime(resolveModuleRuntime(module));\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (options.ctx) {\n return runWithExecutionContext(options.ctx, () => _handlePagesApiRoute(options));\n }\n return _handlePagesApiRoute(options);\n}\n\nasync function _handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n\n try {\n if (isEdgeApiRouteModule(route.module)) {\n // Next.js wraps the incoming Request in a NextRequest before invoking\n // edge API handlers, so handlers can use `req.nextUrl.searchParams`,\n // `req.cookies`, etc. (Cf. NextRequestHint in next/src/server/web/adapter.ts.)\n const nextRequest = new NextRequest(options.request);\n const response = await route.module.default(nextRequest);\n if (response instanceof Response) {\n return response;\n }\n\n throw new Error(\"Edge API route did not return a Response\");\n }\n\n // This is redundant at runtime after the edge branch for function exports, but it\n // keeps the Node handler ABI narrowed without a production type assertion.\n if (!isNodeApiRouteModule(route.module)) {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await route.module.default(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return internalServerErrorResponse();\n }\n}\n"],"mappings":";;;;;;;;;AA2CA,SAAS,qBAAqB,QAAiD;CAC7E,OAAO,OAAO,WAAW,OAAO,QAAQ;;AAyB1C,SAAS,mBAAmB,KAAa,QAA8C;CACrF,OAAO,0BAA0B,iBAAiB,IAAI,EAAE,OAAO;;AAGjE,SAAS,qBACP,QACuE;CACvE,OAAO,OAAO,OAAO,YAAY,cAAc,iBAAiB,qBAAqB,OAAO,CAAC;;AAG/F,SAAS,qBACP,QACuE;CACvE,OAAO,OAAO,OAAO,YAAY,cAAc,CAAC,iBAAiB,qBAAqB,OAAO,CAAC;;AAGhG,eAAsB,oBAAoB,SAAwD;CAChG,IAAI,QAAQ,KACV,OAAO,wBAAwB,QAAQ,WAAW,qBAAqB,QAAQ,CAAC;CAElF,OAAO,qBAAqB,QAAQ;;AAGtC,eAAe,qBAAqB,SAAwD;CAC1F,IAAI,CAAC,QAAQ,OACX,OAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAElC,IAAI;EACF,IAAI,qBAAqB,MAAM,OAAO,EAAE;GAItC,MAAM,cAAc,IAAI,YAAY,QAAQ,QAAQ;GACpD,MAAM,WAAW,MAAM,MAAM,OAAO,QAAQ,YAAY;GACxD,IAAI,oBAAoB,UACtB,OAAO;GAGT,MAAM,IAAI,MAAM,2CAA2C;;EAK7D,IAAI,CAAC,qBAAqB,MAAM,OAAO,EACrC,OAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;EAGtF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAAA,MAFiB,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;EAEF,MAAM,MAAM,OAAO,QAAQ,KAAK,IAAI;EACpC,IAAI,KAAK;EACT,OAAO,MAAM;UACN,OAAO;EACd,IAAI,iBAAiBA,qBACnB,OAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;EAGJ,QAAa,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;EACD,OAAO,6BAA6B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/server/pages-data-route.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
|
|
4
|
+
*
|
|
5
|
+
* Next.js uses this endpoint for client-side navigations in the Pages Router:
|
|
6
|
+
* `next/link` and `router.push()` fetch `pageProps` from this URL instead of
|
|
7
|
+
* doing a full HTML navigation. The server must:
|
|
8
|
+
* 1. Match the URL pattern and extract the page pathname (with the buildId
|
|
9
|
+
* and `.json` extension removed, locale prefix preserved).
|
|
10
|
+
* 2. Normalize the URL BEFORE middleware runs so middleware sees the page
|
|
11
|
+
* path (e.g. `/about`) rather than the raw `/_next/data/.../about.json`.
|
|
12
|
+
* 3. Invoke the same `getServerSideProps` / `getStaticProps` machinery as
|
|
13
|
+
* the HTML page and serialize the resulting props as a JSON envelope:
|
|
14
|
+
* `{ pageProps: ... }` with `Content-Type: application/json`.
|
|
15
|
+
*
|
|
16
|
+
* Ported from Next.js:
|
|
17
|
+
* - `packages/next/src/server/normalizers/request/next-data.ts` — prefix/suffix matcher.
|
|
18
|
+
* - `packages/next/src/server/base-server.ts` (`handleNextDataRequest`) — pipeline normalization.
|
|
19
|
+
* - `packages/next/src/server/render.tsx` — JSON envelope emission (`isNextDataRequest`).
|
|
20
|
+
*/
|
|
21
|
+
type NextDataMatch = {
|
|
22
|
+
/**
|
|
23
|
+
* The normalized page pathname (with leading slash, no trailing slash,
|
|
24
|
+
* `.json` stripped, buildId stripped). For locale-prefixed requests like
|
|
25
|
+
* `/_next/data/<buildId>/en/about.json` this is `/en/about` — locale
|
|
26
|
+
* handling is done downstream by the existing `resolvePagesI18nRequest`
|
|
27
|
+
* pipeline so this helper does not need to know about i18n config.
|
|
28
|
+
*/
|
|
29
|
+
pagePathname: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Returns true if the pathname looks like a `_next/data` request, regardless
|
|
33
|
+
* of buildId. Used by the request pipeline to short-circuit before middleware
|
|
34
|
+
* even when the buildId is wrong (so we can still return a 404 JSON response).
|
|
35
|
+
*/
|
|
36
|
+
declare function isNextDataPathname(pathname: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Parse `/_next/data/<buildId>/<...page>.json` and return the normalized page
|
|
39
|
+
* pathname. Returns `null` if the pathname does not match the pattern or if
|
|
40
|
+
* the buildId segment does not match the server's buildId.
|
|
41
|
+
*
|
|
42
|
+
* The returned `pagePathname` is the page route path Next.js would render for
|
|
43
|
+
* the equivalent HTML navigation — including any locale prefix, which is then
|
|
44
|
+
* stripped by `resolvePagesI18nRequest` downstream.
|
|
45
|
+
*
|
|
46
|
+
* `/_next/data/<buildId>/about.json` → `/about`
|
|
47
|
+
* `/_next/data/<buildId>/en/about.json` → `/en/about`
|
|
48
|
+
* `/_next/data/<buildId>/index.json` → `/`
|
|
49
|
+
* `/_next/data/<buildId>/en.json` → `/en`
|
|
50
|
+
* `/_next/data/<wrong-id>/about.json` → null
|
|
51
|
+
* `/_next/data/<buildId>/about` → null (missing .json suffix)
|
|
52
|
+
*/
|
|
53
|
+
declare function parseNextDataPathname(pathname: string, buildId: string): NextDataMatch | null;
|
|
54
|
+
/**
|
|
55
|
+
* Build the JSON envelope returned by `/_next/data/<buildId>/<page>.json`.
|
|
56
|
+
* Mirrors Next.js' `RenderResult(JSON.stringify(props))` path in
|
|
57
|
+
* `packages/next/src/server/render.tsx` (search for `isNextDataRequest`).
|
|
58
|
+
*
|
|
59
|
+
* The envelope is the outer `props` object the React tree would receive:
|
|
60
|
+
* { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
|
|
61
|
+
*/
|
|
62
|
+
declare function buildNextDataJsonResponse(pageProps: Record<string, unknown>, safeJsonStringify: (value: unknown) => string, init?: ResponseInit): Response;
|
|
63
|
+
/**
|
|
64
|
+
* Build the 404 response Next.js returns for an unknown `_next/data` page.
|
|
65
|
+
* Next.js renders this as a normal 404 page, but the body shape that clients
|
|
66
|
+
* see for a missing page-data endpoint is the literal string `"{ }"` for the
|
|
67
|
+
* body and a 404 status with `application/json` so client-side hard-navigation
|
|
68
|
+
* fallback fires (see `__N_SSP` handling in `router.ts`).
|
|
69
|
+
*
|
|
70
|
+
* We match Next.js' behavior: 404 status + JSON content type. The body is an
|
|
71
|
+
* empty JSON object so clients that blindly call `res.json()` do not throw
|
|
72
|
+
* before checking the status code.
|
|
73
|
+
*/
|
|
74
|
+
declare function buildNextDataNotFoundResponse(): Response;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, parseNextDataPathname };
|
|
77
|
+
//# sourceMappingURL=pages-data-route.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//#region src/server/pages-data-route.ts
|
|
2
|
+
/**
|
|
3
|
+
* Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
|
|
4
|
+
*
|
|
5
|
+
* Next.js uses this endpoint for client-side navigations in the Pages Router:
|
|
6
|
+
* `next/link` and `router.push()` fetch `pageProps` from this URL instead of
|
|
7
|
+
* doing a full HTML navigation. The server must:
|
|
8
|
+
* 1. Match the URL pattern and extract the page pathname (with the buildId
|
|
9
|
+
* and `.json` extension removed, locale prefix preserved).
|
|
10
|
+
* 2. Normalize the URL BEFORE middleware runs so middleware sees the page
|
|
11
|
+
* path (e.g. `/about`) rather than the raw `/_next/data/.../about.json`.
|
|
12
|
+
* 3. Invoke the same `getServerSideProps` / `getStaticProps` machinery as
|
|
13
|
+
* the HTML page and serialize the resulting props as a JSON envelope:
|
|
14
|
+
* `{ pageProps: ... }` with `Content-Type: application/json`.
|
|
15
|
+
*
|
|
16
|
+
* Ported from Next.js:
|
|
17
|
+
* - `packages/next/src/server/normalizers/request/next-data.ts` — prefix/suffix matcher.
|
|
18
|
+
* - `packages/next/src/server/base-server.ts` (`handleNextDataRequest`) — pipeline normalization.
|
|
19
|
+
* - `packages/next/src/server/render.tsx` — JSON envelope emission (`isNextDataRequest`).
|
|
20
|
+
*/
|
|
21
|
+
const NEXT_DATA_PREFIX = "/_next/data/";
|
|
22
|
+
const NEXT_DATA_SUFFIX = ".json";
|
|
23
|
+
/**
|
|
24
|
+
* Returns true if the pathname looks like a `_next/data` request, regardless
|
|
25
|
+
* of buildId. Used by the request pipeline to short-circuit before middleware
|
|
26
|
+
* even when the buildId is wrong (so we can still return a 404 JSON response).
|
|
27
|
+
*/
|
|
28
|
+
function isNextDataPathname(pathname) {
|
|
29
|
+
return pathname.startsWith(NEXT_DATA_PREFIX) && pathname.endsWith(NEXT_DATA_SUFFIX);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse `/_next/data/<buildId>/<...page>.json` and return the normalized page
|
|
33
|
+
* pathname. Returns `null` if the pathname does not match the pattern or if
|
|
34
|
+
* the buildId segment does not match the server's buildId.
|
|
35
|
+
*
|
|
36
|
+
* The returned `pagePathname` is the page route path Next.js would render for
|
|
37
|
+
* the equivalent HTML navigation — including any locale prefix, which is then
|
|
38
|
+
* stripped by `resolvePagesI18nRequest` downstream.
|
|
39
|
+
*
|
|
40
|
+
* `/_next/data/<buildId>/about.json` → `/about`
|
|
41
|
+
* `/_next/data/<buildId>/en/about.json` → `/en/about`
|
|
42
|
+
* `/_next/data/<buildId>/index.json` → `/`
|
|
43
|
+
* `/_next/data/<buildId>/en.json` → `/en`
|
|
44
|
+
* `/_next/data/<wrong-id>/about.json` → null
|
|
45
|
+
* `/_next/data/<buildId>/about` → null (missing .json suffix)
|
|
46
|
+
*/
|
|
47
|
+
function parseNextDataPathname(pathname, buildId) {
|
|
48
|
+
if (!buildId) return null;
|
|
49
|
+
if (!isNextDataPathname(pathname)) return null;
|
|
50
|
+
const expectedPrefix = `${NEXT_DATA_PREFIX}${buildId}/`;
|
|
51
|
+
if (!pathname.startsWith(expectedPrefix)) return null;
|
|
52
|
+
const rest = pathname.slice(expectedPrefix.length, -5);
|
|
53
|
+
if (rest.length === 0) return null;
|
|
54
|
+
if (rest === "index") return { pagePathname: "/" };
|
|
55
|
+
if (rest.endsWith("/index")) return { pagePathname: `/${rest.slice(0, -6)}` };
|
|
56
|
+
return { pagePathname: `/${rest}` };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build the JSON envelope returned by `/_next/data/<buildId>/<page>.json`.
|
|
60
|
+
* Mirrors Next.js' `RenderResult(JSON.stringify(props))` path in
|
|
61
|
+
* `packages/next/src/server/render.tsx` (search for `isNextDataRequest`).
|
|
62
|
+
*
|
|
63
|
+
* The envelope is the outer `props` object the React tree would receive:
|
|
64
|
+
* { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
|
|
65
|
+
*/
|
|
66
|
+
function buildNextDataJsonResponse(pageProps, safeJsonStringify, init) {
|
|
67
|
+
const body = safeJsonStringify({ pageProps });
|
|
68
|
+
return new Response(body, {
|
|
69
|
+
status: init?.status ?? 200,
|
|
70
|
+
statusText: init?.statusText,
|
|
71
|
+
headers: {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
...init?.headers
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the 404 response Next.js returns for an unknown `_next/data` page.
|
|
79
|
+
* Next.js renders this as a normal 404 page, but the body shape that clients
|
|
80
|
+
* see for a missing page-data endpoint is the literal string `"{ }"` for the
|
|
81
|
+
* body and a 404 status with `application/json` so client-side hard-navigation
|
|
82
|
+
* fallback fires (see `__N_SSP` handling in `router.ts`).
|
|
83
|
+
*
|
|
84
|
+
* We match Next.js' behavior: 404 status + JSON content type. The body is an
|
|
85
|
+
* empty JSON object so clients that blindly call `res.json()` do not throw
|
|
86
|
+
* before checking the status code.
|
|
87
|
+
*/
|
|
88
|
+
function buildNextDataNotFoundResponse() {
|
|
89
|
+
return new Response("{}", {
|
|
90
|
+
status: 404,
|
|
91
|
+
headers: { "Content-Type": "application/json" }
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, parseNextDataPathname };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=pages-data-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages-data-route.js","names":[],"sources":["../../src/server/pages-data-route.ts"],"sourcesContent":["/**\n * Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.\n *\n * Next.js uses this endpoint for client-side navigations in the Pages Router:\n * `next/link` and `router.push()` fetch `pageProps` from this URL instead of\n * doing a full HTML navigation. The server must:\n * 1. Match the URL pattern and extract the page pathname (with the buildId\n * and `.json` extension removed, locale prefix preserved).\n * 2. Normalize the URL BEFORE middleware runs so middleware sees the page\n * path (e.g. `/about`) rather than the raw `/_next/data/.../about.json`.\n * 3. Invoke the same `getServerSideProps` / `getStaticProps` machinery as\n * the HTML page and serialize the resulting props as a JSON envelope:\n * `{ pageProps: ... }` with `Content-Type: application/json`.\n *\n * Ported from Next.js:\n * - `packages/next/src/server/normalizers/request/next-data.ts` — prefix/suffix matcher.\n * - `packages/next/src/server/base-server.ts` (`handleNextDataRequest`) — pipeline normalization.\n * - `packages/next/src/server/render.tsx` — JSON envelope emission (`isNextDataRequest`).\n */\n\nconst NEXT_DATA_PREFIX = \"/_next/data/\";\nconst NEXT_DATA_SUFFIX = \".json\";\n\ntype NextDataMatch = {\n /**\n * The normalized page pathname (with leading slash, no trailing slash,\n * `.json` stripped, buildId stripped). For locale-prefixed requests like\n * `/_next/data/<buildId>/en/about.json` this is `/en/about` — locale\n * handling is done downstream by the existing `resolvePagesI18nRequest`\n * pipeline so this helper does not need to know about i18n config.\n */\n pagePathname: string;\n};\n\n/**\n * Returns true if the pathname looks like a `_next/data` request, regardless\n * of buildId. Used by the request pipeline to short-circuit before middleware\n * even when the buildId is wrong (so we can still return a 404 JSON response).\n */\nexport function isNextDataPathname(pathname: string): boolean {\n return pathname.startsWith(NEXT_DATA_PREFIX) && pathname.endsWith(NEXT_DATA_SUFFIX);\n}\n\n/**\n * Parse `/_next/data/<buildId>/<...page>.json` and return the normalized page\n * pathname. Returns `null` if the pathname does not match the pattern or if\n * the buildId segment does not match the server's buildId.\n *\n * The returned `pagePathname` is the page route path Next.js would render for\n * the equivalent HTML navigation — including any locale prefix, which is then\n * stripped by `resolvePagesI18nRequest` downstream.\n *\n * `/_next/data/<buildId>/about.json` → `/about`\n * `/_next/data/<buildId>/en/about.json` → `/en/about`\n * `/_next/data/<buildId>/index.json` → `/`\n * `/_next/data/<buildId>/en.json` → `/en`\n * `/_next/data/<wrong-id>/about.json` → null\n * `/_next/data/<buildId>/about` → null (missing .json suffix)\n */\nexport function parseNextDataPathname(pathname: string, buildId: string): NextDataMatch | null {\n if (!buildId) return null;\n if (!isNextDataPathname(pathname)) return null;\n\n const expectedPrefix = `${NEXT_DATA_PREFIX}${buildId}/`;\n // `/_next/data/<buildId>.json` (no trailing slash) is not a valid data req.\n if (!pathname.startsWith(expectedPrefix)) return null;\n\n const rest = pathname.slice(expectedPrefix.length, -NEXT_DATA_SUFFIX.length);\n\n // Empty rest (`/_next/data/<buildId>/.json`) is not a valid page path.\n if (rest.length === 0) return null;\n\n // Next.js denormalizes `index` to `/` to mirror file-system page paths\n // (`pages/index.tsx` → `/`). See `denormalizePagePath` in Next.js.\n if (rest === \"index\") return { pagePathname: \"/\" };\n if (rest.endsWith(\"/index\")) return { pagePathname: `/${rest.slice(0, -\"/index\".length)}` };\n\n return { pagePathname: `/${rest}` };\n}\n\n/**\n * Build the JSON envelope returned by `/_next/data/<buildId>/<page>.json`.\n * Mirrors Next.js' `RenderResult(JSON.stringify(props))` path in\n * `packages/next/src/server/render.tsx` (search for `isNextDataRequest`).\n *\n * The envelope is the outer `props` object the React tree would receive:\n * { pageProps: {...}, /* optional locale data, redirect markers, etc. *\\/ }\n */\nexport function buildNextDataJsonResponse(\n pageProps: Record<string, unknown>,\n safeJsonStringify: (value: unknown) => string,\n init?: ResponseInit,\n): Response {\n const body = safeJsonStringify({ pageProps });\n return new Response(body, {\n status: init?.status ?? 200,\n statusText: init?.statusText,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(init?.headers as Record<string, string> | undefined),\n },\n });\n}\n\n/**\n * Build the 404 response Next.js returns for an unknown `_next/data` page.\n * Next.js renders this as a normal 404 page, but the body shape that clients\n * see for a missing page-data endpoint is the literal string `\"{ }\"` for the\n * body and a 404 status with `application/json` so client-side hard-navigation\n * fallback fires (see `__N_SSP` handling in `router.ts`).\n *\n * We match Next.js' behavior: 404 status + JSON content type. The body is an\n * empty JSON object so clients that blindly call `res.json()` do not throw\n * before checking the status code.\n */\nexport function buildNextDataNotFoundResponse(): Response {\n return new Response(\"{}\", {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;;;;;;AAkBzB,SAAgB,mBAAmB,UAA2B;CAC5D,OAAO,SAAS,WAAW,iBAAiB,IAAI,SAAS,SAAS,iBAAiB;;;;;;;;;;;;;;;;;;AAmBrF,SAAgB,sBAAsB,UAAkB,SAAuC;CAC7F,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI,CAAC,mBAAmB,SAAS,EAAE,OAAO;CAE1C,MAAM,iBAAiB,GAAG,mBAAmB,QAAQ;CAErD,IAAI,CAAC,SAAS,WAAW,eAAe,EAAE,OAAO;CAEjD,MAAM,OAAO,SAAS,MAAM,eAAe,QAAQ,GAAyB;CAG5E,IAAI,KAAK,WAAW,GAAG,OAAO;CAI9B,IAAI,SAAS,SAAS,OAAO,EAAE,cAAc,KAAK;CAClD,IAAI,KAAK,SAAS,SAAS,EAAE,OAAO,EAAE,cAAc,IAAI,KAAK,MAAM,GAAG,GAAiB,IAAI;CAE3F,OAAO,EAAE,cAAc,IAAI,QAAQ;;;;;;;;;;AAWrC,SAAgB,0BACd,WACA,mBACA,MACU;CACV,MAAM,OAAO,kBAAkB,EAAE,WAAW,CAAC;CAC7C,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ,MAAM,UAAU;EACxB,YAAY,MAAM;EAClB,SAAS;GACP,gBAAgB;GAChB,GAAI,MAAM;GACX;EACF,CAAC;;;;;;;;;;;;;AAcJ,SAAgB,gCAA0C;CACxD,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS,EAAE,gBAAgB,oBAAoB;EAChD,CAAC"}
|
|
@@ -25,6 +25,40 @@ type PagesI18nRequestInfo = {
|
|
|
25
25
|
domainLocale?: DomainLocale;
|
|
26
26
|
redirectUrl?: string;
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Prepend the default locale prefix to a pathname when i18n is configured and
|
|
30
|
+
* the path does not already carry a locale prefix. Mirrors Next.js's
|
|
31
|
+
* server-side path normalisation in `resolve-routes.ts` (lines ~250-263):
|
|
32
|
+
*
|
|
33
|
+
* if (!initialLocaleResult.detectedLocale && !pathname.startsWith('/_next/')) {
|
|
34
|
+
* parsedUrl.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* Run this **before** matching against `next.config.js` redirects/rewrites
|
|
38
|
+
* (which are emitted by `applyLocaleToRoutes` in locale-prefixed forms) so
|
|
39
|
+
* that requests arriving without a locale prefix still match those rules.
|
|
40
|
+
*
|
|
41
|
+
* Skips internal paths that Next.js leaves alone:
|
|
42
|
+
* - `/_next/*` (build assets, prerender manifests, image optimisation)
|
|
43
|
+
* - `/__vinext/*` (vinext-internal endpoints)
|
|
44
|
+
*
|
|
45
|
+
* Returns the input unchanged when i18n is not configured or when the path
|
|
46
|
+
* already starts with one of the configured locales. The host-based default
|
|
47
|
+
* locale (i18n.domains[].defaultLocale) is preferred over the global default
|
|
48
|
+
* when supplied, matching Next.js's `domainLocale.defaultLocale` branch.
|
|
49
|
+
*
|
|
50
|
+
* Item 4 of issue #1336: without this normalisation, requests like
|
|
51
|
+
* `/to-sv` (default locale = en) against a rule `source: '/:locale/to-sv'`
|
|
52
|
+
* with `locale: false` do not match because there is no segment for
|
|
53
|
+
* `:locale`. After normalisation the request looks like `/en/to-sv` and
|
|
54
|
+
* the rule matches with `:locale=en`.
|
|
55
|
+
*
|
|
56
|
+
* Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
|
|
57
|
+
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
|
|
58
|
+
*/
|
|
59
|
+
declare function normalizeDefaultLocalePathname(pathname: string, i18n: NextI18nConfig | null | undefined, options?: {
|
|
60
|
+
hostname?: string | null;
|
|
61
|
+
}): string;
|
|
28
62
|
/**
|
|
29
63
|
* Extract locale prefix from a URL path.
|
|
30
64
|
* e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
|
|
@@ -35,6 +69,22 @@ declare function extractLocaleFromUrl(url: string, i18nConfig: NextI18nConfig, d
|
|
|
35
69
|
url: string;
|
|
36
70
|
hadPrefix: boolean;
|
|
37
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* Strip a leading i18n locale segment from a URL so the result can be used for
|
|
74
|
+
* API route matching. Mirrors Next.js's base-server behaviour for Pages
|
|
75
|
+
* Router API routes: `normalizeLocalePath(pathname, i18n.locales).pathname`
|
|
76
|
+
* runs before the `/api/*` check so `/fr/api/ok` resolves to the
|
|
77
|
+
* `pages/api/ok` handler instead of 404'ing.
|
|
78
|
+
*
|
|
79
|
+
* Returns the original URL untouched when:
|
|
80
|
+
* - `i18nConfig` is null/undefined (no i18n configured)
|
|
81
|
+
* - the URL does not start with a configured locale
|
|
82
|
+
*
|
|
83
|
+
* The query string is preserved verbatim — only the path segment is stripped.
|
|
84
|
+
*
|
|
85
|
+
* Reference: packages/next/src/shared/lib/i18n/normalize-locale-path.ts.
|
|
86
|
+
*/
|
|
87
|
+
declare function stripI18nLocaleForApiRoute(url: string, i18nConfig: NextI18nConfig | null | undefined): string;
|
|
38
88
|
/**
|
|
39
89
|
* Detect the preferred locale from the Accept-Language header.
|
|
40
90
|
* Returns the best matching locale or null.
|
|
@@ -53,5 +103,5 @@ declare function getLocaleRedirect({
|
|
|
53
103
|
}: LocaleRedirectOptions): string | undefined;
|
|
54
104
|
declare function resolvePagesI18nRequest(url: string, i18nConfig: NextI18nConfig, headers?: HeaderBag, hostname?: string | null, basePath?: string, trailingSlash?: boolean): PagesI18nRequestInfo;
|
|
55
105
|
//#endregion
|
|
56
|
-
export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, parseCookieLocaleFromHeader, resolvePagesI18nRequest };
|
|
106
|
+
export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
|
|
57
107
|
//# sourceMappingURL=pages-i18n.d.ts.map
|
|
@@ -9,6 +9,46 @@ function readHeader(headers, name) {
|
|
|
9
9
|
}
|
|
10
10
|
const normalizeHostname = normalizeDomainHostname;
|
|
11
11
|
/**
|
|
12
|
+
* Prepend the default locale prefix to a pathname when i18n is configured and
|
|
13
|
+
* the path does not already carry a locale prefix. Mirrors Next.js's
|
|
14
|
+
* server-side path normalisation in `resolve-routes.ts` (lines ~250-263):
|
|
15
|
+
*
|
|
16
|
+
* if (!initialLocaleResult.detectedLocale && !pathname.startsWith('/_next/')) {
|
|
17
|
+
* parsedUrl.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Run this **before** matching against `next.config.js` redirects/rewrites
|
|
21
|
+
* (which are emitted by `applyLocaleToRoutes` in locale-prefixed forms) so
|
|
22
|
+
* that requests arriving without a locale prefix still match those rules.
|
|
23
|
+
*
|
|
24
|
+
* Skips internal paths that Next.js leaves alone:
|
|
25
|
+
* - `/_next/*` (build assets, prerender manifests, image optimisation)
|
|
26
|
+
* - `/__vinext/*` (vinext-internal endpoints)
|
|
27
|
+
*
|
|
28
|
+
* Returns the input unchanged when i18n is not configured or when the path
|
|
29
|
+
* already starts with one of the configured locales. The host-based default
|
|
30
|
+
* locale (i18n.domains[].defaultLocale) is preferred over the global default
|
|
31
|
+
* when supplied, matching Next.js's `domainLocale.defaultLocale` branch.
|
|
32
|
+
*
|
|
33
|
+
* Item 4 of issue #1336: without this normalisation, requests like
|
|
34
|
+
* `/to-sv` (default locale = en) against a rule `source: '/:locale/to-sv'`
|
|
35
|
+
* with `locale: false` do not match because there is no segment for
|
|
36
|
+
* `:locale`. After normalisation the request looks like `/en/to-sv` and
|
|
37
|
+
* the rule matches with `:locale=en`.
|
|
38
|
+
*
|
|
39
|
+
* Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
|
|
40
|
+
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
|
|
41
|
+
*/
|
|
42
|
+
function normalizeDefaultLocalePathname(pathname, i18n, options = {}) {
|
|
43
|
+
if (!i18n) return pathname;
|
|
44
|
+
if (pathname.startsWith("/_next/") || pathname.startsWith("/__vinext/")) return pathname;
|
|
45
|
+
const parts = pathname.split("/", 3);
|
|
46
|
+
if (parts[1] && i18n.locales.includes(parts[1])) return pathname;
|
|
47
|
+
const defaultLocale = detectDomainLocale(i18n.domains, options.hostname ?? void 0)?.defaultLocale ?? i18n.defaultLocale;
|
|
48
|
+
if (pathname === "/") return `/${defaultLocale}`;
|
|
49
|
+
return `/${defaultLocale}${pathname}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
12
52
|
* Extract locale prefix from a URL path.
|
|
13
53
|
* e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
|
|
14
54
|
* /about -> { locale: defaultLocale, url: "/about", hadPrefix: false }
|
|
@@ -28,6 +68,26 @@ function extractLocaleFromUrl(url, i18nConfig, defaultLocale = i18nConfig.defaul
|
|
|
28
68
|
};
|
|
29
69
|
}
|
|
30
70
|
/**
|
|
71
|
+
* Strip a leading i18n locale segment from a URL so the result can be used for
|
|
72
|
+
* API route matching. Mirrors Next.js's base-server behaviour for Pages
|
|
73
|
+
* Router API routes: `normalizeLocalePath(pathname, i18n.locales).pathname`
|
|
74
|
+
* runs before the `/api/*` check so `/fr/api/ok` resolves to the
|
|
75
|
+
* `pages/api/ok` handler instead of 404'ing.
|
|
76
|
+
*
|
|
77
|
+
* Returns the original URL untouched when:
|
|
78
|
+
* - `i18nConfig` is null/undefined (no i18n configured)
|
|
79
|
+
* - the URL does not start with a configured locale
|
|
80
|
+
*
|
|
81
|
+
* The query string is preserved verbatim — only the path segment is stripped.
|
|
82
|
+
*
|
|
83
|
+
* Reference: packages/next/src/shared/lib/i18n/normalize-locale-path.ts.
|
|
84
|
+
*/
|
|
85
|
+
function stripI18nLocaleForApiRoute(url, i18nConfig) {
|
|
86
|
+
if (!i18nConfig) return url;
|
|
87
|
+
const { url: stripped, hadPrefix } = extractLocaleFromUrl(url, i18nConfig);
|
|
88
|
+
return hadPrefix ? stripped : url;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
31
91
|
* Detect the preferred locale from the Accept-Language header.
|
|
32
92
|
* Returns the best matching locale or null.
|
|
33
93
|
*/
|
|
@@ -120,6 +180,6 @@ function resolvePagesI18nRequest(url, i18nConfig, headers, hostname, basePath =
|
|
|
120
180
|
};
|
|
121
181
|
}
|
|
122
182
|
//#endregion
|
|
123
|
-
export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, parseCookieLocaleFromHeader, resolvePagesI18nRequest };
|
|
183
|
+
export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
|
|
124
184
|
|
|
125
185
|
//# sourceMappingURL=pages-i18n.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages-i18n.js","names":[],"sources":["../../src/server/pages-i18n.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport {\n detectDomainLocale,\n normalizeDomainHostname,\n type DomainLocale,\n} from \"../utils/domain-locale.js\";\n\ntype HeaderValue = string | string[] | undefined;\ntype HeaderBag = Headers | Record<string, HeaderValue> | undefined;\n\ntype LocaleRedirectOptions = {\n headers?: HeaderBag;\n nextConfig: {\n basePath?: string;\n i18n?: NextI18nConfig | null;\n trailingSlash?: boolean;\n };\n pathLocale?: string;\n urlParsed: {\n hostname?: string | null;\n pathname: string;\n search?: string;\n };\n};\n\ntype PagesI18nRequestInfo = {\n locale: string;\n url: string;\n hadPrefix: boolean;\n domainLocale?: DomainLocale;\n redirectUrl?: string;\n};\n\nfunction readHeader(headers: HeaderBag, name: string): string | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined;\n }\n\n // For Record headers, callers must pass lowercase names. Node's\n // IncomingMessage.headers are already lowercased by the HTTP parser.\n const direct = headers[name];\n if (Array.isArray(direct)) return direct.join(\", \");\n return direct;\n}\n\nconst normalizeHostname = normalizeDomainHostname;\nexport { detectDomainLocale };\n\n/**\n * Extract locale prefix from a URL path.\n * e.g. /fr/about -> { locale: \"fr\", url: \"/about\", hadPrefix: true }\n * /about -> { locale: defaultLocale, url: \"/about\", hadPrefix: false }\n */\nexport function extractLocaleFromUrl(\n url: string,\n i18nConfig: NextI18nConfig,\n defaultLocale = i18nConfig.defaultLocale,\n): { locale: string; url: string; hadPrefix: boolean } {\n const pathname = url.split(\"?\")[0];\n const parts = pathname.split(\"/\").filter(Boolean);\n const query = url.includes(\"?\") ? url.slice(url.indexOf(\"?\")) : \"\";\n\n if (parts.length > 0 && i18nConfig.locales.includes(parts[0])) {\n const locale = parts[0];\n const rest = \"/\" + parts.slice(1).join(\"/\");\n return { locale, url: (rest || \"/\") + query, hadPrefix: true };\n }\n\n return { locale: defaultLocale, url, hadPrefix: false };\n}\n\n/**\n * Detect the preferred locale from the Accept-Language header.\n * Returns the best matching locale or null.\n */\nexport function detectLocaleFromAcceptLanguage(\n acceptLang: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!acceptLang) return null;\n\n const langs = acceptLang\n .split(\",\")\n .map((part) => {\n const [lang, qPart] = part.trim().split(\";\");\n const q = qPart ? parseFloat(qPart.replace(\"q=\", \"\")) : 1;\n return { lang: lang.trim().toLowerCase(), q };\n })\n .sort((a, b) => b.q - a.q);\n\n for (const { lang } of langs) {\n const exactMatch = i18nConfig.locales.find((locale) => locale.toLowerCase() === lang);\n if (exactMatch) return exactMatch;\n\n const prefix = lang.split(\"-\")[0];\n const prefixMatch = i18nConfig.locales.find((locale) => {\n const lowered = locale.toLowerCase();\n return lowered === prefix || lowered.startsWith(prefix + \"-\");\n });\n if (prefixMatch) return prefixMatch;\n }\n\n return null;\n}\n\n/**\n * Parse the NEXT_LOCALE cookie.\n * Returns the cookie value if it matches a configured locale, otherwise null.\n */\nexport function parseCookieLocaleFromHeader(\n cookieHeader: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!cookieHeader) return null;\n\n const match = cookieHeader.match(/(?:^|;\\s*)NEXT_LOCALE=([^;]*)/);\n if (!match) return null;\n\n let value: string;\n try {\n value = decodeURIComponent(match[1].trim());\n } catch {\n return null;\n }\n\n if (i18nConfig.locales.includes(value)) return value;\n return null;\n}\n\nfunction formatLocalizedRootPath(\n locale: string,\n defaultLocale: string,\n basePath = \"\",\n trailingSlash = false,\n search = \"\",\n): string | undefined {\n if (locale.toLowerCase() === defaultLocale.toLowerCase()) return undefined;\n const rootPath = `${basePath}/${locale}${trailingSlash ? \"/\" : \"\"}`;\n return `${rootPath.replace(/\\/{2,}/g, \"/\")}${search}`;\n}\n\nexport function getLocaleRedirect({\n headers,\n nextConfig,\n pathLocale,\n urlParsed,\n}: LocaleRedirectOptions): string | undefined {\n const i18n = nextConfig.i18n;\n // Next.js treats localeDetection as the global auto-redirect switch, so\n // disabling it also disables root domain-locale redirects, including\n // cross-domain redirects driven by the current host or Accept-Language.\n if (!i18n || i18n.localeDetection === false || urlParsed.pathname !== \"/\") return undefined;\n\n const domainLocale = detectDomainLocale(i18n.domains, urlParsed.hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18n.defaultLocale;\n const preferredLocale =\n detectLocaleFromAcceptLanguage(readHeader(headers, \"accept-language\"), i18n) ?? undefined;\n const detectedLocale =\n pathLocale ||\n domainLocale?.defaultLocale ||\n (parseCookieLocaleFromHeader(readHeader(headers, \"cookie\"), i18n) ?? undefined) ||\n preferredLocale ||\n i18n.defaultLocale;\n const search = urlParsed.search ?? \"\";\n\n const preferredDomain = detectDomainLocale(i18n.domains, undefined, preferredLocale);\n if (domainLocale && preferredDomain) {\n const sameDomain =\n normalizeHostname(domainLocale.domain) === normalizeHostname(preferredDomain.domain);\n const sameLocale =\n preferredLocale !== undefined &&\n preferredDomain.defaultLocale.toLowerCase() === preferredLocale.toLowerCase();\n\n if (!sameDomain || !sameLocale) {\n // sameDomain && !sameLocale yields a locale-prefixed redirect on the same\n // host (for example /nl-BE). This matches Next.js and doesn't loop because\n // the next request is prefixed and therefore skips getLocaleRedirect().\n const scheme = `http${preferredDomain.http ? \"\" : \"s\"}`;\n const localePath = sameLocale || preferredLocale === undefined ? \"\" : `/${preferredLocale}`;\n const basePath = nextConfig.basePath ?? \"\";\n const rootPath = `${basePath}${localePath}${nextConfig.trailingSlash ? \"/\" : \"\"}` || \"/\";\n const normalizedPath = rootPath.startsWith(\"/\") ? rootPath : `/${rootPath}`;\n return `${scheme}://${preferredDomain.domain}${normalizedPath}${search}`;\n }\n }\n\n return formatLocalizedRootPath(\n detectedLocale,\n defaultLocale,\n nextConfig.basePath,\n nextConfig.trailingSlash,\n search,\n );\n}\n\nexport function resolvePagesI18nRequest(\n url: string,\n i18nConfig: NextI18nConfig,\n headers?: HeaderBag,\n hostname?: string | null,\n basePath = \"\",\n trailingSlash = false,\n): PagesI18nRequestInfo {\n const domainLocale = detectDomainLocale(i18nConfig.domains, hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18nConfig.defaultLocale;\n const localeInfo = extractLocaleFromUrl(url, i18nConfig, defaultLocale);\n\n let redirectUrl: string | undefined;\n if (!localeInfo.hadPrefix) {\n redirectUrl = getLocaleRedirect({\n headers,\n nextConfig: {\n basePath,\n i18n: i18nConfig,\n trailingSlash,\n },\n urlParsed: {\n hostname,\n pathname: localeInfo.url.split(\"?\")[0] || \"/\",\n search: localeInfo.url.includes(\"?\")\n ? localeInfo.url.slice(localeInfo.url.indexOf(\"?\"))\n : \"\",\n },\n });\n }\n\n return {\n ...localeInfo,\n domainLocale,\n redirectUrl,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pages-i18n.js","names":[],"sources":["../../src/server/pages-i18n.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport {\n detectDomainLocale,\n normalizeDomainHostname,\n type DomainLocale,\n} from \"../utils/domain-locale.js\";\n\ntype HeaderValue = string | string[] | undefined;\ntype HeaderBag = Headers | Record<string, HeaderValue> | undefined;\n\ntype LocaleRedirectOptions = {\n headers?: HeaderBag;\n nextConfig: {\n basePath?: string;\n i18n?: NextI18nConfig | null;\n trailingSlash?: boolean;\n };\n pathLocale?: string;\n urlParsed: {\n hostname?: string | null;\n pathname: string;\n search?: string;\n };\n};\n\ntype PagesI18nRequestInfo = {\n locale: string;\n url: string;\n hadPrefix: boolean;\n domainLocale?: DomainLocale;\n redirectUrl?: string;\n};\n\nfunction readHeader(headers: HeaderBag, name: string): string | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined;\n }\n\n // For Record headers, callers must pass lowercase names. Node's\n // IncomingMessage.headers are already lowercased by the HTTP parser.\n const direct = headers[name];\n if (Array.isArray(direct)) return direct.join(\", \");\n return direct;\n}\n\nconst normalizeHostname = normalizeDomainHostname;\nexport { detectDomainLocale };\n\n/**\n * Prepend the default locale prefix to a pathname when i18n is configured and\n * the path does not already carry a locale prefix. Mirrors Next.js's\n * server-side path normalisation in `resolve-routes.ts` (lines ~250-263):\n *\n * if (!initialLocaleResult.detectedLocale && !pathname.startsWith('/_next/')) {\n * parsedUrl.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`\n * }\n *\n * Run this **before** matching against `next.config.js` redirects/rewrites\n * (which are emitted by `applyLocaleToRoutes` in locale-prefixed forms) so\n * that requests arriving without a locale prefix still match those rules.\n *\n * Skips internal paths that Next.js leaves alone:\n * - `/_next/*` (build assets, prerender manifests, image optimisation)\n * - `/__vinext/*` (vinext-internal endpoints)\n *\n * Returns the input unchanged when i18n is not configured or when the path\n * already starts with one of the configured locales. The host-based default\n * locale (i18n.domains[].defaultLocale) is preferred over the global default\n * when supplied, matching Next.js's `domainLocale.defaultLocale` branch.\n *\n * Item 4 of issue #1336: without this normalisation, requests like\n * `/to-sv` (default locale = en) against a rule `source: '/:locale/to-sv'`\n * with `locale: false` do not match because there is no segment for\n * `:locale`. After normalisation the request looks like `/en/to-sv` and\n * the rule matches with `:locale=en`.\n *\n * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts\n */\nexport function normalizeDefaultLocalePathname(\n pathname: string,\n i18n: NextI18nConfig | null | undefined,\n options: { hostname?: string | null } = {},\n): string {\n if (!i18n) return pathname;\n // Don't touch internal paths.\n if (pathname.startsWith(\"/_next/\") || pathname.startsWith(\"/__vinext/\")) return pathname;\n // If the path already starts with a known locale, leave it alone.\n const parts = pathname.split(\"/\", 3);\n // parts[0] is the empty string before the leading \"/\", parts[1] is the first segment.\n if (parts[1] && i18n.locales.includes(parts[1])) return pathname;\n\n // Pick the default locale: prefer the domain-mapped one when host matches.\n const domainLocale = detectDomainLocale(i18n.domains, options.hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale ?? i18n.defaultLocale;\n\n if (pathname === \"/\") return `/${defaultLocale}`;\n return `/${defaultLocale}${pathname}`;\n}\n\n/**\n * Extract locale prefix from a URL path.\n * e.g. /fr/about -> { locale: \"fr\", url: \"/about\", hadPrefix: true }\n * /about -> { locale: defaultLocale, url: \"/about\", hadPrefix: false }\n */\nexport function extractLocaleFromUrl(\n url: string,\n i18nConfig: NextI18nConfig,\n defaultLocale = i18nConfig.defaultLocale,\n): { locale: string; url: string; hadPrefix: boolean } {\n const pathname = url.split(\"?\")[0];\n const parts = pathname.split(\"/\").filter(Boolean);\n const query = url.includes(\"?\") ? url.slice(url.indexOf(\"?\")) : \"\";\n\n if (parts.length > 0 && i18nConfig.locales.includes(parts[0])) {\n const locale = parts[0];\n const rest = \"/\" + parts.slice(1).join(\"/\");\n return { locale, url: (rest || \"/\") + query, hadPrefix: true };\n }\n\n return { locale: defaultLocale, url, hadPrefix: false };\n}\n\n/**\n * Strip a leading i18n locale segment from a URL so the result can be used for\n * API route matching. Mirrors Next.js's base-server behaviour for Pages\n * Router API routes: `normalizeLocalePath(pathname, i18n.locales).pathname`\n * runs before the `/api/*` check so `/fr/api/ok` resolves to the\n * `pages/api/ok` handler instead of 404'ing.\n *\n * Returns the original URL untouched when:\n * - `i18nConfig` is null/undefined (no i18n configured)\n * - the URL does not start with a configured locale\n *\n * The query string is preserved verbatim — only the path segment is stripped.\n *\n * Reference: packages/next/src/shared/lib/i18n/normalize-locale-path.ts.\n */\nexport function stripI18nLocaleForApiRoute(\n url: string,\n i18nConfig: NextI18nConfig | null | undefined,\n): string {\n if (!i18nConfig) return url;\n const { url: stripped, hadPrefix } = extractLocaleFromUrl(url, i18nConfig);\n return hadPrefix ? stripped : url;\n}\n\n/**\n * Detect the preferred locale from the Accept-Language header.\n * Returns the best matching locale or null.\n */\nexport function detectLocaleFromAcceptLanguage(\n acceptLang: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!acceptLang) return null;\n\n const langs = acceptLang\n .split(\",\")\n .map((part) => {\n const [lang, qPart] = part.trim().split(\";\");\n const q = qPart ? parseFloat(qPart.replace(\"q=\", \"\")) : 1;\n return { lang: lang.trim().toLowerCase(), q };\n })\n .sort((a, b) => b.q - a.q);\n\n for (const { lang } of langs) {\n const exactMatch = i18nConfig.locales.find((locale) => locale.toLowerCase() === lang);\n if (exactMatch) return exactMatch;\n\n const prefix = lang.split(\"-\")[0];\n const prefixMatch = i18nConfig.locales.find((locale) => {\n const lowered = locale.toLowerCase();\n return lowered === prefix || lowered.startsWith(prefix + \"-\");\n });\n if (prefixMatch) return prefixMatch;\n }\n\n return null;\n}\n\n/**\n * Parse the NEXT_LOCALE cookie.\n * Returns the cookie value if it matches a configured locale, otherwise null.\n */\nexport function parseCookieLocaleFromHeader(\n cookieHeader: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!cookieHeader) return null;\n\n const match = cookieHeader.match(/(?:^|;\\s*)NEXT_LOCALE=([^;]*)/);\n if (!match) return null;\n\n let value: string;\n try {\n value = decodeURIComponent(match[1].trim());\n } catch {\n return null;\n }\n\n if (i18nConfig.locales.includes(value)) return value;\n return null;\n}\n\nfunction formatLocalizedRootPath(\n locale: string,\n defaultLocale: string,\n basePath = \"\",\n trailingSlash = false,\n search = \"\",\n): string | undefined {\n if (locale.toLowerCase() === defaultLocale.toLowerCase()) return undefined;\n const rootPath = `${basePath}/${locale}${trailingSlash ? \"/\" : \"\"}`;\n return `${rootPath.replace(/\\/{2,}/g, \"/\")}${search}`;\n}\n\nexport function getLocaleRedirect({\n headers,\n nextConfig,\n pathLocale,\n urlParsed,\n}: LocaleRedirectOptions): string | undefined {\n const i18n = nextConfig.i18n;\n // Next.js treats localeDetection as the global auto-redirect switch, so\n // disabling it also disables root domain-locale redirects, including\n // cross-domain redirects driven by the current host or Accept-Language.\n if (!i18n || i18n.localeDetection === false || urlParsed.pathname !== \"/\") return undefined;\n\n const domainLocale = detectDomainLocale(i18n.domains, urlParsed.hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18n.defaultLocale;\n const preferredLocale =\n detectLocaleFromAcceptLanguage(readHeader(headers, \"accept-language\"), i18n) ?? undefined;\n const detectedLocale =\n pathLocale ||\n domainLocale?.defaultLocale ||\n (parseCookieLocaleFromHeader(readHeader(headers, \"cookie\"), i18n) ?? undefined) ||\n preferredLocale ||\n i18n.defaultLocale;\n const search = urlParsed.search ?? \"\";\n\n const preferredDomain = detectDomainLocale(i18n.domains, undefined, preferredLocale);\n if (domainLocale && preferredDomain) {\n const sameDomain =\n normalizeHostname(domainLocale.domain) === normalizeHostname(preferredDomain.domain);\n const sameLocale =\n preferredLocale !== undefined &&\n preferredDomain.defaultLocale.toLowerCase() === preferredLocale.toLowerCase();\n\n if (!sameDomain || !sameLocale) {\n // sameDomain && !sameLocale yields a locale-prefixed redirect on the same\n // host (for example /nl-BE). This matches Next.js and doesn't loop because\n // the next request is prefixed and therefore skips getLocaleRedirect().\n const scheme = `http${preferredDomain.http ? \"\" : \"s\"}`;\n const localePath = sameLocale || preferredLocale === undefined ? \"\" : `/${preferredLocale}`;\n const basePath = nextConfig.basePath ?? \"\";\n const rootPath = `${basePath}${localePath}${nextConfig.trailingSlash ? \"/\" : \"\"}` || \"/\";\n const normalizedPath = rootPath.startsWith(\"/\") ? rootPath : `/${rootPath}`;\n return `${scheme}://${preferredDomain.domain}${normalizedPath}${search}`;\n }\n }\n\n return formatLocalizedRootPath(\n detectedLocale,\n defaultLocale,\n nextConfig.basePath,\n nextConfig.trailingSlash,\n search,\n );\n}\n\nexport function resolvePagesI18nRequest(\n url: string,\n i18nConfig: NextI18nConfig,\n headers?: HeaderBag,\n hostname?: string | null,\n basePath = \"\",\n trailingSlash = false,\n): PagesI18nRequestInfo {\n const domainLocale = detectDomainLocale(i18nConfig.domains, hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18nConfig.defaultLocale;\n const localeInfo = extractLocaleFromUrl(url, i18nConfig, defaultLocale);\n\n let redirectUrl: string | undefined;\n if (!localeInfo.hadPrefix) {\n redirectUrl = getLocaleRedirect({\n headers,\n nextConfig: {\n basePath,\n i18n: i18nConfig,\n trailingSlash,\n },\n urlParsed: {\n hostname,\n pathname: localeInfo.url.split(\"?\")[0] || \"/\",\n search: localeInfo.url.includes(\"?\")\n ? localeInfo.url.slice(localeInfo.url.indexOf(\"?\"))\n : \"\",\n },\n });\n }\n\n return {\n ...localeInfo,\n domainLocale,\n redirectUrl,\n };\n}\n"],"mappings":"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"}
|