@timber-js/app 0.2.0-alpha.18 → 0.2.0-alpha.181
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 +344 -0
- package/dist/_chunks/actions-O_LsyCE4.js +317 -0
- package/dist/_chunks/actions-O_LsyCE4.js.map +1 -0
- package/dist/_chunks/build-output-helper-DF5uScqS.js +158 -0
- package/dist/_chunks/build-output-helper-DF5uScqS.js.map +1 -0
- package/dist/_chunks/cache-api-B-lhk9p4.js +1202 -0
- package/dist/_chunks/cache-api-B-lhk9p4.js.map +1 -0
- package/dist/_chunks/canonicalize-DQHyFClh.js +248 -0
- package/dist/_chunks/canonicalize-DQHyFClh.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-D3naS3eH.js +688 -0
- package/dist/_chunks/cli-schema-sync-D3naS3eH.js.map +1 -0
- package/dist/_chunks/cloudflare-AHoWYTYr.js +1188 -0
- package/dist/_chunks/cloudflare-AHoWYTYr.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/define-COtkxMRT.js +191 -0
- package/dist/_chunks/define-COtkxMRT.js.map +1 -0
- package/dist/_chunks/define-c4au4I9R.js +82 -0
- package/dist/_chunks/define-c4au4I9R.js.map +1 -0
- package/dist/_chunks/dist-BA3u1z3W.js +423 -0
- package/dist/_chunks/dist-BA3u1z3W.js.map +1 -0
- package/dist/_chunks/fast-hash-D6hIVt1Y.js +36 -0
- package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +1 -0
- package/dist/_chunks/format-CfwjgPz9.js +14 -0
- package/dist/_chunks/format-CfwjgPz9.js.map +1 -0
- package/dist/_chunks/href-validation-CMc5JRls.js +141 -0
- package/dist/_chunks/href-validation-CMc5JRls.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/logger-AWfuX-KJ.js +1468 -0
- package/dist/_chunks/logger-AWfuX-KJ.js.map +1 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js +124 -0
- package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -0
- package/dist/_chunks/plugin-context---kTF5v8.js +315 -0
- package/dist/_chunks/plugin-context---kTF5v8.js.map +1 -0
- package/dist/_chunks/registry-DbJPKoBp.js +20 -0
- package/dist/_chunks/registry-DbJPKoBp.js.map +1 -0
- package/dist/_chunks/resolve-schema-Dz3fcFUo.js +50 -0
- package/dist/_chunks/resolve-schema-Dz3fcFUo.js.map +1 -0
- package/dist/_chunks/router-ref-CtmF-aPv.js +28 -0
- package/dist/_chunks/router-ref-CtmF-aPv.js.map +1 -0
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +119 -0
- package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +1 -0
- package/dist/_chunks/segment-classify-Byy425ng.js +176 -0
- package/dist/_chunks/segment-classify-Byy425ng.js.map +1 -0
- package/dist/_chunks/segment-context-ZDnXDkbz.js +34 -0
- package/dist/_chunks/segment-context-ZDnXDkbz.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-BOWsq18U.js} +1 -1
- package/dist/_chunks/ssr-data-BOWsq18U.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-DFvWd-EA.js} +71 -26
- package/dist/_chunks/use-query-states-DFvWd-EA.js.map +1 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js +151 -0
- package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -0
- package/dist/_chunks/walkers-BtTlKviE.js +1002 -0
- package/dist/_chunks/walkers-BtTlKviE.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +29 -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 +73 -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 +124 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +189 -21
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -188
- package/dist/adapters/compress-module.d.ts +5 -4
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +41 -3
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +224 -172
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/types.d.ts +2 -6
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/cache-api.d.ts +48 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- 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 +31 -8
- 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 +140 -8
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +19 -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 +20 -10
- 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/fastly-purge.d.ts +25 -0
- package/dist/cdn/fastly-purge.d.ts.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/purge-store.d.ts +23 -0
- package/dist/cdn/purge-store.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.d.ts +16 -0
- package/dist/cdn/workers-cache-purge.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 +35 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +113 -34
- 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 +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 +29 -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 +27 -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 +28 -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 +47 -10
- package/dist/client/error-boundary.js.map +1 -1
- 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/history.d.ts +21 -6
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +10 -24
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +185 -1134
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +19 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +938 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link.d.ts +69 -60
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-api.d.ts +121 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +3 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +119 -0
- package/dist/client/navigation-root.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/router-ref.d.ts +1 -1
- package/dist/client/router.d.ts +99 -14
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +62 -15
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +30 -7
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +57 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/segment-update-context.d.ts +21 -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-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 +13 -4
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/state.d.ts +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-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.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 +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +12 -5
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +8 -6
- 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 +284 -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/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 +58 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +2 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +257 -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/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 +54 -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 +110 -6
- 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/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 +4 -2
- package/dist/fonts/google.d.ts.map +1 -1
- package/dist/fonts/local.d.ts +4 -4
- 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 +46 -180
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9243 -14093
- 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 +217 -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 +43 -7
- 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-server.d.ts +17 -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/mdx.d.ts +1 -1
- 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 +42 -0
- package/dist/plugins/prerender-sugar.d.ts.map +1 -0
- package/dist/plugins/request-dep.d.ts +21 -0
- package/dist/plugins/request-dep.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 +5 -26
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +67 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +64 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +7 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts +41 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/export-detect.d.ts +56 -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 +7 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +4 -2
- package/dist/routing/interception.d.ts +0 -5
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +90 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/manifest-codegen.d.ts +32 -0
- package/dist/routing/manifest-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +1 -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 +81 -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/types.d.ts +81 -25
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +51 -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 +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +91 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +188 -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 +34 -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 +89 -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 +8 -3
- 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 +35 -1
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +6 -30
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +93 -11
- 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 +12 -29
- 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/coalesce-tick.d.ts +40 -0
- package/dist/server/coalesce-tick.d.ts.map +1 -0
- 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/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/deny-boundary.d.ts +117 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +2 -2
- 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 +13 -11
- 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 +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 +42 -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/html-injector-core.d.ts +242 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +82 -41
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +11 -47
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +182 -2906
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +49 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +3892 -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-routes.d.ts +60 -11
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata.d.ts +8 -0
- package/dist/server/metadata.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 +119 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +54 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +95 -0
- package/dist/server/pipeline-helpers.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-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +59 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +140 -19
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +117 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/prebuilt/cache-key.d.ts +62 -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 +23 -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 +78 -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 +66 -0
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts +120 -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 +88 -43
- 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/render-utils.d.ts +25 -0
- package/dist/server/render-utils.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +62 -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/route-element-builder.d.ts +53 -25
- 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 +25 -36
- package/dist/server/route-matcher.d.ts.map +1 -1
- 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 +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +69 -37
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +28 -6
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +51 -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 +6 -6
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +25 -1
- 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 +36 -4
- 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/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 +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 +66 -5
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +121 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -0
- package/dist/server/ssr-entry.d.ts +2 -43
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +64 -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/state-tree-diff.d.ts +72 -9
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +22 -11
- 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 +44 -9
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +69 -30
- package/dist/server/tree-builder.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 +71 -6
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/utils/mdx-file.d.ts +15 -0
- package/dist/server/utils/mdx-file.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/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/redirect-type.d.ts +17 -0
- package/dist/shared/redirect-type.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 +35 -11
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +11 -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 +233 -0
- package/docs/api/31-api-client.mdx +161 -0
- package/docs/api/32-api-cache.mdx +311 -0
- package/docs/api/33-api-search-params.mdx +154 -0
- package/docs/api/34-api-config.mdx +325 -0
- package/docs/api/35-api-typescript.mdx +170 -0
- package/docs/api/36-cli.mdx +143 -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/03b-access-control.mdx +130 -0
- package/docs/learn/04-loading-states.mdx +67 -0
- package/docs/learn/04b-the-flush-point.mdx +115 -0
- package/docs/learn/05-typed-params.mdx +275 -0
- package/docs/learn/06-forms-and-actions.mdx +146 -0
- package/docs/learn/07-typed-routes.mdx +127 -0
- package/docs/learn/08-streaming.mdx +146 -0
- package/docs/learn/09-caching.mdx +252 -0
- package/docs/learn/10-middleware.mdx +157 -0
- package/docs/learn/11-error-handling.mdx +156 -0
- package/docs/learn/12-client-navigation.mdx +176 -0
- package/docs/learn/13-configuration.mdx +162 -0
- package/docs/learn/14-deploying.mdx +264 -0
- package/docs/more/01-advanced-routing.mdx +173 -0
- package/docs/more/02-advanced-forms.mdx +137 -0
- package/docs/more/03-coming-from-nextjs.mdx +186 -0
- package/docs/more/04-metadata-and-fonts.mdx +193 -0
- package/docs/more/04b-mdx.mdx +209 -0
- package/docs/more/05-content-collections.mdx +90 -0
- package/docs/more/06-instrumentation.mdx +214 -0
- package/docs/more/07-security.mdx +129 -0
- package/docs/more/08-developer-experience.mdx +134 -0
- package/docs/more/40-why-timber.mdx +50 -0
- package/docs/more/41-timber-vs-nextjs.mdx +81 -0
- package/docs/more/42-timber-vs-others.mdx +68 -0
- package/docs/more/50-ai-agent-instructions.mdx +169 -0
- package/llms.txt +55 -0
- package/package.json +105 -26
- package/src/adapters/build-output-helper.ts +199 -0
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +204 -0
- package/src/adapters/cloudflare.ts +620 -129
- package/src/adapters/compress-module.ts +27 -92
- package/src/adapters/nitro.ts +266 -122
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/adapters/shared.ts +68 -0
- package/src/adapters/types.ts +2 -7
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +107 -0
- package/src/cache/handler-store.ts +76 -0
- package/src/cache/index.ts +114 -21
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/json-lossy-check.ts +75 -0
- package/src/cache/redis-handler.ts +197 -19
- package/src/cache/singleflight.ts +64 -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 +161 -36
- 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 +17 -0
- package/src/cdn/purge-store.ts +34 -0
- package/src/cdn/workers-cache-purge.ts +30 -0
- package/src/cli-schema-sync.ts +401 -0
- package/src/cli.ts +167 -34
- package/src/client/browser-dev.ts +156 -1
- package/src/client/browser-entry/action-dispatch.ts +124 -0
- package/src/client/browser-entry/hmr.ts +70 -0
- package/src/client/browser-entry/hydrate.ts +187 -0
- package/src/client/browser-entry/index.ts +113 -0
- package/src/client/browser-entry/post-hydration.ts +110 -0
- package/src/client/browser-entry/router-init.ts +286 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +50 -0
- package/src/client/error-boundary.tsx +127 -22
- package/src/client/error-reconstituter.tsx +79 -0
- package/src/client/form.tsx +31 -32
- package/src/client/history.ts +21 -6
- package/src/client/index.ts +67 -45
- package/src/client/internal.ts +58 -0
- package/src/client/link.tsx +349 -150
- package/src/client/navigation-api.ts +345 -0
- package/src/client/navigation-context.ts +15 -7
- package/src/client/navigation-root.tsx +355 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +589 -215
- package/src/client/rsc-fetch.ts +251 -34
- package/src/client/segment-cache.ts +105 -17
- package/src/client/segment-outlet.tsx +141 -0
- package/src/client/segment-update-context.ts +42 -0
- package/src/client/shallow-url.ts +22 -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 +13 -5
- package/src/client/state.ts +2 -2
- package/src/client/top-loader.tsx +11 -9
- package/src/client/use-cookie.ts +60 -15
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-pathname.ts +1 -0
- package/src/client/use-pending-navigation.ts +40 -0
- package/src/client/use-query-states.ts +108 -10
- package/src/client/use-router.ts +4 -1
- package/src/client/use-search-params.ts +31 -44
- package/src/client/{use-params.ts → use-segment-params.ts} +9 -6
- package/src/codec.ts +149 -0
- package/src/config-types.ts +282 -0
- package/src/config-validation.ts +330 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +217 -53
- package/src/cookies/index.ts +12 -1
- 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/dev-page-shell.ts +260 -0
- package/src/dev-tools/error-page.ts +331 -0
- package/src/dev-tools/holding-server.ts +187 -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 +477 -126
- package/src/fonts/bundle.ts +138 -0
- package/src/fonts/dev-middleware.ts +85 -0
- package/src/fonts/fallbacks.ts +0 -23
- package/src/fonts/google.ts +100 -18
- package/src/fonts/local.ts +9 -8
- 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 +446 -352
- 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 +432 -0
- package/src/plugins/adapter-build.ts +220 -7
- package/src/plugins/build-manifest.ts +177 -23
- package/src/plugins/build-report.ts +253 -35
- 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 +1 -1
- package/src/plugins/dev-server.ts +284 -94
- package/src/plugins/entries.ts +134 -16
- package/src/plugins/fonts.ts +225 -660
- package/src/plugins/mdx.ts +47 -10
- 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 +328 -0
- package/src/plugins/request-dep.ts +458 -0
- package/src/plugins/routing.ts +237 -241
- package/src/plugins/server-bundle.ts +89 -12
- package/src/plugins/shims.ts +241 -64
- package/src/plugins/static-build.ts +15 -90
- package/src/routing/codegen-shared.ts +115 -0
- package/src/routing/codegen-types.ts +65 -0
- package/src/routing/codegen.ts +372 -178
- package/src/routing/convention-lint.ts +394 -0
- package/src/routing/export-detect.ts +304 -0
- package/src/routing/file-cache.ts +23 -0
- package/src/routing/index.ts +10 -1
- package/src/routing/interception.ts +3 -22
- package/src/routing/link-codegen.ts +313 -0
- package/src/routing/manifest-codegen.ts +287 -0
- package/src/routing/scanner.ts +338 -189
- package/src/routing/schema-validation.ts +155 -0
- package/src/routing/segment-classify.ts +223 -0
- package/src/routing/segment-codegen.ts +98 -0
- package/src/routing/types.ts +82 -25
- package/src/routing/walkers.ts +90 -0
- package/src/rsc-runtime/rsc.ts +9 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/schema-bridge.ts +253 -0
- package/src/search-params/define.ts +576 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +101 -0
- package/src/segment-params/define.ts +249 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +111 -34
- package/src/server/action-client.ts +120 -29
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +123 -33
- package/src/server/actions.ts +48 -54
- package/src/server/als-registry.ts +137 -20
- package/src/server/asset-headers.ts +15 -37
- package/src/server/body-limits.ts +10 -2
- package/src/server/build-manifest.ts +19 -56
- package/src/server/canonicalize.ts +6 -3
- package/src/server/coalesce-tick.ts +75 -0
- package/src/server/compress.ts +34 -7
- package/src/server/cookie-context.ts +484 -0
- package/src/server/cookie-parsing.ts +163 -0
- package/src/server/csrf.ts +39 -6
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-boundary.ts +314 -0
- package/src/server/deny-renderer.ts +85 -77
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/early-hints.ts +37 -27
- package/src/server/error-boundary-wrapper.ts +61 -22
- package/src/server/fallback-error.ts +79 -102
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/form-data.ts +124 -12
- package/src/server/html-injector-core.ts +495 -0
- package/src/server/html-injectors.ts +271 -254
- package/src/server/index.ts +31 -185
- package/src/server/internal.ts +181 -0
- package/src/server/logger.ts +72 -36
- package/src/server/metadata-routes.ts +205 -24
- package/src/server/metadata.ts +21 -0
- package/src/server/middleware-runner.ts +31 -4
- package/src/server/node-stream-transforms.ts +336 -0
- package/src/server/param-coercion.ts +207 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +45 -18
- package/src/server/pipeline-metadata.ts +14 -0
- package/src/server/pipeline-outcome.ts +197 -0
- package/src/server/pipeline-phases.ts +545 -0
- package/src/server/pipeline.ts +274 -382
- package/src/server/port-resolution.ts +215 -0
- package/src/server/prebuilt/cache-key.ts +298 -0
- package/src/server/prebuilt/capture-state.ts +89 -0
- package/src/server/prebuilt/key-discipline.ts +53 -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 +201 -0
- package/src/server/prebuilt/slots.ts +190 -0
- package/src/server/prebuilt/synthetic-store.ts +121 -0
- package/src/server/prebuilt-builder.ts +809 -0
- package/src/server/prebuilt-runtime.ts +815 -0
- package/src/server/primitives.ts +160 -83
- package/src/server/render-timeout.ts +108 -0
- package/src/server/render-utils.ts +31 -0
- package/src/server/request-context.ts +170 -337
- package/src/server/request-dep.ts +37 -0
- package/src/server/route-element-builder.ts +699 -295
- package/src/server/route-handler.ts +31 -4
- package/src/server/route-matcher.ts +158 -277
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +69 -32
- package/src/server/rsc-entry/deny-fallback.ts +92 -0
- package/src/server/rsc-entry/error-renderer.ts +306 -89
- package/src/server/rsc-entry/helpers.ts +210 -85
- package/src/server/rsc-entry/index.ts +332 -332
- package/src/server/rsc-entry/render-route.ts +300 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +349 -0
- package/src/server/rsc-entry/rsc-payload.ts +102 -42
- package/src/server/rsc-entry/rsc-stream.ts +93 -13
- package/src/server/rsc-entry/ssr-bridge.ts +18 -5
- package/src/server/rsc-entry/ssr-renderer.ts +275 -43
- package/src/server/rsc-entry/wrap-action-dispatch.ts +186 -0
- 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/sitemap-generator.ts +345 -0
- package/src/server/sitemap-handler.ts +157 -0
- package/src/server/slot-resolver.ts +574 -250
- package/src/server/ssr-bridge-types.ts +124 -0
- package/src/server/ssr-entry.ts +206 -86
- package/src/server/ssr-render.ts +345 -86
- package/src/server/ssr-wrappers.tsx +141 -0
- package/src/server/state-tree-diff.ts +177 -30
- package/src/server/status-code-resolver.ts +115 -130
- package/src/server/stream-utils.ts +288 -0
- package/src/server/tracing.ts +126 -14
- package/src/server/tree-builder.ts +214 -90
- package/src/server/tree-match.ts +262 -0
- package/src/server/types.ts +78 -9
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/utils/mdx-file.ts +22 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/workers-cache-bridge.ts +33 -0
- package/src/shared/href-validation.ts +159 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shared/redirect-type.ts +17 -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 +51 -29
- package/src/shims/navigation.ts +14 -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 +0 -153
- 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.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/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.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/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/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/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/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/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/utils/directive-parser.ts +0 -529
|
@@ -16,33 +16,75 @@
|
|
|
16
16
|
* See design/02-rendering-pipeline.md §"Parallel Slots"
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { TimberErrorBoundary } from '
|
|
20
|
-
import SlotErrorFallback from '
|
|
19
|
+
import { TimberErrorBoundary } from '../client/error-boundary.js';
|
|
20
|
+
import SlotErrorFallback from '../client/slot-error-fallback.js';
|
|
21
21
|
import { SlotAccessGate } from './access-gate.js';
|
|
22
22
|
import { wrapSegmentWithErrorBoundaries } from './error-boundary-wrapper.js';
|
|
23
|
+
import { isClientReference } from './route-element-builder.js';
|
|
24
|
+
import { loadModule } from './safe-load.js';
|
|
23
25
|
import type { InterceptionContext, RouteMatch } from './pipeline.js';
|
|
24
|
-
import { DenySignal } from './primitives.js';
|
|
26
|
+
import { DenySignal, RedirectSignal } from './primitives.js';
|
|
27
|
+
import { logRenderError } from './logger.js';
|
|
25
28
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
29
|
+
import { setSlotParams } from './request-context.js';
|
|
30
|
+
import { coerceSlotParams } from './param-coercion.js';
|
|
31
|
+
import { matchUrlParts } from './tree-match.js';
|
|
32
|
+
import { SegmentOutlet } from '../client/segment-outlet.js';
|
|
33
|
+
import { computeSlotKey, shouldSkipSlot, type ClientStateTree } from './state-tree-diff.js';
|
|
34
|
+
import { isStaticRequestDependent } from './request-dep.js';
|
|
26
35
|
|
|
27
36
|
type CreateElementFn = (...args: unknown[]) => React.ReactElement;
|
|
28
37
|
|
|
38
|
+
// ─── Module Loading Helpers ─────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Load a module and extract its default export as a component function.
|
|
42
|
+
* Returns undefined if no default export exists.
|
|
43
|
+
*/
|
|
44
|
+
async function loadComponent(loader: {
|
|
45
|
+
load: () => Promise<unknown>;
|
|
46
|
+
filePath: string;
|
|
47
|
+
}): Promise<((...args: unknown[]) => unknown) | undefined> {
|
|
48
|
+
const mod = await loadModule(loader);
|
|
49
|
+
return mod.default as ((...args: unknown[]) => unknown) | undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load and render the default.tsx fallback for a slot node.
|
|
54
|
+
* Returns null if the slot has no default.tsx or it has no default export.
|
|
55
|
+
*/
|
|
56
|
+
async function renderDefaultFallback(
|
|
57
|
+
slotNode: ManifestSegmentNode,
|
|
58
|
+
h: CreateElementFn
|
|
59
|
+
): Promise<React.ReactElement | null> {
|
|
60
|
+
if (!slotNode.default) return null;
|
|
61
|
+
const DefaultComp = await loadComponent(slotNode.default);
|
|
62
|
+
if (!DefaultComp) return null;
|
|
63
|
+
return h(DefaultComp, {});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Slot Element Resolution ────────────────────────────────────────────────
|
|
67
|
+
|
|
29
68
|
/**
|
|
30
69
|
* Resolve the element for a parallel slot.
|
|
31
70
|
*
|
|
32
71
|
* Finds a matching page in the slot's sub-tree for the current route.
|
|
33
72
|
* Falls back to default.tsx if no match, or null if no default.
|
|
34
73
|
*
|
|
35
|
-
* When a match is found, the element is wrapped
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
74
|
+
* When a match is found, the element is wrapped per segment in the slot's
|
|
75
|
+
* matched chain with (innermost → outermost):
|
|
76
|
+
* 1. Error boundaries
|
|
77
|
+
* 2. Layout
|
|
78
|
+
* 3. SlotAccessGate if the segment has access.ts (gate OUTSIDE the layout,
|
|
79
|
+
* so a denied layout never executes — see TIM-1074)
|
|
39
80
|
*/
|
|
40
81
|
export async function resolveSlotElement(
|
|
41
82
|
slotNode: ManifestSegmentNode,
|
|
42
83
|
match: RouteMatch,
|
|
43
|
-
paramsPromise: Promise<Record<string, string | string[]>>,
|
|
44
84
|
h: CreateElementFn,
|
|
45
|
-
interception?: InterceptionContext
|
|
85
|
+
interception?: InterceptionContext,
|
|
86
|
+
parentTreePath?: string,
|
|
87
|
+
accessVerdicts?: SlotAccessVerdict[]
|
|
46
88
|
): Promise<React.ReactElement | null> {
|
|
47
89
|
// When interception is active, try to match intercepting children in this
|
|
48
90
|
// slot against the target pathname. If an intercepting child matches, render
|
|
@@ -54,125 +96,89 @@ export async function resolveSlotElement(
|
|
|
54
96
|
: findSlotMatch(slotNode, match);
|
|
55
97
|
|
|
56
98
|
if (slotMatch) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
99
|
+
// Store per-slot params in ALS so getSegmentParams(segmentPath) returns
|
|
100
|
+
// the slot's own param types (e.g. catch-all → string[] vs dynamic → string).
|
|
101
|
+
if (parentTreePath && Object.keys(slotMatch.slotParams).length > 0) {
|
|
102
|
+
// Build the full tree path: parent prefix + slot chain segment names.
|
|
103
|
+
const slotSuffix = slotMatch.chain
|
|
104
|
+
.map((s) => s.segmentName)
|
|
105
|
+
.filter(Boolean)
|
|
106
|
+
.join('/');
|
|
107
|
+
const prefix = parentTreePath === '/' ? '' : parentTreePath;
|
|
108
|
+
const fullSlotPath = `${prefix}/${slotSuffix}`;
|
|
109
|
+
|
|
110
|
+
// Coerce slot params through global schema codecs (same as main route).
|
|
111
|
+
const coerced = coerceSlotParams(slotMatch.chain, slotMatch.slotParams);
|
|
112
|
+
setSlotParams(fullSlotPath, coerced);
|
|
113
|
+
}
|
|
60
114
|
|
|
115
|
+
const SlotPage = await loadComponent(slotMatch.page);
|
|
116
|
+
if (SlotPage) {
|
|
61
117
|
// Load default.tsx fallback for notFound() handling in the slot page.
|
|
62
118
|
// When a slot page calls notFound() or deny(), it should gracefully
|
|
63
119
|
// degrade to default.tsx or null — not crash the page. This matches
|
|
64
120
|
// Next.js behavior. See design/02-rendering-pipeline.md
|
|
65
121
|
// §"Slot Access Failure = Graceful Degradation"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
let element: React.ReactElement = h(SafeSlotPage, {
|
|
93
|
-
params: paramsPromise,
|
|
94
|
-
searchParams: {},
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Wrap with error boundaries and layouts from intermediate slot segments
|
|
98
|
-
// (everything between slot root and leaf). Process innermost-first, same
|
|
99
|
-
// order as route-element-builder.ts handles main segments. The slot root
|
|
100
|
-
// (index 0) is handled separately after the access gate below.
|
|
101
|
-
for (let i = slotMatch.chain.length - 1; i > 0; i--) {
|
|
102
|
-
const seg = slotMatch.chain[i];
|
|
103
|
-
|
|
104
|
-
// Error boundaries from this segment
|
|
105
|
-
element = await wrapSegmentWithErrorBoundaries(seg, element, h);
|
|
106
|
-
|
|
107
|
-
// Layout from this segment
|
|
108
|
-
if (seg.layout) {
|
|
109
|
-
const layoutMod = (await seg.layout.load()) as Record<string, unknown>;
|
|
110
|
-
if (layoutMod.default) {
|
|
111
|
-
const Layout = layoutMod.default as (...args: unknown[]) => unknown;
|
|
112
|
-
element = h(Layout, {
|
|
113
|
-
params: paramsPromise,
|
|
114
|
-
searchParams: {},
|
|
115
|
-
children: element,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Wrap in SlotAccessGate if slot root has access.ts.
|
|
122
|
-
// On denial: denied.tsx → default.tsx → null (graceful degradation).
|
|
123
|
-
// See design/04-authorization.md §"Slot-Level Auth".
|
|
124
|
-
if (slotNode.access) {
|
|
125
|
-
const accessMod = (await slotNode.access.load()) as Record<string, unknown>;
|
|
126
|
-
const accessFn = accessMod.default as
|
|
127
|
-
| ((ctx: { params: Record<string, string | string[]>; searchParams: unknown }) => unknown)
|
|
128
|
-
| undefined;
|
|
129
|
-
if (accessFn) {
|
|
130
|
-
// Load denied.tsx fallback
|
|
131
|
-
let deniedFallback: React.ReactElement | null = null;
|
|
132
|
-
if (slotNode.denied) {
|
|
133
|
-
const deniedMod = (await slotNode.denied.load()) as Record<string, unknown>;
|
|
134
|
-
const DeniedComponent = deniedMod.default as
|
|
135
|
-
| ((...args: unknown[]) => unknown)
|
|
136
|
-
| undefined;
|
|
137
|
-
if (DeniedComponent) {
|
|
138
|
-
deniedFallback = h(DeniedComponent, {});
|
|
122
|
+
const denyFallback = await renderDefaultFallback(slotNode, h);
|
|
123
|
+
|
|
124
|
+
// Build the slot page element.
|
|
125
|
+
// Client references ('use client' pages) must NOT be called as functions —
|
|
126
|
+
// they are proxy objects that throw when invoked. For client references,
|
|
127
|
+
// use createElement directly. Error catching is unnecessary because client
|
|
128
|
+
// references are serialized as references in the RSC Flight stream — they
|
|
129
|
+
// don't execute on the server. See TIM-627.
|
|
130
|
+
//
|
|
131
|
+
// For server components, wrap in SafeSlotPage to catch ALL errors at the
|
|
132
|
+
// component level. This prevents errors from leaving unresolved Flight
|
|
133
|
+
// rows in the RSC stream — see TIM-524 for details.
|
|
134
|
+
let element: React.ReactElement;
|
|
135
|
+
if (isClientReference(SlotPage)) {
|
|
136
|
+
element = h(SlotPage, {});
|
|
137
|
+
} else {
|
|
138
|
+
const SafeSlotPage = async (props: Record<string, unknown>) => {
|
|
139
|
+
try {
|
|
140
|
+
return await (SlotPage as (props: Record<string, unknown>) => unknown)(props);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// RedirectSignal must propagate — the pipeline handles redirects
|
|
143
|
+
// at the top level. Swallowing it here would silently return
|
|
144
|
+
// fallback content instead of redirecting. See TIM-554.
|
|
145
|
+
if (error instanceof RedirectSignal) {
|
|
146
|
+
throw error;
|
|
139
147
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// Load default.tsx fallback
|
|
143
|
-
let defaultFallback: React.ReactElement | null = null;
|
|
144
|
-
if (slotNode.default) {
|
|
145
|
-
const defaultMod = (await slotNode.default.load()) as Record<string, unknown>;
|
|
146
|
-
const DefaultComp = defaultMod.default as ((...args: unknown[]) => unknown) | undefined;
|
|
147
|
-
if (DefaultComp) {
|
|
148
|
-
defaultFallback = h(DefaultComp, { params: paramsPromise, searchParams: {} });
|
|
148
|
+
if (error instanceof DenySignal) {
|
|
149
|
+
return denyFallback;
|
|
149
150
|
}
|
|
151
|
+
// Log the error but don't re-throw — returning fallback ensures
|
|
152
|
+
// the Flight row is resolved and the page hydrates correctly.
|
|
153
|
+
logRenderError({
|
|
154
|
+
method: '',
|
|
155
|
+
path: '',
|
|
156
|
+
error,
|
|
157
|
+
});
|
|
158
|
+
return denyFallback;
|
|
150
159
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
element = h(SlotAccessGate, {
|
|
154
|
-
accessFn,
|
|
155
|
-
params,
|
|
156
|
-
searchParams: {},
|
|
157
|
-
deniedFallback,
|
|
158
|
-
defaultFallback,
|
|
159
|
-
children: element,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
160
|
+
};
|
|
161
|
+
element = h(SafeSlotPage, {});
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// Wrap with
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
164
|
+
// Wrap with error boundaries, layouts, and access gates from
|
|
165
|
+
// intermediate slot segments (everything between slot root and leaf).
|
|
166
|
+
// Process innermost-first, same order as route-element-builder.ts
|
|
167
|
+
// handles main segments. The slot root (index 0) is handled below.
|
|
168
|
+
element = await wrapWithIntermediateSegments(slotMatch.chain, element, h, accessVerdicts);
|
|
169
|
+
|
|
170
|
+
// Wrap with slot root's layout — INSIDE the access gate, so the layout
|
|
171
|
+
// server component never executes when access.ts denies. See TIM-1074.
|
|
172
|
+
element = await wrapWithLayout(slotNode, element, h);
|
|
173
|
+
|
|
174
|
+
// Wrap in SlotAccessGate if slot root has access.ts. The gate is
|
|
175
|
+
// OUTSIDE the layout, matching the segment model in
|
|
176
|
+
// route-element-builder.ts: a denied layout must not render, or it
|
|
177
|
+
// would fetch/serialize protected data into the RSC Flight stream.
|
|
178
|
+
// On denial: denied.tsx → default.tsx → null (graceful degradation),
|
|
179
|
+
// rendered WITHOUT the denied slot's own layout.
|
|
180
|
+
// See design/04-authorization.md §"Slot-Level Auth".
|
|
181
|
+
element = await wrapWithAccessGate(slotNode, element, h, accessVerdicts);
|
|
176
182
|
|
|
177
183
|
// Wrap with slot root's error boundaries (outermost)
|
|
178
184
|
element = await wrapSegmentWithErrorBoundaries(slotNode, element, h);
|
|
@@ -180,7 +186,7 @@ export async function resolveSlotElement(
|
|
|
180
186
|
// Catch-all error boundary: ensures slot errors NEVER propagate to the
|
|
181
187
|
// parent layout. Without this, a slot without error.tsx that throws
|
|
182
188
|
// causes SSR's renderToReadableStream to reject, triggering renderDenyPage
|
|
183
|
-
// which re-executes all layout server components (including
|
|
189
|
+
// which re-executes all layout server components (including getHeaders() calls
|
|
184
190
|
// that fail in the SSR environment). The null fallback means the slot
|
|
185
191
|
// degrades to nothing — consistent with the slot access denial behavior.
|
|
186
192
|
// See design/02-rendering-pipeline.md §"Slot Access Failure = Graceful Degradation"
|
|
@@ -194,25 +200,115 @@ export async function resolveSlotElement(
|
|
|
194
200
|
}
|
|
195
201
|
}
|
|
196
202
|
|
|
197
|
-
// No matching page — render default.tsx fallback
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
203
|
+
// No matching page — render default.tsx fallback.
|
|
204
|
+
// Per design/02-rendering-pipeline.md: "No access check for default.tsx."
|
|
205
|
+
// Access verdicts from the eager evaluation are not applied here.
|
|
206
|
+
// Pass taintKey so accessor calls inside default.tsx are scoped to this
|
|
207
|
+
return renderDefaultFallback(slotNode, h);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ─── Element Wrapping Helpers ───────────────────────────────────────────────
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Wrap an element with error boundaries, access gates, and layouts from
|
|
214
|
+
* intermediate slot segments (indices 1..n, skipping the slot root at index 0).
|
|
215
|
+
* Processes innermost-first to match route-element-builder.ts ordering.
|
|
216
|
+
*
|
|
217
|
+
* Access gates are enforced for every intermediate segment that has access.ts,
|
|
218
|
+
* not just the slot root. Without this, nested slot children (e.g.,
|
|
219
|
+
* @admin/reports/access.ts) and intercepting route children with access.ts
|
|
220
|
+
* would bypass authorization. See TIM-999.
|
|
221
|
+
*
|
|
222
|
+
* Wrap order per segment (innermost → outermost): error boundaries → layout
|
|
223
|
+
* → access gate. The gate must be OUTSIDE the layout so a denying access.ts
|
|
224
|
+
* prevents the layout server component from executing — otherwise the layout
|
|
225
|
+
* would fetch/serialize protected data into the RSC Flight stream. Matches
|
|
226
|
+
* route-element-builder.ts. See TIM-1074.
|
|
227
|
+
*/
|
|
228
|
+
async function wrapWithIntermediateSegments(
|
|
229
|
+
chain: ManifestSegmentNode[],
|
|
230
|
+
element: React.ReactElement,
|
|
231
|
+
h: CreateElementFn,
|
|
232
|
+
accessVerdicts?: SlotAccessVerdict[]
|
|
233
|
+
): Promise<React.ReactElement> {
|
|
234
|
+
for (let i = chain.length - 1; i > 0; i--) {
|
|
235
|
+
const seg = chain[i];
|
|
236
|
+
element = await wrapSegmentWithErrorBoundaries(seg, element, h);
|
|
237
|
+
element = await wrapWithLayout(seg, element, h);
|
|
238
|
+
element = await wrapWithAccessGate(seg, element, h, accessVerdicts);
|
|
204
239
|
}
|
|
240
|
+
return element;
|
|
241
|
+
}
|
|
205
242
|
|
|
206
|
-
|
|
207
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Wrap an element with a segment's layout component, if present.
|
|
245
|
+
*/
|
|
246
|
+
async function wrapWithLayout(
|
|
247
|
+
node: ManifestSegmentNode,
|
|
248
|
+
element: React.ReactElement,
|
|
249
|
+
h: CreateElementFn
|
|
250
|
+
): Promise<React.ReactElement> {
|
|
251
|
+
if (!node.layout) return element;
|
|
252
|
+
const Layout = await loadComponent(node.layout);
|
|
253
|
+
if (!Layout) return element;
|
|
254
|
+
return h(Layout, { children: element });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Wrap an element with a SlotAccessGate if the node has access.ts.
|
|
259
|
+
* On denial: denied.tsx → default.tsx → null (graceful degradation).
|
|
260
|
+
*/
|
|
261
|
+
async function wrapWithAccessGate(
|
|
262
|
+
slotNode: ManifestSegmentNode,
|
|
263
|
+
element: React.ReactElement,
|
|
264
|
+
h: CreateElementFn,
|
|
265
|
+
accessVerdicts?: SlotAccessVerdict[]
|
|
266
|
+
): Promise<React.ReactElement> {
|
|
267
|
+
if (!slotNode.access) return element;
|
|
268
|
+
|
|
269
|
+
const accessFn = await loadComponent(slotNode.access);
|
|
270
|
+
if (!accessFn) return element;
|
|
271
|
+
|
|
272
|
+
let DeniedComponent: ((...args: unknown[]) => unknown) | null = null;
|
|
273
|
+
if (slotNode.denied) {
|
|
274
|
+
DeniedComponent = (await loadComponent(slotNode.denied)) ?? null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const slotName = slotNode.segmentName?.replace(/^@/, '') ?? '';
|
|
278
|
+
|
|
279
|
+
const defaultFallback = await renderDefaultFallback(slotNode, h);
|
|
280
|
+
|
|
281
|
+
// Look up pre-computed verdict from eager evaluation. Only replay
|
|
282
|
+
// denial/redirect verdicts — 'pass' verdicts must NOT be replayed
|
|
283
|
+
// because the access function may warm React.cache (e.g., requireUser())
|
|
284
|
+
// for layout/page dedup, and replaying 'pass' skips the cache-warming
|
|
285
|
+
// call. 'error' verdicts are also excluded — the gate must re-run
|
|
286
|
+
// accessFn so the error reaches the slot's error boundary.
|
|
287
|
+
const preVerdict = accessVerdicts?.find(
|
|
288
|
+
(v) => v.node === slotNode && v.verdict !== 'pass' && v.verdict !== 'error'
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
return h(SlotAccessGate, {
|
|
292
|
+
accessFn,
|
|
293
|
+
DeniedComponent,
|
|
294
|
+
slotName,
|
|
295
|
+
createElement: h,
|
|
296
|
+
defaultFallback,
|
|
297
|
+
children: element,
|
|
298
|
+
verdict: preVerdict?.verdict,
|
|
299
|
+
});
|
|
208
300
|
}
|
|
209
301
|
|
|
302
|
+
// ─── Slot Matching ──────────────────────────────────────────────────────────
|
|
303
|
+
|
|
210
304
|
/** Result of matching a slot's sub-tree against the current route. */
|
|
211
305
|
interface SlotMatchResult {
|
|
212
306
|
/** The page file at the matched leaf. */
|
|
213
307
|
page: NonNullable<ManifestSegmentNode['page']>;
|
|
214
308
|
/** The full chain of slot nodes traversed (slot root → … → leaf with page). */
|
|
215
309
|
chain: ManifestSegmentNode[];
|
|
310
|
+
/** Params collected from the slot's segment chain (may differ from main route params). */
|
|
311
|
+
slotParams: Record<string, string | string[]>;
|
|
216
312
|
}
|
|
217
313
|
|
|
218
314
|
/**
|
|
@@ -231,7 +327,7 @@ interface SlotMatchResult {
|
|
|
231
327
|
* to find the deepest matching page.
|
|
232
328
|
*/
|
|
233
329
|
function findSlotMatch(slotNode: ManifestSegmentNode, match: RouteMatch): SlotMatchResult | null {
|
|
234
|
-
const segments = match.segments
|
|
330
|
+
const segments = match.segments;
|
|
235
331
|
|
|
236
332
|
// Find the parent segment that owns this slot by comparing urlPaths.
|
|
237
333
|
// The slot's urlPath matches its parent's urlPath (slots don't add URL depth).
|
|
@@ -253,90 +349,60 @@ function findSlotMatch(slotNode: ManifestSegmentNode, match: RouteMatch): SlotMa
|
|
|
253
349
|
// against the slot's children.
|
|
254
350
|
const remainingSegments = parentIndex >= 0 ? segments.slice(parentIndex + 1) : [];
|
|
255
351
|
|
|
256
|
-
//
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// Check for optional-catch-all child — [[...slug]] matches zero segments
|
|
262
|
-
for (const child of slotNode.children ?? []) {
|
|
263
|
-
if (child.segmentType === 'optional-catch-all' && child.page) {
|
|
264
|
-
return { page: child.page, chain: [slotNode, child] };
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
352
|
+
// Extract raw URL parts from the remaining main-route segments.
|
|
353
|
+
// Use rawSegmentParams (pre-coercion) to ensure we get actual URL strings,
|
|
354
|
+
// not codec-transformed values. Fall back to segmentParams for tests/compat.
|
|
355
|
+
const rawParams = match.rawSegmentParams ?? match.segmentParams ?? {};
|
|
356
|
+
const urlParts = extractUrlParts(remainingSegments, rawParams);
|
|
269
357
|
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const childName = seg.segmentName;
|
|
276
|
-
const directChildren = currentNode.children ?? [];
|
|
277
|
-
|
|
278
|
-
let found: ManifestSegmentNode | null = null;
|
|
279
|
-
for (const child of directChildren) {
|
|
280
|
-
// Exact static match
|
|
281
|
-
if (child.segmentType === 'static' && child.segmentName === childName) {
|
|
282
|
-
found = child;
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
358
|
+
// Match URL parts against the slot's segment tree using the shared walker.
|
|
359
|
+
// Handles zero parts (slot's own page), catch-all, optional-catch-all,
|
|
360
|
+
// groups, backtracking, and correct priority ordering.
|
|
361
|
+
const result = matchUrlParts(slotNode, urlParts);
|
|
362
|
+
if (!result) return null;
|
|
286
363
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
for (const child of directChildren) {
|
|
290
|
-
if (child.segmentType === 'dynamic') {
|
|
291
|
-
found = child;
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
364
|
+
const leaf = result.chain[result.chain.length - 1];
|
|
365
|
+
if (!leaf.page) return null;
|
|
296
366
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (!found) {
|
|
300
|
-
for (const child of directChildren) {
|
|
301
|
-
if (child.segmentType === 'catch-all' || child.segmentType === 'optional-catch-all') {
|
|
302
|
-
found = child;
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (found) {
|
|
307
|
-
chain.push(found);
|
|
308
|
-
currentNode = found;
|
|
309
|
-
break;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
367
|
+
return { page: leaf.page, chain: result.chain, slotParams: result.params };
|
|
368
|
+
}
|
|
312
369
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
370
|
+
/**
|
|
371
|
+
* Extract raw URL path parts from a main-route segment chain.
|
|
372
|
+
*
|
|
373
|
+
* Each dynamic segment consumed one URL part (its param value).
|
|
374
|
+
* Static segments consumed their own name. Groups are transparent.
|
|
375
|
+
* Catch-all segments consumed multiple parts (their param value is string[]).
|
|
376
|
+
*
|
|
377
|
+
* Uses rawSegmentParams (pre-coercion) to get actual URL strings.
|
|
378
|
+
* Values are coerced to String() defensively in case a codec leaked
|
|
379
|
+
* a non-string value into the params map.
|
|
380
|
+
*/
|
|
381
|
+
export function extractUrlParts(
|
|
382
|
+
segments: ManifestSegmentNode[],
|
|
383
|
+
mainParams: Record<string, string | string[]>
|
|
384
|
+
): string[] {
|
|
385
|
+
const parts: string[] = [];
|
|
386
|
+
for (const seg of segments) {
|
|
387
|
+
if (seg.segmentType === 'group') continue;
|
|
388
|
+
if (seg.segmentType === 'static') {
|
|
389
|
+
parts.push(seg.segmentName);
|
|
390
|
+
} else if (seg.paramName) {
|
|
391
|
+
const value = mainParams[seg.paramName];
|
|
392
|
+
if (Array.isArray(value)) {
|
|
393
|
+
parts.push(...value.map(String));
|
|
394
|
+
} else if (value !== undefined) {
|
|
395
|
+
// Reconstruct the original URL part for affixed segments.
|
|
396
|
+
// The param value is the stripped middle (e.g. "123" for [id].png
|
|
397
|
+
// matching "123.png"), so we re-attach prefix/suffix so that slot
|
|
398
|
+
// matching through matchUrlParts sees the original part.
|
|
399
|
+
const prefix = seg.paramPrefix ?? '';
|
|
400
|
+
const suffix = seg.paramSuffix ?? '';
|
|
401
|
+
parts.push(prefix + String(value) + suffix);
|
|
325
402
|
}
|
|
326
403
|
}
|
|
327
|
-
|
|
328
|
-
if (!found) {
|
|
329
|
-
// No matching child in slot tree — slot doesn't match this URL
|
|
330
|
-
return null;
|
|
331
|
-
}
|
|
332
|
-
chain.push(found);
|
|
333
|
-
currentNode = found;
|
|
334
404
|
}
|
|
335
|
-
|
|
336
|
-
if (currentNode.page) {
|
|
337
|
-
return { page: currentNode.page, chain };
|
|
338
|
-
}
|
|
339
|
-
return null;
|
|
405
|
+
return parts;
|
|
340
406
|
}
|
|
341
407
|
|
|
342
408
|
/**
|
|
@@ -372,63 +438,321 @@ function findInterceptingMatch(
|
|
|
372
438
|
}
|
|
373
439
|
if (matchIdx < 0) continue;
|
|
374
440
|
|
|
375
|
-
//
|
|
441
|
+
// Match remaining target parts against the intercepting child's sub-tree.
|
|
376
442
|
const remaining = targetParts.slice(matchIdx + 1);
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (
|
|
381
|
-
return {
|
|
443
|
+
const result = matchUrlParts(child, remaining);
|
|
444
|
+
if (result) {
|
|
445
|
+
const leaf = result.chain[result.chain.length - 1];
|
|
446
|
+
if (leaf.page) {
|
|
447
|
+
return {
|
|
448
|
+
page: leaf.page,
|
|
449
|
+
// Prepend slotNode — matchUrlParts starts from child, not slot root
|
|
450
|
+
chain: [slotNode, ...result.chain],
|
|
451
|
+
slotParams: result.params,
|
|
452
|
+
};
|
|
382
453
|
}
|
|
383
|
-
continue;
|
|
384
454
|
}
|
|
455
|
+
}
|
|
385
456
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
for (const part of remaining) {
|
|
389
|
-
const children = currentNode.children ?? [];
|
|
390
|
-
let found: ManifestSegmentNode | null = null;
|
|
391
|
-
|
|
392
|
-
// Static match
|
|
393
|
-
for (const c of children) {
|
|
394
|
-
if (c.segmentType === 'static' && c.segmentName === part) {
|
|
395
|
-
found = c;
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
399
459
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
460
|
+
// ─── Slot Access Evaluation ─────────────────────────────────────────────────
|
|
461
|
+
|
|
462
|
+
/** Result of eagerly evaluating one segment's access.ts. */
|
|
463
|
+
export interface SlotAccessVerdict {
|
|
464
|
+
node: ManifestSegmentNode;
|
|
465
|
+
/**
|
|
466
|
+
* 'pass' — access allowed.
|
|
467
|
+
* DenySignal/RedirectSignal — access denied, replayed in SlotAccessGate.
|
|
468
|
+
* 'error' — unknown error. Forces full render. No verdict passed to
|
|
469
|
+
* SlotAccessGate, so it calls accessFn during render and the error
|
|
470
|
+
* reaches the slot's error boundary.
|
|
471
|
+
*/
|
|
472
|
+
verdict: 'pass' | 'error' | DenySignal | RedirectSignal;
|
|
473
|
+
}
|
|
409
474
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
475
|
+
/**
|
|
476
|
+
* Eagerly evaluate the access chain for a slot (root + intermediate segments).
|
|
477
|
+
*
|
|
478
|
+
* Runs each access.ts top-down (outermost first). If any denies, the chain
|
|
479
|
+
* stops (shallowest failure wins, matching segment access semantics).
|
|
480
|
+
*
|
|
481
|
+
* Verdicts are stored for replay in SlotAccessGate / wrapWithIntermediateSegments
|
|
482
|
+
* so access.ts is called exactly once per request.
|
|
483
|
+
*/
|
|
484
|
+
async function evaluateSlotAccessChain(
|
|
485
|
+
slotRoot: ManifestSegmentNode,
|
|
486
|
+
chain: ManifestSegmentNode[]
|
|
487
|
+
): Promise<SlotAccessVerdict[]> {
|
|
488
|
+
// Collect all nodes with access.ts: slot root + intermediate chain segments
|
|
489
|
+
const nodesWithAccess: ManifestSegmentNode[] = [];
|
|
490
|
+
if (slotRoot.access) nodesWithAccess.push(slotRoot);
|
|
491
|
+
for (let i = 1; i < chain.length; i++) {
|
|
492
|
+
if (chain[i].access) nodesWithAccess.push(chain[i]);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (nodesWithAccess.length === 0) return [];
|
|
419
496
|
|
|
420
|
-
|
|
421
|
-
|
|
497
|
+
const results: SlotAccessVerdict[] = [];
|
|
498
|
+
for (const node of nodesWithAccess) {
|
|
499
|
+
const accessFn = await loadComponent(node.access!);
|
|
500
|
+
if (!accessFn) {
|
|
501
|
+
results.push({ node, verdict: 'pass' });
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
await accessFn();
|
|
506
|
+
results.push({ node, verdict: 'pass' });
|
|
507
|
+
} catch (e) {
|
|
508
|
+
if (e instanceof DenySignal) {
|
|
509
|
+
results.push({ node, verdict: e });
|
|
510
|
+
break; // shallowest failure wins
|
|
511
|
+
}
|
|
512
|
+
if (e instanceof RedirectSignal) {
|
|
513
|
+
results.push({ node, verdict: e });
|
|
422
514
|
break;
|
|
423
515
|
}
|
|
424
|
-
|
|
425
|
-
|
|
516
|
+
// Unknown error — record as 'error' to force full render (blocks
|
|
517
|
+
// canSkip via accessBlocked). No verdict is passed to SlotAccessGate
|
|
518
|
+
// (wrapWithAccessGate filters 'error' out), so the gate calls
|
|
519
|
+
// accessFn during render and the error reaches the error boundary.
|
|
520
|
+
results.push({ node, verdict: 'error' });
|
|
521
|
+
break;
|
|
426
522
|
}
|
|
523
|
+
}
|
|
524
|
+
return results;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// ─── Slot Caching ──────────────────────────────────────────────────────────
|
|
528
|
+
|
|
529
|
+
export interface SlotSkipEntry {
|
|
530
|
+
slotKey: string;
|
|
531
|
+
parentSegmentId: string;
|
|
532
|
+
/**
|
|
533
|
+
* Whether the slot's components called request accessors (getHeaders,
|
|
534
|
+
* getSearchParams, cookies) during their last render. Replaces the
|
|
535
|
+
* unreliable AsyncFunction heuristic — taint-tracked via ALS.
|
|
536
|
+
*/
|
|
537
|
+
isRequestDependent: boolean;
|
|
538
|
+
/** Whether the slot's access.ts denied on this render. */
|
|
539
|
+
denied: boolean;
|
|
540
|
+
/** Whether the slot was skipped (content not rendered, client keeps cached). */
|
|
541
|
+
skipped?: boolean;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
interface ResolveSlotPropsArgs {
|
|
545
|
+
segment: ManifestSegmentNode;
|
|
546
|
+
segmentId: string;
|
|
547
|
+
match: RouteMatch;
|
|
548
|
+
h: CreateElementFn;
|
|
549
|
+
interception?: InterceptionContext;
|
|
550
|
+
parentTreePath: string;
|
|
551
|
+
departingUrl: string | null;
|
|
552
|
+
destinationUrl: string;
|
|
553
|
+
clientStateTree: ClientStateTree | null;
|
|
554
|
+
slotSkipInfo: SlotSkipEntry[];
|
|
555
|
+
}
|
|
427
556
|
|
|
428
|
-
|
|
429
|
-
|
|
557
|
+
/**
|
|
558
|
+
* Resolve all parallel route slots for a layout, wrapping each in a
|
|
559
|
+
* SegmentOutlet for client-side caching. Slots whose matched content
|
|
560
|
+
* hasn't changed between the departing and destination URLs are rendered
|
|
561
|
+
* with `skip=true` so the client keeps its cached content.
|
|
562
|
+
*/
|
|
563
|
+
export async function resolveSlotProps({
|
|
564
|
+
segment,
|
|
565
|
+
segmentId,
|
|
566
|
+
match,
|
|
567
|
+
h,
|
|
568
|
+
interception,
|
|
569
|
+
parentTreePath,
|
|
570
|
+
departingUrl,
|
|
571
|
+
destinationUrl,
|
|
572
|
+
clientStateTree,
|
|
573
|
+
slotSkipInfo,
|
|
574
|
+
}: ResolveSlotPropsArgs): Promise<Record<string, unknown>> {
|
|
575
|
+
const slotProps: Record<string, unknown> = {};
|
|
576
|
+
const slotEntries = Object.entries(segment.slots ?? {});
|
|
577
|
+
if (slotEntries.length === 0) return slotProps;
|
|
578
|
+
|
|
579
|
+
// Parse URLs to extract pathnames for slot skip comparison.
|
|
580
|
+
// The departing URL (X-Timber-URL) is an untrusted request header —
|
|
581
|
+
// catch parse failures and fall back to no-cache (full render).
|
|
582
|
+
const destParsed = new URL(destinationUrl, 'http://localhost');
|
|
583
|
+
let depParsed: URL | null = null;
|
|
584
|
+
if (departingUrl) {
|
|
585
|
+
try {
|
|
586
|
+
depParsed = new URL(departingUrl, 'http://localhost');
|
|
587
|
+
} catch {
|
|
588
|
+
// Malformed departing URL — disable slot skipping for this request
|
|
430
589
|
}
|
|
431
590
|
}
|
|
591
|
+
const destinationPathname = destParsed.pathname;
|
|
592
|
+
const departingPathname = depParsed?.pathname ?? null;
|
|
593
|
+
|
|
594
|
+
// Compute URL parts for slot skip comparison.
|
|
595
|
+
// Include the owning segment (segIdx + 1) to match findSlotMatch,
|
|
596
|
+
// which slices at parentIndex + 1. Filter out the root segment
|
|
597
|
+
// (segmentName === '') — it maps to '/' and doesn't consume a URL part.
|
|
598
|
+
const segIdx = match.segments.indexOf(segment);
|
|
599
|
+
const parentSegments =
|
|
600
|
+
segIdx >= 0 ? match.segments.slice(0, segIdx + 1).filter((s) => s.segmentName !== '') : [];
|
|
601
|
+
const rawParams = match.rawSegmentParams ?? match.segmentParams ?? {};
|
|
602
|
+
const parentConsumedParts = extractUrlParts(parentSegments, rawParams);
|
|
603
|
+
const sliceAt = parentConsumedParts.length;
|
|
604
|
+
|
|
605
|
+
function splitPathname(pathname: string): string[] {
|
|
606
|
+
return pathname === '/' ? [] : pathname.slice(1).split('/');
|
|
607
|
+
}
|
|
432
608
|
|
|
433
|
-
|
|
609
|
+
const destinationAll = splitPathname(destinationPathname);
|
|
610
|
+
const departingAll = departingPathname ? splitPathname(departingPathname) : null;
|
|
611
|
+
const destinationParts = destinationAll.slice(sliceAt);
|
|
612
|
+
const departingParts = departingAll ? departingAll.slice(sliceAt) : null;
|
|
613
|
+
const clientSlots = clientStateTree?.slots ?? null;
|
|
614
|
+
|
|
615
|
+
// Check if parent segment's URL parts changed (e.g., /users/1 → /users/2).
|
|
616
|
+
let parentParamsChanged = false;
|
|
617
|
+
if (departingAll) {
|
|
618
|
+
const depParent = departingAll.slice(0, sliceAt);
|
|
619
|
+
const destParent = destinationAll.slice(0, sliceAt);
|
|
620
|
+
parentParamsChanged =
|
|
621
|
+
depParent.length !== destParent.length || depParent.some((p, i) => p !== destParent[i]);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
for (const [slotName, slotNode] of slotEntries) {
|
|
625
|
+
const slotManifest = slotNode as ManifestSegmentNode;
|
|
626
|
+
const slotKey = computeSlotKey(segmentId, `@${slotName}`);
|
|
627
|
+
|
|
628
|
+
// Match the slot's sub-tree against the destination URL parts.
|
|
629
|
+
// Used for both the skip decision and eager access evaluation.
|
|
630
|
+
const destMatch = matchUrlParts(slotManifest, destinationParts);
|
|
631
|
+
|
|
632
|
+
// Seed slot params BEFORE eager access evaluation so that access.ts
|
|
633
|
+
// files calling getSegmentParams() see the slot's own coerced params,
|
|
634
|
+
// not the main route's. This is the same seeding that resolveSlotElement
|
|
635
|
+
// does, but we need it here for the eager path.
|
|
636
|
+
if (destMatch && parentTreePath && Object.keys(destMatch.params).length > 0) {
|
|
637
|
+
const slotSuffix = destMatch.chain
|
|
638
|
+
.map((s) => s.segmentName)
|
|
639
|
+
.filter(Boolean)
|
|
640
|
+
.join('/');
|
|
641
|
+
const prefix = parentTreePath === '/' ? '' : parentTreePath;
|
|
642
|
+
const fullSlotPath = `${prefix}/${slotSuffix}`;
|
|
643
|
+
const coerced = coerceSlotParams(destMatch.chain, destMatch.params);
|
|
644
|
+
setSlotParams(fullSlotPath, coerced);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Check non-access skip conditions first. If any of these fail,
|
|
648
|
+
// the slot can't be skipped regardless of access — no need to run
|
|
649
|
+
// the eager access evaluation (which would double-run access.ts
|
|
650
|
+
// since the in-tree gate also calls it during render).
|
|
651
|
+
const hasInterceptingChildren = slotManifest.children.some(
|
|
652
|
+
(c) => c.segmentType === 'intercepting'
|
|
653
|
+
);
|
|
654
|
+
const isSkipCandidate =
|
|
655
|
+
!interception &&
|
|
656
|
+
!hasInterceptingChildren &&
|
|
657
|
+
!parentParamsChanged &&
|
|
658
|
+
departingParts !== null &&
|
|
659
|
+
shouldSkipSlot({
|
|
660
|
+
slotKey,
|
|
661
|
+
clientSlots,
|
|
662
|
+
slotNode: slotManifest,
|
|
663
|
+
departingUrlParts: departingParts,
|
|
664
|
+
destinationUrlParts: destinationParts,
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
// Eagerly evaluate the slot's access chain only for skip candidates.
|
|
668
|
+
// This serves two purposes:
|
|
669
|
+
// 1. Satisfies security principle #3 (auth always runs) for skipped slots
|
|
670
|
+
// 2. Determines whether access denied (denied slots must not be skipped)
|
|
671
|
+
//
|
|
672
|
+
// Non-skip-candidate slots skip eager evaluation — their access.ts
|
|
673
|
+
// runs during render via SlotAccessGate (normal path). Per design doc:
|
|
674
|
+
// "No access check for default.tsx" (destMatch null = unmatched slot).
|
|
675
|
+
const chainVerdicts =
|
|
676
|
+
isSkipCandidate && destMatch
|
|
677
|
+
? await evaluateSlotAccessChain(slotManifest, destMatch.chain)
|
|
678
|
+
: [];
|
|
679
|
+
const accessBlocked = chainVerdicts.some((v) => v.verdict !== 'pass');
|
|
680
|
+
const canSkip = isSkipCandidate && !accessBlocked;
|
|
681
|
+
|
|
682
|
+
if (canSkip) {
|
|
683
|
+
// Access already ran eagerly (all verdicts 'pass') — principle #3 satisfied.
|
|
684
|
+
// No gate wrapper needed.
|
|
685
|
+
slotProps[slotName] = h(SegmentOutlet, {
|
|
686
|
+
segmentPath: slotKey,
|
|
687
|
+
skip: true,
|
|
688
|
+
children: null,
|
|
689
|
+
});
|
|
690
|
+
slotSkipInfo.push({
|
|
691
|
+
slotKey,
|
|
692
|
+
parentSegmentId: segmentId,
|
|
693
|
+
isRequestDependent: false,
|
|
694
|
+
denied: false,
|
|
695
|
+
skipped: true,
|
|
696
|
+
});
|
|
697
|
+
} else {
|
|
698
|
+
const resolvedElement = await resolveSlotElement(
|
|
699
|
+
slotManifest,
|
|
700
|
+
match,
|
|
701
|
+
h,
|
|
702
|
+
interception,
|
|
703
|
+
parentTreePath,
|
|
704
|
+
chainVerdicts
|
|
705
|
+
);
|
|
706
|
+
slotProps[slotName] = h(SegmentOutlet, {
|
|
707
|
+
segmentPath: slotKey,
|
|
708
|
+
children: resolvedElement,
|
|
709
|
+
});
|
|
710
|
+
// Static analysis: check if any file in the slot's RENDERED tree
|
|
711
|
+
// is request-dependent. Only check layouts when destMatch exists —
|
|
712
|
+
// unmatched slots render default.tsx directly without layouts.
|
|
713
|
+
let slotRequestDep = false;
|
|
714
|
+
const destLeaf = destMatch?.chain[destMatch.chain.length - 1];
|
|
715
|
+
const hasRenderedPage = destMatch && destLeaf?.page;
|
|
716
|
+
if (hasRenderedPage) {
|
|
717
|
+
// Check slot root layout (rendered by wrapWithLayout)
|
|
718
|
+
if (
|
|
719
|
+
slotManifest.layout?.filePath &&
|
|
720
|
+
isStaticRequestDependent(slotManifest.layout.filePath)
|
|
721
|
+
) {
|
|
722
|
+
slotRequestDep = true;
|
|
723
|
+
}
|
|
724
|
+
// Check intermediate slot layouts
|
|
725
|
+
if (!slotRequestDep) {
|
|
726
|
+
for (const seg of destMatch.chain) {
|
|
727
|
+
if (seg.layout?.filePath && isStaticRequestDependent(seg.layout.filePath)) {
|
|
728
|
+
slotRequestDep = true;
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
// Check leaf page
|
|
734
|
+
if (!slotRequestDep) {
|
|
735
|
+
if (destLeaf?.page?.filePath && isStaticRequestDependent(destLeaf.page.filePath)) {
|
|
736
|
+
slotRequestDep = true;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
} else {
|
|
740
|
+
// No match — only default.tsx is rendered (no layouts)
|
|
741
|
+
const defaultFile = slotManifest.default?.filePath;
|
|
742
|
+
if (!defaultFile) {
|
|
743
|
+
slotRequestDep = true; // No entry file → conservative
|
|
744
|
+
} else {
|
|
745
|
+
slotRequestDep = isStaticRequestDependent(defaultFile);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
slotSkipInfo.push({
|
|
749
|
+
slotKey,
|
|
750
|
+
parentSegmentId: segmentId,
|
|
751
|
+
isRequestDependent: slotRequestDep,
|
|
752
|
+
denied: accessBlocked,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
return slotProps;
|
|
434
758
|
}
|