vinext 0.0.51 → 0.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/build/clean-output.d.ts +14 -0
- package/dist/build/clean-output.js +36 -0
- package/dist/build/clean-output.js.map +1 -0
- package/dist/build/precompress.d.ts +7 -7
- package/dist/build/precompress.js +18 -17
- package/dist/build/precompress.js.map +1 -1
- package/dist/build/prerender.d.ts +9 -16
- package/dist/build/prerender.js +88 -50
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/run-prerender.js +10 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/static-export.d.ts +5 -0
- package/dist/build/static-export.js +8 -3
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.js +4 -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 +58 -4
- package/dist/cli.js.map +1 -1
- package/dist/client/instrumentation-client-inject.d.ts +34 -0
- package/dist/client/instrumentation-client-inject.js +57 -0
- package/dist/client/instrumentation-client-inject.js.map +1 -0
- package/dist/client/navigation-runtime.d.ts +60 -0
- package/dist/client/navigation-runtime.js +171 -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 +14 -3
- 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 +10 -2
- 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/cloudflare/tpr.js +1 -1
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.d.ts +63 -16
- package/dist/config/config-matchers.js +145 -9
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +32 -5
- package/dist/config/next-config.js +55 -15
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +130 -46
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.js +9 -3
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +4 -2
- package/dist/entries/app-rsc-entry.js +76 -16
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +1 -0
- package/dist/entries/app-rsc-manifest.js +53 -6
- 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 +40 -3
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +261 -31
- 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 +161 -46
- package/dist/index.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.js +30 -5
- 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/strip-server-exports.js +5 -8
- package/dist/plugins/strip-server-exports.js.map +1 -1
- package/dist/routing/app-route-graph.d.ts +20 -1
- package/dist/routing/app-route-graph.js +58 -6
- 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-trie.js +13 -18
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/utils.d.ts +12 -1
- package/dist/routing/utils.js +18 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js +153 -42
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-action-result.d.ts +16 -1
- package/dist/server/app-browser-action-result.js +15 -1
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +309 -155
- package/dist/server/app-browser-entry.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 +3 -1
- package/dist/server/app-browser-navigation-controller.js +5 -1
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-rsc-redirect.d.ts +2 -1
- package/dist/server/app-browser-rsc-redirect.js +2 -2
- package/dist/server/app-browser-rsc-redirect.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +18 -1
- package/dist/server/app-browser-state.js +19 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-stream.d.ts +5 -14
- package/dist/server/app-browser-stream.js +13 -7
- package/dist/server/app-browser-stream.js.map +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +2 -1
- package/dist/server/app-browser-visible-commit.js +1 -0
- package/dist/server/app-browser-visible-commit.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +10 -5
- package/dist/server/app-elements-wire.js +84 -2
- 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 +12 -3
- package/dist/server/app-fallback-renderer.js +15 -8
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-history-state.js +6 -2
- package/dist/server/app-history-state.js.map +1 -1
- package/dist/server/app-interception-context-header.d.ts +33 -0
- package/dist/server/app-interception-context-header.js +44 -0
- package/dist/server/app-interception-context-header.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-mounted-slots-header.d.ts +19 -0
- package/dist/server/app-mounted-slots-header.js +40 -1
- package/dist/server/app-mounted-slots-header.js.map +1 -1
- package/dist/server/app-optimistic-routing.d.ts +54 -0
- package/dist/server/app-optimistic-routing.js +208 -0
- package/dist/server/app-optimistic-routing.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +2 -0
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +1 -0
- package/dist/server/app-page-boundary.js +2 -0
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +15 -1
- package/dist/server/app-page-cache.js +68 -7
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +5 -0
- package/dist/server/app-page-dispatch.js +39 -5
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +2 -1
- package/dist/server/app-page-element-builder.js +7 -3
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +29 -1
- package/dist/server/app-page-execution.js +91 -4
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +1 -0
- package/dist/server/app-page-head.js +29 -2
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-probe.js +1 -1
- package/dist/server/app-page-render-observation.js +1 -1
- package/dist/server/app-page-render.d.ts +3 -0
- package/dist/server/app-page-render.js +7 -3
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-response.d.ts +11 -1
- package/dist/server/app-page-response.js +18 -5
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +1 -0
- package/dist/server/app-page-route-wiring.js +35 -15
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +4 -0
- package/dist/server/app-page-stream.js +3 -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 +7 -1
- package/dist/server/app-route-handler-dispatch.js +4 -1
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-execution.d.ts +18 -2
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.js +6 -5
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-router-entry.js +6 -2
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +11 -1
- package/dist/server/app-rsc-handler.js +48 -21
- 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 +6 -2
- 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.js +2 -2
- package/dist/server/app-rsc-route-matching.js.map +1 -1
- package/dist/server/app-segment-config.d.ts +4 -1
- package/dist/server/app-segment-config.js +6 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +5 -1
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +92 -55
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +30 -2
- package/dist/server/app-ssr-stream.js +95 -8
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +2 -1
- package/dist/server/app-static-generation.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +1 -1
- 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 +49 -3
- package/dist/server/cache-proof.js +78 -22
- 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/default-not-found-module.d.ts +20 -0
- package/dist/server/default-not-found-module.js +20 -0
- package/dist/server/default-not-found-module.js.map +1 -0
- package/dist/server/dev-server.d.ts +10 -2
- package/dist/server/dev-server.js +99 -36
- 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/headers.d.ts +22 -1
- package/dist/server/headers.js +22 -1
- package/dist/server/headers.js.map +1 -1
- package/dist/server/http-error-responses.d.ts +16 -1
- package/dist/server/http-error-responses.js +21 -1
- package/dist/server/http-error-responses.js.map +1 -1
- package/dist/server/image-optimization.d.ts +13 -4
- package/dist/server/image-optimization.js +15 -4
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/isr-cache.d.ts +6 -2
- package/dist/server/isr-cache.js +20 -4
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +15 -0
- package/dist/server/middleware-runtime.js +59 -7
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +5 -3
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/navigation-planner.d.ts +9 -3
- package/dist/server/navigation-planner.js +98 -25
- package/dist/server/navigation-planner.js.map +1 -1
- package/dist/server/navigation-trace.d.ts +2 -1
- package/dist/server/navigation-trace.js +1 -0
- package/dist/server/navigation-trace.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +45 -1
- package/dist/server/pages-api-route.js +27 -4
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-body-parser-config.d.ts +60 -0
- package/dist/server/pages-body-parser-config.js +79 -0
- package/dist/server/pages-body-parser-config.js.map +1 -0
- package/dist/server/pages-data-route.d.ts +77 -0
- package/dist/server/pages-data-route.js +98 -0
- package/dist/server/pages-data-route.js.map +1 -0
- package/dist/server/pages-default-404.d.ts +31 -0
- package/dist/server/pages-default-404.js +40 -0
- package/dist/server/pages-default-404.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-node-compat.d.ts +10 -0
- package/dist/server/pages-node-compat.js +12 -1
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +69 -2
- package/dist/server/pages-page-data.js +47 -31
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +13 -1
- package/dist/server/pages-page-response.js +16 -11
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prerender-route-params.d.ts +14 -0
- package/dist/server/prerender-route-params.js +94 -0
- package/dist/server/prerender-route-params.js.map +1 -0
- package/dist/server/prod-server.d.ts +15 -37
- package/dist/server/prod-server.js +143 -107
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/proxy-trust.d.ts +41 -0
- package/dist/server/proxy-trust.js +70 -0
- package/dist/server/proxy-trust.js.map +1 -0
- package/dist/server/request-pipeline.d.ts +13 -4
- package/dist/server/request-pipeline.js +32 -14
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/seed-cache.d.ts +12 -31
- package/dist/server/seed-cache.js +30 -37
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.js +8 -3
- package/dist/server/server-action-not-found.js.map +1 -1
- 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 +8 -7
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/server/streaming-metadata.d.ts +5 -0
- package/dist/server/streaming-metadata.js +10 -0
- package/dist/server/streaming-metadata.js.map +1 -0
- package/dist/shims/app-router-scroll-state.d.ts +12 -0
- package/dist/shims/app-router-scroll-state.js +38 -0
- package/dist/shims/app-router-scroll-state.js.map +1 -0
- package/dist/shims/app-router-scroll.d.ts +14 -0
- package/dist/shims/app-router-scroll.js +100 -0
- package/dist/shims/app-router-scroll.js.map +1 -0
- package/dist/shims/before-interactive-context.d.ts +30 -0
- package/dist/shims/before-interactive-context.js +10 -0
- package/dist/shims/before-interactive-context.js.map +1 -0
- package/dist/shims/cache-runtime.d.ts +1 -1
- package/dist/shims/cache-runtime.js +14 -1
- package/dist/shims/cache-runtime.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/default-not-found.d.ts +12 -0
- package/dist/shims/default-not-found.js +61 -0
- package/dist/shims/default-not-found.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/font-local.d.ts +5 -0
- package/dist/shims/font-local.js +6 -2
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/form.js +13 -6
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/head.js +4 -4
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +6 -2
- package/dist/shims/headers.js +64 -21
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.d.ts +1 -1
- package/dist/shims/image.js +4 -4
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/pages-data-target.d.ts +58 -0
- package/dist/shims/internal/pages-data-target.js +91 -0
- package/dist/shims/internal/pages-data-target.js.map +1 -0
- package/dist/shims/internal/pages-data-url.d.ts +42 -0
- package/dist/shims/internal/pages-data-url.js +73 -0
- package/dist/shims/internal/pages-data-url.js.map +1 -0
- package/dist/shims/link.d.ts +21 -3
- package/dist/shims/link.js +189 -30
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +2 -1
- package/dist/shims/metadata.js +65 -6
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +67 -23
- package/dist/shims/navigation.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/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 +12 -5
- package/dist/shims/router.js +535 -86
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.js +86 -12
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.d.ts +21 -4
- package/dist/shims/server.js +30 -9
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.js +5 -1
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +1 -1
- 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 +2 -1
- package/dist/shims/url-utils.js +15 -4
- 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 +33 -5
- package/dist/utils/asset-prefix.js +39 -6
- package/dist/utils/asset-prefix.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/html-limited-bots.d.ts +5 -0
- package/dist/utils/html-limited-bots.js +15 -0
- package/dist/utils/html-limited-bots.js.map +1 -0
- 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/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 +23 -1
- package/dist/utils/query.js +46 -2
- 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/package.json +11 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-utils.js","names":[],"sources":["../../src/shims/url-utils.ts"],"sourcesContent":["/**\n * Shared URL utilities for same-origin detection.\n *\n * Used by link.tsx, navigation.ts, and router.ts to normalize\n * same-origin absolute URLs to local paths for client-side navigation.\n */\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\n\n// Mirrors Next.js's absolute URL classification:\n// packages/next/src/shared/lib/utils.ts\nconst ABSOLUTE_URL_REGEX = /^[a-zA-Z][a-zA-Z\\d+\\-.]*?:/;\n\nexport function isAbsoluteUrl(url: string): boolean {\n const firstChar = url.charCodeAt(0);\n const startsWithLetter =\n (firstChar >= 65 && firstChar <= 90) || (firstChar >= 97 && firstChar <= 122);\n\n return startsWithLetter && ABSOLUTE_URL_REGEX.test(url);\n}\n\nexport function isAbsoluteOrProtocolRelativeUrl(url: string): boolean {\n return isAbsoluteUrl(url) || url.startsWith(\"//\");\n}\n\n/**\n * If `url` is an absolute same-origin URL, return the local path\n * (pathname + search + hash). Returns null for truly external URLs\n * or on the server (where origin is unknown).\n */\nexport function toSameOriginPath(url: string): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const parsed = url.startsWith(\"//\") ? new URL(url, window.location.origin) : new URL(url);\n if (parsed.origin === window.location.origin) {\n return parsed.pathname + parsed.search + parsed.hash;\n }\n } catch {\n // not a valid absolute URL — ignore\n }\n return null;\n}\n\n/**\n * If `url` is an absolute same-origin URL, return the app-relative path\n * (basePath stripped from the pathname, if configured). Returns null for\n * truly external URLs or on the server.\n */\nexport function toSameOriginAppPath(url: string, basePath: string): string | null {\n const localPath = toSameOriginPath(url);\n if (localPath == null || !basePath) return localPath;\n\n try {\n const parsed = new URL(localPath, \"http://vinext.local\");\n if (!hasBasePath(parsed.pathname, basePath)) {\n return null;\n }\n const pathname = stripBasePath(parsed.pathname, basePath);\n return pathname + parsed.search + parsed.hash;\n } catch {\n return localPath;\n }\n}\n\n/**\n * Split a path string into pathname, query, and hash without depending on\n * the URL constructor (which would resolve relative paths against an origin).\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/parse-path.ts\n */\nfunction parsePath(path: string): { pathname: string; query: string; hash: string } {\n const hashIndex = path.indexOf(\"#\");\n const queryIndex = path.indexOf(\"?\");\n const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex);\n\n if (hasQuery || hashIndex > -1) {\n return {\n pathname: path.substring(0, hasQuery ? queryIndex : hashIndex),\n query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : \"\",\n hash: hashIndex > -1 ? path.slice(hashIndex) : \"\",\n };\n }\n\n return { pathname: path, query: \"\", hash: \"\" };\n}\n\n/**\n * Drop trailing slashes from a route while preserving the bare root.\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/remove-trailing-slash.ts\n */\nfunction removeRouteTrailingSlash(route: string): string {\n return route.replace(/\\/$/, \"\") || \"/\";\n}\n\n/**\n * Normalise the trailing slash of a local URL according to the\n * `trailingSlash` config option in `next.config.js`. Used by the `<Link>`\n * shim so that rendered `href` attributes match the canonical URL form\n * (which is what the server-side redirect would otherwise enforce).\n *\n * Behaviour matches Next.js's client-side `normalizePathTrailingSlash`:\n * packages/next/src/client/normalize-trailing-slash.ts\n *\n * - Absolute URLs (`http://`, `https://`, `//`) and non-local strings are\n * returned unchanged.\n * - Paths whose final segment looks like a filename (`...\\.ext`) have any\n * trailing slash stripped even when `trailingSlash: true`, mirroring the\n * `.well-known`-aware redirect rule shipped in `routes-manifest.json`.\n * - Query strings and hash fragments are preserved verbatim.\n * - Idempotent: already-canonical paths round-trip unchanged.\n */\nexport function normalizePathTrailingSlash(path: string, trailingSlash: boolean): string {\n if (!path.startsWith(\"/\") || path.startsWith(\"//\")) {\n return path;\n }\n\n const { pathname, query, hash } = parsePath(path);\n\n if (trailingSlash) {\n if (/\\.[^/]+\\/?$/.test(pathname)) {\n // Looks like a filename — strip trailing slash even with trailingSlash: true.\n return `${removeRouteTrailingSlash(pathname)}${query}${hash}`;\n }\n if (pathname.endsWith(\"/\")) {\n return `${pathname}${query}${hash}`;\n }\n return `${pathname}/${query}${hash}`;\n }\n\n return `${removeRouteTrailingSlash(pathname)}${query}${hash}`;\n}\n\n/**\n * Prepend basePath to a local path for browser URLs / fetches.\n */\nexport function withBasePath(path: string, basePath: string): string {\n if (!basePath || !path.startsWith(\"/\") || isAbsoluteOrProtocolRelativeUrl(path)) {\n return path;\n }\n\n return basePath + path;\n}\n\n/**\n * Resolve a potentially relative href against the current URL.\n * Handles: \"#hash\", \"?query\", \"?query#hash\", and relative paths.\n */\nexport function resolveRelativeHref(href: string, currentUrl?: string, basePath = \"\"): string {\n const base = currentUrl ?? (typeof window !== \"undefined\" ? window.location.href : undefined);\n\n if (!base) return href;\n\n if (href.startsWith(\"/\") || isAbsoluteOrProtocolRelativeUrl(href)) {\n return href;\n }\n\n try {\n const resolved = new URL(href, base);\n const pathname =\n basePath && resolved.pathname === basePath\n ? \"\"\n : basePath\n ? stripBasePath(resolved.pathname, basePath)\n : resolved.pathname;\n return pathname + resolved.search + resolved.hash;\n } catch {\n return href;\n }\n}\n\n/**\n * Convert a local navigation target into the browser URL that should be used\n * for history entries, fetches, and onNavigate callbacks.\n */\nexport function toBrowserNavigationHref(href: string, currentUrl?: string, basePath = \"\"): string {\n const resolved = resolveRelativeHref(href, currentUrl, basePath);\n\n if (!basePath) {\n return withBasePath(resolved, basePath);\n }\n\n if (resolved === \"\") {\n return basePath;\n }\n\n if (resolved.startsWith(\"?\") || resolved.startsWith(\"#\")) {\n return basePath + resolved;\n }\n\n return withBasePath(resolved, basePath);\n}\n\nexport function isHashOnlyBrowserUrlChange(\n href: string,\n currentHref: string,\n basePath = \"\",\n): boolean {\n try {\n const current = new URL(currentHref);\n const next = new URL(href, currentHref);\n const currentPathname = stripBasePath(current.pathname, basePath);\n const nextPathname = stripBasePath(next.pathname, basePath);\n return currentPathname === nextPathname && current.search === next.search && next.hash !== \"\";\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"url-utils.js","names":[],"sources":["../../src/shims/url-utils.ts"],"sourcesContent":["/**\n * Shared URL utilities for same-origin detection.\n *\n * Used by link.tsx, navigation.ts, and router.ts to normalize\n * same-origin absolute URLs to local paths for client-side navigation.\n */\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\n\n// Mirrors Next.js's absolute URL classification:\n// packages/next/src/shared/lib/utils.ts\nconst ABSOLUTE_URL_REGEX = /^[a-zA-Z][a-zA-Z\\d+\\-.]*?:/;\n\nexport function isAbsoluteUrl(url: string): boolean {\n const firstChar = url.charCodeAt(0);\n const startsWithLetter =\n (firstChar >= 65 && firstChar <= 90) || (firstChar >= 97 && firstChar <= 122);\n\n return startsWithLetter && ABSOLUTE_URL_REGEX.test(url);\n}\n\nexport function isAbsoluteOrProtocolRelativeUrl(url: string): boolean {\n return isAbsoluteUrl(url) || url.startsWith(\"//\");\n}\n\nexport function getWindowOrigin(): string | null {\n if (typeof window === \"undefined\") return null;\n const { origin, href } = window.location;\n if (origin) return origin;\n try {\n return new URL(href).origin;\n } catch {\n return null;\n }\n}\n\n/**\n * If `url` is an absolute same-origin URL, return the local path\n * (pathname + search + hash). Returns null for truly external URLs\n * or on the server (where origin is unknown).\n */\nexport function toSameOriginPath(url: string): string | null {\n const origin = getWindowOrigin();\n if (!origin) return null;\n try {\n const parsed = url.startsWith(\"//\") ? new URL(url, origin) : new URL(url);\n if (parsed.origin === origin) {\n return parsed.pathname + parsed.search + parsed.hash;\n }\n } catch {\n // not a valid absolute URL — ignore\n }\n return null;\n}\n\n/**\n * If `url` is an absolute same-origin URL, return the app-relative path\n * (basePath stripped from the pathname, if configured). Returns null for\n * truly external URLs or on the server.\n */\nexport function toSameOriginAppPath(url: string, basePath: string): string | null {\n const localPath = toSameOriginPath(url);\n if (localPath == null || !basePath) return localPath;\n\n try {\n const parsed = new URL(localPath, \"http://vinext.local\");\n if (!hasBasePath(parsed.pathname, basePath)) {\n return null;\n }\n const pathname = stripBasePath(parsed.pathname, basePath);\n return pathname + parsed.search + parsed.hash;\n } catch {\n return localPath;\n }\n}\n\n/**\n * Split a path string into pathname, query, and hash without depending on\n * the URL constructor (which would resolve relative paths against an origin).\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/parse-path.ts\n */\nfunction parsePath(path: string): { pathname: string; query: string; hash: string } {\n const hashIndex = path.indexOf(\"#\");\n const queryIndex = path.indexOf(\"?\");\n const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex);\n\n if (hasQuery || hashIndex > -1) {\n return {\n pathname: path.substring(0, hasQuery ? queryIndex : hashIndex),\n query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : \"\",\n hash: hashIndex > -1 ? path.slice(hashIndex) : \"\",\n };\n }\n\n return { pathname: path, query: \"\", hash: \"\" };\n}\n\n/**\n * Drop trailing slashes from a route while preserving the bare root.\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/remove-trailing-slash.ts\n */\nfunction removeRouteTrailingSlash(route: string): string {\n return route.replace(/\\/$/, \"\") || \"/\";\n}\n\n/**\n * Normalise the trailing slash of a local URL according to the\n * `trailingSlash` config option in `next.config.js`. Used by the `<Link>`\n * shim so that rendered `href` attributes match the canonical URL form\n * (which is what the server-side redirect would otherwise enforce).\n *\n * Behaviour matches Next.js's client-side `normalizePathTrailingSlash`:\n * packages/next/src/client/normalize-trailing-slash.ts\n *\n * - Absolute URLs (`http://`, `https://`, `//`) and non-local strings are\n * returned unchanged.\n * - Paths whose final segment looks like a filename (`...\\.ext`) have any\n * trailing slash stripped even when `trailingSlash: true`, mirroring the\n * `.well-known`-aware redirect rule shipped in `routes-manifest.json`.\n * - Query strings and hash fragments are preserved verbatim.\n * - Idempotent: already-canonical paths round-trip unchanged.\n */\nexport function normalizePathTrailingSlash(path: string, trailingSlash: boolean): string {\n if (!path.startsWith(\"/\") || path.startsWith(\"//\")) {\n return path;\n }\n\n const { pathname, query, hash } = parsePath(path);\n\n if (trailingSlash) {\n if (/\\.[^/]+\\/?$/.test(pathname)) {\n // Looks like a filename — strip trailing slash even with trailingSlash: true.\n return `${removeRouteTrailingSlash(pathname)}${query}${hash}`;\n }\n if (pathname.endsWith(\"/\")) {\n return `${pathname}${query}${hash}`;\n }\n return `${pathname}/${query}${hash}`;\n }\n\n return `${removeRouteTrailingSlash(pathname)}${query}${hash}`;\n}\n\n/**\n * Prepend basePath to a local path for browser URLs / fetches.\n */\nexport function withBasePath(path: string, basePath: string): string {\n if (!basePath || !path.startsWith(\"/\") || isAbsoluteOrProtocolRelativeUrl(path)) {\n return path;\n }\n\n return basePath + path;\n}\n\n/**\n * Resolve a potentially relative href against the current URL.\n * Handles: \"#hash\", \"?query\", \"?query#hash\", and relative paths.\n */\nexport function resolveRelativeHref(href: string, currentUrl?: string, basePath = \"\"): string {\n const base = currentUrl ?? (typeof window !== \"undefined\" ? window.location.href : undefined);\n\n if (!base) return href;\n\n if (href.startsWith(\"/\") || isAbsoluteOrProtocolRelativeUrl(href)) {\n return href;\n }\n\n try {\n const resolved = new URL(href, base);\n const pathname =\n basePath && resolved.pathname === basePath\n ? \"\"\n : basePath\n ? stripBasePath(resolved.pathname, basePath)\n : resolved.pathname;\n return pathname + resolved.search + resolved.hash;\n } catch {\n return href;\n }\n}\n\n/**\n * Convert a local navigation target into the browser URL that should be used\n * for history entries, fetches, and onNavigate callbacks.\n */\nexport function toBrowserNavigationHref(href: string, currentUrl?: string, basePath = \"\"): string {\n const resolved = resolveRelativeHref(href, currentUrl, basePath);\n\n if (!basePath) {\n return withBasePath(resolved, basePath);\n }\n\n if (resolved === \"\") {\n return basePath;\n }\n\n if (resolved.startsWith(\"?\") || resolved.startsWith(\"#\")) {\n return basePath + resolved;\n }\n\n return withBasePath(resolved, basePath);\n}\n\nexport function isHashOnlyBrowserUrlChange(\n href: string,\n currentHref: string,\n basePath = \"\",\n): boolean {\n try {\n const current = new URL(currentHref);\n const next = new URL(href, currentHref);\n const currentPathname = stripBasePath(current.pathname, basePath);\n const nextPathname = stripBasePath(next.pathname, basePath);\n return currentPathname === nextPathname && current.search === next.search && next.hash !== \"\";\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/typegen.d.ts
|
|
2
|
+
type GenerateRouteTypesOptions = {
|
|
3
|
+
root: string;
|
|
4
|
+
appDir?: string | null;
|
|
5
|
+
pageExtensions?: readonly string[];
|
|
6
|
+
};
|
|
7
|
+
declare function generateRouteTypes(options: GenerateRouteTypesOptions): Promise<string>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { generateRouteTypes };
|
|
10
|
+
//# sourceMappingURL=typegen.d.ts.map
|
package/dist/typegen.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { decodeRouteSegment } from "./routing/utils.js";
|
|
2
|
+
import { patternToNextFormat } from "./routing/route-validation.js";
|
|
3
|
+
import { isInvisibleSegment } from "./routing/app-route-graph.js";
|
|
4
|
+
import { appRouteGraph } from "./routing/app-router.js";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
//#region src/typegen.ts
|
|
8
|
+
const NEXT_ENV_FILE_CONTENT = `/// <reference types="next" />
|
|
9
|
+
/// <reference types="next/image-types/global" />
|
|
10
|
+
import "./.next/types/routes.d.ts";
|
|
11
|
+
|
|
12
|
+
// NOTE: This file should not be edited
|
|
13
|
+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
|
14
|
+
`;
|
|
15
|
+
async function generateRouteTypes(options) {
|
|
16
|
+
const root = path.resolve(options.root);
|
|
17
|
+
const appDir = options.appDir ? path.resolve(options.appDir) : await findAppDir(root);
|
|
18
|
+
const outPath = path.join(root, ".next", "types", "routes.d.ts");
|
|
19
|
+
const content = appDir ? renderRouteTypes(await collectRouteTypeModel(appDir, options.pageExtensions)) : renderRouteTypes(emptyRouteTypeModel());
|
|
20
|
+
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
21
|
+
await fs.writeFile(outPath, content, "utf-8");
|
|
22
|
+
await ensureNextEnvFile(root);
|
|
23
|
+
return outPath;
|
|
24
|
+
}
|
|
25
|
+
async function ensureNextEnvFile(root) {
|
|
26
|
+
const envPath = path.join(root, "next-env.d.ts");
|
|
27
|
+
try {
|
|
28
|
+
await fs.writeFile(envPath, NEXT_ENV_FILE_CONTENT, {
|
|
29
|
+
encoding: "utf-8",
|
|
30
|
+
flag: "wx"
|
|
31
|
+
});
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error.code !== "EEXIST") throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function emptyRouteTypeModel() {
|
|
37
|
+
return {
|
|
38
|
+
pageRoutes: [],
|
|
39
|
+
layoutRoutes: [],
|
|
40
|
+
routeHandlerRoutes: [],
|
|
41
|
+
params: /* @__PURE__ */ new Map(),
|
|
42
|
+
layoutSlots: /* @__PURE__ */ new Map()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function collectRouteTypeModel(appDir, pageExtensions) {
|
|
46
|
+
const graph = await appRouteGraph(appDir, pageExtensions);
|
|
47
|
+
const model = emptyRouteTypeModel();
|
|
48
|
+
const segmentGraph = graph.routeManifest.segmentGraph;
|
|
49
|
+
const layoutRouteKeys = createLayoutRouteKeyMap(segmentGraph.layouts.values());
|
|
50
|
+
const pageRouteSet = /* @__PURE__ */ new Set();
|
|
51
|
+
const layoutRouteSet = /* @__PURE__ */ new Set();
|
|
52
|
+
const routeHandlerRouteSet = /* @__PURE__ */ new Set();
|
|
53
|
+
for (const route of segmentGraph.pages.values()) {
|
|
54
|
+
const routeEntry = segmentGraph.routes.get(route.routeId);
|
|
55
|
+
addRoute(model.pageRoutes, pageRouteSet, model.params, patternToNextFormat(route.pattern), paramsForPatternParts(routeEntry?.patternParts ?? []));
|
|
56
|
+
}
|
|
57
|
+
for (const route of segmentGraph.routeHandlers.values()) {
|
|
58
|
+
const routeEntry = segmentGraph.routes.get(route.routeId);
|
|
59
|
+
addRoute(model.routeHandlerRoutes, routeHandlerRouteSet, model.params, patternToNextFormat(route.pattern), paramsForPatternParts(routeEntry?.patternParts ?? []));
|
|
60
|
+
}
|
|
61
|
+
for (const layout of segmentGraph.layouts.values()) {
|
|
62
|
+
const route = layoutRouteKeys.get(layout.treePath) ?? treePathToRouteLiteral(layout.treePath);
|
|
63
|
+
addRoute(model.layoutRoutes, layoutRouteSet, model.params, route, paramsForPatternParts(layout.patternParts));
|
|
64
|
+
}
|
|
65
|
+
const layoutSlotSets = /* @__PURE__ */ new Map();
|
|
66
|
+
for (const slot of segmentGraph.slots.values()) {
|
|
67
|
+
const layoutRoute = layoutRouteKeyForSlot(slot, segmentGraph.layouts, layoutRouteKeys);
|
|
68
|
+
if (!layoutRoute) continue;
|
|
69
|
+
let slotNames = layoutSlotSets.get(layoutRoute);
|
|
70
|
+
if (!slotNames) {
|
|
71
|
+
slotNames = /* @__PURE__ */ new Set();
|
|
72
|
+
layoutSlotSets.set(layoutRoute, slotNames);
|
|
73
|
+
model.layoutSlots.set(layoutRoute, []);
|
|
74
|
+
}
|
|
75
|
+
if (!slotNames.has(slot.name)) {
|
|
76
|
+
slotNames.add(slot.name);
|
|
77
|
+
model.layoutSlots.get(layoutRoute)?.push(slot.name);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
model.pageRoutes.sort(compareStrings);
|
|
81
|
+
model.layoutRoutes.sort(compareStrings);
|
|
82
|
+
model.routeHandlerRoutes.sort(compareStrings);
|
|
83
|
+
for (const slotNames of model.layoutSlots.values()) slotNames.sort(compareStrings);
|
|
84
|
+
return model;
|
|
85
|
+
}
|
|
86
|
+
async function findAppDir(root) {
|
|
87
|
+
for (const rel of ["app", path.join("src", "app")]) {
|
|
88
|
+
const candidate = path.join(root, rel);
|
|
89
|
+
try {
|
|
90
|
+
if ((await fs.stat(candidate)).isDirectory()) return candidate;
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function renderRouteTypes(model) {
|
|
96
|
+
const allRoutes = uniqueSorted([
|
|
97
|
+
...model.pageRoutes,
|
|
98
|
+
...model.layoutRoutes,
|
|
99
|
+
...model.routeHandlerRoutes
|
|
100
|
+
]);
|
|
101
|
+
return `// This file is generated by vinext. Do not edit.
|
|
102
|
+
import type * as React from "react";
|
|
103
|
+
|
|
104
|
+
declare global {
|
|
105
|
+
type PageProps<Route extends VinextRouteTypes.PageRoute = VinextRouteTypes.PageRoute> = {
|
|
106
|
+
params: Promise<VinextRouteTypes.ParamMap[Route]>;
|
|
107
|
+
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
type LayoutProps<Route extends VinextRouteTypes.LayoutRoute> = {
|
|
111
|
+
params: Promise<VinextRouteTypes.ParamMap[Route]>;
|
|
112
|
+
children: React.ReactNode;
|
|
113
|
+
} & {
|
|
114
|
+
[K in VinextRouteTypes.LayoutSlotMap[Route]]: React.ReactNode;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
type RouteContext<Route extends VinextRouteTypes.RouteHandlerRoute = VinextRouteTypes.RouteHandlerRoute> = {
|
|
118
|
+
params: Promise<VinextRouteTypes.ParamMap[Route]>;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
declare namespace VinextRouteTypes {
|
|
123
|
+
type PageRoute = ${routeUnion(model.pageRoutes)};
|
|
124
|
+
type LayoutRoute = ${routeUnion(model.layoutRoutes)};
|
|
125
|
+
type RouteHandlerRoute = ${routeUnion(model.routeHandlerRoutes)};
|
|
126
|
+
type AppRoute = ${routeUnion(allRoutes)};
|
|
127
|
+
|
|
128
|
+
interface ParamMap {
|
|
129
|
+
${renderParamMap(allRoutes, model.params)}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface LayoutSlotMap {
|
|
133
|
+
${renderLayoutSlotMap(model.layoutRoutes, model.layoutSlots)}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export {};
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
function renderParamMap(routes, params) {
|
|
141
|
+
if (routes.length === 0) return " [route: string]: {};\n";
|
|
142
|
+
return routes.map((route) => ` ${quote(route)}: ${renderParamShape(params.get(route) ?? /* @__PURE__ */ new Map())};`).join("\n");
|
|
143
|
+
}
|
|
144
|
+
function renderParamShape(params) {
|
|
145
|
+
if (params.size === 0) return "{}";
|
|
146
|
+
return `{ ${Array.from(params.entries()).sort(([left], [right]) => compareStrings(left, right)).map(([name, kind]) => {
|
|
147
|
+
const optional = kind === "string[]?";
|
|
148
|
+
const valueType = optional ? "string[]" : kind;
|
|
149
|
+
return `${propertyName(name)}${optional ? "?" : ""}: ${valueType};`;
|
|
150
|
+
}).join(" ")} }`;
|
|
151
|
+
}
|
|
152
|
+
function renderLayoutSlotMap(layoutRoutes, layoutSlots) {
|
|
153
|
+
if (layoutRoutes.length === 0) return " [route: string]: never;\n";
|
|
154
|
+
return layoutRoutes.map((route) => {
|
|
155
|
+
const slots = layoutSlots.get(route) ?? [];
|
|
156
|
+
return ` ${quote(route)}: ${routeUnion(slots)};`;
|
|
157
|
+
}).join("\n");
|
|
158
|
+
}
|
|
159
|
+
function paramsForPatternParts(patternParts) {
|
|
160
|
+
const params = /* @__PURE__ */ new Map();
|
|
161
|
+
for (const part of patternParts) {
|
|
162
|
+
if (!part.startsWith(":")) continue;
|
|
163
|
+
if (part.endsWith("+")) params.set(part.slice(1, -1), "string[]");
|
|
164
|
+
else if (part.endsWith("*")) params.set(part.slice(1, -1), "string[]?");
|
|
165
|
+
else params.set(part.slice(1), "string");
|
|
166
|
+
}
|
|
167
|
+
return params;
|
|
168
|
+
}
|
|
169
|
+
function createLayoutRouteKeyMap(layouts) {
|
|
170
|
+
const treePathsByRoute = /* @__PURE__ */ new Map();
|
|
171
|
+
for (const { treePath } of layouts) {
|
|
172
|
+
const route = treePathToRouteLiteral(treePath);
|
|
173
|
+
const treePaths = treePathsByRoute.get(route) ?? [];
|
|
174
|
+
treePaths.push(treePath);
|
|
175
|
+
treePathsByRoute.set(route, treePaths);
|
|
176
|
+
}
|
|
177
|
+
const keys = /* @__PURE__ */ new Map();
|
|
178
|
+
for (const [route, treePaths] of treePathsByRoute) for (const treePath of treePaths) keys.set(treePath, treePaths.length === 1 ? route : treePathToScopedLayoutRouteLiteral(treePath));
|
|
179
|
+
return keys;
|
|
180
|
+
}
|
|
181
|
+
function layoutRouteKeyForSlot(slot, layouts, layoutRouteKeys) {
|
|
182
|
+
if (!slot.ownerLayoutId) return null;
|
|
183
|
+
const layout = layouts.get(slot.ownerLayoutId);
|
|
184
|
+
if (!layout) throw new Error(`[vinext] App route graph invariant violated: slot ${slot.id} references missing owner layout ${slot.ownerLayoutId}`);
|
|
185
|
+
return layoutRouteKeys.get(layout.treePath) ?? treePathToRouteLiteral(layout.treePath);
|
|
186
|
+
}
|
|
187
|
+
/** Convert a layout tree path to its URL route literal, stripping invisible segments. */
|
|
188
|
+
function treePathToRouteLiteral(treePath) {
|
|
189
|
+
if (treePath === "/") return "/";
|
|
190
|
+
const segments = treePath.split("/").filter(Boolean).filter((segment) => !isInvisibleSegment(segment)).map((segment) => decodeRouteSegment(segment));
|
|
191
|
+
return segments.length === 0 ? "/" : `/${segments.join("/")}`;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Convert a layout tree path to a scoped route literal that preserves
|
|
195
|
+
* route-group and `@slot` segments. Used only as a fallback key when multiple
|
|
196
|
+
* layouts collapse to the same URL route literal, so consumers can keep their
|
|
197
|
+
* slot/params typings distinct.
|
|
198
|
+
*/
|
|
199
|
+
function treePathToScopedLayoutRouteLiteral(treePath) {
|
|
200
|
+
if (treePath === "/") return "/";
|
|
201
|
+
const segments = treePath.split("/").filter(Boolean).filter((segment) => segment !== ".").map((segment) => decodeRouteSegment(segment));
|
|
202
|
+
return segments.length === 0 ? "/" : `/${segments.join("/")}`;
|
|
203
|
+
}
|
|
204
|
+
function addRoute(routes, seen, params, route, paramShape) {
|
|
205
|
+
if (!seen.has(route)) {
|
|
206
|
+
seen.add(route);
|
|
207
|
+
routes.push(route);
|
|
208
|
+
}
|
|
209
|
+
const existingParamShape = params.get(route);
|
|
210
|
+
if (existingParamShape) {
|
|
211
|
+
if (!paramShapesEqual(existingParamShape, paramShape)) throw new Error(`[vinext] Conflicting route param shapes generated for ${route}`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
params.set(route, paramShape);
|
|
215
|
+
}
|
|
216
|
+
function paramShapesEqual(left, right) {
|
|
217
|
+
if (left.size !== right.size) return false;
|
|
218
|
+
for (const [name, kind] of left) if (right.get(name) !== kind) return false;
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
function uniqueSorted(values) {
|
|
222
|
+
return Array.from(new Set(values)).sort(compareStrings);
|
|
223
|
+
}
|
|
224
|
+
function routeUnion(routes) {
|
|
225
|
+
if (routes.length === 0) return "never";
|
|
226
|
+
return routes.map(quote).join(" | ");
|
|
227
|
+
}
|
|
228
|
+
function propertyName(name) {
|
|
229
|
+
return /^[A-Za-z_$][\w$]*$/.test(name) ? name : quote(name);
|
|
230
|
+
}
|
|
231
|
+
function quote(value) {
|
|
232
|
+
return JSON.stringify(value);
|
|
233
|
+
}
|
|
234
|
+
function compareStrings(left, right) {
|
|
235
|
+
if (left < right) return -1;
|
|
236
|
+
if (left > right) return 1;
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
export { generateRouteTypes };
|
|
241
|
+
|
|
242
|
+
//# sourceMappingURL=typegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen.js","names":[],"sources":["../src/typegen.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { isInvisibleSegment } from \"./routing/app-route-graph.js\";\nimport { appRouteGraph } from \"./routing/app-router.js\";\nimport { patternToNextFormat } from \"./routing/route-validation.js\";\nimport { decodeRouteSegment } from \"./routing/utils.js\";\n\ntype GenerateRouteTypesOptions = {\n root: string;\n appDir?: string | null;\n pageExtensions?: readonly string[];\n};\n\ntype ParamShape = Map<string, \"string\" | \"string[]\" | \"string[]?\">;\n\nconst NEXT_ENV_FILE_CONTENT = `/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\nimport \"./.next/types/routes.d.ts\";\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.\n`;\n\nexport async function generateRouteTypes(options: GenerateRouteTypesOptions): Promise<string> {\n const root = path.resolve(options.root);\n const appDir = options.appDir ? path.resolve(options.appDir) : await findAppDir(root);\n const outPath = path.join(root, \".next\", \"types\", \"routes.d.ts\");\n\n const content = appDir\n ? renderRouteTypes(await collectRouteTypeModel(appDir, options.pageExtensions))\n : renderRouteTypes(emptyRouteTypeModel());\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, content, \"utf-8\");\n await ensureNextEnvFile(root);\n return outPath;\n}\n\nasync function ensureNextEnvFile(root: string): Promise<void> {\n const envPath = path.join(root, \"next-env.d.ts\");\n try {\n await fs.writeFile(envPath, NEXT_ENV_FILE_CONTENT, { encoding: \"utf-8\", flag: \"wx\" });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n }\n}\n\ntype RouteTypeModel = {\n pageRoutes: string[];\n layoutRoutes: string[];\n routeHandlerRoutes: string[];\n params: Map<string, ParamShape>;\n layoutSlots: Map<string, string[]>;\n};\n\nfunction emptyRouteTypeModel(): RouteTypeModel {\n return {\n pageRoutes: [],\n layoutRoutes: [],\n routeHandlerRoutes: [],\n params: new Map(),\n layoutSlots: new Map(),\n };\n}\n\nasync function collectRouteTypeModel(\n appDir: string,\n pageExtensions?: readonly string[],\n): Promise<RouteTypeModel> {\n const graph = await appRouteGraph(appDir, pageExtensions);\n const model = emptyRouteTypeModel();\n const segmentGraph = graph.routeManifest.segmentGraph;\n const layoutRouteKeys = createLayoutRouteKeyMap(segmentGraph.layouts.values());\n const pageRouteSet = new Set<string>();\n const layoutRouteSet = new Set<string>();\n const routeHandlerRouteSet = new Set<string>();\n\n for (const route of segmentGraph.pages.values()) {\n const routeEntry = segmentGraph.routes.get(route.routeId);\n addRoute(\n model.pageRoutes,\n pageRouteSet,\n model.params,\n patternToNextFormat(route.pattern),\n paramsForPatternParts(routeEntry?.patternParts ?? []),\n );\n }\n\n for (const route of segmentGraph.routeHandlers.values()) {\n const routeEntry = segmentGraph.routes.get(route.routeId);\n addRoute(\n model.routeHandlerRoutes,\n routeHandlerRouteSet,\n model.params,\n patternToNextFormat(route.pattern),\n paramsForPatternParts(routeEntry?.patternParts ?? []),\n );\n }\n\n for (const layout of segmentGraph.layouts.values()) {\n const route = layoutRouteKeys.get(layout.treePath) ?? treePathToRouteLiteral(layout.treePath);\n addRoute(\n model.layoutRoutes,\n layoutRouteSet,\n model.params,\n route,\n paramsForPatternParts(layout.patternParts),\n );\n }\n\n const layoutSlotSets = new Map<string, Set<string>>();\n for (const slot of segmentGraph.slots.values()) {\n const layoutRoute = layoutRouteKeyForSlot(slot, segmentGraph.layouts, layoutRouteKeys);\n if (!layoutRoute) continue;\n\n let slotNames = layoutSlotSets.get(layoutRoute);\n if (!slotNames) {\n slotNames = new Set();\n layoutSlotSets.set(layoutRoute, slotNames);\n model.layoutSlots.set(layoutRoute, []);\n }\n if (!slotNames.has(slot.name)) {\n slotNames.add(slot.name);\n model.layoutSlots.get(layoutRoute)?.push(slot.name);\n }\n }\n\n // Sort all collected route lists once after collection. addRoute() and the\n // slot loop above intentionally skip per-insertion sorts to keep collection\n // O(n) — the rendered output relies on stable sorted order, so the single\n // pass here is enough.\n model.pageRoutes.sort(compareStrings);\n model.layoutRoutes.sort(compareStrings);\n model.routeHandlerRoutes.sort(compareStrings);\n for (const slotNames of model.layoutSlots.values()) slotNames.sort(compareStrings);\n\n return model;\n}\n\nasync function findAppDir(root: string): Promise<string | null> {\n for (const rel of [\"app\", path.join(\"src\", \"app\")]) {\n const candidate = path.join(root, rel);\n try {\n const stat = await fs.stat(candidate);\n if (stat.isDirectory()) return candidate;\n } catch {\n // Try the next conventional app directory.\n }\n }\n return null;\n}\n\nfunction renderRouteTypes(model: RouteTypeModel): string {\n const allRoutes = uniqueSorted([\n ...model.pageRoutes,\n ...model.layoutRoutes,\n ...model.routeHandlerRoutes,\n ]);\n\n return `// This file is generated by vinext. Do not edit.\nimport type * as React from \"react\";\n\ndeclare global {\n type PageProps<Route extends VinextRouteTypes.PageRoute = VinextRouteTypes.PageRoute> = {\n params: Promise<VinextRouteTypes.ParamMap[Route]>;\n searchParams: Promise<Record<string, string | string[] | undefined>>;\n };\n\n type LayoutProps<Route extends VinextRouteTypes.LayoutRoute> = {\n params: Promise<VinextRouteTypes.ParamMap[Route]>;\n children: React.ReactNode;\n } & {\n [K in VinextRouteTypes.LayoutSlotMap[Route]]: React.ReactNode;\n };\n\n type RouteContext<Route extends VinextRouteTypes.RouteHandlerRoute = VinextRouteTypes.RouteHandlerRoute> = {\n params: Promise<VinextRouteTypes.ParamMap[Route]>;\n };\n}\n\ndeclare namespace VinextRouteTypes {\n type PageRoute = ${routeUnion(model.pageRoutes)};\n type LayoutRoute = ${routeUnion(model.layoutRoutes)};\n type RouteHandlerRoute = ${routeUnion(model.routeHandlerRoutes)};\n type AppRoute = ${routeUnion(allRoutes)};\n\n interface ParamMap {\n${renderParamMap(allRoutes, model.params)}\n }\n\n interface LayoutSlotMap {\n${renderLayoutSlotMap(model.layoutRoutes, model.layoutSlots)}\n }\n}\n\nexport {};\n`;\n}\n\nfunction renderParamMap(\n routes: readonly string[],\n params: ReadonlyMap<string, ParamShape>,\n): string {\n if (routes.length === 0) return \" [route: string]: {};\\n\";\n\n return routes\n .map((route) => ` ${quote(route)}: ${renderParamShape(params.get(route) ?? new Map())};`)\n .join(\"\\n\");\n}\n\nfunction renderParamShape(params: ParamShape): string {\n if (params.size === 0) return \"{}\";\n\n const fields = Array.from(params.entries())\n .sort(([left], [right]) => compareStrings(left, right))\n .map(([name, kind]) => {\n const optional = kind === \"string[]?\";\n const valueType = optional ? \"string[]\" : kind;\n return `${propertyName(name)}${optional ? \"?\" : \"\"}: ${valueType};`;\n });\n\n return `{ ${fields.join(\" \")} }`;\n}\n\nfunction renderLayoutSlotMap(\n layoutRoutes: readonly string[],\n layoutSlots: ReadonlyMap<string, readonly string[]>,\n): string {\n if (layoutRoutes.length === 0) return \" [route: string]: never;\\n\";\n\n return layoutRoutes\n .map((route) => {\n const slots = layoutSlots.get(route) ?? [];\n return ` ${quote(route)}: ${routeUnion(slots)};`;\n })\n .join(\"\\n\");\n}\n\nfunction paramsForPatternParts(patternParts: readonly string[]): ParamShape {\n const params: ParamShape = new Map();\n for (const part of patternParts) {\n if (!part.startsWith(\":\")) continue;\n\n if (part.endsWith(\"+\")) {\n params.set(part.slice(1, -1), \"string[]\");\n } else if (part.endsWith(\"*\")) {\n params.set(part.slice(1, -1), \"string[]?\");\n } else {\n params.set(part.slice(1), \"string\");\n }\n }\n return params;\n}\n\nfunction createLayoutRouteKeyMap(layouts: Iterable<{ treePath: string }>): Map<string, string> {\n const treePathsByRoute = new Map<string, string[]>();\n for (const { treePath } of layouts) {\n const route = treePathToRouteLiteral(treePath);\n const treePaths = treePathsByRoute.get(route) ?? [];\n treePaths.push(treePath);\n treePathsByRoute.set(route, treePaths);\n }\n\n const keys = new Map<string, string>();\n for (const [route, treePaths] of treePathsByRoute) {\n for (const treePath of treePaths) {\n keys.set(\n treePath,\n treePaths.length === 1 ? route : treePathToScopedLayoutRouteLiteral(treePath),\n );\n }\n }\n return keys;\n}\n\nfunction layoutRouteKeyForSlot(\n slot: { id: string; ownerLayoutId: string | null },\n layouts: ReadonlyMap<string, { treePath: string }>,\n layoutRouteKeys: ReadonlyMap<string, string>,\n): string | null {\n if (!slot.ownerLayoutId) return null;\n\n const layout = layouts.get(slot.ownerLayoutId);\n if (!layout) {\n throw new Error(\n `[vinext] App route graph invariant violated: slot ${slot.id} references missing owner layout ${slot.ownerLayoutId}`,\n );\n }\n\n return layoutRouteKeys.get(layout.treePath) ?? treePathToRouteLiteral(layout.treePath);\n}\n\n/** Convert a layout tree path to its URL route literal, stripping invisible segments. */\nfunction treePathToRouteLiteral(treePath: string): string {\n if (treePath === \"/\") return \"/\";\n\n const segments = treePath\n .split(\"/\")\n .filter(Boolean)\n .filter((segment) => !isInvisibleSegment(segment))\n .map((segment) => decodeRouteSegment(segment));\n return segments.length === 0 ? \"/\" : `/${segments.join(\"/\")}`;\n}\n\n/**\n * Convert a layout tree path to a scoped route literal that preserves\n * route-group and `@slot` segments. Used only as a fallback key when multiple\n * layouts collapse to the same URL route literal, so consumers can keep their\n * slot/params typings distinct.\n */\nfunction treePathToScopedLayoutRouteLiteral(treePath: string): string {\n if (treePath === \"/\") return \"/\";\n\n const segments = treePath\n .split(\"/\")\n .filter(Boolean)\n .filter((segment) => segment !== \".\")\n .map((segment) => decodeRouteSegment(segment));\n return segments.length === 0 ? \"/\" : `/${segments.join(\"/\")}`;\n}\n\nfunction addRoute(\n routes: string[],\n seen: Set<string>,\n params: Map<string, ParamShape>,\n route: string,\n paramShape: ParamShape,\n): void {\n if (!seen.has(route)) {\n seen.add(route);\n routes.push(route);\n }\n const existingParamShape = params.get(route);\n if (existingParamShape) {\n if (!paramShapesEqual(existingParamShape, paramShape)) {\n throw new Error(`[vinext] Conflicting route param shapes generated for ${route}`);\n }\n return;\n }\n params.set(route, paramShape);\n}\n\nfunction paramShapesEqual(left: ParamShape, right: ParamShape): boolean {\n if (left.size !== right.size) return false;\n for (const [name, kind] of left) {\n if (right.get(name) !== kind) return false;\n }\n return true;\n}\n\nfunction uniqueSorted(values: readonly string[]): string[] {\n return Array.from(new Set(values)).sort(compareStrings);\n}\n\nfunction routeUnion(routes: readonly string[]): string {\n if (routes.length === 0) return \"never\";\n return routes.map(quote).join(\" | \");\n}\n\nfunction propertyName(name: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(name) ? name : quote(name);\n}\n\nfunction quote(value: string): string {\n return JSON.stringify(value);\n}\n\nfunction compareStrings(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n"],"mappings":"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"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* static asset URL emitted in the page. It is distinct from `basePath`, which
|
|
7
7
|
* affects route URLs.
|
|
8
8
|
*
|
|
9
|
-
* - A `assetPrefix` of `""` (empty) means "no prefix"
|
|
10
|
-
*
|
|
9
|
+
* - A `assetPrefix` of `""` (empty) means "no prefix". URLs are emitted as
|
|
10
|
+
* `/_next/static/...` (Next.js's canonical convention) and assets are
|
|
11
|
+
* written to `dist/client/_next/static/...` so the on-disk layout matches.
|
|
11
12
|
* - A path prefix like `"/custom-asset-prefix"` is applied as a URL prefix
|
|
12
13
|
* relative to the deployment origin. The prod server must also serve assets
|
|
13
14
|
* under that prefix.
|
|
@@ -37,8 +38,14 @@ declare function isAbsoluteAssetPrefix(assetPrefix: string): boolean;
|
|
|
37
38
|
* server) serves them directly without a runtime rewrite.
|
|
38
39
|
* - Absolute URL (with or without path component): write to `_next/static/`.
|
|
39
40
|
* Runtime serving is best-effort — the CDN is expected to serve these.
|
|
40
|
-
* - Empty:
|
|
41
|
-
*
|
|
41
|
+
* - Empty: write to `_next/static/` so the on-disk layout matches the URL
|
|
42
|
+
* Next.js itself emits (and that the Next.js client runtime + upstream
|
|
43
|
+
* test suites assert against). This makes `assetPrefix` consistent in
|
|
44
|
+
* both the configured and unconfigured cases — the URL contract is
|
|
45
|
+
* always `/<prefix?>/_next/static/...`, and the on-disk layout mirrors
|
|
46
|
+
* it 1:1 so the static-file layer can serve hits and return
|
|
47
|
+
* `404 + "Not Found"` on misses without any URL-shape special-casing
|
|
48
|
+
* upstream of it.
|
|
42
49
|
*/
|
|
43
50
|
declare function resolveAssetsDir(assetPrefix: string): string;
|
|
44
51
|
/**
|
|
@@ -64,6 +71,27 @@ declare function resolveAssetUrlPrefix(assetPrefix: string): string;
|
|
|
64
71
|
* requests that arrive at the deployment origin under the configured prefix.
|
|
65
72
|
*/
|
|
66
73
|
declare function assetPrefixPathname(assetPrefix: string): string;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the incoming request pathname targets the canonical `_next/static/`
|
|
76
|
+
* tree, after stripping any configured `basePath` and `assetPrefix` path
|
|
77
|
+
* component.
|
|
78
|
+
*
|
|
79
|
+
* Used by the Cloudflare worker entry to recognise asset-shaped requests
|
|
80
|
+
* that the ASSETS binding didn't serve, so they can short-circuit with a
|
|
81
|
+
* plain-text 404 instead of falling through to the RSC handler (which
|
|
82
|
+
* would render the full HTML 404 page). Mirrors Next.js's behaviour in
|
|
83
|
+
* `packages/next/src/server/lib/router-server.ts` where
|
|
84
|
+
* `realRequestPathname` is stripped of basePath/assetPrefix/i18n locale
|
|
85
|
+
* before the `startsWith('/_next/static/')` check.
|
|
86
|
+
*
|
|
87
|
+
* - `pathname`: incoming request pathname (with leading slash, no query).
|
|
88
|
+
* - `basePath`: configured `basePath` (e.g. `"/docs"`) or `""`.
|
|
89
|
+
* - `assetPathPrefix`: path component of `assetPrefix` (e.g. `"/cdn"`) or
|
|
90
|
+
* `""`. Use `assetPrefixPathname()` to derive this from a raw assetPrefix.
|
|
91
|
+
*
|
|
92
|
+
* @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-server.ts
|
|
93
|
+
*/
|
|
94
|
+
declare function isNextStaticPath(pathname: string, basePath: string, assetPathPrefix: string): boolean;
|
|
67
95
|
//#endregion
|
|
68
|
-
export { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, resolveAssetUrlPrefix, resolveAssetsDir };
|
|
96
|
+
export { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, isNextStaticPath, resolveAssetUrlPrefix, resolveAssetsDir };
|
|
69
97
|
//# sourceMappingURL=asset-prefix.d.ts.map
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* static asset URL emitted in the page. It is distinct from `basePath`, which
|
|
7
7
|
* affects route URLs.
|
|
8
8
|
*
|
|
9
|
-
* - A `assetPrefix` of `""` (empty) means "no prefix"
|
|
10
|
-
*
|
|
9
|
+
* - A `assetPrefix` of `""` (empty) means "no prefix". URLs are emitted as
|
|
10
|
+
* `/_next/static/...` (Next.js's canonical convention) and assets are
|
|
11
|
+
* written to `dist/client/_next/static/...` so the on-disk layout matches.
|
|
11
12
|
* - A path prefix like `"/custom-asset-prefix"` is applied as a URL prefix
|
|
12
13
|
* relative to the deployment origin. The prod server must also serve assets
|
|
13
14
|
* under that prefix.
|
|
@@ -39,11 +40,17 @@ function isAbsoluteAssetPrefix(assetPrefix) {
|
|
|
39
40
|
* server) serves them directly without a runtime rewrite.
|
|
40
41
|
* - Absolute URL (with or without path component): write to `_next/static/`.
|
|
41
42
|
* Runtime serving is best-effort — the CDN is expected to serve these.
|
|
42
|
-
* - Empty:
|
|
43
|
-
*
|
|
43
|
+
* - Empty: write to `_next/static/` so the on-disk layout matches the URL
|
|
44
|
+
* Next.js itself emits (and that the Next.js client runtime + upstream
|
|
45
|
+
* test suites assert against). This makes `assetPrefix` consistent in
|
|
46
|
+
* both the configured and unconfigured cases — the URL contract is
|
|
47
|
+
* always `/<prefix?>/_next/static/...`, and the on-disk layout mirrors
|
|
48
|
+
* it 1:1 so the static-file layer can serve hits and return
|
|
49
|
+
* `404 + "Not Found"` on misses without any URL-shape special-casing
|
|
50
|
+
* upstream of it.
|
|
44
51
|
*/
|
|
45
52
|
function resolveAssetsDir(assetPrefix) {
|
|
46
|
-
if (!assetPrefix) return
|
|
53
|
+
if (!assetPrefix) return ASSET_PREFIX_URL_DIR;
|
|
47
54
|
if (isAbsoluteAssetPrefix(assetPrefix)) return ASSET_PREFIX_URL_DIR;
|
|
48
55
|
let stripped = assetPrefix;
|
|
49
56
|
while (stripped.startsWith("/")) stripped = stripped.slice(1);
|
|
@@ -85,7 +92,33 @@ function assetPrefixPathname(assetPrefix) {
|
|
|
85
92
|
return "";
|
|
86
93
|
}
|
|
87
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether the incoming request pathname targets the canonical `_next/static/`
|
|
97
|
+
* tree, after stripping any configured `basePath` and `assetPrefix` path
|
|
98
|
+
* component.
|
|
99
|
+
*
|
|
100
|
+
* Used by the Cloudflare worker entry to recognise asset-shaped requests
|
|
101
|
+
* that the ASSETS binding didn't serve, so they can short-circuit with a
|
|
102
|
+
* plain-text 404 instead of falling through to the RSC handler (which
|
|
103
|
+
* would render the full HTML 404 page). Mirrors Next.js's behaviour in
|
|
104
|
+
* `packages/next/src/server/lib/router-server.ts` where
|
|
105
|
+
* `realRequestPathname` is stripped of basePath/assetPrefix/i18n locale
|
|
106
|
+
* before the `startsWith('/_next/static/')` check.
|
|
107
|
+
*
|
|
108
|
+
* - `pathname`: incoming request pathname (with leading slash, no query).
|
|
109
|
+
* - `basePath`: configured `basePath` (e.g. `"/docs"`) or `""`.
|
|
110
|
+
* - `assetPathPrefix`: path component of `assetPrefix` (e.g. `"/cdn"`) or
|
|
111
|
+
* `""`. Use `assetPrefixPathname()` to derive this from a raw assetPrefix.
|
|
112
|
+
*
|
|
113
|
+
* @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-server.ts
|
|
114
|
+
*/
|
|
115
|
+
function isNextStaticPath(pathname, basePath, assetPathPrefix) {
|
|
116
|
+
let p = pathname;
|
|
117
|
+
if (basePath && (p === basePath || p.startsWith(basePath + "/"))) p = p.slice(basePath.length) || "/";
|
|
118
|
+
if (assetPathPrefix && (p === assetPathPrefix || p.startsWith(assetPathPrefix + "/"))) p = p.slice(assetPathPrefix.length) || "/";
|
|
119
|
+
return p.startsWith(`/${ASSET_PREFIX_URL_DIR}/`);
|
|
120
|
+
}
|
|
88
121
|
//#endregion
|
|
89
|
-
export { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, resolveAssetUrlPrefix, resolveAssetsDir };
|
|
122
|
+
export { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, isNextStaticPath, resolveAssetUrlPrefix, resolveAssetsDir };
|
|
90
123
|
|
|
91
124
|
//# sourceMappingURL=asset-prefix.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-prefix.js","names":[],"sources":["../../src/utils/asset-prefix.ts"],"sourcesContent":["/**\n * Shared helpers for next.config `assetPrefix`.\n *\n * Mirrors Next.js semantics: `assetPrefix` is prepended to every JS/CSS/image/\n * static asset URL emitted in the page. It is distinct from `basePath`, which\n * affects route URLs.\n *\n * - A `assetPrefix` of `\"\"` (empty) means \"no prefix\"
|
|
1
|
+
{"version":3,"file":"asset-prefix.js","names":[],"sources":["../../src/utils/asset-prefix.ts"],"sourcesContent":["/**\n * Shared helpers for next.config `assetPrefix`.\n *\n * Mirrors Next.js semantics: `assetPrefix` is prepended to every JS/CSS/image/\n * static asset URL emitted in the page. It is distinct from `basePath`, which\n * affects route URLs.\n *\n * - A `assetPrefix` of `\"\"` (empty) means \"no prefix\". URLs are emitted as\n * `/_next/static/...` (Next.js's canonical convention) and assets are\n * written to `dist/client/_next/static/...` so the on-disk layout matches.\n * - A path prefix like `\"/custom-asset-prefix\"` is applied as a URL prefix\n * relative to the deployment origin. The prod server must also serve assets\n * under that prefix.\n * - An absolute URL like `\"https://cdn.example.com\"` makes asset URLs fully\n * qualified. Runtime serving on the deployment origin is a no-op — the CDN\n * serves the assets directly.\n *\n * The path component of the asset URL after the prefix is always\n * `/_next/static/<filename>` to match Next.js's convention. This is the\n * convention upstream test suites assert against.\n *\n * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/assetPrefix\n */\n\n/**\n * Suffix appended to the assetPrefix (or used standalone when no prefix is\n * configured) to form the leading portion of every emitted asset URL.\n * Matches Next.js: assets always live under `/_next/static/`.\n */\nexport const ASSET_PREFIX_URL_DIR = \"_next/static\";\n\n/** Whether `assetPrefix` is an absolute URL (vs a path prefix). */\nexport function isAbsoluteAssetPrefix(assetPrefix: string): boolean {\n return /^https?:\\/\\//i.test(assetPrefix);\n}\n\n/**\n * Compute the on-disk `build.assetsDir` for the given `assetPrefix`.\n *\n * - Path prefix (`/cdn`): write to `cdn/_next/static/` so the on-disk layout\n * matches the URL — the Cloudflare ASSETS binding (and any static file\n * server) serves them directly without a runtime rewrite.\n * - Absolute URL (with or without path component): write to `_next/static/`.\n * Runtime serving is best-effort — the CDN is expected to serve these.\n * - Empty: write to `_next/static/` so the on-disk layout matches the URL\n * Next.js itself emits (and that the Next.js client runtime + upstream\n * test suites assert against). This makes `assetPrefix` consistent in\n * both the configured and unconfigured cases — the URL contract is\n * always `/<prefix?>/_next/static/...`, and the on-disk layout mirrors\n * it 1:1 so the static-file layer can serve hits and return\n * `404 + \"Not Found\"` on misses without any URL-shape special-casing\n * upstream of it.\n */\nexport function resolveAssetsDir(assetPrefix: string): string {\n if (!assetPrefix) return ASSET_PREFIX_URL_DIR;\n if (isAbsoluteAssetPrefix(assetPrefix)) {\n // Files on disk land at `_next/static/...`. The absolute URL is applied\n // at URL-rendering time via renderBuiltUrl; on-disk path is irrelevant\n // to the CDN.\n return ASSET_PREFIX_URL_DIR;\n }\n // Path prefix — strip leading slash so the path joins cleanly with outDir.\n // Use an explicit loop instead of `replace(/^\\/+/, \"\")` so CodeQL doesn't\n // flag the regex as polynomial-time on uncontrolled input.\n let stripped = assetPrefix;\n while (stripped.startsWith(\"/\")) stripped = stripped.slice(1);\n return `${stripped}/${ASSET_PREFIX_URL_DIR}`;\n}\n\n/**\n * Build the URL prefix to apply to emitted asset URLs. Returns the full URL\n * prefix including the `_next/static/` directory, with a trailing slash.\n *\n * Examples:\n * - `\"\"` → `\"/_next/static/\"`\n * - `\"/cdn\"` → `\"/cdn/_next/static/\"`\n * - `\"https://cdn.example.com\"` → `\"https://cdn.example.com/_next/static/\"`\n * - `\"https://cdn.example.com/sub\"` → `\"https://cdn.example.com/sub/_next/static/\"`\n */\nexport function resolveAssetUrlPrefix(assetPrefix: string): string {\n if (!assetPrefix) return `/${ASSET_PREFIX_URL_DIR}/`;\n return `${assetPrefix}/${ASSET_PREFIX_URL_DIR}/`;\n}\n\n/**\n * Extract the path portion of `assetPrefix` for use in runtime URL matching.\n *\n * - For a path prefix: returns it verbatim (e.g. `/custom-asset-prefix`).\n * - For an absolute URL: returns its pathname stripped of trailing slashes\n * (e.g. `\"https://cdn.example.com/sub\"` → `/sub`, plain origin → `\"\"`).\n * - For empty input: returns `\"\"`.\n *\n * Used by the prod server and Cloudflare worker entry to recognise asset\n * requests that arrive at the deployment origin under the configured prefix.\n */\nexport function assetPrefixPathname(assetPrefix: string): string {\n if (!assetPrefix) return \"\";\n if (!isAbsoluteAssetPrefix(assetPrefix)) return assetPrefix;\n try {\n let pathname = new URL(assetPrefix).pathname;\n while (pathname.endsWith(\"/\")) pathname = pathname.slice(0, -1);\n return pathname === \"\" ? \"\" : pathname;\n } catch {\n return \"\";\n }\n}\n\n/**\n * Whether the incoming request pathname targets the canonical `_next/static/`\n * tree, after stripping any configured `basePath` and `assetPrefix` path\n * component.\n *\n * Used by the Cloudflare worker entry to recognise asset-shaped requests\n * that the ASSETS binding didn't serve, so they can short-circuit with a\n * plain-text 404 instead of falling through to the RSC handler (which\n * would render the full HTML 404 page). Mirrors Next.js's behaviour in\n * `packages/next/src/server/lib/router-server.ts` where\n * `realRequestPathname` is stripped of basePath/assetPrefix/i18n locale\n * before the `startsWith('/_next/static/')` check.\n *\n * - `pathname`: incoming request pathname (with leading slash, no query).\n * - `basePath`: configured `basePath` (e.g. `\"/docs\"`) or `\"\"`.\n * - `assetPathPrefix`: path component of `assetPrefix` (e.g. `\"/cdn\"`) or\n * `\"\"`. Use `assetPrefixPathname()` to derive this from a raw assetPrefix.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-server.ts\n */\nexport function isNextStaticPath(\n pathname: string,\n basePath: string,\n assetPathPrefix: string,\n): boolean {\n let p = pathname;\n if (basePath && (p === basePath || p.startsWith(basePath + \"/\"))) {\n p = p.slice(basePath.length) || \"/\";\n }\n if (assetPathPrefix && (p === assetPathPrefix || p.startsWith(assetPathPrefix + \"/\"))) {\n p = p.slice(assetPathPrefix.length) || \"/\";\n }\n return p.startsWith(`/${ASSET_PREFIX_URL_DIR}/`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,uBAAuB;;AAGpC,SAAgB,sBAAsB,aAA8B;CAClE,OAAO,gBAAgB,KAAK,YAAY;;;;;;;;;;;;;;;;;;;AAoB1C,SAAgB,iBAAiB,aAA6B;CAC5D,IAAI,CAAC,aAAa,OAAO;CACzB,IAAI,sBAAsB,YAAY,EAIpC,OAAO;CAKT,IAAI,WAAW;CACf,OAAO,SAAS,WAAW,IAAI,EAAE,WAAW,SAAS,MAAM,EAAE;CAC7D,OAAO,GAAG,SAAS,GAAG;;;;;;;;;;;;AAaxB,SAAgB,sBAAsB,aAA6B;CACjE,IAAI,CAAC,aAAa,OAAO,IAAI,qBAAqB;CAClD,OAAO,GAAG,YAAY,GAAG,qBAAqB;;;;;;;;;;;;;AAchD,SAAgB,oBAAoB,aAA6B;CAC/D,IAAI,CAAC,aAAa,OAAO;CACzB,IAAI,CAAC,sBAAsB,YAAY,EAAE,OAAO;CAChD,IAAI;EACF,IAAI,WAAW,IAAI,IAAI,YAAY,CAAC;EACpC,OAAO,SAAS,SAAS,IAAI,EAAE,WAAW,SAAS,MAAM,GAAG,GAAG;EAC/D,OAAO,aAAa,KAAK,KAAK;SACxB;EACN,OAAO;;;;;;;;;;;;;;;;;;;;;;;AAwBX,SAAgB,iBACd,UACA,UACA,iBACS;CACT,IAAI,IAAI;CACR,IAAI,aAAa,MAAM,YAAY,EAAE,WAAW,WAAW,IAAI,GAC7D,IAAI,EAAE,MAAM,SAAS,OAAO,IAAI;CAElC,IAAI,oBAAoB,MAAM,mBAAmB,EAAE,WAAW,kBAAkB,IAAI,GAClF,IAAI,EAAE,MAAM,gBAAgB,OAAO,IAAI;CAEzC,OAAO,EAAE,WAAW,IAAI,qBAAqB,GAAG"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { isUnknownRecord } from "./record.js";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/cache-control-metadata.d.ts
|
|
2
|
-
declare function isUnknownRecord(value: unknown): value is Record<string, unknown>;
|
|
3
4
|
declare function readCacheControlNumberField(ctx: Record<string, unknown> | undefined, field: string): number | undefined;
|
|
4
5
|
//#endregion
|
|
5
6
|
export { isUnknownRecord, readCacheControlNumberField };
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
import { isUnknownRecord } from "./record.js";
|
|
1
2
|
//#region src/utils/cache-control-metadata.ts
|
|
2
|
-
function isUnknownRecord(value) {
|
|
3
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4
|
-
}
|
|
5
3
|
function readRecordField(ctx, field) {
|
|
6
4
|
const value = ctx?.[field];
|
|
7
5
|
return isUnknownRecord(value) ? value : void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-control-metadata.js","names":[],"sources":["../../src/utils/cache-control-metadata.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"cache-control-metadata.js","names":[],"sources":["../../src/utils/cache-control-metadata.ts"],"sourcesContent":["import { isUnknownRecord } from \"./record.js\";\nexport { isUnknownRecord } from \"./record.js\";\n\nfunction readRecordField(\n ctx: Record<string, unknown> | undefined,\n field: string,\n): Record<string, unknown> | undefined {\n const value = ctx?.[field];\n return isUnknownRecord(value) ? value : undefined;\n}\n\nexport function readCacheControlNumberField(\n ctx: Record<string, unknown> | undefined,\n field: string,\n): number | undefined {\n const cacheControl = readRecordField(ctx, \"cacheControl\");\n const value = cacheControl?.[field] ?? ctx?.[field];\n return typeof value === \"number\" ? value : undefined;\n}\n"],"mappings":";;AAGA,SAAS,gBACP,KACA,OACqC;CACrC,MAAM,QAAQ,MAAM;CACpB,OAAO,gBAAgB,MAAM,GAAG,QAAQ,KAAA;;AAG1C,SAAgB,4BACd,KACA,OACoB;CAEpB,MAAM,QADe,gBAAgB,KAAK,eAChB,GAAG,UAAU,MAAM;CAC7C,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA"}
|
|
@@ -12,6 +12,7 @@ declare function normalizeDomainHostname(hostname: string | null | undefined): s
|
|
|
12
12
|
*/
|
|
13
13
|
declare function detectDomainLocale(domainItems?: readonly DomainLocale[], hostname?: string, detectedLocale?: string): DomainLocale | undefined;
|
|
14
14
|
declare function addLocalePrefix(path: string, locale: string, localeDefault: string): string;
|
|
15
|
+
declare function getLocalePathPrefix(path: string, locales: readonly string[] | undefined): string | undefined;
|
|
15
16
|
declare function getDomainLocaleUrl(url: string, locale: string, {
|
|
16
17
|
basePath,
|
|
17
18
|
currentHostname,
|
|
@@ -22,5 +23,5 @@ declare function getDomainLocaleUrl(url: string, locale: string, {
|
|
|
22
23
|
domainItems?: readonly DomainLocale[];
|
|
23
24
|
}): string | undefined;
|
|
24
25
|
//#endregion
|
|
25
|
-
export { DomainLocale, addLocalePrefix, detectDomainLocale, getDomainLocaleUrl, normalizeDomainHostname };
|
|
26
|
+
export { DomainLocale, addLocalePrefix, detectDomainLocale, getDomainLocaleUrl, getLocalePathPrefix, normalizeDomainHostname };
|
|
26
27
|
//# sourceMappingURL=domain-locale.d.ts.map
|
|
@@ -25,6 +25,14 @@ function addLocalePrefix(path, locale, localeDefault) {
|
|
|
25
25
|
if (normalizedPathname === localePrefix || normalizedPathname.startsWith(`${localePrefix}/`)) return path.startsWith("/") ? path : pathWithLeadingSlash;
|
|
26
26
|
return `/${locale}${pathWithLeadingSlash}`;
|
|
27
27
|
}
|
|
28
|
+
function getLocalePathPrefix(path, locales) {
|
|
29
|
+
if (!locales?.length) return void 0;
|
|
30
|
+
const pathWithLeadingSlash = path.startsWith("/") ? path : `/${path}`;
|
|
31
|
+
const firstSegment = (pathWithLeadingSlash.split(/[?#]/, 1)[0] ?? pathWithLeadingSlash).split("/").find(Boolean);
|
|
32
|
+
if (!firstSegment) return void 0;
|
|
33
|
+
const normalizedSegment = firstSegment.toLowerCase();
|
|
34
|
+
return locales.find((locale) => locale.toLowerCase() === normalizedSegment);
|
|
35
|
+
}
|
|
28
36
|
function withBasePath(path, basePath = "") {
|
|
29
37
|
if (!basePath) return path;
|
|
30
38
|
return basePath + path;
|
|
@@ -39,6 +47,6 @@ function getDomainLocaleUrl(url, locale, { basePath, currentHostname, domainItem
|
|
|
39
47
|
return `${`http${targetDomain.http ? "" : "s"}://`}${targetDomain.domain}${withBasePath(localizedPath, basePath)}`;
|
|
40
48
|
}
|
|
41
49
|
//#endregion
|
|
42
|
-
export { addLocalePrefix, detectDomainLocale, getDomainLocaleUrl, normalizeDomainHostname };
|
|
50
|
+
export { addLocalePrefix, detectDomainLocale, getDomainLocaleUrl, getLocalePathPrefix, normalizeDomainHostname };
|
|
43
51
|
|
|
44
52
|
//# sourceMappingURL=domain-locale.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-locale.js","names":[],"sources":["../../src/utils/domain-locale.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\n\nexport type DomainLocale = NonNullable<NextI18nConfig[\"domains\"]>[number];\n\nexport function normalizeDomainHostname(hostname: string | null | undefined): string | undefined {\n if (!hostname) return undefined;\n return hostname.split(\",\", 1)[0]?.trim().split(\":\", 1)[0]?.toLowerCase() || undefined;\n}\n\n/**\n * Match a configured domain either by hostname or locale.\n * When both are provided, the checks intentionally use OR semantics so the\n * same helper can cover Next.js's hostname lookup and preferred-locale lookup.\n * If both are passed, the first domain matching either input wins, so callers\n * should pass hostname or detectedLocale, not both.\n */\nexport function detectDomainLocale(\n domainItems?: readonly DomainLocale[],\n hostname?: string,\n detectedLocale?: string,\n): DomainLocale | undefined {\n if (!domainItems?.length) return undefined;\n\n const normalizedHostname = normalizeDomainHostname(hostname);\n const normalizedLocale = detectedLocale?.toLowerCase();\n\n for (const item of domainItems) {\n const domainHostname = normalizeDomainHostname(item.domain);\n if (\n normalizedHostname === domainHostname ||\n normalizedLocale === item.defaultLocale.toLowerCase() ||\n item.locales?.some((locale) => locale.toLowerCase() === normalizedLocale)\n ) {\n return item;\n }\n }\n\n return undefined;\n}\n\nexport function addLocalePrefix(path: string, locale: string, localeDefault: string): string {\n const normalizedLocale = locale.toLowerCase();\n if (normalizedLocale === localeDefault.toLowerCase()) return path;\n\n const pathWithLeadingSlash = path.startsWith(\"/\") ? path : `/${path}`;\n const pathname = pathWithLeadingSlash.split(/[?#]/, 1)[0] ?? pathWithLeadingSlash;\n const normalizedPathname = pathname.toLowerCase();\n const localePrefix = `/${normalizedLocale}`;\n\n if (normalizedPathname === localePrefix || normalizedPathname.startsWith(`${localePrefix}/`)) {\n return path.startsWith(\"/\") ? path : pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash}`;\n}\n\nfunction withBasePath(path: string, basePath = \"\"): string {\n if (!basePath) return path;\n return basePath + path;\n}\n\nexport function getDomainLocaleUrl(\n url: string,\n locale: string,\n {\n basePath,\n currentHostname,\n domainItems,\n }: {\n basePath?: string;\n currentHostname?: string | null;\n domainItems?: readonly DomainLocale[];\n },\n): string | undefined {\n if (!domainItems?.length) return undefined;\n\n const targetDomain = detectDomainLocale(domainItems, undefined, locale);\n if (!targetDomain) return undefined;\n\n const currentDomain = detectDomainLocale(domainItems, currentHostname ?? undefined);\n const localizedPath = addLocalePrefix(url, locale, targetDomain.defaultLocale);\n\n if (\n currentDomain &&\n normalizeDomainHostname(currentDomain.domain) === normalizeDomainHostname(targetDomain.domain)\n ) {\n // Same-domain switches fall back to the caller's standard locale-prefix\n // logic. This relies on __VINEXT_DEFAULT_LOCALE__ matching the current\n // domain's defaultLocale, which the server entry keeps in sync.\n return undefined;\n }\n\n const scheme = `http${targetDomain.http ? \"\" : \"s\"}://`;\n return `${scheme}${targetDomain.domain}${withBasePath(localizedPath, basePath)}`;\n}\n"],"mappings":";AAIA,SAAgB,wBAAwB,UAAyD;CAC/F,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,OAAO,SAAS,MAAM,KAAK,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC,IAAI,aAAa,IAAI,KAAA;;;;;;;;;AAU9E,SAAgB,mBACd,aACA,UACA,gBAC0B;CAC1B,IAAI,CAAC,aAAa,QAAQ,OAAO,KAAA;CAEjC,MAAM,qBAAqB,wBAAwB,SAAS;CAC5D,MAAM,mBAAmB,gBAAgB,aAAa;CAEtD,KAAK,MAAM,QAAQ,aAEjB,IACE,uBAFqB,wBAAwB,KAAK,OAEb,IACrC,qBAAqB,KAAK,cAAc,aAAa,IACrD,KAAK,SAAS,MAAM,WAAW,OAAO,aAAa,KAAK,iBAAiB,EAEzE,OAAO;;AAOb,SAAgB,gBAAgB,MAAc,QAAgB,eAA+B;CAC3F,MAAM,mBAAmB,OAAO,aAAa;CAC7C,IAAI,qBAAqB,cAAc,aAAa,EAAE,OAAO;CAE7D,MAAM,uBAAuB,KAAK,WAAW,IAAI,GAAG,OAAO,IAAI;CAE/D,MAAM,sBADW,qBAAqB,MAAM,QAAQ,EAAE,CAAC,MAAM,sBACzB,aAAa;CACjD,MAAM,eAAe,IAAI;CAEzB,IAAI,uBAAuB,gBAAgB,mBAAmB,WAAW,GAAG,aAAa,GAAG,EAC1F,OAAO,KAAK,WAAW,IAAI,GAAG,OAAO;CAGvC,OAAO,IAAI,SAAS;;AAGtB,SAAS,aAAa,MAAc,WAAW,IAAY;CACzD,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,WAAW;;AAGpB,SAAgB,mBACd,KACA,QACA,EACE,UACA,iBACA,eAMkB;CACpB,IAAI,CAAC,aAAa,QAAQ,OAAO,KAAA;CAEjC,MAAM,eAAe,mBAAmB,aAAa,KAAA,GAAW,OAAO;CACvE,IAAI,CAAC,cAAc,OAAO,KAAA;CAE1B,MAAM,gBAAgB,mBAAmB,aAAa,mBAAmB,KAAA,EAAU;CACnF,MAAM,gBAAgB,gBAAgB,KAAK,QAAQ,aAAa,cAAc;CAE9E,IACE,iBACA,wBAAwB,cAAc,OAAO,KAAK,wBAAwB,aAAa,OAAO,EAK9F;CAIF,OAAO,GAAG,OADY,aAAa,OAAO,KAAK,IAAI,OAChC,aAAa,SAAS,aAAa,eAAe,SAAS"}
|
|
1
|
+
{"version":3,"file":"domain-locale.js","names":[],"sources":["../../src/utils/domain-locale.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\n\nexport type DomainLocale = NonNullable<NextI18nConfig[\"domains\"]>[number];\n\nexport function normalizeDomainHostname(hostname: string | null | undefined): string | undefined {\n if (!hostname) return undefined;\n return hostname.split(\",\", 1)[0]?.trim().split(\":\", 1)[0]?.toLowerCase() || undefined;\n}\n\n/**\n * Match a configured domain either by hostname or locale.\n * When both are provided, the checks intentionally use OR semantics so the\n * same helper can cover Next.js's hostname lookup and preferred-locale lookup.\n * If both are passed, the first domain matching either input wins, so callers\n * should pass hostname or detectedLocale, not both.\n */\nexport function detectDomainLocale(\n domainItems?: readonly DomainLocale[],\n hostname?: string,\n detectedLocale?: string,\n): DomainLocale | undefined {\n if (!domainItems?.length) return undefined;\n\n const normalizedHostname = normalizeDomainHostname(hostname);\n const normalizedLocale = detectedLocale?.toLowerCase();\n\n for (const item of domainItems) {\n const domainHostname = normalizeDomainHostname(item.domain);\n if (\n normalizedHostname === domainHostname ||\n normalizedLocale === item.defaultLocale.toLowerCase() ||\n item.locales?.some((locale) => locale.toLowerCase() === normalizedLocale)\n ) {\n return item;\n }\n }\n\n return undefined;\n}\n\nexport function addLocalePrefix(path: string, locale: string, localeDefault: string): string {\n const normalizedLocale = locale.toLowerCase();\n if (normalizedLocale === localeDefault.toLowerCase()) return path;\n\n const pathWithLeadingSlash = path.startsWith(\"/\") ? path : `/${path}`;\n const pathname = pathWithLeadingSlash.split(/[?#]/, 1)[0] ?? pathWithLeadingSlash;\n const normalizedPathname = pathname.toLowerCase();\n const localePrefix = `/${normalizedLocale}`;\n\n if (normalizedPathname === localePrefix || normalizedPathname.startsWith(`${localePrefix}/`)) {\n return path.startsWith(\"/\") ? path : pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash}`;\n}\n\nexport function getLocalePathPrefix(\n path: string,\n locales: readonly string[] | undefined,\n): string | undefined {\n if (!locales?.length) return undefined;\n\n const pathWithLeadingSlash = path.startsWith(\"/\") ? path : `/${path}`;\n const pathname = pathWithLeadingSlash.split(/[?#]/, 1)[0] ?? pathWithLeadingSlash;\n const firstSegment = pathname.split(\"/\").find(Boolean);\n if (!firstSegment) return undefined;\n\n const normalizedSegment = firstSegment.toLowerCase();\n return locales.find((locale) => locale.toLowerCase() === normalizedSegment);\n}\n\nfunction withBasePath(path: string, basePath = \"\"): string {\n if (!basePath) return path;\n return basePath + path;\n}\n\nexport function getDomainLocaleUrl(\n url: string,\n locale: string,\n {\n basePath,\n currentHostname,\n domainItems,\n }: {\n basePath?: string;\n currentHostname?: string | null;\n domainItems?: readonly DomainLocale[];\n },\n): string | undefined {\n if (!domainItems?.length) return undefined;\n\n const targetDomain = detectDomainLocale(domainItems, undefined, locale);\n if (!targetDomain) return undefined;\n\n const currentDomain = detectDomainLocale(domainItems, currentHostname ?? undefined);\n const localizedPath = addLocalePrefix(url, locale, targetDomain.defaultLocale);\n\n if (\n currentDomain &&\n normalizeDomainHostname(currentDomain.domain) === normalizeDomainHostname(targetDomain.domain)\n ) {\n // Same-domain switches fall back to the caller's standard locale-prefix\n // logic. This relies on __VINEXT_DEFAULT_LOCALE__ matching the current\n // domain's defaultLocale, which the server entry keeps in sync.\n return undefined;\n }\n\n const scheme = `http${targetDomain.http ? \"\" : \"s\"}://`;\n return `${scheme}${targetDomain.domain}${withBasePath(localizedPath, basePath)}`;\n}\n"],"mappings":";AAIA,SAAgB,wBAAwB,UAAyD;CAC/F,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,OAAO,SAAS,MAAM,KAAK,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC,IAAI,aAAa,IAAI,KAAA;;;;;;;;;AAU9E,SAAgB,mBACd,aACA,UACA,gBAC0B;CAC1B,IAAI,CAAC,aAAa,QAAQ,OAAO,KAAA;CAEjC,MAAM,qBAAqB,wBAAwB,SAAS;CAC5D,MAAM,mBAAmB,gBAAgB,aAAa;CAEtD,KAAK,MAAM,QAAQ,aAEjB,IACE,uBAFqB,wBAAwB,KAAK,OAEb,IACrC,qBAAqB,KAAK,cAAc,aAAa,IACrD,KAAK,SAAS,MAAM,WAAW,OAAO,aAAa,KAAK,iBAAiB,EAEzE,OAAO;;AAOb,SAAgB,gBAAgB,MAAc,QAAgB,eAA+B;CAC3F,MAAM,mBAAmB,OAAO,aAAa;CAC7C,IAAI,qBAAqB,cAAc,aAAa,EAAE,OAAO;CAE7D,MAAM,uBAAuB,KAAK,WAAW,IAAI,GAAG,OAAO,IAAI;CAE/D,MAAM,sBADW,qBAAqB,MAAM,QAAQ,EAAE,CAAC,MAAM,sBACzB,aAAa;CACjD,MAAM,eAAe,IAAI;CAEzB,IAAI,uBAAuB,gBAAgB,mBAAmB,WAAW,GAAG,aAAa,GAAG,EAC1F,OAAO,KAAK,WAAW,IAAI,GAAG,OAAO;CAGvC,OAAO,IAAI,SAAS;;AAGtB,SAAgB,oBACd,MACA,SACoB;CACpB,IAAI,CAAC,SAAS,QAAQ,OAAO,KAAA;CAE7B,MAAM,uBAAuB,KAAK,WAAW,IAAI,GAAG,OAAO,IAAI;CAE/D,MAAM,gBADW,qBAAqB,MAAM,QAAQ,EAAE,CAAC,MAAM,sBAC/B,MAAM,IAAI,CAAC,KAAK,QAAQ;CACtD,IAAI,CAAC,cAAc,OAAO,KAAA;CAE1B,MAAM,oBAAoB,aAAa,aAAa;CACpD,OAAO,QAAQ,MAAM,WAAW,OAAO,aAAa,KAAK,kBAAkB;;AAG7E,SAAS,aAAa,MAAc,WAAW,IAAY;CACzD,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,WAAW;;AAGpB,SAAgB,mBACd,KACA,QACA,EACE,UACA,iBACA,eAMkB;CACpB,IAAI,CAAC,aAAa,QAAQ,OAAO,KAAA;CAEjC,MAAM,eAAe,mBAAmB,aAAa,KAAA,GAAW,OAAO;CACvE,IAAI,CAAC,cAAc,OAAO,KAAA;CAE1B,MAAM,gBAAgB,mBAAmB,aAAa,mBAAmB,KAAA,EAAU;CACnF,MAAM,gBAAgB,gBAAgB,KAAK,QAAQ,aAAa,cAAc;CAE9E,IACE,iBACA,wBAAwB,cAAc,OAAO,KAAK,wBAAwB,aAAa,OAAO,EAK9F;CAIF,OAAO,GAAG,OADY,aAAa,OAAO,KAAK,IAAI,OAChC,aAAa,SAAS,aAAa,eAAe,SAAS"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/utils/html-limited-bots.ts
|
|
2
|
+
const HTML_LIMITED_BOT_UA_RE_STRING = String.raw`[\w-]+-Google|Google-[\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight`;
|
|
3
|
+
const htmlLimitedBotRegexCache = /* @__PURE__ */ new Map();
|
|
4
|
+
function getHtmlLimitedBotRegex(htmlLimitedBots) {
|
|
5
|
+
const source = htmlLimitedBots || HTML_LIMITED_BOT_UA_RE_STRING;
|
|
6
|
+
const cached = htmlLimitedBotRegexCache.get(source);
|
|
7
|
+
if (cached) return cached;
|
|
8
|
+
const regex = new RegExp(source, "i");
|
|
9
|
+
htmlLimitedBotRegexCache.set(source, regex);
|
|
10
|
+
return regex;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { getHtmlLimitedBotRegex };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=html-limited-bots.js.map
|