@timber-js/app 0.2.0-alpha.8 → 0.2.0-alpha.81
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/dist/_chunks/actions-Dg-ANYHb.js +421 -0
- package/dist/_chunks/actions-Dg-ANYHb.js.map +1 -0
- package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
- package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
- package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
- package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
- package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
- package/dist/_chunks/define-C77ScO0m.js +106 -0
- package/dist/_chunks/define-C77ScO0m.js.map +1 -0
- package/dist/_chunks/define-CZqDwhSu.js +199 -0
- package/dist/_chunks/define-CZqDwhSu.js.map +1 -0
- package/dist/_chunks/define-cookie-C2IkoFGN.js +94 -0
- package/dist/_chunks/define-cookie-C2IkoFGN.js.map +1 -0
- package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
- package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
- package/dist/_chunks/format-CYBGxKtc.js +14 -0
- package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-Dpn_UfAD.js} +171 -97
- package/dist/_chunks/interception-Dpn_UfAD.js.map +1 -0
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
- package/dist/_chunks/request-context-qMsWgy9C.js +478 -0
- package/dist/_chunks/request-context-qMsWgy9C.js.map +1 -0
- package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
- package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
- package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
- package/dist/_chunks/stale-reload-BX5gL1r-.js +64 -0
- package/dist/_chunks/stale-reload-BX5gL1r-.js.map +1 -0
- package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
- package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
- package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
- package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-Lo_s_pw2.js} +4 -4
- package/dist/_chunks/use-query-states-Lo_s_pw2.js.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 +73 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +95 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +148 -12
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +135 -11
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +17 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +56 -13
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/handler-store.d.ts +31 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +23 -7
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +142 -80
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/singleflight.d.ts +18 -1
- 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/timber-cache.d.ts +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +27 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
- package/dist/client/browser-entry/action-dispatch.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 +46 -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 +26 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +23 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +19 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/error-boundary.d.ts +12 -5
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +10 -4
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +54 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +3 -3
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/history.d.ts +19 -4
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +7 -21
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +210 -1017
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +18 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +890 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link-pending-store.d.ts +63 -0
- package/dist/client/link-pending-store.d.ts.map +1 -0
- package/dist/client/link.d.ts +90 -32
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/nav-link-store.d.ts +36 -0
- package/dist/client/nav-link-store.d.ts.map +1 -0
- package/dist/client/navigation-api-types.d.ts +90 -0
- package/dist/client/navigation-api-types.d.ts.map +1 -0
- package/dist/client/navigation-api.d.ts +115 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +13 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/router.d.ts +70 -4
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +38 -3
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +63 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +13 -4
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +5 -5
- package/dist/client/top-loader.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-params.d.ts +6 -4
- package/dist/client/use-params.d.ts.map +1 -1
- package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/codec.d.ts +33 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +2 -0
- package/dist/config-types.d.ts +227 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts +35 -14
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -83
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/index.d.ts +45 -192
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12357 -11925
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +107 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +2 -2
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +3 -3
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +32 -0
- package/dist/plugins/client-chunks.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-browser-logs.d.ts +84 -0
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
- package/dist/plugins/dev-error-overlay.d.ts +26 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/dev-logs.d.ts +1 -1
- package/dist/plugins/dev-logs.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +19 -5
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +1 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- 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 +6 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +4 -4
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/index.d.ts +2 -0
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -2
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +46 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/status-file-lint.d.ts +2 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +16 -4
- package/dist/routing/types.d.ts.map +1 -1
- 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 +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +76 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +139 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +32 -441
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/registry.d.ts +2 -2
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/segment-params/define.d.ts +78 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +3 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +2 -0
- package/dist/server/access-gate.d.ts +4 -0
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +25 -6
- 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.map +1 -1
- package/dist/server/actions.d.ts +3 -6
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +32 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/debug.d.ts +1 -1
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-page-resolver.d.ts +52 -0
- package/dist/server/deny-page-resolver.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-holding-server.d.ts +52 -0
- package/dist/server/dev-holding-server.d.ts.map +1 -0
- package/dist/server/dev-warnings.d.ts +1 -21
- package/dist/server/dev-warnings.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +4 -3
- 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 +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/flush.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +51 -11
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +5 -43
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +37 -2798
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +46 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +2883 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +25 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +19 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +113 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/page-deny-boundary.d.ts +31 -0
- package/dist/server/page-deny-boundary.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +6 -0
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +42 -10
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +69 -18
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +112 -43
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +27 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +9 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +2 -2
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +48 -5
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +8 -3
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +4 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +129 -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/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +22 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +39 -21
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +50 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +1 -1
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +36 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +4 -4
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +22 -19
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.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/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 +2 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +1 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +3 -2
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/directive-parser.d.ts +5 -2
- package/dist/utils/directive-parser.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/package.json +56 -22
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/adapters/cloudflare.ts +342 -28
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +52 -8
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +38 -0
- package/src/cache/handler-store.ts +68 -0
- package/src/cache/index.ts +81 -18
- package/src/cache/singleflight.ts +62 -4
- package/src/cache/sizeof.ts +31 -0
- package/src/cache/timber-cache.ts +24 -20
- package/src/cli.ts +16 -6
- package/src/client/browser-dev.ts +128 -1
- package/src/client/browser-entry/action-dispatch.ts +116 -0
- package/src/client/browser-entry/hmr.ts +81 -0
- package/src/client/browser-entry/hydrate.ts +145 -0
- package/src/client/browser-entry/index.ts +138 -0
- package/src/client/browser-entry/post-hydration.ts +119 -0
- package/src/client/browser-entry/router-init.ts +193 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +27 -0
- package/src/client/error-boundary.tsx +48 -16
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +9 -7
- package/src/client/history.ts +26 -4
- package/src/client/index.ts +19 -38
- package/src/client/internal.ts +57 -0
- package/src/client/link-pending-store.ts +111 -0
- package/src/client/link.tsx +329 -97
- package/src/client/nav-link-store.ts +47 -0
- package/src/client/navigation-api-types.ts +112 -0
- package/src/client/navigation-api.ts +332 -0
- package/src/client/navigation-context.ts +31 -6
- package/src/client/navigation-root.tsx +342 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +299 -72
- package/src/client/rsc-fetch.ts +97 -8
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/stale-reload.ts +72 -3
- package/src/client/top-loader.tsx +16 -8
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-params.ts +7 -5
- package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
- package/src/client/use-query-states.ts +3 -3
- package/src/client/use-router.ts +1 -1
- package/src/codec.ts +49 -0
- package/src/config-types.ts +225 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +78 -25
- package/src/cookies/index.ts +8 -0
- package/src/fonts/css.ts +2 -1
- package/src/index.ts +295 -354
- package/src/plugin-context.ts +240 -0
- package/src/plugins/adapter-build.ts +9 -3
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +3 -3
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-browser-logs.ts +288 -0
- package/src/plugins/dev-error-overlay.ts +70 -1
- package/src/plugins/dev-logs.ts +1 -1
- package/src/plugins/dev-server.ts +70 -9
- package/src/plugins/entries.ts +71 -10
- package/src/plugins/fonts.ts +168 -61
- package/src/plugins/mdx.ts +1 -1
- package/src/plugins/routing.ts +57 -17
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +135 -35
- package/src/plugins/static-build.ts +17 -11
- package/src/routing/codegen.ts +165 -105
- package/src/routing/index.ts +2 -0
- package/src/routing/scanner.ts +93 -23
- package/src/routing/segment-classify.ts +89 -0
- package/src/routing/status-file-lint.ts +3 -2
- package/src/routing/types.ts +17 -4
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
- package/src/search-params/define.ts +482 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +85 -0
- package/src/segment-params/define.ts +279 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +70 -29
- package/src/server/action-client.ts +46 -11
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +21 -4
- package/src/server/actions.ts +10 -9
- package/src/server/als-registry.ts +34 -6
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/debug.ts +1 -1
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-page-resolver.ts +154 -0
- package/src/server/deny-renderer.ts +24 -38
- package/src/server/dev-holding-server.ts +185 -0
- package/src/server/dev-warnings.ts +4 -49
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +74 -22
- package/src/server/fallback-error.ts +31 -15
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injectors.ts +280 -120
- package/src/server/index.ts +25 -177
- package/src/server/internal.ts +169 -0
- package/src/server/logger.ts +44 -36
- package/src/server/middleware-runner.ts +31 -4
- package/src/server/node-stream-transforms.ts +509 -0
- package/src/server/page-deny-boundary.tsx +56 -0
- package/src/server/pipeline-interception.ts +17 -16
- package/src/server/pipeline-metadata.ts +13 -0
- package/src/server/pipeline.ts +227 -62
- package/src/server/primitives.ts +111 -28
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +293 -132
- package/src/server/route-element-builder.ts +283 -191
- package/src/server/route-handler.ts +24 -4
- package/src/server/route-matcher.ts +24 -20
- package/src/server/rsc-entry/api-handler.ts +15 -16
- package/src/server/rsc-entry/error-renderer.ts +300 -89
- package/src/server/rsc-entry/helpers.ts +134 -5
- package/src/server/rsc-entry/index.ts +200 -112
- package/src/server/rsc-entry/rsc-payload.ts +65 -18
- package/src/server/rsc-entry/rsc-stream.ts +65 -13
- package/src/server/rsc-entry/ssr-bridge.ts +14 -5
- package/src/server/rsc-entry/ssr-renderer.ts +168 -38
- package/src/server/safe-load.ts +60 -0
- package/src/server/sitemap-generator.ts +338 -0
- package/src/server/sitemap-handler.ts +126 -0
- package/src/server/slot-resolver.ts +244 -229
- package/src/server/ssr-entry.ts +211 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/status-code-resolver.ts +1 -1
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +20 -9
- package/src/server/tree-builder.ts +92 -58
- package/src/server/types.ts +3 -6
- package/src/server/version-skew.ts +104 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +5 -1
- package/src/shims/navigation-client.ts +1 -1
- package/src/shims/navigation.ts +7 -2
- package/src/utils/directive-parser.ts +5 -2
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
- package/dist/_chunks/format-DviM89f0.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
- package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
- 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.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/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/cookies/index.js.map +0 -1
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.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/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/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/response-cache.d.ts +0 -54
- package/dist/server/response-cache.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/link-status-provider.tsx +0 -30
- package/src/client/transition-root.tsx +0 -166
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/prerender.ts +0 -139
- package/src/server/response-cache.ts +0 -410
package/src/routing/codegen.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* No runtime overhead — purely static type generation.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { existsSync } from 'node:fs';
|
|
12
|
-
import {
|
|
11
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { relative, posix } from 'node:path';
|
|
13
13
|
import type { RouteTree, SegmentNode } from './types.js';
|
|
14
14
|
|
|
15
15
|
/** A single route entry extracted from the segment tree. */
|
|
@@ -18,10 +18,10 @@ interface RouteEntry {
|
|
|
18
18
|
urlPath: string;
|
|
19
19
|
/** Accumulated params from all ancestor dynamic segments */
|
|
20
20
|
params: ParamEntry[];
|
|
21
|
-
/** Whether
|
|
21
|
+
/** Whether the page.tsx exports searchParams */
|
|
22
22
|
hasSearchParams: boolean;
|
|
23
|
-
/** Absolute path to
|
|
24
|
-
|
|
23
|
+
/** Absolute path to the page file that exports searchParams (for import paths) */
|
|
24
|
+
searchParamsPagePath?: string;
|
|
25
25
|
/** Whether this is an API route (route.ts) vs page route */
|
|
26
26
|
isApiRoute: boolean;
|
|
27
27
|
}
|
|
@@ -29,15 +29,17 @@ interface RouteEntry {
|
|
|
29
29
|
interface ParamEntry {
|
|
30
30
|
name: string;
|
|
31
31
|
type: 'string' | 'string[]' | 'string[] | undefined';
|
|
32
|
+
/** When a layout/page exports defineParams, the absolute path to that file. */
|
|
33
|
+
codecFilePath?: string;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
/** Options for route map generation. */
|
|
35
37
|
export interface CodegenOptions {
|
|
36
|
-
/** Absolute path to the app/ directory. Required for
|
|
38
|
+
/** Absolute path to the app/ directory. Required for page searchParams detection. */
|
|
37
39
|
appDir?: string;
|
|
38
40
|
/**
|
|
39
41
|
* Absolute path to the directory where the .d.ts file will be written.
|
|
40
|
-
* Used to compute correct relative import paths for
|
|
42
|
+
* Used to compute correct relative import paths for page files.
|
|
41
43
|
* Defaults to appDir when not provided (preserves backward compat for tests).
|
|
42
44
|
*/
|
|
43
45
|
outputDir?: string;
|
|
@@ -51,7 +53,7 @@ export interface CodegenOptions {
|
|
|
51
53
|
*/
|
|
52
54
|
export function generateRouteMap(tree: RouteTree, options: CodegenOptions = {}): string {
|
|
53
55
|
const routes: RouteEntry[] = [];
|
|
54
|
-
collectRoutes(tree.root, [],
|
|
56
|
+
collectRoutes(tree.root, [], routes);
|
|
55
57
|
|
|
56
58
|
// Sort routes alphabetically for deterministic output
|
|
57
59
|
routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));
|
|
@@ -71,15 +73,17 @@ export function generateRouteMap(tree: RouteTree, options: CodegenOptions = {}):
|
|
|
71
73
|
function collectRoutes(
|
|
72
74
|
node: SegmentNode,
|
|
73
75
|
ancestorParams: ParamEntry[],
|
|
74
|
-
appDir: string | undefined,
|
|
75
76
|
routes: RouteEntry[]
|
|
76
77
|
): void {
|
|
77
78
|
// Accumulate params from this segment
|
|
78
79
|
const params = [...ancestorParams];
|
|
79
80
|
if (node.paramName) {
|
|
81
|
+
// Check if layout or page exports a params codec for this segment
|
|
82
|
+
const codecFile = findParamsExport(node);
|
|
80
83
|
params.push({
|
|
81
84
|
name: node.paramName,
|
|
82
85
|
type: paramTypeForSegment(node.segmentType),
|
|
86
|
+
codecFilePath: codecFile,
|
|
83
87
|
});
|
|
84
88
|
}
|
|
85
89
|
|
|
@@ -95,13 +99,14 @@ function collectRoutes(
|
|
|
95
99
|
isApiRoute,
|
|
96
100
|
};
|
|
97
101
|
|
|
98
|
-
// Detect
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
const searchParamsFile = findSearchParamsFile(segmentDir);
|
|
102
|
-
if (searchParamsFile) {
|
|
102
|
+
// Detect searchParams export from params.ts (primary) or page.tsx (fallback)
|
|
103
|
+
if (isPage) {
|
|
104
|
+
if (node.params && fileHasExport(node.params.filePath, 'searchParams')) {
|
|
103
105
|
entry.hasSearchParams = true;
|
|
104
|
-
entry.
|
|
106
|
+
entry.searchParamsPagePath = node.params.filePath;
|
|
107
|
+
} else if (node.page && fileHasExport(node.page.filePath, 'searchParams')) {
|
|
108
|
+
entry.hasSearchParams = true;
|
|
109
|
+
entry.searchParamsPagePath = node.page.filePath;
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
|
|
@@ -110,12 +115,12 @@ function collectRoutes(
|
|
|
110
115
|
|
|
111
116
|
// Recurse into children
|
|
112
117
|
for (const child of node.children) {
|
|
113
|
-
collectRoutes(child, params,
|
|
118
|
+
collectRoutes(child, params, routes);
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
// Recurse into slots (they share the parent's URL path, but may have their own pages)
|
|
117
122
|
for (const [, slot] of node.slots) {
|
|
118
|
-
collectRoutes(slot, params,
|
|
123
|
+
collectRoutes(slot, params, routes);
|
|
119
124
|
}
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -134,33 +139,43 @@ function paramTypeForSegment(segmentType: string): ParamEntry['type'] {
|
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
/**
|
|
137
|
-
*
|
|
142
|
+
* Check if a file exports a specific named export.
|
|
138
143
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
144
|
+
* Uses a lightweight regex check — not full AST parsing. The actual type
|
|
145
|
+
* extraction happens via the TypeScript compiler in the generated .d.ts.
|
|
141
146
|
*/
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
function fileHasExport(filePath: string, exportName: string): boolean {
|
|
148
|
+
if (!existsSync(filePath)) return false;
|
|
149
|
+
try {
|
|
150
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
151
|
+
const e = exportName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
152
|
+
return (
|
|
153
|
+
new RegExp(`export\\s+(const|let|var)\\s+${e}\\b`).test(content) ||
|
|
154
|
+
new RegExp(`export\\s*\\{[^}]*\\b${e}\\b[^}]*\\}`).test(content)
|
|
155
|
+
);
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
150
158
|
}
|
|
151
|
-
// Fallback: construct from urlPath (imprecise for groups, but acceptable)
|
|
152
|
-
return appDir;
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/**
|
|
156
|
-
* Find
|
|
162
|
+
* Find which file exports `segmentParams` for a dynamic segment.
|
|
163
|
+
*
|
|
164
|
+
* Priority: params.ts (convention file) > layout > page.
|
|
165
|
+
* params.ts is the canonical location (TIM-508). Layout/page fallback
|
|
166
|
+
* exists for backward compat during migration.
|
|
157
167
|
*/
|
|
158
|
-
function
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
function findParamsExport(node: SegmentNode): string | undefined {
|
|
169
|
+
// params.ts convention file — primary location
|
|
170
|
+
if (node.params && fileHasExport(node.params.filePath, 'segmentParams')) {
|
|
171
|
+
return node.params.filePath;
|
|
172
|
+
}
|
|
173
|
+
// Fallback: layout or page export (legacy, will be removed)
|
|
174
|
+
if (node.layout && fileHasExport(node.layout.filePath, 'segmentParams')) {
|
|
175
|
+
return node.layout.filePath;
|
|
176
|
+
}
|
|
177
|
+
if (node.page && fileHasExport(node.page.filePath, 'segmentParams')) {
|
|
178
|
+
return node.page.filePath;
|
|
164
179
|
}
|
|
165
180
|
return undefined;
|
|
166
181
|
}
|
|
@@ -184,11 +199,11 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
|
|
|
184
199
|
lines.push(' interface Routes {');
|
|
185
200
|
|
|
186
201
|
for (const route of routes) {
|
|
187
|
-
const paramsType = formatParamsType(route.params);
|
|
202
|
+
const paramsType = formatParamsType(route.params, importBase);
|
|
188
203
|
const searchParamsType = formatSearchParamsType(route, importBase);
|
|
189
204
|
|
|
190
205
|
lines.push(` '${route.urlPath}': {`);
|
|
191
|
-
lines.push(`
|
|
206
|
+
lines.push(` segmentParams: ${paramsType}`);
|
|
192
207
|
lines.push(` searchParams: ${searchParamsType}`);
|
|
193
208
|
lines.push(` }`);
|
|
194
209
|
}
|
|
@@ -200,15 +215,9 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
|
|
|
200
215
|
// Generate @timber-js/app/server augmentation — typed searchParams() generic
|
|
201
216
|
const pageRoutes = routes.filter((r) => !r.isApiRoute);
|
|
202
217
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
lines.push(
|
|
207
|
-
" export function searchParams<R extends keyof Routes>(): Promise<Routes[R]['searchParams']>"
|
|
208
|
-
);
|
|
209
|
-
lines.push('}');
|
|
210
|
-
lines.push('');
|
|
211
|
-
}
|
|
218
|
+
// Note: searchParams() always returns Promise<URLSearchParams>.
|
|
219
|
+
// Typed parsing is done via definition.parse(searchParams()).
|
|
220
|
+
// No module augmentation needed for @timber-js/app/server.
|
|
212
221
|
|
|
213
222
|
// Generate overloads for @timber-js/app/client
|
|
214
223
|
const dynamicRoutes = routes.filter((r) => r.params.length > 0);
|
|
@@ -223,10 +232,10 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
|
|
|
223
232
|
// useParams overloads
|
|
224
233
|
if (dynamicRoutes.length > 0) {
|
|
225
234
|
for (const route of dynamicRoutes) {
|
|
226
|
-
const paramsType = formatParamsType(route.params);
|
|
227
|
-
lines.push(` export function
|
|
235
|
+
const paramsType = formatParamsType(route.params, importBase);
|
|
236
|
+
lines.push(` export function useSegmentParams(route: '${route.urlPath}'): ${paramsType}`);
|
|
228
237
|
}
|
|
229
|
-
lines.push(' export function
|
|
238
|
+
lines.push(' export function useSegmentParams(): Record<string, string | string[]>');
|
|
230
239
|
lines.push('');
|
|
231
240
|
}
|
|
232
241
|
|
|
@@ -236,10 +245,14 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
|
|
|
236
245
|
lines.push('');
|
|
237
246
|
}
|
|
238
247
|
|
|
239
|
-
// Typed Link overloads
|
|
248
|
+
// Typed Link overloads — per-route with DIRECT types (no conditionals).
|
|
249
|
+
// Direct types preserve TypeScript's excess property checking.
|
|
250
|
+
// The catch-all overload (segmentParams?: never) lives in link.tsx.
|
|
251
|
+
// See TIM-624.
|
|
240
252
|
if (pageRoutes.length > 0) {
|
|
241
|
-
lines.push(' // Typed Link
|
|
253
|
+
lines.push(' // Typed Link overloads per route');
|
|
242
254
|
lines.push(...formatTypedLinkOverloads(pageRoutes, importBase));
|
|
255
|
+
lines.push('');
|
|
243
256
|
}
|
|
244
257
|
|
|
245
258
|
lines.push('}');
|
|
@@ -252,31 +265,56 @@ function formatDeclarationFile(routes: RouteEntry[], importBase?: string): strin
|
|
|
252
265
|
/**
|
|
253
266
|
* Format the params type for a route entry.
|
|
254
267
|
*/
|
|
255
|
-
function formatParamsType(params: ParamEntry[]): string {
|
|
268
|
+
function formatParamsType(params: ParamEntry[], importBase?: string): string {
|
|
256
269
|
if (params.length === 0) {
|
|
257
270
|
return '{}';
|
|
258
271
|
}
|
|
259
272
|
|
|
260
|
-
const fields = params.map((p) =>
|
|
273
|
+
const fields = params.map((p) => {
|
|
274
|
+
if (p.codecFilePath) {
|
|
275
|
+
// Use the codec's inferred type from the layout/page file
|
|
276
|
+
const absPath = p.codecFilePath.replace(/\.(ts|tsx)$/, '');
|
|
277
|
+
let importPath: string;
|
|
278
|
+
if (importBase) {
|
|
279
|
+
importPath = './' + relative(importBase, absPath).replace(/\\/g, '/');
|
|
280
|
+
} else {
|
|
281
|
+
importPath = './' + posix.basename(absPath);
|
|
282
|
+
}
|
|
283
|
+
// Extract T from the 'segmentParams' named export's ParamsDefinition<T>
|
|
284
|
+
const codecType = `(typeof import('${importPath}'))['segmentParams'] extends import('@timber-js/app/segment-params').ParamsDefinition<infer T> ? T[${JSON.stringify(p.name)}] : ${p.type}`;
|
|
285
|
+
return `${p.name}: ${codecType}`;
|
|
286
|
+
}
|
|
287
|
+
return `${p.name}: ${p.type}`;
|
|
288
|
+
});
|
|
261
289
|
return `{ ${fields.join('; ')} }`;
|
|
262
290
|
}
|
|
263
291
|
|
|
264
292
|
/**
|
|
265
|
-
* Format the params type for Link
|
|
293
|
+
* Format the params type for Link overloads.
|
|
266
294
|
*
|
|
267
295
|
* Link params accept `string | number` for single dynamic segments
|
|
268
296
|
* (convenience — values are stringified at runtime). Catch-all and
|
|
269
297
|
* optional catch-all remain `string[]` / `string[] | undefined`.
|
|
270
298
|
*
|
|
271
|
-
*
|
|
299
|
+
* Uses DIRECT types (not conditional) to preserve excess property checking.
|
|
272
300
|
*/
|
|
273
|
-
function formatLinkParamsType(params: ParamEntry[]): string {
|
|
301
|
+
function formatLinkParamsType(params: ParamEntry[], importBase?: string): string {
|
|
274
302
|
if (params.length === 0) {
|
|
275
303
|
return '{}';
|
|
276
304
|
}
|
|
277
305
|
|
|
278
306
|
const fields = params.map((p) => {
|
|
279
|
-
|
|
307
|
+
if (p.codecFilePath) {
|
|
308
|
+
const absPath = p.codecFilePath.replace(/\.(ts|tsx)$/, '');
|
|
309
|
+
let importPath: string;
|
|
310
|
+
if (importBase) {
|
|
311
|
+
importPath = './' + relative(importBase, absPath).replace(/\\/g, '/');
|
|
312
|
+
} else {
|
|
313
|
+
importPath = './' + posix.basename(absPath);
|
|
314
|
+
}
|
|
315
|
+
const codecType = `(typeof import('${importPath}'))['segmentParams'] extends import('@timber-js/app/segment-params').ParamsDefinition<infer T> ? T[${JSON.stringify(p.name)}] : ${p.type}`;
|
|
316
|
+
return `${p.name}: ${codecType}`;
|
|
317
|
+
}
|
|
280
318
|
const type = p.type === 'string' ? 'string | number' : p.type;
|
|
281
319
|
return `${p.name}: ${type}`;
|
|
282
320
|
});
|
|
@@ -286,13 +324,13 @@ function formatLinkParamsType(params: ParamEntry[]): string {
|
|
|
286
324
|
/**
|
|
287
325
|
* Format the searchParams type for a route entry.
|
|
288
326
|
*
|
|
289
|
-
* When a
|
|
327
|
+
* When a page.tsx exports searchParams, we reference its inferred type via an import type.
|
|
290
328
|
* The import path is relative to `importBase` (the directory where the .d.ts will be
|
|
291
329
|
* written). When importBase is undefined, falls back to a bare relative path.
|
|
292
330
|
*/
|
|
293
331
|
function formatSearchParamsType(route: RouteEntry, importBase?: string): string {
|
|
294
|
-
if (route.hasSearchParams && route.
|
|
295
|
-
const absPath = route.
|
|
332
|
+
if (route.hasSearchParams && route.searchParamsPagePath) {
|
|
333
|
+
const absPath = route.searchParamsPagePath.replace(/\.(ts|tsx)$/, '');
|
|
296
334
|
let importPath: string;
|
|
297
335
|
if (importBase) {
|
|
298
336
|
// Make the path relative to the output directory, converted to posix separators
|
|
@@ -300,10 +338,8 @@ function formatSearchParamsType(route: RouteEntry, importBase?: string): string
|
|
|
300
338
|
} else {
|
|
301
339
|
importPath = './' + posix.basename(absPath);
|
|
302
340
|
}
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
// a namespace member access which doesn't work for default exports.
|
|
306
|
-
return `(typeof import('${importPath}'))['default'] extends import('@timber-js/app/search-params').SearchParamsDefinition<infer T> ? T : never`;
|
|
341
|
+
// Extract the type from the named 'searchParams' export of the page module.
|
|
342
|
+
return `(typeof import('${importPath}'))['searchParams'] extends import('@timber-js/app/search-params').SearchParamsDefinition<infer T> ? T : never`;
|
|
307
343
|
}
|
|
308
344
|
return '{}';
|
|
309
345
|
}
|
|
@@ -338,59 +374,83 @@ function formatUseQueryStatesOverloads(routes: RouteEntry[], importBase?: string
|
|
|
338
374
|
}
|
|
339
375
|
|
|
340
376
|
/**
|
|
341
|
-
*
|
|
377
|
+
* Build a TypeScript template literal pattern for a dynamic route.
|
|
378
|
+
* e.g. '/products/[id]' → '/products/${string}'
|
|
379
|
+
* '/blog/[...slug]' → '/blog/${string}'
|
|
380
|
+
* '/docs/[[...path]]' → '/docs/${string}' (also matches /docs)
|
|
381
|
+
* '/[org]/[repo]' → '/${string}/${string}'
|
|
382
|
+
*/
|
|
383
|
+
function buildResolvedPattern(route: RouteEntry): string | null {
|
|
384
|
+
const parts = route.urlPath.split('/');
|
|
385
|
+
const templateParts = parts.map((part) => {
|
|
386
|
+
if (part.startsWith('[[...') && part.endsWith(']]')) {
|
|
387
|
+
// Optional catch-all — matches any trailing path
|
|
388
|
+
return '${string}';
|
|
389
|
+
}
|
|
390
|
+
if (part.startsWith('[...') && part.endsWith(']')) {
|
|
391
|
+
// Catch-all — matches one or more segments
|
|
392
|
+
return '${string}';
|
|
393
|
+
}
|
|
394
|
+
if (part.startsWith('[') && part.endsWith(']')) {
|
|
395
|
+
// Dynamic segment
|
|
396
|
+
return '${string}';
|
|
397
|
+
}
|
|
398
|
+
return part;
|
|
399
|
+
});
|
|
400
|
+
return templateParts.join('/');
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Generate typed Link call signatures via LinkFunction interface merging.
|
|
342
405
|
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
406
|
+
* Each call signature uses DIRECT types (not conditional types) for
|
|
407
|
+
* segmentParams, preserving TypeScript's excess property checking.
|
|
408
|
+
* Interface merging is the only reliable way to add "overloads" via
|
|
409
|
+
* module augmentation — function overloads can't be augmented.
|
|
347
410
|
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
411
|
+
* The catch-all call signature (external protocols + computed strings)
|
|
412
|
+
* lives in link.tsx. See TIM-624.
|
|
350
413
|
*/
|
|
351
414
|
function formatTypedLinkOverloads(routes: RouteEntry[], importBase?: string): string[] {
|
|
352
415
|
const lines: string[] = [];
|
|
416
|
+
const baseProps =
|
|
417
|
+
"Omit<import('react').AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & { prefetch?: boolean; scroll?: boolean; preserveSearchParams?: true | string[]; onNavigate?: import('./client/link.js').OnNavigateHandler; children?: import('react').ReactNode }";
|
|
353
418
|
|
|
419
|
+
lines.push(' interface LinkFunction {');
|
|
354
420
|
for (const route of routes) {
|
|
355
421
|
const hasDynamicParams = route.params.length > 0;
|
|
356
|
-
const
|
|
422
|
+
const paramsProp = hasDynamicParams
|
|
423
|
+
? `segmentParams: ${formatLinkParamsType(route.params, importBase)}`
|
|
424
|
+
: 'segmentParams?: never';
|
|
425
|
+
|
|
357
426
|
const searchParamsType = route.hasSearchParams
|
|
358
427
|
? formatSearchParamsType(route, importBase)
|
|
359
428
|
: null;
|
|
360
|
-
|
|
429
|
+
const searchParamsProp = searchParamsType
|
|
430
|
+
? `searchParams?: { definition: SearchParamsDefinition<${searchParamsType}>; values: Partial<${searchParamsType}> }`
|
|
431
|
+
: 'searchParams?: never';
|
|
432
|
+
|
|
433
|
+
lines.push(` (props: ${baseProps} & {`);
|
|
434
|
+
lines.push(` href: '${route.urlPath}'`);
|
|
435
|
+
lines.push(` ${paramsProp}`);
|
|
436
|
+
lines.push(` ${searchParamsProp}`);
|
|
437
|
+
lines.push(` }): import('react').JSX.Element`);
|
|
438
|
+
|
|
439
|
+
// For dynamic routes, also emit a resolved-pattern signature.
|
|
440
|
+
// This accepts template literal hrefs like `/products/${id}` without
|
|
441
|
+
// segmentParams — the params are already interpolated into the URL.
|
|
361
442
|
if (hasDynamicParams) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
:
|
|
366
|
-
|
|
367
|
-
`
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
lines.push(` params: ${paramsType}`);
|
|
371
|
-
lines.push(` ${spProp}`);
|
|
372
|
-
lines.push(` prefetch?: boolean; scroll?: boolean; children?: import('react').ReactNode`);
|
|
373
|
-
lines.push(` }): import('react').JSX.Element`);
|
|
374
|
-
} else {
|
|
375
|
-
// Static route — no params needed
|
|
376
|
-
const spProp = searchParamsType
|
|
377
|
-
? `searchParams?: { definition: SearchParamsDefinition<${searchParamsType}>; values: Partial<${searchParamsType}> }`
|
|
378
|
-
: `searchParams?: never`;
|
|
379
|
-
lines.push(
|
|
380
|
-
` export function Link(props: Omit<import('react').AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {`
|
|
381
|
-
);
|
|
382
|
-
lines.push(` href: '${route.urlPath}'`);
|
|
383
|
-
lines.push(` params?: never`);
|
|
384
|
-
lines.push(` ${spProp}`);
|
|
385
|
-
lines.push(` prefetch?: boolean; scroll?: boolean; children?: import('react').ReactNode`);
|
|
386
|
-
lines.push(` }): import('react').JSX.Element`);
|
|
443
|
+
const templatePattern = buildResolvedPattern(route);
|
|
444
|
+
if (templatePattern) {
|
|
445
|
+
lines.push(` (props: ${baseProps} & {`);
|
|
446
|
+
lines.push(` href: \`${templatePattern}\``);
|
|
447
|
+
lines.push(` segmentParams?: never`);
|
|
448
|
+
lines.push(` ${searchParamsProp}`);
|
|
449
|
+
lines.push(` }): import('react').JSX.Element`);
|
|
450
|
+
}
|
|
387
451
|
}
|
|
388
452
|
}
|
|
389
|
-
|
|
390
|
-
// Fallback overload for arbitrary string hrefs (escape hatch)
|
|
391
|
-
lines.push(
|
|
392
|
-
` export function Link(props: import('./client/link.js').LinkProps): import('react').JSX.Element`
|
|
393
|
-
);
|
|
453
|
+
lines.push(' }');
|
|
394
454
|
|
|
395
455
|
return lines;
|
|
396
456
|
}
|
package/src/routing/index.ts
CHANGED
|
@@ -12,3 +12,5 @@ export type {
|
|
|
12
12
|
export { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS } from './types.js';
|
|
13
13
|
export { collectInterceptionRewrites } from './interception.js';
|
|
14
14
|
export type { InterceptionRewrite } from './interception.js';
|
|
15
|
+
export { classifyUrlSegment } from './segment-classify.js';
|
|
16
|
+
export type { UrlSegment } from './segment-classify.js';
|
package/src/routing/scanner.ts
CHANGED
|
@@ -18,8 +18,9 @@ import type {
|
|
|
18
18
|
ScannerConfig,
|
|
19
19
|
InterceptionMarker,
|
|
20
20
|
} from './types.js';
|
|
21
|
+
import { classifyUrlSegment } from './segment-classify.js';
|
|
21
22
|
import { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS } from './types.js';
|
|
22
|
-
import { classifyMetadataRoute, isDynamicMetadataExtension } from '
|
|
23
|
+
import { classifyMetadataRoute, isDynamicMetadataExtension } from '../server/metadata-routes.js';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Pattern matching encoded path delimiters that must be rejected during route discovery.
|
|
@@ -53,7 +54,7 @@ const LEGACY_STATUS_FILES: Record<string, number> = {
|
|
|
53
54
|
/**
|
|
54
55
|
* File convention names that are always .ts/.tsx (never .mdx etc.)
|
|
55
56
|
*/
|
|
56
|
-
const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', '
|
|
57
|
+
const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'params']);
|
|
57
58
|
|
|
58
59
|
/**
|
|
59
60
|
* Status-code file patterns:
|
|
@@ -83,6 +84,14 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
|
|
|
83
84
|
tree.proxy = proxyFile;
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
// Check for global-error.{tsx,ts,jsx,js} at app root.
|
|
88
|
+
// Tier 2 error page — renders standalone (no layouts) when no segment-level
|
|
89
|
+
// error file is found. See design/10-error-handling.md §"Tier 2".
|
|
90
|
+
const globalErrorFile = findPageExtFile(appDir, 'global-error', extSet);
|
|
91
|
+
if (globalErrorFile) {
|
|
92
|
+
tree.globalError = globalErrorFile;
|
|
93
|
+
}
|
|
94
|
+
|
|
86
95
|
// Scan the root directory's files
|
|
87
96
|
scanSegmentFiles(appDir, tree.root, extSet);
|
|
88
97
|
|
|
@@ -92,6 +101,10 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
|
|
|
92
101
|
// Validate: detect route group collisions (different groups producing pages at the same URL)
|
|
93
102
|
validateRouteGroupCollisions(tree.root);
|
|
94
103
|
|
|
104
|
+
// Validate: detect duplicate param names in nested dynamic segments
|
|
105
|
+
// e.g., /[id]/items/[id] — same param name in ancestor and descendant
|
|
106
|
+
validateDuplicateParamNames(tree.root);
|
|
107
|
+
|
|
95
108
|
return tree;
|
|
96
109
|
}
|
|
97
110
|
|
|
@@ -153,22 +166,12 @@ export function classifySegment(dirName: string): {
|
|
|
153
166
|
return { type: 'group' };
|
|
154
167
|
}
|
|
155
168
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
// Catch-all: [...name]
|
|
163
|
-
if (dirName.startsWith('[...') && dirName.endsWith(']')) {
|
|
164
|
-
const paramName = dirName.slice(4, -1);
|
|
165
|
-
return { type: 'catch-all', paramName };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Dynamic: [name]
|
|
169
|
-
if (dirName.startsWith('[') && dirName.endsWith(']')) {
|
|
170
|
-
const paramName = dirName.slice(1, -1);
|
|
171
|
-
return { type: 'dynamic', paramName };
|
|
169
|
+
// Bracket-syntax segments: [param], [...param], [[...param]]
|
|
170
|
+
// Delegated to the shared character-based classifier. If you change
|
|
171
|
+
// bracket syntax, update segment-classify.ts — not here.
|
|
172
|
+
const urlSeg = classifyUrlSegment(dirName);
|
|
173
|
+
if (urlSeg.kind !== 'static') {
|
|
174
|
+
return { type: urlSeg.kind, paramName: urlSeg.name };
|
|
172
175
|
}
|
|
173
176
|
|
|
174
177
|
return { type: 'static' };
|
|
@@ -278,11 +281,8 @@ function scanSegmentFiles(dirPath: string, node: SegmentNode, extSet: Set<string
|
|
|
278
281
|
case 'route':
|
|
279
282
|
node.route = file;
|
|
280
283
|
break;
|
|
281
|
-
case '
|
|
282
|
-
node.
|
|
283
|
-
break;
|
|
284
|
-
case 'search-params':
|
|
285
|
-
node.searchParams = file;
|
|
284
|
+
case 'params':
|
|
285
|
+
node.params = file;
|
|
286
286
|
break;
|
|
287
287
|
}
|
|
288
288
|
continue;
|
|
@@ -482,6 +482,54 @@ function collectRoutableLeaves(
|
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
/**
|
|
486
|
+
* Validate that no route chain contains duplicate dynamic param names.
|
|
487
|
+
*
|
|
488
|
+
* Example violation:
|
|
489
|
+
* app/[id]/items/[id]/page.tsx — 'id' appears twice in the ancestor chain.
|
|
490
|
+
*
|
|
491
|
+
* Route groups are transparent — params accumulate through them.
|
|
492
|
+
* Slots are independent — duplicate detection does NOT cross slot boundaries.
|
|
493
|
+
*
|
|
494
|
+
* See design/07-routing.md §"Duplicate Param Name Detection"
|
|
495
|
+
*/
|
|
496
|
+
function validateDuplicateParamNames(root: SegmentNode): void {
|
|
497
|
+
walkForDuplicateParams(root, new Map());
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Recursively walk the segment tree, tracking seen param names → segment paths.
|
|
502
|
+
* Throws on the first duplicate found.
|
|
503
|
+
*/
|
|
504
|
+
function walkForDuplicateParams(node: SegmentNode, seen: Map<string, string>): void {
|
|
505
|
+
// If this node introduces a param name, check for duplicates
|
|
506
|
+
if (node.paramName) {
|
|
507
|
+
const existing = seen.get(node.paramName);
|
|
508
|
+
if (existing) {
|
|
509
|
+
throw new Error(
|
|
510
|
+
`[timber] Duplicate param name '${node.paramName}' in route chain.\n` +
|
|
511
|
+
` First defined at: ${existing}\n` +
|
|
512
|
+
` Duplicate at: ${node.urlPath || '/'}\n` +
|
|
513
|
+
` Rename one of the segments to avoid ambiguity.`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
// Add to seen for descendants (use a new Map to avoid polluting siblings)
|
|
517
|
+
seen = new Map(seen);
|
|
518
|
+
seen.set(node.paramName, node.urlPath || '/');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Recurse into children (they inherit the accumulated params)
|
|
522
|
+
for (const child of node.children) {
|
|
523
|
+
walkForDuplicateParams(child, seen);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Slots are independent parallel routes — start fresh param tracking
|
|
527
|
+
// (a slot's params don't conflict with the main route's params)
|
|
528
|
+
for (const [, slotNode] of node.slots) {
|
|
529
|
+
walkForDuplicateParams(slotNode, new Map(seen));
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
485
533
|
/**
|
|
486
534
|
* Find a fixed-extension file (proxy.ts) in a directory.
|
|
487
535
|
*/
|
|
@@ -498,3 +546,25 @@ function findFixedFile(dirPath: string, name: string): RouteFile | undefined {
|
|
|
498
546
|
}
|
|
499
547
|
return undefined;
|
|
500
548
|
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Find a file using the configured page extensions (tsx, ts, jsx, js, mdx, etc.).
|
|
552
|
+
* Used for app-root conventions like global-error that aren't per-segment.
|
|
553
|
+
*/
|
|
554
|
+
function findPageExtFile(
|
|
555
|
+
dirPath: string,
|
|
556
|
+
name: string,
|
|
557
|
+
extSet: Set<string>
|
|
558
|
+
): RouteFile | undefined {
|
|
559
|
+
for (const ext of extSet) {
|
|
560
|
+
const fullPath = join(dirPath, `${name}.${ext}`);
|
|
561
|
+
try {
|
|
562
|
+
if (statSync(fullPath).isFile()) {
|
|
563
|
+
return { filePath: fullPath, extension: ext };
|
|
564
|
+
}
|
|
565
|
+
} catch {
|
|
566
|
+
// File doesn't exist
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|