@timber-js/app 0.2.0-alpha.20 → 0.2.0-alpha.201
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/LICENSE +8 -0
- package/agent-skill.md +346 -0
- package/bin/timber.mjs +15 -1
- package/dist/_chunks/actions-HUdJADAD.js +345 -0
- package/dist/_chunks/actions-HUdJADAD.js.map +1 -0
- package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
- package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
- package/dist/_chunks/base-path-DaQrzbez.js +80 -0
- package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/build-output-helper-9dqCv1pZ.js +370 -0
- package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +1 -0
- package/dist/_chunks/cache-api-CAPbZTga.js +1149 -0
- package/dist/_chunks/cache-api-CAPbZTga.js.map +1 -0
- package/dist/_chunks/canonicalize-CgHoscYO.js +66 -0
- package/dist/_chunks/canonicalize-CgHoscYO.js.map +1 -0
- package/dist/_chunks/chains-CBNA0Ozj.js +412 -0
- package/dist/_chunks/chains-CBNA0Ozj.js.map +1 -0
- package/dist/_chunks/cli-check-BzMGuIH6.js +293 -0
- package/dist/_chunks/cli-check-BzMGuIH6.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-DnXqcIIj.js +299 -0
- package/dist/_chunks/cli-schema-sync-DnXqcIIj.js.map +1 -0
- package/dist/_chunks/cloudflare-DxX1SU0g.js +1290 -0
- package/dist/_chunks/cloudflare-DxX1SU0g.js.map +1 -0
- package/dist/_chunks/codec-registry-oOUxugz3.js +21 -0
- package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -0
- package/dist/_chunks/convention-lint-DHOFvX5s.js +803 -0
- package/dist/_chunks/convention-lint-DHOFvX5s.js.map +1 -0
- package/dist/_chunks/csp-nonce-hOGniaG4.js +227 -0
- package/dist/_chunks/csp-nonce-hOGniaG4.js.map +1 -0
- package/dist/_chunks/dev-server-DioP7tkQ.js +2288 -0
- package/dist/_chunks/dev-server-DioP7tkQ.js.map +1 -0
- package/dist/_chunks/dist-DtrJyBbw.js +386 -0
- package/dist/_chunks/dist-DtrJyBbw.js.map +1 -0
- package/dist/_chunks/error-boundary-BQKxl6EX.js +1044 -0
- package/dist/_chunks/error-boundary-BQKxl6EX.js.map +1 -0
- package/dist/_chunks/fast-hash-C-tVYrLb.js +41 -0
- package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
- package/dist/_chunks/file-cache-Dw6BJPG7.js +458 -0
- package/dist/_chunks/file-cache-Dw6BJPG7.js.map +1 -0
- package/dist/_chunks/format-BKclgVbk.js +14 -0
- package/dist/_chunks/format-BKclgVbk.js.map +1 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
- package/dist/_chunks/graph-cache-Cv3njEH8.js +304 -0
- package/dist/_chunks/graph-cache-Cv3njEH8.js.map +1 -0
- package/dist/_chunks/href-validation-BIrxavIy.js +213 -0
- package/dist/_chunks/href-validation-BIrxavIy.js.map +1 -0
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js +63 -0
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +1 -0
- package/dist/_chunks/live-graph-VjHFF5EV.js +150 -0
- package/dist/_chunks/live-graph-VjHFF5EV.js.map +1 -0
- package/dist/_chunks/logger-DqJ2VoAY.js +1476 -0
- package/dist/_chunks/logger-DqJ2VoAY.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DSDjM_hJ.js} +71 -27
- package/dist/_chunks/metadata-routes-DSDjM_hJ.js.map +1 -0
- package/dist/_chunks/navigation-context-D0TU0Jog.js +135 -0
- package/dist/_chunks/navigation-context-D0TU0Jog.js.map +1 -0
- package/dist/_chunks/navigation-root-mHSK9psY.js +126 -0
- package/dist/_chunks/navigation-root-mHSK9psY.js.map +1 -0
- package/dist/_chunks/param-value-C8TNYchQ.js +66 -0
- package/dist/_chunks/param-value-C8TNYchQ.js.map +1 -0
- package/dist/_chunks/plugin-context-8idfR3UZ.js +321 -0
- package/dist/_chunks/plugin-context-8idfR3UZ.js.map +1 -0
- package/dist/_chunks/poison-rules-DoEhbqaY.js +110 -0
- package/dist/_chunks/poison-rules-DoEhbqaY.js.map +1 -0
- package/dist/_chunks/poison-scan-lEbz4pQE.js +101 -0
- package/dist/_chunks/poison-scan-lEbz4pQE.js.map +1 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
- package/dist/_chunks/resolve-schema-CBR6Lm4i.js +50 -0
- package/dist/_chunks/resolve-schema-CBR6Lm4i.js.map +1 -0
- package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/_chunks/rsc-cache-key-ClUiXQnK.js +243 -0
- package/dist/_chunks/rsc-cache-key-ClUiXQnK.js.map +1 -0
- package/dist/_chunks/rsc-media-type-DDc7duTD.js +61 -0
- package/dist/_chunks/rsc-media-type-DDc7duTD.js.map +1 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
- package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
- package/dist/_chunks/scan-BoP17W3w.js +140 -0
- package/dist/_chunks/scan-BoP17W3w.js.map +1 -0
- package/dist/_chunks/scanner-B_tnqFcF.js +1671 -0
- package/dist/_chunks/scanner-B_tnqFcF.js.map +1 -0
- package/dist/_chunks/schema-bridge-C83xa9lT.js +199 -0
- package/dist/_chunks/schema-bridge-C83xa9lT.js.map +1 -0
- package/dist/_chunks/segment-classify-C539Pa2O.js +197 -0
- package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
- package/dist/_chunks/segment-context-D9_89u34.js +34 -0
- package/dist/_chunks/segment-context-D9_89u34.js.map +1 -0
- package/dist/_chunks/segment-keys-D5hu1hz4.js +62 -0
- package/dist/_chunks/segment-keys-D5hu1hz4.js.map +1 -0
- package/dist/_chunks/singleflight-2lUWfcAk.js +54 -0
- package/dist/_chunks/singleflight-2lUWfcAk.js.map +1 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js +35 -0
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-D6T6Y3ef.js} +3 -31
- package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +1 -0
- package/dist/_chunks/state-FippDgxN.js +52 -0
- package/dist/_chunks/state-FippDgxN.js.map +1 -0
- package/dist/_chunks/status-page-marker-DwQBrLBz.js +496 -0
- package/dist/_chunks/status-page-marker-DwQBrLBz.js.map +1 -0
- package/dist/_chunks/tree-match-CdbvYTBz.js +122 -0
- package/dist/_chunks/tree-match-CdbvYTBz.js.map +1 -0
- package/dist/_chunks/use-query-states-I3JMng6J.js +226 -0
- package/dist/_chunks/use-query-states-I3JMng6J.js.map +1 -0
- package/dist/_chunks/walkers-Cm3PC5JT.js +144 -0
- package/dist/_chunks/walkers-Cm3PC5JT.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +72 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +74 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +65 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +123 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +200 -22
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -188
- package/dist/adapters/compress-module.d.ts +17 -4
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +64 -0
- package/dist/adapters/fs-identity.d.ts.map +1 -0
- package/dist/adapters/nitro-presets.d.ts +37 -0
- package/dist/adapters/nitro-presets.d.ts.map +1 -0
- package/dist/adapters/nitro-preview.d.ts +32 -0
- package/dist/adapters/nitro-preview.d.ts.map +1 -0
- package/dist/adapters/nitro.d.ts +66 -37
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +457 -300
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +62 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/types.d.ts +28 -6
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/analyze/chains.d.ts +124 -0
- package/dist/analyze/chains.d.ts.map +1 -0
- package/dist/analyze/classify.d.ts +150 -0
- package/dist/analyze/classify.d.ts.map +1 -0
- package/dist/analyze/crawl-entry.d.ts +17 -0
- package/dist/analyze/crawl-entry.d.ts.map +1 -0
- package/dist/analyze/crawl-entry.js +313 -0
- package/dist/analyze/crawl-entry.js.map +1 -0
- package/dist/analyze/crawl.d.ts +134 -0
- package/dist/analyze/crawl.d.ts.map +1 -0
- package/dist/analyze/graph-cache.d.ts +104 -0
- package/dist/analyze/graph-cache.d.ts.map +1 -0
- package/dist/analyze/graph-command.d.ts +43 -0
- package/dist/analyze/graph-command.d.ts.map +1 -0
- package/dist/analyze/graph-command.js +472 -0
- package/dist/analyze/graph-command.js.map +1 -0
- package/dist/analyze/live-graph.d.ts +81 -0
- package/dist/analyze/live-graph.d.ts.map +1 -0
- package/dist/analyze/poison-rules.d.ts +72 -0
- package/dist/analyze/poison-rules.d.ts.map +1 -0
- package/dist/analyze/poison-scan.d.ts +48 -0
- package/dist/analyze/poison-scan.d.ts.map +1 -0
- package/dist/analyze/scan.d.ts +73 -0
- package/dist/analyze/scan.d.ts.map +1 -0
- package/dist/cache/cache-api.d.ts +48 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/fast-hash.d.ts +5 -0
- package/dist/cache/fast-hash.d.ts.map +1 -1
- package/dist/cache/handler-store.d.ts +33 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +32 -9
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -326
- package/dist/cache/invalidation-epoch.d.ts +43 -0
- package/dist/cache/invalidation-epoch.d.ts.map +1 -0
- package/dist/cache/json-lossy-check.d.ts +11 -0
- package/dist/cache/json-lossy-check.d.ts.map +1 -0
- package/dist/cache/redis-handler.d.ts +141 -9
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +21 -2
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts +22 -0
- package/dist/cache/sizeof.d.ts.map +1 -0
- package/dist/cache/stable-stringify.d.ts +9 -0
- package/dist/cache/stable-stringify.d.ts.map +1 -1
- package/dist/cache/store.d.ts +53 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
- package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.js +29 -0
- package/dist/cache/stores/cloudflare-kv.js.map +1 -0
- package/dist/cache/stores/memory.d.ts +42 -0
- package/dist/cache/stores/memory.d.ts.map +1 -0
- package/dist/cache/stores/memory.js +90 -0
- package/dist/cache/stores/memory.js.map +1 -0
- package/dist/cache/stores/redis.d.ts +69 -0
- package/dist/cache/stores/redis.d.ts.map +1 -0
- package/dist/cache/stores/redis.js +35 -0
- package/dist/cache/stores/redis.js.map +1 -0
- package/dist/cache/stores/vercel.d.ts +36 -0
- package/dist/cache/stores/vercel.d.ts.map +1 -0
- package/dist/cache/stores/vercel.js +33 -0
- package/dist/cache/stores/vercel.js.map +1 -0
- package/dist/cache/tag-aware-handler.d.ts +52 -0
- package/dist/cache/tag-aware-handler.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts +21 -11
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cdn/cloudflare-purge.d.ts +23 -0
- package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
- package/dist/cdn/cloudflare-purge.js +30 -0
- package/dist/cdn/cloudflare-purge.js.map +1 -0
- package/dist/cdn/fastly-purge.d.ts +25 -0
- package/dist/cdn/fastly-purge.d.ts.map +1 -0
- package/dist/cdn/fastly-purge.js +33 -0
- package/dist/cdn/fastly-purge.js.map +1 -0
- package/dist/cdn/headers.d.ts +97 -0
- package/dist/cdn/headers.d.ts.map +1 -0
- package/dist/cdn/index.d.ts +5 -0
- package/dist/cdn/index.d.ts.map +1 -0
- package/dist/cdn/index.js +94 -0
- package/dist/cdn/index.js.map +1 -0
- package/dist/cdn/purge-store.d.ts +23 -0
- package/dist/cdn/purge-store.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.d.ts +20 -0
- package/dist/cdn/workers-cache-purge.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.js +35 -0
- package/dist/cdn/workers-cache-purge.js.map +1 -0
- package/dist/cli-check.d.ts +163 -0
- package/dist/cli-check.d.ts.map +1 -0
- package/dist/cli-schema-sync.d.ts +59 -0
- package/dist/cli-schema-sync.d.ts.map +1 -0
- package/dist/cli.d.ts +81 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +216 -51
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +37 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +19 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/action-queue.d.ts +63 -0
- package/dist/client/browser-entry/action-queue.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +63 -0
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
- package/dist/client/browser-entry/index.d.ts +30 -0
- package/dist/client/browser-entry/index.d.ts.map +1 -0
- package/dist/client/browser-entry/post-hydration.d.ts +29 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +46 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +32 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +28 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/deny-last-resort.d.ts +29 -0
- package/dist/client/deny-last-resort.d.ts.map +1 -0
- package/dist/client/error-boundary.d.ts +55 -7
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +2 -126
- package/dist/client/error-reconstituter.d.ts +61 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +16 -27
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/global-context.d.ts +15 -0
- package/dist/client/global-context.d.ts.map +1 -0
- package/dist/client/history.d.ts +50 -9
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +20 -33
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +323 -1148
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +20 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +818 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link.d.ts +63 -60
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/location-search.d.ts +12 -0
- package/dist/client/location-search.d.ts.map +1 -0
- package/dist/client/navigation-api.d.ts +121 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-commit.d.ts +98 -0
- package/dist/client/navigation-commit.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +51 -31
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +98 -0
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/navigation-transition.d.ts +187 -0
- package/dist/client/navigation-transition.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts +1 -1
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/params-context.d.ts +81 -0
- package/dist/client/params-context.d.ts.map +1 -0
- package/dist/client/react-root.d.ts +44 -0
- package/dist/client/react-root.d.ts.map +1 -0
- package/dist/client/router-effects.d.ts +130 -0
- package/dist/client/router-effects.d.ts.map +1 -0
- package/dist/client/router-lifecycle.d.ts +98 -0
- package/dist/client/router-lifecycle.d.ts.map +1 -0
- package/dist/client/router-pipeline.d.ts +87 -0
- package/dist/client/router-pipeline.d.ts.map +1 -0
- package/dist/client/router-ref.d.ts +2 -2
- package/dist/client/router-ref.d.ts.map +1 -1
- package/dist/client/router-skew.d.ts +21 -0
- package/dist/client/router-skew.d.ts.map +1 -0
- package/dist/client/router-types.d.ts +272 -0
- package/dist/client/router-types.d.ts.map +1 -0
- package/dist/client/router.d.ts +1 -97
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +104 -26
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +161 -25
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +68 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/segment-update-context.d.ts +15 -0
- package/dist/client/segment-update-context.d.ts.map +1 -0
- package/dist/client/shallow-url.d.ts +10 -0
- package/dist/client/shallow-url.d.ts.map +1 -0
- package/dist/client/slot-content-cache-context.d.ts +35 -0
- package/dist/client/slot-content-cache-context.d.ts.map +1 -0
- package/dist/client/slot-context.d.ts +31 -0
- package/dist/client/slot-context.d.ts.map +1 -0
- package/dist/client/slot-outlet.d.ts +16 -0
- package/dist/client/slot-outlet.d.ts.map +1 -0
- package/dist/client/slot-provider.d.ts +25 -0
- package/dist/client/slot-provider.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +29 -7
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-client.d.ts +69 -0
- package/dist/client/stale-client.d.ts.map +1 -0
- package/dist/client/state.d.ts +19 -8
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/status-page-marker.d.ts +25 -0
- package/dist/client/status-page-marker.d.ts.map +1 -0
- package/dist/client/top-loader.d.ts +7 -6
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/unload-guard.d.ts +5 -0
- package/dist/client/unload-guard.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts +12 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-link-status.d.ts +5 -5
- package/dist/client/use-link-status.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts +13 -11
- package/dist/client/use-pathname.d.ts.map +1 -1
- package/dist/client/use-pending-navigation.d.ts +23 -0
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +10 -4
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +2 -2
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +15 -8
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/client/use-segment-params.d.ts +55 -0
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +69 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +76 -0
- package/dist/codec.js.map +1 -0
- package/dist/config-types.d.ts +322 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-validation.d.ts +51 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/cookies/define-cookie.d.ts +58 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +3 -2
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +256 -36
- package/dist/cookies/index.js.map +1 -1
- package/dist/cookies/json-cookie.d.ts +64 -0
- package/dist/cookies/json-cookie.d.ts.map +1 -0
- package/dist/cookies/validation.d.ts +34 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +50 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +40 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/debug-channel.d.ts +55 -0
- package/dist/dev-tools/debug-channel.d.ts.map +1 -0
- package/dist/dev-tools/dev-page-shell.d.ts +78 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +32 -0
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/dev-tools/holding-server.d.ts +46 -0
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/hydration-overlay.d.ts +11 -0
- package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/dev-tools/instrumentation.d.ts +59 -0
- package/dist/dev-tools/instrumentation.d.ts.map +1 -0
- package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
- package/dist/dev-tools/logger.d.ts.map +1 -0
- package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +17 -3
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/dev-tools/overlay.d.ts +91 -0
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/dev-tools/terminal.d.ts +28 -0
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/fonts/ast-walk.d.ts +68 -0
- package/dist/fonts/ast-walk.d.ts.map +1 -0
- package/dist/fonts/ast.d.ts +112 -8
- package/dist/fonts/ast.d.ts.map +1 -1
- package/dist/fonts/bundle.d.ts +50 -0
- package/dist/fonts/bundle.d.ts.map +1 -0
- package/dist/fonts/css.d.ts +1 -1
- package/dist/fonts/dev-middleware.d.ts +22 -0
- package/dist/fonts/dev-middleware.d.ts.map +1 -0
- package/dist/fonts/fallbacks.d.ts +0 -7
- package/dist/fonts/fallbacks.d.ts.map +1 -1
- package/dist/fonts/google.d.ts +5 -3
- package/dist/fonts/google.d.ts.map +1 -1
- package/dist/fonts/local.d.ts +5 -5
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/paths.d.ts +43 -0
- package/dist/fonts/paths.d.ts.map +1 -0
- package/dist/fonts/pipeline.d.ts +177 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +82 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +47 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +77 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +35 -181
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8462 -14279
- package/dist/index.js.map +1 -1
- package/dist/params/codec-registry.d.ts +26 -0
- package/dist/params/codec-registry.d.ts.map +1 -0
- package/dist/params/define-schema.d.ts +81 -0
- package/dist/params/define-schema.d.ts.map +1 -0
- package/dist/params/index.d.ts +5 -0
- package/dist/params/index.d.ts.map +1 -0
- package/dist/params/index.js +34 -0
- package/dist/params/index.js.map +1 -0
- package/dist/params/resolve-schema.d.ts +34 -0
- package/dist/params/resolve-schema.d.ts.map +1 -0
- package/dist/plugin-context.d.ts +276 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +21 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +7 -3
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +47 -10
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/cache.d.ts +64 -0
- package/dist/plugins/cache.d.ts.map +1 -0
- package/dist/plugins/callsite-ast.d.ts +117 -0
- package/dist/plugins/callsite-ast.d.ts.map +1 -0
- package/dist/plugins/callsite-jsx.d.ts +35 -0
- package/dist/plugins/callsite-jsx.d.ts.map +1 -0
- package/dist/plugins/chunks.d.ts +11 -4
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +40 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/cloudflare-wasm.d.ts +21 -0
- package/dist/plugins/cloudflare-wasm.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-discovery.d.ts +123 -0
- package/dist/plugins/dev-discovery.d.ts.map +1 -0
- package/dist/plugins/dev-server.d.ts +24 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +28 -4
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +16 -73
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/graph-endpoint.d.ts +112 -0
- package/dist/plugins/graph-endpoint.d.ts.map +1 -0
- package/dist/plugins/mdx.d.ts +18 -5
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/prebuilt-capture.d.ts +60 -0
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts +40 -0
- package/dist/plugins/prebuilt-options-analysis.d.ts.map +1 -0
- package/dist/plugins/prebuilt.d.ts +82 -0
- package/dist/plugins/prebuilt.d.ts.map +1 -0
- package/dist/plugins/prerender-sugar.d.ts +39 -0
- package/dist/plugins/prerender-sugar.d.ts.map +1 -0
- package/dist/plugins/request-dep/analysis.d.ts +106 -0
- package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
- package/dist/plugins/request-dep/index.d.ts +75 -0
- package/dist/plugins/request-dep/index.d.ts.map +1 -0
- package/dist/plugins/request-dep/origin.d.ts +61 -0
- package/dist/plugins/request-dep/origin.d.ts.map +1 -0
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts +29 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +218 -21
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +26 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +61 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen-write.d.ts +51 -0
- package/dist/routing/codegen-write.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +8 -3
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/collision-probe.d.ts +104 -0
- package/dist/routing/collision-probe.d.ts.map +1 -0
- package/dist/routing/collision-spaces.d.ts +26 -0
- package/dist/routing/collision-spaces.d.ts.map +1 -0
- package/dist/routing/convention-lint.d.ts +55 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/export-detect.d.ts +72 -0
- package/dist/routing/export-detect.d.ts.map +1 -0
- package/dist/routing/file-cache.d.ts +8 -0
- package/dist/routing/file-cache.d.ts.map +1 -0
- package/dist/routing/index.d.ts +13 -7
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +5 -2
- package/dist/routing/interception-overlap.d.ts +35 -0
- package/dist/routing/interception-overlap.d.ts.map +1 -0
- package/dist/routing/interception.d.ts +234 -10
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +105 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/manifest-codegen.d.ts +26 -0
- package/dist/routing/manifest-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +14 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/schema-validation.d.ts +35 -0
- package/dist/routing/schema-validation.d.ts.map +1 -0
- package/dist/routing/segment-classify.d.ts +114 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/segment-codegen.d.ts +38 -0
- package/dist/routing/segment-codegen.d.ts.map +1 -0
- package/dist/routing/segment-keys.d.ts +118 -0
- package/dist/routing/segment-keys.d.ts.map +1 -0
- package/dist/routing/slot-placement.d.ts +48 -0
- package/dist/routing/slot-placement.d.ts.map +1 -0
- package/dist/routing/types.d.ts +74 -26
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +57 -0
- package/dist/routing/walkers.d.ts.map +1 -0
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +14 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/rsc-runtime/transforms.d.ts +13 -0
- package/dist/rsc-runtime/transforms.d.ts.map +1 -0
- package/dist/schema-bridge.d.ts +145 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +262 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +3 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +179 -360
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/parse-total.d.ts +81 -0
- package/dist/search-params/parse-total.d.ts.map +1 -0
- package/dist/search-params/serialize-equal.d.ts +9 -0
- package/dist/search-params/serialize-equal.d.ts.map +1 -0
- package/dist/search-params/wrappers.d.ts +76 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/server/access-gate.d.ts +98 -10
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +42 -7
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts +39 -5
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +29 -35
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +117 -13
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +8 -18
- package/dist/server/asset-headers.d.ts.map +1 -1
- package/dist/server/body-limits.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +25 -30
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/canonicalize.d.ts +10 -0
- package/dist/server/canonicalize.d.ts.map +1 -1
- package/dist/server/chain-url-parts.d.ts +82 -0
- package/dist/server/chain-url-parts.d.ts.map +1 -0
- package/dist/server/children-interception.d.ts +49 -0
- package/dist/server/children-interception.d.ts.map +1 -0
- package/dist/server/coalesce-tick.d.ts +40 -0
- package/dist/server/coalesce-tick.d.ts.map +1 -0
- package/dist/server/compress.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +170 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +65 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/csp-nonce.d.ts +45 -0
- package/dist/server/csp-nonce.d.ts.map +1 -0
- package/dist/server/csrf.d.ts +3 -2
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/default-status-page.d.ts +45 -0
- package/dist/server/default-status-page.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +251 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +20 -10
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-source-map.d.ts +22 -0
- package/dist/server/dev-source-map.d.ts.map +1 -0
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +14 -12
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +94 -10
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/error-response-headers.d.ts +3 -0
- package/dist/server/error-response-headers.d.ts.map +1 -0
- package/dist/server/fallback-error.d.ts +12 -7
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +45 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/form-data.d.ts +41 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/form-flash.d.ts +1 -1
- package/dist/server/head-response.d.ts +35 -0
- package/dist/server/head-response.d.ts.map +1 -0
- package/dist/server/html-injector-core.d.ts +257 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +84 -42
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +18 -54
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +195 -2922
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +1 -1
- package/dist/server/internal.d.ts +50 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +3859 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +39 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/metadata-collector.d.ts +71 -0
- package/dist/server/metadata-collector.d.ts.map +1 -0
- package/dist/server/metadata-platform.d.ts +2 -2
- package/dist/server/metadata-render.d.ts +2 -2
- package/dist/server/metadata-render.d.ts.map +1 -1
- package/dist/server/metadata-routes.d.ts +60 -11
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-social.d.ts +2 -2
- package/dist/server/metadata.d.ts +10 -2
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +20 -5
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +105 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/nuqs-ssr-provider.d.ts +7 -3
- package/dist/server/nuqs-ssr-provider.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +78 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +77 -0
- package/dist/server/pipeline-helpers.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +59 -9
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +7 -1
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +70 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +161 -20
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +31 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/prebuilt/cache-key.d.ts +63 -0
- package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +57 -0
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
- package/dist/server/prebuilt/key-discipline.d.ts +52 -0
- package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
- package/dist/server/prebuilt/overlay.d.ts +100 -0
- package/dist/server/prebuilt/overlay.d.ts.map +1 -0
- package/dist/server/prebuilt/payload-source.d.ts +79 -0
- package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +99 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -0
- package/dist/server/prebuilt/synthetic-store.d.ts +67 -0
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts +121 -0
- package/dist/server/prebuilt-builder.d.ts.map +1 -0
- package/dist/server/prebuilt-runtime.d.ts +111 -0
- package/dist/server/prebuilt-runtime.d.ts.map +1 -0
- package/dist/server/primitives.d.ts +131 -45
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/publish-params.d.ts +33 -0
- package/dist/server/publish-params.d.ts.map +1 -0
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/render-utils.d.ts +26 -0
- package/dist/server/render-utils.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +111 -107
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-dep.d.ts +15 -0
- package/dist/server/request-dep.d.ts.map +1 -0
- package/dist/server/response-cache-policy.d.ts +3 -0
- package/dist/server/response-cache-policy.d.ts.map +1 -0
- package/dist/server/route-element-builder.d.ts +57 -30
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-element-helpers.d.ts +12 -0
- package/dist/server/route-element-helpers.d.ts.map +1 -0
- package/dist/server/route-handler.d.ts +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +40 -38
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/route-module-loader.d.ts +37 -0
- package/dist/server/route-module-loader.d.ts.map +1 -0
- package/dist/server/rsc-cache-key-guard.d.ts +78 -0
- package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts +12 -3
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +29 -0
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
- package/dist/server/rsc-entry/error-renderer.d.ts +34 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +47 -51
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +40 -6
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +52 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +108 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts +26 -6
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +36 -3
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +38 -5
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +89 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
- package/dist/server/rsc-error-envelope.d.ts +11 -0
- package/dist/server/rsc-error-envelope.d.ts.map +1 -0
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/sensitive-fields.d.ts +74 -0
- package/dist/server/sensitive-fields.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +130 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/skippable-prefix.d.ts +29 -0
- package/dist/server/skippable-prefix.d.ts.map +1 -0
- package/dist/server/slot-interception.d.ts +80 -0
- package/dist/server/slot-interception.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +137 -7
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/slot-subtree-contain.d.ts +54 -0
- package/dist/server/slot-subtree-contain.d.ts.map +1 -0
- package/dist/server/ssr-bridge-types.d.ts +160 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -0
- package/dist/server/ssr-entry.d.ts +1 -43
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +69 -22
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +93 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/state-tree-diff.d.ts +44 -9
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/static-generator.d.ts +112 -0
- package/dist/server/static-generator.d.ts.map +1 -0
- package/dist/server/static-not-found.d.ts +52 -0
- package/dist/server/static-not-found.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +26 -15
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +47 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +46 -11
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-match.d.ts +49 -0
- package/dist/server/tree-match.d.ts.map +1 -0
- package/dist/server/types.d.ts +88 -7
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/element-type.d.ts +50 -0
- package/dist/server/utils/element-type.d.ts.map +1 -0
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/workers-cache-bridge.d.ts +26 -0
- package/dist/server/workers-cache-bridge.d.ts.map +1 -0
- package/dist/shared/als-slots.d.ts +42 -0
- package/dist/shared/als-slots.d.ts.map +1 -0
- package/dist/shared/base-path.d.ts +56 -0
- package/dist/shared/base-path.d.ts.map +1 -0
- package/dist/shared/href-validation.d.ts +49 -0
- package/dist/shared/href-validation.d.ts.map +1 -0
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shared/param-value.d.ts +104 -0
- package/dist/shared/param-value.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +109 -0
- package/dist/shared/payload-root.d.ts.map +1 -0
- package/dist/shared/redirect-type.d.ts +17 -0
- package/dist/shared/redirect-type.d.ts.map +1 -0
- package/dist/shared/rsc-cache-key.d.ts +163 -0
- package/dist/shared/rsc-cache-key.d.ts.map +1 -0
- package/dist/shared/rsc-error-envelope.d.ts +16 -0
- package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
- package/dist/shared/rsc-manifest.d.ts +28 -0
- package/dist/shared/rsc-manifest.d.ts.map +1 -0
- package/dist/shared/rsc-media-type.d.ts +52 -0
- package/dist/shared/rsc-media-type.d.ts.map +1 -0
- package/dist/shared/rsc-payload-path.d.ts +42 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -0
- package/dist/shared/segment-info.d.ts +66 -0
- package/dist/shared/segment-info.d.ts.map +1 -0
- package/dist/shared/slot-params.d.ts +52 -0
- package/dist/shared/slot-params.d.ts.map +1 -0
- package/dist/shared/static-platform-files.d.ts +71 -0
- package/dist/shared/static-platform-files.d.ts.map +1 -0
- package/dist/shared/status-reason-phrase.d.ts +26 -0
- package/dist/shared/status-reason-phrase.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.d.ts +26 -0
- package/dist/shims/font-local.d.ts.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/dist/shims/headers.d.ts +53 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/image.d.ts +120 -120
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +25 -12
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation-rsc.d.ts +21 -0
- package/dist/shims/navigation-rsc.d.ts.map +1 -0
- package/dist/shims/navigation.d.ts +10 -5
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +236 -0
- package/docs/api/31-api-client.mdx +167 -0
- package/docs/api/32-api-cache.mdx +311 -0
- package/docs/api/33-api-search-params.mdx +176 -0
- package/docs/api/34-api-config.mdx +329 -0
- package/docs/api/35-api-typescript.mdx +91 -0
- package/docs/api/36-cli.mdx +192 -0
- package/docs/learn/00-introduction.mdx +109 -0
- package/docs/learn/01-quick-start.mdx +94 -0
- package/docs/learn/02-pages-and-layouts.mdx +147 -0
- package/docs/learn/03-fetching-data.mdx +211 -0
- package/docs/learn/04-access-control.mdx +115 -0
- package/docs/learn/05-the-flush-point.mdx +175 -0
- package/docs/learn/06-typed-params.mdx +275 -0
- package/docs/learn/07-typed-routes.mdx +108 -0
- package/docs/learn/08-forms-and-actions.mdx +146 -0
- package/docs/learn/09-streaming.mdx +140 -0
- package/docs/learn/10-caching.mdx +252 -0
- package/docs/learn/11-middleware.mdx +158 -0
- package/docs/learn/12-error-handling.mdx +187 -0
- package/docs/learn/13-deploying.mdx +287 -0
- package/llms.txt +55 -0
- package/package.json +116 -30
- package/src/adapters/build-output-helper.ts +351 -0
- package/src/adapters/cloudflare-dev.ts +183 -0
- package/src/adapters/cloudflare-kv-cache.ts +207 -0
- package/src/adapters/cloudflare.ts +747 -130
- package/src/adapters/compress-module.ts +101 -88
- package/src/adapters/fs-identity.ts +156 -0
- package/src/adapters/nitro-presets.ts +139 -0
- package/src/adapters/nitro-preview.ts +340 -0
- package/src/adapters/nitro.ts +249 -426
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/adapters/shared.ts +274 -0
- package/src/adapters/types.ts +28 -7
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/analyze/chains.ts +411 -0
- package/src/analyze/classify.ts +258 -0
- package/src/analyze/crawl-entry.ts +68 -0
- package/src/analyze/crawl.ts +500 -0
- package/src/analyze/graph-cache.ts +332 -0
- package/src/analyze/graph-command.ts +762 -0
- package/src/analyze/live-graph.ts +232 -0
- package/src/analyze/poison-rules.ts +165 -0
- package/src/analyze/poison-scan.ts +162 -0
- package/src/analyze/scan.ts +149 -0
- package/src/cache/cache-api.ts +107 -0
- package/src/cache/fast-hash.ts +5 -0
- package/src/cache/handler-store.ts +76 -0
- package/src/cache/index.ts +115 -22
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/json-lossy-check.ts +75 -0
- package/src/cache/redis-handler.ts +198 -20
- package/src/cache/singleflight.ts +69 -6
- package/src/cache/sizeof.ts +33 -0
- package/src/cache/stable-stringify.ts +65 -2
- package/src/cache/store.ts +71 -0
- package/src/cache/stores/cloudflare-kv.ts +52 -0
- package/src/cache/stores/memory.ts +125 -0
- package/src/cache/stores/redis.ts +97 -0
- package/src/cache/stores/vercel.ts +59 -0
- package/src/cache/tag-aware-handler.ts +237 -0
- package/src/cache/timber-cache.ts +165 -40
- package/src/cdn/cloudflare-purge.ts +50 -0
- package/src/cdn/fastly-purge.ts +63 -0
- package/src/cdn/headers.ts +153 -0
- package/src/cdn/index.ts +23 -0
- package/src/cdn/purge-store.ts +34 -0
- package/src/cdn/workers-cache-purge.ts +34 -0
- package/src/cli-check.ts +507 -0
- package/src/cli-schema-sync.ts +401 -0
- package/src/cli.ts +323 -62
- package/src/client/browser-dev.ts +157 -2
- package/src/client/browser-entry/action-dispatch.ts +209 -0
- package/src/client/browser-entry/action-queue.ts +152 -0
- package/src/client/browser-entry/hmr.ts +70 -0
- package/src/client/browser-entry/hydrate.ts +148 -0
- package/src/client/browser-entry/index.ts +131 -0
- package/src/client/browser-entry/post-hydration.ts +123 -0
- package/src/client/browser-entry/router-init.ts +418 -0
- package/src/client/browser-entry/rsc-stream.ts +222 -0
- package/src/client/browser-entry/scroll.ts +50 -0
- package/src/client/deny-last-resort.tsx +54 -0
- package/src/client/error-boundary.tsx +289 -39
- package/src/client/error-reconstituter.tsx +79 -0
- package/src/client/form.tsx +36 -32
- package/src/client/global-context.ts +31 -0
- package/src/client/history.ts +81 -10
- package/src/client/index.ts +89 -53
- package/src/client/internal.ts +59 -0
- package/src/client/link.tsx +439 -151
- package/src/client/location-search.ts +15 -0
- package/src/client/navigation-api.ts +347 -0
- package/src/client/navigation-commit.ts +295 -0
- package/src/client/navigation-context.ts +67 -98
- package/src/client/navigation-root.tsx +224 -0
- package/src/client/navigation-transition.ts +327 -0
- package/src/client/nuqs-adapter.tsx +21 -9
- package/src/client/params-context.ts +187 -0
- package/src/client/react-root.ts +72 -0
- package/src/client/router-effects.ts +228 -0
- package/src/client/router-lifecycle.ts +354 -0
- package/src/client/router-pipeline.ts +490 -0
- package/src/client/router-ref.ts +3 -3
- package/src/client/router-skew.ts +30 -0
- package/src/client/router-types.ts +294 -0
- package/src/client/router.ts +435 -421
- package/src/client/rsc-fetch.ts +512 -73
- package/src/client/segment-cache.ts +327 -40
- package/src/client/segment-context.ts +7 -4
- package/src/client/segment-outlet.tsx +96 -0
- package/src/client/segment-update-context.ts +23 -0
- package/src/client/shallow-url.ts +22 -0
- package/src/client/slot-content-cache-context.ts +43 -0
- package/src/client/slot-context.ts +50 -0
- package/src/client/slot-outlet.tsx +22 -0
- package/src/client/slot-provider.tsx +32 -0
- package/src/client/ssr-data.ts +30 -9
- package/src/client/stale-client.ts +191 -0
- package/src/client/state.ts +29 -15
- package/src/client/status-page-marker.tsx +32 -0
- package/src/client/top-loader.tsx +13 -10
- package/src/client/unload-guard.ts +35 -3
- package/src/client/use-cookie.ts +70 -18
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-pathname.ts +22 -31
- package/src/client/use-pending-navigation.ts +40 -0
- package/src/client/use-query-states.ts +206 -36
- package/src/client/use-router.ts +6 -3
- package/src/client/use-search-params.ts +38 -49
- package/src/client/use-segment-params.ts +69 -0
- package/src/client/use-selected-layout-segment.ts +2 -2
- package/src/codec.ts +149 -0
- package/src/config-types.ts +322 -0
- package/src/config-validation.ts +347 -0
- package/src/cookies/define-cookie.ts +222 -53
- package/src/cookies/index.ts +13 -2
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +192 -0
- package/src/dev-tools/404-page.ts +286 -0
- package/src/dev-tools/browser-logs.ts +55 -0
- package/src/dev-tools/debug-channel.ts +151 -0
- package/src/dev-tools/dev-page-shell.ts +260 -0
- package/src/dev-tools/error-page.ts +331 -0
- package/src/dev-tools/holding-server.ts +185 -0
- package/src/dev-tools/hydration-overlay.ts +158 -0
- package/src/dev-tools/index.ts +83 -0
- package/src/dev-tools/instrumentation.ts +213 -0
- package/src/{server/dev-logger.ts → dev-tools/logger.ts} +33 -51
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +122 -26
- package/src/dev-tools/overlay.ts +469 -0
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +182 -0
- package/src/fonts/ast-walk.ts +235 -0
- package/src/fonts/ast.ts +479 -128
- package/src/fonts/bundle.ts +138 -0
- package/src/fonts/css.ts +1 -1
- package/src/fonts/dev-middleware.ts +85 -0
- package/src/fonts/fallbacks.ts +0 -23
- package/src/fonts/google.ts +101 -19
- package/src/fonts/local.ts +12 -11
- package/src/fonts/paths.ts +58 -0
- package/src/fonts/pipeline.ts +348 -0
- package/src/fonts/transform.ts +311 -0
- package/src/fonts/types.ts +52 -1
- package/src/fonts/virtual-modules.ts +179 -0
- package/src/index.ts +482 -377
- package/src/params/codec-registry.ts +34 -0
- package/src/params/define-schema.ts +115 -0
- package/src/params/index.ts +17 -0
- package/src/params/resolve-schema.ts +84 -0
- package/src/plugin-context.ts +503 -0
- package/src/plugins/adapter-build.ts +229 -7
- package/src/plugins/build-manifest.ts +201 -26
- package/src/plugins/build-report.ts +259 -47
- package/src/plugins/cache.ts +243 -0
- package/src/plugins/callsite-ast.ts +472 -0
- package/src/plugins/callsite-jsx.ts +243 -0
- package/src/plugins/chunks.ts +74 -5
- package/src/plugins/client-chunks.ts +185 -0
- package/src/plugins/cloudflare-wasm.ts +141 -0
- package/src/plugins/content.ts +5 -1
- package/src/plugins/dev-discovery.ts +218 -0
- package/src/plugins/dev-server.ts +418 -94
- package/src/plugins/entries.ts +141 -16
- package/src/plugins/fonts.ts +234 -659
- package/src/plugins/graph-endpoint.ts +532 -0
- package/src/plugins/mdx.ts +108 -35
- package/src/plugins/prebuilt-capture.ts +217 -0
- package/src/plugins/prebuilt-options-analysis.ts +175 -0
- package/src/plugins/prebuilt.ts +655 -0
- package/src/plugins/prerender-sugar.ts +320 -0
- package/src/plugins/request-dep/analysis.ts +447 -0
- package/src/plugins/request-dep/index.ts +376 -0
- package/src/plugins/request-dep/origin.ts +310 -0
- package/src/plugins/routing.ts +273 -277
- package/src/plugins/server-bundle.ts +99 -14
- package/src/plugins/shims.ts +259 -97
- package/src/plugins/static-build.ts +708 -66
- package/src/react-canary.d.ts +2 -0
- package/src/routing/codegen-shared.ts +39 -0
- package/src/routing/codegen-types.ts +62 -0
- package/src/routing/codegen-write.ts +141 -0
- package/src/routing/codegen.ts +349 -232
- package/src/routing/collision-probe.ts +438 -0
- package/src/routing/collision-spaces.ts +281 -0
- package/src/routing/convention-lint.ts +516 -0
- package/src/routing/export-detect.ts +448 -0
- package/src/routing/file-cache.ts +23 -0
- package/src/routing/index.ts +16 -7
- package/src/routing/interception-overlap.ts +141 -0
- package/src/routing/interception.ts +1044 -67
- package/src/routing/link-codegen.ts +280 -0
- package/src/routing/manifest-codegen.ts +226 -0
- package/src/routing/scanner.ts +408 -223
- package/src/routing/schema-validation.ts +155 -0
- package/src/routing/segment-classify.ts +280 -0
- package/src/routing/segment-codegen.ts +98 -0
- package/src/routing/segment-keys.ts +186 -0
- package/src/routing/slot-placement.ts +97 -0
- package/src/routing/types.ts +75 -26
- package/src/routing/walkers.ts +98 -0
- package/src/rsc-runtime/rsc.ts +9 -0
- package/src/rsc-runtime/ssr.ts +51 -0
- package/src/rsc-runtime/transforms.ts +13 -0
- package/src/rsc-runtime/vendor-types.d.ts +19 -0
- package/src/schema-bridge.ts +380 -0
- package/src/search-params/define.ts +677 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/parse-total.ts +91 -0
- package/src/search-params/serialize-equal.ts +14 -0
- package/src/search-params/wrappers.ts +150 -0
- package/src/server/access-gate.tsx +194 -56
- package/src/server/action-client.ts +122 -31
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +256 -56
- package/src/server/actions.ts +112 -68
- package/src/server/als-registry.ts +160 -21
- package/src/server/asset-headers.ts +15 -37
- package/src/server/body-limits.ts +10 -2
- package/src/server/build-manifest.ts +33 -57
- package/src/server/canonicalize.ts +6 -3
- package/src/server/chain-url-parts.ts +163 -0
- package/src/server/children-interception.ts +115 -0
- package/src/server/coalesce-tick.ts +75 -0
- package/src/server/compress.ts +43 -8
- package/src/server/cookie-context.ts +484 -0
- package/src/server/cookie-parsing.ts +163 -0
- package/src/server/csp-nonce.ts +70 -0
- package/src/server/csrf.ts +39 -6
- package/src/server/default-logger.ts +99 -0
- package/src/server/default-status-page.ts +88 -0
- package/src/server/deny-boundary.ts +515 -0
- package/src/server/deny-renderer.ts +211 -113
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +4 -3
- package/src/server/early-hints.ts +39 -29
- package/src/server/error-boundary-wrapper.ts +157 -44
- package/src/server/error-response-headers.ts +18 -0
- package/src/server/fallback-error.ts +79 -102
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +67 -0
- package/src/server/form-data.ts +124 -12
- package/src/server/form-flash.ts +2 -2
- package/src/server/head-response.ts +54 -0
- package/src/server/html-injector-core.ts +512 -0
- package/src/server/html-injectors.ts +272 -255
- package/src/server/index.ts +40 -192
- package/src/server/instrumentation.ts +1 -1
- package/src/server/internal.ts +173 -0
- package/src/server/logger.ts +73 -37
- package/src/server/metadata-collector.ts +174 -0
- package/src/server/metadata-platform.ts +2 -2
- package/src/server/metadata-render.ts +30 -8
- package/src/server/metadata-routes.ts +205 -24
- package/src/server/metadata-social.ts +2 -2
- package/src/server/metadata.ts +23 -2
- package/src/server/middleware-runner.ts +32 -5
- package/src/server/node-stream-transforms.ts +323 -0
- package/src/server/nuqs-ssr-provider.tsx +8 -7
- package/src/server/param-coercion.ts +198 -0
- package/src/server/pipeline-helpers.ts +159 -0
- package/src/server/pipeline-interception.ts +109 -33
- package/src/server/pipeline-metadata.ts +15 -1
- package/src/server/pipeline-outcome.ts +218 -0
- package/src/server/pipeline-phases.ts +606 -0
- package/src/server/pipeline.ts +333 -384
- package/src/server/port-resolution.ts +53 -0
- package/src/server/prebuilt/cache-key.ts +299 -0
- package/src/server/prebuilt/capture-state.ts +89 -0
- package/src/server/prebuilt/key-discipline.ts +122 -0
- package/src/server/prebuilt/manifest-tag-index.ts +46 -0
- package/src/server/prebuilt/overlay.ts +256 -0
- package/src/server/prebuilt/payload-source.ts +202 -0
- package/src/server/prebuilt/slots.ts +190 -0
- package/src/server/prebuilt/synthetic-store.ts +122 -0
- package/src/server/prebuilt-builder.ts +804 -0
- package/src/server/prebuilt-runtime.ts +817 -0
- package/src/server/primitives.ts +240 -98
- package/src/server/publish-params.ts +42 -0
- package/src/server/render-timeout.ts +108 -0
- package/src/server/render-utils.ts +35 -0
- package/src/server/request-context.ts +244 -334
- package/src/server/request-dep.ts +37 -0
- package/src/server/response-cache-policy.ts +45 -0
- package/src/server/route-element-builder.ts +508 -355
- package/src/server/route-element-helpers.ts +37 -0
- package/src/server/route-handler.ts +40 -13
- package/src/server/route-matcher.ts +165 -272
- package/src/server/route-module-loader.ts +161 -0
- package/src/server/rsc-cache-key-guard.ts +122 -0
- package/src/server/rsc-entry/action-middleware-runner.ts +174 -0
- package/src/server/rsc-entry/api-handler.ts +78 -34
- package/src/server/rsc-entry/deny-fallback.ts +93 -0
- package/src/server/rsc-entry/error-renderer.ts +341 -91
- package/src/server/rsc-entry/helpers.ts +180 -106
- package/src/server/rsc-entry/index.ts +371 -331
- package/src/server/rsc-entry/render-route.ts +315 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +350 -0
- package/src/server/rsc-entry/rsc-payload.ts +209 -55
- package/src/server/rsc-entry/rsc-stream.ts +154 -26
- package/src/server/rsc-entry/ssr-bridge.ts +18 -5
- package/src/server/rsc-entry/ssr-renderer.ts +317 -60
- package/src/server/rsc-entry/wrap-action-dispatch.ts +186 -0
- package/src/server/rsc-error-envelope.ts +18 -0
- package/src/server/rsc-prop-warnings.ts +1 -1
- package/src/server/safe-load.ts +60 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/server-only-guard-noop.js +3 -0
- package/src/server/server-timing.ts +1 -1
- package/src/server/sitemap-generator.ts +337 -0
- package/src/server/sitemap-handler.ts +157 -0
- package/src/server/skippable-prefix.ts +172 -0
- package/src/server/slot-interception.ts +168 -0
- package/src/server/slot-resolver.ts +707 -300
- package/src/server/slot-subtree-contain.ts +255 -0
- package/src/server/ssr-bridge-types.ts +165 -0
- package/src/server/ssr-entry.ts +230 -85
- package/src/server/ssr-render.ts +357 -85
- package/src/server/ssr-wrappers.tsx +162 -0
- package/src/server/state-tree-diff.ts +85 -30
- package/src/server/static-generator.ts +715 -0
- package/src/server/static-not-found.ts +134 -0
- package/src/server/status-code-resolver.ts +107 -148
- package/src/server/stream-utils.ts +292 -0
- package/src/server/tracing.ts +128 -16
- package/src/server/tree-match.ts +262 -0
- package/src/server/types.ts +95 -10
- package/src/server/utils/element-type.ts +88 -0
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/waituntil-bridge.ts +1 -1
- package/src/server/workers-cache-bridge.ts +33 -0
- package/src/shared/als-slots.ts +74 -0
- package/src/shared/base-path.ts +80 -0
- package/src/shared/href-validation.ts +159 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shared/param-value.ts +281 -0
- package/src/shared/payload-root.ts +152 -0
- package/src/shared/redirect-type.ts +17 -0
- package/src/shared/rsc-cache-key.ts +269 -0
- package/src/shared/rsc-error-envelope.ts +16 -0
- package/src/shared/rsc-manifest.ts +29 -0
- package/src/shared/rsc-media-type.ts +59 -0
- package/src/shared/rsc-payload-path.ts +45 -0
- package/src/shared/segment-info.ts +67 -0
- package/src/shared/slot-params.ts +109 -0
- package/src/shared/static-platform-files.ts +75 -0
- package/src/shared/status-reason-phrase.ts +61 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +122 -1
- package/src/shims/navigation-client.ts +36 -32
- package/src/shims/navigation-rsc.ts +47 -0
- package/src/shims/navigation.ts +10 -7
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js +0 -41
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-B3Gypr3D.js +0 -108
- package/dist/_chunks/debug-B3Gypr3D.js.map +0 -1
- package/dist/_chunks/format-RyoGQL74.js +0 -164
- package/dist/_chunks/format-RyoGQL74.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js +0 -676
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/metadata-routes-Cjmvi3rQ.js.map +0 -1
- package/dist/_chunks/request-context-BQUC8PHn.js +0 -330
- package/dist/_chunks/request-context-BQUC8PHn.js.map +0 -1
- package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
- package/dist/_chunks/tracing-CemImE6h.js +0 -187
- package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/_chunks/use-query-states-D5KaffOK.js +0 -109
- package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
- package/dist/adapters/cloudflare.js.map +0 -1
- package/dist/cache/index.js.map +0 -1
- package/dist/cache/register-cached-function.d.ts +0 -17
- package/dist/cache/register-cached-function.d.ts.map +0 -1
- package/dist/client/browser-entry.d.ts +0 -21
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/error-boundary.js.map +0 -1
- package/dist/client/head.d.ts +0 -16
- package/dist/client/head.d.ts.map +0 -1
- package/dist/client/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/client/segment-merger.d.ts +0 -119
- package/dist/client/segment-merger.d.ts.map +0 -1
- package/dist/client/stale-reload.d.ts +0 -44
- package/dist/client/stale-reload.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts +0 -74
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts +0 -26
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/client/use-params.d.ts +0 -92
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/content/index.d.ts +0 -11
- package/dist/content/index.d.ts.map +0 -1
- package/dist/content/index.js +0 -2
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts +0 -60
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/plugins/server-action-exports.d.ts +0 -26
- package/dist/plugins/server-action-exports.d.ts.map +0 -1
- package/dist/routing/status-file-lint.d.ts +0 -33
- package/dist/routing/status-file-lint.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/codecs.d.ts +0 -53
- package/dist/search-params/codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/search-params/registry.d.ts +0 -20
- package/dist/search-params/registry.d.ts.map +0 -1
- package/dist/server/client-module-map.d.ts +0 -47
- package/dist/server/client-module-map.d.ts.map +0 -1
- package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
- package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts +0 -29
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts +0 -129
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/flush.d.ts +0 -74
- package/dist/server/flush.d.ts.map +0 -1
- package/dist/server/manifest-status-resolver.d.ts +0 -58
- package/dist/server/manifest-status-resolver.d.ts.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/tree-builder.d.ts +0 -126
- package/dist/server/tree-builder.d.ts.map +0 -1
- package/dist/utils/directive-parser.d.ts +0 -70
- package/dist/utils/directive-parser.d.ts.map +0 -1
- package/src/cache/register-cached-function.ts +0 -103
- package/src/client/browser-entry.ts +0 -678
- package/src/client/head.ts +0 -61
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/segment-merger.ts +0 -339
- package/src/client/stale-reload.ts +0 -87
- package/src/client/transition-root.tsx +0 -166
- package/src/client/use-navigation-pending.ts +0 -38
- package/src/client/use-params.ts +0 -141
- package/src/content/index.ts +0 -13
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dev-error-overlay.ts +0 -230
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/plugins/server-action-exports.ts +0 -220
- package/src/routing/status-file-lint.ts +0 -112
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/codecs.ts +0 -153
- package/src/search-params/create.ts +0 -321
- package/src/search-params/registry.ts +0 -31
- package/src/server/client-module-map.ts +0 -58
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/dev-warnings.ts +0 -283
- package/src/server/flush.ts +0 -182
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/prerender.ts +0 -139
- package/src/server/tree-builder.ts +0 -382
- package/src/shims/server-only-noop.js +0 -6
- package/src/utils/directive-parser.ts +0 -529
|
@@ -17,26 +17,189 @@
|
|
|
17
17
|
* See design/07-routing.md §"Intercepting Routes"
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import type { SegmentNode, InterceptionMarker } from './types.
|
|
20
|
+
import type { SegmentNode, InterceptionMarker, RouteFile } from './types.ts';
|
|
21
|
+
import { computeSegmentTreePaths, treePathDepth } from './segment-keys.ts';
|
|
22
|
+
import { classifyUrlSegment, effectiveUrlSegment } from './segment-classify.ts';
|
|
23
|
+
// Every collision space — the main tree, each slot, each intercepting subtree
|
|
24
|
+
// — decides order-dependence with the same oracle, so the spaces cannot drift
|
|
25
|
+
// on what counts as two pages answering one URL. See TIM-1308.
|
|
26
|
+
import { findOrderDependentCollision, type ProbeLeaf } from './collision-probe.ts';
|
|
27
|
+
import { interceptedPatternsOverlap } from './interception-overlap.ts';
|
|
21
28
|
|
|
22
|
-
/**
|
|
23
|
-
|
|
29
|
+
/** Fields shared by both interception shapes. */
|
|
30
|
+
interface InterceptionRewriteBase {
|
|
24
31
|
/**
|
|
25
32
|
* The URL pattern that this rewrite intercepts (the target of navigation).
|
|
26
33
|
* E.g., "/photo/[id]" for a (.)photo/[id] interception.
|
|
27
34
|
*/
|
|
28
35
|
interceptedPattern: string;
|
|
29
36
|
/**
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
32
|
-
*
|
|
37
|
+
* The tree path of the segment that OWNS the slot holding this
|
|
38
|
+
* intercepting route (`computeSegmentTreePaths`, e.g. "/feed",
|
|
39
|
+
* "/(browse)", "/(browse)/feed", or "/" at the app root).
|
|
40
|
+
*
|
|
41
|
+
* The rewrite only applies when the source route — the page the user is
|
|
42
|
+
* navigating FROM — passes through that directory, because only then
|
|
43
|
+
* does the slot holding the intercepting page exist in the rendered
|
|
44
|
+
* tree. The server checks this by matching X-Timber-URL and testing its
|
|
45
|
+
* segment chain's tree paths for this value.
|
|
46
|
+
*
|
|
47
|
+
* Neither of the identities already in the codebase works here:
|
|
48
|
+
*
|
|
49
|
+
* - A **URL prefix** cannot express it. Route groups contribute nothing
|
|
50
|
+
* to `urlPath`, so `(browse)/@detail/(...)x` and a genuinely
|
|
51
|
+
* root-level `@modal/(...)x` both have prefix "/" while meaning very
|
|
52
|
+
* different things.
|
|
53
|
+
* - A **state-tree key** (`computeSegmentKeys`) cannot either. It
|
|
54
|
+
* qualifies a group with its ancestry but resets to `urlPath` at the
|
|
55
|
+
* next URL-visible segment, so `(browse)/feed` and `(landing)/feed`
|
|
56
|
+
* both key as "/feed" — and a navigation inside `(landing)/feed/…`
|
|
57
|
+
* would reach `(browse)/feed`'s slot.
|
|
58
|
+
*
|
|
59
|
+
* Tree paths never reset, so two directories that render different
|
|
60
|
+
* layouts never share one. "/" as a scope means the app root, which
|
|
61
|
+
* every route passes through — preserving the intentional
|
|
62
|
+
* match-from-anywhere behavior of a root-level `(...)` interception
|
|
63
|
+
* (TIM-1006) without an exemption. See TIM-1279.
|
|
33
64
|
*/
|
|
34
|
-
|
|
65
|
+
interceptingScope: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* A conditional rewrite rule generated from an intercepting route.
|
|
70
|
+
*
|
|
71
|
+
* `mode` records which of the two shapes the directory expresses, because the
|
|
72
|
+
* two render through entirely different mechanisms and the fields they need
|
|
73
|
+
* are not the same. It is a union rather than a flag so a reader cannot
|
|
74
|
+
* re-match `interceptingPrefix` on the shape that has no such pathname.
|
|
75
|
+
*
|
|
76
|
+
* See design/07-routing.md §"Intercepting Routes".
|
|
77
|
+
*/
|
|
78
|
+
export type InterceptionRewrite = SlotInterceptionRewrite | ChildrenInterceptionRewrite;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A **modal overlay** interception — the intercepting directory is a direct
|
|
82
|
+
* child of a parallel slot (`feed/@modal/(.)photo/[id]`).
|
|
83
|
+
*
|
|
84
|
+
* The server re-matches the *source* route and the slot resolver finds the
|
|
85
|
+
* intercepting child inside the slot, so the intercepting page layers over
|
|
86
|
+
* the page the user was already on.
|
|
87
|
+
*/
|
|
88
|
+
export interface SlotInterceptionRewrite extends InterceptionRewriteBase {
|
|
89
|
+
mode: 'slot';
|
|
35
90
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
91
|
+
* The pathname the server re-matches when this rewrite applies — the
|
|
92
|
+
* intercepting slot owner's URL path. E.g., "/feed" for a (.)photo/[id]
|
|
93
|
+
* inside /feed/@modal/.
|
|
94
|
+
*
|
|
95
|
+
* This is a build-time constant, never a client-supplied value: the
|
|
96
|
+
* X-Timber-URL header selects a rewrite but never becomes the rendered
|
|
97
|
+
* pathname.
|
|
38
98
|
*/
|
|
39
|
-
|
|
99
|
+
interceptingPrefix: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A **sibling layout swap** interception — the intercepting directory is a
|
|
104
|
+
* direct child of an ordinary segment or route group
|
|
105
|
+
* (`(browse)/(...)[artistSlug]/…`).
|
|
106
|
+
*
|
|
107
|
+
* There is no overlay, no slot and no `default.tsx`: the intercepting page
|
|
108
|
+
* *replaces* `children` for the owner's layout chain. Nothing is re-matched
|
|
109
|
+
* either. The server resolves the owner by `interceptingScope` — a tree path,
|
|
110
|
+
* which identifies exactly one directory — and builds the rendered chain as
|
|
111
|
+
* `[…owner ancestors, interceptingNode, …its matched descendants]`. That is an
|
|
112
|
+
* ordinary segment chain, so `route-element-builder.ts` renders it with no
|
|
113
|
+
* knowledge that interception happened.
|
|
114
|
+
*
|
|
115
|
+
* Resolving the owner from the tree rather than from a URL is what makes this
|
|
116
|
+
* shape work where the modal shape cannot: `interceptingPrefix` is
|
|
117
|
+
* URL-derived, and a route group contributes nothing to `urlPath`, so an owner
|
|
118
|
+
* like `app/(browse)/` serializes to "/" and re-matching it lands in whichever
|
|
119
|
+
* group owns the canonical page. A tree path never collapses (TIM-1280).
|
|
120
|
+
*/
|
|
121
|
+
export interface ChildrenInterceptionRewrite extends InterceptionRewriteBase {
|
|
122
|
+
mode: 'children';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A set of sibling interceptors that compete for one URL position.
|
|
127
|
+
*
|
|
128
|
+
* `base` is the intercepted base they share — the URL their own segments sit
|
|
129
|
+
* directly under — and `anchorIndex` is how many URL parts that base spans,
|
|
130
|
+
* which is the index in a target pathname their segments are matched at.
|
|
131
|
+
* Deeper anchors are more local and are tried first.
|
|
132
|
+
*/
|
|
133
|
+
export interface InterceptorAnchorGroup<TFile> {
|
|
134
|
+
base: string;
|
|
135
|
+
anchorIndex: number;
|
|
136
|
+
interceptors: SegmentNode<TFile>[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Group an owner's intercepting children by the URL position they contend for.
|
|
141
|
+
*
|
|
142
|
+
* This is the definition of *which interceptors compete*, and it has exactly
|
|
143
|
+
* one caller shape on each side of the build: `findInterceptingMatch` resolves
|
|
144
|
+
* a group with one `matchUrlParts` walk, and
|
|
145
|
+
* `assertNoInterceptedPatternCollisions` validates the same group as one
|
|
146
|
+
* collision space. Written twice, the two would be free to disagree about what
|
|
147
|
+
* competes — and a resolver that walks a wider set than the validator checked
|
|
148
|
+
* is precisely the order-dependence the validator exists to reject (TIM-1310).
|
|
149
|
+
*
|
|
150
|
+
* Contention is keyed by the computed intercepted **base**, not by the marker:
|
|
151
|
+
* under an owner at `/feed`, `(..)` and `(...)` both base at `/` and are both
|
|
152
|
+
* matched at index 0, so they are one group. Different bases are different
|
|
153
|
+
* positions — a `(.)` interceptor can never claim a target that belongs to a
|
|
154
|
+
* `(..)` one beside it, because the base must also match the target's leading
|
|
155
|
+
* parts.
|
|
156
|
+
*
|
|
157
|
+
* The base is a URL *pattern*, so its length is its part count only because
|
|
158
|
+
* every pattern part stands for exactly one URL part. A catch-all in the base
|
|
159
|
+
* breaks that, and `assertInterceptedBaseIsCountable` rejects the shape at
|
|
160
|
+
* build time.
|
|
161
|
+
*
|
|
162
|
+
* A node missing either marker field is skipped, which `classifySegment` never
|
|
163
|
+
* produces — it sets both whenever it reports `'intercepting'`. Stating the
|
|
164
|
+
* filter here rather than defaulting the marker is what makes the validator and
|
|
165
|
+
* the resolver see the same set: such a node renders nothing either way, and a
|
|
166
|
+
* validator more permissive than the resolver would be checking a candidate
|
|
167
|
+
* that never competes while the resolver walks one nobody checked.
|
|
168
|
+
*
|
|
169
|
+
* `children` is read directly rather than flattened through route groups,
|
|
170
|
+
* matching both resolvers: the slot resolver reads `slotNode.children`, and an
|
|
171
|
+
* interceptor deeper inside a slot subtree is rejected by
|
|
172
|
+
* `validateInterceptionPlacement`. On the children path an interceptor under a
|
|
173
|
+
* route group is legal and the *group* is its owner, so it is grouped with that
|
|
174
|
+
* group's other interceptors — which is again exactly what the resolver walks,
|
|
175
|
+
* since it resolves the owner by tree path.
|
|
176
|
+
*/
|
|
177
|
+
export function groupByInterceptedAnchor<TFile>(
|
|
178
|
+
ownerUrlPath: string,
|
|
179
|
+
children: readonly SegmentNode<TFile>[]
|
|
180
|
+
): InterceptorAnchorGroup<TFile>[] {
|
|
181
|
+
const byBase = new Map<string, InterceptorAnchorGroup<TFile>>();
|
|
182
|
+
|
|
183
|
+
for (const child of children) {
|
|
184
|
+
if (child.segmentType !== 'intercepting') continue;
|
|
185
|
+
if (!child.interceptionMarker || !child.interceptedSegmentName) continue;
|
|
186
|
+
|
|
187
|
+
const base = computeInterceptedBase(ownerUrlPath, child.interceptionMarker);
|
|
188
|
+
const group = byBase.get(base);
|
|
189
|
+
if (group) {
|
|
190
|
+
group.interceptors.push(child);
|
|
191
|
+
} else {
|
|
192
|
+
byBase.set(base, {
|
|
193
|
+
base,
|
|
194
|
+
anchorIndex: base === '/' ? 0 : base.slice(1).split('/').length,
|
|
195
|
+
interceptors: [child],
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Deepest anchor first: a `(.)` interception is the most local one and wins
|
|
201
|
+
// over a `(...)` that reaches the same page from the root.
|
|
202
|
+
return [...byBase.values()].sort((a, b) => b.anchorIndex - a.anchorIndex);
|
|
40
203
|
}
|
|
41
204
|
|
|
42
205
|
/**
|
|
@@ -44,34 +207,742 @@ export interface InterceptionRewrite {
|
|
|
44
207
|
*
|
|
45
208
|
* Walks the tree recursively. For each intercepting segment, computes the
|
|
46
209
|
* intercepted URL based on the marker and the segment's position.
|
|
210
|
+
*
|
|
211
|
+
* The list is returned **deepest scope first**, which is what makes
|
|
212
|
+
* `findInterceptionMatch`'s first-match rule deterministic; see
|
|
213
|
+
* `sortByScopeDepth`.
|
|
47
214
|
*/
|
|
48
215
|
export function collectInterceptionRewrites(root: SegmentNode): InterceptionRewrite[] {
|
|
49
216
|
const rewrites: InterceptionRewrite[] = [];
|
|
50
|
-
walkForInterceptions(root, [root], rewrites);
|
|
51
|
-
return rewrites;
|
|
217
|
+
walkForInterceptions(root, [root], false, rewrites);
|
|
218
|
+
return sortByScopeDepth(rewrites);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Order the rewrites deepest scope first, so the request-time first-match rule
|
|
223
|
+
* resolves two applicable rewrites by *nesting* rather than by tree-walk order.
|
|
224
|
+
*
|
|
225
|
+
* `findInterceptionMatch` returns the first rewrite whose pattern matches the
|
|
226
|
+
* target and whose scope the source route reports. More than one can satisfy
|
|
227
|
+
* both, and the case is not exotic — an owner and a directory *beneath* it may
|
|
228
|
+
* each hold an interceptor for one URL:
|
|
229
|
+
*
|
|
230
|
+
* ```
|
|
231
|
+
* app/feed/(.)photo/page.tsx scope /feed
|
|
232
|
+
* app/feed/(a)/(.)photo/page.tsx scope /feed/(a)
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
235
|
+
* A page inside `(a)` renders both owners' layouts, so the client reports both
|
|
236
|
+
* tree paths and both scopes pass. Unsorted, the winner is whichever the
|
|
237
|
+
* filesystem enumerated first — renaming the group flips which page a click
|
|
238
|
+
* opens, the defect class TIM-1305/TIM-1308/TIM-1310 each rejected in a
|
|
239
|
+
* different space. Here it is an ambiguity between *rewrites* rather than
|
|
240
|
+
* between pages inside one walk, so no collision space sees it.
|
|
241
|
+
*
|
|
242
|
+
* **Deepest wins, and it is specified rather than rejected** because the shape
|
|
243
|
+
* is one a correct app writes on purpose: a nested layout refining the
|
|
244
|
+
* interception its parent declares, exactly as `groupByInterceptedAnchor`
|
|
245
|
+
* already prefers the deepest *anchor* within one owner. The two rules are the
|
|
246
|
+
* same preference — the more local interception is the author's more specific
|
|
247
|
+
* statement — applied at the two levels the mechanism has.
|
|
248
|
+
*
|
|
249
|
+
* Depth is counted on the **tree path**, the identity that never collapses
|
|
250
|
+
* (TIM-1279/TIM-1280); a `urlPath` prefix test would relate `(browse)` and
|
|
251
|
+
* `(landing)`, which render different layouts and share no chain. Two scopes on
|
|
252
|
+
* one rendered chain are strictly nested, so depth orders them totally, and two
|
|
253
|
+
* scopes that are *not* on one chain — sibling groups, `feed/(a)` beside
|
|
254
|
+
* `feed/(b)` — never both pass the scope check, so their relative order is not
|
|
255
|
+
* observable. That is why this sorts on depth alone rather than testing
|
|
256
|
+
* ancestry: it is a total order over the pairs that can compete, and it costs
|
|
257
|
+
* nothing per request.
|
|
258
|
+
*
|
|
259
|
+
* Sorting is stable, so rewrites sharing one scope keep tree-walk order. Equal
|
|
260
|
+
* scopes mean one owner, and of the three pairings that produces only one was
|
|
261
|
+
* ambiguous — a children-path interceptor beside a slot one — and that is now
|
|
262
|
+
* rejected at build time by `assertNoCrossModeClaims` (TIM-1319). The
|
|
263
|
+
* enumeration is in design/07-routing.md §"Selection Between Owners" rather
|
|
264
|
+
* than repeated here, so there is one place to correct if a rewrite ever grows
|
|
265
|
+
* a field that makes two of them distinguishable.
|
|
266
|
+
*/
|
|
267
|
+
function sortByScopeDepth(rewrites: InterceptionRewrite[]): InterceptionRewrite[] {
|
|
268
|
+
return rewrites.sort(
|
|
269
|
+
(a, b) => treePathDepth(b.interceptingScope) - treePathDepth(a.interceptingScope)
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Validate that every intercepting segment sits where it can actually render.
|
|
275
|
+
*
|
|
276
|
+
* There are exactly two positions a renderer exists for, and they are the two
|
|
277
|
+
* shapes interception has:
|
|
278
|
+
*
|
|
279
|
+
* 1. **Direct child of a parallel slot** — the modal overlay. The slot
|
|
280
|
+
* resolver scans a slot node's *direct children* for an intercepting
|
|
281
|
+
* segment (`server/slot-interception.ts`). Nothing between the slot and
|
|
282
|
+
* the intercepting directory is allowed, because nothing walks it.
|
|
283
|
+
* 2. **Direct child of an ordinary segment or route group** — the sibling
|
|
284
|
+
* layout swap (TIM-1280). The pipeline resolves the owner by tree path and
|
|
285
|
+
* builds the rendered chain through the intercepting node itself
|
|
286
|
+
* (`server/children-interception.ts`).
|
|
287
|
+
*
|
|
288
|
+
* Everywhere else, rewrite generation still emits a rewrite and nothing
|
|
289
|
+
* renders it: the rewrite matches the soft navigation, and the user is served
|
|
290
|
+
* the page they were already on under a changed URL (TIM-1278). The rejected
|
|
291
|
+
* positions are:
|
|
292
|
+
*
|
|
293
|
+
* - **Inside a slot subtree but not directly under the slot**
|
|
294
|
+
* (`@modal/(inner)/(.)photo`). Neither renderer applies: the slot resolver
|
|
295
|
+
* only reads direct children, and the children-path resolver builds a
|
|
296
|
+
* *chain*, which cannot express a descent through a slot.
|
|
297
|
+
* - **Inside another intercepting subtree** (`(.)a/(.)b`). Left unvalidated
|
|
298
|
+
* `collectLeavesWithRewrites` walks the inner one as an ordinary URL
|
|
299
|
+
* segment and emits a pattern containing a literal "(.)b".
|
|
300
|
+
*
|
|
301
|
+
* Two further shapes are rejected here (TIM-1288). Both are about a catch-all,
|
|
302
|
+
* and both are specific to interception: elsewhere in the tree the same
|
|
303
|
+
* shapes are inert or fail safely, and the general "nothing below a catch-all
|
|
304
|
+
* is reachable" rule is tracked as TIM-1286.
|
|
305
|
+
*
|
|
306
|
+
* And one is specific to the children path: an owner chain that binds params
|
|
307
|
+
* (see `assertOwnerChainBindsNoParams`).
|
|
308
|
+
*/
|
|
309
|
+
export function validateInterceptionPlacement(root: SegmentNode): void {
|
|
310
|
+
walkForPlacement(root, '', {
|
|
311
|
+
parentIsSlot: false,
|
|
312
|
+
inSlotSubtree: false,
|
|
313
|
+
inInterceptingSubtree: false,
|
|
314
|
+
ancestorsBindParams: false,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Reject a children-path interception whose owner chain binds params.
|
|
320
|
+
*
|
|
321
|
+
* The rendered chain is `[…owner ancestors, interceptingNode, …descendants]`,
|
|
322
|
+
* and the only pathname available to bind params from is the **target** — the
|
|
323
|
+
* URL being navigated to. The intercepting subtree's own params come from it
|
|
324
|
+
* by construction. The owner chain's do not, in general:
|
|
325
|
+
*
|
|
326
|
+
* - With a climbing marker the owner's URL segments are not in the target at
|
|
327
|
+
* all. `app/[team]/(..)photo/[id]` bases at "/", so the target is
|
|
328
|
+
* `/photo/9` — there is no team value anywhere in it, and `[team]`'s layout
|
|
329
|
+
* would render with the param it declares missing.
|
|
330
|
+
* - With `(.)` the base *is* the owner's `urlPath`, so the target's leading
|
|
331
|
+
* parts would bind it. Supporting only that half means one marker behaves
|
|
332
|
+
* differently from its siblings for reasons the author cannot see from the
|
|
333
|
+
* directory names, so the rule is stated once, on the owner chain.
|
|
334
|
+
*
|
|
335
|
+
* A layout that silently renders without the param it declares is the failure
|
|
336
|
+
* this prevents; it is rejected where it can be explained rather than left to
|
|
337
|
+
* surface as `undefined` deep inside user code. Route groups and static
|
|
338
|
+
* segments bind nothing and are unrestricted, which is the whole motivating
|
|
339
|
+
* shape (`app/(browse)/(...)[artistSlug]/…`).
|
|
340
|
+
*
|
|
341
|
+
* The rule stops at a slot boundary: a slot-mode interception re-matches the
|
|
342
|
+
* *source* route, which supplies the owner's params, so a dynamic owner is
|
|
343
|
+
* fine there and always has been.
|
|
344
|
+
*/
|
|
345
|
+
/**
|
|
346
|
+
* Require a children-path interception's owner to have a `layout.tsx`.
|
|
347
|
+
*
|
|
348
|
+
* The scope is the owner's tree path, and the client reports which tree paths
|
|
349
|
+
* it has mounted from `X-Timber-Segments` — which carries **one entry per
|
|
350
|
+
* layout-bearing segment**, because those are the segments the client needs an
|
|
351
|
+
* outlet and a cache node for. `buildSegmentInfo` skips the rest.
|
|
352
|
+
*
|
|
353
|
+
* For the modal shape that set is exactly the set of possible scope owners, by
|
|
354
|
+
* construction: a slot is only resolved inside a rendering layout
|
|
355
|
+
* (`route-element-builder.ts`), so a layoutless segment can never own one. A
|
|
356
|
+
* children-path interception broke that equivalence — its owner is an ordinary
|
|
357
|
+
* directory and needs no layout.
|
|
358
|
+
*
|
|
359
|
+
* Left unchecked the result is a swap that works exactly once: the first soft
|
|
360
|
+
* navigation renders, then the client reports no such tree path, and the next
|
|
361
|
+
* navigation fails the scope check and falls back to the canonical page. That
|
|
362
|
+
* is fail-safe but silent, and the address-bar channel cannot recover it —
|
|
363
|
+
* once the swap is on screen the address holds the *intercepted* URL, which
|
|
364
|
+
* re-matches the canonical chain (the TIM-1282 problem, in the one shape the
|
|
365
|
+
* rendered-scope fix does not reach).
|
|
366
|
+
*
|
|
367
|
+
* Requiring the layout restores the invariant the state tree is built on
|
|
368
|
+
* rather than widening the wire format to carry segments that own no outlet
|
|
369
|
+
* and no payload. It also costs the author nothing they were not already
|
|
370
|
+
* doing: the point of this shape is to render inside the owner's own layout,
|
|
371
|
+
* so an owner with no layout has no chrome to preserve.
|
|
372
|
+
*/
|
|
373
|
+
function assertOwnerHasLayout(ownerPath: string, childPath: string): void {
|
|
374
|
+
const owner = ownerPath || '(app root)';
|
|
375
|
+
throw new Error(
|
|
376
|
+
`Build error: intercepting route whose owner has no layout.\n` +
|
|
377
|
+
` Directory: app/${childPath}\n` +
|
|
378
|
+
` Owner: app/${owner}\n` +
|
|
379
|
+
`An intercepting directory outside a parallel slot renders inside its owner's ` +
|
|
380
|
+
`layout chain, and the owner must have a layout.tsx: the client reports which ` +
|
|
381
|
+
`directories it has mounted from its layout segments, and a scope it cannot ` +
|
|
382
|
+
`report would let the interception fire once and then silently stop.\n` +
|
|
383
|
+
`Add app/${owner}/layout.tsx (a pass-through returning {children} is enough), or ` +
|
|
384
|
+
`move the interception under a directory that has one.\n` +
|
|
385
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function assertOwnerChainBindsNoParams(childPath: string, marker: InterceptionMarker): void {
|
|
390
|
+
throw new Error(
|
|
391
|
+
`Build error: intercepting route under a dynamic segment.\n` +
|
|
392
|
+
` Directory: app/${childPath}\n` +
|
|
393
|
+
`An intercepting directory outside a parallel slot renders inside its own ` +
|
|
394
|
+
`layout chain, and the only pathname available to bind params from is the ` +
|
|
395
|
+
`intercepted URL — which does not carry the values of the segments above ` +
|
|
396
|
+
`"${marker}".\n` +
|
|
397
|
+
`Move the interception so every directory above it is a static segment or a ` +
|
|
398
|
+
`route group, or place it inside a parallel slot (@modal/) to render it as an ` +
|
|
399
|
+
`overlay over the source route instead.\n` +
|
|
400
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Reject an intercepting route whose intercepted level is not well-defined.
|
|
406
|
+
*
|
|
407
|
+
* "One level up" is counted in URL segments, which works because every
|
|
408
|
+
* pattern part stands for exactly one URL part — except a catch-all, which
|
|
409
|
+
* stands for a number that varies per request. `anchorIndex` fixes the anchor
|
|
410
|
+
* at the base's pattern length, so with an owner at `/docs/[...path]` the
|
|
411
|
+
* interception resolves when the catch-all consumed exactly one segment
|
|
412
|
+
* (`/docs/a/photo/5`) and is dropped when it consumed more
|
|
413
|
+
* (`/docs/a/b/photo/5`), because the base no longer matches the target's
|
|
414
|
+
* leading parts.
|
|
415
|
+
*
|
|
416
|
+
* Dropping is fail-safe — the canonical route renders, as on hard navigation
|
|
417
|
+
* — so this is never a wrong page. But it is a modal that opens at one depth
|
|
418
|
+
* and silently does not at another, with nothing to tell the author why, and
|
|
419
|
+
* no request-time input can fix it: the only available source depth is
|
|
420
|
+
* `X-Timber-URL`, which is the browser's address bar, and once a modal is
|
|
421
|
+
* open that holds the *intercepted* URL rather than the source.
|
|
422
|
+
*
|
|
423
|
+
* So the shape is rejected where it can be explained. A marker that climbs
|
|
424
|
+
* *past* the catch-all is fine — `(..)` from `/docs/[...path]` bases at
|
|
425
|
+
* `/docs` — and so is `(...)`, which always bases at the root. The rule is on
|
|
426
|
+
* the *computed* base, not on having a catch-all anywhere above.
|
|
427
|
+
*/
|
|
428
|
+
function assertInterceptedBaseIsCountable(
|
|
429
|
+
child: SegmentNode,
|
|
430
|
+
ownerUrlPath: string,
|
|
431
|
+
childPath: string
|
|
432
|
+
): void {
|
|
433
|
+
const marker = child.interceptionMarker ?? '(.)';
|
|
434
|
+
const base = computeInterceptedBase(ownerUrlPath, marker);
|
|
435
|
+
const baseParts = base === '/' ? [] : base.slice(1).split('/');
|
|
436
|
+
const ambiguous = baseParts.find((part) => {
|
|
437
|
+
const kind = classifyUrlSegment(part).kind;
|
|
438
|
+
return kind === 'catch-all' || kind === 'optional-catch-all';
|
|
439
|
+
});
|
|
440
|
+
if (!ambiguous) return;
|
|
441
|
+
|
|
442
|
+
throw new Error(
|
|
443
|
+
`Build error: intercepting route below a catch-all segment.\n` +
|
|
444
|
+
` Directory: app/${childPath}\n` +
|
|
445
|
+
` Intercepted base: ${base}\n` +
|
|
446
|
+
`A catch-all (${ambiguous}) matches a number of URL segments that varies per ` +
|
|
447
|
+
`request, so "${marker}" cannot identify which segment of a target pathname the ` +
|
|
448
|
+
`interception starts at — the modal would open at one depth and silently not at ` +
|
|
449
|
+
`another.\n` +
|
|
450
|
+
`Move the interception above the catch-all, or use a marker that climbs past it ` +
|
|
451
|
+
`((..) or (...)).\n` +
|
|
452
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Reject a catch-all inside an intercepting subtree that has directories
|
|
458
|
+
* below it.
|
|
459
|
+
*
|
|
460
|
+
* A catch-all consumes the whole remaining path, so nothing under it is
|
|
461
|
+
* reachable — `matchUrlParts` only accepts a catch-all as a terminal leaf and
|
|
462
|
+
* never descends past one. Rewrite generation is not so strict: it walks the
|
|
463
|
+
* subtree and emits `/feed/[...rest]/child`, and `pathnameMatchesPattern`
|
|
464
|
+
* returns as soon as it reaches the catch-all without ever looking at
|
|
465
|
+
* `child`. So the rewrite matches the navigation and then no renderer exists
|
|
466
|
+
* — the TIM-1278 failure mode reached by a different route, with the user
|
|
467
|
+
* served the page they were already on under a changed URL.
|
|
468
|
+
*
|
|
469
|
+
* The check covers the whole intercepting subtree, not just the intercepted
|
|
470
|
+
* segment: `(.)photo/[...rest]/child` emits `/feed/photo/[...rest]/child` and
|
|
471
|
+
* hijacks `/feed/photo/a/b` by exactly the same mechanism. And it does not
|
|
472
|
+
* exempt a catch-all that carries its own page — that one does render, but
|
|
473
|
+
* the rewrite generated for the unreachable descendant is broader than any
|
|
474
|
+
* route in the tree, so the tail modal fires on navigations no directory
|
|
475
|
+
* describes.
|
|
476
|
+
*
|
|
477
|
+
* Outside a slot the same shape merely 404s, which is why the general rule is
|
|
478
|
+
* tracked separately (TIM-1286); here it is unsafe, and it only became
|
|
479
|
+
* reachable when catch-all intercepted segments started matching at all
|
|
480
|
+
* (TIM-1281).
|
|
481
|
+
*
|
|
482
|
+
* The walk descends `children` and not `slots`, mirroring
|
|
483
|
+
* `collectLeavesWithRewrites` exactly: what this rejects is precisely the set
|
|
484
|
+
* of paths rewrite generation emits, so the two cannot disagree about which
|
|
485
|
+
* shapes exist. A slot nested inside an intercepting subtree produces no
|
|
486
|
+
* rewrite and so cannot hijack anything.
|
|
487
|
+
*/
|
|
488
|
+
function assertInterceptedCatchAllsAreTerminal(node: SegmentNode, nodePath: string): void {
|
|
489
|
+
const { segmentType, segmentName } = effectiveUrlSegment(node);
|
|
490
|
+
const isCatchAll = segmentType === 'catch-all' || segmentType === 'optional-catch-all';
|
|
491
|
+
|
|
492
|
+
if (isCatchAll && node.children.length > 0) {
|
|
493
|
+
throw new Error(
|
|
494
|
+
`Build error: catch-all with nested segments inside an intercepting route.\n` +
|
|
495
|
+
` Directory: app/${nodePath}\n` +
|
|
496
|
+
` Nested: ${node.children.map((c) => c.segmentName).join(', ')}\n` +
|
|
497
|
+
`A catch-all (${segmentName}) consumes every remaining URL segment, so nothing ` +
|
|
498
|
+
`below it can ever match — but the interception rewrite would still be generated ` +
|
|
499
|
+
`and would hijack the navigation with no page to render.\n` +
|
|
500
|
+
`Move the nested routes above the catch-all, or intercept a named segment instead.\n` +
|
|
501
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
for (const child of node.children) {
|
|
506
|
+
assertInterceptedCatchAllsAreTerminal(child, `${nodePath}/${child.segmentName}`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Reject a `route.ts` anywhere inside an intercepting subtree.
|
|
512
|
+
*
|
|
513
|
+
* An interception is a soft-navigation variant of a page — it swaps which
|
|
514
|
+
* page component renders. A route handler returns a `Response` and cannot
|
|
515
|
+
* be an interception target: `walkInterceptedLeaves` visits `node.page`
|
|
516
|
+
* only, so no rewrite is emitted for it, but `isTerminal` in
|
|
517
|
+
* `tree-match.ts` counts both `page` and `route`, so `matchUrlParts` can
|
|
518
|
+
* resolve to the route handler. `slot-interception.ts` then drops the
|
|
519
|
+
* match (`if (!leaf.page) continue`), silently disabling the page's
|
|
520
|
+
* interception. Fail-safe (the canonical route renders) but silent.
|
|
521
|
+
*
|
|
522
|
+
* The walk mirrors `assertInterceptedCatchAllsAreTerminal`: it descends
|
|
523
|
+
* `children` (not `slots`), matching `collectLeavesWithRewrites` exactly.
|
|
524
|
+
*/
|
|
525
|
+
function assertNoRouteHandlersInSubtree(node: SegmentNode, nodePath: string): void {
|
|
526
|
+
if (node.route) {
|
|
527
|
+
throw new Error(
|
|
528
|
+
`Build error: route handler inside an intercepting route.\n` +
|
|
529
|
+
` File: ${node.route.filePath}\n` +
|
|
530
|
+
` Directory: app/${nodePath}\n` +
|
|
531
|
+
`An intercepting subtree renders a page component on soft navigation — a ` +
|
|
532
|
+
`route handler returns a Response and cannot be an interception target. ` +
|
|
533
|
+
`The route handler would silently shadow the interception: the resolver ` +
|
|
534
|
+
`would match it and then discard it because it has no page, so the modal ` +
|
|
535
|
+
`would stop opening with no diagnostic.\n` +
|
|
536
|
+
`Remove the route.ts, or move it outside the intercepting subtree.\n` +
|
|
537
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
for (const child of node.children) {
|
|
542
|
+
assertNoRouteHandlersInSubtree(child, `${nodePath}/${child.segmentName}`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Reject two pages that answer one URL among the interceptors an owner
|
|
548
|
+
* resolves in a single walk.
|
|
549
|
+
*
|
|
550
|
+
* `validateRouteGroupCollisions` in the scanner returns early on an
|
|
551
|
+
* intercepting node, so nothing else validates in here. That exemption exists
|
|
552
|
+
* for a real reason — an interception's computed URL legitimately mirrors the
|
|
553
|
+
* canonical route it replaces, and interceptors at *different* anchors
|
|
554
|
+
* deliberately target one URL, which the resolver then orders (deepest anchor
|
|
555
|
+
* first). But the exemption was broader than its reason. Two shapes slip
|
|
556
|
+
* through it, and they are the same shape seen from two levels:
|
|
557
|
+
*
|
|
558
|
+
* feed/(.)photo/(a)/page.tsx feed/@modal/(.)[a]/page.tsx
|
|
559
|
+
* feed/(.)photo/(b)/page.tsx feed/@modal/(.)[b]/page.tsx
|
|
560
|
+
*
|
|
561
|
+
* Both pairs answer one URL, and in both `matchUrlParts` resolves the tie by
|
|
562
|
+
* whichever `children` array lists first — so the winner is whichever the
|
|
563
|
+
* filesystem enumerated first, and renaming a directory flips it. That is
|
|
564
|
+
* exactly what `validateRouteGroupCollisions` and
|
|
565
|
+
* `validateAffixedSiblingConflicts` exist to reject for ordinary siblings.
|
|
566
|
+
*
|
|
567
|
+
* **The collision space is the anchor group, not the directory.** An earlier
|
|
568
|
+
* revision ran once per intercepting directory, which sees the left-hand pair
|
|
569
|
+
* and not the right-hand one: those leaves live in two different directories.
|
|
570
|
+
* The space is `groupByInterceptedAnchor`'s output — the same grouping
|
|
571
|
+
* `findInterceptingMatch` hands to one `matchUrlParts` call — so what is
|
|
572
|
+
* validated together is exactly what is resolved together. Interceptors at
|
|
573
|
+
* different anchors stay independent, which is the documented case, and two
|
|
574
|
+
* slots on one owner are two owners and so two spaces.
|
|
575
|
+
*
|
|
576
|
+
* **Two checks, and the difference between them matters.** A duplicate
|
|
577
|
+
* intercepted *pattern* is decided by string equality, which is exact: two
|
|
578
|
+
* leaves with one pattern claim one set of URLs, whatever the precedence rules
|
|
579
|
+
* are. Everything else is decided by asking the matcher — `collision-probe.ts`,
|
|
580
|
+
* the same oracle the main tree and every slot use, so the spaces cannot
|
|
581
|
+
* disagree about whether a pair of pages collides.
|
|
582
|
+
*
|
|
583
|
+
* Not covered: two affixed dynamics that tie on specificity (`(x)/a-[id]` vs
|
|
584
|
+
* `(y)/[slug]-b`, ambiguous only for a part shaped `a-…-b`). No single probe
|
|
585
|
+
* URL exercises both, and `validateAffixedSiblingConflicts` already rejects
|
|
586
|
+
* that pair by affix length — including through groups, inside intercepting
|
|
587
|
+
* subtrees, and between two interceptors sharing an anchor.
|
|
588
|
+
*
|
|
589
|
+
* The shape applies to both interception mechanisms — a slot interceptor and a
|
|
590
|
+
* children-path one produce their leaves through the same walk, and both are
|
|
591
|
+
* resolved by `findInterceptingMatch` — so this is called from the one place in
|
|
592
|
+
* `walkForPlacement` that sees every owner regardless of position.
|
|
593
|
+
*/
|
|
594
|
+
function assertNoInterceptedPatternCollisions(owner: SegmentNode, ownerPath: string): void {
|
|
595
|
+
for (const group of groupByInterceptedAnchor(owner.urlPath, owner.children)) {
|
|
596
|
+
assertAnchorGroupHasNoCollisions(group, ownerPath);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Reject a children-path interceptor and a slot interceptor from the same owner
|
|
602
|
+
* that claim URLs in common.
|
|
603
|
+
*
|
|
604
|
+
* Within one mode the ambiguity is either non-existent (two children-path
|
|
605
|
+
* rewrites are interchangeable, §"Selection Between Owners") or harmless (two
|
|
606
|
+
* slots on one owner both render). Across modes one is a layout swap and the
|
|
607
|
+
* other is a modal overlay, and the walk order picks the children-path shape —
|
|
608
|
+
* making the modal dead, silently and deterministically (TIM-1319).
|
|
609
|
+
*
|
|
610
|
+
* Overlap is a **pattern intersection** test: do two intercepted URL patterns
|
|
611
|
+
* share any concrete URL? This is not the same question the within-mode
|
|
612
|
+
* collision oracle answers. `findOrderDependentCollision` checks whether two
|
|
613
|
+
* candidates in one `matchUrlParts` walk produce different winners when
|
|
614
|
+
* `children` order is reversed — that is, order-dependence. A static segment
|
|
615
|
+
* always beats a dynamic one deterministically (no order-dependence), so
|
|
616
|
+
* `/feed/foo` and `/feed/[id]` pass the oracle even though
|
|
617
|
+
* `pathnameMatchesPattern` — the actual rewrite matcher — accepts both. The
|
|
618
|
+
* pattern intersection test catches that: it walks both patterns segment by
|
|
619
|
+
* segment and asks whether any value satisfies both.
|
|
620
|
+
*
|
|
621
|
+
* The check collects intercepted patterns from children-path interceptors and
|
|
622
|
+
* from each slot's interceptors independently. Slots are checked one at a time
|
|
623
|
+
* so two slot interceptors from *different* slots claiming one URL — the legal
|
|
624
|
+
* "two slots on one owner" case — are never compared.
|
|
625
|
+
*/
|
|
626
|
+
function assertNoCrossModeClaims(node: SegmentNode, ownerPath: string): void {
|
|
627
|
+
// Collect children-path interceptor patterns
|
|
628
|
+
const childrenLeaves: Array<{ pattern: string; filePath: string }> = [];
|
|
629
|
+
for (const child of node.children) {
|
|
630
|
+
if (
|
|
631
|
+
child.segmentType !== 'intercepting' ||
|
|
632
|
+
!child.interceptionMarker ||
|
|
633
|
+
!child.interceptedSegmentName
|
|
634
|
+
)
|
|
635
|
+
continue;
|
|
636
|
+
const urlBase = computeInterceptedUrlBase(
|
|
637
|
+
node.urlPath,
|
|
638
|
+
child.interceptionMarker,
|
|
639
|
+
child.interceptedSegmentName
|
|
640
|
+
);
|
|
641
|
+
walkInterceptedLeaves(child, urlBase, [child], (page, leaf) => {
|
|
642
|
+
childrenLeaves.push({ pattern: leaf.interceptedPattern, filePath: page.filePath });
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (childrenLeaves.length === 0) return;
|
|
647
|
+
|
|
648
|
+
const owner = ownerPath || '(app root)';
|
|
649
|
+
|
|
650
|
+
for (const slot of Object.values(node.slots)) {
|
|
651
|
+
const slotLeaves: Array<{ pattern: string; filePath: string }> = [];
|
|
652
|
+
for (const child of slot.children) {
|
|
653
|
+
if (
|
|
654
|
+
child.segmentType !== 'intercepting' ||
|
|
655
|
+
!child.interceptionMarker ||
|
|
656
|
+
!child.interceptedSegmentName
|
|
657
|
+
)
|
|
658
|
+
continue;
|
|
659
|
+
const urlBase = computeInterceptedUrlBase(
|
|
660
|
+
node.urlPath,
|
|
661
|
+
child.interceptionMarker,
|
|
662
|
+
child.interceptedSegmentName
|
|
663
|
+
);
|
|
664
|
+
walkInterceptedLeaves(child, urlBase, [child], (page, leaf) => {
|
|
665
|
+
slotLeaves.push({ pattern: leaf.interceptedPattern, filePath: page.filePath });
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
for (const cl of childrenLeaves) {
|
|
670
|
+
for (const sl of slotLeaves) {
|
|
671
|
+
const overlap = interceptedPatternsOverlap(cl.pattern, sl.pattern);
|
|
672
|
+
if (overlap !== null) {
|
|
673
|
+
throwCrossModeClaim(owner, overlap, cl.filePath, sl.filePath);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function throwCrossModeClaim(
|
|
681
|
+
owner: string,
|
|
682
|
+
url: string,
|
|
683
|
+
childFile: string,
|
|
684
|
+
slotFile: string
|
|
685
|
+
): never {
|
|
686
|
+
throw new Error(
|
|
687
|
+
`Build error: a children-path interception and a slot interception both ` +
|
|
688
|
+
`claim the same URL.\n` +
|
|
689
|
+
` Owner: app/${owner}\n` +
|
|
690
|
+
` URL: ${url}\n` +
|
|
691
|
+
` Children: ${childFile}\n` +
|
|
692
|
+
` Slot: ${slotFile}\n` +
|
|
693
|
+
`The children-path interceptor replaces the owner's children (layout swap) ` +
|
|
694
|
+
`while the slot interceptor renders inside a parallel slot (modal overlay). ` +
|
|
695
|
+
`Both apply from the same scope at the same URL, and which one wins would ` +
|
|
696
|
+
`depend on internal walk order rather than an explicit rule.\n` +
|
|
697
|
+
`Remove one of the two, or move them to different scopes.\n` +
|
|
698
|
+
`See design/07-routing.md §"Selection Between Owners".`
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* The URL-matching identity of an intercepting node, as a node.
|
|
704
|
+
*
|
|
705
|
+
* `matchUrlParts` reads `segmentType` directly and knows nothing about
|
|
706
|
+
* interception, so a marker'd directory has to be handed to it under the
|
|
707
|
+
* identity of the segment it intercepts — `(.)[id]` as `[id]`. Priority
|
|
708
|
+
* ordering, affix stripping and catch-all handling then come from the shared
|
|
709
|
+
* walker rather than from a second classifier here.
|
|
710
|
+
*
|
|
711
|
+
* Shared with `findInterceptingMatch` for the same reason the grouping is: the
|
|
712
|
+
* collision space is the resolver's synthetic anchor parent, so its children
|
|
713
|
+
* have to carry the identity the resolver gives them or the validator would be
|
|
714
|
+
* probing a tree that does not match the one served. The caller keeps its own
|
|
715
|
+
* map back to the real node — the proxy is a matching identity, not a
|
|
716
|
+
* replacement (tree paths still need the directory name).
|
|
717
|
+
*/
|
|
718
|
+
export function interceptorProxy<TFile>(node: SegmentNode<TFile>): SegmentNode<TFile> {
|
|
719
|
+
return { ...node, ...effectiveUrlSegment(node) };
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function assertAnchorGroupHasNoCollisions(
|
|
723
|
+
group: InterceptorAnchorGroup<RouteFile>,
|
|
724
|
+
ownerPath: string
|
|
725
|
+
): void {
|
|
726
|
+
const { base } = group;
|
|
727
|
+
const owner = ownerPath || '(app root)';
|
|
728
|
+
|
|
729
|
+
// The space the resolver walks: a synthetic parent sitting at the anchor
|
|
730
|
+
// base, holding every interceptor of this group under its matching identity.
|
|
731
|
+
// `matchUrlParts` starts below this node, so the interceptors' own segments
|
|
732
|
+
// are matched parts here — which is what lets a probe reach across two
|
|
733
|
+
// directories and find the pair that competes.
|
|
734
|
+
const proxies = group.interceptors.map(interceptorProxy);
|
|
735
|
+
const anchorNode: SegmentNode = {
|
|
736
|
+
segmentName: '',
|
|
737
|
+
segmentType: 'static',
|
|
738
|
+
urlPath: base,
|
|
739
|
+
children: proxies,
|
|
740
|
+
slots: {},
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
const patterns = new Map<string, string>();
|
|
744
|
+
const probeLeaves: ProbeLeaf[] = [];
|
|
745
|
+
|
|
746
|
+
for (const proxy of proxies) {
|
|
747
|
+
// The proxy's name, not the directory's `interceptedSegmentName`: they are
|
|
748
|
+
// the same string, and this is the one `matchUrlParts` matches on, so the
|
|
749
|
+
// reported pattern and the probed URL cannot describe different segments.
|
|
750
|
+
const pattern = joinInterceptedBase(base, proxy.segmentName);
|
|
751
|
+
walkInterceptedLeaves(proxy, pattern, [proxy], (page, leaf) => {
|
|
752
|
+
// Two leaves whose intercepted pattern is the *same string* claim exactly
|
|
753
|
+
// the same set of URLs — one is ambiguous with the other, or dead. This
|
|
754
|
+
// needs no probe and no reasoning about precedence: identical patterns are
|
|
755
|
+
// identical URL sets by definition. It is the case route groups make easy
|
|
756
|
+
// to write, `(a)/page.tsx` beside `(b)/page.tsx`, and the one the main
|
|
757
|
+
// tree already rejects by comparing urlPath. Across two interceptors it
|
|
758
|
+
// is `(..)photo` beside `(...)photo` under `/feed`, which both base at
|
|
759
|
+
// `/` and both intercept the literal `photo`.
|
|
760
|
+
const duplicate = patterns.get(leaf.interceptedPattern);
|
|
761
|
+
if (duplicate) {
|
|
762
|
+
throw new Error(
|
|
763
|
+
`Build error: route collision between intercepting routes — two pages intercept the same URL.\n` +
|
|
764
|
+
` Owner: app/${owner}\n` +
|
|
765
|
+
` Intercepted base: ${base}\n` +
|
|
766
|
+
` URL: ${leaf.interceptedPattern}\n` +
|
|
767
|
+
` File 1: ${duplicate}\n` +
|
|
768
|
+
` File 2: ${page.filePath}\n` +
|
|
769
|
+
`A route group is transparent for matching, so moving a page into one does not ` +
|
|
770
|
+
`give it a URL of its own — these two claim the same one. Rename or move one of ` +
|
|
771
|
+
`them.\n` +
|
|
772
|
+
`See design/07-routing.md §"Collisions Among Intercepting Routes".`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
patterns.set(leaf.interceptedPattern, page.filePath);
|
|
776
|
+
probeLeaves.push({ filePath: page.filePath, chain: leaf.chain });
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Differently-spelled patterns that nonetheless compete: ask the matcher.
|
|
781
|
+
const collision = findOrderDependentCollision(anchorNode, probeLeaves, base);
|
|
782
|
+
if (collision) {
|
|
783
|
+
throw new Error(
|
|
784
|
+
`Build error: route collision between intercepting routes — two pages answer the same URL.\n` +
|
|
785
|
+
` Owner: app/${owner}\n` +
|
|
786
|
+
` Intercepted base: ${base}\n` +
|
|
787
|
+
` URL: ${collision.url}\n` +
|
|
788
|
+
` File 1: ${collision.first}\n` +
|
|
789
|
+
` File 2: ${collision.second}\n` +
|
|
790
|
+
`Both match it, so which one renders would be decided by filesystem enumeration ` +
|
|
791
|
+
`order — renaming a route group can flip it. Rename or move one of them.\n` +
|
|
792
|
+
`Pages are compared by the URLs they match, not by how they are spelled: [id] and ` +
|
|
793
|
+
`[slug] match the same URLs, and an optional catch-all also matches with zero ` +
|
|
794
|
+
`segments.\n` +
|
|
795
|
+
`Intercepting directories based at *different* URLs may target one page — the ` +
|
|
796
|
+
`resolver tries the deepest first — so this rejects only an ambiguity among the ` +
|
|
797
|
+
`ones based at ${base}.\n` +
|
|
798
|
+
`See design/07-routing.md §"Collisions Among Intercepting Routes".`
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/** What the walk knows about the position it is currently standing in. */
|
|
804
|
+
interface PlacementContext {
|
|
805
|
+
/** `node` is itself a slot node, so its children are direct slot children. */
|
|
806
|
+
parentIsSlot: boolean;
|
|
807
|
+
/** `node` is at or below a slot node. */
|
|
808
|
+
inSlotSubtree: boolean;
|
|
809
|
+
/** `node` is inside an intercepting subtree. */
|
|
810
|
+
inInterceptingSubtree: boolean;
|
|
811
|
+
/** Some segment from the root down to `node`, inclusive, binds a param. */
|
|
812
|
+
ancestorsBindParams: boolean;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
function walkForPlacement(node: SegmentNode, path: string, ctx: PlacementContext): void {
|
|
816
|
+
for (const child of node.children) {
|
|
817
|
+
const childPath = path ? `${path}/${child.segmentName}` : child.segmentName;
|
|
818
|
+
|
|
819
|
+
if (child.segmentType === 'intercepting') {
|
|
820
|
+
const marker = child.interceptionMarker ?? '(.)';
|
|
821
|
+
|
|
822
|
+
if (ctx.inInterceptingSubtree) {
|
|
823
|
+
throw new Error(
|
|
824
|
+
`Build error: intercepting route nested inside another intercepting route.\n` +
|
|
825
|
+
` Directory: app/${childPath}\n` +
|
|
826
|
+
`An intercepting directory (${marker}) resolves against the URL its own parent ` +
|
|
827
|
+
`renders at, and an intercepting subtree has no such URL — nothing walks it, so ` +
|
|
828
|
+
`the rewrite would match the navigation and then have nothing to render.\n` +
|
|
829
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Inside a slot, only a *direct* slot child is reachable: the slot
|
|
834
|
+
// resolver reads `slotNode.children` and stops. The children-path
|
|
835
|
+
// renderer cannot pick it up either — it builds a segment chain, which
|
|
836
|
+
// has no way to express a descent through a slot.
|
|
837
|
+
if (ctx.inSlotSubtree && !ctx.parentIsSlot) {
|
|
838
|
+
throw new Error(
|
|
839
|
+
`Build error: intercepting route inside a parallel slot but not directly under it.\n` +
|
|
840
|
+
` Directory: app/${childPath}\n` +
|
|
841
|
+
`An intercepting directory (${marker}) inside an @slot must be a *direct* child of ` +
|
|
842
|
+
`that slot, e.g. app/feed/@modal/${child.segmentName}/page.tsx. The slot resolver ` +
|
|
843
|
+
`scans the slot's direct children only; elsewhere the rewrite would match the ` +
|
|
844
|
+
`navigation and then have nothing to render.\n` +
|
|
845
|
+
`See design/07-routing.md §"Intercepting Routes".`
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Outside a slot the intercepting page replaces `children` for the
|
|
850
|
+
// owner's own layout chain, so those layouts render against the
|
|
851
|
+
// intercepted URL — which carries no values for params declared above
|
|
852
|
+
// the interception.
|
|
853
|
+
if (!ctx.parentIsSlot && ctx.ancestorsBindParams) {
|
|
854
|
+
assertOwnerChainBindsNoParams(childPath, marker);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (!ctx.parentIsSlot && !node.layout) {
|
|
858
|
+
assertOwnerHasLayout(path, childPath);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// `node` is the owner — the slot (whose urlPath is the owning segment's,
|
|
862
|
+
// since slots add no URL depth) or the ordinary segment holding the
|
|
863
|
+
// interception. The same input rewrite generation bases from.
|
|
864
|
+
assertInterceptedBaseIsCountable(child, node.urlPath, childPath);
|
|
865
|
+
assertInterceptedCatchAllsAreTerminal(child, childPath);
|
|
866
|
+
assertNoRouteHandlersInSubtree(child, childPath);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
walkForPlacement(child, childPath, {
|
|
870
|
+
parentIsSlot: false,
|
|
871
|
+
// A slot subtree stays a slot subtree all the way down: the deeper
|
|
872
|
+
// positions are exactly the ones neither renderer reaches.
|
|
873
|
+
inSlotSubtree: ctx.inSlotSubtree,
|
|
874
|
+
inInterceptingSubtree: ctx.inInterceptingSubtree || child.segmentType === 'intercepting',
|
|
875
|
+
ancestorsBindParams: ctx.ancestorsBindParams || !!child.paramName,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// After every child has been recursed into, so a placement error inside any
|
|
880
|
+
// intercepting subtree is reported in preference to what it causes here — a
|
|
881
|
+
// nested interception leaves a node `matchUrlParts` cannot match at all, and
|
|
882
|
+
// the resulting nonsense below it is not what the author needs to be told
|
|
883
|
+
// about. This is per *owner* rather than per intercepting directory because
|
|
884
|
+
// the collision space is the anchor group; see
|
|
885
|
+
// `assertNoInterceptedPatternCollisions`.
|
|
886
|
+
assertNoInterceptedPatternCollisions(node, path);
|
|
887
|
+
|
|
888
|
+
for (const [slotName, slotNode] of Object.entries(node.slots)) {
|
|
889
|
+
walkForPlacement(slotNode, path ? `${path}/@${slotName}` : `@${slotName}`, {
|
|
890
|
+
parentIsSlot: true,
|
|
891
|
+
inSlotSubtree: true,
|
|
892
|
+
inInterceptingSubtree: ctx.inInterceptingSubtree,
|
|
893
|
+
// A slot-mode interception never binds owner params from the target —
|
|
894
|
+
// the pipeline re-matches the source route, which supplies them — so the
|
|
895
|
+
// rule stops at the slot boundary.
|
|
896
|
+
ancestorsBindParams: false,
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// After both children and slots have been validated independently, check for
|
|
901
|
+
// the cross-mode ambiguity that neither space covers: a children-path
|
|
902
|
+
// interceptor and a slot interceptor from the same owner claiming one URL.
|
|
903
|
+
// Within each mode the collision is either ordered (two children-path) or
|
|
904
|
+
// harmless (two slots) — see §"Selection Between Owners" — but across modes
|
|
905
|
+
// one is an overlay and the other a layout swap, and the walk order picks the
|
|
906
|
+
// children-path shape silently (TIM-1319).
|
|
907
|
+
assertNoCrossModeClaims(node, path);
|
|
52
908
|
}
|
|
53
909
|
|
|
54
910
|
/**
|
|
55
911
|
* Recursively walk the segment tree to find intercepting routes.
|
|
912
|
+
*
|
|
913
|
+
* `ancestors` deliberately excludes slot nodes: a slot doesn't appear in a
|
|
914
|
+
* matched route chain, so the last entry is always the nearest chain-visible
|
|
915
|
+
* ancestor — the segment that owns the slot, and therefore the segment whose
|
|
916
|
+
* presence in the source route gates the interception.
|
|
917
|
+
*
|
|
918
|
+
* Intercepting nodes only ever appear as a direct child of a slot or of an
|
|
919
|
+
* ordinary chain segment in a valid tree; `validateInterceptionPlacement`
|
|
920
|
+
* rejects every other placement at scan time, so this walk never has to
|
|
921
|
+
* decide what an unrenderable intercepting node should generate.
|
|
922
|
+
*
|
|
923
|
+
* `parentIsSlot` is what distinguishes the two shapes, and it is the only
|
|
924
|
+
* input that does: the owner, the scope and the intercepted pattern are all
|
|
925
|
+
* computed identically either way.
|
|
56
926
|
*/
|
|
57
927
|
function walkForInterceptions(
|
|
58
928
|
node: SegmentNode,
|
|
59
929
|
ancestors: SegmentNode[],
|
|
930
|
+
parentIsSlot: boolean,
|
|
60
931
|
rewrites: InterceptionRewrite[]
|
|
61
932
|
): void {
|
|
62
933
|
// Check children
|
|
63
934
|
for (const child of node.children) {
|
|
64
935
|
if (child.segmentType === 'intercepting' && child.interceptionMarker) {
|
|
65
936
|
// Found an intercepting route — collect rewrites from its sub-tree
|
|
66
|
-
collectFromInterceptingNode(child, ancestors, rewrites);
|
|
937
|
+
collectFromInterceptingNode(child, ancestors, parentIsSlot, rewrites);
|
|
67
938
|
} else {
|
|
68
|
-
walkForInterceptions(child, [...ancestors, child], rewrites);
|
|
939
|
+
walkForInterceptions(child, [...ancestors, child], false, rewrites);
|
|
69
940
|
}
|
|
70
941
|
}
|
|
71
942
|
|
|
72
943
|
// Check slots (intercepting routes are typically inside slots like @modal)
|
|
73
|
-
for (const
|
|
74
|
-
walkForInterceptions(slot, ancestors, rewrites);
|
|
944
|
+
for (const slot of Object.values(node.slots)) {
|
|
945
|
+
walkForInterceptions(slot, ancestors, true, rewrites);
|
|
75
946
|
}
|
|
76
947
|
}
|
|
77
948
|
|
|
@@ -82,6 +953,7 @@ function walkForInterceptions(
|
|
|
82
953
|
function collectFromInterceptingNode(
|
|
83
954
|
interceptingNode: SegmentNode,
|
|
84
955
|
ancestors: SegmentNode[],
|
|
956
|
+
parentIsSlot: boolean,
|
|
85
957
|
rewrites: InterceptionRewrite[]
|
|
86
958
|
): void {
|
|
87
959
|
const marker = interceptingNode.interceptionMarker!;
|
|
@@ -89,85 +961,190 @@ function collectFromInterceptingNode(
|
|
|
89
961
|
|
|
90
962
|
// Compute the intercepted URL base based on the marker
|
|
91
963
|
const parentUrlPath = ancestors[ancestors.length - 1].urlPath;
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
964
|
+
const interceptedUrlBase = computeInterceptedUrlBase(parentUrlPath, marker, segmentName);
|
|
965
|
+
|
|
966
|
+
// The scope key and the re-match prefix both describe the same node — the
|
|
967
|
+
// interception's owner — so they are derived here together from one
|
|
968
|
+
// ancestor chain.
|
|
969
|
+
const ancestorPaths = computeSegmentTreePaths(ancestors);
|
|
970
|
+
const interceptingScope = ancestorPaths[ancestorPaths.length - 1];
|
|
95
971
|
|
|
96
972
|
// Find all leaf pages in the intercepting sub-tree
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
[...ancestors, interceptingNode],
|
|
102
|
-
rewrites
|
|
103
|
-
);
|
|
973
|
+
const shape: InterceptionShape = parentIsSlot
|
|
974
|
+
? { mode: 'slot', interceptingPrefix: parentUrlPath, interceptingScope }
|
|
975
|
+
: { mode: 'children', interceptingScope };
|
|
976
|
+
collectLeavesWithRewrites(interceptingNode, interceptedUrlBase, shape, rewrites);
|
|
104
977
|
}
|
|
105
978
|
|
|
106
979
|
/**
|
|
107
|
-
*
|
|
108
|
-
* rewrite
|
|
980
|
+
* Everything about a rewrite except which URL it intercepts — one intercepting
|
|
981
|
+
* directory produces one of these and one rewrite per leaf page beneath it.
|
|
982
|
+
*
|
|
983
|
+
* Written as a union of `Omit`s rather than `Omit` of the union: `Omit` is not
|
|
984
|
+
* distributive, so the latter would silently collapse to the shapes' common
|
|
985
|
+
* fields and drop `interceptingPrefix`.
|
|
109
986
|
*/
|
|
110
|
-
|
|
987
|
+
type InterceptionShape =
|
|
988
|
+
| Omit<SlotInterceptionRewrite, 'interceptedPattern'>
|
|
989
|
+
| Omit<ChildrenInterceptionRewrite, 'interceptedPattern'>;
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Walk an intercepting sub-tree and visit every page-bearing node with the URL
|
|
993
|
+
* pattern it is intercepted at, and URLs that reach it.
|
|
994
|
+
*
|
|
995
|
+
* Route groups are transparent, exactly as they are in the main tree — which
|
|
996
|
+
* is what makes two groups under one interceptor able to claim one URL, and is
|
|
997
|
+
* why the collision validator has to walk the same shape this does.
|
|
998
|
+
*
|
|
999
|
+
* Rewrite generation and that validator are the two callers. They share this
|
|
1000
|
+
* walk rather than each having their own so they cannot disagree about which
|
|
1001
|
+
* URLs an interceptor claims: a leaf the validator did not see is a rewrite
|
|
1002
|
+
* nobody checked, and a leaf only the validator sees is a build error for a
|
|
1003
|
+
* route that does not exist. Slots are not descended, here or in either caller
|
|
1004
|
+
* — a slot nested inside an intercepting subtree produces no rewrite.
|
|
1005
|
+
*
|
|
1006
|
+
* That answers the rewrite question only, and the resolution question is
|
|
1007
|
+
* answered elsewhere: `validateSlotsInsideInterceptingSubtree`
|
|
1008
|
+
* (`collision-spaces.ts`) gives each such slot its own collision space, and
|
|
1009
|
+
* `validateSlotPlacement` (`slot-placement.ts`) rejects the ones no renderer
|
|
1010
|
+
* reaches. Between them the slots this walk skips are covered; do not conclude
|
|
1011
|
+
* from the skip here that they are unvalidated (TIM-1308, TIM-1311).
|
|
1012
|
+
*
|
|
1013
|
+
* The walk reports the chain of URL-contributing nodes rather than building
|
|
1014
|
+
* probe URLs itself: choosing a probe value means running the matcher over the
|
|
1015
|
+
* whole subtree, which is the validator's business and not something rewrite
|
|
1016
|
+
* generation should be paying for or passing dummy arguments around.
|
|
1017
|
+
*/
|
|
1018
|
+
function walkInterceptedLeaves(
|
|
111
1019
|
node: SegmentNode,
|
|
112
1020
|
interceptedUrlPath: string,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
rewrites: InterceptionRewrite[]
|
|
1021
|
+
chain: SegmentNode[],
|
|
1022
|
+
visit: (page: NonNullable<SegmentNode['page']>, leaf: InterceptedLeaf) => void
|
|
116
1023
|
): void {
|
|
117
1024
|
if (node.page) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
segmentPath: [...segmentPath],
|
|
122
|
-
});
|
|
1025
|
+
// The page is handed over rather than the node so callers reading it do
|
|
1026
|
+
// not need a non-null assertion to say what this branch already proved.
|
|
1027
|
+
visit(node.page, { interceptedPattern: interceptedUrlPath, chain });
|
|
123
1028
|
}
|
|
124
1029
|
|
|
125
1030
|
for (const child of node.children) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
? interceptedUrlPath
|
|
129
|
-
: `${interceptedUrlPath}/${child.segmentName}`;
|
|
130
|
-
collectLeavesWithRewrites(
|
|
1031
|
+
const isGroup = child.segmentType === 'group';
|
|
1032
|
+
walkInterceptedLeaves(
|
|
131
1033
|
child,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
rewrites
|
|
1034
|
+
isGroup ? interceptedUrlPath : `${interceptedUrlPath}/${child.segmentName}`,
|
|
1035
|
+
isGroup ? chain : [...chain, child],
|
|
1036
|
+
visit
|
|
136
1037
|
);
|
|
137
1038
|
}
|
|
138
1039
|
}
|
|
139
1040
|
|
|
1041
|
+
/** What one page-bearing node in an intercepting subtree claims. */
|
|
1042
|
+
interface InterceptedLeaf {
|
|
1043
|
+
/** The URL pattern the rewrite carries — the author's own spelling. */
|
|
1044
|
+
interceptedPattern: string;
|
|
1045
|
+
/**
|
|
1046
|
+
* The nodes from the intercepting directory down to this page that contribute
|
|
1047
|
+
* URL parts — route groups excluded, since they are transparent for matching.
|
|
1048
|
+
* Empty for the intercepting directory's own page.
|
|
1049
|
+
*/
|
|
1050
|
+
chain: SegmentNode[];
|
|
1051
|
+
}
|
|
1052
|
+
|
|
140
1053
|
/**
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
1054
|
+
* Recursively find leaf pages in an intercepting sub-tree and generate
|
|
1055
|
+
* rewrite rules for each.
|
|
1056
|
+
*/
|
|
1057
|
+
function collectLeavesWithRewrites(
|
|
1058
|
+
node: SegmentNode,
|
|
1059
|
+
interceptedUrlPath: string,
|
|
1060
|
+
shape: InterceptionShape,
|
|
1061
|
+
rewrites: InterceptionRewrite[]
|
|
1062
|
+
): void {
|
|
1063
|
+
walkInterceptedLeaves(node, interceptedUrlPath, [], (_page, leaf) => {
|
|
1064
|
+
rewrites.push({ ...shape, interceptedPattern: leaf.interceptedPattern });
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* How many URL levels a marker climbs from the slot owner to reach the
|
|
1070
|
+
* intercepted segment, or `'root'` for a marker that climbs all the way.
|
|
148
1071
|
*
|
|
149
1072
|
* Level counting operates on URL path segments, NOT filesystem directories.
|
|
150
1073
|
* Route groups and parallel slots are already excluded from urlPath (they
|
|
151
1074
|
* don't add URL depth), so (..) correctly climbs visible segments. This
|
|
152
1075
|
* avoids the Vinext bug where path.dirname() on filesystem paths would
|
|
153
1076
|
* waste climbs on invisible route groups.
|
|
1077
|
+
*
|
|
1078
|
+
* Used only by `computeInterceptedBase` below — both rewrite generation and
|
|
1079
|
+
* the slot resolver go through that, so the arithmetic exists once.
|
|
154
1080
|
*/
|
|
155
|
-
function
|
|
1081
|
+
function interceptionClimb(marker: InterceptionMarker): number | 'root' {
|
|
156
1082
|
switch (marker) {
|
|
157
1083
|
case '(.)':
|
|
158
|
-
return
|
|
159
|
-
case '(..)':
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return
|
|
163
|
-
}
|
|
1084
|
+
return 0;
|
|
1085
|
+
case '(..)':
|
|
1086
|
+
return 1;
|
|
1087
|
+
case '(..)(..)':
|
|
1088
|
+
return 2;
|
|
164
1089
|
case '(...)':
|
|
165
|
-
return '
|
|
166
|
-
case '(..)(..)': {
|
|
167
|
-
const parts = parentUrlPath.split('/').filter(Boolean);
|
|
168
|
-
parts.pop();
|
|
169
|
-
parts.pop();
|
|
170
|
-
return parts.length === 0 ? '/' : `/${parts.join('/')}`;
|
|
171
|
-
}
|
|
1090
|
+
return 'root';
|
|
172
1091
|
}
|
|
173
1092
|
}
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Compute the base URL that an intercepting route intercepts, given the
|
|
1096
|
+
* parent's URL path and the interception marker.
|
|
1097
|
+
*
|
|
1098
|
+
* - (.) — same level: parent's URL path
|
|
1099
|
+
* - (..) — one level up: parent's parent URL path
|
|
1100
|
+
* - (...) — root level: /
|
|
1101
|
+
* - (..)(..) — two levels up: parent's grandparent URL path
|
|
1102
|
+
*
|
|
1103
|
+
* The result is a URL **pattern**, not a URL — `parentUrlPath` carries the
|
|
1104
|
+
* directory names, so a dynamic ancestor appears as `/docs/[...path]`.
|
|
1105
|
+
* Rewrite generation wants exactly that. The slot resolver imports this to
|
|
1106
|
+
* locate the intercepted segment in a concrete target pathname, and must
|
|
1107
|
+
* therefore account for a bracket part standing for a different number of
|
|
1108
|
+
* URL parts than itself (TIM-1281).
|
|
1109
|
+
*
|
|
1110
|
+
* Climbing past the root clamps to `/` rather than erroring, so generation
|
|
1111
|
+
* and resolution never disagree about what an over-reaching marker
|
|
1112
|
+
* intercepts.
|
|
1113
|
+
*/
|
|
1114
|
+
/**
|
|
1115
|
+
* The URL pattern an intercepting directory's own page sits at — its
|
|
1116
|
+
* `computeInterceptedBase` joined with the segment it intercepts.
|
|
1117
|
+
*
|
|
1118
|
+
* The root case is why this is a function rather than a template literal at
|
|
1119
|
+
* each caller: a base of `/` must not produce `//photo`. Rewrite generation
|
|
1120
|
+
* and the collision validator both start their walk from this value, so the
|
|
1121
|
+
* two describe the same URLs by construction.
|
|
1122
|
+
*/
|
|
1123
|
+
export function computeInterceptedUrlBase(
|
|
1124
|
+
parentUrlPath: string,
|
|
1125
|
+
marker: InterceptionMarker,
|
|
1126
|
+
interceptedSegmentName: string
|
|
1127
|
+
): string {
|
|
1128
|
+
return joinInterceptedBase(computeInterceptedBase(parentUrlPath, marker), interceptedSegmentName);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* An intercepted base joined with one segment beneath it.
|
|
1133
|
+
*
|
|
1134
|
+
* The whole content of the "function rather than a template literal" rule
|
|
1135
|
+
* above: a base of `/` must not produce `//photo`. The collision validator has
|
|
1136
|
+
* the base in hand already (it groups by it) and joins through this rather than
|
|
1137
|
+
* re-deriving it from an owner path, so both callers spell the root case once.
|
|
1138
|
+
*/
|
|
1139
|
+
export function joinInterceptedBase(base: string, segmentName: string): string {
|
|
1140
|
+
return base === '/' ? `/${segmentName}` : `${base}/${segmentName}`;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
export function computeInterceptedBase(parentUrlPath: string, marker: InterceptionMarker): string {
|
|
1144
|
+
const climb = interceptionClimb(marker);
|
|
1145
|
+
if (climb === 'root') return '/';
|
|
1146
|
+
|
|
1147
|
+
const parts = parentUrlPath.split('/').filter(Boolean);
|
|
1148
|
+
for (let i = 0; i < climb; i++) parts.pop();
|
|
1149
|
+
return parts.length === 0 ? '/' : `/${parts.join('/')}`;
|
|
1150
|
+
}
|