@timber-js/app 0.2.0-alpha.21 → 0.2.0-alpha.211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/agent-skill.md +346 -0
- package/bin/timber.mjs +15 -1
- package/dist/_chunks/actions-Rjk4htmA.js +1199 -0
- package/dist/_chunks/actions-Rjk4htmA.js.map +1 -0
- package/dist/_chunks/als-registry-DaxkVjt5.js +45 -0
- package/dist/_chunks/als-registry-DaxkVjt5.js.map +1 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
- package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
- package/dist/_chunks/base-path-DaQrzbez.js +80 -0
- package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/build-output-helper-RV_BRcF1.js +367 -0
- package/dist/_chunks/build-output-helper-RV_BRcF1.js.map +1 -0
- package/dist/_chunks/cache-api-DGdYfNJn.js +1182 -0
- package/dist/_chunks/cache-api-DGdYfNJn.js.map +1 -0
- package/dist/_chunks/canonicalize-CgHoscYO.js +66 -0
- package/dist/_chunks/canonicalize-CgHoscYO.js.map +1 -0
- package/dist/_chunks/chains-DGX9zmg9.js +272 -0
- package/dist/_chunks/chains-DGX9zmg9.js.map +1 -0
- package/dist/_chunks/classify-QwG5rxKI.js +147 -0
- package/dist/_chunks/classify-QwG5rxKI.js.map +1 -0
- package/dist/_chunks/cli-check-ajNY3B2e.js +252 -0
- package/dist/_chunks/cli-check-ajNY3B2e.js.map +1 -0
- package/dist/_chunks/cli-context-By7k2xVo.js +70 -0
- package/dist/_chunks/cli-context-By7k2xVo.js.map +1 -0
- package/dist/_chunks/cli-schema-sync-D2eI8jEg.js +299 -0
- package/dist/_chunks/cli-schema-sync-D2eI8jEg.js.map +1 -0
- package/dist/_chunks/client-dep-entries-2HCF09no.js +66 -0
- package/dist/_chunks/client-dep-entries-2HCF09no.js.map +1 -0
- package/dist/_chunks/cloudflare-Byxl8FWP.js +1333 -0
- package/dist/_chunks/cloudflare-Byxl8FWP.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/codegen-Bps1sLKJ.js +432 -0
- package/dist/_chunks/codegen-Bps1sLKJ.js.map +1 -0
- package/dist/_chunks/convention-lint-DLmhGsRS.js +590 -0
- package/dist/_chunks/convention-lint-DLmhGsRS.js.map +1 -0
- package/dist/_chunks/dev-server-TFpEwm3H.js +2039 -0
- package/dist/_chunks/dev-server-TFpEwm3H.js.map +1 -0
- package/dist/_chunks/dist-DtrJyBbw.js +386 -0
- package/dist/_chunks/dist-DtrJyBbw.js.map +1 -0
- package/dist/_chunks/error-boundary-DsNScGRM.js +1024 -0
- package/dist/_chunks/error-boundary-DsNScGRM.js.map +1 -0
- package/dist/_chunks/fast-hash-C-tVYrLb.js +41 -0
- package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
- package/dist/_chunks/format-BKclgVbk.js +14 -0
- package/dist/_chunks/format-BKclgVbk.js.map +1 -0
- package/dist/_chunks/fs-identity-BRKuL215.js +207 -0
- package/dist/_chunks/fs-identity-BRKuL215.js.map +1 -0
- package/dist/_chunks/graph-cache-CYiUS2aS.js +303 -0
- package/dist/_chunks/graph-cache-CYiUS2aS.js.map +1 -0
- package/dist/_chunks/href-validation-BIrxavIy.js +213 -0
- package/dist/_chunks/href-validation-BIrxavIy.js.map +1 -0
- package/dist/_chunks/json-lossy-check-CVuRs2hG.js +66 -0
- package/dist/_chunks/json-lossy-check-CVuRs2hG.js.map +1 -0
- package/dist/_chunks/live-graph-cNuWMYQI.js +151 -0
- package/dist/_chunks/live-graph-cNuWMYQI.js.map +1 -0
- package/dist/_chunks/logger-BP0LN6vP.js +662 -0
- package/dist/_chunks/logger-BP0LN6vP.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DSDjM_hJ.js} +71 -27
- package/dist/_chunks/metadata-routes-DSDjM_hJ.js.map +1 -0
- package/dist/_chunks/navigation-root-BQfo1-kG.js +126 -0
- package/dist/_chunks/navigation-root-BQfo1-kG.js.map +1 -0
- package/dist/_chunks/param-value-C8TNYchQ.js +66 -0
- package/dist/_chunks/param-value-C8TNYchQ.js.map +1 -0
- package/dist/_chunks/plugin-context-BPBPc3lL.js +345 -0
- package/dist/_chunks/plugin-context-BPBPc3lL.js.map +1 -0
- package/dist/_chunks/poison-rules-DoEhbqaY.js +110 -0
- package/dist/_chunks/poison-rules-DoEhbqaY.js.map +1 -0
- package/dist/_chunks/poison-scan-CfQ3unZR.js +99 -0
- package/dist/_chunks/poison-scan-CfQ3unZR.js.map +1 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
- package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
- package/dist/_chunks/render-timeout-DOf_BBcO.js +46 -0
- package/dist/_chunks/render-timeout-DOf_BBcO.js.map +1 -0
- package/dist/_chunks/resolve-schema-CBR6Lm4i.js +50 -0
- package/dist/_chunks/resolve-schema-CBR6Lm4i.js.map +1 -0
- package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/_chunks/rsc-cache-key-ClUiXQnK.js +243 -0
- package/dist/_chunks/rsc-cache-key-ClUiXQnK.js.map +1 -0
- package/dist/_chunks/rsc-media-type-DDc7duTD.js +61 -0
- package/dist/_chunks/rsc-media-type-DDc7duTD.js.map +1 -0
- package/dist/_chunks/rsc-payload-path-dffcs4jp.js +54 -0
- package/dist/_chunks/rsc-payload-path-dffcs4jp.js.map +1 -0
- package/dist/_chunks/scan-BoP17W3w.js +140 -0
- package/dist/_chunks/scan-BoP17W3w.js.map +1 -0
- package/dist/_chunks/scanner-DmqdxzbW.js +2056 -0
- package/dist/_chunks/scanner-DmqdxzbW.js.map +1 -0
- package/dist/_chunks/schema-bridge-C83xa9lT.js +199 -0
- package/dist/_chunks/schema-bridge-C83xa9lT.js.map +1 -0
- package/dist/_chunks/segment-classify-C539Pa2O.js +197 -0
- package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
- package/dist/_chunks/segment-context-xtPUGfdq.js +137 -0
- package/dist/_chunks/segment-context-xtPUGfdq.js.map +1 -0
- package/dist/_chunks/segment-keys-D5hu1hz4.js +62 -0
- package/dist/_chunks/segment-keys-D5hu1hz4.js.map +1 -0
- package/dist/_chunks/singleflight-BeVMMKi0.js +55 -0
- package/dist/_chunks/singleflight-BeVMMKi0.js.map +1 -0
- package/dist/_chunks/sizeof-BM1409x2.js +36 -0
- package/dist/_chunks/sizeof-BM1409x2.js.map +1 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js +49 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js.map +1 -0
- package/dist/_chunks/state-BhNGPsdi.js +50 -0
- package/dist/_chunks/state-BhNGPsdi.js.map +1 -0
- package/dist/_chunks/status-page-marker-BRX9Ib-d.js +564 -0
- package/dist/_chunks/status-page-marker-BRX9Ib-d.js.map +1 -0
- package/dist/_chunks/tree-match-6yihorhk.js +169 -0
- package/dist/_chunks/tree-match-6yihorhk.js.map +1 -0
- package/dist/_chunks/use-query-states-I3JMng6J.js +226 -0
- package/dist/_chunks/use-query-states-I3JMng6J.js.map +1 -0
- package/dist/_chunks/walkers-Czu2jXFq.js +144 -0
- package/dist/_chunks/walkers-Czu2jXFq.js.map +1 -0
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js +32 -0
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +72 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/canonicalize-module.d.ts +8 -0
- package/dist/adapters/canonicalize-module.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +74 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +65 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +123 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +224 -24
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -188
- package/dist/adapters/compress-module.d.ts +25 -4
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +63 -0
- package/dist/adapters/fs-identity.d.ts.map +1 -0
- package/dist/adapters/nitro-presets.d.ts +31 -0
- package/dist/adapters/nitro-presets.d.ts.map +1 -0
- package/dist/adapters/nitro-preview.d.ts +64 -0
- package/dist/adapters/nitro-preview.d.ts.map +1 -0
- package/dist/adapters/nitro.d.ts +54 -37
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +631 -359
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +67 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/types.d.ts +122 -16
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js +0 -0
- package/dist/analyze/chains.d.ts +124 -0
- package/dist/analyze/chains.d.ts.map +1 -0
- package/dist/analyze/classify.d.ts +153 -0
- package/dist/analyze/classify.d.ts.map +1 -0
- package/dist/analyze/crawl-entry.d.ts +17 -0
- package/dist/analyze/crawl-entry.d.ts.map +1 -0
- package/dist/analyze/crawl-entry.js +314 -0
- package/dist/analyze/crawl-entry.js.map +1 -0
- package/dist/analyze/crawl.d.ts +134 -0
- package/dist/analyze/crawl.d.ts.map +1 -0
- package/dist/analyze/graph-cache.d.ts +104 -0
- package/dist/analyze/graph-cache.d.ts.map +1 -0
- package/dist/analyze/graph-command.d.ts +43 -0
- package/dist/analyze/graph-command.d.ts.map +1 -0
- package/dist/analyze/graph-command.js +472 -0
- package/dist/analyze/graph-command.js.map +1 -0
- package/dist/analyze/live-graph.d.ts +81 -0
- package/dist/analyze/live-graph.d.ts.map +1 -0
- package/dist/analyze/poison-rules.d.ts +72 -0
- package/dist/analyze/poison-rules.d.ts.map +1 -0
- package/dist/analyze/poison-scan.d.ts +48 -0
- package/dist/analyze/poison-scan.d.ts.map +1 -0
- package/dist/analyze/scan.d.ts +73 -0
- package/dist/analyze/scan.d.ts.map +1 -0
- package/dist/cache/cache-api.d.ts +48 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/fast-hash.d.ts +5 -0
- package/dist/cache/fast-hash.d.ts.map +1 -1
- package/dist/cache/handler-store.d.ts +33 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +32 -9
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -326
- package/dist/cache/invalidation-epoch.d.ts +43 -0
- package/dist/cache/invalidation-epoch.d.ts.map +1 -0
- package/dist/cache/json-lossy-check.d.ts +11 -0
- package/dist/cache/json-lossy-check.d.ts.map +1 -0
- package/dist/cache/redis-handler.d.ts +141 -9
- package/dist/cache/redis-handler.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts +21 -2
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts +22 -0
- package/dist/cache/sizeof.d.ts.map +1 -0
- package/dist/cache/stable-stringify.d.ts +9 -0
- package/dist/cache/stable-stringify.d.ts.map +1 -1
- package/dist/cache/store.d.ts +53 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.d.ts +38 -0
- package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -0
- package/dist/cache/stores/cloudflare-kv.js +29 -0
- package/dist/cache/stores/cloudflare-kv.js.map +1 -0
- package/dist/cache/stores/memory.d.ts +42 -0
- package/dist/cache/stores/memory.d.ts.map +1 -0
- package/dist/cache/stores/memory.js +90 -0
- package/dist/cache/stores/memory.js.map +1 -0
- package/dist/cache/stores/redis.d.ts +69 -0
- package/dist/cache/stores/redis.d.ts.map +1 -0
- package/dist/cache/stores/redis.js +35 -0
- package/dist/cache/stores/redis.js.map +1 -0
- package/dist/cache/stores/vercel.d.ts +36 -0
- package/dist/cache/stores/vercel.d.ts.map +1 -0
- package/dist/cache/stores/vercel.js +33 -0
- package/dist/cache/stores/vercel.js.map +1 -0
- package/dist/cache/tag-aware-handler.d.ts +52 -0
- package/dist/cache/tag-aware-handler.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts +21 -11
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cdn/cloudflare-purge.d.ts +23 -0
- package/dist/cdn/cloudflare-purge.d.ts.map +1 -0
- package/dist/cdn/cloudflare-purge.js +30 -0
- package/dist/cdn/cloudflare-purge.js.map +1 -0
- package/dist/cdn/fastly-purge.d.ts +25 -0
- package/dist/cdn/fastly-purge.d.ts.map +1 -0
- package/dist/cdn/fastly-purge.js +33 -0
- package/dist/cdn/fastly-purge.js.map +1 -0
- package/dist/cdn/headers.d.ts +97 -0
- package/dist/cdn/headers.d.ts.map +1 -0
- package/dist/cdn/index.d.ts +5 -0
- package/dist/cdn/index.d.ts.map +1 -0
- package/dist/cdn/index.js +94 -0
- package/dist/cdn/index.js.map +1 -0
- package/dist/cdn/purge-store.d.ts +23 -0
- package/dist/cdn/purge-store.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.d.ts +20 -0
- package/dist/cdn/workers-cache-purge.d.ts.map +1 -0
- package/dist/cdn/workers-cache-purge.js +35 -0
- package/dist/cdn/workers-cache-purge.js.map +1 -0
- package/dist/cli-check.d.ts +133 -0
- package/dist/cli-check.d.ts.map +1 -0
- package/dist/cli-context.d.ts +54 -0
- package/dist/cli-context.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 +85 -13
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +224 -63
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +42 -2
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +19 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/action-queue.d.ts +63 -0
- package/dist/client/browser-entry/action-queue.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +53 -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 +41 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +32 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +28 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/deny-last-resort.d.ts +29 -0
- package/dist/client/deny-last-resort.d.ts.map +1 -0
- package/dist/client/error-boundary.d.ts +58 -9
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +2 -126
- package/dist/client/error-reconstituter.d.ts +55 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +16 -27
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/global-context.d.ts +15 -0
- package/dist/client/global-context.d.ts.map +1 -0
- package/dist/client/history.d.ts +50 -9
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +20 -33
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +330 -1150
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +20 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +792 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link.d.ts +85 -60
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/location-search.d.ts +12 -0
- package/dist/client/location-search.d.ts.map +1 -0
- package/dist/client/navigation-api.d.ts +133 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-commit.d.ts +111 -0
- package/dist/client/navigation-commit.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +54 -36
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/navigation-root.d.ts +106 -0
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/navigation-transition.d.ts +192 -0
- package/dist/client/navigation-transition.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts +1 -1
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/params-context.d.ts +81 -0
- package/dist/client/params-context.d.ts.map +1 -0
- package/dist/client/react-root.d.ts +45 -0
- package/dist/client/react-root.d.ts.map +1 -0
- package/dist/client/router-effects.d.ts +137 -0
- package/dist/client/router-effects.d.ts.map +1 -0
- package/dist/client/router-lifecycle.d.ts +98 -0
- package/dist/client/router-lifecycle.d.ts.map +1 -0
- package/dist/client/router-pipeline.d.ts +84 -0
- package/dist/client/router-pipeline.d.ts.map +1 -0
- package/dist/client/router-ref.d.ts +2 -2
- package/dist/client/router-ref.d.ts.map +1 -1
- package/dist/client/router-skew.d.ts +21 -0
- package/dist/client/router-skew.d.ts.map +1 -0
- package/dist/client/router-types.d.ts +334 -0
- package/dist/client/router-types.d.ts.map +1 -0
- package/dist/client/router-url.d.ts +24 -0
- package/dist/client/router-url.d.ts.map +1 -0
- package/dist/client/router.d.ts +1 -97
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +110 -28
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +186 -25
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +68 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/segment-update-context.d.ts +15 -0
- package/dist/client/segment-update-context.d.ts.map +1 -0
- package/dist/client/shallow-url.d.ts +10 -0
- package/dist/client/shallow-url.d.ts.map +1 -0
- package/dist/client/slot-content-cache-context.d.ts +35 -0
- package/dist/client/slot-content-cache-context.d.ts.map +1 -0
- package/dist/client/slot-context.d.ts +31 -0
- package/dist/client/slot-context.d.ts.map +1 -0
- package/dist/client/slot-outlet.d.ts +16 -0
- package/dist/client/slot-outlet.d.ts.map +1 -0
- package/dist/client/slot-provider.d.ts +25 -0
- package/dist/client/slot-provider.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +26 -50
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-client.d.ts +69 -0
- package/dist/client/stale-client.d.ts.map +1 -0
- package/dist/client/state.d.ts +21 -13
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/status-page-marker.d.ts +25 -0
- package/dist/client/status-page-marker.d.ts.map +1 -0
- package/dist/client/top-loader.d.ts +7 -6
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/unload-guard.d.ts +5 -0
- package/dist/client/unload-guard.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts +12 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/use-link-status.d.ts +5 -5
- package/dist/client/use-link-status.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts +13 -11
- package/dist/client/use-pathname.d.ts.map +1 -1
- package/dist/client/use-pending-navigation.d.ts +23 -0
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +10 -4
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +15 -8
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts +15 -8
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/client/use-segment-params.d.ts +55 -0
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +69 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +76 -0
- package/dist/codec.js.map +1 -0
- package/dist/config-types.d.ts +323 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-validation.d.ts +68 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/cookies/define-cookie.d.ts +58 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +3 -2
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +256 -36
- package/dist/cookies/index.js.map +1 -1
- package/dist/cookies/json-cookie.d.ts +64 -0
- package/dist/cookies/json-cookie.d.ts.map +1 -0
- package/dist/cookies/validation.d.ts +34 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +50 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +40 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/dev-page-shell.d.ts +95 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +32 -0
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/dev-tools/holding-server.d.ts +46 -0
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/hydration-overlay.d.ts +11 -0
- package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/dev-tools/instrumentation.d.ts +74 -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/{plugins/dev-error-overlay.d.ts → dev-tools/overlay.d.ts} +15 -25
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/dev-tools/terminal.d.ts +28 -0
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/fonts/ast-walk.d.ts +68 -0
- package/dist/fonts/ast-walk.d.ts.map +1 -0
- package/dist/fonts/ast.d.ts +112 -8
- package/dist/fonts/ast.d.ts.map +1 -1
- package/dist/fonts/bundle.d.ts +50 -0
- package/dist/fonts/bundle.d.ts.map +1 -0
- package/dist/fonts/css.d.ts +1 -1
- package/dist/fonts/dev-middleware.d.ts +22 -0
- package/dist/fonts/dev-middleware.d.ts.map +1 -0
- package/dist/fonts/fallbacks.d.ts +0 -7
- package/dist/fonts/fallbacks.d.ts.map +1 -1
- package/dist/fonts/google.d.ts +5 -3
- package/dist/fonts/google.d.ts.map +1 -1
- package/dist/fonts/local.d.ts +5 -5
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/paths.d.ts +43 -0
- package/dist/fonts/paths.d.ts.map +1 -0
- package/dist/fonts/pipeline.d.ts +177 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +82 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +47 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +77 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +35 -181
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8871 -14233
- 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 +262 -0
- package/dist/plugin-context.d.ts.map +1 -0
- 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 +61 -11
- 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/client-dep-entries.d.ts +44 -0
- package/dist/plugins/client-dep-entries.d.ts.map +1 -0
- package/dist/plugins/cloudflare-wasm.d.ts +21 -0
- package/dist/plugins/cloudflare-wasm.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-discovery.d.ts +123 -0
- package/dist/plugins/dev-discovery.d.ts.map +1 -0
- package/dist/plugins/dev-server.d.ts +24 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +34 -4
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +35 -74
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/graph-endpoint.d.ts +112 -0
- package/dist/plugins/graph-endpoint.d.ts.map +1 -0
- package/dist/plugins/mdx.d.ts +18 -5
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/post-build.d.ts +110 -0
- package/dist/plugins/post-build.d.ts.map +1 -0
- package/dist/plugins/prebuilt-capture.d.ts +67 -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 +98 -0
- package/dist/plugins/prebuilt.d.ts.map +1 -0
- package/dist/plugins/prerender-sugar.d.ts +39 -0
- package/dist/plugins/prerender-sugar.d.ts.map +1 -0
- package/dist/plugins/react-resolve.d.ts +49 -0
- package/dist/plugins/react-resolve.d.ts.map +1 -0
- package/dist/plugins/request-dep/analysis.d.ts +106 -0
- package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
- package/dist/plugins/request-dep/index.d.ts +75 -0
- package/dist/plugins/request-dep/index.d.ts.map +1 -0
- package/dist/plugins/request-dep/origin.d.ts +61 -0
- package/dist/plugins/request-dep/origin.d.ts.map +1 -0
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/rsc-assets-manifest.d.ts +33 -0
- package/dist/plugins/rsc-assets-manifest.d.ts.map +1 -0
- 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 +246 -26
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +26 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +61 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen-write.d.ts +42 -0
- package/dist/routing/codegen-write.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +8 -3
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/collision-probe.d.ts +104 -0
- package/dist/routing/collision-probe.d.ts.map +1 -0
- package/dist/routing/collision-spaces.d.ts +26 -0
- package/dist/routing/collision-spaces.d.ts.map +1 -0
- package/dist/routing/convention-lint.d.ts +55 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/export-detect.d.ts +91 -0
- package/dist/routing/export-detect.d.ts.map +1 -0
- package/dist/routing/file-cache.d.ts +8 -0
- package/dist/routing/file-cache.d.ts.map +1 -0
- package/dist/routing/index.d.ts +13 -7
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +5 -2
- package/dist/routing/interception-overlap.d.ts +35 -0
- package/dist/routing/interception-overlap.d.ts.map +1 -0
- package/dist/routing/interception.d.ts +234 -10
- package/dist/routing/interception.d.ts.map +1 -1
- package/dist/routing/link-codegen.d.ts +105 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/manifest-codegen.d.ts +26 -0
- package/dist/routing/manifest-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +14 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/schema-validation.d.ts +35 -0
- package/dist/routing/schema-validation.d.ts.map +1 -0
- package/dist/routing/segment-classify.d.ts +114 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/segment-codegen.d.ts +38 -0
- package/dist/routing/segment-codegen.d.ts.map +1 -0
- package/dist/routing/segment-keys.d.ts +118 -0
- package/dist/routing/segment-keys.d.ts.map +1 -0
- package/dist/routing/slot-placement.d.ts +48 -0
- package/dist/routing/slot-placement.d.ts.map +1 -0
- package/dist/routing/types.d.ts +81 -26
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +57 -0
- package/dist/routing/walkers.d.ts.map +1 -0
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +14 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/rsc-runtime/transforms.d.ts +13 -0
- package/dist/rsc-runtime/transforms.d.ts.map +1 -0
- package/dist/schema-bridge.d.ts +145 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +262 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +3 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +179 -360
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/parse-total.d.ts +81 -0
- package/dist/search-params/parse-total.d.ts.map +1 -0
- package/dist/search-params/serialize-equal.d.ts +9 -0
- package/dist/search-params/serialize-equal.d.ts.map +1 -0
- package/dist/search-params/wrappers.d.ts +76 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/server/access-gate.d.ts +98 -10
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +44 -9
- 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 +40 -5
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +78 -40
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +166 -16
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/body-limits.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +25 -30
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/canonicalize.d.ts +10 -0
- package/dist/server/canonicalize.d.ts.map +1 -1
- package/dist/server/chain-url-parts.d.ts +82 -0
- package/dist/server/chain-url-parts.d.ts.map +1 -0
- package/dist/server/children-interception.d.ts +49 -0
- package/dist/server/children-interception.d.ts.map +1 -0
- package/dist/server/coalesce-tick.d.ts +40 -0
- package/dist/server/coalesce-tick.d.ts.map +1 -0
- package/dist/server/compress.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +149 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +65 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/csp-nonce.d.ts +36 -0
- package/dist/server/csp-nonce.d.ts.map +1 -0
- package/dist/server/csrf.d.ts +58 -15
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/debug.d.ts +0 -1
- package/dist/server/debug.d.ts.map +1 -1
- package/dist/server/default-logger.d.ts +23 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/default-status-page.d.ts +45 -0
- package/dist/server/default-status-page.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +257 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts +21 -15
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +14 -12
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +102 -10
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/error-response-headers.d.ts +3 -0
- package/dist/server/error-response-headers.d.ts.map +1 -0
- package/dist/server/fallback-error.d.ts +19 -7
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +45 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/form-data.d.ts +41 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/form-flash.d.ts +2 -2
- package/dist/server/head-response.d.ts +35 -0
- package/dist/server/head-response.d.ts.map +1 -0
- package/dist/server/html-injector-core.d.ts +257 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +84 -42
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +17 -54
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +195 -2922
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +11 -4
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/internal.d.ts +47 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +4645 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/json-status-response.d.ts +34 -0
- package/dist/server/json-status-response.d.ts.map +1 -0
- package/dist/server/logger.d.ts +78 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/metadata-collector.d.ts +73 -0
- package/dist/server/metadata-collector.d.ts.map +1 -0
- package/dist/server/metadata-platform.d.ts +2 -2
- package/dist/server/metadata-render.d.ts +2 -2
- package/dist/server/metadata-render.d.ts.map +1 -1
- package/dist/server/metadata-routes.d.ts +71 -11
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-social.d.ts +2 -2
- package/dist/server/metadata.d.ts +10 -2
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +20 -5
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +105 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/nuqs-ssr-provider.d.ts +7 -3
- package/dist/server/nuqs-ssr-provider.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +83 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +193 -0
- package/dist/server/pipeline-helpers.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +70 -9
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +7 -1
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +59 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +70 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +147 -23
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +31 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/prebuilt/cache-key.d.ts +63 -0
- package/dist/server/prebuilt/cache-key.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-render.d.ts +25 -0
- package/dist/server/prebuilt/capture-render.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-routes.d.ts +37 -0
- package/dist/server/prebuilt/capture-routes.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +101 -0
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -0
- package/dist/server/prebuilt/key-discipline.d.ts +52 -0
- package/dist/server/prebuilt/key-discipline.d.ts.map +1 -0
- package/dist/server/prebuilt/lifetime.d.ts +38 -0
- package/dist/server/prebuilt/lifetime.d.ts.map +1 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts +27 -0
- package/dist/server/prebuilt/manifest-tag-index.d.ts.map +1 -0
- package/dist/server/prebuilt/overlay.d.ts +100 -0
- package/dist/server/prebuilt/overlay.d.ts.map +1 -0
- package/dist/server/prebuilt/payload-source.d.ts +79 -0
- package/dist/server/prebuilt/payload-source.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +106 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -0
- package/dist/server/prebuilt/synthetic-store.d.ts +67 -0
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -0
- package/dist/server/prebuilt-builder.d.ts +121 -0
- package/dist/server/prebuilt-builder.d.ts.map +1 -0
- package/dist/server/prebuilt-runtime.d.ts +111 -0
- package/dist/server/prebuilt-runtime.d.ts.map +1 -0
- package/dist/server/primitives.d.ts +101 -90
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/publish-params.d.ts +33 -0
- package/dist/server/publish-params.d.ts.map +1 -0
- package/dist/server/react-cache-bridge.d.ts +59 -0
- package/dist/server/react-cache-bridge.d.ts.map +1 -0
- package/dist/server/react-cache-scope.d.ts +49 -0
- package/dist/server/react-cache-scope.d.ts.map +1 -0
- package/dist/server/render-timeout.d.ts +66 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/render-utils.d.ts +35 -0
- package/dist/server/render-utils.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +128 -103
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-dep.d.ts +15 -0
- package/dist/server/request-dep.d.ts.map +1 -0
- package/dist/server/response-cache-policy.d.ts +3 -0
- package/dist/server/response-cache-policy.d.ts.map +1 -0
- package/dist/server/route-element-builder.d.ts +57 -30
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-element-helpers.d.ts +12 -0
- package/dist/server/route-element-helpers.d.ts.map +1 -0
- package/dist/server/route-handler.d.ts +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +55 -38
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/route-module-loader.d.ts +37 -0
- package/dist/server/route-module-loader.d.ts.map +1 -0
- package/dist/server/rsc-cache-key-guard.d.ts +78 -0
- package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
- package/dist/server/rsc-entry/action-dispatcher.d.ts +67 -0
- package/dist/server/rsc-entry/action-dispatcher.d.ts.map +1 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts +19 -3
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +55 -0
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -0
- package/dist/server/rsc-entry/error-renderer.d.ts +35 -21
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +14 -59
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +30 -6
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +50 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/render-signals.d.ts +65 -0
- package/dist/server/rsc-entry/render-signals.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +98 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts +30 -6
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +12 -30
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +6 -2
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +44 -7
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-error-envelope.d.ts +11 -0
- package/dist/server/rsc-error-envelope.d.ts.map +1 -0
- package/dist/server/safe-load.d.ts +39 -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/signal-identity.d.ts +43 -0
- package/dist/server/signal-identity.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +130 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/skippable-prefix.d.ts +29 -0
- package/dist/server/skippable-prefix.d.ts.map +1 -0
- package/dist/server/slot-interception.d.ts +80 -0
- package/dist/server/slot-interception.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +138 -7
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/slot-subtree-contain.d.ts +54 -0
- package/dist/server/slot-subtree-contain.d.ts.map +1 -0
- package/dist/server/ssr-bridge-types.d.ts +198 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -0
- package/dist/server/ssr-entry.d.ts +8 -47
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +60 -27
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +93 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/state-tree-diff.d.ts +44 -9
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/static-generator.d.ts +112 -0
- package/dist/server/static-generator.d.ts.map +1 -0
- package/dist/server/static-not-found.d.ts +52 -0
- package/dist/server/static-not-found.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +26 -15
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +59 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +57 -26
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-match.d.ts +59 -0
- package/dist/server/tree-match.d.ts.map +1 -0
- package/dist/server/types.d.ts +89 -8
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/element-type.d.ts +50 -0
- package/dist/server/utils/element-type.d.ts.map +1 -0
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/workers-cache-bridge.d.ts +26 -0
- package/dist/server/workers-cache-bridge.d.ts.map +1 -0
- package/dist/shared/als-slots.d.ts +42 -0
- package/dist/shared/als-slots.d.ts.map +1 -0
- package/dist/shared/base-path.d.ts +56 -0
- package/dist/shared/base-path.d.ts.map +1 -0
- package/dist/shared/csrf-reject.d.ts +16 -0
- package/dist/shared/csrf-reject.d.ts.map +1 -0
- package/dist/shared/error-digest.d.ts +28 -0
- package/dist/shared/error-digest.d.ts.map +1 -0
- package/dist/shared/href-validation.d.ts +49 -0
- package/dist/shared/href-validation.d.ts.map +1 -0
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shared/param-value.d.ts +104 -0
- package/dist/shared/param-value.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +110 -0
- package/dist/shared/payload-root.d.ts.map +1 -0
- package/dist/shared/redirect-type.d.ts +17 -0
- package/dist/shared/redirect-type.d.ts.map +1 -0
- package/dist/shared/rsc-cache-key.d.ts +163 -0
- package/dist/shared/rsc-cache-key.d.ts.map +1 -0
- package/dist/shared/rsc-error-envelope.d.ts +16 -0
- package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
- package/dist/shared/rsc-manifest.d.ts +28 -0
- package/dist/shared/rsc-manifest.d.ts.map +1 -0
- package/dist/shared/rsc-media-type.d.ts +52 -0
- package/dist/shared/rsc-media-type.d.ts.map +1 -0
- package/dist/shared/rsc-payload-path.d.ts +48 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -0
- package/dist/shared/segment-info.d.ts +66 -0
- package/dist/shared/segment-info.d.ts.map +1 -0
- package/dist/shared/slot-params.d.ts +52 -0
- package/dist/shared/slot-params.d.ts.map +1 -0
- package/dist/shared/static-platform-files.d.ts +71 -0
- package/dist/shared/static-platform-files.d.ts.map +1 -0
- package/dist/shared/status-reason-phrase.d.ts +26 -0
- package/dist/shared/status-reason-phrase.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.d.ts +26 -0
- package/dist/shims/font-local.d.ts.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/dist/shims/headers.d.ts +53 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/image.d.ts +120 -120
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +25 -12
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation-rsc.d.ts +21 -0
- package/dist/shims/navigation-rsc.d.ts.map +1 -0
- package/dist/shims/navigation.d.ts +10 -5
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/dist/utils/write-file-atomic.d.ts +17 -0
- package/dist/utils/write-file-atomic.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +239 -0
- package/docs/api/31-api-client.mdx +170 -0
- package/docs/api/32-api-cache.mdx +339 -0
- package/docs/api/33-api-search-params.mdx +176 -0
- package/docs/api/34-api-config.mdx +359 -0
- package/docs/api/35-api-typescript.mdx +91 -0
- package/docs/api/36-cli.mdx +202 -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 +227 -0
- package/docs/learn/04-access-control.mdx +115 -0
- package/docs/learn/05-the-flush-point.mdx +175 -0
- package/docs/learn/06-typed-params.mdx +275 -0
- package/docs/learn/07-typed-routes.mdx +108 -0
- package/docs/learn/08-forms-and-actions.mdx +146 -0
- package/docs/learn/09-streaming.mdx +140 -0
- package/docs/learn/10-caching.mdx +270 -0
- package/docs/learn/11-middleware.mdx +164 -0
- package/docs/learn/12-error-handling.mdx +192 -0
- package/docs/learn/13-deploying.mdx +287 -0
- package/llms.txt +55 -0
- package/package.json +120 -29
- package/src/adapters/build-output-helper.ts +353 -0
- package/src/adapters/canonicalize-module.ts +29 -0
- package/src/adapters/cloudflare-dev.ts +183 -0
- package/src/adapters/cloudflare-kv-cache.ts +207 -0
- package/src/adapters/cloudflare.ts +809 -150
- package/src/adapters/compress-module.ts +110 -86
- package/src/adapters/fs-identity.ts +155 -0
- package/src/adapters/nitro-presets.ts +124 -0
- package/src/adapters/nitro-preview.ts +476 -0
- package/src/adapters/nitro.ts +317 -457
- package/src/adapters/raw-imports.d.ts +5 -0
- package/src/adapters/shared.ts +283 -0
- package/src/adapters/types.ts +127 -17
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/analyze/chains.ts +411 -0
- package/src/analyze/classify.ts +259 -0
- package/src/analyze/crawl-entry.ts +68 -0
- package/src/analyze/crawl.ts +500 -0
- package/src/analyze/graph-cache.ts +331 -0
- package/src/analyze/graph-command.ts +762 -0
- package/src/analyze/live-graph.ts +232 -0
- package/src/analyze/poison-rules.ts +165 -0
- package/src/analyze/poison-scan.ts +159 -0
- package/src/analyze/scan.ts +149 -0
- package/src/cache/cache-api.ts +107 -0
- package/src/cache/fast-hash.ts +5 -0
- package/src/cache/handler-store.ts +76 -0
- package/src/cache/index.ts +115 -22
- package/src/cache/invalidation-epoch.ts +93 -0
- package/src/cache/json-lossy-check.ts +69 -0
- package/src/cache/redis-handler.ts +198 -20
- package/src/cache/singleflight.ts +72 -6
- package/src/cache/sizeof.ts +35 -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 +254 -0
- package/src/cache/timber-cache.ts +165 -40
- package/src/cdn/cloudflare-purge.ts +50 -0
- package/src/cdn/fastly-purge.ts +63 -0
- package/src/cdn/headers.ts +153 -0
- package/src/cdn/index.ts +23 -0
- package/src/cdn/purge-store.ts +34 -0
- package/src/cdn/workers-cache-purge.ts +34 -0
- package/src/cli-check.ts +417 -0
- package/src/cli-context.ts +119 -0
- package/src/cli-schema-sync.ts +401 -0
- package/src/cli.ts +330 -78
- package/src/client/browser-dev.ts +192 -5
- package/src/client/browser-entry/action-dispatch.ts +237 -0
- package/src/client/browser-entry/action-queue.ts +152 -0
- package/src/client/browser-entry/hmr.ts +70 -0
- package/src/client/browser-entry/hydrate.ts +143 -0
- package/src/client/browser-entry/index.ts +120 -0
- package/src/client/browser-entry/post-hydration.ts +99 -0
- package/src/client/browser-entry/router-init.ts +406 -0
- package/src/client/browser-entry/rsc-stream.ts +145 -0
- package/src/client/browser-entry/scroll.ts +50 -0
- package/src/client/deny-last-resort.tsx +54 -0
- package/src/client/error-boundary.tsx +279 -61
- package/src/client/error-reconstituter.tsx +84 -0
- package/src/client/form.tsx +36 -32
- package/src/client/global-context.ts +31 -0
- package/src/client/history.ts +74 -11
- package/src/client/index.ts +89 -53
- package/src/client/internal.ts +54 -0
- package/src/client/link.tsx +468 -151
- package/src/client/location-search.ts +15 -0
- package/src/client/navigation-api.ts +380 -0
- package/src/client/navigation-commit.ts +318 -0
- package/src/client/navigation-context.ts +67 -134
- package/src/client/navigation-root.tsx +236 -0
- package/src/client/navigation-transition.ts +337 -0
- package/src/client/nuqs-adapter.tsx +21 -9
- package/src/client/params-context.ts +187 -0
- package/src/client/react-root.ts +82 -0
- package/src/client/router-effects.ts +235 -0
- package/src/client/router-lifecycle.ts +354 -0
- package/src/client/router-pipeline.ts +458 -0
- package/src/client/router-ref.ts +3 -3
- package/src/client/router-skew.ts +30 -0
- package/src/client/router-types.ts +370 -0
- package/src/client/router-url.ts +32 -0
- package/src/client/router.ts +491 -424
- package/src/client/rsc-fetch.ts +510 -109
- package/src/client/segment-cache.ts +362 -41
- package/src/client/segment-context.ts +7 -4
- package/src/client/segment-outlet.tsx +96 -0
- package/src/client/segment-update-context.ts +23 -0
- package/src/client/shallow-url.ts +22 -0
- package/src/client/slot-content-cache-context.ts +43 -0
- package/src/client/slot-context.ts +50 -0
- package/src/client/slot-outlet.tsx +22 -0
- package/src/client/slot-provider.tsx +32 -0
- package/src/client/ssr-data.ts +27 -67
- package/src/client/stale-client.ts +191 -0
- package/src/client/state.ts +31 -24
- package/src/client/status-page-marker.tsx +32 -0
- package/src/client/top-loader.tsx +13 -10
- package/src/client/unload-guard.ts +35 -3
- package/src/client/use-cookie.ts +70 -18
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-pathname.ts +22 -31
- package/src/client/use-pending-navigation.ts +40 -0
- package/src/client/use-query-states.ts +206 -36
- package/src/client/use-router.ts +31 -9
- package/src/client/use-search-params.ts +38 -49
- package/src/client/use-segment-params.ts +69 -0
- package/src/client/use-selected-layout-segment.ts +2 -2
- package/src/codec.ts +149 -0
- package/src/config-types.ts +323 -0
- package/src/config-validation.ts +464 -0
- package/src/cookies/define-cookie.ts +222 -53
- package/src/cookies/index.ts +13 -2
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +192 -0
- package/src/dev-tools/404-page.ts +286 -0
- package/src/dev-tools/browser-logs.ts +55 -0
- package/src/dev-tools/dev-page-shell.ts +278 -0
- package/src/dev-tools/error-page.ts +331 -0
- package/src/dev-tools/holding-server.ts +185 -0
- package/src/dev-tools/hydration-overlay.ts +158 -0
- package/src/dev-tools/index.ts +79 -0
- package/src/dev-tools/instrumentation.ts +261 -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/{plugins/dev-error-overlay.ts → dev-tools/overlay.ts} +25 -80
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +182 -0
- package/src/fonts/ast-walk.ts +235 -0
- package/src/fonts/ast.ts +479 -128
- package/src/fonts/bundle.ts +138 -0
- package/src/fonts/css.ts +1 -1
- package/src/fonts/dev-middleware.ts +85 -0
- package/src/fonts/fallbacks.ts +0 -23
- package/src/fonts/google.ts +101 -19
- package/src/fonts/local.ts +12 -11
- package/src/fonts/paths.ts +58 -0
- package/src/fonts/pipeline.ts +348 -0
- package/src/fonts/transform.ts +311 -0
- package/src/fonts/types.ts +52 -1
- package/src/fonts/virtual-modules.ts +179 -0
- package/src/index.ts +513 -380
- 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 +502 -0
- package/src/plugins/build-manifest.ts +204 -36
- package/src/plugins/build-report.ts +299 -87
- 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/client-dep-entries.ts +78 -0
- package/src/plugins/cloudflare-wasm.ts +141 -0
- package/src/plugins/content.ts +31 -2
- package/src/plugins/dev-discovery.ts +218 -0
- package/src/plugins/dev-server.ts +360 -97
- package/src/plugins/entries.ts +149 -16
- package/src/plugins/fonts.ts +260 -657
- package/src/plugins/graph-endpoint.ts +532 -0
- package/src/plugins/mdx.ts +108 -35
- package/src/plugins/post-build.ts +327 -0
- package/src/plugins/prebuilt-capture.ts +213 -0
- package/src/plugins/prebuilt-options-analysis.ts +175 -0
- package/src/plugins/prebuilt.ts +670 -0
- package/src/plugins/prerender-sugar.ts +316 -0
- package/src/plugins/react-resolve.ts +149 -0
- package/src/plugins/request-dep/analysis.ts +447 -0
- package/src/plugins/request-dep/index.ts +376 -0
- package/src/plugins/request-dep/origin.ts +310 -0
- package/src/plugins/routing.ts +273 -277
- package/src/plugins/rsc-assets-manifest.ts +251 -0
- package/src/plugins/server-bundle.ts +99 -14
- package/src/plugins/shims.ts +260 -97
- package/src/plugins/static-build.ts +681 -71
- package/src/react-canary.d.ts +2 -0
- package/src/routing/codegen-shared.ts +39 -0
- package/src/routing/codegen-types.ts +62 -0
- package/src/routing/codegen-write.ts +163 -0
- package/src/routing/codegen.ts +349 -232
- package/src/routing/collision-probe.ts +438 -0
- package/src/routing/collision-spaces.ts +281 -0
- package/src/routing/convention-lint.ts +651 -0
- package/src/routing/export-detect.ts +536 -0
- package/src/routing/file-cache.ts +23 -0
- package/src/routing/index.ts +16 -7
- package/src/routing/interception-overlap.ts +141 -0
- package/src/routing/interception.ts +1044 -67
- package/src/routing/link-codegen.ts +280 -0
- package/src/routing/manifest-codegen.ts +232 -0
- package/src/routing/scanner.ts +417 -223
- package/src/routing/schema-validation.ts +155 -0
- package/src/routing/segment-classify.ts +280 -0
- package/src/routing/segment-codegen.ts +99 -0
- package/src/routing/segment-keys.ts +186 -0
- package/src/routing/slot-placement.ts +97 -0
- package/src/routing/types.ts +82 -26
- package/src/routing/walkers.ts +98 -0
- package/src/rsc-runtime/rsc.ts +9 -0
- package/src/rsc-runtime/ssr.ts +51 -0
- package/src/rsc-runtime/transforms.ts +13 -0
- package/src/rsc-runtime/vendor-types.d.ts +27 -0
- package/src/schema-bridge.ts +382 -0
- package/src/search-params/define.ts +677 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/parse-total.ts +91 -0
- package/src/search-params/serialize-equal.ts +14 -0
- package/src/search-params/wrappers.ts +150 -0
- package/src/server/access-gate.tsx +195 -56
- package/src/server/action-client.ts +126 -33
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +457 -111
- package/src/server/actions.ts +172 -85
- package/src/server/als-registry.ts +224 -25
- package/src/server/body-limits.ts +10 -2
- package/src/server/build-manifest.ts +33 -57
- package/src/server/canonicalize.ts +6 -3
- package/src/server/chain-url-parts.ts +163 -0
- package/src/server/children-interception.ts +116 -0
- package/src/server/coalesce-tick.ts +75 -0
- package/src/server/compress.ts +43 -8
- package/src/server/cookie-context.ts +454 -0
- package/src/server/cookie-parsing.ts +163 -0
- package/src/server/csp-nonce.ts +58 -0
- package/src/server/csrf.ts +228 -35
- package/src/server/debug.ts +0 -1
- package/src/server/default-logger.ts +100 -0
- package/src/server/default-status-page.ts +88 -0
- package/src/server/deny-boundary.ts +527 -0
- package/src/server/deny-renderer.ts +201 -179
- package/src/server/early-hints-sender.ts +4 -3
- package/src/server/early-hints.ts +39 -29
- package/src/server/error-boundary-wrapper.ts +160 -44
- package/src/server/error-response-headers.ts +18 -0
- package/src/server/fallback-error.ts +88 -104
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +67 -0
- package/src/server/form-data.ts +124 -12
- package/src/server/form-flash.ts +3 -3
- package/src/server/head-response.ts +54 -0
- package/src/server/html-injector-core.ts +512 -0
- package/src/server/html-injectors.ts +270 -255
- package/src/server/index.ts +36 -192
- package/src/server/instrumentation.ts +11 -4
- package/src/server/internal.ts +168 -0
- package/src/server/json-status-response.ts +105 -0
- package/src/server/logger.ts +126 -38
- package/src/server/metadata-collector.ts +177 -0
- package/src/server/metadata-platform.ts +2 -2
- package/src/server/metadata-render.ts +30 -8
- package/src/server/metadata-routes.ts +220 -24
- package/src/server/metadata-social.ts +2 -2
- package/src/server/metadata.ts +23 -2
- package/src/server/middleware-runner.ts +32 -5
- package/src/server/node-stream-transforms.ts +323 -0
- package/src/server/nuqs-ssr-provider.tsx +8 -7
- package/src/server/param-coercion.ts +201 -0
- package/src/server/pipeline-helpers.ts +485 -0
- package/src/server/pipeline-interception.ts +241 -32
- package/src/server/pipeline-metadata.ts +15 -1
- package/src/server/pipeline-outcome.ts +290 -0
- package/src/server/pipeline-phases.ts +496 -0
- package/src/server/pipeline.ts +385 -427
- package/src/server/port-resolution.ts +53 -0
- package/src/server/prebuilt/cache-key.ts +299 -0
- package/src/server/prebuilt/capture-render.ts +118 -0
- package/src/server/prebuilt/capture-routes.ts +104 -0
- package/src/server/prebuilt/capture-state.ts +196 -0
- package/src/server/prebuilt/key-discipline.ts +122 -0
- package/src/server/prebuilt/lifetime.ts +151 -0
- package/src/server/prebuilt/manifest-tag-index.ts +46 -0
- package/src/server/prebuilt/overlay.ts +256 -0
- package/src/server/prebuilt/payload-source.ts +202 -0
- package/src/server/prebuilt/slots.ts +202 -0
- package/src/server/prebuilt/synthetic-store.ts +125 -0
- package/src/server/prebuilt-builder.ts +514 -0
- package/src/server/prebuilt-runtime.ts +813 -0
- package/src/server/primitives.ts +153 -171
- package/src/server/publish-params.ts +42 -0
- package/src/server/react-cache-bridge.ts +124 -0
- package/src/server/react-cache-scope.ts +104 -0
- package/src/server/render-timeout.ts +128 -0
- package/src/server/render-utils.ts +45 -0
- package/src/server/request-context.ts +269 -332
- package/src/server/request-dep.ts +37 -0
- package/src/server/response-cache-policy.ts +45 -0
- package/src/server/route-element-builder.ts +514 -355
- package/src/server/route-element-helpers.ts +37 -0
- package/src/server/route-handler.ts +67 -27
- package/src/server/route-matcher.ts +238 -267
- package/src/server/route-module-loader.ts +161 -0
- package/src/server/rsc-cache-key-guard.ts +122 -0
- package/src/server/rsc-entry/action-dispatcher.ts +142 -0
- package/src/server/rsc-entry/action-middleware-runner.ts +130 -0
- package/src/server/rsc-entry/api-handler.ts +49 -81
- package/src/server/rsc-entry/deny-fallback.ts +151 -0
- package/src/server/rsc-entry/error-renderer.ts +301 -113
- package/src/server/rsc-entry/helpers.ts +90 -115
- package/src/server/rsc-entry/index.ts +370 -350
- package/src/server/rsc-entry/render-route.ts +229 -0
- package/src/server/rsc-entry/render-signals.ts +108 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +349 -0
- package/src/server/rsc-entry/rsc-payload.ts +192 -72
- package/src/server/rsc-entry/rsc-stream.ts +128 -131
- package/src/server/rsc-entry/ssr-bridge.ts +19 -6
- package/src/server/rsc-entry/ssr-renderer.ts +300 -137
- package/src/server/rsc-error-envelope.ts +18 -0
- package/src/server/rsc-prop-warnings.ts +1 -1
- package/src/server/safe-load.ts +53 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/server-only-guard-noop.js +3 -0
- package/src/server/server-timing.ts +1 -1
- package/src/server/signal-identity.ts +112 -0
- package/src/server/sitemap-generator.ts +337 -0
- package/src/server/sitemap-handler.ts +157 -0
- package/src/server/skippable-prefix.ts +172 -0
- package/src/server/slot-interception.ts +168 -0
- package/src/server/slot-resolver.ts +707 -300
- package/src/server/slot-subtree-contain.ts +273 -0
- package/src/server/ssr-bridge-types.ts +201 -0
- package/src/server/ssr-entry.ts +225 -104
- package/src/server/ssr-render.ts +354 -91
- package/src/server/ssr-wrappers.tsx +162 -0
- package/src/server/state-tree-diff.ts +85 -30
- package/src/server/static-generator.ts +680 -0
- package/src/server/static-not-found.ts +134 -0
- package/src/server/status-code-resolver.ts +107 -148
- package/src/server/stream-utils.ts +343 -0
- package/src/server/tracing.ts +163 -68
- package/src/server/tree-match.ts +494 -0
- package/src/server/types.ts +96 -11
- package/src/server/utils/element-type.ts +88 -0
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/waituntil-bridge.ts +1 -1
- package/src/server/workers-cache-bridge.ts +33 -0
- package/src/shared/als-slots.ts +74 -0
- package/src/shared/base-path.ts +80 -0
- package/src/shared/csrf-reject.ts +15 -0
- package/src/shared/error-digest.ts +46 -0
- package/src/shared/href-validation.ts +159 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shared/param-value.ts +281 -0
- package/src/shared/payload-root.ts +153 -0
- package/src/shared/redirect-type.ts +17 -0
- package/src/shared/rsc-cache-key.ts +269 -0
- package/src/shared/rsc-error-envelope.ts +16 -0
- package/src/shared/rsc-manifest.ts +29 -0
- package/src/shared/rsc-media-type.ts +59 -0
- package/src/shared/rsc-payload-path.ts +52 -0
- package/src/shared/segment-info.ts +67 -0
- package/src/shared/slot-params.ts +109 -0
- package/src/shared/static-platform-files.ts +75 -0
- package/src/shared/status-reason-phrase.ts +61 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +122 -1
- package/src/shims/navigation-client.ts +36 -32
- package/src/shims/navigation-rsc.ts +47 -0
- package/src/shims/navigation.ts +10 -7
- package/src/utils/state-machine.ts +111 -0
- package/src/utils/write-file-atomic.ts +32 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js +0 -41
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-B3Gypr3D.js +0 -108
- package/dist/_chunks/debug-B3Gypr3D.js.map +0 -1
- package/dist/_chunks/format-RyoGQL74.js +0 -164
- package/dist/_chunks/format-RyoGQL74.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js +0 -676
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/metadata-routes-Cjmvi3rQ.js.map +0 -1
- package/dist/_chunks/request-context-BQUC8PHn.js +0 -330
- package/dist/_chunks/request-context-BQUC8PHn.js.map +0 -1
- package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
- package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
- package/dist/_chunks/tracing-CemImE6h.js +0 -187
- package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/_chunks/use-query-states-D5KaffOK.js +0 -109
- package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
- package/dist/adapters/cloudflare.js.map +0 -1
- package/dist/cache/index.js.map +0 -1
- package/dist/cache/register-cached-function.d.ts +0 -17
- package/dist/cache/register-cached-function.d.ts.map +0 -1
- package/dist/client/browser-entry.d.ts +0 -21
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/error-boundary.js.map +0 -1
- package/dist/client/head.d.ts +0 -16
- package/dist/client/head.d.ts.map +0 -1
- package/dist/client/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/client/segment-merger.d.ts +0 -119
- package/dist/client/segment-merger.d.ts.map +0 -1
- package/dist/client/stale-reload.d.ts +0 -44
- package/dist/client/stale-reload.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts +0 -74
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/types.d.ts +0 -14
- package/dist/client/types.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts +0 -26
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/client/use-params.d.ts +0 -92
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/content/index.d.ts +0 -11
- package/dist/content/index.d.ts.map +0 -1
- package/dist/content/index.js +0 -2
- package/dist/plugins/adapter-build.d.ts +0 -18
- package/dist/plugins/adapter-build.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.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/plugins/server-action-exports.d.ts +0 -26
- package/dist/plugins/server-action-exports.d.ts.map +0 -1
- package/dist/routing/status-file-lint.d.ts +0 -33
- package/dist/routing/status-file-lint.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/codecs.d.ts +0 -53
- package/dist/search-params/codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/search-params/registry.d.ts +0 -20
- package/dist/search-params/registry.d.ts.map +0 -1
- package/dist/server/asset-headers.d.ts +0 -42
- package/dist/server/asset-headers.d.ts.map +0 -1
- package/dist/server/client-module-map.d.ts +0 -47
- package/dist/server/client-module-map.d.ts.map +0 -1
- package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
- package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts +0 -29
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts +0 -129
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/flush.d.ts +0 -74
- package/dist/server/flush.d.ts.map +0 -1
- package/dist/server/manifest-status-resolver.d.ts +0 -58
- package/dist/server/manifest-status-resolver.d.ts.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/tree-builder.d.ts +0 -126
- package/dist/server/tree-builder.d.ts.map +0 -1
- package/dist/utils/directive-parser.d.ts +0 -70
- package/dist/utils/directive-parser.d.ts.map +0 -1
- package/src/cache/register-cached-function.ts +0 -103
- package/src/client/browser-entry.ts +0 -678
- package/src/client/head.ts +0 -61
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/segment-merger.ts +0 -339
- package/src/client/stale-reload.ts +0 -87
- package/src/client/transition-root.tsx +0 -166
- package/src/client/types.ts +0 -21
- package/src/client/use-navigation-pending.ts +0 -38
- package/src/client/use-params.ts +0 -141
- package/src/content/index.ts +0 -13
- package/src/plugins/adapter-build.ts +0 -118
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/plugins/server-action-exports.ts +0 -220
- package/src/routing/status-file-lint.ts +0 -112
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/codecs.ts +0 -153
- package/src/search-params/create.ts +0 -321
- package/src/search-params/registry.ts +0 -31
- package/src/server/asset-headers.ts +0 -81
- package/src/server/client-module-map.ts +0 -58
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/dev-warnings.ts +0 -283
- package/src/server/flush.ts +0 -182
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/prerender.ts +0 -139
- package/src/server/tree-builder.ts +0 -382
- package/src/shims/server-only-noop.js +0 -6
- package/src/utils/directive-parser.ts +0 -529
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","names":[],"sources":["../../src/server/render-utils.ts","../../src/server/server-timing.ts","../../src/server/stream-utils.ts","../../src/server/instrumentation.ts","../../src/server/safe-load.ts","../../src/server/route-matcher.ts","../../src/shared/csrf-reject.ts","../../src/server/csrf.ts","../../src/server/pipeline-helpers.ts","../../src/server/proxy.ts","../../src/server/middleware-runner.ts","../../src/server/csp-nonce.ts","../../src/server/param-coercion.ts","../../src/server/pipeline-metadata.ts","../../src/server/state-tree-diff.ts","../../src/server/pipeline-interception.ts","../../src/server/response-cache-policy.ts","../../src/server/error-response-headers.ts","../../src/server/rsc-error-envelope.ts","../../src/server/pipeline-outcome.ts","../../src/server/pipeline-phases.ts","../../src/server/rsc-cache-key-guard.ts","../../src/server/head-response.ts","../../src/server/pipeline.ts","../../src/server/early-hints.ts","../../src/server/early-hints-sender.ts","../../src/client/error-reconstituter.tsx","../../src/server/deny-boundary.ts","../../src/server/access-gate.tsx","../../src/server/status-code-resolver.ts","../../src/server/body-limits.ts","../../src/server/metadata-social.ts","../../src/server/metadata-platform.ts","../../src/server/metadata-render.ts","../../src/server/metadata.ts","../../src/server/route-handler.ts","../../src/server/prebuilt/cache-key.ts","../../src/client/slot-context.ts","../../src/client/slot-outlet.tsx","../../src/client/slot-provider.tsx","../../src/server/prebuilt/lifetime.ts","../../src/server/prebuilt/slots.ts","../../src/server/prebuilt/key-discipline.ts","../../src/server/prebuilt/capture-state.ts","../../src/server/prebuilt-runtime.ts"],"sourcesContent":["/**\n * Shared render-phase utilities — used by both the Node.js and Web\n * stream wrappers. Pure functions only; no stream-shape dependencies.\n *\n * Consolidated from duplicated copies in node-stream-transforms.ts,\n * ssr-render.ts, and rsc-entry/helpers.ts. See TIM-1071 item 1.\n */\n\n/**\n * The ` nonce=\"…\"` attribute fragment for a timber-generated `<script>` tag,\n * or `''` when the request has no nonce. Callers interpolate it directly\n * after the tag name: `` `<script${nonceAttr(nonce)}>` ``.\n *\n * The value comes from `generateNonce` in csp-nonce.ts and is base64, so no attribute\n * escaping is required.\n */\nexport function nonceAttr(nonce: string | undefined): string {\n return nonce ? ` nonce=\"${nonce}\"` : '';\n}\n\n/**\n * Check if an error is an abort error (connection closed by client).\n *\n * When the browser aborts a request (page refresh, navigation away),\n * the AbortSignal fires and React/streams throw an AbortError. This\n * is not an application error — suppress it from error boundaries and logs.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof DOMException && error.name === 'AbortError') return true;\n if (error instanceof Error && error.name === 'AbortError') return true;\n return false;\n}\n\n/**\n * Inline script that adds `<meta name=\"robots\" content=\"noindex\">` to the\n * document head. Injected when a render-phase error replaces the shell so\n * search engines don't index error pages.\n *\n * MUST be byte-identical across all stream wrappers (Node and Web) for a\n * given nonce to ensure consistent Content-Length headers — which is why\n * both wrappers call this one function rather than inlining the string.\n */\nexport function noindexScript(nonce?: string): string {\n return `<script${nonceAttr(nonce)}>document.head.appendChild(Object.assign(document.createElement(\"meta\"),{name:\"robots\",content:\"noindex\"}))</script>`;\n}\n","/**\n * Server-Timing header — dev-mode timing breakdowns for Chrome DevTools.\n *\n * Collects timing entries per request using ALS. Each pipeline phase\n * (proxy, middleware, render, SSR, access, fetch) records an entry.\n * Before response flush, entries are formatted into a Server-Timing header.\n *\n * Only active in dev mode — zero overhead in production.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing\n * Task: LOCAL-290\n */\n\nimport { timingAls } from './als-registry.ts';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\nexport interface TimingEntry {\n /** Metric name (alphanumeric + hyphens, no spaces). */\n name: string;\n /** Duration in milliseconds. */\n dur: number;\n /** Human-readable description (shown in DevTools). */\n desc?: string;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────\n\n/**\n * Run a callback with a per-request timing collector.\n * Must be called at the top of the request pipeline (wraps the full request).\n */\nexport function runWithTimingCollector<T>(fn: () => T): T {\n return timingAls.run({ entries: [] }, fn);\n}\n\n/**\n * Record a timing entry for the current request.\n * No-ops if called outside a timing collector (e.g. in production).\n */\nexport function recordTiming(entry: TimingEntry): void {\n const store = timingAls.getStore();\n if (!store) return;\n store.entries.push(entry);\n}\n\n/**\n * Run a function and automatically record its duration as a timing entry.\n * Returns the function's result. No-ops the recording if outside a collector.\n */\nexport async function withTiming<T>(\n name: string,\n desc: string | undefined,\n fn: () => T | Promise<T>\n): Promise<T> {\n const store = timingAls.getStore();\n if (!store) return fn();\n\n const start = performance.now();\n try {\n return await fn();\n } finally {\n const dur = Math.round(performance.now() - start);\n store.entries.push({ name, dur, desc });\n }\n}\n\n/**\n * Get the Server-Timing header value for the current request.\n * Returns null if no entries exist or outside a collector.\n *\n * Format: `name;dur=123;desc=\"description\", name2;dur=456`\n * See RFC 6797 / Server-Timing spec for format details.\n */\nexport function getServerTimingHeader(): string | null {\n const store = timingAls.getStore();\n if (!store || store.entries.length === 0) return null;\n\n // Deduplicate names — if a name appears multiple times, suffix with index\n const nameCounts = new Map<string, number>();\n const entries = store.entries.map((entry) => {\n const count = nameCounts.get(entry.name) ?? 0;\n nameCounts.set(entry.name, count + 1);\n const uniqueName = count > 0 ? `${entry.name}-${count}` : entry.name;\n return { ...entry, name: uniqueName };\n });\n\n const parts = entries.map((entry) => {\n let part = `${entry.name};dur=${entry.dur}`;\n if (entry.desc) {\n // Escape quotes in desc per Server-Timing spec\n const safeDesc = entry.desc.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n part += `;desc=\"${safeDesc}\"`;\n }\n return part;\n });\n\n // Respect header size limits — browsers typically handle up to 8KB headers.\n // Truncate if the header exceeds 4KB to leave room for other headers.\n const MAX_HEADER_SIZE = 4096;\n let result = '';\n for (let i = 0; i < parts.length; i++) {\n const candidate = result ? `${result}, ${parts[i]}` : parts[i]!;\n if (candidate.length > MAX_HEADER_SIZE) break;\n result = candidate;\n }\n\n return result || null;\n}\n\n/**\n * Sanitize a URL for use in Server-Timing desc.\n * Strips query params and truncates long paths to avoid information leakage.\n */\nexport function sanitizeUrlForTiming(url: string): string {\n try {\n const parsed = new URL(url);\n const origin = parsed.host;\n let path = parsed.pathname;\n // Truncate long paths\n if (path.length > 50) {\n path = path.slice(0, 47) + '...';\n }\n return `${origin}${path}`;\n } catch {\n // Not a valid URL — truncate raw string\n if (url.length > 60) {\n return url.slice(0, 57) + '...';\n }\n return url;\n }\n}\n","/**\n * Stream utilities for the RSC rendering pipeline.\n *\n * teeWithErrorPropagation — wraps native ReadableStream.tee() with:\n * 1. Cross-branch error propagation (error on one branch cancels the other)\n * 2. Buffer divergence monitoring (warns + cancels when threshold exceeded)\n *\n * This prevents two classes of bugs:\n * - Silent stalls when one tee branch errors and the other hangs indefinitely\n * - Unbounded memory growth when one consumer (SSR) is much slower than the other\n *\n * Design doc: 02-rendering-pipeline.md §\"RSC → SSR → Client Hydration\"\n */\n\nimport { getLogger } from './logger.ts';\n\n/** Default maximum buffer divergence before cancellation (5MB). */\nconst DEFAULT_MAX_BUFFER_BYTES = 5 * 1024 * 1024;\n\nexport interface TeeOptions {\n /**\n * Maximum byte divergence between the two branches before both are\n * cancelled. When one branch has consumed this many more bytes than\n * the other, the tee's internal buffer is at least this large.\n *\n * Default: 5MB.\n */\n maxBufferBytes?: number;\n}\n\n/**\n * Tee a ReadableStream with error propagation and buffer monitoring.\n *\n * Delegates to the native `stream.tee()` for the actual forking, then wraps\n * each branch in a ReadableStream that:\n * - Tracks bytes consumed per branch\n * - Cancels both branches if byte divergence exceeds `maxBufferBytes`\n * - Cancels the other branch if either branch is cancelled or errors\n *\n * The returned streams are drop-in replacements for the native tee branches.\n */\nexport function teeWithErrorPropagation(\n stream: ReadableStream<Uint8Array>,\n options?: TeeOptions\n): [ReadableStream<Uint8Array>, ReadableStream<Uint8Array>] {\n const maxBuffer = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n const [rawBranch1, rawBranch2] = stream.tee();\n\n // Shared state for cross-branch coordination\n let consumed1 = 0;\n let consumed2 = 0;\n let cancelled = false;\n\n // Readers and controllers are assigned when wrapBranch creates the wrapped\n // streams. We store them so cancelBoth can cancel raw tee branches AND\n // error the wrapped stream controllers for cross-branch propagation.\n let rawReader1: ReadableStreamDefaultReader<Uint8Array> | undefined;\n let rawReader2: ReadableStreamDefaultReader<Uint8Array> | undefined;\n let controller1: ReadableStreamDefaultController<Uint8Array> | undefined;\n let controller2: ReadableStreamDefaultController<Uint8Array> | undefined;\n\n /**\n * Cancel both tee branches. `initiator` is the branch index (0 or 1)\n * that triggered the cancellation — its controller is already being\n * closed/errored by the pull/cancel that triggered this, so we skip it.\n * Pass -1 to cancel+error both (e.g., from the buffer divergence guard).\n *\n * Both raw readers are always canceled regardless of initiator, because\n * the tee source stream is only released when both branches are canceled.\n * ReadableStreamDefaultReader.cancel() is idempotent, so double-cancel\n * is safe.\n */\n function cancelBoth(reason: unknown, initiator: number = -1): void {\n if (cancelled) return;\n cancelled = true;\n // Cancel both raw readers — tee source requires both branches canceled.\n rawReader1?.cancel(reason).catch(() => {});\n rawReader2?.cancel(reason).catch(() => {});\n // Error wrapped controllers so consumers see the failure.\n // Skip the initiator's controller — it's already being closed/errored.\n if (initiator !== 0) {\n try {\n controller1?.error(reason);\n } catch {\n /* already closed/errored */\n }\n }\n if (initiator !== 1) {\n try {\n controller2?.error(reason);\n } catch {\n /* already closed/errored */\n }\n }\n }\n\n function wrapBranch(\n branchIndex: number,\n rawBranch: ReadableStream<Uint8Array>,\n assignReader: (r: ReadableStreamDefaultReader<Uint8Array>) => void,\n assignController: (c: ReadableStreamDefaultController<Uint8Array>) => void,\n addConsumed: (n: number) => void,\n getSelfConsumed: () => number,\n getOtherConsumed: () => number\n ): ReadableStream<Uint8Array> {\n const reader = rawBranch.getReader();\n assignReader(reader);\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n assignController(controller);\n },\n\n async pull(controller) {\n if (cancelled) {\n return;\n }\n\n try {\n const { done, value } = await reader.read();\n\n // Re-check after await — cancelBoth may have fired while we\n // were waiting on the raw reader.\n if (cancelled) return;\n\n if (done) {\n try {\n controller.close();\n } catch {\n /* controller already errored by cancelBoth */\n }\n return;\n }\n\n addConsumed(value.byteLength);\n\n // Check buffer divergence: the difference in consumed bytes\n // approximates the tee's internal buffer size.\n const divergence = getSelfConsumed() - getOtherConsumed();\n if (divergence > maxBuffer) {\n const error = new Error(\n `RSC stream tee buffer exceeded ${formatBytes(maxBuffer)} ` +\n `(divergence: ${formatBytes(divergence)}). ` +\n `This usually means SSR is much slower than the inline stream consumer. ` +\n `Consider reducing RSC payload size or increasing the tee buffer limit.`\n );\n console.warn(`[timber] ${error.message}`);\n cancelBoth(error);\n return;\n }\n\n controller.enqueue(value);\n } catch (err) {\n if (!cancelled) {\n // Source stream errored — propagate to both branches.\n // cancelBoth with initiator skips our own controller,\n // so we error it explicitly here.\n cancelBoth(err, branchIndex);\n try {\n controller.error(err);\n } catch {\n /* already closed/errored */\n }\n }\n }\n },\n\n cancel(reason) {\n // Consumer cancelled this branch — propagate to the other\n cancelBoth(reason, branchIndex);\n },\n });\n }\n\n const wrapped1 = wrapBranch(\n 0,\n rawBranch1,\n (r) => {\n rawReader1 = r;\n },\n (c) => {\n controller1 = c;\n },\n (n) => {\n consumed1 += n;\n },\n () => consumed1,\n () => consumed2\n );\n\n const wrapped2 = wrapBranch(\n 1,\n rawBranch2,\n (r) => {\n rawReader2 = r;\n },\n (c) => {\n controller2 = c;\n },\n (n) => {\n consumed2 += n;\n },\n () => consumed2,\n () => consumed1\n );\n\n return [wrapped1, wrapped2];\n}\n\n/**\n * Wrap a response body with stream-lifecycle timing instrumentation.\n *\n * Logs firstChunk, lastChunk, close, maxGap (largest inter-chunk gap),\n * chunk count, and byte count on stream termination (clean close OR\n * cancellation/disconnect). Gated behind `serverTiming: 'detailed'`.\n *\n * Uses a manual reader pump to guarantee logging on all termination\n * paths — TransformStream.flush() is not called on cancellation.\n */\nexport function wrapResponseWithStreamTiming(\n body: ReadableStream<Uint8Array>,\n startTime: number\n): ReadableStream<Uint8Array> {\n let firstChunkMs = 0;\n let lastChunkMs = 0;\n let maxGapMs = 0;\n let prevChunkTime = 0;\n let chunks = 0;\n let bytes = 0;\n let cancelled = false;\n\n function emitLog(): void {\n const closeMs = Math.round(performance.now() - startTime);\n getLogger().debug('stream-lifecycle', {\n firstChunkMs,\n lastChunkMs,\n closeMs,\n maxGapMs,\n chunks,\n bytes,\n ...(cancelled ? { cancelled: true } : {}),\n });\n }\n\n const reader = body.getReader();\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const { done, value } = await reader.read();\n if (done) {\n emitLog();\n controller.close();\n return;\n }\n\n const now = performance.now();\n const relativeMs = Math.round(now - startTime);\n\n if (chunks === 0) {\n firstChunkMs = relativeMs;\n } else {\n const gap = Math.round(now - prevChunkTime);\n if (gap > maxGapMs) maxGapMs = gap;\n }\n\n prevChunkTime = now;\n lastChunkMs = relativeMs;\n chunks++;\n bytes += value.byteLength;\n\n controller.enqueue(value);\n } catch (err) {\n emitLog();\n controller.error(err);\n }\n },\n\n cancel(reason) {\n cancelled = true;\n emitLog();\n reader.cancel(reason).catch(() => {});\n },\n });\n}\n\n/** Format bytes as human-readable string (e.g., \"5.00 MB\"). */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n}\n\n/**\n * Read a byte stream to completion under one overall deadline and return\n * the concatenated bytes. Every read is raced against the time remaining,\n * and the reader is cancelled on every exit, so a stalled upstream never\n * outlives the deadline. See design/02-rendering-pipeline.md §\"Always\n * Timeout-Guard Stream Reads\".\n *\n * @param label - Prefix for the timeout error message. Both ways the deadline\n * can pass (between reads, or while a read is pending) reject with the same\n * `${label} did not complete within ${timeoutMs}ms`.\n */\nexport async function readAllBytesWithDeadline(\n stream: ReadableStream<Uint8Array>,\n timeoutMs: number,\n label: string\n): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n const deadline = Date.now() + timeoutMs;\n const deadlineError = () => new Error(`${label} did not complete within ${timeoutMs}ms`);\n try {\n for (;;) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) throw deadlineError();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(deadlineError()), remaining);\n });\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await Promise.race([reader.read(), timeout]);\n } finally {\n clearTimeout(timer);\n }\n if (result.done) break;\n chunks.push(result.value);\n totalLength += result.value.byteLength;\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n const bytes = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n}\n","/**\n * Instrumentation — loads and runs the user's instrumentation.ts file.\n *\n * instrumentation.ts is a file convention at the project root that exports:\n * - register() — called once at server startup, before the first request\n * - onRequestError() — called for every unhandled server error\n * - logger — any object with info/warn/error/debug methods\n *\n * See design/17-logging.md §\"instrumentation.ts — The Entry Point\"\n */\n\nimport { setLogger, type TimberLogger } from './logger.ts';\n\n// ─── Instrumentation Types ────────────────────────────────────────────────\n\nexport type InstrumentationOnRequestError = (\n error: unknown,\n request: InstrumentationRequestInfo,\n context: InstrumentationErrorContext\n) => void | Promise<void>;\n\nexport interface InstrumentationRequestInfo {\n /** HTTP method: 'GET', 'POST', etc. */\n method: string;\n /** Request path: '/dashboard/projects/123' */\n path: string;\n /** Request headers as a plain object. */\n headers: Record<string, string>;\n}\n\nexport interface InstrumentationErrorContext {\n /**\n * Which pipeline phase the error occurred in. `'setup'` is route setup\n * between `proxy.ts` and `middleware.ts`: route matching and segment-param\n * coercion (e.g. an `app/schema.ts` codec returning a value a param cannot\n * hold). `'handler'` is `middleware.ts`; `'route'` is a `route.ts` handler\n * or its `access.ts`, or a metadata route handler. design/17 §\"Which errors\n * reach it\" lists every error that is reported, and those that are not.\n */\n phase: 'proxy' | 'setup' | 'handler' | 'render' | 'action' | 'route';\n /** The route pattern: '/dashboard/projects/[id]' */\n routePath: string;\n /** Type of route that was matched. A metadata route reports as `'route'`. */\n routeType: 'page' | 'route' | 'action';\n /** Always set — OTEL trace ID or UUID fallback. */\n traceId: string;\n}\n\n// ─── Instrumentation Module Shape ─────────────────────────────────────────\n\ninterface InstrumentationModule {\n register?: () => void | Promise<void>;\n onRequestError?: InstrumentationOnRequestError;\n logger?: TimberLogger;\n}\n\n// ─── State ────────────────────────────────────────────────────────────────\n//\n// Intentional per-app singletons (not per-request). Instrumentation loads\n// once at server startup and persists for the lifetime of the process/isolate.\n// These must NOT be migrated to ALS — they are correctly scoped to the app.\n\nlet _initialized = false;\nlet _onRequestError: InstrumentationOnRequestError | null = null;\n\n/**\n * Load and initialize the user's instrumentation.ts module.\n *\n * - Awaits register() before returning (server blocks on this).\n * - Picks up the logger export and wires it into the framework logger.\n * - Stores onRequestError for later invocation.\n *\n * @param loader - Function that dynamically imports the user's instrumentation module.\n * Returns null if no instrumentation.ts exists.\n */\nexport async function loadInstrumentation(\n loader: () => Promise<InstrumentationModule | null>\n): Promise<void> {\n if (_initialized) return;\n _initialized = true;\n\n let mod: InstrumentationModule | null;\n try {\n mod = await loader();\n } catch (error) {\n console.error('[timber] Failed to load instrumentation.ts:', error);\n return;\n }\n\n if (!mod) return;\n\n // Wire up the logger export\n if (mod.logger && typeof mod.logger.info === 'function') {\n setLogger(mod.logger);\n }\n\n // Store onRequestError for later\n if (typeof mod.onRequestError === 'function') {\n _onRequestError = mod.onRequestError;\n }\n\n // Await register() — server does not accept requests until this resolves\n if (typeof mod.register === 'function') {\n try {\n await mod.register();\n } catch (error) {\n console.error('[timber] instrumentation.ts register() threw:', error);\n throw error;\n }\n }\n}\n\n/**\n * Call the user's onRequestError hook. Catches and logs any errors thrown\n * by the hook itself — it must not affect the response.\n */\nexport async function callOnRequestError(\n error: unknown,\n request: InstrumentationRequestInfo,\n context: InstrumentationErrorContext\n): Promise<void> {\n if (!_onRequestError) return;\n try {\n await _onRequestError(error, request, context);\n } catch (hookError) {\n console.error('[timber] onRequestError hook threw:', hookError);\n }\n}\n\n/**\n * Check if onRequestError is registered.\n */\nexport function hasOnRequestError(): boolean {\n return _onRequestError !== null;\n}\n\n/**\n * Reset instrumentation state. Test-only.\n */\nexport function resetInstrumentation(): void {\n _initialized = false;\n _onRequestError = null;\n}\n","/**\n * loadModule — enriched error context for route manifest .load() failures.\n *\n * Wraps the lazy `load()` functions from the route manifest with a\n * try/catch that re-throws with the file path and original cause.\n *\n * Loads the render can do without (status, error and fallback pages) go\n * through `loadFallbackModule()` in pipeline-helpers.ts instead, which logs\n * and reports the failure and resolves to `null` — never a bare\n * `.catch(() => null)`, which skips a broken page silently (TIM-1458).\n *\n * See design/spike-TIM-551-dynamic-import-audit.md §\"Proposed Wrapping Strategy\"\n */\n\n/** A manifest file reference with a lazy import function and file path. */\nexport interface ManifestLoader {\n load: () => Promise<unknown>;\n filePath: string;\n}\n\n/**\n * Custom error class for module load failures.\n *\n * Preserves the original error as `cause` while providing a\n * human-readable message with the file path.\n */\nexport class ModuleLoadError extends Error {\n /** The file path that failed to load. */\n readonly filePath: string;\n\n constructor(filePath: string, cause: unknown) {\n const originalMessage = cause instanceof Error ? cause.message : String(cause);\n super(`[timber] Failed to load module ${filePath}\\n ${originalMessage}`, { cause });\n this.name = 'ModuleLoadError';\n this.filePath = filePath;\n }\n}\n\n/**\n * Load a route manifest module with enriched error context.\n *\n * On success: returns the module object (same as `loader.load()`).\n * On failure: throws `ModuleLoadError` with file path and original cause.\n *\n * Error rendering paths that need fallthrough use `loadFallbackModule()`.\n */\nexport async function loadModule<T = Record<string, unknown>>(loader: ManifestLoader): Promise<T> {\n try {\n return (await loader.load()) as T;\n } catch (error) {\n throw new ModuleLoadError(loader.filePath, error);\n }\n}\n","/**\n * Route matcher — resolves a canonical pathname to a RouteMatch.\n *\n * Walks the manifest segment tree to find the best matching route.\n * Priority: static > dynamic > catch-all > optional-catch-all.\n * Groups are transparent (don't add URL depth).\n *\n * See design/07-routing.md §\"Request Lifecycle\"\n */\n\nimport type { RouteMatch } from './pipeline.ts';\nimport type { MiddlewareFn } from './middleware-runner.ts';\nimport type { SegmentNode, RouteTree } from '../routing/types.ts';\nimport {\n METADATA_ROUTE_CONVENTIONS,\n isStaticMetadataExtension,\n resolveStaticContentType,\n resolveServePathForFile,\n type MetadataRouteType,\n} from './metadata-routes.ts';\nimport { matchUrlParts, matchUrlPartsAll } from './tree-match.ts';\n\n// ─── Manifest Types ───────────────────────────────────────────────────────\n//\n// TIM-848: the runtime route manifest re-uses the same `SegmentNode<TFile>`\n// / `RouteTree<TFile>` interfaces from `routing/types.ts`. The only\n// difference between build-time and runtime is the file reference payload\n// — build-time has `{ filePath, extension }`, runtime has `{ filePath, load }`.\n// Walkers parameterized over `TFile` work on either; there is no separate\n// \"manifest\" tree shape.\n\n/** A file reference in the manifest (lazy import + path). */\nexport interface ManifestFile {\n load: () => Promise<unknown>;\n filePath: string;\n}\n\n/**\n * A segment node as it appears in the virtual:timber-route-manifest module.\n *\n * Type alias for `SegmentNode<ManifestFile>` — the same shape used by the\n * scanner, only with lazy `load` functions instead of build-time extension\n * metadata.\n */\nexport type ManifestSegmentNode = SegmentNode<ManifestFile>;\n\n/**\n * The manifest shape from virtual:timber-route-manifest.\n *\n * Extends `RouteTree<ManifestFile>` with `viteRoot`, the absolute path\n * to the Vite project root captured at build/load time. Used by dev-only\n * features (e.g., dev error page frame classification) that need a\n * correct project root even when CWD differs (e.g., monorepo custom root).\n * See TIM-807 / TIM-808.\n */\nexport interface ManifestRoot extends RouteTree<ManifestFile> {\n viteRoot: string;\n}\n\n// ─── Matcher ──────────────────────────────────────────────────────────────\n\n/**\n * Create a route matcher function from a manifest.\n *\n * The returned function takes a canonical pathname and returns a RouteMatch\n * or null if no route matches.\n */\nexport function createRouteMatcher(\n manifest: ManifestRoot\n): (pathname: string) => RouteMatch | null {\n return (pathname: string) => matchPathname(manifest.root, pathname);\n}\n\n/**\n * Match a canonical pathname against the segment tree.\n *\n * Splits the pathname into segments and delegates to the shared\n * tree walker. Collects middleware from the matched segment chain.\n */\nfunction matchPathname(root: ManifestSegmentNode, pathname: string): RouteMatch | null {\n const parts = pathname === '/' ? [] : pathname.slice(1).split('/');\n\n const result = matchUrlParts(root, parts);\n if (!result) return null;\n\n return {\n segments: result.chain,\n rawSegmentParams: result.params,\n // Uncoerced until the pipeline runs the codecs; a copy, so nothing that\n // later replaces or edits it can reach the raw record.\n segmentParams: { ...result.params },\n middlewareChain: collectMiddlewareChain(result.chain),\n };\n}\n\n/**\n * Collect middleware from a matched segment chain, root to leaf.\n *\n * Each entry is lazy-loaded via dynamic import on first invocation.\n *\n * Shared with the children-path interception resolver\n * (`children-interception.ts`), which assembles a chain from the tree rather\n * than from a pathname but produces the same kind of `RouteMatch` — every\n * `middleware.ts` above an intercepted page must run exactly as it does for\n * the canonical route.\n */\nexport function collectMiddlewareChain(chain: ManifestSegmentNode[]): MiddlewareFn[] {\n const middlewareChain: MiddlewareFn[] = [];\n for (const segment of chain) {\n if (segment.middleware) {\n const loader = segment.middleware.load;\n middlewareChain.push(async (ctx) => {\n const mod = (await loader()) as { default?: MiddlewareFn };\n if (mod.default) {\n return mod.default(ctx);\n }\n });\n }\n }\n return middlewareChain;\n}\n\n/**\n * Whether a matched chain renders as an API route: its leaf has a\n * `route.ts` and no `page.tsx`. The same test `renderRoute` dispatches on,\n * so every answer about a route's format — early hints, deny format, error\n * format, error reporting — agrees with what actually ran.\n */\nexport function isApiRouteChain(segments: readonly ManifestSegmentNode[]): boolean {\n const leaf = segments[segments.length - 1];\n return !!leaf?.route && !leaf.page;\n}\n\n/**\n * Whether a matched chain is a route.ts handler that opted out of the CSRF\n * check with `export const csrf = false`. Keyed on the same leaf\n * `isApiRouteChain` dispatches on, so the exemption can only ever apply to\n * the route.ts that will actually run — never to a page, and so never to a\n * server action. See design/08-forms-and-actions.md §\"Per-route exemption\".\n */\nexport function isCsrfExemptRoute(segments: readonly ManifestSegmentNode[]): boolean {\n return isApiRouteChain(segments) && segments[segments.length - 1]?.csrfExempt === true;\n}\n\n// ─── Metadata Route Matcher ─────────────────────────────────────────────\n\n/** Result of matching a metadata route. */\nexport interface MetadataRouteMatch {\n /** The metadata route type (sitemap, robots, icon, etc.) */\n type: MetadataRouteType;\n /** Content-Type header for the response. */\n contentType: string;\n /** The manifest file reference for the handler module. */\n file: ManifestFile;\n /** The matched segment (for context/params if needed). */\n segment: ManifestSegmentNode;\n /**\n * Whether this is a static file (e.g. sitemap.xml, favicon.ico, icon.png)\n * that should be served from disk rather than executed as a handler.\n */\n isStatic: boolean;\n /** Extracted segment params from dynamic segments in the URL prefix. */\n segmentParams: Record<string, string | string[]>;\n}\n\n// Reverse lookup: serve path (with extension) → convention base name\nconst SERVE_PATH_TO_CONVENTION = new Map<string, string>();\nfor (const [baseName, convention] of Object.entries(METADATA_ROUTE_CONVENTIONS)) {\n if (convention.serveExtension) {\n for (const ext of [...convention.staticExtensions, convention.serveExtension]) {\n SERVE_PATH_TO_CONVENTION.set(`${convention.servePath}.${ext}`, baseName);\n }\n } else {\n SERVE_PATH_TO_CONVENTION.set(convention.servePath, baseName);\n }\n}\n\n/**\n * Create a metadata route matcher from a manifest.\n *\n * Uses dynamic tree matching to resolve metadata routes, supporting\n * dynamic segments like /docs/[slug]/opengraph-image.\n *\n * See design/16-metadata.md §\"Metadata Routes\"\n */\nexport function createMetadataRouteMatcher(\n manifest: ManifestRoot\n): (pathname: string) => MetadataRouteMatch | null {\n return (pathname: string) => matchMetadataPathname(manifest.root, pathname);\n}\n\n/**\n * Match a pathname against metadata routes in the segment tree.\n *\n * Checks if the last URL part is a known metadata route serve path,\n * then walks the tree to find the segment that owns the route.\n */\nfunction matchMetadataPathname(\n root: ManifestSegmentNode,\n pathname: string\n): MetadataRouteMatch | null {\n const parts = pathname === '/' ? [] : pathname.slice(1).split('/');\n if (parts.length === 0) return null;\n\n const lastPart = parts[parts.length - 1];\n const baseName = SERVE_PATH_TO_CONVENTION.get(lastPart);\n if (!baseName) return null;\n\n const convention = METADATA_ROUTE_CONVENTIONS[baseName];\n if (!convention) return null;\n\n // The prefix parts identify which segment owns this metadata route.\n // For root-level routes (e.g. /sitemap.xml), prefix is empty → root segment.\n const prefixParts = parts.slice(0, -1);\n\n let segment: ManifestSegmentNode;\n let params: Record<string, string | string[]>;\n let file: ManifestFile | null = null;\n\n // Find the metadata file owner. For prefix matches, iterate all matching\n // segments in priority order — when competing bare-dynamic groups match\n // the same prefix, the first may not own the file. For root-level matches,\n // search all group children since findMetadataRouteInSegment may return\n // a file with the wrong extension when multiple groups own the same\n // convention with different static types.\n segment = root;\n params = {};\n const candidates = [...metadataOwnerCandidates(root, prefixParts)];\n\n // Two passes: direct owners first (node itself + groups), then\n // zero-segment optional-catch-all descent. A direct owner across any\n // candidate must beat a zero-segment catch-all on an earlier candidate.\n for (const allowCatchAll of [false, true]) {\n for (const candidate of candidates) {\n if (!convention.nestable && candidate.segment !== root) continue;\n const found = findMetadataRouteInSegment(\n candidate.segment,\n baseName,\n allowCatchAll && convention.nestable\n );\n if (!found) continue;\n if (convention.serveExtension) {\n const resolvedServePath = resolveServePathForFile(baseName, found.filePath);\n if (lastPart !== resolvedServePath) continue;\n }\n segment = candidate.segment;\n params = candidate.params;\n file = found;\n break;\n }\n if (file) break;\n }\n\n if (!file) return null;\n\n const ext = file.filePath.slice(file.filePath.lastIndexOf('.') + 1);\n const isStatic = isStaticMetadataExtension(baseName, ext);\n const contentType = isStatic\n ? resolveStaticContentType(convention.contentType, ext)\n : convention.contentType;\n\n return {\n type: convention.type,\n contentType,\n file,\n segment,\n isStatic,\n segmentParams: params,\n };\n}\n\n/**\n * Find a metadata route file in a segment, including children that match\n * zero URL segments at the segment's own path:\n *\n * - Group children are transparent — they don't add URL depth.\n * - Optional catch-all children ([[...slug]]) match zero segments, so\n * `app/docs/[[...path]]/icon.tsx` serves `/docs/icon`. The non-zero\n * case is handled by the tree walker (requireTerminal:false), but the\n * zero-segment case never reaches the walker — the parent node accepts\n * the fully-consumed prefix first, so the fallback lives here.\n *\n * Optional catch-all descent applies to NESTABLE conventions only. A\n * non-nestable file (robots, manifest, favicon) inside `[[...slug]]` is\n * not at the root — serving it there would bypass the root-only rule.\n * Group descent is unconditional: groups are transparent and a group\n * child of the root IS at the root.\n *\n * The segment's own metadata file wins over a zero-segment child's.\n */\nfunction findMetadataRouteInSegment(\n node: ManifestSegmentNode,\n baseName: string,\n nestable: boolean\n): ManifestFile | null {\n if (node.metadataRoutes?.[baseName]) {\n return node.metadataRoutes[baseName];\n }\n for (const child of node.children) {\n if (child.segmentType === 'group' || (nestable && child.segmentType === 'optional-catch-all')) {\n const found = findMetadataRouteInSegment(child, baseName, nestable);\n if (found) return found;\n }\n }\n return null;\n}\n\n/**\n * Yield candidate owner segments for a metadata route.\n *\n * For root-level metadata (empty prefix), yields the root and then each\n * transparent group child — so extension validation can skip a group that\n * owns the wrong static type and find the right one. For prefix matches,\n * delegates to `matchUrlPartsAll` which handles all segment kinds.\n */\nfunction* metadataOwnerCandidates(\n root: ManifestSegmentNode,\n prefixParts: string[]\n): Generator<{ segment: ManifestSegmentNode; params: Record<string, string | string[]> }> {\n if (prefixParts.length === 0) {\n yield { segment: root, params: {} };\n // Also yield each group child individually so the caller can validate\n // extensions per-group rather than taking the first file found.\n for (const child of root.children) {\n if (child.segmentType === 'group') {\n yield* groupDescendants(child);\n }\n }\n } else {\n for (const result of matchUrlPartsAll(root, prefixParts, { requireTerminal: false })) {\n yield { segment: result.chain[result.chain.length - 1], params: result.params };\n }\n }\n}\n\nfunction* groupDescendants(\n node: ManifestSegmentNode\n): Generator<{ segment: ManifestSegmentNode; params: Record<string, string | string[]> }> {\n yield { segment: node, params: {} };\n for (const child of node.children) {\n if (child.segmentType === 'group') {\n yield* groupDescendants(child);\n }\n }\n}\n","/**\n * Marker header on CSRF rejections.\n *\n * A CSRF rejection is a 403, the same status as an access-control denial.\n * The server stamps this header on every CSRF 403 so callers — the browser\n * action runtime, a same-origin `fetch` in user code, a curl session — can\n * tell the two apart without parsing the body. A cross-origin `fetch` cannot\n * read it: the rejection returns before proxy.ts, so no CORS headers are set\n * and the browser reports a network error instead. Shared so the server writer and the client\n * reader cannot drift.\n *\n * See design/08-forms-and-actions.md §\"CSRF Protection\" (TIM-1459).\n */\nexport const CSRF_REJECT_HEADER = 'X-Timber-Reject';\nexport const CSRF_REJECT_VALUE = 'csrf';\n","/**\n * CSRF protection — Fetch Metadata first, Origin as the fallback.\n *\n * CSRF needs a victim's browser to attach cookies, and browsers mark the\n * requests they send: `Sec-Fetch-Site` on HTTPS (and localhost) pages in\n * every current browser, `Origin` on cross-site POSTs everywhere else. So\n * the check trusts those two headers in that order, and lets a request\n * carrying neither through — a webhook, curl, or a server-to-server\n * `fetch`. The residual risk is browsers old enough to send neither on a\n * form POST (Firefox < 70, IE11); SameSite cookies are the defense there.\n * See design/08-forms-and-actions.md §\"CSRF Protection\".\n *\n * Prior art: Go's `net/http.CrossOriginProtection` (Go 1.25) and the OWASP\n * CSRF cheat sheet (Fetch Metadata as a primary defense).\n *\n * The per-route exemption (`export const csrf = false` in route.ts) is not\n * decided here: the caller owns route matching and applies it to a\n * rejection. Disable globally with csrf: false (not recommended).\n *\n * See design/08-forms-and-actions.md §\"CSRF Protection\"\n * See design/13-security.md §\"Security Testing Checklist\" #6\n */\n\nimport { logCsrfRejected } from './logger.ts';\nimport { CSRF_REJECT_HEADER, CSRF_REJECT_VALUE } from '../shared/csrf-reject.ts';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\nexport interface CsrfConfig {\n /**\n * Origins trusted in addition to the request's own. Canonical origins\n * only (`new URL(x).origin === x`); `validateConfig` enforces that.\n */\n allowedOrigins?: string[];\n /** Set to false to disable CSRF validation entirely. */\n csrf?: boolean;\n}\n\n/** Why a request failed the check — one value per rejection path. */\nexport type CsrfRejectReason =\n | 'cross-origin'\n | 'missing-host'\n | 'invalid-host'\n | 'invalid-origin'\n | 'origin-mismatch';\n\n/**\n * A failed check. `origin` is the request's Origin header and `fetchSite`\n * its Sec-Fetch-Site header (null when absent); `expected` is the origin(s)\n * `origin` was compared against: the `allowedOrigins` list, preceded on\n * `origin-mismatch` by the origin derived from the Host header. All three are for\n * the server log only — never the response.\n */\nexport interface CsrfRejection {\n ok: false;\n status: 403;\n reason: CsrfRejectReason;\n origin: string | null;\n fetchSite: string | null;\n expected: readonly string[];\n}\n\nexport type CsrfResult = { ok: true } | CsrfRejection;\n\n// ─── Constants ────────────────────────────────────────────────────────────\n\n/** HTTP methods that are considered safe (no mutation). */\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\n\n/**\n * `Sec-Fetch-Site` values that mean the browser itself vouches for the\n * request: `same-origin`, or `none` (user-initiated — typed URL, bookmark).\n * Every other value, including ones no browser sends, is not same-origin.\n * The header is forbidden to page scripts, so a page cannot forge it.\n */\nconst TRUSTED_FETCH_SITES = new Set(['same-origin', 'none']);\n\n// ─── Implementation ───────────────────────────────────────────────────────\n\n/**\n * Derive the request's scheme from trusted sources.\n *\n * Priority:\n * 1. X-Forwarded-Proto (set by reverse proxies / load balancers)\n * 2. Request URL protocol\n *\n * Falls back to 'https' (fail closed) if neither is available.\n */\nfunction deriveRequestScheme(req: Request): string {\n const forwarded = req.headers.get('X-Forwarded-Proto');\n if (forwarded) {\n const proto = forwarded.split(',')[0].trim().toLowerCase();\n if (proto === 'http' || proto === 'https') return proto;\n }\n\n try {\n return new URL(req.url).protocol.replace(':', '');\n } catch {\n return 'https';\n }\n}\n\n/**\n * Decide whether an unsafe-method request may proceed.\n *\n * In order:\n * 1. `Sec-Fetch-Site` is `same-origin` or `none` → allow.\n * 2. `Sec-Fetch-Site` has any other value → allow only if `Origin` is in\n * `allowedOrigins`.\n * 3. No `Sec-Fetch-Site`, `Origin` present (a plain-HTTP page, or an\n * older browser) → `Origin` must be in `allowedOrigins` or equal the\n * origin derived from the scheme and `Host`.\n * 4. Neither header → allow: not a browser, so no ambient cookies to abuse.\n *\n * Safe methods (GET, HEAD, OPTIONS) and `csrf: false` always pass.\n */\nexport function validateCsrf(req: Request, config: CsrfConfig): CsrfResult {\n if (SAFE_METHODS.has(req.method)) return { ok: true };\n if (config.csrf === false) return { ok: true };\n\n const fetchSite = req.headers.get('Sec-Fetch-Site');\n const origin = req.headers.get('Origin');\n const rejection = (reason: CsrfRejectReason, expected: readonly string[]): CsrfRejection => ({\n ok: false,\n status: 403,\n reason,\n origin,\n fetchSite,\n expected,\n });\n\n // Steps 1–2: the browser told us where the request came from.\n if (fetchSite !== null) {\n if (TRUSTED_FETCH_SITES.has(fetchSite)) return { ok: true };\n if (origin !== null && config.allowedOrigins?.includes(origin)) return { ok: true };\n return rejection('cross-origin', config.allowedOrigins ?? []);\n }\n\n // Step 4: no browser marker at all.\n if (origin === null) return { ok: true };\n\n // Step 3: Origin only. The request's own origin, or a listed one — the\n // same two sources step 2 trusts, so a same-origin POST from a page that\n // gets no Fetch Metadata (plain HTTP) never needs listing (Go's\n // CrossOriginProtection makes the same union).\n const allowed = config.allowedOrigins ?? [];\n if (allowed.includes(origin)) return { ok: true };\n\n const host = req.headers.get('Host');\n if (!host) return rejection('missing-host', allowed);\n\n // Compare full origins (scheme + host + port) using URL.origin for\n // canonical port normalization (e.g. https://x:443 → https://x).\n let originOrigin: string;\n try {\n originOrigin = new URL(origin).origin;\n } catch {\n return rejection('invalid-origin', allowed);\n }\n\n let expectedOrigin: string;\n try {\n expectedOrigin = new URL(`${deriveRequestScheme(req)}://${host}`).origin;\n } catch {\n return rejection('invalid-host', allowed);\n }\n\n return originOrigin === expectedOrigin\n ? { ok: true }\n : rejection('origin-mismatch', [expectedOrigin, ...allowed]);\n}\n\n// ─── Rejection Response ───────────────────────────────────────────────────\n\n/**\n * Longest request-derived value echoed into the server log. Origin, Host,\n * Sec-Fetch-Site, and the path are attacker-controlled; a request can carry\n * kilobytes in each, and every rejection writes a log line. Real values are\n * far shorter.\n */\nconst MAX_LOGGED_VALUE = 200;\n\nfunction clip(value: string): string {\n return value.length > MAX_LOGGED_VALUE ? `${value.slice(0, MAX_LOGGED_VALUE)}…` : value;\n}\n\n/**\n * Clip and quote a request-derived value for the log. JSON quoting escapes\n * quotes and control characters, so a crafted header cannot close the quote\n * and forge `key=value` fields or a second line.\n */\nfunction quote(value: string): string {\n return JSON.stringify(clip(value));\n}\n\nconst PROXY_HINT =\n 'If the app runs behind a proxy that rewrites Host or terminates TLS, forward the ' +\n 'original Host and X-Forwarded-Proto, or list the public origin in allowedOrigins ' +\n 'in timber.config.ts.';\n\nconst EXEMPTION_HINT =\n 'If this route.ts must accept cross-site browser requests (OIDC form_post, SAML, ' +\n '3-D Secure returns), add `export const csrf = false` to it.';\n\n/**\n * Browsers send `Origin: null` from opaque contexts: sandboxed iframes, a POST\n * redirected across origins, file: pages. Every such context shares the one\n * value — an attacker's `<iframe sandbox>` included — so config validation\n * refuses it in `allowedOrigins` and the hint points at the exemption instead.\n */\nconst OPAQUE_ORIGIN_DETAIL =\n 'origin \"null\" is an opaque origin (sandboxed iframe, a POST redirected across ' +\n 'origins, or a file: page). allowedOrigins cannot admit it: every opaque context ' +\n `sends \"null\", including an attacker's sandboxed iframe. ${EXEMPTION_HINT}`;\n\n/** One sentence per rejection path: what was observed, and what to change. */\nfunction describeRejection(r: CsrfRejection, host: string | null): string {\n const opaque = r.origin === 'null';\n const origin = quote(r.origin ?? '');\n const expected = r.expected.map(quote).join(', ');\n switch (r.reason) {\n // The opaque-origin note replaces only the reasons where the origin\n // itself is the fault. A null-origin request that fails for another\n // reason (no Host, a bad Host) keeps that reason's diagnosis and hint.\n case 'cross-origin': {\n if (opaque) return OPAQUE_ORIGIN_DETAIL;\n const from = r.origin === null ? 'with no Origin header' : `from origin ${origin}`;\n const allowed = r.expected.length > 0 ? ` and is not in allowedOrigins [${expected}]` : '';\n return (\n `Sec-Fetch-Site ${quote(r.fetchSite ?? '')} request ${from}: the browser reports ` +\n `it is not same-origin${allowed}. If this origin is legitimate, add it to ` +\n `allowedOrigins in timber.config.ts. ${EXEMPTION_HINT}`\n );\n }\n case 'missing-host':\n return `origin ${origin} could not be checked: request has no Host header. ${PROXY_HINT}`;\n case 'invalid-host':\n return `origin ${origin} could not be checked: Host header ${quote(host ?? '')} is not a valid host. ${PROXY_HINT}`;\n case 'invalid-origin':\n if (opaque) return OPAQUE_ORIGIN_DETAIL;\n return `Origin header ${origin} is not a valid origin.`;\n case 'origin-mismatch': {\n const [own, ...listed] = r.expected.map(quote);\n const list = listed.length > 0 ? ` or allowedOrigins [${listed.join(', ')}]` : '';\n return `origin ${origin} does not match the request origin ${own}${list}. ${PROXY_HINT}`;\n }\n }\n}\n\n/**\n * Turn a failed check into the response the client sees, and log why.\n *\n * The response is a 403 marked as a CSRF rejection (header + plain-text\n * body) so it cannot be mistaken for an access-control 403. It never\n * carries the observed or expected origins — `allowedOrigins` is server\n * configuration, and a Host-derived origin can be an internal hostname\n * behind a proxy. The server log gets the full diagnosis.\n */\nexport function csrfRejectionResponse(req: Request, rejection: CsrfRejection): Response {\n logCsrfRejected(describeRejection(rejection, req.headers.get('Host')), {\n method: req.method,\n path: clip(new URL(req.url).pathname),\n reason: rejection.reason,\n });\n return new Response('Forbidden: CSRF origin check failed\\n', {\n status: rejection.status,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n [CSRF_REJECT_HEADER]: CSRF_REJECT_VALUE,\n },\n });\n}\n","/**\n * Pipeline helpers — small utility functions used by `pipeline.ts` and\n * `pipeline-phases.ts`. Lifted out of `pipeline.ts` to keep that file\n * focused on the request handler entry point.\n *\n * Each helper is intentionally a free function with no closure capture, so\n * it can be unit-tested in isolation.\n *\n * See design/07-routing.md §\"Request Lifecycle\".\n */\n\nimport type { ProxyExport } from './proxy.ts';\nimport { getSetCookieHeaders } from './cookie-context.ts';\nimport {\n callOnRequestError,\n hasOnRequestError,\n type InstrumentationErrorContext,\n} from './instrumentation.ts';\nimport { getTraceId } from './tracing.ts';\nimport { requestContextAls } from './als-registry.ts';\nimport { RedirectSignal } from './primitives.ts';\nimport { isControlFlowSignal } from './signal-identity.ts';\nimport { logRenderError, logSkippedModule, swallow } from './logger.ts';\nimport { isAbortError } from './render-utils.ts';\nimport { loadModule, ModuleLoadError, type ManifestLoader } from './safe-load.ts';\nimport { getWaitUntil } from './waituntil-bridge.ts';\nimport { isApiRouteChain, isCsrfExemptRoute, type ManifestSegmentNode } from './route-matcher.ts';\nimport type { ProxyConfig, RouteMatcher } from './pipeline.ts';\nimport { csrfRejectionResponse, validateCsrf, type CsrfConfig } from './csrf.ts';\nimport type { PhaseName } from './pipeline-outcome.ts';\n\n// ─── Prototype-Pollution-Safe Sanitizer ────────────────────────────────────\n\n// ─── CSRF Gate ─────────────────────────────────────────────────────────────\n\n/**\n * The pipeline-boundary CSRF gate: the 403 to answer with, or null to go on.\n *\n * Runs on every request after canonicalization and before proxy.ts, so it\n * covers route.ts handlers and server actions alike, and no user code has\n * run when it decides. The per-route exemption is looked up only for a\n * request the check would reject — the common accepted request never pays\n * for a match. The lookup uses the pipeline's own matcher on the canonical\n * path, the same match `handleRequest` dispatches on, and reads a flag the\n * scanner took from route.ts source, so deciding it loads no module.\n *\n * A matcher that throws leaves the request unexempted: fail closed.\n *\n * See design/08-forms-and-actions.md §\"CSRF Protection\".\n */\nexport function csrfGate(\n req: Request,\n canonicalPath: string,\n csrf: CsrfConfig,\n matchRoute: RouteMatcher\n): Response | null {\n const result = validateCsrf(req, csrf);\n if (result.ok) return null;\n let exempt = false;\n try {\n const match = matchRoute(canonicalPath);\n exempt = match !== null && isCsrfExemptRoute(match.segments);\n } catch (err) {\n swallow(err, 'csrf gate: route match for exemption lookup threw');\n }\n return exempt ? null : csrfRejectionResponse(req, result);\n}\n\n// ─── Proxy Resolver ────────────────────────────────────────────────────────\n\n/**\n * Resolver closure produced once at pipeline construction. The lazy variant\n * still calls `loader()` per-request (HMR relies on re-importing), but the\n * choice of which branch to take is made once, not on every request.\n */\nexport type ProxyResolver = () => ProxyExport | Promise<ProxyExport>;\n\n/**\n * Build a proxy resolver closure from the declared source. Called exactly\n * once at `createPipeline` setup time, so the hot path sees only the branch\n * that corresponds to this pipeline's configured variant.\n *\n * Returns `null` when the app has no proxy.ts — the hot path short-circuits\n * around `runProxyPhase` entirely in that case.\n *\n * Accepts the sugar form (a bare `ProxyExport` — function or function array)\n * and normalises it to the static variant. Functions and arrays are\n * structurally distinct from the tagged `{ kind: 'lazy', loader }` object,\n * so discrimination is unambiguous.\n */\nexport function makeProxyResolver(\n proxy: ProxyConfig | ProxyExport | undefined\n): ProxyResolver | null {\n if (proxy === undefined) return null;\n // Sugar: a bare ProxyExport (function or function array) — treat as static.\n if (typeof proxy === 'function' || Array.isArray(proxy)) {\n const exp = proxy;\n return () => exp;\n }\n if (proxy.kind === 'static') {\n const exp = proxy.export;\n return () => exp;\n }\n const loader = proxy.loader;\n return async () => (await loader()).default;\n}\n\n// ─── Cookie / Header Helpers ───────────────────────────────────────────────\n\n/**\n * Apply all Set-Cookie headers from the cookie jar to a Headers object.\n * Each cookie gets its own Set-Cookie header per RFC 6265 §4.1.\n */\nexport function applyCookieJar(headers: Headers): void {\n for (const value of getSetCookieHeaders()) {\n headers.append('Set-Cookie', value);\n }\n}\n\n/**\n * Bring a bag the jar was already applied to up to date with the jar.\n *\n * `applied` is what `getSetCookieHeaders()` returned when the jar was\n * applied to `headers`. Values the jar no longer holds (a later write to the\n * same name replaced them) are removed, and values it gained are appended.\n * Every cookie then appears once, with its last write (design/29-cookies.md\n * §\"Last-Write-Wins for Same Name\"). `Set-Cookie` values that did not come\n * from the jar, such as a middleware appending to `ctx.headers` directly,\n * are left alone.\n */\nexport function syncCookieJar(headers: Headers, applied: readonly string[]): void {\n const current = getSetCookieHeaders();\n const stale = applied.filter((value) => !current.includes(value));\n const added = current.filter((value) => !applied.includes(value));\n if (stale.length === 0 && added.length === 0) return;\n\n const kept = headers.getSetCookie();\n for (const value of stale) {\n const index = kept.indexOf(value);\n if (index !== -1) kept.splice(index, 1);\n }\n headers.delete('Set-Cookie');\n for (const value of [...kept, ...added]) headers.append('Set-Cookie', value);\n}\n\n/**\n * Merge framework-managed response headers onto a terminal response without\n * overwriting headers the terminal response already set itself.\n */\nexport function mergeMissingHeaders(target: Headers, source: Headers): void {\n const existingKeys = new Set([...target.keys()].map((key) => key.toLowerCase()));\n for (const [key, value] of source.entries()) {\n if (!existingKeys.has(key.toLowerCase())) {\n target.append(key, value);\n }\n }\n}\n\n// ─── Mutable Response Cloning ──────────────────────────────────────────────\n\n/**\n * Clone a Response into a fresh one whose header bag is guaranteed mutable.\n *\n * `Response.redirect()` and some platform-level passthrough responses (notably\n * on Cloudflare Workers) return objects with frozen header bags. Calling\n * `.set()` or `.append()` on them throws `TypeError: immutable`, which the\n * pipeline can hit when it appends Set-Cookie or Server-Timing entries.\n *\n * The pipeline calls this at the producer sites where user-controlled\n * responses enter the framework — `outcomeToResponse` for all phase outcomes,\n * and `handleRequest` for metadata-route and auto-sitemap user handlers — so\n * downstream code can write headers without runtime feature-detection.\n *\n * The clone is unconditional. This is a deliberate trade: we avoid a\n * try/catch + thrown `TypeError` on every request (the previous probe-based\n * approach paid that cost on the hot path) and accept one cheap Response\n * rewrap at the framework boundary instead.\n */\nexport function cloneWithMutableHeaders(response: Response): Response {\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: new Headers(response.headers),\n });\n}\n\n// ─── Response Headers ──────────────────────────────────────────────────────\n\n/**\n * A fresh response header bag for a page the pipeline renders, seeded with\n * the default dynamic-page cache policy.\n *\n * Without a Cache-Control header, CDNs (particularly Cloudflare) may attempt\n * to buffer/process the response differently, causing intermittent\n * multi-second delays. This matches Next.js's default behavior. Every bag a\n * rendered page can be written onto starts here — a matched route, the\n * no-match 404, and a deny page for a proxy-phase signal — so none of them\n * leaves without a cache policy. Middleware and route handlers may replace it.\n */\nexport function dynamicResponseHeaders(): Headers {\n return new Headers({\n 'Cache-Control': 'private, no-cache, no-store, max-age=0, must-revalidate',\n });\n}\n\n// ─── Redirect Builder ──────────────────────────────────────────────────────\n\n/**\n * Build a redirect Response from a RedirectSignal.\n *\n * For a client navigation (an RSC payload request for a page), returns 204 +\n * X-Timber-Redirect so the client router can perform a soft SPA redirect. A\n * raw 302 would be turned into an opaque redirect by\n * fetch({redirect:'manual'}), crashing createFromFetch. See\n * design/19-client-navigation.md. The caller decides what counts as a\n * navigation: a route.ts match answers with a real 3xx whatever it accepts.\n */\nexport function buildRedirectResponse(\n signal: RedirectSignal,\n headers: Headers,\n navigation: boolean\n): Response {\n if (navigation) {\n headers.set('X-Timber-Redirect', signal.location);\n return new Response(null, { status: 204, headers });\n }\n headers.set('Location', signal.location);\n return new Response(null, { status: signal.status, headers });\n}\n\n// ─── Instrumentation ───────────────────────────────────────────────────────\n\n/**\n * Where an error was raised: a pipeline phase, a server action, or a\n * handler that answers outside the page pipeline — a metadata route or the\n * auto-generated sitemap — which reports like a route.ts handler.\n */\nexport type ErrorSource = PhaseName | 'action' | 'route';\n\n/**\n * Fire the user's onRequestError hook with request context.\n *\n * The one place a pipeline phase becomes the `phase` / `routeType` the hook\n * reports, so every caller agrees. A render-phase error on a route.ts match\n * is phase `'route'`, because the handler is what ran. Middleware reports\n * as `'handler'`, its public name.\n */\nexport async function fireOnRequestError(\n error: unknown,\n req: Request,\n source: ErrorSource,\n segments?: readonly ManifestSegmentNode[]\n): Promise<void> {\n // One rule for every caller (design/17 §\"Which errors reach it\"): outcomes\n // and aborts are not failures, and neither is anything a request raises\n // after its client left — a driver throwing \"connection closed\" is not a bug.\n if (!isReportableError(error) || req.signal?.aborted) return;\n if (isRepeatedLoadFailure(error)) return;\n await callHook(error, req, source, segments);\n}\n\n/**\n * Module evaluations whose failure was already reported. A module that fails\n * to evaluate rethrows the same error on every later import, and\n * `loadModule()` wraps each one in a new `ModuleLoadError` with that error\n * as its `cause`. One broken module is one bug until it changes, however many\n * loads trip over it in a request or across requests: the page's boundaries,\n * then the fallback page, then the next request. A WeakSet, so a module that\n * is re-evaluated (an HMR edit) gets a new cause and is reported again.\n */\nconst reportedLoadFailures = new WeakSet<object>();\n\n/**\n * The same for a module that threw a primitive (`throw 'broken'`), which a\n * WeakSet cannot hold. Keyed on the file and the value instead, so a module\n * re-broken after an edit with the very same value is not reported again.\n * It grows with the number of broken modules, not with requests.\n */\nconst reportedPrimitiveLoadFailures = new Set<string>();\n\nfunction isRepeatedLoadFailure(error: unknown): boolean {\n if (!(error instanceof ModuleLoadError)) return false;\n const cause: unknown = error.cause;\n if (typeof cause === 'object' && cause !== null) {\n if (reportedLoadFailures.has(cause)) return true;\n reportedLoadFailures.add(cause);\n return false;\n }\n const key = `${error.filePath}\\0${typeof cause}\\0${String(cause)}`;\n if (reportedPrimitiveLoadFailures.has(key)) return true;\n reportedPrimitiveLoadFailures.add(key);\n return false;\n}\n\n/**\n * Call the hook with request context, with no filtering. Only\n * `fireOnRequestError()` and background reporting call it: background work\n * runs after the response, so its request having aborted says nothing about\n * the failure.\n */\nasync function callHook(\n error: unknown,\n req: Request,\n source: ErrorSource,\n segments?: readonly ManifestSegmentNode[]\n): Promise<void> {\n if (!hasOnRequestError()) return;\n const url = new URL(req.url);\n const headersObj: Record<string, string> = {};\n req.headers.forEach((v, k) => {\n headersObj[k] = v;\n });\n const apiRoute = source === 'route' || (segments !== undefined && isApiRouteChain(segments));\n\n await callOnRequestError(\n error,\n { method: req.method, path: url.pathname, headers: headersObj },\n {\n phase: reportedPhase(source, apiRoute),\n routePath: url.pathname,\n routeType: source === 'action' ? 'action' : apiRoute ? 'route' : 'page',\n traceId: getTraceId(),\n }\n );\n}\n\n/**\n * Whether an error is a failure `onRequestError` should hear about.\n *\n * Control-flow signals are outcomes the code chose — a `deny()` picks the\n * page's status and data — and an abort is the client leaving. Callers answering\n * a live request also skip everything once `req.signal` has aborted: a\n * driver that throws \"connection closed\" after a disconnect is not a bug.\n */\nexport function isReportableError(error: unknown): boolean {\n return !isControlFlowSignal(error) && !isAbortError(error);\n}\n\n/**\n * Fire the hook without making the caller wait, for callers that cannot:\n * Flight's `onError` is synchronous, and background work has no caller.\n * The promise is registered with the request's `waitUntil` so platforms\n * that stop work when the response ends (Workers, Lambda) let the hook\n * finish. The hook's own failures are caught in `callOnRequestError()`.\n */\nfunction fireInBackground(report: Promise<void>): void {\n getWaitUntil()?.(\n report.catch((hookError: unknown) => swallow(hookError, 'onRequestError could not be called'))\n );\n}\n\n/**\n * Log and report a render error that was answered in place rather than\n * handed to the pipeline: a slot that degraded to its fallback, a Flight\n * error row, a fallback page that failed and fell back again. The pipeline\n * never sees these, so this is their one report. Errors that are not\n * reportable (`isReportableError()`), or that arrive after the request\n * aborted, are only logged.\n */\nexport function reportRenderError(\n error: unknown,\n req: Request,\n details: { errorId?: string; segments?: readonly ManifestSegmentNode[] } = {}\n): void {\n const { errorId, segments } = details;\n logRenderError({ method: req.method, path: new URL(req.url).pathname, error, errorId });\n fireInBackground(fireOnRequestError(error, req, 'render', segments));\n}\n\n/**\n * Load a module the render can do without — a status page, an error page,\n * `global-error.tsx`, a fallback page's layout — or report why it could not\n * load and return `null`, so the next tier answers instead of the failure\n * taking the page down. Every such load goes through here, whether it builds\n * a boundary for a normal render or a fallback page, so a broken module is\n * never skipped silently.\n *\n * Logged and reported once per broken file, not once per request: every\n * request that renders under a broken `error.tsx` loads it again (TIM-1458).\n * See `skippedFiles` for how \"the same failure\" is recognised. The first\n * request to hit a failure is the one that reports it; if that request has\n * already aborted, `fireOnRequestError()` drops the report and the failure is\n * only logged.\n *\n * Never rejects, including when a user logger throws: building an error\n * boundary must not itself throw (TIM-584), and the boundary walk does not\n * catch for it.\n */\nexport async function loadFallbackModule(\n file: ManifestLoader,\n req: Request,\n segments?: readonly ManifestSegmentNode[]\n): Promise<Record<string, unknown> | null> {\n let loadError: unknown;\n try {\n const mod = await loadModule(file);\n skippedFiles.delete(file.filePath);\n return mod;\n } catch (error) {\n loadError = error;\n }\n const failure = loadError instanceof Error ? loadError.message : String(loadError);\n if (skippedFiles.get(file.filePath) === failure) return null;\n skippedFiles.set(file.filePath, failure);\n try {\n logSkippedModule({\n method: req.method,\n path: new URL(req.url).pathname,\n file: file.filePath,\n error: loadError,\n });\n } catch (logError) {\n swallow(logError, 'logger.error threw while logging a skipped route file');\n }\n fireInBackground(fireOnRequestError(loadError, req, 'render', segments));\n return null;\n}\n\n/**\n * The failure each broken fallback file was last logged with, keyed by the\n * file and compared by message — not by error identity. In Vite dev a file\n * that fails to transform (a syntax error) is fetched again on every import,\n * and the module runner revives the server's error as a new `Error` each\n * time (`reviveInvokeError`), so identity never repeats; the message does.\n * Keyed by file so two files skipped over one broken import each log.\n *\n * A successful load clears the file's entry, so fixing a file and breaking\n * it again — even with the same message — logs again. An edit that changes\n * the error changes the message and logs too. It grows with the number of\n * broken files, not with requests.\n */\nconst skippedFiles = new Map<string, string>();\n\n/**\n * Run a `cache.component` stale-while-revalidate re-render as a singleflight\n * body, and log and report its failure once for the flight. The stale\n * payload already answered, so nothing else sees the failure.\n *\n * - **Once per flight.** A `.catch` on the flight's promise would run once\n * per request that joined it, so the report happens inside the body. A\n * body still running when the singleflight times out is reported then,\n * with the timeout error (the signal's reason), and its later rejection\n * is dropped.\n * - **Against the request whose stale read started it**, read from the\n * request context the work runs in. With no request (the build-time\n * capture store) it is only logged.\n * - **As phase `'render'`, route type `'page`.** A `cache.component` is a\n * server component, so the read that started this was a page render (a\n * revalidated page tree included). The request's own abort does not\n * suppress the report: the work runs after the response either way.\n */\nexport async function runBackgroundFlight(\n signal: AbortSignal,\n work: () => Promise<unknown>,\n log: (error: unknown) => void\n): Promise<void> {\n const failed = (error: unknown): void => {\n log(error);\n const request = requestContextAls.getStore()?.request;\n if (request && isReportableError(error)) fireInBackground(callHook(error, request, 'render'));\n };\n const onTimeout = (): void => failed(signal.reason);\n signal.addEventListener('abort', onTimeout, { once: true });\n try {\n await work();\n } catch (error) {\n if (!signal.aborted) failed(error);\n } finally {\n signal.removeEventListener('abort', onTimeout);\n }\n}\n\nfunction reportedPhase(\n source: ErrorSource,\n apiRoute: boolean\n): InstrumentationErrorContext['phase'] {\n switch (source) {\n case 'middleware':\n return 'handler';\n case 'render':\n return apiRoute ? 'route' : 'render';\n default:\n return source;\n }\n}\n","/**\n * Proxy runner — executes app/proxy.ts before route matching.\n *\n * Supports two forms:\n * - Function: (req, next) => Promise<Response>\n * - Array: middleware functions composed left-to-right\n *\n * See design/07-routing.md §\"proxy.ts — Global Middleware\"\n */\n\n/** Signature for a single proxy middleware function. */\nexport type ProxyFn = (req: Request, next: () => Promise<Response>) => Response | Promise<Response>;\n\n/** The proxy.ts default export — either a function or an array of functions. */\nexport type ProxyExport = ProxyFn | ProxyFn[];\n\n/**\n * Run the proxy pipeline.\n *\n * @param proxyExport - The default export from proxy.ts (function or array)\n * @param req - The incoming request\n * @param next - The continuation that proceeds to route matching and rendering\n * @returns The final response\n */\nexport async function runProxy(\n proxyExport: ProxyExport,\n req: Request,\n next: () => Promise<Response>\n): Promise<Response> {\n const fns = Array.isArray(proxyExport) ? proxyExport : [proxyExport];\n\n // Compose left-to-right: first item's next() calls the second, etc.\n // The last item's next() calls the original `next` (route matching + render).\n let i = fns.length;\n let composed = next;\n while (i--) {\n const fn = fns[i]!;\n const downstream = composed;\n composed = () => Promise.resolve(fn(req, downstream));\n }\n\n return composed();\n}\n","/**\n * Middleware runner — executes a route's middleware.ts chain before rendering.\n *\n * All middleware.ts files in the segment chain run, root to leaf (top-down).\n * The first middleware that returns a Response short-circuits the chain.\n * There is no next() — each middleware is independent.\n *\n * See design/07-routing.md §\"middleware.ts\"\n */\n\nimport type { MiddlewareContext } from './types.ts';\n\n/** Signature of a middleware.ts default export. */\nexport type MiddlewareFn = (ctx: MiddlewareContext) => Response | void | Promise<Response | void>;\n\n/**\n * Run a route's middleware function.\n *\n * @param middlewareFn - The default export from the route's middleware.ts\n * @param ctx - The middleware context (req, params, headers, requestHeaders, searchParams)\n * @returns A Response if middleware short-circuited, or undefined to continue\n */\nexport async function runMiddleware(\n middlewareFn: MiddlewareFn,\n ctx: MiddlewareContext\n): Promise<Response | undefined> {\n const result = await middlewareFn(ctx);\n if (result instanceof Response) {\n return result;\n }\n return undefined;\n}\n\n/**\n * Run all middleware functions in the segment chain, root to leaf.\n *\n * Execution is top-down: root middleware runs first, leaf middleware runs last.\n * All middleware share the same MiddlewareContext — a parent that sets\n * ctx.requestHeaders makes it visible to child middleware and downstream components.\n *\n * Short-circuits on the first middleware that returns a Response.\n * Remaining middleware in the chain do not execute.\n *\n * @param chain - Middleware functions ordered root-to-leaf\n * @param ctx - Shared middleware context\n * @returns A Response if any middleware short-circuited, or undefined to continue\n */\nexport async function runMiddlewareChain(\n chain: MiddlewareFn[],\n ctx: MiddlewareContext\n): Promise<Response | undefined> {\n for (const fn of chain) {\n const result = await fn(ctx);\n if (result instanceof Response) {\n return result;\n }\n }\n return undefined;\n}\n","/**\n * CSP nonce — per-request, generated on demand.\n *\n * timber emits several inline `<script>` tags per HTML response — React's\n * bootstrap script and Fizz runtime, the Flight init/chunk scripts, the\n * segment-tree script, and the post-flush noindex script. Under a strict\n * `Content-Security-Policy` (`script-src 'nonce-…' 'strict-dynamic'`) every\n * one of them needs the request's nonce or the browser refuses to run it.\n *\n * The app opts in by reading `ctx.nonce` in `middleware.ts` and putting it\n * in the CSP header it sets through `ctx.headers`. The first read generates\n * the value and stores it on the request context; the render pipeline reads\n * it back with `getCspNonce()` and stamps it on every inline script. A\n * request whose middleware never reads `ctx.nonce` has no nonce, and its\n * markup is byte-identical to a render without this feature. timber does\n * not parse the CSP header — the app owns the policy, timber owns the\n * markup, and `ctx.nonce` is the one value both are built from.\n *\n * `proxy.ts` cannot participate: it only sees the finished response from\n * `next()`, after the markup exists.\n *\n * See design/13-security.md §\"Content Security Policy\" (TIM-1414).\n */\n\nimport { requestContextAls } from './als-registry.ts';\n\n/**\n * Generate a CSP nonce: 128 random bits, base64. Matches CSP's\n * `base64-value` grammar, so it is valid in the header verbatim and safe\n * inside a double-quoted HTML attribute without escaping.\n */\nfunction generateNonce(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n let binary = '';\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary);\n}\n\n/**\n * The request's CSP nonce, creating it on first call. Backs the\n * `ctx.nonce` getter on `MiddlewareContext`. Outside a request context\n * (tests, build-time rendering) a fresh value is returned but not\n * retained, since there is no request for it to belong to.\n */\nexport function requestCspNonce(): string {\n const store = requestContextAls.getStore();\n if (!store) return generateNonce();\n store.cspNonce ??= generateNonce();\n return store.cspNonce;\n}\n\n/**\n * The request's CSP nonce if middleware asked for one, else `undefined` —\n * in which case the pipeline emits bare `<script>` tags.\n */\nexport function getCspNonce(): string | undefined {\n return requestContextAls.getStore()?.cspNonce;\n}\n","/**\n * Segment param coercion — runs the app/schema.ts codecs over the raw\n * matcher output before middleware and rendering.\n *\n * Lifted out of `pipeline-phases.ts` (TIM-853) so the coercer can be\n * imported directly by other entry points (the action-dispatch wrapper,\n * the revalidation renderer in `rsc-entry/index.ts`) without pulling\n * the entire pipeline phase module along with it.\n *\n * The function throws `ParamCoercionError` (defined below) on any codec\n * failure; the pipeline catches that and dispatches to the 404 page.\n * See design/07-routing.md §\"Where Coercion Runs\".\n */\n\nimport type { Codec } from '../codec.ts';\nimport type { SegmentType } from '../routing/types.ts';\nimport { effectiveUrlSegment } from '../routing/segment-classify.ts';\nimport { toBracketKey } from '../params/resolve-schema.ts';\nimport type { RouteMatch } from './pipeline.ts';\nimport { normalizeParamValue, type CoercedParams } from '../shared/param-value.ts';\n/**\n * Thrown when an app/schema.ts segment-param codec's parse() fails.\n * The pipeline catches this and responds with 404.\n */\nexport class ParamCoercionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ParamCoercionError';\n }\n}\nimport { isDebug } from './debug.ts';\n\n// ---------------------------------------------------------------------------\n// Module-level global codec store (TIM-931)\n// ---------------------------------------------------------------------------\n\n/** Global schema codecs, set once at startup from virtual:timber-schema. */\nlet _globalCodecs: Record<string, Codec<unknown>> | null = null;\n\n/**\n * Register the global schema codecs. Called once from the RSC entry\n * at server startup when app/schema.ts provides segment param codecs.\n * @internal\n */\nexport function setGlobalSchemaCodecs(codecs: Record<string, Codec<unknown>> | null): void {\n _globalCodecs = codecs;\n}\n\n/**\n * Coerce raw slot params through global schema codecs.\n *\n * Each slot segment that has a paramName is looked up in the global codec\n * map by its bracket key (e.g. '[...year]' for catch-all). If a codec\n * exists, the raw value is parsed through it. If no codec exists or no\n * global codecs are registered, the raw value passes through unchanged.\n *\n * Segments are read through `effectiveUrlSegment` because an intercepting\n * node's own `segmentType` is `'intercepting'` and its `paramName` is unset\n * — the param it binds lives in the intercepted name (`(.)[id]` → `[id]`).\n * The slot resolver matches through the same helper, so the key a param is\n * coerced under is always the key it was matched under (TIM-1281).\n *\n * Unlike main route coercion, this does NOT throw ParamCoercionError on\n * failure — slots degrade gracefully. A failed coercion logs a warning\n * in dev mode and keeps the raw value.\n *\n * @internal — framework use only\n */\nexport function coerceSlotParams(\n slotChain: Array<{\n segmentName: string;\n segmentType: SegmentType;\n paramName?: string;\n interceptedSegmentName?: string;\n }>,\n rawParams: Record<string, string | string[]>\n): CoercedParams {\n const globalCodecs = _globalCodecs;\n if (!globalCodecs) return rawParams;\n\n const result: CoercedParams = Object.create(null);\n for (const key of Object.keys(rawParams)) {\n result[key] = rawParams[key];\n }\n\n for (const node of slotChain) {\n const segment = effectiveUrlSegment(node);\n if (!segment.paramName) continue;\n const bracketKey = toBracketKey(segment.segmentType, segment.paramName);\n const codec = globalCodecs[bracketKey];\n if (!codec) continue;\n\n const key = segment.paramName;\n if (!(key in result)) continue;\n\n let parsed: unknown;\n try {\n parsed = codec.parse(result[key] as string | string[]);\n } catch (err) {\n // Slot param coercion failures are non-fatal — keep the raw value.\n // The main route already validated the URL; the slot just interprets\n // the same parts differently.\n if (isDebug()) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[timber] Slot param coercion failed for \"${key}\" (codec: ${bracketKey})\\n` +\n ` Error: ${message}\\n` +\n ` Raw value: ${JSON.stringify(result[key])}\\n` +\n ` Keeping raw value.`\n );\n }\n continue;\n }\n result[key] = normalizeParamValue(parsed, key);\n }\n\n return result;\n}\n\n/**\n * Coerce the matched route's raw segment params and return the result.\n *\n * Reads `match.rawSegmentParams` and never writes to `match`: the caller\n * decides where the coerced params go. Reading the raw record makes the call\n * repeatable — coercing a match twice runs every codec on the URL value both\n * times, never on its own output.\n *\n * Codecs come from `app/schema.ts` and nowhere else (TIM-1342 completed\n * design/41-global-params.md migration step 9). A route with no schema, or\n * a param the schema does not declare, keeps its raw string — which is the\n * honest type for an uninterpreted URL segment.\n *\n * Throws ParamCoercionError if any codec fails (→ 404).\n *\n * This runs BEFORE middleware, so ctx.segmentParams is already typed.\n * See design/07-routing.md §\"Where Coercion Runs\"\n * See design/41-global-params.md §\"Pipeline Integration\"\n *\n * Stays `async` with nothing to await: it is injected as a\n * `CoerceSegmentParamsFn` into the revalidation renderer, which awaits\n * it. Making it synchronous would\n * change that contract and remove a microtask boundary the pipeline's\n * ordering has always had, for no gain.\n */\n// eslint-disable-next-line @typescript-eslint/require-await -- see above\nexport async function coerceSegmentParams(match: RouteMatch): Promise<CoercedParams> {\n const globalCodecs = _globalCodecs;\n // Always a null-prototype record, whether or not any segment has a codec.\n const mergeTarget: CoercedParams = Object.create(null);\n for (const key of Object.keys(match.rawSegmentParams)) {\n if (key !== '__proto__') {\n mergeTarget[key] = match.rawSegmentParams[key];\n }\n }\n\n // TIM-931/TIM-936: When a global schema is available, use it for coercion\n // instead of per-segment params.ts files. The global codec map is keyed\n // by bracket name (e.g. '[id]', '[...slug]') to avoid collisions between\n // distinct segment types that share a param name.\n if (globalCodecs) {\n for (const node of match.segments) {\n // Read through `effectiveUrlSegment` for the same reason\n // `coerceSlotParams` does: an intercepting node's own `segmentType` is\n // 'intercepting' and its `paramName` is unset — the param it binds lives\n // in the intercepted name (`(.)[id]` → `[id]`). Until TIM-1280 an\n // intercepting node could only appear in a *slot* chain, so only that\n // path needed it; a children-path interception puts one in the main\n // chain, and reading the node directly would silently skip coercion for\n // exactly the param the intercepting directory declares — so the swapped\n // route and the canonical one would disagree about the param's type.\n const segment = effectiveUrlSegment(node);\n if (!segment.paramName) continue;\n const bracketKey = toBracketKey(segment.segmentType, segment.paramName);\n const codec = globalCodecs[bracketKey];\n if (!codec) continue; // no codec in schema → keep raw string\n\n const key = segment.paramName;\n if (!(key in mergeTarget)) continue;\n let parsed: unknown;\n try {\n parsed = codec.parse(mergeTarget[key] as string | string[]);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (isDebug()) {\n console.warn(\n `[timber] Global schema codec rejected value for param \"${key}\"\\n` +\n ` Error: ${message}\\n` +\n ` Raw value: ${JSON.stringify(mergeTarget[key])}\\n` +\n ` Hint: check the codec in app/schema.ts for key '${bracketKey}'.`\n );\n }\n throw new ParamCoercionError(message);\n }\n // Outside the catch: a codec that rejects a URL value is a 404, a codec\n // that returns an unrepresentable one is a bug in the app. Normalizing\n // inside would report the second as the first.\n mergeTarget[key] = normalizeParamValue(parsed, key);\n }\n }\n return mergeTarget;\n}\n","/**\n * Metadata route helpers for the request pipeline.\n *\n * Handles serving static metadata files and serializing sitemap responses.\n * Extracted from pipeline.ts to keep files under 500 lines.\n *\n * See design/16-metadata.md §\"Metadata Routes\"\n */\n\nimport { readFile } from 'node:fs/promises';\n\n/**\n * Content types that are text-based and should include charset=utf-8.\n * Binary formats (images) should not include charset.\n */\nconst TEXT_CONTENT_TYPES = new Set([\n 'application/xml',\n 'text/plain',\n 'application/json',\n 'application/manifest+json',\n 'image/svg+xml',\n]);\n\n/**\n * Serve a static metadata file by reading it from disk.\n *\n * Static metadata route files (.xml, .txt, .json, .png, .ico, .svg, etc.)\n * are served as-is with the appropriate Content-Type header.\n * Text files include charset=utf-8; binary files do not.\n *\n * See design/16-metadata.md §\"Metadata Routes\"\n */\nexport async function serveStaticMetadataFile(\n metaMatch: import('./route-matcher.ts').MetadataRouteMatch\n): Promise<Response> {\n const { contentType, file } = metaMatch;\n const isText = TEXT_CONTENT_TYPES.has(contentType);\n\n const body = await readFile(file.filePath);\n\n const headers: Record<string, string> = {\n 'Content-Type': isText ? `${contentType}; charset=utf-8` : contentType,\n 'Content-Length': String(body.byteLength),\n 'Cache-Control': 'public, max-age=14400, must-revalidate',\n };\n\n return new Response(body, { status: 200, headers });\n}\n\n/**\n * Serialize a sitemap array to XML.\n * Follows the sitemap.org protocol: https://www.sitemaps.org/protocol.html\n */\nexport function serializeSitemap(\n entries: Array<{\n url: string;\n lastModified?: string | Date;\n changeFrequency?: string;\n priority?: number;\n }>\n): string {\n const urls = entries\n .map((e) => {\n let xml = ` <url>\\n <loc>${escapeXml(e.url)}</loc>`;\n if (e.lastModified) {\n const date = e.lastModified instanceof Date ? e.lastModified.toISOString() : e.lastModified;\n xml += `\\n <lastmod>${escapeXml(date)}</lastmod>`;\n }\n if (e.changeFrequency) {\n xml += `\\n <changefreq>${escapeXml(e.changeFrequency)}</changefreq>`;\n }\n if (e.priority !== undefined) {\n xml += `\\n <priority>${e.priority}</priority>`;\n }\n xml += '\\n </url>';\n return xml;\n })\n .join('\\n');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${urls}\\n</urlset>`;\n}\n\n/**\n * Serialize a sitemap index (list of sub-sitemap URLs) to XML.\n * Used for pagination when the total URL count exceeds 50,000.\n * Follows the sitemap.org protocol: https://www.sitemaps.org/protocol.html\n */\nexport function serializeSitemapIndex(sitemapUrls: string[]): string {\n const sitemaps = sitemapUrls\n .map((url) => ` <sitemap>\\n <loc>${escapeXml(url)}</loc>\\n </sitemap>`)\n .join('\\n');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${sitemaps}\\n</sitemapindex>`;\n}\n\n/** Escape special XML characters. */\nexport function escapeXml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n","/**\n * State Tree Diffing — Server-side parsing and diffing of X-Timber-State-Tree.\n *\n * The client sends X-Timber-State-Tree on navigation requests, listing\n * the sync segments it has cached. The server diffs this against the\n * target route's segments to skip re-rendering unchanged sync layouts.\n *\n * This is a performance optimization only — NOT a security boundary.\n * All access.ts files run regardless of the state tree content.\n * A fabricated state tree can only cause extra rendering work or stale\n * layouts — never auth bypass.\n *\n * See design/19-client-navigation.md §\"X-Timber-State-Tree Header\"\n * See design/13-security.md §\"State tree manipulation\"\n */\n\nimport { swallow } from './logger.ts';\n\n// ─── State Tree Parsing ──────────────────────────────────────────\n\n/** Parsed client state tree with segment paths and optional slot paths. */\nexport interface ClientStateTree extends Set<string> {\n slots?: Set<string> | null;\n /**\n * `app/` directory paths of the segments currently mounted on the client.\n * Read only by interception scoping — never by the skip decisions.\n * See design/07-routing.md §\"Intercepting Routes\" (TIM-1282).\n */\n treePaths?: Set<string> | null;\n}\n\n/**\n * Parse the X-Timber-State-Tree header from a request.\n *\n * Returns a Set of segment paths the client has cached (with an\n * additional `slots` property for cached slot paths), or null if\n * the header is missing, malformed, or empty. Parsing happens before\n * renderToReadableStream — not inside the React render pass.\n *\n * @returns ClientStateTree with segments and slots, or null if no valid state tree\n */\nexport function parseClientStateTree(req: Request): ClientStateTree | null {\n const header = req.headers.get('X-Timber-State-Tree');\n if (!header) return null;\n\n try {\n const parsed = JSON.parse(header) as {\n segments?: unknown;\n slots?: unknown;\n treePaths?: unknown;\n };\n const hasSegments = Array.isArray(parsed.segments) && parsed.segments.length > 0;\n const hasSlots = Array.isArray(parsed.slots) && parsed.slots.length > 0;\n const hasTreePaths = Array.isArray(parsed.treePaths) && parsed.treePaths.length > 0;\n if (!hasSegments && !hasSlots && !hasTreePaths) {\n return null;\n }\n const result = new Set(hasSegments ? (parsed.segments as string[]) : []) as ClientStateTree;\n result.slots = hasSlots ? new Set(parsed.slots as string[]) : null;\n result.treePaths = hasTreePaths ? new Set(parsed.treePaths as string[]) : null;\n return result;\n } catch (err) {\n swallow(err, 'malformed X-Timber-State-Tree header');\n return null;\n }\n}\n\n/**\n * Determine whether a segment's layout rendering can be skipped.\n *\n * A segment is skipped when ALL of the following are true:\n * 1. The client sent a state tree (clientSegments is non-null)\n * 2. The client has this segment cached (clientSegments contains urlPath)\n * 3. The segment has a layout (otherwise nothing to skip)\n * 4. The layout is sync (not an async function — async layouts may depend\n * on per-request data and must always re-render)\n * 5. The segment is NOT the leaf (pages are never cached across navigations)\n *\n * Additional constraints enforced by the caller (buildRouteElement):\n * - Must have a rendered layout below (so SegmentOutlet has content to show)\n * - Skipped segments must form a contiguous prefix from root\n *\n * Access.ts still runs for skipped segments — this is enforced by the caller\n * which wraps with AccessGate regardless of skip status.\n *\n * @param segmentKey - The segment's state-tree key from computeSegmentKeys()\n * @param layoutComponent - The loaded layout component function\n * @param isLeaf - Whether this is the leaf segment (page segment)\n * @param clientSegments - Set of paths from X-Timber-State-Tree, or null\n */\nexport function shouldSkipSegment(\n segmentKey: string,\n layoutComponent: ((...args: unknown[]) => unknown) | undefined,\n isLeaf: boolean,\n clientSegments: Set<string> | null\n): boolean {\n if (!clientSegments) return false;\n if (!clientSegments.has(segmentKey)) return false;\n if (!layoutComponent) return false;\n if (isLeaf) return false;\n\n // Pre-render guard: async layouts may depend on per-request data.\n // Taint tracking (runInTaintScope) handles the post-render client-side\n // caching decision via X-Timber-Segments. This server-side check remains\n // conservative because taint results aren't available at element-build time.\n if (layoutComponent.constructor.name === 'AsyncFunction') return false;\n\n return true;\n}\n\n// ─── Slot Skip Decision ─────────────────────────────────────────\n\n/**\n * Determine whether a parallel route slot can be skipped.\n *\n * A slot is skipped when the destination content key — computed from the\n * owning segment's URL parts, the slot name, the matched entry file, and\n * the slot's extracted params — is in the set of keys the client advertised.\n *\n * This replaced URL-based departing/destination diffing in TIM-1370.\n * The previous approach reconstructed the client's state by re-matching a\n * departing URL against each slot's sub-tree, which was a recurring bug\n * source because the reconstruction could drift from the client's actual\n * mounted state. The key-based approach is a single set-membership check.\n *\n * This is a performance optimization only, NOT a security boundary.\n * Slot access.ts always runs via SlotAccessGate regardless.\n */\nexport function shouldSkipSlot(contentKey: string, clientSlotKeys: Set<string> | null): boolean {\n if (!clientSlotKeys) return false;\n return clientSlotKeys.has(contentKey);\n}\n","/**\n * Interception route matching for the request pipeline.\n *\n * Matches target URLs against interception rewrites to support the\n * modal route pattern (soft navigation intercepts).\n *\n * Extracted from pipeline.ts to keep files under 500 lines.\n *\n * See design/07-routing.md §\"Intercepting Routes\"\n */\n\nimport { classifyUrlSegment } from '../routing/segment-classify.ts';\nimport type { InterceptionRewrite } from '../routing/interception.ts';\nimport { computeSegmentTreePaths } from '../routing/segment-keys.ts';\nimport { isRscRequest } from '../shared/rsc-media-type.ts';\nimport { canonicalize } from './canonicalize.ts';\nimport { parseClientStateTree } from './state-tree-diff.ts';\nimport type { InterceptionContext, PipelineConfig, RouteMatch } from './pipeline.ts';\n\n/**\n * Check if an intercepting route applies for this soft navigation.\n *\n * Two conditions must hold:\n *\n * 1. The **target** pathname matches the rewrite's intercepted pattern.\n * 2. The **source** route — the page the user is navigating FROM, per the\n * validated X-Timber-URL header — renders the segment that owns the slot\n * holding the intercepting page (`interceptingScope`). Only then does that\n * slot exist in the rendered tree, so only then can the intercepting page\n * render.\n *\n * Condition 2 replaced a URL-prefix check (TIM-1279). A prefix cannot\n * distinguish a route-group-scoped interception from a genuinely root-level\n * one — route groups are invisible in `urlPath`, so both collapse to \"/\" and\n * the guard degenerates to always-true. Tree paths carry group identity.\n * The scope check also subsumes the old segment-boundary rule: a source route\n * under /feed-private has no \"/feed\" in its chain.\n *\n * A third condition lives with the caller, which owns route matching, and it\n * applies to the `'slot'` shape only: the route produced by re-matching\n * `interceptingPrefix` must pass through the scope too. Conditions 1–2 are\n * about the route the user is leaving; the slot has to exist in the tree that\n * actually renders. The `'children'` shape resolves its owner from the scope\n * directly rather than from a pathname, so it satisfies that by construction.\n *\n * `resolveSourceScopes` is a thunk so its inputs are only resolved when some\n * rewrite's pattern actually matches the target — the common case is no match\n * at all. It returns the two client-supplied answers to \"what is on screen?\"\n * as **separate sets, most authoritative first**: the tree paths the client\n * says it has mounted, then those of the route the departing URL matches. It\n * returns null only when neither yields anything, which is not a soft\n * navigation this can reason about.\n *\n * They are two sets rather than one union because ranking needs a chain\n * (TIM-1318). Each channel describes a single rendered chain, so within one the\n * scopes are strictly nested and the deepest is the innermost owner. Unioned\n * they are not: once a modal is open the address bar holds the *intercepted*\n * URL, so the second channel describes the canonical branch — possibly an\n * exclusive route group the client never mounted — and a deeper scope from\n * there would outrank the owner actually on screen. Trying the mounted channel\n * to exhaustion first keeps the fallback the union was there to provide while\n * ranking only within one chain.\n *\n * Returns the winning build-time rewrite, or null. Only build-time values ever\n * reach the renderer: the client-supplied header selects a rewrite but never\n * becomes a rendered route or pathname.\n *\n * The **first** matching rewrite wins, and the caller does not fall back to the\n * next one when the winner fails to resolve. That is deliberate and pre-dates\n * the two shapes: a rewrite that matched the target and the scope described the\n * author's intent, and quietly rendering some other author's interception\n * instead would be harder to explain than rendering the canonical route.\n *\n * \"First\" is meaningful because the list arrives **deepest scope first** —\n * `collectInterceptionRewrites` sorts it at build time, so the deepest owner a\n * single chain passes through wins and nothing here has to score (TIM-1318).\n * Tree-walk order used to decide it, which meant renaming a route group flipped\n * which modal opened. The precondition is a property of the manifest this reads\n * rather than something it can re-derive, so it is asserted at its source:\n * `tests/interception.test.ts` §\"rewrite order is decided by scope depth\".\n */\nexport function findInterceptionMatch(\n targetPathname: string,\n resolveSourceScopes: () => ReadonlySet<string>[] | null,\n rewrites: InterceptionRewrite[]\n): InterceptionRewrite | null {\n // Dynamic segments in the pattern match any single URL segment. Collected up\n // front rather than inside the channel loop so a pattern is matched once\n // however many channels are tried — and the common case, no rewrite matching\n // at all, costs exactly the same scan it always did and resolves no scope.\n const candidates = rewrites.filter((rewrite) =>\n pathnameMatchesPattern(targetPathname, rewrite.interceptedPattern)\n );\n if (candidates.length === 0) return null;\n\n // Nothing at all is known about the source tree — no scope can contain\n // anything, so no rewrite can apply.\n const scopes = resolveSourceScopes();\n if (!scopes) return null;\n\n // `candidates` is deepest scope first (`collectInterceptionRewrites`), so\n // within one channel the first hit is the innermost owner that channel\n // reports. Channels are tried in order, so a scope the client says it has\n // mounted always beats one only the address bar implies.\n for (const scope of scopes) {\n for (const rewrite of candidates) {\n if (scope.has(rewrite.interceptingScope)) return rewrite;\n }\n }\n return null;\n}\n\n/**\n * Check if a pathname matches a URL pattern with dynamic segments.\n *\n * Supports [param] (single segment) and [...param] (one or more segments).\n * Static segments must match exactly.\n */\nexport function pathnameMatchesPattern(pathname: string, pattern: string): boolean {\n const pathParts = pathname === '/' ? [] : pathname.slice(1).split('/');\n const patternParts = pattern === '/' ? [] : pattern.slice(1).split('/');\n\n let pi = 0;\n for (let i = 0; i < patternParts.length; i++) {\n const seg = classifyUrlSegment(patternParts[i]);\n\n switch (seg.kind) {\n case 'catch-all':\n return pi < pathParts.length;\n case 'optional-catch-all':\n return true;\n case 'dynamic': {\n if (pi >= pathParts.length) return false;\n const prefix = seg.prefix ?? '';\n const suffix = seg.suffix ?? '';\n const pathPart = pathParts[pi];\n if (prefix || suffix) {\n if (\n pathPart.length <= prefix.length + suffix.length ||\n (prefix && !pathPart.startsWith(prefix)) ||\n (suffix && !pathPart.endsWith(suffix))\n ) {\n return false;\n }\n }\n pi++;\n continue;\n }\n case 'static':\n if (pi >= pathParts.length || pathParts[pi] !== seg.value) return false;\n pi++;\n continue;\n }\n }\n\n return pi === pathParts.length;\n}\n\n// ─── Pipeline Resolution ──────────────────────────────────────────────────\n\n/**\n * Resolve which route renders a soft navigation that an intercepting route\n * may claim. Returns the canonical match unchanged when no rewrite applies.\n *\n * Runs during route setup, so anything it throws is a `'setup'` outcome.\n */\nexport function resolveInterceptedRoute(\n config: PipelineConfig,\n req: Request,\n canonicalPathname: string,\n canonicalMatch: RouteMatch | null\n): { match: RouteMatch | null; interception?: InterceptionContext } {\n const stripTrailingSlash = config.stripTrailingSlash ?? true;\n let match = canonicalMatch;\n let interception: InterceptionContext | undefined;\n\n // Stage 2a: Intercepting route resolution (modal pattern).\n // Only honored on RSC client-navigation requests (Accept: text/x-component)\n // to prevent spoofing from plain HTML navigations or raw HTTP clients.\n // The header value must be a valid relative pathname — reject schemes,\n // authority, and control characters. Canonicalize before matching.\n if (isRscRequest(req) && config.interceptionRewrites?.length) {\n const rawSourceUrl = req.headers.get('X-Timber-URL');\n const validatedSourceUrl = rawSourceUrl\n ? validateInterceptionHeader(rawSourceUrl, stripTrailingSlash)\n : null;\n if (validatedSourceUrl) {\n // The scope of an interception is the segment that owns the intercepting\n // slot, so the guard asks whether the route the user is LEAVING renders\n // that segment. Two independent answers to \"what is on screen?\", tried in\n // order — deferred behind a thunk so neither runs unless a rewrite's\n // target pattern matches.\n //\n // 1. What the client says it has mounted (X-Timber-State-Tree\n // `treePaths`). Authoritative about tree shape and nothing else.\n // 2. What re-matching X-Timber-URL implies. Correct while the address bar\n // still holds the source page, which stops being true the moment a\n // modal is open — the address is then the *intercepted* URL and\n // re-matching it resolves through whichever group owns the canonical\n // page (TIM-1282).\n //\n // Neither is trusted: both are client-supplied, and satisfying the scope\n // only selects which build-time rewrite applies. The rendered pathname is\n // always the rewrite's own `interceptingPrefix`, the server re-derives the\n // rendered chain from it below, and every access.ts runs regardless.\n //\n // They are handed over as two sets in that order rather than one union:\n // each describes a single rendered chain, and only within one chain does\n // \"the deepest scope\" name the innermost owner (TIM-1318). Unioned, a\n // deeper scope from the address-implied canonical branch — which after\n // (2) may be a route group the client never mounted — would outrank the\n // owner actually on screen.\n const resolveSourceScopes = () => {\n const mounted = new Set(parseClientStateTree(req)?.treePaths ?? []);\n const sourceRoute = config.matchRoute(validatedSourceUrl);\n const addressed = new Set(sourceRoute ? computeSegmentTreePaths(sourceRoute.segments) : []);\n const scopes = [mounted, addressed].filter((scope) => scope.size > 0);\n // Neither channel produced a tree — no scope can contain anything, and\n // an origin that matches no route is not a legitimate soft navigation.\n return scopes.length > 0 ? scopes : null;\n };\n const rewrite = findInterceptionMatch(\n canonicalPathname,\n resolveSourceScopes,\n config.interceptionRewrites\n );\n if (rewrite?.mode === 'children') {\n // Sibling layout swap (TIM-1280). Nothing is re-matched: the resolver\n // addresses the owner directory by tree path and returns the chain\n // `[…owner ancestors, interceptingNode, …descendants]`, which renders\n // as an ordinary route. `interception` stays unset — there is no slot\n // to intercept into, and setting it would additionally arm the modal\n // path for every slot in the tree we are about to render.\n //\n // A null here means the scope named nothing in this manifest, or no\n // intercepting child matched the target. Both fall through to the\n // canonical route, which is what a hard navigation renders.\n const interceptedMatch = config.matchInterceptedRoute?.(\n canonicalPathname,\n rewrite.interceptingScope\n );\n if (interceptedMatch) match = interceptedMatch;\n } else if (rewrite) {\n const sourceMatch = config.matchRoute(rewrite.interceptingPrefix);\n // The scope test above was about the route the user is LEAVING. The\n // route we are about to render is a different one —\n // `interceptingPrefix` is URL-derived, and route groups are\n // URL-invisible, so `/` can resolve into a sibling group that does not\n // own the slot. Rendering that would reproduce the TIM-1278 failure on\n // a valid tree: the rewrite hijacks the navigation and no slot exists\n // to render the intercepting page. Fall through to the canonical\n // target route instead.\n const rendersTheSlot =\n sourceMatch !== null &&\n computeSegmentTreePaths(sourceMatch.segments).includes(rewrite.interceptingScope);\n if (rendersTheSlot) {\n match = sourceMatch;\n interception = { targetPathname: canonicalPathname };\n }\n }\n }\n }\n\n return { match, interception };\n}\n\n/**\n * Validate and canonicalize the X-Timber-URL header value.\n *\n * Returns the canonical pathname if valid, or null if rejected:\n * - Must start with '/' (relative pathname, no scheme/authority)\n * - Must not contain control characters\n * - Must pass canonicalization (no encoded separators, null bytes, etc.)\n */\nfunction validateInterceptionHeader(raw: string, stripTrailingSlash: boolean): string | null {\n if (!raw.startsWith('/')) return null;\n if (raw.startsWith('//')) return null;\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n if (code <= 0x1f || code === 0x7f) return null;\n }\n const result = canonicalize(raw, stripTrailingSlash);\n if (!result.ok) return null;\n return result.pathname;\n}\n","/**\n * Legacy shared-cache control fields that predate RFC 9213 and so do not\n * follow the `<target>-Cache-Control` naming pattern — the one part of this\n * rule that cannot be matched by shape. `X-Accel-Expires` is nginx\n * `proxy_cache`, which gives it precedence over `Cache-Control`.\n *\n * A closed historical set, unlike the vendor `*-Cache-Control` names, which\n * keep being minted and are handled by pattern below.\n */\nconst LEGACY_CDN_CACHE_HEADERS = ['Surrogate-Control', 'Edge-Control', 'X-Accel-Expires'];\n\n/**\n * Whether a response header overrides `Cache-Control` at a shared cache.\n *\n * Matched by *shape*, not by vendor name. RFC 9213 defines targeted fields\n * as `<target>-Cache-Control`, and every CDN spells its own: `CDN-`,\n * `Cloudflare-CDN-`, `Netlify-CDN-`, `Vercel-CDN-`, and whichever ships\n * next. A vendor list here is a denylist with an unbounded tail — it was\n * extended twice during review, each time by one name, which is the signal\n * that enumeration is the wrong shape. The suffix rule is total.\n *\n * `Cache-Control` itself does not match (no `-` prefix) and is replaced\n * separately.\n */\nfunction isSharedCacheOverride(name: string): boolean {\n const lowered = name.toLowerCase();\n return (\n lowered.endsWith('-cache-control') ||\n LEGACY_CDN_CACHE_HEADERS.some((legacy) => legacy.toLowerCase() === lowered)\n );\n}\n\n/** Disable caching, including CDN overrides that take precedence over Cache-Control. */\nexport function preventResponseCaching(headers: Headers): void {\n // Collected before deleting — mutating Headers while iterating its live\n // key iterator can skip entries.\n const overrides: string[] = [];\n for (const name of headers.keys()) {\n if (isSharedCacheOverride(name)) overrides.push(name);\n }\n for (const name of overrides) {\n headers.delete(name);\n }\n headers.set('Cache-Control', 'private, no-store');\n}\n","import { preventResponseCaching } from './response-cache-policy.ts';\n\n/** Preserve request-wide metadata when replacing a failed response body. */\nexport function errorResponseHeaders(responseHeaders?: Headers): Headers {\n const headers = new Headers(responseHeaders);\n // These describe the abandoned body, not the replacement empty/JSON body.\n headers.delete('Content-Length');\n headers.delete('Content-Encoding');\n headers.delete('Transfer-Encoding');\n // A transient failure must not inherit the success page's cache lifetime\n // or validators, including CDN overrides of Cache-Control.\n preventResponseCaching(headers);\n headers.delete('ETag');\n headers.delete('Last-Modified');\n headers.delete('Expires');\n headers.delete('Age');\n return headers;\n}\n","import { TIMBER_ERROR_HEADER } from '../shared/rsc-error-envelope.ts';\nimport { errorResponseHeaders } from './error-response-headers.ts';\n\n/**\n * Build the hard-navigate envelope for a status code.\n *\n * Preserve middleware's request-wide headers and cookies, but discard the\n * abandoned body's framing, validators, and cache policy. Every producer,\n * including errors returned normally during render, gets this cleanup here.\n * The input header bag is left intact. The body deliberately carries no message —\n * only the status already on the wire (design/13-security.md principle 4).\n */\nexport function rscErrorEnvelope(status: number, responseHeaders?: Headers): Response {\n const headers = errorResponseHeaders(responseHeaders);\n headers.set(TIMBER_ERROR_HEADER, '1');\n headers.set('content-type', 'application/json; charset=utf-8');\n return new Response(JSON.stringify({ error: true, status }), { status, headers });\n}\n","/**\n * Pipeline outcome translator — converts a `PhaseOutcome` (the value\n * each phase function returns) into a final `Response`.\n *\n * Lifted out of `pipeline-phases.ts` (TIM-853) so the per-phase try /\n * catch logic and the terminal Response-building logic each live in\n * their own file. The phases produce values; this module is the single\n * source of truth for how those values become wire responses.\n *\n * See design/07-routing.md §\"Request Lifecycle\".\n */\n\nimport {\n applyCookieJar,\n buildRedirectResponse,\n cloneWithMutableHeaders,\n dynamicResponseHeaders,\n fireOnRequestError,\n mergeMissingHeaders,\n} from './pipeline-helpers.ts';\nimport {\n logProxyError,\n logMiddlewareError,\n logMiddlewareShortCircuit,\n logRenderError,\n logRouteError,\n logRouteSetupError,\n} from './logger.ts';\nimport { markResponseFlushed } from './request-context.ts';\nimport { RedirectSignal, DenySignal } from './primitives.ts';\nimport { isDenySignal, isRedirectSignal } from './signal-identity.ts';\nimport { isApiRouteChain } from './route-matcher.ts';\nimport { isDebug } from './debug.ts';\nimport { errorResponseHeaders } from './error-response-headers.ts';\nimport { rscErrorEnvelope } from './rsc-error-envelope.ts';\nimport { isRscRequest } from '../shared/rsc-media-type.ts';\nimport type { PipelineConfig, RouteMatch } from './pipeline.ts';\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction rscErrorResponse(isRsc: boolean, status: number, headers: Headers): Response {\n if (isRsc) return rscErrorEnvelope(status, headers);\n return new Response(null, { status, headers: errorResponseHeaders(headers) });\n}\n\n/**\n * Resolve the header bag a signal/error outcome is written onto, with the\n * cookie jar applied exactly once.\n *\n * Ownership rule (design/49 §P0b): the phase that owns `responseHeaders`\n * applies the jar to it once; the translator applies it only for outcomes\n * that arrive without it. Render-phase outcomes already carry the jar —\n * `runRenderPhase()` applies it on entry, with or without a middleware\n * chain — so re-applying here emitted every middleware `Set-Cookie` twice\n * (TIM-1491).\n *\n * The guard is \"not render\", not \"only middleware\": proxy-phase signals\n * reach the translator with no `responseHeaders` at all, and for a\n * `proxy.ts` that awaits `next()` and then throws, this is the only place\n * the cookies downstream middleware set can reach the wire\n * (design/29-cookies.md §\"proxy.ts Cookie Access\"). Middleware-phase\n * signals throw before that phase's own application, so they need it too,\n * and so do setup-phase outcomes, which come before any phase applied it.\n *\n * `fresh` creates the bag for an outcome that arrives without one.\n */\nfunction outcomeHeaders(\n outcome: PhaseOutcome,\n ctx: OutcomeContext,\n fresh: () => Headers = () => new Headers()\n): Headers {\n const headers = ctx.responseHeaders ?? fresh();\n if (outcome.phase !== 'render') applyCookieJar(headers);\n return headers;\n}\n\n/** Whether the outcome is for a route.ts match, which answers in its own format. */\nfunction isApiRouteMatch(ctx: OutcomeContext): boolean {\n return ctx.match !== undefined && isApiRouteChain(ctx.match.segments);\n}\n\n/**\n * Report an error outcome once: log it under its phase, fire\n * `onRequestError`, and hand it to the dev overlay. An error from a\n * route.ts handler — or anything else in its render phase — logs as a route\n * error and reports as phase `'route'`.\n */\nasync function reportError(\n config: PipelineConfig,\n error: unknown,\n phase: PhaseName,\n ctx: OutcomeContext\n): Promise<void> {\n const { method, path } = ctx;\n switch (phase) {\n case 'proxy':\n logProxyError({ error });\n break;\n case 'setup':\n logRouteSetupError({ method, path, error });\n break;\n case 'middleware':\n logMiddlewareError({ method, path, error });\n break;\n case 'render':\n if (isApiRouteMatch(ctx)) {\n logRouteError({ method, path, error });\n } else {\n logRenderError({ method, path, error });\n }\n break;\n }\n await fireOnRequestError(error, ctx.req, phase, ctx.match?.segments);\n if (config.onPipelineError && error instanceof Error) config.onPipelineError(error, phase);\n}\n\n// ─── Phase Outcome ─────────────────────────────────────────────────────────\n\n/**\n * The pipeline phase an outcome came from.\n *\n * `'setup'` is route setup between `proxy.ts` and `middleware.ts`: route\n * matching, interception, and segment-param coercion. It has its own name\n * rather than borrowing `'middleware'` because both the cookie-jar guard\n * and `onRequestError` key on the phase (TIM-1537).\n */\nexport type PhaseName = 'proxy' | 'setup' | 'middleware' | 'render';\n\nexport type PhaseOutcome =\n | { kind: 'response'; phase: PhaseName; response: Response }\n | { kind: 'redirect'; phase: PhaseName; signal: RedirectSignal }\n | { kind: 'deny'; phase: PhaseName; signal: DenySignal }\n | { kind: 'error'; phase: PhaseName; error: unknown };\n\n/** The outcome for a value a phase threw: a signal, or an error. */\nexport function thrownOutcome(phase: PhaseName, thrown: unknown): PhaseOutcome {\n if (isRedirectSignal(thrown)) return { kind: 'redirect', phase, signal: thrown };\n if (isDenySignal(thrown)) return { kind: 'deny', phase, signal: thrown };\n return { kind: 'error', phase, error: thrown };\n}\n\nexport interface OutcomeContext {\n req: Request;\n method: string;\n path: string;\n responseHeaders?: Headers;\n match?: RouteMatch;\n}\n\n// ─── Translator ────────────────────────────────────────────────────────────\n\n/**\n * Terminal outcome handler — converts a `PhaseOutcome` into a final\n * `Response`, applying cookies, building redirects, rendering deny pages\n * and fallback error pages, and firing instrumentation hooks.\n *\n * This is the single source of truth for how phase outputs become wire\n * responses; the per-phase try/catch blocks now produce values, not\n * Responses, so the conversion logic lives in exactly one place.\n */\nexport async function outcomeToResponse(\n config: PipelineConfig,\n outcome: PhaseOutcome,\n ctx: OutcomeContext\n): Promise<Response> {\n switch (outcome.kind) {\n case 'response': {\n // Clone unconditionally so downstream code (cookie/header merge,\n // Server-Timing in createPipeline) can write headers without paying\n // for a try/catch immutability probe per request. User middleware,\n // proxy, and route code may all return `Response.redirect()` or\n // platform-level responses with frozen header bags. See TIM-866.\n const finalResponse = cloneWithMutableHeaders(outcome.response);\n\n if (outcome.phase === 'proxy') return finalResponse;\n\n if (outcome.phase === 'middleware' && ctx.responseHeaders) {\n applyCookieJar(finalResponse.headers);\n mergeMissingHeaders(finalResponse.headers, ctx.responseHeaders);\n logMiddlewareShortCircuit({\n method: ctx.method,\n path: ctx.path,\n status: finalResponse.status,\n });\n }\n\n if (outcome.phase === 'render') {\n markResponseFlushed();\n }\n\n return finalResponse;\n }\n\n case 'redirect': {\n const headers = outcomeHeaders(outcome, ctx);\n // A route.ts match redirects with a real 3xx whatever it accepts; only\n // a page navigation gets the client router's soft redirect.\n const navigation = isRscRequest(ctx.req) && !isApiRouteMatch(ctx);\n return buildRedirectResponse(outcome.signal, headers, navigation);\n }\n\n case 'deny': {\n // A deny with no bag of its own (a proxy-phase deny) gets the\n // dynamic-page cache policy every other rendered page starts with.\n // Only the deny: a redirect proxy.ts chose keeps HTTP's own caching\n // semantics (a 308 is heuristically cacheable).\n const headers = outcomeHeaders(outcome, ctx, dynamicResponseHeaders);\n if (config.renderDenyFallback) {\n try {\n // Clone user-supplied deny-page responses so downstream\n // Server-Timing writes are safe against frozen header bags\n // (e.g. user returned Response.redirect from the hook).\n return cloneWithMutableHeaders(\n await config.renderDenyFallback(outcome.signal, ctx.req, headers, ctx.match)\n );\n } catch (denyRenderError) {\n // Deny page rendering failed — log before falling through to bare response.\n // Without this, a crashing deny page produces a blank response with zero\n // server-side signal. See TIM-876.\n logRenderError({ method: ctx.method, path: ctx.path, error: denyRenderError });\n await fireOnRequestError(denyRenderError, ctx.req, 'render', ctx.match?.segments);\n if (config.onPipelineError && denyRenderError instanceof Error)\n config.onPipelineError(denyRenderError, 'render');\n // A client navigation cannot decode an empty body: send the\n // hard-navigate envelope so the document request renders the deny.\n if (isRscRequest(ctx.req)) return rscErrorEnvelope(outcome.signal.status, headers);\n }\n }\n if (isDebug()) {\n console.warn(\n `[timber] DenySignal(${outcome.signal.status}) from ${outcome.phase} phase — ` +\n `no renderDenyFallback configured, returning bare ${outcome.signal.status} response\\n` +\n ` Request: ${ctx.method} ${ctx.path}\\n` +\n ` Add a status-code file (e.g. 404.tsx) or error.tsx to render a custom deny page.`\n );\n }\n return new Response(null, { status: outcome.signal.status, headers });\n }\n\n case 'error': {\n // RSC payload requests (client navigation) expect Flight data, not HTML.\n // Signal the error via X-Timber-Error so the client hard-navigates\n // to the server-rendered error page instead of feeding HTML to the\n // Flight decoder (which crashes with \"enqueueModel is not a function\").\n const isRsc = isRscRequest(ctx.req);\n const headers = outcomeHeaders(outcome, ctx);\n await reportError(config, outcome.error, outcome.phase, ctx);\n\n // proxy.ts and middleware.ts errors answer with a bare 500 — no page.\n if (outcome.phase === 'proxy' || outcome.phase === 'middleware') {\n return rscErrorResponse(isRsc, 500, headers);\n }\n\n // A route.ts match answers in its JSON format whatever the Accept\n // header says, so it skips the navigation envelope and goes to the\n // fallback renderer with the match.\n if (isRsc && !isApiRouteMatch(ctx)) {\n return rscErrorResponse(true, 500, headers);\n }\n\n if (config.renderFallbackError) {\n try {\n // Clone user-supplied fallback error responses so downstream\n // Server-Timing writes are safe against frozen header bags.\n return cloneWithMutableHeaders(\n // Sanitized: the replacement body must not inherit the success\n // response's encoding, length, validators, or cache lifetime\n // that middleware may already have set on the bag.\n await config.renderFallbackError(\n outcome.error,\n ctx.req,\n errorResponseHeaders(headers),\n ctx.match\n )\n );\n } catch (fallbackRenderError) {\n // Fallback rendering itself failed — log the secondary error before\n // falling through to bare 500. The original render error was already\n // logged above; this captures the fallback renderer's own crash so it\n // doesn't vanish silently. See TIM-876.\n logRenderError({ method: ctx.method, path: ctx.path, error: fallbackRenderError });\n await fireOnRequestError(fallbackRenderError, ctx.req, 'render', ctx.match?.segments);\n if (config.onPipelineError && fallbackRenderError instanceof Error)\n config.onPipelineError(fallbackRenderError, 'render');\n }\n }\n return rscErrorResponse(false, 500, headers);\n }\n }\n}\n","/**\n * Pipeline phase functions — module-level free functions that take their\n * dependencies as explicit parameters. Each phase returns a `PhaseOutcome`\n * (a discriminated union over response / redirect / deny / error) defined\n * in `pipeline-outcome.ts`. The terminal `outcomeToResponse` (also in\n * `pipeline-outcome.ts`) translates outcomes into Responses.\n *\n * Lifted out of `createPipeline` so each phase can be unit-tested in\n * isolation. The lift is mechanical — these functions used to be closures\n * over `config`; they now take `config` as an explicit parameter.\n *\n * See design/07-routing.md §\"Request Lifecycle\", design/02-rendering-pipeline.md §\"Request Flow\".\n */\n\nimport { canonicalize } from './canonicalize.ts';\nimport { runProxy } from './proxy.ts';\nimport { runMiddlewareChain } from './middleware-runner.ts';\nimport { withTiming } from './server-timing.ts';\nimport {\n applyRequestHeaderOverlay,\n setMutableCookieContext,\n setSegmentParams,\n setMatchedSegmentPath,\n} from './request-context.ts';\nimport { withSpan } from './tracing.ts';\nimport { requestCspNonce } from './csp-nonce.ts';\nimport { logRenderError } from './logger.ts';\nimport { isDenySignal, isRedirectSignal } from './signal-identity.ts';\nimport { ParamCoercionError } from './param-coercion.ts';\nimport { checkVersionSkew, applyReloadHeaders } from './version-skew.ts';\nimport { serveStaticMetadataFile, serializeSitemap } from './pipeline-metadata.ts';\nimport { loadModule } from './safe-load.ts';\nimport { resolveInterceptedRoute } from './pipeline-interception.ts';\nimport { isApiRouteChain } from './route-matcher.ts';\nimport {\n applyCookieJar,\n cloneWithMutableHeaders,\n dynamicResponseHeaders,\n fireOnRequestError,\n type ProxyResolver,\n} from './pipeline-helpers.ts';\nimport { coerceSegmentParams } from './param-coercion.ts';\nimport { outcomeToResponse, thrownOutcome, type PhaseOutcome } from './pipeline-outcome.ts';\nimport type { InterceptionContext, PipelineConfig, RouteMatch } from './pipeline.ts';\nimport type { MetadataHandler, MetadataRoute, MiddlewareContext } from './types.ts';\nimport { swallow } from './logger.ts';\nimport { isDebug } from './debug.ts';\nimport { isRscRequest } from '../shared/rsc-media-type.ts';\n\ninterface RenderContext {\n canonicalPathname: string;\n interception?: InterceptionContext;\n}\n\n// ─── Phase: Proxy ──────────────────────────────────────────────────────────\n\n/**\n * Run the proxy.ts phase. Calls user proxy code with a `next()` continuation.\n *\n * When `next` is provided, it replaces the default `handleRequest` as the\n * continuation — this lets the pipeline inject action dispatch between proxy\n * and route matching (TIM-1213). The proxy resolver was picked at pipeline\n * construction time so the hot path sees no per-request branching on the\n * `ProxyConfig` discriminant.\n */\nexport async function runProxyPhase(\n config: PipelineConfig,\n getProxy: ProxyResolver,\n req: Request,\n method: string,\n path: string,\n next?: () => Promise<Response>\n): Promise<PhaseOutcome> {\n const detailed = config.serverTiming === 'detailed';\n try {\n const proxyExport = await getProxy();\n const continuation = next ?? (() => handleRequest(config, req, method, path, true));\n const proxyFn = () => runProxy(proxyExport, req, continuation);\n const response = await withSpan('timber.proxy', {}, () =>\n detailed ? withTiming('proxy', 'proxy.ts', proxyFn) : proxyFn()\n );\n return { kind: 'response', phase: 'proxy', response };\n } catch (error) {\n return thrownOutcome('proxy', error);\n }\n}\n\n// ─── Phase: Middleware ─────────────────────────────────────────────────────\n\n/**\n * Run the middleware chain phase. If the chain short-circuits with a Response,\n * returns it as a 'response' outcome. Otherwise applies the request header\n * overlay and falls through to the render phase.\n */\nexport async function runMiddlewarePhase(\n config: PipelineConfig,\n req: Request,\n match: RouteMatch,\n responseHeaders: Headers,\n renderContext: RenderContext\n): Promise<PhaseOutcome> {\n const detailed = config.serverTiming === 'detailed';\n const requestHeaderOverlay = new Headers();\n const ctx: MiddlewareContext = {\n req,\n requestHeaders: requestHeaderOverlay,\n headers: responseHeaders,\n segmentParams: match.segmentParams,\n // Lazy: reading it is the opt-in that makes the render nonce its scripts.\n get nonce() {\n return requestCspNonce();\n },\n earlyHints: (hints) => {\n for (const hint of hints) {\n // Match Cloudflare's cached Early Hints attribute order: `as` before `rel`.\n // Cloudflare caches Link headers and re-emits them on subsequent 200s.\n // If our order differs, the browser sees duplicate preloads and warns.\n let value: string;\n if (hint.as !== undefined) {\n value = `<${hint.href}>; as=${hint.as}; rel=${hint.rel}`;\n } else {\n value = `<${hint.href}>; rel=${hint.rel}`;\n }\n if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;\n if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;\n responseHeaders.append('Link', value);\n }\n },\n };\n\n try {\n const chainFn = () => runMiddlewareChain(match.middlewareChain, ctx);\n // Enable cookie mutation during middleware (design/29-cookies.md §\"Context Tracking\")\n const middlewareResponse = await (async () => {\n setMutableCookieContext(true);\n try {\n return await withSpan('timber.middleware', {}, () =>\n detailed ? withTiming('mw', 'middleware.ts', chainFn) : chainFn()\n );\n } finally {\n setMutableCookieContext(false);\n }\n })();\n if (middlewareResponse) {\n return { kind: 'response', phase: 'middleware', response: middlewareResponse };\n }\n // Middleware chain completed without short-circuiting — apply any\n // injected request headers so getHeaders() returns them downstream.\n applyRequestHeaderOverlay(requestHeaderOverlay);\n\n return runRenderPhase(config, req, match, responseHeaders, renderContext);\n } catch (error) {\n return thrownOutcome('middleware', error);\n }\n}\n\n// ─── Phase: Render ─────────────────────────────────────────────────────────\n\n/**\n * Run the render phase. Wraps the configured renderer in a span and a\n * timing scope, and translates thrown signals into outcome variants.\n *\n * The render phase owns `responseHeaders` from here on, so it is the one\n * place the cookie jar is applied to that bag (design/29-cookies.md\n * §\"Applied Exactly Once\"). Doing it here rather than in the middleware\n * phase means every render-phase outcome — a 200, or a deny / redirect /\n * error thrown from render — carries the jar whether or not a middleware\n * chain ran, and `outcomeToResponse` can skip render-phase outcomes\n * unconditionally (TIM-1491). Application precedes `config.render` so\n * middleware cookie writes are visible to route-handler header merging,\n * while handler `Set-Cookie` values still come after them and take\n * precedence.\n */\nexport async function runRenderPhase(\n config: PipelineConfig,\n req: Request,\n match: RouteMatch,\n responseHeaders: Headers,\n { canonicalPathname, interception }: RenderContext\n): Promise<PhaseOutcome> {\n const detailed = config.serverTiming === 'detailed';\n applyCookieJar(responseHeaders);\n try {\n const renderFn = () => config.render(req, match, responseHeaders, interception);\n const response = await withSpan('timber.render', { 'http.route': canonicalPathname }, () =>\n detailed ? withTiming('render', 'RSC + SSR render', renderFn) : renderFn()\n );\n return { kind: 'response', phase: 'render', response };\n } catch (error) {\n return thrownOutcome('render', error);\n }\n}\n\n// ─── Request Handler ───────────────────────────────────────────────────────\n\n/**\n * Process a single request from canonicalization through phase dispatch.\n *\n * Stages: canonicalize → metadata routes → auto-sitemap → version skew →\n * route match → interception → early hints → param coercion → middleware →\n * render → outcome translation. Pre-routing short-circuits return Responses\n * directly; post-match dispatch goes through `outcomeToResponse`.\n *\n * Used both as the top-level entry (when no proxy.ts is configured) and as\n * the `next()` continuation passed to `runProxy()`.\n *\n * @param pathIsCanonical When true, `path` has already been canonicalized by\n * `createPipeline` — skip re-canonicalization to prevent double-decode.\n * When false (default), runs canonicalize as a safety net for direct callers.\n */\nexport async function handleRequest(\n config: PipelineConfig,\n req: Request,\n method: string,\n path: string,\n pathIsCanonical?: boolean\n): Promise<Response> {\n const stripTrailingSlash = config.stripTrailingSlash ?? true;\n\n // Stage 1: URL canonicalization.\n // When pathIsCanonical is true, createPipeline has already run canonicalize()\n // and passed the result as `path`. Re-canonicalizing would double-decode\n // percent-encoded characters (e.g., %61dmin → admin). See TIM-1004.\n //\n // When pathIsCanonical is false, this is a safety net for direct callers\n // (tests, non-pipeline usage) that haven't pre-canonicalized.\n let canonicalPathname: string;\n if (pathIsCanonical) {\n canonicalPathname = path;\n } else {\n const result = canonicalize(path, stripTrailingSlash);\n if (!result.ok) {\n if (isDebug()) {\n console.warn(\n `[timber] URL canonicalization rejected ${method} ${path} — responding with ${result.status}\\n` +\n ` This usually means the URL contains encoded separators (%2f, %5c),\\n` +\n ` null bytes (%00), path traversal (..), or malformed percent-encoding.`\n );\n }\n return new Response(null, { status: result.status });\n }\n canonicalPathname = result.pathname;\n }\n\n // Stage 1b: Metadata route matching — runs before regular route matching.\n // Metadata routes skip middleware.ts and access.ts (public endpoints for crawlers).\n // See design/16-metadata.md §\"Pipeline Integration\"\n if (config.matchMetadataRoute) {\n const metaMatch = config.matchMetadataRoute(canonicalPathname);\n if (metaMatch) {\n try {\n // Static metadata files (.xml, .txt, .png, .ico, etc.) are served\n // directly from disk. Dynamic metadata routes (.ts, .tsx) export a\n // handler function that generates the response.\n if (metaMatch.isStatic) {\n return await serveStaticMetadataFile(metaMatch);\n }\n\n setSegmentParams(metaMatch.segmentParams);\n const mod = await loadModule<{ default?: MetadataHandler }>(metaMatch.file);\n if (typeof mod.default !== 'function') {\n if (isDebug()) {\n console.warn(\n `[timber] Metadata route ${metaMatch.file} does not export a default function — responding with 500\\n` +\n ` Metadata routes must export a default function that returns the metadata content.`\n );\n }\n return new Response('Metadata route must export a default function', { status: 500 });\n }\n const handlerResult = await mod.default();\n // If the handler returns a Response, normalize headers so the\n // outer Server-Timing writer can append without hitting an\n // immutable header bag (e.g. user returns Response.redirect()).\n if (handlerResult instanceof Response) {\n return cloneWithMutableHeaders(handlerResult);\n }\n // Otherwise, serialize based on content type. The type discriminator\n // here is the metadata route's declared content type (from the file\n // convention), not the shape of `handlerResult` — TS can't narrow the\n // `MetadataResult` union on that, so we assert against the expected\n // shape at each branch.\n const contentType = metaMatch.contentType;\n let body: string;\n if (typeof handlerResult === 'string') {\n body = handlerResult;\n } else if (contentType === 'application/xml') {\n body = serializeSitemap(handlerResult as MetadataRoute.Sitemap);\n } else if (contentType === 'application/manifest+json') {\n body = JSON.stringify(handlerResult, null, 2);\n } else {\n body = String(handlerResult);\n }\n return new Response(body, {\n status: 200,\n headers: {\n 'Content-Type': `${contentType}; charset=utf-8`,\n 'Cache-Control': 'public, max-age=14400, must-revalidate',\n },\n });\n } catch (error) {\n // Control-flow signals from the metadata handler (e.g. a sitemap that\n // calls deny(404) for an unknown tenant, or a dynamic icon that\n // redirects to a CDN-hosted asset) translate to proper HTTP responses\n // instead of being logged as 500s.\n if (isRedirectSignal(error)) {\n return new Response(null, {\n status: error.status,\n headers: { Location: error.location },\n });\n }\n if (isDenySignal(error)) {\n return new Response(null, { status: error.status });\n }\n logRenderError({ method, path, error });\n await fireOnRequestError(error, req, 'route');\n if (config.onPipelineError && error instanceof Error)\n config.onPipelineError(error, 'metadata-route');\n return new Response(null, { status: 500 });\n }\n }\n }\n\n // Stage 1b.2: Auto-generated sitemap — serves /sitemap.xml and /sitemap/N.xml\n // when sitemap generation is enabled and no user-authored sitemap exists.\n // Runs after metadata route matching so user sitemaps always take precedence.\n // See design/16-metadata.md §\"Auto-generated Sitemap\"\n if (config.autoSitemapHandler) {\n try {\n const sitemapResponse = await config.autoSitemapHandler(canonicalPathname);\n if (sitemapResponse) return cloneWithMutableHeaders(sitemapResponse);\n } catch (error) {\n logRenderError({ method, path, error });\n await fireOnRequestError(error, req, 'route');\n if (config.onPipelineError && error instanceof Error)\n config.onPipelineError(error, 'auto-sitemap');\n return new Response(null, { status: 500 });\n }\n }\n\n // Stage 1c: Version skew detection (TIM-446).\n // For RSC payload requests (client navigation), check if the client's\n // deployment ID matches the current build. On mismatch, signal the\n // client to do a full page reload instead of returning an RSC payload\n // that references mismatched module IDs.\n const isRsc = isRscRequest(req);\n if (isRsc) {\n const skewCheck = checkVersionSkew(req);\n if (!skewCheck.ok) {\n const reloadHeaders = new Headers();\n applyReloadHeaders(reloadHeaders);\n return new Response(null, { status: 204, headers: reloadHeaders });\n }\n }\n\n // Response and request header containers — created before early hints so\n // the emitter can append Link headers (e.g. for Cloudflare CDN → 103).\n // Seeded with the dynamic-page cache policy, which the no-match 404\n // rendered below carries too.\n const responseHeaders = dynamicResponseHeaders();\n\n // Stages 2–2c are route setup. Anything they throw — a matcher bug, a\n // codec returning a value a param cannot hold — is a `'setup'` outcome:\n // logged, reported to onRequestError, and answered with the fallback page,\n // with the match when there is one so a route.ts match keeps its format.\n // Before TIM-1537 it escaped `createPipeline`, or was reported as\n // \"proxy.ts threw\" when a proxy wrapped it.\n //\n // Rendering the 404 page is render work, not setup, so its own failure is\n // a `'render'` outcome even when setup decided the request is a 404.\n const renderNotFound = async (headers: Headers): Promise<Response> => {\n if (!config.renderNoMatch) return new Response(null, { status: 404 });\n try {\n return cloneWithMutableHeaders(await config.renderNoMatch(req, headers));\n } catch (error) {\n return outcomeToResponse(config, thrownOutcome('render', error), {\n req,\n method,\n path,\n responseHeaders: headers,\n });\n }\n };\n let match: RouteMatch | null = null;\n let interception: InterceptionContext | undefined;\n try {\n // Stage 2: Route matching, then 2a: intercepting route resolution.\n match = config.matchRoute(canonicalPathname);\n ({ match, interception } = resolveInterceptedRoute(config, req, canonicalPathname, match));\n\n if (!match) {\n // Dev-time diagnostic: log the unmatched pathname so developers can\n // see why a request 404'd without needing to add breakpoints.\n if (isDebug()) {\n console.warn(\n `[timber] No route matched for pathname: ${canonicalPathname}\\n` +\n ` Input path: ${path}\\n` +\n ` Method: ${method}`\n );\n }\n // No route matched — render 404.tsx in root layout if available,\n // otherwise fall back to a bare 404 Response.\n return await renderNotFound(responseHeaders);\n }\n\n // Stage 2b: 103 Early Hints (before middleware, after match)\n // Fires before middleware so the browser can begin fetching critical\n // assets while middleware runs. Non-fatal — a failing emitter never\n // blocks the request.\n //\n // Skip on RSC requests (client-side navigations) — the browser already\n // has CSS, fonts, and JS chunks from the initial full-page load.\n // Skip on API routes (route.ts without page.tsx) — they return data\n // (JSON, images, etc.), not HTML that needs CSS/JS/font hints.\n if (config.earlyHints && !isRsc && !isApiRouteChain(match.segments)) {\n try {\n await config.earlyHints(match, req, responseHeaders);\n } catch (err) {\n swallow(err, 'early hints hook threw');\n }\n }\n\n // Stage 2c: Param coercion (before middleware)\n // Coerce raw string params through the app/schema.ts codecs.\n // Coercion failure → 404\n // (middleware never runs). See design/07-routing.md §\"Where Coercion Runs\"\n try {\n match = { ...match, segmentParams: await coerceSegmentParams(match) };\n } catch (error) {\n if (error instanceof ParamCoercionError) {\n // Dev-time diagnostic: log param coercion failures so developers can\n // see why a matched route 404'd. Silent coercion 404s are brutal to debug.\n if (isDebug()) {\n const segmentChain = match.segments.map((s) => s.segmentName || '/').join(' → ');\n console.warn(\n `[timber] Param coercion failed for ${method} ${canonicalPathname} — responding with 404\\n` +\n ` Matched segments: ${segmentChain}\\n` +\n ` Error: ${error.message}\\n` +\n ` This usually means a codec in app/schema.ts rejected the URL value.\\n` +\n ` Check the codec for the bracket key of the segment named above.`\n );\n }\n // For API routes (route.ts), return a bare 404 — not an HTML page.\n // API consumers expect JSON/empty responses, not rendered HTML.\n if (isApiRouteChain(match.segments)) {\n return new Response(null, { status: 404 });\n }\n // Route through the app's 404 page (404.tsx in root layout) instead of\n // returning a bare empty 404 Response. Falls back to bare 404 only if\n // no renderNoMatch renderer is configured.\n return await renderNotFound(responseHeaders);\n }\n throw error;\n }\n\n // Store coerced segment params in ALS so components can access them\n // via getSegmentParams() instead of receiving them as a prop.\n // See design/07-routing.md §\"params.ts — Convention File for Typed Params\"\n setSegmentParams(match.segmentParams);\n\n // Store the matched segment path for dev-mode validation in getSegmentParams().\n // Build the tree path from the segment chain (includes groups and slots).\n const segmentPath =\n match.segments\n .map((s) => s.segmentName)\n .filter(Boolean)\n .join('/') || '/';\n setMatchedSegmentPath(segmentPath.startsWith('/') ? segmentPath : `/${segmentPath}`);\n } catch (error) {\n return outcomeToResponse(config, thrownOutcome('setup', error), {\n req,\n method,\n path,\n responseHeaders,\n match: match ?? undefined,\n });\n }\n\n const outcome =\n match.middlewareChain.length > 0\n ? await runMiddlewarePhase(config, req, match, responseHeaders, {\n canonicalPathname,\n interception,\n })\n : await runRenderPhase(config, req, match, responseHeaders, {\n canonicalPathname,\n interception,\n });\n\n return outcomeToResponse(config, outcome, {\n req,\n method,\n path,\n responseHeaders,\n match,\n });\n}\n","/**\n * Origin-side binding of the `_rsc` cache key to the request that produced\n * the response (TIM-1268).\n *\n * The key is deterministic, and deliberately so — that is what makes RSC\n * payloads cacheable. But deterministic also means *predictable*: anyone can\n * compute the key another client will request. Without this guard, a caller\n * could request `/about?_rsc=<victim's key>` while sending its own\n * `X-Timber-State-Tree`, and a shared cache that keys by URL — the exact\n * environment this feature targets — would store that variant under the\n * victim's key. Every subsequent legitimate navigation would then be served\n * a payload rendered for someone else's segment tree or deployment.\n *\n * The guard is a *storability* rule, not a rejection: if the claimed key\n * does not match the key derived from the received headers, the response\n * loses its shared-cache directives. Mismatched requests are still served\n * normally, they just cannot be stored for anyone else.\n *\n * Why not Next.js's 307 self-correction: a redirect is cacheable in its own\n * right, costs a round trip on every legitimate miss, and would make the\n * server's behaviour depend on a parameter it otherwise never reads. This\n * rule closes the same hole by making the poisoned entry unstorable at the\n * source, in the response the developer already has to opt into sharing.\n *\n * See design/19-client-navigation.md §\"The `_rsc` cache key\".\n */\n\nimport { rscCacheKey, isRscCacheKeyShape, RSC_KEY_PARAM } from '../shared/rsc-cache-key.ts';\nimport { isRscContentType } from '../shared/rsc-media-type.ts';\nimport { preventResponseCaching } from './response-cache-policy.ts';\n\n/**\n * Whether the request's `_rsc` parameter matches the key derived from its\n * own headers.\n *\n * Requests without the parameter are not claiming a key at all, so they are\n * left alone — the bare document URL is the developer's declared territory\n * (see design/32-response-caching.md, TIM-1264). Neither is a parameter\n * whose value could not be one of our digests: `_rsc` is not reserved, and\n * an application that already uses it for its own search state\n * (`/search?_rsc=foo`) must not have its cache policy silently revoked by a\n * guard that mistook that for a forgery.\n */\nexport async function hasValidRscCacheKey(req: Request): Promise<boolean> {\n // Fast path: this runs on every request, and the overwhelming majority\n // (document requests) have no query string at all. Keyed on `?` and not\n // on the literal `_rsc=`, because a substring test is not a parse: a\n // request for `?%5Frsc=<key>` carries no literal `_rsc=`, yet\n // `URLSearchParams` decodes it to one — and a cache that canonicalizes\n // percent-encoded unreserved characters in its key while forwarding the\n // original URL would store the response under the decoded, claimed key.\n // The only sound fast path is one that cannot answer \"no key\" wrongly.\n if (!req.url.includes('?')) return true;\n let values: string[];\n try {\n values = new URL(req.url).searchParams.getAll(RSC_KEY_PARAM);\n } catch {\n // Unparseable URL — nothing to validate, and nothing safe to assume.\n return false;\n }\n // Every value, not the first. An application that owns `_rsc` for its own\n // search state makes the client emit `?_rsc=foo&_rsc=<key>` — reading only\n // the first would see `foo`, exempt it as application data, and never\n // check the real key sitting beside it.\n const claims = values.filter(isRscCacheKeyShape);\n if (claims.length === 0) return true;\n const expected = await rscCacheKey((name) => req.headers.get(name));\n // No digest available means the claim is unverifiable, which is not the\n // same as verified. Every server runtime timber targets has\n // `crypto.subtle`, so this is a guard against a future one that does not.\n if (expected === null) return false;\n // All of them, because at most one can be legitimate and a cache keys on\n // the whole query string — a second, mismatched key would ride along\n // inside an address that otherwise looks validated.\n return claims.every((claim) => claim === expected);\n}\n\n/**\n * Ensure a Flight payload can never be interpreted as a document.\n *\n * Applied here, at the pipeline's single exit, rather than where each\n * payload response is built. Six places build one — the success path, three\n * in `deny-renderer.ts`, the action paths — and hardening them one at a time\n * is how you end up hardening five of six. The response is Flight if it says\n * it is; that is the only test that covers every producer, including ones\n * added later.\n *\n * Matters because the payload URL is observable and, on a shared-cache hit,\n * the origin is never consulted — so a top-level navigation can be handed\n * these bytes with no request-time check available. See design/13-security.md\n * #36c.\n */\nexport function hardenRscPayloadResponse(response: Response): void {\n if (!isRscContentType(response.headers.get('content-type'))) return;\n response.headers.set('X-Content-Type-Options', 'nosniff');\n}\n\n/**\n * Make a response unstorable by any shared cache when its request claimed an\n * `_rsc` key that does not match its own headers.\n *\n * The end state is unconditional and therefore statable: **a mismatched\n * response is never stored by any cache.** Every targeted cache-control\n * field is removed and `Cache-Control` is replaced outright, rather than\n * downgrading only when a shared directive is spotted. Conditional variants\n * of this were tried and were wrong twice over — they missed the CDN-\n * specific headers, and leaving `Cache-Control` alone when it looked\n * harmless lets a CDN apply heuristic caching to a response that has none.\n *\n * The cost is that a mismatched request loses developer-chosen *browser*\n * caching too. That is a request no timber client ever makes.\n *\n * Purge tags (`Surrogate-Key`, `Cache-Tag`) are deliberately left alone:\n * they address stored entries, and this response is not stored.\n *\n * Mutates `response.headers` in place; the pipeline guarantees mutable\n * headers at this point (see TIM-866).\n */\nexport async function enforceRscCacheKey(req: Request, response: Response): Promise<void> {\n if (await hasValidRscCacheKey(req)) return;\n preventResponseCaching(response.headers);\n}\n","/**\n * HEAD body stripping — RFC 9110 §9.3.2.\n *\n * \"The HEAD method is identical to GET except that the server MUST NOT send\n * content in the response.\" The headers, however, must be the ones the\n * corresponding GET would have produced — which is why timber renders the\n * route in full and discards the body here rather than short-circuiting the\n * render. Content-Type, Content-Length, Set-Cookie, cache directives and\n * everything else ride through untouched.\n *\n * Node's `ServerResponse` happens to discard writes for HEAD, so the wire is\n * usually correct even without this. That is a property of one adapter, not of\n * the `Response` object: static generation, the Cloudflare and Nitro adapters,\n * tests, and anything calling the pipeline handler as a function all observe\n * the `Response` directly and saw the full body before TIM-1324.\n *\n * The pipeline applies this at its single exit so every response shape is\n * covered — page render, API route, metadata route, deny page, error page,\n * proxy short-circuit. The unit-level producer that is also reachable as a\n * standalone function (`handleRouteRequest`) calls it too, so it honours HEAD\n * on its own; it shares this implementation rather than repeating it, and\n * applying it twice is a no-op.\n */\n\n/**\n * Return a bodyless copy of `response` when `method` is HEAD.\n *\n * A no-op for every other method and for responses that already carry no body\n * (204, 304, redirects), so callers do not need to pre-check either.\n *\n * The discarded stream is cancelled: an SSR render that reached this point has\n * a live producer attached, and dropping the reference without cancelling\n * leaks it for the lifetime of the render (design/13-security.md A4).\n */\nexport function stripHeadBody(response: Response, method: string): Response {\n if (method.toUpperCase() !== 'HEAD') return response;\n const body = response.body;\n if (body === null) return response;\n\n // `cancel()` rejects if the stream is already errored and throws\n // synchronously if it is locked — neither is actionable here, the body is\n // being discarded either way.\n try {\n body.cancel().catch(() => {});\n } catch {\n /* stream already locked or disturbed */\n }\n\n return new Response(null, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n}\n","/**\n * Request pipeline — the central dispatch for all timber.js requests.\n *\n * Pipeline stages (in order):\n * canonicalize → CSRF gate → proxy.ts → route match → 103 Early Hints → middleware.ts → render\n *\n * The phase functions live in `pipeline-phases.ts` so each phase can be\n * tested in isolation. The terminal `outcomeToResponse` translator and\n * stateless helpers live in `pipeline-phases.ts` and `pipeline-helpers.ts`\n * respectively. This file owns only the public type surface and the\n * `createPipeline` entry point: trace ID setup, request-context ALS,\n * Server-Timing wrapping, and the activeRequests counter.\n *\n * See design/07-routing.md §\"Request Lifecycle\", design/02-rendering-pipeline.md §\"Request Flow\",\n * and design/17-logging.md §\"Production Logging\"\n */\n\nimport type { CoercedParams } from '../shared/param-value.ts';\nimport type { ProxyExport } from './proxy.ts';\nimport type { MiddlewareFn } from './middleware-runner.ts';\nimport { runWithTimingCollector, getServerTimingHeader } from './server-timing.ts';\nimport { wrapResponseWithStreamTiming } from './stream-utils.ts';\nimport { runWithRequestContext } from './request-context.ts';\nimport {\n generateTraceId,\n runWithTraceId,\n getOtelTraceId,\n replaceTraceId,\n withSpan,\n setSpanAttribute,\n} from './tracing.ts';\nimport { logRequestReceived, logRequestCompleted, logSlowRequest } from './logger.ts';\nimport { DenySignal } from './primitives.ts';\nimport type { ManifestSegmentNode } from './route-matcher.ts';\nimport { csrfGate, makeProxyResolver } from './pipeline-helpers.ts';\nimport type { CsrfConfig } from './csrf.ts';\nimport { handleRequest, runProxyPhase } from './pipeline-phases.ts';\nimport { outcomeToResponse } from './pipeline-outcome.ts';\nimport { canonicalize } from './canonicalize.ts';\nimport { enforceRscCacheKey, hardenRscPayloadResponse } from './rsc-cache-key-guard.ts';\nimport { stripHeadBody } from './head-response.ts';\nimport { RSC_KEY_HEADERS } from '../shared/rsc-cache-key.ts';\nimport { isDebug } from './debug.ts';\n\n// ─── Route Match Result ────────────────────────────────────────────────────\n\n/**\n * Result of matching a canonical pathname against the route tree.\n *\n * `segments` is the runtime (`ManifestFile`-specialized) shape — the same\n * nodes carried in the virtual route manifest. TIM-863 unified this: the\n * matcher produces `ManifestSegmentNode[]` directly and every consumer\n * (render, slots, params coercion, early hints, deny fallback) sees the\n * same structural type with no `as unknown as` laundering.\n */\nexport interface RouteMatch {\n /** The matched segment chain from root to leaf. */\n segments: ManifestSegmentNode[];\n /**\n * Segment params as the page sees them. The matcher sets them to the raw\n * values; whoever runs `coerceSegmentParams()` replaces them with its\n * result, whose values may be non-string (TIM-1347).\n */\n segmentParams: CoercedParams;\n /**\n * Segment params as the URL carried them (catch-all segments produce\n * string[]). Set by the matcher, which owns them, and never replaced.\n * Slot resolution and URL-part reconstruction read these: coerced values\n * need not round-trip to the URL (`\"007\"` → `7`).\n */\n rawSegmentParams: Record<string, string | string[]>;\n /** Middleware chain from the segment tree, ordered root-to-leaf. */\n middlewareChain: MiddlewareFn[];\n}\n\n/** Function that matches a canonical pathname to a route. */\nexport type RouteMatcher = (pathname: string) => RouteMatch | null;\n\n/** Function that matches a canonical pathname to a metadata route. */\nexport type MetadataRouteMatcher = (\n pathname: string\n) => import('./route-matcher.ts').MetadataRouteMatch | null;\n\n/** Context for intercepting route resolution (modal pattern). */\nexport interface InterceptionContext {\n /** The URL the user is navigating TO (the intercepted route). */\n targetPathname: string;\n}\n\n/** Function that renders a matched route into a Response. */\nexport type RouteRenderer = (\n req: Request,\n match: RouteMatch,\n responseHeaders: Headers,\n interception?: InterceptionContext\n) => Response | Promise<Response>;\n\n/** Function that sends 103 Early Hints for a matched route. */\nexport type EarlyHintsEmitter = (\n match: RouteMatch,\n req: Request,\n responseHeaders: Headers\n) => void | Promise<void>;\n\n// ─── Pipeline Configuration ────────────────────────────────────────────────\n\n/**\n * Proxy source — a tagged union so the choice between \"already-resolved\n * export\" and \"lazy HMR-friendly loader\" is encoded in the type, not\n * inferred per-request.\n *\n * - `static` — the proxy export is already resolved (production, tests).\n * - `lazy` — a loader is called per-request for HMR freshness (dev).\n *\n * `PipelineConfig.proxy` also accepts a bare `ProxyExport` (a function or\n * function array) as shorthand for the static variant — convenient for tests\n * that construct a `createPipeline` config inline. Omit the field entirely\n * when the app has no `proxy.ts`.\n *\n * See design/07-routing.md §\"proxy.ts — Global Middleware\".\n */\nexport type ProxyConfig =\n | { kind: 'static'; export: ProxyExport }\n | { kind: 'lazy'; loader: () => Promise<{ default: ProxyExport }> };\n\nexport interface PipelineConfig {\n /**\n * proxy.ts source. Undefined if the app has no proxy.ts. Accepts either a\n * tagged `ProxyConfig` (canonical) or a bare `ProxyExport` as sugar for the\n * static variant.\n */\n proxy?: ProxyConfig | ProxyExport;\n /** Route matcher — resolves a canonical pathname to a RouteMatch. */\n matchRoute: RouteMatcher;\n /**\n * CSRF configuration (`allowedOrigins`, the `csrf: false` switch). The\n * gate is on when this is omitted — protection is never opt-in. See\n * design/08-forms-and-actions.md §\"CSRF Protection\".\n */\n csrf?: CsrfConfig;\n /** Metadata route matcher — resolves metadata route pathnames (sitemap.xml, robots.txt, etc.) */\n matchMetadataRoute?: MetadataRouteMatcher;\n /** Renderer — produces the final Response for a matched route. */\n render: RouteRenderer;\n /** Renderer for no-match 404 — renders 404.tsx in root layout. */\n renderNoMatch?: (req: Request, responseHeaders: Headers) => Response | Promise<Response>;\n /** Early hints emitter — fires 103 hints after route match, before middleware. */\n earlyHints?: EarlyHintsEmitter;\n /** Whether to strip trailing slashes during canonicalization. Default: true. */\n stripTrailingSlash?: boolean;\n /** Slow request threshold in ms. Requests exceeding this emit a warning. 0 to disable. Default: 3000. */\n slowRequestMs?: number;\n /**\n * Interception rewrites — conditional routes for the modal pattern.\n * Generated at build time from intercepting route directories.\n * See design/07-routing.md §\"Intercepting Routes\"\n */\n interceptionRewrites?: import('../routing/interception.ts').InterceptionRewrite[];\n /**\n * Resolver for children-path interceptions — the sibling layout swap.\n *\n * Separate from `matchRoute` because it addresses the owner directory by\n * tree path rather than by pathname, which needs the manifest tree itself.\n * Omitting it disables the `'children'` interception shape and leaves the\n * canonical route rendering, which is the fail-safe outcome.\n *\n * See design/07-routing.md §\"Intercepting Routes\"\n */\n matchInterceptedRoute?: import('./children-interception.ts').InterceptedRouteMatcher;\n /**\n * Control Server-Timing header output.\n *\n * - `'detailed'` — per-phase breakdown (proxy, middleware, render).\n * - `'total'` — single `total;dur=N` entry (production-safe).\n * - `false` — no Server-Timing header at all.\n *\n * Default: `'total'`.\n */\n serverTiming?: 'detailed' | 'total' | false;\n /**\n * Auto-generated sitemap handler. When provided, the pipeline intercepts\n * `/sitemap.xml` and `/sitemap/N.xml` requests and delegates to this\n * function. Returns a Response or null (pass-through to regular routing).\n *\n * See design/16-metadata.md §\"Auto-generated Sitemap\"\n */\n autoSitemapHandler?: (pathname: string) => Promise<Response | null>;\n /**\n * Dev pipeline error callback — called when a pipeline phase (proxy,\n * middleware, render) catches an unhandled error. Used to wire the error\n * into the Vite browser error overlay in dev mode.\n *\n * Undefined in production — zero overhead.\n */\n onPipelineError?: (error: Error, phase: string) => void;\n\n /**\n * Fallback error renderer — called when a catastrophic error escapes the\n * render phase. Produces an HTML Response instead of a bare empty 500.\n *\n * In dev mode, this renders a styled error page with the error message\n * and stack trace. In production, this attempts to render the app's\n * error.tsx / 5xx.tsx / 500.tsx from the root segment.\n *\n * If this function throws, the pipeline falls back to a bare\n * `new Response(null, { status: 500 })`.\n */\n renderFallbackError?: (\n error: unknown,\n req: Request,\n responseHeaders: Headers,\n /**\n * The matched route, when the error came after matching. A route.ts\n * match is answered in the API route's JSON format, never a page\n * (design/10-error-handling.md §\"JSON Error Pages\").\n */\n match?: RouteMatch\n ) => Response | Promise<Response>;\n /**\n * Fallback deny page renderer — called when a DenySignal escapes from\n * middleware or the render phase. Renders the appropriate status-code\n * page (403.tsx, 404.tsx, etc.) instead of returning a bare empty response.\n *\n * If this function throws, the pipeline falls back to a bare\n * `new Response(null, { status: denyStatus })`.\n */\n renderDenyFallback?: (\n deny: DenySignal,\n req: Request,\n responseHeaders: Headers,\n /**\n * The matched route, if available. Provided by both the middleware-stage\n * and render-stage catch blocks (matching runs before middleware). When\n * present, the renderer should resolve the deny status file against the\n * matched chain so colocated `403.tsx`/`4xx.tsx`/`401.json` files are\n * picked up. Falls back to the root-only chain when omitted (e.g. for\n * deny()s thrown before route matching could complete). See TIM-822.\n */\n match?: RouteMatch\n ) => Response | Promise<Response>;\n\n /**\n * Server action dispatch — called after proxy.ts runs for POST requests\n * that look like server actions. Returns a Response if the request was\n * handled as an action, or null to fall through to normal routing.\n *\n * `canonicalPath` is the already-decoded canonical pathname — the same\n * value that `handleRequest` and `matchRoute` use. Do NOT re-derive it\n * from `req.url` (which re-encodes).\n *\n * The `reenter` parameter is the full pipeline function (including proxy,\n * ALS, tracing) for the no-JS validation rerender path — the synthetic\n * GET flows through the complete pipeline. Its `cookies` argument becomes\n * that request's parsed cookies (`runWithRequestContext`'s `cookies`\n * option), so the rerender reads the action's post-mutation state without\n * the pipeline needing the same `Request` object to reach it.\n *\n * Moved into the pipeline (TIM-1213) so proxy.ts runs on action POSTs,\n * matching the design doc contract: \"proxy.ts runs on every request,\n * no exclusions.\"\n */\n dispatchAction?: (\n req: Request,\n canonicalPath: string,\n reenter: (req: Request, cookies: Map<string, string>) => Promise<Response>\n ) => Promise<Response | null>;\n}\n\n// ─── Pipeline ──────────────────────────────────────────────────────────────\n\n/**\n * Create the request handler from a pipeline configuration.\n *\n * Returns a function that processes an incoming Request through all pipeline\n * stages and produces a Response. This is the top-level entry point for the\n * server. The body is intentionally small — phase logic lives in\n * `pipeline-phases.ts`. This function only owns the per-request setup that\n * has to wrap the entire dispatch: trace ID, request context ALS, span\n * scope, Server-Timing header emission, and the active-request counter.\n */\nexport function createPipeline(config: PipelineConfig): (req: Request) => Promise<Response> {\n // Resolve the proxy source once. The request hot path calls this closure\n // directly with no discriminant check — the branch is taken here during\n // setup. For the lazy variant, `loader()` still runs per-request so HMR\n // continues to re-import the user's proxy.ts.\n const proxyResolver = makeProxyResolver(config.proxy);\n const slowRequestMs = config.slowRequestMs ?? 3000;\n const serverTiming = config.serverTiming ?? 'total';\n\n // Concurrent request counter — tracks how many requests are in-flight.\n // Logged with each request for diagnosing resource contention.\n let activeRequests = 0;\n\n // Self-reference for re-entry — the no-JS validation rerender path\n // passes a synthetic GET back through the full pipeline (including\n // proxy, ALS, tracing). The inner closure captures `pipelineFn` by\n // name; by the time it's invoked, the const binding is initialized.\n const pipelineFn = async (req: Request, cookies?: Map<string, string>): Promise<Response> => {\n const url = new URL(req.url);\n const method = req.method;\n const path = url.pathname;\n const startTime = performance.now();\n\n // Establish per-request trace ID scope (design/17-logging.md §\"trace_id is Always Set\").\n // This runs before runWithRequestContext so traceId() is available from the\n // very first line of proxy.ts, middleware.ts, and all server code.\n const traceIdValue = generateTraceId();\n\n return runWithTraceId(traceIdValue, async () => {\n // Runs in the request context ALS scope, so getHeaders() and getCookies()\n // work throughout the entire request lifecycle (proxy, middleware, render).\n const inRequestContext = async () => {\n // In dev mode, wrap with timing collector for Server-Timing header.\n // The collector uses ALS so timing entries are per-request.\n const runRequest = async () => {\n logRequestReceived({ method, path });\n\n // Incremented and decremented in one scope, the decrement in\n // `finally`: a rejection that escaped the span used to skip it and\n // leave the request counted as in flight for the life of the\n // process (TIM-1537).\n activeRequests++;\n let concurrency = activeRequests;\n let response: Response;\n try {\n response = await withSpan(\n 'http.server.request',\n { 'http.request.method': method, 'url.path': path },\n async () => {\n // If OTEL is active, the root span now exists — replace the UUID\n // fallback with the real OTEL trace ID for log–trace correlation.\n const otelTraceId = await getOtelTraceId();\n if (otelTraceId) {\n replaceTraceId(otelTraceId);\n }\n\n // Stage 0: Canonicalize URL at the outer boundary — before\n // proxy.ts sees the request. Every layer (proxy, middleware,\n // access, render) must see the same canonical path.\n // See design/07-routing.md §\"URL Canonicalization & Security\".\n const stripTrailingSlash = config.stripTrailingSlash ?? true;\n const canonResult = canonicalize(url.pathname, stripTrailingSlash);\n if (!canonResult.ok) {\n if (isDebug()) {\n console.warn(\n `[timber] URL canonicalization rejected ${method} ${url.pathname} — responding with ${canonResult.status}\\n` +\n ` This usually means the URL contains encoded separators (%2f, %5c),\\n` +\n ` null bytes (%00), path traversal (..), or malformed percent-encoding.`\n );\n }\n // Early returns set the span status themselves: the shared\n // assignment below never runs for them, and a span with\n // none reads as 200 in DevSpanProcessor.\n await setSpanAttribute('http.response.status_code', canonResult.status);\n return new Response(null, { status: canonResult.status });\n }\n const canonicalPath = canonResult.pathname;\n\n // Construct a Request with the canonical URL so proxy.ts sees\n // the same path that route matching will use. This prevents\n // auth bypass via /admin/, /%61dmin, etc.\n let canonicalReq = req;\n if (url.pathname !== canonicalPath) {\n const canonicalUrl = new URL(req.url);\n canonicalUrl.pathname = canonicalPath;\n canonicalReq = new Request(canonicalUrl.toString(), req);\n }\n\n // Stage 0b: CSRF gate — every unsafe-method request, before\n // proxy.ts or any other user code, and before action\n // dispatch, so route.ts handlers are covered too (LOCAL-773).\n const csrfRejection = csrfGate(\n canonicalReq,\n canonicalPath,\n config.csrf ?? {},\n config.matchRoute\n );\n if (csrfRejection) {\n await setSpanAttribute('http.response.status_code', csrfRejection.status);\n return csrfRejection;\n }\n\n // Build the inner handler — runs after proxy, before route\n // matching. Checks for server action POSTs and dispatches them\n // without entering the route match → middleware → render chain.\n // Falls through to handleRequest for normal route handling.\n // TIM-1213: action dispatch is now INSIDE the pipeline so\n // proxy.ts runs on every request, including action POSTs.\n const innerHandler = async (): Promise<Response> => {\n if (config.dispatchAction) {\n const actionResult = await config.dispatchAction(\n canonicalReq,\n canonicalPath,\n pipelineFn\n );\n if (actionResult) return actionResult;\n }\n return handleRequest(config, canonicalReq, method, canonicalPath, true);\n };\n\n let result: Response;\n if (proxyResolver) {\n const outcome = await runProxyPhase(\n config,\n proxyResolver,\n canonicalReq,\n method,\n canonicalPath,\n innerHandler\n );\n result = await outcomeToResponse(config, outcome, {\n req: canonicalReq,\n method,\n path: canonicalPath,\n });\n } else {\n result = await innerHandler();\n }\n\n // Set response status on the root span before it ends —\n // DevSpanProcessor reads this for tree/summary output.\n await setSpanAttribute('http.response.status_code', result.status);\n\n // Vary on exactly the headers the `_rsc` cache key hashes.\n //\n // Those two mechanisms answer the same question — which request\n // headers change this response — so they are the same list, not\n // two lists that happen to agree. A separate hand-written list\n // here drifted from `RSC_KEY_HEADERS` the moment the key set\n // grew, and the drift is invisible: `Vary` is the *fallback*\n // layer, used only when a cache omits the query from its key,\n // which is precisely when nobody is watching (TIM-1268).\n //\n // Why any of it: without `Vary: Accept` a shared cache may serve\n // an RSC Flight payload to a browser expecting HTML, or the\n // reverse (GHSA-wfc6-r584-vfw7, design/13-security.md). The\n // `_rsc` param puts that distinction in the URL, so correctness\n // no longer *depends* on `Vary` — which is opt-in configuration\n // on Cloudflare and CloudFront. `Vary` covers the requests that\n // arrive without the param: a stripped query, a hand-rolled\n // client.\n //\n // It costs no hit rate. Document requests send no `X-Timber-*`\n // header at all, so they collapse to a single cache key; payload\n // requests are already fragmented by these same values via the\n // URL.\n const varyTokens = [...RSC_KEY_HEADERS];\n const existingVary = result.headers.get('Vary');\n const existingTokens = existingVary\n ? existingVary\n .toLowerCase()\n .split(',')\n .map((t) => t.trim())\n : [];\n const newTokens = varyTokens.filter(\n (t) => !existingTokens.includes(t.toLowerCase())\n );\n if (newTokens.length > 0) {\n result.headers.set(\n 'Vary',\n existingVary ? `${existingVary}, ${newTokens.join(', ')}` : newTokens.join(', ')\n );\n }\n\n // A request may only claim an `_rsc` cache key that matches its\n // own headers. The key is predictable by design, so without this\n // a caller could render its own variant under another client's\n // key and have a shared cache store it there (TIM-1268).\n await enforceRscCacheKey(canonicalReq, result);\n\n // Flight payloads must never be sniffable into a renderable\n // type — applied at this single exit so every producer is\n // covered, not just the success path (TIM-1268).\n hardenRscPayloadResponse(result);\n\n // A HEAD response carries the headers its GET would produce and\n // no content (RFC 9110 §9.3.2). Applied at this single exit so\n // every response shape is covered — page render, API route,\n // metadata route, deny page, error page, proxy short-circuit —\n // rather than per-renderer, where it was missing for page\n // renders entirely (TIM-1324). The render still runs: the\n // headers have to be the ones a GET would have sent.\n result = stripHeadBody(result, method);\n\n // Append Server-Timing header based on configured mode.\n // Header mutability is guaranteed by the producer-side clone\n // in `outcomeToResponse` and the metadata-route / auto-sitemap\n // user-handler clones in `handleRequest`, so we can write\n // directly without a runtime probe. See TIM-866.\n if (serverTiming === 'detailed') {\n // Detailed: per-phase breakdown (proxy, middleware, render).\n const timingHeader = getServerTimingHeader();\n if (timingHeader) {\n result.headers.set('Server-Timing', timingHeader);\n }\n } else if (serverTiming === 'total') {\n // Total only: single `total;dur=N` — no phase names.\n // Prevents information disclosure while giving browser\n // DevTools useful timing data.\n const totalMs = Math.round(performance.now() - startTime);\n result.headers.set('Server-Timing', `total;dur=${totalMs}`);\n }\n // serverTiming === false: no header at all\n\n // Wrap the response body with stream-lifecycle timing when\n // detailed mode is on. Logs firstChunk/lastChunk/maxGap/close\n // on stream close — measures the post-flush stream tail that\n // the Server-Timing header can't capture (TIM-1106).\n if (serverTiming === 'detailed' && result.body) {\n result = new Response(wrapResponseWithStreamTiming(result.body, startTime), {\n status: result.status,\n statusText: result.statusText,\n headers: result.headers,\n });\n }\n\n return result;\n }\n );\n } finally {\n concurrency = activeRequests;\n activeRequests--;\n }\n\n // Post-span: structured production logging\n const durationMs = Math.round(performance.now() - startTime);\n const status = response.status;\n logRequestCompleted({ method, path, status, durationMs, concurrency });\n\n if (slowRequestMs > 0 && durationMs > slowRequestMs) {\n logSlowRequest({ method, path, durationMs, threshold: slowRequestMs, concurrency });\n }\n\n return response;\n };\n\n return serverTiming === 'detailed' ? runWithTimingCollector(runRequest) : runRequest();\n };\n return runWithRequestContext(req, inRequestContext, { cookies });\n });\n };\n\n return pipelineFn;\n}\n","/**\n * 103 Early Hints utilities.\n *\n * Early Hints are sent before the final response to let the browser\n * start fetching critical resources (CSS, fonts, JS) while the server\n * is still rendering.\n *\n * The framework collects hints from two sources:\n * 1. Build manifest — CSS, fonts, and JS chunks known at route-match time\n * 2. ctx.earlyHints() — explicit hints added by middleware or route handlers\n *\n * Both are emitted as Link headers. Cloudflare CDN automatically converts\n * Link headers into 103 Early Hints responses.\n *\n * Design docs: 02-rendering-pipeline.md §\"Early Hints (103)\"\n */\n\nimport {\n collectRouteCss,\n collectRouteFonts,\n collectRouteModulepreloads,\n} from './build-manifest.ts';\nimport type { BuildManifest } from './build-manifest.ts';\n\n/** Minimal segment shape needed for early hint collection. */\ninterface SegmentWithFiles {\n layout?: { filePath: string };\n page?: { filePath: string };\n}\n\n// ─── EarlyHint type ───────────────────────────────────────────────────────\n\n/**\n * A single Link header hint for 103 Early Hints.\n *\n * ```ts\n * ctx.earlyHints([\n * { href: '/styles/critical.css', rel: 'preload', as: 'style' },\n * { href: 'https://fonts.googleapis.com', rel: 'preconnect' },\n * ])\n * ```\n */\nexport interface EarlyHint {\n /** The resource URL (absolute or root-relative). */\n href: string;\n /** Link relation — `preload`, `modulepreload`, or `preconnect`. */\n rel: 'preload' | 'modulepreload' | 'preconnect';\n /** Resource type for `preload` hints (omit for `modulepreload` / `preconnect`). */\n as?: 'style' | 'script' | 'font' | 'image' | 'fetch' | 'document';\n /** Crossorigin attribute — required for font preloads per spec. */\n crossOrigin?: 'anonymous' | 'use-credentials';\n /** Fetch priority hint — `high`, `low`, or `auto`. */\n fetchPriority?: 'high' | 'low' | 'auto';\n}\n\n// ─── formatLinkHeader ─────────────────────────────────────────────────────\n\n/**\n * Format a single EarlyHint as a Link header value.\n *\n * Attribute order: `as` before `rel` to match Cloudflare CDN's cached\n * Early Hints format. Cloudflare caches Link headers from 200 responses\n * and re-emits them as 103 Early Hints on subsequent requests. If our\n * attribute order differs from Cloudflare's cached copy, the browser\n * sees two preload headers for the same URL (different attribute order)\n * and warns \"Preload was ignored.\" Matching the order ensures the\n * browser deduplicates them correctly.\n *\n * Examples:\n * `</styles/root.css>; as=style; rel=preload`\n * `</fonts/inter.woff2>; as=font; rel=preload; crossorigin=anonymous`\n * `</_timber/client.js>; rel=modulepreload`\n * `<https://fonts.googleapis.com>; rel=preconnect`\n */\nexport function formatLinkHeader(hint: EarlyHint): string {\n // For preload hints, emit `as` before `rel` to match Cloudflare's\n // cached header format and avoid duplicate preload warnings.\n if (hint.as !== undefined) {\n let value = `<${hint.href}>; as=${hint.as}; rel=${hint.rel}`;\n if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;\n if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;\n return value;\n }\n // For modulepreload / preconnect (no `as`), emit rel first.\n let value = `<${hint.href}>; rel=${hint.rel}`;\n if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;\n if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;\n return value;\n}\n\n// ─── collectEarlyHintHeaders ──────────────────────────────────────────────\n\n/** Options for early hint collection. */\nexport interface EarlyHintOptions {\n /** Skip JS modulepreload hints (e.g. when client JavaScript is disabled). */\n skipJs?: boolean;\n}\n\n/**\n * Collect all Link header strings for a matched route's segment chain.\n *\n * Walks the build manifest to emit hints for:\n * - CSS stylesheets (as=style; rel=preload)\n * - Font assets (as=font; rel=preload; crossorigin)\n * - JS modulepreload hints (rel=modulepreload) — unless skipJs is set\n *\n * Returns formatted Link header strings, deduplicated by URL, root → leaf order.\n * Returns an empty array in dev mode (manifest is empty).\n */\nexport function collectEarlyHintHeaders(\n segments: SegmentWithFiles[],\n manifest: BuildManifest,\n options?: EarlyHintOptions\n): string[] {\n const result: string[] = [];\n // Dedup by URL (href), not by full formatted header string.\n // Different code paths can produce the same URL with different attribute\n // ordering, which would bypass a full-string dedup and produce duplicate\n // Link headers that trigger browser \"preload was ignored\" warnings.\n const seenUrls = new Set<string>();\n\n const add = (url: string, header: string) => {\n if (!seenUrls.has(url)) {\n seenUrls.add(url);\n result.push(header);\n }\n };\n\n // Per-route CSS — as=style; rel=preload\n // The HTML <head> also contains a matching <link rel=\"preload\" as=\"style\">\n // tag so browsers can deduplicate the 103 hint against the HTML tag.\n for (const url of collectRouteCss(segments, manifest)) {\n add(url, formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));\n }\n\n // Fonts — as=font; rel=preload; crossorigin (crossorigin required per spec)\n for (const font of collectRouteFonts(segments, manifest)) {\n add(\n font.href,\n formatLinkHeader({ href: font.href, rel: 'preload', as: 'font', crossOrigin: 'anonymous' })\n );\n }\n\n // JS chunks — rel=modulepreload (skip when client JS is disabled)\n if (!options?.skipJs) {\n for (const url of collectRouteModulepreloads(segments, manifest)) {\n add(url, formatLinkHeader({ href: url, rel: 'modulepreload' }));\n }\n }\n\n return result;\n}\n","/**\n * Per-request 103 Early Hints sender — ALS bridge for platform adapters.\n *\n * The pipeline collects Link headers for CSS, fonts, and JS chunks at\n * route-match time. On platforms that support it (Node.js v18.11+, Bun),\n * the adapter can send these as a 103 Early Hints interim response before\n * the final response is ready.\n *\n * This module provides an ALS-based bridge: the generated entry point\n * (e.g., the Nitro entry) wraps the handler with `runWithEarlyHintsSender`,\n * binding a per-request sender function. The pipeline calls\n * `sendEarlyHints103()` to fire the 103 if a sender is available.\n *\n * On platforms where 103 is handled at the CDN level (e.g., Cloudflare\n * converts Link headers into 103 automatically), no sender is installed\n * and `sendEarlyHints103()` is a no-op.\n *\n * Design doc: 02-rendering-pipeline.md §\"Early Hints (103)\"\n */\n\nimport { earlyHintsSenderAls } from './als-registry.ts';\nimport { swallow } from './logger.ts';\n\n/** Function that sends Link header values as a 103 Early Hints response. */\nexport type EarlyHintsSenderFn = (links: string[]) => void;\n\n/**\n * Run a function with a per-request early hints sender installed.\n *\n * Called by generated entry points (e.g., Nitro node-server/bun) to\n * bind the platform's writeEarlyHints capability for the request duration.\n */\nexport function runWithEarlyHintsSender<T>(sender: EarlyHintsSenderFn, fn: () => T): T {\n return earlyHintsSenderAls.run(sender, fn);\n}\n\n/**\n * Send collected Link headers as a 103 Early Hints response.\n *\n * No-op if no sender is installed for the current request (e.g., on\n * Cloudflare where the CDN handles 103 automatically, or in dev mode).\n *\n * Non-fatal: errors from the sender are caught and silently ignored.\n */\nexport function sendEarlyHints103(links: string[]): void {\n if (!links.length) return;\n const sender = earlyHintsSenderAls.getStore();\n if (!sender) return;\n try {\n sender(links);\n } catch (err) {\n swallow(err, 'early hints 103 send failed');\n }\n}\n","'use client';\n\n/**\n * Reconstitutes a SerializableError into a real Error instance before\n * passing to the user's error component.\n *\n * TSX error pages are 'use client' components that receive { error: Error, digest, reset }.\n * Error objects are not RSC-serializable (React Flight throws \"Only plain objects\n * can be passed to Client Components\"). This wrapper receives the error as a plain\n * SerializableError object, reconstitutes a real Error instance, and passes it\n * to the user's error component — ensuring error instanceof Error works correctly.\n *\n * See design/spike-TIM-565-unify-error-pages.md §\"Edge Case B\"\n * See design/10-error-handling.md §\"RSC → SSR for Error Pages via SerializableError\"\n */\n\nimport { createElement, type ReactNode, type ComponentType } from 'react';\n\n/**\n * Plain-object representation of an Error that can cross the RSC → client boundary.\n * Stack is only included in dev mode (gated by isDevMode() on the server).\n */\nexport interface SerializableError {\n message: string;\n name: string;\n stack?: string;\n}\n\n/**\n * Props for the ErrorReconstituter wrapper component.\n * All props are RSC-serializable:\n * - error: plain object (SerializableError)\n * - digest: the server log's correlation ID for the error, or null\n * - reset: undefined (only meaningful on client after boundary catch)\n * - component: client module reference (RSC Flight serializes as opaque ref)\n * - status / data: set only when error.tsx serves a deny()\n * as the last entry in the 4xx fallback chain — forwarded so dual-shape\n * error.tsx implementations can branch on the deny status (TIM-1081)\n */\ninterface ErrorReconstituterProps {\n error: SerializableError;\n digest: string | null;\n reset: undefined;\n component: ComponentType<{\n error: Error;\n digest: string | null;\n reset: (() => void) | undefined;\n status?: number;\n data?: unknown;\n }>;\n status?: number;\n data?: unknown;\n}\n\n/**\n * Reconstitute a SerializableError into a real Error instance and render\n * the user's error component with the proper props.\n */\nexport function ErrorReconstituter({\n error: serialized,\n digest,\n reset,\n component,\n status,\n data,\n}: ErrorReconstituterProps): ReactNode {\n // Reconstitute a real Error so instanceof checks work in user code.\n // `new Error()` captures a stack of wherever this component renders — in\n // SSR that is the server's bundle paths and React internals. Production\n // serializes no stack (design/13-security.md), so the stack is set to the\n // header line alone: nothing about the server, and the same string in SSR\n // and on the client (TIM-1551).\n const error = Object.assign(new Error(serialized.message), {\n name: serialized.name,\n stack: serialized.stack ?? `${serialized.name}: ${serialized.message}`,\n });\n\n return createElement(component, {\n error,\n digest,\n reset,\n ...(status != null ? { status, data } : {}),\n });\n}\n","/**\n * Deny boundary subsystem — the in-tree DenySignal flow.\n *\n * Three things live together here because they form a single flow:\n *\n * 1. **Chain construction** (`buildDenyPageChain`) — walks the matched\n * segment chain at element-tree build time and produces a list of\n * `DenyPageEntry` records ordered by specificity (specific status →\n * category catch-all → `error.tsx`).\n *\n * 2. **Runtime matching and placement** (`matchDenyEntry`, `placeDenyPage`,\n * `handleCaughtDeny`) — picks the first chain entry whose status filter\n * matches the thrown DenySignal, then decides whether the catch site may\n * render it where it stands. A chain spans the catcher outward to root,\n * so a match may belong to an ancestor segment; rendering it in place\n * would wrap it in every layout in between. Ancestor-owned matches are\n * re-thrown with `ownerKey` stamped on the signal so the error boundary\n * at the owning segment renders it. See TIM-1356.\n *\n * 3. **The page boundary itself** (`PageDenyBoundary`) — the async server\n * component that wraps a server-component page, calls it, and catches\n * `DenySignal` so the deny page renders in-tree (no throw reaches\n * React Flight, single render pass).\n *\n * Plus the ALS helpers (`setDenyStatus` / `getDenyStatus`) the boundary\n * uses to thread the matched status code back to the pipeline so the\n * HTTP status reflects the deny.\n *\n * Folded into one module from the former `deny-page-resolver.ts` and\n * `page-deny-boundary.tsx` (TIM-853) — the names were misleading and the\n * three pieces only made sense together.\n *\n * See design/04-authorization.md, design/10-error-handling.md, TIM-666.\n */\n\nimport { createElement } from 'react';\n\nimport { ErrorReconstituter } from '../client/error-reconstituter.tsx';\nimport type { SerializableError } from '../client/error-reconstituter.tsx';\nimport { StatusPageMarker } from '../client/status-page-marker.tsx';\nimport { requestContextAls } from './als-registry.ts';\nimport { DenySignal } from './primitives.ts';\nimport { isDenySignal } from './signal-identity.ts';\nimport { loadFallbackModule } from './pipeline-helpers.ts';\nimport type { ManifestLoader } from './safe-load.ts';\nimport { withSpan } from './tracing.ts';\nimport { isValidElementType, type LoadedComponent } from './utils/element-type.ts';\nimport type { ManifestSegmentNode } from './route-matcher.ts';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\n/** A single entry in the deny page fallback chain. */\nexport interface DenyPageEntry {\n /** Status code filter: specific (403), category (400 = any 4xx), or null (catch-all). */\n status: number | null;\n /** The component to render (server or client — both work). */\n component: (...args: unknown[]) => unknown;\n /**\n * How the entry matched: a status-code file (404.tsx/4xx.tsx) or the\n * error.tsx catch-all. error.tsx entries render with their documented\n * { error, digest, reset } contract, not bare deny props. See TIM-1081.\n */\n kind: 'status' | 'error';\n /**\n * Position in the segment chain (0 = root, ascending toward leaf).\n * Used by `matchDenyEntry` to reconstruct per-segment ordering for 5xx\n * statuses — `resolve5xx` walks per-segment (status files then error.tsx\n * at each segment before moving outward), while the chain is stored in\n * the 4xx two-pass order. Without this, `deny(503)` resolves to a\n * different file depending on which path serves it. See TIM-1360.\n */\n segmentIndex: number;\n /**\n * Segment key of the segment whose directory holds this file — where the\n * deny page must render, which is not necessarily where it was caught.\n *\n * A chain flattens every segment from the catcher outward to root, so\n * without this a catcher cannot tell a file it owns from an ancestor's,\n * and renders both at its own position — wrapping the deny page in every\n * layout in between (TIM-1356).\n *\n * A **key**, not an index: `computeSegmentKeys` produces the identity the\n * client segment cache already navigates by, and it survives the trip\n * through the Flight digest to a boundary the client mounted on an\n * earlier navigation. A chain position would not — depth varies with\n * route groups and interception.\n *\n * It inherits that key's known collision rather than fixing it: keys reset\n * to `urlPath` at each URL-visible segment, so `(browse)/feed` and\n * `(landing)/feed` are both `/feed` (see `routing/segment-keys.ts`). Two\n * such branches are already indistinguishable to the skip decision and the\n * client cache, so a deny addressed across them can land in the wrong\n * branch's layout. Fixing that means fixing the key for every reader, not\n * minting a second identity here.\n */\n ownerKey: string;\n}\n\n/**\n * What `renderDenyEntry` needs to build the element: which component, and\n * which props contract it expects. Deliberately excludes `ownerKey` — the\n * re-render fallback path builds an entry from a `resolveStatusFile`\n * resolution that already carries the position, and would otherwise have to\n * invent an owner it never reads.\n */\nexport type DenyEntryShape = Pick<DenyPageEntry, 'component' | 'kind'>;\n\n/**\n * Where a matched deny page must render, relative to the catcher that\n * matched it.\n *\n * `render` — the catcher owns the file and is already at the right\n * position. `hoist` — an ancestor owns it; the catcher must re-throw so the\n * boundary at `ownerKey` renders it, outside the layouts in between.\n */\nexport type DenyPlacement =\n | { kind: 'render'; element: React.ReactElement }\n | { kind: 'hoist'; ownerKey: string };\n\n// ─── Chain Construction ──────────────────────────────────────────────────\n\n/**\n * Load a candidate's default export, or null if it cannot be a component.\n *\n * Gated on `isValidElementType` — the same predicate `error-boundary-wrapper.ts`\n * uses to decide whether to create a boundary at all, and deliberately not a\n * second expression of it. A file this walk accepts but that one rejects\n * yields a chain entry whose owner has no boundary, so a deny addressed to it\n * passes every boundary and escapes with nothing to catch it. (Before the two\n * agreed, such an entry instead crashed inside `createElement` when rendered\n * in place.)\n *\n * Agreement is per-file, which is not the same as per-segment: this walk runs\n * over every segment in the chain, while the boundary walk is skipped for a\n * segment the client already has cached. See the skip branch in\n * `route-element-builder.ts` for why that case still lands.\n *\n * See TIM-1356.\n */\nasync function loadChainComponent(\n file: ManifestLoader,\n req: Request,\n segments: ManifestSegmentNode[]\n): Promise<LoadedComponent | null> {\n const mod = await loadFallbackModule(file, req, segments);\n return isValidElementType(mod?.default) ? mod.default : null;\n}\n\n/**\n * Build the deny page fallback chain from the segment chain.\n *\n * Walks segments from `startIndex` outward (toward root) and collects\n * status-code file components in fallback order:\n * 1. Specific status files (403.tsx, 404.tsx) — exact match\n * 2. Category catch-alls (4xx.tsx, 5xx.tsx) — matches any in category\n * 3. error.tsx — catches everything\n *\n * The chain is stored in the 4xx two-pass order (all status files across\n * segments, then all error.tsx), which mirrors `resolve4xx`. For 5xx,\n * `matchDenyEntry` reconstructs the per-segment walk from each entry's\n * `segmentIndex` — matching `resolve5xx`'s single-pass ordering where a\n * leaf `error.tsx` beats a root `5xx.tsx`. See TIM-1360.\n */\nexport async function buildDenyPageChain(\n segments: ManifestSegmentNode[],\n startIndex: number,\n segmentKeys: string[],\n req: Request\n): Promise<DenyPageEntry[]> {\n const chain: DenyPageEntry[] = [];\n\n // Pass 1: Status files (specific + category) across ALL segments.\n // These have higher priority than error.tsx — a root 4xx.tsx should\n // match before a leaf error.tsx. Walking inner → outer ensures the\n // nearest match wins within each priority tier.\n for (let i = startIndex; i >= 0; i--) {\n const segment = segments[i];\n if (!segment.statusFiles) continue;\n\n // Specific status files (403.tsx, 404.tsx, etc.)\n for (const [key, file] of Object.entries(segment.statusFiles)) {\n if (key !== '4xx' && key !== '5xx') {\n const status = parseInt(key, 10);\n if (!isNaN(status)) {\n const component = await loadChainComponent(file, req, segments);\n if (component) {\n chain.push({\n status,\n component,\n kind: 'status',\n segmentIndex: i,\n ownerKey: segmentKeys[i],\n });\n }\n }\n }\n }\n\n // Category catch-alls (4xx.tsx, 5xx.tsx)\n for (const [key, file] of Object.entries(segment.statusFiles)) {\n if (key === '4xx' || key === '5xx') {\n const component = await loadChainComponent(file, req, segments);\n if (component) {\n const categoryStatus = key === '4xx' ? 400 : 500;\n chain.push({\n status: categoryStatus,\n component,\n kind: 'status',\n segmentIndex: i,\n ownerKey: segmentKeys[i],\n });\n }\n }\n }\n }\n\n // Pass 2: error.tsx files — lowest priority catch-all.\n // Only added AFTER all status and legacy files so they never shadow a\n // more specific file from an ancestor segment.\n for (let i = startIndex; i >= 0; i--) {\n const segment = segments[i];\n if (segment.error) {\n const component = await loadChainComponent(segment.error, req, segments);\n if (component) {\n chain.push({\n status: null,\n component,\n kind: 'error',\n segmentIndex: i,\n ownerKey: segmentKeys[i],\n });\n }\n }\n }\n\n return chain;\n}\n\n// ─── Runtime Matcher ──────────────────────────────────────────────────────\n\n/**\n * Find the first deny page in the chain whose status filter matches.\n * Returns null when nothing in the chain accepts this status.\n *\n * For 4xx statuses, the chain's stored order is correct: every status file\n * across all segments (inner→outer) before any error.tsx — so a root\n * `404.tsx` beats a leaf `error.tsx`. This matches `resolve4xx`.\n *\n * For 5xx statuses, the match walks per-segment (inner→outer): at each\n * segment, status files (`503.tsx` → `5xx.tsx`) then `error.tsx`, before\n * moving to the next segment outward. A leaf `error.tsx` therefore beats a\n * root `5xx.tsx` — the intentional inverse of the 4xx chain, matching\n * `resolve5xx`. See TIM-1360.\n */\nexport function matchDenyEntry(chain: DenyPageEntry[], status: number): DenyPageEntry | null {\n return matchDenyEntries(chain, status)[0] ?? null;\n}\n\n/**\n * Return ALL deny page entries whose status filter matches, in traversal\n * order (best match first). `matchDenyEntry` returns only the first;\n * late addressing (TIM-1450) needs the full list so the client can find\n * the first *reachable* owner via its ancestry context.\n */\nexport function matchDenyEntries(chain: DenyPageEntry[], status: number): DenyPageEntry[] {\n if (status >= 500) return matchDenyEntries5xx(chain, status);\n\n const matches: DenyPageEntry[] = [];\n for (const entry of chain) {\n if (entry.status === status) matches.push(entry);\n else if (entry.status === 400 && status >= 400 && status <= 499) matches.push(entry);\n else if (entry.status === null) matches.push(entry);\n }\n return matches;\n}\n\n/**\n * 5xx per-segment walk: at each segment (inner→outer), check status files\n * then error.tsx before moving outward. Mirrors `resolve5xx`.\n */\nfunction matchDenyEntries5xx(chain: DenyPageEntry[], status: number): DenyPageEntry[] {\n const segmentIndices: number[] = [];\n for (const entry of chain) {\n if (!segmentIndices.includes(entry.segmentIndex)) {\n segmentIndices.push(entry.segmentIndex);\n }\n }\n segmentIndices.sort((a, b) => b - a);\n\n const matches: DenyPageEntry[] = [];\n for (const seg of segmentIndices) {\n for (const entry of chain) {\n if (entry.segmentIndex !== seg || entry.kind === 'error') continue;\n if (entry.status === status) matches.push(entry);\n else if (entry.status === 500 && status >= 500 && status <= 599) matches.push(entry);\n }\n for (const entry of chain) {\n if (entry.segmentIndex !== seg || entry.kind !== 'error') continue;\n matches.push(entry);\n }\n }\n return matches;\n}\n\n/**\n * Decide where the deny page for `status` renders, from the perspective of\n * the catch site at `selfKey`.\n *\n * The match itself is unchanged — first entry in fallback order wins, so\n * every path picks the same file. What this adds is the position: a chain\n * built at segment i spans i outward to root, so a matched entry is owned\n * either by the catcher or by one of its ancestors.\n *\n * - Owned by the catcher → `render`. The catcher already sits at the\n * owning segment's position.\n * - Owned by an ancestor → `hoist`. Rendering here would wrap the deny page\n * in every layout between the owner and the catcher. The caller re-throws\n * with `ownerKey` stamped on the signal so the boundary at that segment\n * renders it instead — inside the owner's layout, outside the rest.\n *\n * Returns null when no entry matches; the caller re-throws unannotated and\n * the re-render fallback resolves it.\n *\n * See design/04-authorization.md §\"Where a Deny Page Renders\", TIM-1356.\n */\nexport function placeDenyPage(\n chain: DenyPageEntry[],\n status: number,\n data: unknown,\n selfKey: string | undefined\n): DenyPlacement | null {\n const entry = matchDenyEntry(chain, status);\n if (!entry) return null;\n\n if (entry.ownerKey !== selfKey) {\n return { kind: 'hoist', ownerKey: entry.ownerKey };\n }\n\n // Rendering in place is unaffected: `renderDenyEntry` builds the MDX element\n // here, at catch time, with the real status.\n return { kind: 'render', element: renderDenyEntry(entry, status, data) };\n}\n\n/**\n * Build the element for a matched deny chain entry with the props contract\n * the file's convention documents:\n *\n * - Status-code files: { status, data }\n * - error.tsx (TSX): { error, digest, reset } via ErrorReconstituter, plus\n * { status, data } for dual-shape implementations. Without\n * the Error prop, any error.tsx written per the docs (reading\n * error.message) crashes — turning a clean deny(404) into a 500. TIM-1081.\n * - error.mdx: plain { status } — server component, static content.\n */\nexport function renderDenyEntry(\n entry: DenyEntryShape,\n status: number,\n data: unknown\n): React.ReactElement {\n const h = createElement as (...args: unknown[]) => React.ReactElement;\n // Every deny page the server places — in-tree at the owning catch site, or\n // through the fallback renderers — is a status page the client's segment\n // cache must not learn from, and the marker is how it says so on commit.\n // See client/status-page-marker.tsx (TIM-1495).\n return h(StatusPageMarker, null, renderDenyPage(entry, status, data, h));\n}\n\nfunction renderDenyPage(\n entry: DenyEntryShape,\n status: number,\n data: unknown,\n h: (...args: unknown[]) => React.ReactElement\n): React.ReactElement {\n if (entry.kind !== 'error') {\n return h(entry.component, { status, data });\n }\n\n // The message is derived solely from the status code (already on the\n // wire) — safe to cross the RSC→client boundary in production. No stack,\n // no user data. See design/13-security.md §\"Errors don't leak\".\n const serializableDeny: SerializableError = {\n message: `Access denied with status ${status}`,\n name: 'DenySignal',\n };\n return h(ErrorReconstituter, {\n error: serializableDeny,\n digest: null,\n reset: undefined,\n component: entry.component,\n status,\n data,\n });\n}\n\n/**\n * The whole of what an in-tree catch site does with a `DenySignal`, shared\n * by all three of them (`PageDenyBoundary`, `TracedLayout`, `AccessGate`).\n *\n * Returns the deny page element when this catch site owns the matched file.\n * Otherwise it throws — annotated with `ownerKey` when an ancestor owns the\n * file, bare when nothing matched at all.\n *\n * `setDenyStatus` runs on the hoist path too, *before* the throw, for one\n * case. Normally Flight's `onError` captures the rethrown signal within the\n * renderer's promotion cap, and the pipeline renders the deny page with\n * `deny.status` — the recorded status goes unread. When the signal lands\n * after the cap but within the detection window that follows, the renderer\n * discards it (never promoted) and streams the document it already has;\n * `getDenyStatus()`, read once as the renderer returns, gives that document\n * the deny's 4xx instead of a 200. A deny later than that commits 200. Pinned by\n * `tests/late-hoisted-deny-status.test.ts`. The RSC payload path never\n * reads it — a Flight payload response is always 200 and the row itself\n * carries the deny (TIM-1495).\n *\n * Either branch leaves part of the matched chain unmounted — hoisting sends\n * the render to a boundary that discards everything below it, and a layout\n * that denies returns the deny page instead of its own child outlet. What the\n * client then learns about the tree is decided by the boundary that renders\n * the page, at the commit that puts it on screen (`navigation-commit.ts`).\n */\nexport function handleCaughtDeny(\n chain: DenyPageEntry[] | undefined,\n error: DenySignal,\n selfKey: string | undefined\n): React.ReactElement {\n const placement = chain ? placeDenyPage(chain, error.status, error.data, selfKey) : null;\n\n if (placement?.kind === 'render') {\n setDenyStatus(error.status);\n return placement.element;\n }\n if (placement?.kind === 'hoist') {\n setDenyStatus(error.status);\n error.owners = [placement.ownerKey];\n }\n throw error;\n}\n\n// ─── Page Boundary ────────────────────────────────────────────────────────\n\n/**\n * Async server component that wraps a page call with DenySignal catching.\n *\n * Calls the page component as an async function (the same thing React\n * Flight does internally), awaits it, and catches DenySignal. On catch,\n * renders the matching deny page in-tree. On success, returns the page's\n * rendered output normally.\n *\n * Client component pages ('use client') are NOT wrapped — they can't call\n * deny() (server-only API) and must go through createElement normally.\n *\n * No error reaches React Flight — the Flight stream is clean, SSR succeeds,\n * and the entire request uses a single renderToReadableStream call.\n */\nexport async function PageDenyBoundary({\n Page,\n route,\n denyPages,\n segmentKey,\n}: {\n /** The page server component function. */\n Page: (...args: unknown[]) => unknown;\n /** Route path for OTEL tracing. */\n route: string;\n /** Deny page fallback chain from the segment chain. */\n denyPages: DenyPageEntry[];\n /**\n * Segment key of the leaf. The page renders inside the leaf's layout, so\n * a leaf-owned deny page is already at the right position; anything the\n * chain matched further up is hoisted to its owner.\n */\n segmentKey: string;\n}): Promise<React.ReactElement> {\n try {\n const result = await withSpan('timber.page', { 'timber.route': route }, () => Page({}));\n return result as React.ReactElement;\n } catch (error: unknown) {\n if (isDenySignal(error)) {\n return handleCaughtDeny(denyPages, error, segmentKey);\n }\n throw error;\n }\n}\n\n// ─── ALS Helpers ──────────────────────────────────────────────────────────\n\n/**\n * Set the deny status in the request context ALS.\n * Called from AccessGate / PageDenyBoundary when a DenySignal is caught.\n * The document path reads this after render to set the HTTP status code.\n */\nexport function setDenyStatus(status: number): void {\n const store = requestContextAls.getStore();\n if (store) {\n store.denyStatus = status;\n }\n}\n\n/**\n * Read the deny status from the request context ALS.\n * Returns undefined if no deny was caught during render.\n */\nexport function getDenyStatus(): number | undefined {\n return requestContextAls.getStore()?.denyStatus;\n}\n\n/**\n * Record the first denied segment index in the request context ALS.\n * Called from AccessGate when a DenySignal is caught during render.\n * Only the first (shallowest) denial is recorded — deeper denials are\n * unreachable because the gate short-circuits the subtree.\n * See TIM-1363.\n */\nexport function setFirstDeniedSegmentIndex(index: number): void {\n const store = requestContextAls.getStore();\n if (store && store._firstDeniedSegmentIndex === undefined) {\n store._firstDeniedSegmentIndex = index;\n }\n}\n\n/**\n * Read the first denied segment index from the request context ALS.\n * Returns Infinity if no segment denied during render.\n */\nexport function getFirstDeniedSegmentIndex(): number {\n return requestContextAls.getStore()?._firstDeniedSegmentIndex ?? Infinity;\n}\n","/**\n * AccessGate and SlotAccessGate — framework-injected async server components.\n *\n * AccessGate wraps each segment's layout in the element tree. It calls the\n * segment's access.ts before the layout renders. If access.ts calls deny()\n * or redirect(), the signal propagates as a render-phase throw — caught by\n * the flush controller to produce the correct HTTP status code.\n *\n * SlotAccessGate wraps parallel slot content. On denial, it renders the\n * graceful degradation chain: denied.tsx → default.tsx → null. Slot denial\n * does not affect the HTTP status code.\n *\n * See design/04-authorization.md and design/02-rendering-pipeline.md §\"AccessGate\"\n */\n\nimport { DenySignal, RedirectSignal } from './primitives.ts';\nimport { isDenySignal, isRedirectSignal } from './signal-identity.ts';\nimport { withSpan, setSpanAttribute } from './tracing.ts';\nimport { isDebug } from './debug.ts';\nimport type { DenyPageEntry } from './deny-boundary.ts';\nimport { handleCaughtDeny, setFirstDeniedSegmentIndex } from './deny-boundary.ts';\nimport type { ReactNode } from 'react';\nimport type { LoadedComponent } from './utils/element-type.ts';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\n/**\n * Function that creates a React element. Matches React.createElement signature.\n *\n * `props` is typed as `object | null` rather than `Record<string, unknown>` so\n * that interface types with known keys (e.g. `AccessGateProps`,\n * `ErrorBoundaryProps`) flow through without an explicit index-signature cast.\n */\nexport type CreateElement = (\n type: unknown,\n props: object | null,\n ...children: unknown[]\n) => ReactNode;\n\n/**\n * Framework-injected access gate component.\n *\n * When `verdict` is provided (from the pre-render pass), AccessGate replays\n * the stored result synchronously — no re-execution, no async, immune to\n * Suspense timing. When `verdict` is absent, falls back to calling `accessFn`\n * (backward compat for construction sites that don't run a pre-render pass).\n */\nexport interface AccessGateProps {\n accessFn: () => unknown;\n /** Segment name for dev logging (e.g. \"authenticated\", \"dashboard\"). */\n segmentName?: string;\n /**\n * Segment key of the gated segment (`computeSegmentKeys`). Decides whether\n * a matched deny page renders here or is hoisted to the segment that owns\n * it. Omitted by construction sites that build no deny chains — with no\n * chain there is nothing to place. See TIM-1356.\n */\n segmentKey?: string;\n /**\n * Index of this segment in the matched segment chain. Recorded in ALS\n * when the gate catches a DenySignal so post-render consumers\n * (buildSegmentInfo, X-Timber-Segments) can bound the segment list\n * without a pre-render access pass. See TIM-1363.\n */\n segmentIndex?: number;\n /**\n * Deny page fallback chain. When provided and a DenySignal is caught,\n * AccessGate renders the matching deny page in-tree instead of throwing.\n * This prevents the error from reaching React Flight, eliminating the\n * second render pass. See TIM-666.\n *\n * Omitted for skipped segments — a deny there must hard-navigate to\n * avoid rendering the deny page inside cached layout chrome (TIM-1074).\n */\n denyPages?: DenyPageEntry[];\n /**\n * When true, this gate wraps a skipped segment. On deny, the gate\n * records the deny in ALS and rethrows so the response path can\n * return rscErrorEnvelope for a client hard-navigate.\n */\n skippedSegment?: boolean;\n children: ReactNode;\n}\n\n/**\n * Framework-injected slot access gate component.\n * On denial, renders denied.tsx → default.tsx → null instead of failing the page.\n *\n * DeniedComponent is passed instead of a pre-built element so that\n * SlotAccessGate can forward DenySignal.data as the data prop\n * and slotName as the slot prop after catching the signal.\n */\nexport interface SlotAccessGateProps {\n accessFn: () => unknown;\n /** The denied.tsx component (not a pre-built element). null if no denied.tsx exists. */\n DeniedComponent: LoadedComponent | null;\n /** Slot directory name without @ prefix (e.g. \"admin\", \"sidebar\"). */\n slotName: string;\n /** createElement function for building elements dynamically. */\n createElement: CreateElement;\n defaultFallback: ReactNode;\n children: ReactNode;\n}\n\n// ─── AccessGate ─────────────────────────────────────────────────────────────\n\n/**\n * Framework-injected access gate for segments.\n *\n * Calls accessFn during render — inside `renderToReadableStream`, sharing\n * the same `React.cache` scope as layouts and pages. A `requireUser()`\n * call in access.ts populates the cache; the same call in any layout is\n * a free hit. Access executes exactly once per request. See TIM-1363.\n *\n * access.ts is a pure gate — return values are discarded. The layout below\n * gets the same data by calling the same cached functions (React.cache dedup).\n *\n * On denial the gate renders the matching deny page only when this segment\n * owns it. Because the gate is wrapped OUTSIDE its own layout, that render\n * omits the denying segment's layout — deliberate, and the one place the\n * in-tree path diverges from `renderDenyPage`'s inclusive slice: a layout\n * whose access.ts denied must never run and serialize protected data into\n * the Flight stream (TIM-1074). An ancestor-owned page is hoisted instead,\n * because the gate also sits inside every layout above it and rendering\n * here would wrap the deny page in all of them (TIM-1356).\n *\n * For skipped segments (skippedSegment=true), deny pages are NOT rendered\n * in-tree — the client's cached layout chrome would wrap them incorrectly.\n * Instead, the deny is recorded in ALS and rethrown so the response path\n * can return rscErrorEnvelope for a client hard-navigate.\n */\nexport function AccessGate(props: AccessGateProps): Promise<ReactNode> {\n const { accessFn, segmentName, segmentKey, segmentIndex, denyPages, skippedSegment, children } =\n props;\n\n return accessGateFallback(\n accessFn,\n segmentName,\n segmentKey,\n segmentIndex,\n skippedSegment ? undefined : denyPages,\n skippedSegment,\n children\n );\n}\n\n/**\n * Calls accessFn during render with OTEL instrumentation.\n * Records the first denied segment index in ALS for post-render consumers.\n */\nasync function accessGateFallback(\n accessFn: AccessGateProps['accessFn'],\n segmentName: AccessGateProps['segmentName'],\n segmentKey: AccessGateProps['segmentKey'],\n segmentIndex: AccessGateProps['segmentIndex'],\n denyPages: DenyPageEntry[] | undefined,\n skippedSegment: boolean | undefined,\n children: ReactNode\n): Promise<ReactNode> {\n try {\n await withSpan('timber.access', { 'timber.segment': segmentName ?? 'unknown' }, async () => {\n try {\n await accessFn();\n await setSpanAttribute('timber.result', 'pass');\n } catch (error: unknown) {\n if (isDenySignal(error)) {\n await setSpanAttribute('timber.result', 'deny');\n await setSpanAttribute('timber.deny_status', error.status);\n if (error.sourceFile) {\n await setSpanAttribute('timber.deny_file', error.sourceFile);\n }\n } else if (isRedirectSignal(error)) {\n await setSpanAttribute('timber.result', 'redirect');\n }\n throw error;\n }\n });\n } catch (error: unknown) {\n if (isDenySignal(error)) {\n if (segmentIndex !== undefined) {\n setFirstDeniedSegmentIndex(segmentIndex);\n }\n\n if (skippedSegment) {\n error._hardNavigate = true;\n throw error;\n }\n\n if (denyPages) {\n return handleCaughtDeny(denyPages, error, segmentKey);\n }\n }\n throw error;\n }\n\n return children;\n}\n\n// ─── SlotAccessGate ─────────────────────────────────────────────────────────\n\n/**\n * Framework-injected access gate for parallel slots.\n *\n * On denial, graceful degradation: denied.tsx → default.tsx → null.\n * The HTTP status code is unaffected — slot denial is a UI concern, not\n * a protocol concern. The parent layout and sibling slots still render.\n *\n * DeniedComponent is passed instead of a pre-built element so that\n * DenySignal.data can be forwarded as the data prop\n * and the slot name can be passed as the slot prop. See TIM-488.\n *\n * redirect() in slot access.ts is a dev-mode error — redirecting from a\n * slot doesn't make architectural sense.\n */\nexport async function SlotAccessGate(props: SlotAccessGateProps): Promise<ReactNode> {\n const { accessFn, DeniedComponent, slotName, createElement, defaultFallback, children } = props;\n\n try {\n await accessFn();\n } catch (error: unknown) {\n // DenySignal → graceful degradation (denied.tsx → default.tsx → null)\n // Build the denied element dynamically so DenySignal.data is forwarded.\n if (isDenySignal(error)) {\n return (\n buildDeniedFallback(DeniedComponent, slotName, error.data, createElement) ??\n defaultFallback ??\n null\n );\n }\n\n // RedirectSignal in slot access → dev-mode error.\n // Slot access should use deny(), not redirect(). Redirecting from a\n // slot would redirect the entire page, which breaks the contract that\n // slot failure is graceful degradation.\n if (isRedirectSignal(error)) {\n if (isDebug()) {\n console.error(\n '[timber] redirect() is not allowed in slot access.ts. ' +\n 'Slots use deny() for graceful degradation — denied.tsx → default.tsx → null. ' +\n \"If you need to redirect, move the logic to the parent segment's access.ts.\"\n );\n }\n // In production, treat as a deny — render fallback rather than crash.\n return (\n buildDeniedFallback(DeniedComponent, slotName, undefined, createElement) ??\n defaultFallback ??\n null\n );\n }\n\n // Unhandled error — re-throw so error boundaries can catch it.\n // Dev-mode warning: slot access should use deny(), not throw.\n if (isDebug()) {\n console.warn(\n '[timber] Unhandled error in slot access.ts. ' +\n 'Use deny() for access control, not unhandled throws.',\n error\n );\n }\n throw error;\n }\n\n // Access passed — render slot content.\n return children;\n}\n\n/**\n * Build the denied fallback element dynamically with DenySignal data.\n * Returns null if no DeniedComponent is available.\n */\nfunction buildDeniedFallback(\n DeniedComponent: SlotAccessGateProps['DeniedComponent'],\n slotName: string,\n data: unknown,\n createElement: SlotAccessGateProps['createElement']\n): ReactNode | null {\n if (!DeniedComponent) return null;\n return createElement(DeniedComponent, {\n slot: slotName,\n data,\n });\n}\n","/**\n * Status-code file resolver for timber.js error/denial rendering.\n *\n * Given an HTTP status code and a matched segment chain, resolves the\n * correct file to render by walking the fallback chain described in\n * design/10-error-handling.md §\"Status-Code Files\".\n *\n * **Generic over `TFile`** (TIM-848). Walks `SegmentNode<TFile>` trees\n * regardless of whether `TFile` is the build-time `RouteFile` or the\n * runtime `ManifestFile`. Before TIM-848 there were two near-identical\n * resolvers — one for the Map-based scanner output and one for the\n * object-based runtime manifest. Now there is one.\n *\n * Supports two format families:\n * - 'component' (default): .tsx/.jsx/.mdx status files → React rendering pipeline\n * - 'json': .json status files → raw JSON response, no React\n *\n * Fallback chains operate within the same format family (no cross-format fallback).\n *\n * **Component chain (4xx):**\n * Pass 1 — status files (leaf → root): {status}.tsx → 4xx.tsx\n * Pass 2 — error.tsx (leaf → root)\n * Pass 3 — framework default (returns null)\n *\n * **JSON chain (4xx and 5xx):**\n * Pass 1 — json status files (leaf → root): {status}.json → {category}.json\n * Pass 2 — framework default JSON (returns null, caller provides bare JSON)\n *\n * **5xx component:**\n * Per-segment (leaf → root): {status}.tsx → 5xx.tsx → error.tsx\n * Then framework default (returns null)\n */\n\nimport type { SegmentNode } from '../routing/types.ts';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** How the status-code file was matched. */\nexport type StatusFileKind =\n | 'exact' // e.g. 403.tsx matched status 403\n | 'category' // e.g. 4xx.tsx matched status 403\n | 'error'; // error.tsx as last resort\n\n/** Response format family for status-code resolution. */\nexport type StatusFileFormat = 'component' | 'json';\n\n/** Result of resolving a status-code file for a segment chain. */\nexport interface StatusFileResolution<TFile> {\n /** The matched route file. */\n file: TFile;\n /** The HTTP status code (always the original status, not the file's code). */\n status: number;\n /** How the file was matched. */\n kind: StatusFileKind;\n /** Index into the segments array where the file was found. */\n segmentIndex: number;\n}\n\n/** How a slot denial file was matched. */\nexport type SlotDeniedKind = 'denied' | 'default';\n\n/** Result of resolving a slot denied file. */\nexport interface SlotDeniedResolution<TFile> {\n /** The matched route file (denied.tsx or default.tsx). */\n file: TFile;\n /** Slot name without @ prefix. */\n slotName: string;\n /** How the file was matched. */\n kind: SlotDeniedKind;\n}\n\n// ─── Lookup Helpers ──────────────────────────────────────────────────────\n\n/**\n * Look up `{statusStr}` then `{categoryKey}` (e.g. \"4xx\" / \"5xx\") in a\n * status-file group on a single segment. Shared by all three fallback\n * chains — the only structural difference between component 4xx,\n * component 5xx, and JSON resolution is *which* group is searched and\n * how the per-segment loop is layered around it.\n */\nfunction lookupInGroup<TFile>(\n group: Record<string, TFile> | undefined,\n statusStr: string,\n categoryKey: string,\n segmentIndex: number,\n status: number\n): StatusFileResolution<TFile> | null {\n if (!group) return null;\n const exact = group[statusStr];\n if (exact) return { file: exact, status, kind: 'exact', segmentIndex };\n const category = group[categoryKey];\n if (category) return { file: category, status, kind: 'category', segmentIndex };\n return null;\n}\n\n// ─── Resolver ────────────────────────────────────────────────────────────────\n\n/**\n * Resolve the status-code file to render for a given HTTP status code.\n *\n * Walks the segment chain from leaf to root following the fallback chain\n * defined in design/10-error-handling.md. Returns null if no file is found\n * (caller should render the framework default).\n *\n * @param status - The HTTP status code (4xx or 5xx).\n * @param segments - The matched segment chain from root (index 0) to leaf (last).\n * @param format - The response format family ('component' or 'json'). Defaults to 'component'.\n * @param maxIndex - Optional upper bound on the segment index to search.\n * When set, the resolver only considers segments `0..maxIndex` (inclusive),\n * skipping any segments deeper in the tree. Used by the deny renderers to\n * prevent resolving a status file below a denied segment — matching\n * `buildDenyPageChain`'s start-at-i semantics. The error renderers omit\n * this parameter, so the full chain is searched — a 500 from a leaf page\n * should use the leaf's own `5xx.tsx`. See TIM-1358.\n */\nexport function resolveStatusFile<TFile>(\n status: number,\n segments: ReadonlyArray<SegmentNode<TFile>>,\n format: StatusFileFormat = 'component',\n maxIndex?: number\n): StatusFileResolution<TFile> | null {\n if (status < 400 || status > 599) return null;\n if (format === 'json') return resolveJson(status, segments, maxIndex);\n if (status <= 499) return resolve4xx(status, segments, maxIndex);\n return resolve5xx(status, segments, maxIndex);\n}\n\n/**\n * 4xx component fallback chain — two separate full passes leaf→root.\n *\n * The passes must be separate (not interleaved per-segment) so that a\n * root-level `404.tsx` beats a leaf-level `error.tsx`. The 5xx chain\n * inverts this and is per-segment: a leaf's `error.tsx` beats a root's\n * `5xx.tsx`. This asymmetry is the only reason these two functions exist\n * separately.\n *\n * Pass 1 — {status}.tsx → 4xx.tsx (statusFiles)\n * Pass 2 — error.tsx (error)\n */\nfunction resolve4xx<TFile>(\n status: number,\n segments: ReadonlyArray<SegmentNode<TFile>>,\n maxIndex?: number\n): StatusFileResolution<TFile> | null {\n const statusStr = String(status);\n const start =\n maxIndex !== undefined ? Math.min(segments.length - 1, maxIndex) : segments.length - 1;\n\n for (let i = start; i >= 0; i--) {\n const r = lookupInGroup(segments[i].statusFiles, statusStr, '4xx', i, status);\n if (r) return r;\n }\n\n for (let i = start; i >= 0; i--) {\n const errorFile = segments[i].error;\n if (errorFile) {\n return { file: errorFile, status, kind: 'error', segmentIndex: i };\n }\n }\n\n return null;\n}\n\n/**\n * 5xx component fallback chain — single pass, per-segment leaf→root.\n *\n * At each segment: {status}.tsx → 5xx.tsx → error.tsx. A leaf's\n * `error.tsx` therefore beats a root's `5xx.tsx`, which is the\n * intentional inverse of the 4xx chain.\n */\nfunction resolve5xx<TFile>(\n status: number,\n segments: ReadonlyArray<SegmentNode<TFile>>,\n maxIndex?: number\n): StatusFileResolution<TFile> | null {\n const statusStr = String(status);\n const start =\n maxIndex !== undefined ? Math.min(segments.length - 1, maxIndex) : segments.length - 1;\n\n for (let i = start; i >= 0; i--) {\n const segment = segments[i];\n const r = lookupInGroup(segment.statusFiles, statusStr, '5xx', i, status);\n if (r) return r;\n if (segment.error) {\n return { file: segment.error, status, kind: 'error', segmentIndex: i };\n }\n }\n\n return null;\n}\n\n/**\n * JSON fallback chain (for both 4xx and 5xx) — single pass leaf→root.\n *\n * At each segment: {status}.json → {category}.json. No legacy compat,\n * no error.tsx — the JSON chain terminates at the category catch-all\n * and the caller falls back to a bare-JSON framework default.\n */\nfunction resolveJson<TFile>(\n status: number,\n segments: ReadonlyArray<SegmentNode<TFile>>,\n maxIndex?: number\n): StatusFileResolution<TFile> | null {\n const statusStr = String(status);\n const categoryKey = status >= 500 ? '5xx' : '4xx';\n const start =\n maxIndex !== undefined ? Math.min(segments.length - 1, maxIndex) : segments.length - 1;\n\n for (let i = start; i >= 0; i--) {\n const r = lookupInGroup(segments[i].jsonStatusFiles, statusStr, categoryKey, i, status);\n if (r) return r;\n }\n\n return null;\n}\n\n// ─── Slot Denied Resolver ────────────────────────────────────────────────────\n\n/**\n * Resolve the denial file for a parallel route slot.\n *\n * Slot denial is graceful degradation — no HTTP status on the wire.\n * Fallback chain: denied.tsx → default.tsx → null.\n *\n * @param slotNode - The segment node for the slot (segmentType === 'slot').\n */\nexport function resolveSlotDenied<TFile>(\n slotNode: SegmentNode<TFile>\n): SlotDeniedResolution<TFile> | null {\n const slotName = slotNode.segmentName.replace(/^@/, '');\n\n if (slotNode.denied) {\n return { file: slotNode.denied, slotName, kind: 'denied' };\n }\n\n if (slotNode.default) {\n return { file: slotNode.default, slotName, kind: 'default' };\n }\n\n return null;\n}\n","/**\n * Request body size limits — returns 413 when exceeded.\n * See design/08-forms-and-actions.md §\"FormData Limits\"\n */\n\nexport interface BodyLimitsConfig {\n limits?: {\n actionBodySize?: string;\n uploadBodySize?: string;\n maxFields?: number;\n };\n}\n\nexport type BodyLimitResult = { ok: true } | { ok: false; status: 411 | 413 };\n\nexport type BodyKind = 'action' | 'upload';\n\nconst KB = 1024;\nconst MB = 1024 * KB;\nconst GB = 1024 * MB;\n\nexport const DEFAULT_LIMITS = {\n actionBodySize: 1 * MB,\n uploadBodySize: 10 * MB,\n maxFields: 100,\n} as const;\n\nconst SIZE_PATTERN = /^(\\d+(?:\\.\\d+)?)\\s*(kb|mb|gb)?$/i;\n\n/** Parse a human-readable size string (\"1mb\", \"512kb\", \"1024\") into bytes. */\nexport function parseBodySize(size: string): number {\n const match = SIZE_PATTERN.exec(size.trim());\n if (!match) {\n throw new Error(\n `Invalid body size format: \"${size}\". Expected format like \"1mb\", \"512kb\", or \"1024\".`\n );\n }\n\n const value = Number.parseFloat(match[1]);\n const unit = (match[2] ?? '').toLowerCase();\n\n switch (unit) {\n case 'kb':\n return Math.floor(value * KB);\n case 'mb':\n return Math.floor(value * MB);\n case 'gb':\n return Math.floor(value * GB);\n case '':\n return Math.floor(value);\n default:\n throw new Error(`Unknown size unit: \"${unit}\"`);\n }\n}\n\n/** Strict integer pattern: one or more digits, nothing else. */\nconst STRICT_INTEGER_RE = /^\\d+$/;\n\n/** Check whether a request body exceeds the configured size limit (stateless, no ALS). */\nexport function enforceBodyLimits(\n req: Request,\n kind: BodyKind,\n config: BodyLimitsConfig\n): BodyLimitResult {\n const contentLength = req.headers.get('Content-Length');\n if (!contentLength) {\n // Reject requests without Content-Length — prevents body limit bypass via\n // chunked transfer-encoding. Browsers always send Content-Length for form POSTs.\n return { ok: false, status: 411 };\n }\n\n // Reject malformed values: multiple values (\"100, 999999\"), negative numbers,\n // floats (\"100.5\"), or non-numeric strings. parseInt would silently parse\n // the first number from \"100, 999999\" as 100, letting the real body through.\n const trimmed = contentLength.trim();\n if (!STRICT_INTEGER_RE.test(trimmed)) {\n return { ok: false, status: 411 };\n }\n\n const bodySize = Number.parseInt(trimmed, 10);\n\n const limit = resolveLimit(kind, config);\n return bodySize <= limit ? { ok: true } : { ok: false, status: 413 };\n}\n\n/** Check whether a FormData payload exceeds the configured field count limit. */\nexport function enforceFieldLimit(formData: FormData, config: BodyLimitsConfig): BodyLimitResult {\n const maxFields = config.limits?.maxFields ?? DEFAULT_LIMITS.maxFields;\n // Count unique keys — FormData.keys() yields duplicates for multi-value fields,\n // so we use a Set to count distinct field names.\n const fieldCount = new Set(formData.keys()).size;\n return fieldCount <= maxFields ? { ok: true } : { ok: false, status: 413 };\n}\n\n/**\n * Resolve the byte limit for a given body kind, using config overrides or defaults.\n */\nfunction resolveLimit(kind: BodyKind, config: BodyLimitsConfig): number {\n const userLimits = config.limits;\n\n if (kind === 'action') {\n return userLimits?.actionBodySize\n ? parseBodySize(userLimits.actionBodySize)\n : DEFAULT_LIMITS.actionBodySize;\n }\n\n return userLimits?.uploadBodySize\n ? parseBodySize(userLimits.uploadBodySize)\n : DEFAULT_LIMITS.uploadBodySize;\n}\n","/**\n * Social metadata rendering — Open Graph and Twitter Card meta tags.\n *\n * Extracted from metadata-render.ts to keep files under 500 lines.\n *\n * See design/16-metadata.md\n */\n\nimport type { Metadata } from './types.ts';\nimport type { HeadElement } from './metadata.ts';\n\n/**\n * Render Open Graph metadata into head element descriptors.\n *\n * Handles og:title, og:description, og:image (with dimensions/alt),\n * og:video, og:audio, og:article:author, and other OG properties.\n */\nexport function renderOpenGraph(\n og: NonNullable<Metadata['openGraph']>,\n elements: HeadElement[]\n): void {\n const simpleProps: Array<[string, string | undefined]> = [\n ['og:title', og.title],\n ['og:description', og.description],\n ['og:url', og.url],\n ['og:site_name', og.siteName],\n ['og:locale', og.locale],\n ['og:type', og.type],\n ['og:article:published_time', og.publishedTime],\n ['og:article:modified_time', og.modifiedTime],\n ];\n\n for (const [property, content] of simpleProps) {\n if (content) {\n elements.push({ tag: 'meta', attrs: { property, content } });\n }\n }\n\n // Images — normalize single object to array for uniform handling\n if (og.images) {\n if (typeof og.images === 'string') {\n elements.push({ tag: 'meta', attrs: { property: 'og:image', content: og.images } });\n } else {\n const imgList = Array.isArray(og.images) ? og.images : [og.images];\n for (const img of imgList) {\n elements.push({ tag: 'meta', attrs: { property: 'og:image', content: img.url } });\n if (img.width) {\n elements.push({\n tag: 'meta',\n attrs: { property: 'og:image:width', content: String(img.width) },\n });\n }\n if (img.height) {\n elements.push({\n tag: 'meta',\n attrs: { property: 'og:image:height', content: String(img.height) },\n });\n }\n if (img.alt) {\n elements.push({ tag: 'meta', attrs: { property: 'og:image:alt', content: img.alt } });\n }\n }\n }\n }\n\n // Videos\n if (og.videos) {\n for (const video of og.videos) {\n elements.push({ tag: 'meta', attrs: { property: 'og:video', content: video.url } });\n }\n }\n\n // Audio\n if (og.audio) {\n for (const audio of og.audio) {\n elements.push({ tag: 'meta', attrs: { property: 'og:audio', content: audio.url } });\n }\n }\n\n // Authors\n if (og.authors) {\n for (const author of og.authors) {\n elements.push({\n tag: 'meta',\n attrs: { property: 'og:article:author', content: author },\n });\n }\n }\n}\n\n/**\n * Render Twitter Card metadata into head element descriptors.\n *\n * Handles twitter:card, twitter:site, twitter:title, twitter:image,\n * twitter:player, and twitter:app (per-platform name/id/url).\n */\nexport function renderTwitter(tw: NonNullable<Metadata['twitter']>, elements: HeadElement[]): void {\n const simpleProps: Array<[string, string | undefined]> = [\n ['twitter:card', tw.card],\n ['twitter:site', tw.site],\n ['twitter:site:id', tw.siteId],\n ['twitter:title', tw.title],\n ['twitter:description', tw.description],\n ['twitter:creator', tw.creator],\n ['twitter:creator:id', tw.creatorId],\n ];\n\n for (const [name, content] of simpleProps) {\n if (content) {\n elements.push({ tag: 'meta', attrs: { name, content } });\n }\n }\n\n // Images — normalize single object to array for uniform handling\n if (tw.images) {\n if (typeof tw.images === 'string') {\n elements.push({ tag: 'meta', attrs: { name: 'twitter:image', content: tw.images } });\n } else {\n const imgList = Array.isArray(tw.images) ? tw.images : [tw.images];\n for (const img of imgList) {\n const url = typeof img === 'string' ? img : img.url;\n elements.push({ tag: 'meta', attrs: { name: 'twitter:image', content: url } });\n }\n }\n }\n\n // Player card fields\n if (tw.players) {\n for (const player of tw.players) {\n elements.push({ tag: 'meta', attrs: { name: 'twitter:player', content: player.playerUrl } });\n if (player.width) {\n elements.push({\n tag: 'meta',\n attrs: { name: 'twitter:player:width', content: String(player.width) },\n });\n }\n if (player.height) {\n elements.push({\n tag: 'meta',\n attrs: { name: 'twitter:player:height', content: String(player.height) },\n });\n }\n if (player.streamUrl) {\n elements.push({\n tag: 'meta',\n attrs: { name: 'twitter:player:stream', content: player.streamUrl },\n });\n }\n }\n }\n\n // App card fields — 3 platforms × 3 attributes (name, id, url)\n if (tw.app) {\n const platforms: Array<[keyof NonNullable<typeof tw.app.id>, string]> = [\n ['iPhone', 'iphone'],\n ['iPad', 'ipad'],\n ['googlePlay', 'googleplay'],\n ];\n\n // App name is shared across platforms but the spec uses per-platform names.\n // Emit for each platform that has an ID.\n if (tw.app.name) {\n for (const [key, tag] of platforms) {\n if (tw.app.id?.[key]) {\n elements.push({\n tag: 'meta',\n attrs: { name: `twitter:app:name:${tag}`, content: tw.app.name },\n });\n }\n }\n }\n\n for (const [key, tag] of platforms) {\n const id = tw.app.id?.[key];\n if (id) {\n elements.push({ tag: 'meta', attrs: { name: `twitter:app:id:${tag}`, content: id } });\n }\n }\n\n for (const [key, tag] of platforms) {\n const url = tw.app.url?.[key];\n if (url) {\n elements.push({ tag: 'meta', attrs: { name: `twitter:app:url:${tag}`, content: url } });\n }\n }\n }\n}\n","/**\n * Platform-specific metadata rendering — icons, Apple Web App, App Links, iTunes.\n *\n * Extracted from metadata-render.ts to keep files under 500 lines.\n *\n * See design/16-metadata.md\n */\n\nimport type { Metadata } from './types.ts';\nimport type { HeadElement } from './metadata.ts';\n\n/**\n * Render icon link elements (favicon, shortcut, apple-touch-icon, custom).\n */\nexport function renderIcons(icons: NonNullable<Metadata['icons']>, elements: HeadElement[]): void {\n // Icon\n if (icons.icon) {\n if (typeof icons.icon === 'string') {\n elements.push({ tag: 'link', attrs: { rel: 'icon', href: icons.icon } });\n } else if (Array.isArray(icons.icon)) {\n for (const icon of icons.icon) {\n const attrs: Record<string, string> = { rel: 'icon', href: icon.url };\n if (icon.sizes) attrs.sizes = icon.sizes;\n if (icon.type) attrs.type = icon.type;\n elements.push({ tag: 'link', attrs });\n }\n }\n }\n\n // Shortcut\n if (icons.shortcut) {\n const urls = Array.isArray(icons.shortcut) ? icons.shortcut : [icons.shortcut];\n for (const url of urls) {\n elements.push({ tag: 'link', attrs: { rel: 'shortcut icon', href: url } });\n }\n }\n\n // Apple\n if (icons.apple) {\n if (typeof icons.apple === 'string') {\n elements.push({ tag: 'link', attrs: { rel: 'apple-touch-icon', href: icons.apple } });\n } else if (Array.isArray(icons.apple)) {\n for (const icon of icons.apple) {\n const attrs: Record<string, string> = { rel: 'apple-touch-icon', href: icon.url };\n if (icon.sizes) attrs.sizes = icon.sizes;\n elements.push({ tag: 'link', attrs });\n }\n }\n }\n\n // Other\n if (icons.other) {\n for (const icon of icons.other) {\n const attrs: Record<string, string> = { rel: icon.rel, href: icon.url };\n if (icon.sizes) attrs.sizes = icon.sizes;\n if (icon.type) attrs.type = icon.type;\n elements.push({ tag: 'link', attrs });\n }\n }\n}\n\n/**\n * Render alternate link elements (canonical, hreflang, media, types).\n */\nexport function renderAlternates(\n alternates: NonNullable<Metadata['alternates']>,\n elements: HeadElement[]\n): void {\n if (alternates.canonical) {\n elements.push({ tag: 'link', attrs: { rel: 'canonical', href: alternates.canonical } });\n }\n\n if (alternates.languages) {\n for (const [lang, href] of Object.entries(alternates.languages)) {\n elements.push({\n tag: 'link',\n attrs: { rel: 'alternate', hreflang: lang, href },\n });\n }\n }\n\n if (alternates.media) {\n for (const [media, href] of Object.entries(alternates.media)) {\n elements.push({\n tag: 'link',\n attrs: { rel: 'alternate', media, href },\n });\n }\n }\n\n if (alternates.types) {\n for (const [type, href] of Object.entries(alternates.types)) {\n elements.push({\n tag: 'link',\n attrs: { rel: 'alternate', type, href },\n });\n }\n }\n}\n\n/**\n * Render site verification meta tags (Google, Yahoo, Yandex, custom).\n */\nexport function renderVerification(\n verification: NonNullable<Metadata['verification']>,\n elements: HeadElement[]\n): void {\n const verificationProps: Array<[string, string | undefined]> = [\n ['google-site-verification', verification.google],\n ['y_key', verification.yahoo],\n ['yandex-verification', verification.yandex],\n ];\n\n for (const [name, content] of verificationProps) {\n if (content) {\n elements.push({ tag: 'meta', attrs: { name, content } });\n }\n }\n if (verification.other) {\n for (const [name, value] of Object.entries(verification.other)) {\n const content = Array.isArray(value) ? value.join(', ') : value;\n elements.push({ tag: 'meta', attrs: { name, content } });\n }\n }\n}\n\n/**\n * Render Apple Web App meta tags and startup image links.\n */\nexport function renderAppleWebApp(\n appleWebApp: NonNullable<Metadata['appleWebApp']>,\n elements: HeadElement[]\n): void {\n if (appleWebApp.capable) {\n elements.push({\n tag: 'meta',\n attrs: { name: 'apple-mobile-web-app-capable', content: 'yes' },\n });\n }\n if (appleWebApp.title) {\n elements.push({\n tag: 'meta',\n attrs: { name: 'apple-mobile-web-app-title', content: appleWebApp.title },\n });\n }\n if (appleWebApp.statusBarStyle) {\n elements.push({\n tag: 'meta',\n attrs: {\n name: 'apple-mobile-web-app-status-bar-style',\n content: appleWebApp.statusBarStyle,\n },\n });\n }\n if (appleWebApp.startupImage) {\n const images = Array.isArray(appleWebApp.startupImage)\n ? appleWebApp.startupImage\n : [{ url: appleWebApp.startupImage }];\n for (const img of images) {\n const url = typeof img === 'string' ? img : img.url;\n const attrs: Record<string, string> = { rel: 'apple-touch-startup-image', href: url };\n if (typeof img === 'object' && img.media) {\n attrs.media = img.media;\n }\n elements.push({ tag: 'link', attrs });\n }\n }\n}\n\n/**\n * Render App Links (al:*) meta tags for deep linking across platforms.\n */\nexport function renderAppLinks(\n appLinks: NonNullable<Metadata['appLinks']>,\n elements: HeadElement[]\n): void {\n const platformEntries: Array<[string, Array<Record<string, unknown>> | undefined]> = [\n ['ios', appLinks.ios],\n ['android', appLinks.android],\n ['windows', appLinks.windows],\n ['windows_phone', appLinks.windowsPhone],\n ['windows_universal', appLinks.windowsUniversal],\n ];\n\n for (const [platform, entries] of platformEntries) {\n if (!entries) continue;\n for (const entry of entries) {\n for (const [key, value] of Object.entries(entry)) {\n if (value !== undefined && value !== null) {\n elements.push({\n tag: 'meta',\n attrs: { property: `al:${platform}:${key}`, content: String(value) },\n });\n }\n }\n }\n }\n\n if (appLinks.web) {\n if (appLinks.web.url) {\n elements.push({\n tag: 'meta',\n attrs: { property: 'al:web:url', content: appLinks.web.url },\n });\n }\n if (appLinks.web.shouldFallback !== undefined) {\n elements.push({\n tag: 'meta',\n attrs: {\n property: 'al:web:should_fallback',\n content: appLinks.web.shouldFallback ? 'true' : 'false',\n },\n });\n }\n }\n}\n\n/**\n * Render Apple iTunes smart banner meta tag.\n */\nexport function renderItunes(\n itunes: NonNullable<Metadata['itunes']>,\n elements: HeadElement[]\n): void {\n const parts = [`app-id=${itunes.appId}`];\n if (itunes.affiliateData) parts.push(`affiliate-data=${itunes.affiliateData}`);\n if (itunes.appArgument) parts.push(`app-argument=${itunes.appArgument}`);\n elements.push({\n tag: 'meta',\n attrs: { name: 'apple-itunes-app', content: parts.join(', ') },\n });\n}\n","/**\n * Metadata rendering — converts resolved Metadata into HeadElement descriptors.\n *\n * Extracted from metadata.ts to keep files under 500 lines.\n *\n * See design/16-metadata.md\n */\n\nimport type { Metadata } from './types.ts';\nimport type { HeadElement } from './metadata.ts';\nimport { renderOpenGraph, renderTwitter } from './metadata-social.ts';\nimport {\n renderIcons,\n renderAlternates,\n renderVerification,\n renderAppleWebApp,\n renderAppLinks,\n renderItunes,\n} from './metadata-platform.ts';\n\n// ─── Render to Elements ──────────────────────────────────────────────────────\n\n/**\n * Convert resolved metadata into an array of head element descriptors.\n *\n * Each descriptor has a `tag` ('title', 'meta', 'link') and either\n * `content` (for <title>) or `attrs` (for <meta>/<link>).\n *\n * The framework's MetadataResolver component consumes these descriptors\n * and renders them into the <head>.\n */\nexport function renderMetadataToElements(metadata: Metadata): HeadElement[] {\n const elements: HeadElement[] = [];\n\n // Title\n if (typeof metadata.title === 'string') {\n elements.push({ tag: 'title', content: metadata.title });\n }\n\n // Simple string meta tags\n const simpleMetaProps: Array<[string, string | undefined]> = [\n ['description', metadata.description],\n ['generator', metadata.generator],\n ['application-name', metadata.applicationName],\n ['referrer', metadata.referrer],\n ['category', metadata.category],\n ['creator', metadata.creator],\n ['publisher', metadata.publisher],\n ];\n\n for (const [name, content] of simpleMetaProps) {\n if (content) {\n elements.push({ tag: 'meta', attrs: { name, content } });\n }\n }\n\n // Keywords (array or string)\n if (metadata.keywords) {\n const content = Array.isArray(metadata.keywords)\n ? metadata.keywords.join(', ')\n : metadata.keywords;\n elements.push({ tag: 'meta', attrs: { name: 'keywords', content } });\n }\n\n // Robots\n if (metadata.robots) {\n const content =\n typeof metadata.robots === 'string' ? metadata.robots : renderRobotsObject(metadata.robots);\n elements.push({ tag: 'meta', attrs: { name: 'robots', content } });\n\n // googleBot as separate tag\n if (typeof metadata.robots === 'object' && metadata.robots.googleBot) {\n const gbContent =\n typeof metadata.robots.googleBot === 'string'\n ? metadata.robots.googleBot\n : renderRobotsObject(metadata.robots.googleBot);\n elements.push({ tag: 'meta', attrs: { name: 'googlebot', content: gbContent } });\n }\n }\n\n // Open Graph — inherit title/description from top-level when not set explicitly\n if (metadata.openGraph) {\n const og = { ...metadata.openGraph };\n if (og.title === undefined && typeof metadata.title === 'string') {\n og.title = metadata.title;\n }\n if (og.description === undefined && metadata.description) {\n og.description = metadata.description;\n }\n renderOpenGraph(og, elements);\n }\n\n // Twitter — inherit title/description from openGraph or top-level when not set\n if (metadata.twitter) {\n const tw = { ...metadata.twitter };\n if (tw.title === undefined) {\n tw.title =\n metadata.openGraph?.title !== undefined\n ? metadata.openGraph.title\n : typeof metadata.title === 'string'\n ? metadata.title\n : undefined;\n }\n if (tw.description === undefined) {\n tw.description =\n metadata.openGraph?.description !== undefined\n ? metadata.openGraph.description\n : metadata.description;\n }\n renderTwitter(tw, elements);\n }\n\n // Icons\n if (metadata.icons) {\n renderIcons(metadata.icons, elements);\n }\n\n // Manifest\n if (metadata.manifest) {\n elements.push({ tag: 'link', attrs: { rel: 'manifest', href: metadata.manifest } });\n }\n\n // Alternates\n if (metadata.alternates) {\n renderAlternates(metadata.alternates, elements);\n }\n\n // Verification\n if (metadata.verification) {\n renderVerification(metadata.verification, elements);\n }\n\n // Format detection\n if (metadata.formatDetection) {\n const parts: string[] = [];\n if (metadata.formatDetection.telephone === false) parts.push('telephone=no');\n if (metadata.formatDetection.email === false) parts.push('email=no');\n if (metadata.formatDetection.address === false) parts.push('address=no');\n if (parts.length > 0) {\n elements.push({\n tag: 'meta',\n attrs: { name: 'format-detection', content: parts.join(', ') },\n });\n }\n }\n\n // Authors\n if (metadata.authors) {\n const authorList = Array.isArray(metadata.authors) ? metadata.authors : [metadata.authors];\n for (const author of authorList) {\n if (author.name) {\n elements.push({ tag: 'meta', attrs: { name: 'author', content: author.name } });\n }\n if (author.url) {\n elements.push({ tag: 'link', attrs: { rel: 'author', href: author.url } });\n }\n }\n }\n\n // Apple Web App\n if (metadata.appleWebApp) {\n renderAppleWebApp(metadata.appleWebApp, elements);\n }\n\n // App Links (al:*)\n if (metadata.appLinks) {\n renderAppLinks(metadata.appLinks, elements);\n }\n\n // iTunes\n if (metadata.itunes) {\n renderItunes(metadata.itunes, elements);\n }\n\n // Other (custom meta tags)\n if (metadata.other) {\n for (const [name, value] of Object.entries(metadata.other)) {\n const content = Array.isArray(value) ? value.join(', ') : value;\n elements.push({ tag: 'meta', attrs: { name, content } });\n }\n }\n\n return elements;\n}\n\n// ─── Rendering Helpers ───────────────────────────────────────────────────────\n\nfunction renderRobotsObject(robots: Record<string, unknown>): string {\n const parts: string[] = [];\n if (robots.index === true) parts.push('index');\n if (robots.index === false) parts.push('noindex');\n if (robots.follow === true) parts.push('follow');\n if (robots.follow === false) parts.push('nofollow');\n return parts.join(', ');\n}\n","/**\n * Metadata resolution for timber.js.\n *\n * Resolves metadata from a segment chain (layouts + page), applies title\n * templates, shallow-merges entries, and produces head element descriptors.\n *\n * Resolution happens inside the render pass — React.cache is active,\n * metadata is outside Suspense, and the flush point guarantees completeness.\n *\n * Rendering (Metadata → HeadElement[]) is in metadata-render.ts.\n *\n * See design/16-metadata.md\n */\n\nimport { createElement, Fragment } from 'react';\nimport type { Metadata } from './types.ts';\n\n// Re-export renderMetadataToElements from the rendering module so existing\n// consumers (route-element-builder, tests) can keep importing from here.\nexport { renderMetadataToElements } from './metadata-render.ts';\n\n/**\n * Convert HeadElement descriptors to React elements for Float hoisting.\n *\n * React 19 Float hoists <title>, <meta>, and <link> rendered anywhere in\n * the tree into <head> during SSR, and manages them in document.head\n * during client-side rendering.\n */\nexport function headElementsToReact(elements: HeadElement[]): React.ReactElement {\n const children: React.ReactElement[] = [];\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i];\n if (el.tag === 'title' && el.content !== undefined) {\n children.push(createElement('title', { key: `t${i}` }, el.content));\n } else if (el.attrs) {\n children.push(createElement(el.tag, { key: `h${i}`, ...el.attrs }));\n }\n }\n return createElement(Fragment, null, ...children);\n}\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** A single metadata entry from a layout or page module. */\nexport interface SegmentMetadataEntry {\n /** The resolved metadata object (from static or async `metadata` export). */\n metadata: Metadata;\n /** Whether this entry is from the page (leaf) module. */\n isPage: boolean;\n}\n\n/** Options for resolveMetadata. */\nexport interface ResolveMetadataOptions {\n /**\n * When true, the page's metadata is discarded (simulating a render error)\n * and `<meta name=\"robots\" content=\"noindex\">` is injected.\n */\n errorState?: boolean;\n}\n\n/** A rendered head element descriptor. */\nexport interface HeadElement {\n tag: 'title' | 'meta' | 'link';\n content?: string;\n attrs?: Record<string, string>;\n}\n\n// ─── Title Resolution ────────────────────────────────────────────────────────\n\n/**\n * Resolve a title value with an optional template.\n *\n * - string → apply template if present\n * - { absolute: '...' } → use as-is, skip template\n * - { default: '...' } → use as fallback (no template applied)\n * - undefined → undefined\n */\nexport function resolveTitle(\n title: Metadata['title'],\n template: string | undefined\n): string | undefined {\n if (title === undefined || title === null) {\n return undefined;\n }\n\n if (typeof title === 'string') {\n return template ? template.replace('%s', title) : title;\n }\n\n // Object form\n if (title.absolute !== undefined) {\n return title.absolute;\n }\n\n if (title.default !== undefined) {\n return title.default;\n }\n\n return undefined;\n}\n\n// ─── Metadata Resolution ─────────────────────────────────────────────────────\n\n/**\n * Resolve metadata from a segment chain.\n *\n * Processes entries from root layout to page (in segment order).\n * The merge algorithm:\n * 1. Shallow-merge all keys except title (later wins)\n * 2. Track the most recent title template\n * 3. Resolve the final title using the template\n *\n * In error state, the page entry is dropped and noindex is injected.\n *\n * See design/16-metadata.md §\"Merge Algorithm\"\n */\nexport function resolveMetadata(\n entries: SegmentMetadataEntry[],\n options: ResolveMetadataOptions = {}\n): Metadata {\n const { errorState = false } = options;\n\n const merged: Metadata = {};\n let titleTemplate: string | undefined;\n let lastDefault: string | undefined;\n let rawTitle: Metadata['title'];\n\n for (const { metadata, isPage } of entries) {\n // In error state, skip the page's metadata entirely\n if (errorState && isPage) {\n continue;\n }\n\n // Track title template\n if (metadata.title !== undefined && typeof metadata.title === 'object') {\n if (metadata.title.template !== undefined) {\n titleTemplate = metadata.title.template;\n }\n if (metadata.title.default !== undefined) {\n lastDefault = metadata.title.default;\n }\n }\n\n // Shallow-merge all keys except title\n for (const key of Object.keys(metadata) as Array<keyof Metadata>) {\n if (key === 'title') continue;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (merged as any)[key] = metadata[key];\n }\n\n // Track raw title (will be resolved after the loop)\n if (metadata.title !== undefined) {\n rawTitle = metadata.title;\n }\n }\n\n // In error state, we lost page title — use the most recent default\n if (errorState) {\n rawTitle = lastDefault !== undefined ? { default: lastDefault } : rawTitle;\n // Don't apply template in error state\n titleTemplate = undefined;\n }\n\n // Resolve the final title\n const resolvedTitle = resolveTitle(rawTitle, titleTemplate);\n if (resolvedTitle !== undefined) {\n merged.title = resolvedTitle;\n }\n\n // Error state: inject noindex, overriding any user robots\n if (errorState) {\n merged.robots = 'noindex';\n }\n\n return merged;\n}\n\n// ─── URL Resolution ──────────────────────────────────────────────────────────\n\n/**\n * Check if a string is an absolute URL.\n */\nfunction isAbsoluteUrl(url: string): boolean {\n return url.startsWith('http://') || url.startsWith('https://') || url.startsWith('//');\n}\n\n/**\n * Resolve a relative URL against a base URL.\n */\nfunction resolveUrl(url: string, base: URL): string {\n if (isAbsoluteUrl(url)) return url;\n return new URL(url, base).toString();\n}\n\n/**\n * Resolve relative URLs in metadata fields against metadataBase.\n *\n * Returns a new metadata object with URLs resolved. Absolute URLs are not modified.\n * If metadataBase is not set, returns the metadata unchanged.\n */\nexport function resolveMetadataUrls(metadata: Metadata): Metadata {\n const base = metadata.metadataBase;\n if (!base) return metadata;\n\n const result = { ...metadata };\n\n // Resolve openGraph images\n if (result.openGraph) {\n result.openGraph = { ...result.openGraph };\n if (typeof result.openGraph.images === 'string') {\n result.openGraph.images = resolveUrl(result.openGraph.images, base);\n } else if (Array.isArray(result.openGraph.images)) {\n result.openGraph.images = result.openGraph.images.map((img) => ({\n ...img,\n url: resolveUrl(img.url, base),\n }));\n } else if (result.openGraph.images) {\n // Single object: { url, width?, height?, alt? }\n result.openGraph.images = {\n ...result.openGraph.images,\n url: resolveUrl(result.openGraph.images.url, base),\n };\n }\n if (result.openGraph.url && !isAbsoluteUrl(result.openGraph.url)) {\n result.openGraph.url = resolveUrl(result.openGraph.url, base);\n }\n }\n\n // Resolve twitter images\n if (result.twitter) {\n result.twitter = { ...result.twitter };\n if (typeof result.twitter.images === 'string') {\n result.twitter.images = resolveUrl(result.twitter.images, base);\n } else if (Array.isArray(result.twitter.images)) {\n // Resolve each image URL, preserving the union type structure\n const resolved = result.twitter.images.map((img) =>\n typeof img === 'string' ? resolveUrl(img, base) : { ...img, url: resolveUrl(img.url, base) }\n );\n // If all entries are strings, assign as string[]; otherwise as object[]\n const allStrings = resolved.every((r) => typeof r === 'string');\n result.twitter.images = allStrings\n ? (resolved as string[])\n : (resolved as Array<{ url: string; alt?: string; width?: number; height?: number }>);\n } else if (result.twitter.images) {\n // Single object: { url, alt?, width?, height? }\n result.twitter.images = {\n ...result.twitter.images,\n url: resolveUrl(result.twitter.images.url, base),\n };\n }\n }\n\n // Resolve alternates\n if (result.alternates) {\n result.alternates = { ...result.alternates };\n if (result.alternates.canonical && !isAbsoluteUrl(result.alternates.canonical)) {\n result.alternates.canonical = resolveUrl(result.alternates.canonical, base);\n }\n if (result.alternates.languages) {\n const langs: Record<string, string> = {};\n for (const [lang, url] of Object.entries(result.alternates.languages)) {\n langs[lang] = isAbsoluteUrl(url) ? url : resolveUrl(url, base);\n }\n result.alternates.languages = langs;\n }\n }\n\n // Resolve icon URLs\n if (result.icons) {\n result.icons = { ...result.icons };\n if (typeof result.icons.icon === 'string') {\n result.icons.icon = resolveUrl(result.icons.icon, base);\n } else if (Array.isArray(result.icons.icon)) {\n result.icons.icon = result.icons.icon.map((i) => ({ ...i, url: resolveUrl(i.url, base) }));\n }\n if (typeof result.icons.apple === 'string') {\n result.icons.apple = resolveUrl(result.icons.apple, base);\n } else if (Array.isArray(result.icons.apple)) {\n result.icons.apple = result.icons.apple.map((i) => ({ ...i, url: resolveUrl(i.url, base) }));\n }\n }\n\n return result;\n}\n","/**\n * Route handler for route.ts API endpoints.\n *\n * route.ts files export named HTTP method handlers (GET, POST, etc.).\n * They share the same pipeline (proxy → match → middleware → access → handler)\n * but don't render React trees.\n *\n * See design/07-routing.md §\"route.ts — API Endpoints\"\n */\n\nimport type { RouteContext } from './types.ts';\nimport { stripHeadBody } from './head-response.ts';\nimport { setMutableCookieContext } from './request-context.ts';\nimport { getSetCookieHeaders } from './cookie-context.ts';\nimport { syncCookieJar } from './pipeline-helpers.ts';\n\n// ─── Types ───────────────────────────────────────────────────────────────\n\n/** HTTP methods that route.ts can export as named handlers. */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';\n\n/** A single route handler function — one-arg signature. */\nexport type RouteHandler = (ctx: RouteContext) => Response | Promise<Response>;\n\n/** A route.ts module — named exports for each supported HTTP method. */\nexport type RouteModule = {\n [K in HttpMethod]?: RouteHandler;\n};\n\n/** All recognized HTTP method export names. */\nconst HTTP_METHODS: HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];\n\n// ─── Allowed Methods ─────────────────────────────────────────────────────\n\n/**\n * Resolve the full list of allowed methods for a route module.\n *\n * Includes:\n * - All explicitly exported methods\n * - HEAD (implicit when GET is exported)\n * - OPTIONS (always implicit)\n */\nexport function resolveAllowedMethods(mod: RouteModule): HttpMethod[] {\n const methods: HttpMethod[] = [];\n\n for (const method of HTTP_METHODS) {\n if (method === 'HEAD' || method === 'OPTIONS') continue;\n if (mod[method]) {\n methods.push(method);\n }\n }\n\n // HEAD is implicit when GET is exported\n if (mod.GET && !mod.HEAD) {\n methods.push('HEAD');\n } else if (mod.HEAD) {\n methods.push('HEAD');\n }\n\n // OPTIONS is always implicit\n if (!mod.OPTIONS) {\n methods.push('OPTIONS');\n } else {\n methods.push('OPTIONS');\n }\n\n return methods;\n}\n\n// ─── Route Request Handler ───────────────────────────────────────────────\n\n/**\n * Handle an incoming request against a route.ts module.\n *\n * Dispatches to the named method handler, auto-generates 405/OPTIONS,\n * and merges response headers from ctx.headers.\n */\nexport async function handleRouteRequest(mod: RouteModule, ctx: RouteContext): Promise<Response> {\n const method = ctx.req.method.toUpperCase() as HttpMethod;\n const allowed = resolveAllowedMethods(mod);\n const allowHeader = allowed.join(', ');\n\n // Auto OPTIONS — 204 with Allow header. Merged like any handler response,\n // so a CORS header middleware set reaches the preflight.\n if (method === 'OPTIONS') {\n if (mod.OPTIONS) {\n return runHandler(mod.OPTIONS, ctx);\n }\n return mergeResponseHeaders(\n new Response(null, { status: 204, headers: { Allow: allowHeader } }),\n ctx.headers\n );\n }\n\n // HEAD fallback — dispatch to GET when the module exports no HEAD, so the\n // headers are the ones a GET would produce. The body is stripped by the\n // shared helper (also applied at the pipeline exit, where it is a no-op the\n // second time) rather than open-coded here — one implementation means the\n // discarded stream is cancelled on every path. See TIM-1324.\n if (method === 'HEAD') {\n if (mod.HEAD) {\n return stripHeadBody(await runHandler(mod.HEAD, ctx), method);\n }\n if (mod.GET) {\n return stripHeadBody(await runHandler(mod.GET, ctx), method);\n }\n }\n\n // Dispatch to the named handler\n const handler = mod[method];\n if (!handler) {\n return mergeResponseHeaders(\n new Response(null, { status: 405, headers: { Allow: allowHeader } }),\n ctx.headers\n );\n }\n\n return runHandler(handler, ctx);\n}\n\n/**\n * Run a handler with cookie writes enabled and merge ctx.headers into its\n * response.\n *\n * Cookies (design/29-cookies.md §\"Where Cookies Can Be Set\"): the render\n * phase applied the jar to `ctx.headers` before the handler ran, so on the\n * way out only what the handler changed is synced onto that bag. It happens\n * whether the handler returns or throws, so a cookie set before `redirect()`\n * rides the redirect, and the pipeline's 500 for a throw carries the same\n * bag.\n *\n * Nothing is caught. A signal goes to the pipeline, whose deny fallback\n * answers a route.ts match in JSON and whose redirect outcome sends the 3xx\n * (TIM-1533). Any other error goes to the pipeline, which logs it,\n * reports it to `onRequestError` as phase `'route'`, and answers it in the\n * same format as every other route.ts error (TIM-1537).\n */\nasync function runHandler(handler: RouteHandler, ctx: RouteContext): Promise<Response> {\n const applied = getSetCookieHeaders();\n setMutableCookieContext(true);\n let res: Response;\n try {\n res = await handler(ctx);\n } finally {\n setMutableCookieContext(false);\n syncCookieJar(ctx.headers, applied);\n }\n return mergeResponseHeaders(res, ctx.headers);\n}\n\n/**\n * Merge response headers from ctx.headers into the handler's response.\n * ctx.headers (set by middleware or the handler) are applied to the final response.\n * Handler-set headers take precedence over ctx.headers.\n */\nfunction mergeResponseHeaders(res: Response, ctxHeaders: Headers): Response {\n // If no ctx headers to merge, return as-is\n let hasCtxHeaders = false;\n ctxHeaders.forEach(() => {\n hasCtxHeaders = true;\n });\n if (!hasCtxHeaders) return res;\n\n // Merge: ctx.headers first, then handler response headers override.\n // Set-Cookie needs special handling: Headers.set() replaces all values\n // for a key, but each Set-Cookie must be its own header per RFC 6265 §4.1.\n // Use append for Set-Cookie, set for everything else.\n const merged = new Headers();\n ctxHeaders.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') {\n merged.append(key, value);\n } else {\n merged.set(key, value);\n }\n });\n // Response Set-Cookie headers: use getSetCookie() to preserve individual\n // cookies (forEach joins them with \", \" into one entry).\n const resCookies = res.headers.getSetCookie();\n for (const cookie of resCookies) {\n merged.append('Set-Cookie', cookie);\n }\n res.headers.forEach((value, key) => {\n if (key.toLowerCase() !== 'set-cookie') {\n merged.set(key, value);\n }\n });\n\n return new Response(res.body, {\n status: res.status,\n statusText: res.statusText,\n headers: merged,\n });\n}\n","/**\n * Component cache-key hashing for prebuilt (cache.component) entries.\n *\n * Key: `sha256(canonicalJson({ props, params })).slice(0, 16)` — see\n * design/44-render-at-build-time.md §Cache Key. Both the request-time\n * lookup (prebuilt-runtime.ts) and the post-build capture pass (TIM-1119)\n * MUST use this exact function, or build artifacts become unaddressable.\n *\n * THE IDENTITY CONTRACT (design/44 §Cache Key): cache identity is **JSON\n * value semantics** — two inputs are the same entry iff they are the same\n * JSON value. This is an ALLOWLIST, not a denylist: a value participates\n * in caching iff it is plain JSON data — null, boolean, finite number,\n * string, dense array, or a plain `Object.prototype` object with only\n * enumerable string-keyed data properties — plus `undefined` and `-0`,\n * which hash as distinct sentinels because flight preserves them. Every\n * value outside that domain (functions, symbols, bigints, accessors,\n * hidden or symbol-keyed properties, non-`Object.prototype` prototypes\n * including null, aliased references, sparse arrays, cycles, non-finite\n * numbers) is UNKEYABLE by definition: `computeComponentCacheKey` returns\n * null and the caller renders live — slower, never wrong.\n *\n * The line between rejected and declared-out-of-domain: values are\n * REJECTED when the JSON projection itself would be ambiguous or lossy\n * (hidden/symbol/non-enumerable properties, accessors, exotic\n * prototypes). Observable state that leaves the projection intact — key\n * order, reference identity, descriptor metadata (writable/configurable,\n * frozen/sealed/extensible), proxy behavior — is DECLARED outside\n * cache.component's supported input domain rather than rejected:\n * key-order insensitivity is required for determinism, and rejecting\n * frozen objects would unkey ubiquitous legitimate inputs\n * (Object.freeze'd config props) to defend against components that\n * render differently based on property attributes.\n *\n * Two hard rules for this walk itself: it must be TOTAL (never throw\n * anything but UnkeyableValueError) and SIDE-EFFECT-FREE (descriptor\n * reads only; never invoke user code such as getters).\n *\n * Object keys sort recursively so `{a, b}` and `{b, a}` hash identically\n * (design/13-security.md checklist #14 — cache key determinism; key order\n * is deliberately NOT part of identity).\n */\n\nimport { createHash } from 'node:crypto';\nimport type { CoercedParams } from '../../shared/param-value.ts';\n\nclass UnkeyableValueError extends Error {}\n\nfunction canonicalize(value: unknown, seen: Set<object>): string {\n if (value === null) return 'null';\n switch (typeof value) {\n case 'string':\n return JSON.stringify(value);\n case 'boolean':\n return value ? 'true' : 'false';\n case 'number':\n if (!Number.isFinite(value)) throw new UnkeyableValueError('non-finite number');\n // -0 is distinct: flight preserves it (\"$-0\"), and String(-0) would\n // collapse it to \"0\" (codex review round 4 on PR #835).\n return Object.is(value, -0) ? '-0' : String(value);\n case 'object':\n break;\n case 'undefined':\n // Distinct sentinel, NOT collapsed to null or omitted: flight\n // serialization preserves `undefined` (\"$undefined\"), so a component\n // can render [undefined] differently from [null] and {a: undefined}\n // differently from {}. Bare `undefined` cannot collide with any\n // other canonical output (strings are always quoted). Codex review\n // round 3 on PR #835.\n return 'undefined';\n default:\n // function, symbol, bigint\n throw new UnkeyableValueError(`unsupported type: ${typeof value}`);\n }\n const obj = value as object;\n // Any REPEATED reference — cycle or alias — is unkeyable. Flight\n // preserves reference identity (the second occurrence serializes as a\n // row reference), so a component can observe `props.a === props.b`;\n // hashing an aliased shape identically to a structurally-equal\n // non-aliased one could splice the wrong subtree (codex review round 5\n // on PR #835). Objects are never removed from `seen`: revisiting one\n // anywhere in the walk throws.\n if (seen.has(obj)) throw new UnkeyableValueError('repeated object reference (cycle or alias)');\n seen.add(obj);\n // Hidden own properties — symbol keys and non-enumerable props — are\n // readable by a live-rendered component but invisible to this walk, so\n // two observably different inputs would collide on one key (codex\n // review on PR #835). Unkeyable.\n if (Object.getOwnPropertySymbols(obj).length > 0) {\n throw new UnkeyableValueError('symbol-keyed property');\n }\n {\n if (Array.isArray(obj)) {\n // Dense-array own names are exactly ['0'..'n-1', 'length'] — anything\n // else is a custom expando property this walk would silently drop.\n if (Object.getOwnPropertyNames(obj).length !== obj.length + 1) {\n throw new UnkeyableValueError('non-index array property');\n }\n const parts: string[] = [];\n for (let i = 0; i < obj.length; i++) {\n // Sparse holes are unkeyable: a server component receiving the\n // original array can observe `i in arr`, which no canonical form\n // survives faithfully. (An explicit undefined element is fine —\n // handled by the sentinel above.)\n const desc = Object.getOwnPropertyDescriptor(obj, i);\n if (desc === undefined) throw new UnkeyableValueError('sparse array hole');\n // Accessors are rejected WITHOUT invoking them — a getter may\n // throw or side-effect, and the key walk must never alter a\n // render (codex review on PR #835).\n if (desc.get !== undefined || desc.set !== undefined) {\n throw new UnkeyableValueError('accessor property');\n }\n // Non-enumerable elements are invisible to Object.keys/spread/\n // JSON.stringify — the JSON projection would be ambiguous, same\n // rule as the object branch's keys-vs-names check.\n if (!desc.enumerable) throw new UnkeyableValueError('non-enumerable array element');\n parts.push(canonicalize(desc.value, seen));\n }\n return '[' + parts.join(',') + ']';\n }\n // Allowlist: exactly Object.prototype. Dates, Maps, class instances —\n // and null-prototype objects, which a component can distinguish from\n // literals via Object.getPrototypeOf — are all outside the JSON\n // domain.\n if (Object.getPrototypeOf(obj) !== Object.prototype) {\n throw new UnkeyableValueError('non-plain object');\n }\n const keys = Object.keys(obj).sort();\n if (keys.length !== Object.getOwnPropertyNames(obj).length) {\n throw new UnkeyableValueError('non-enumerable property');\n }\n const parts: string[] = [];\n for (const key of keys) {\n // Descriptor read, not property read: accessors are rejected WITHOUT\n // invoking them — a getter may throw or side-effect, and the key\n // walk must never alter a render (codex review on PR #835).\n const desc = Object.getOwnPropertyDescriptor(obj, key)!;\n if (desc.get !== undefined || desc.set !== undefined) {\n throw new UnkeyableValueError('accessor property');\n }\n parts.push(JSON.stringify(key) + ':' + canonicalize(desc.value, seen));\n }\n return '{' + parts.join(',') + '}';\n }\n}\n\n/**\n * Canonicalize a single value, or null if it is unkeyable. The ONE\n * definition of \"faithfully comparable\" — every prebuilt code path that\n * needs value equality (cache keys, slot-param divergence) goes through\n * this, so the unkeyable rules (accessors, hidden props, aliases,\n * bigints, …) live in exactly one place.\n */\nexport function tryCanonicalize(value: unknown): string | null {\n try {\n return canonicalize(value, new Set());\n } catch (error) {\n return toUnkeyable(error);\n }\n}\n\n/**\n * Totality by construction: ANY throw from the walk means the input is\n * outside the keyable domain. The walk touches only user-controlled\n * values through reflection ops — and a Proxy trap can throw arbitrary\n * errors from any of them (codex review on PR #835) — so converting only\n * UnkeyableValueError would let hostile/exotic inputs abort a render\n * that plain live rendering would have served fine. Unexpected error\n * types are logged for visibility (they would indicate either a proxy\n * trap or a canonicalizer bug) but still degrade to unkeyable.\n */\nfunction toUnkeyable(error: unknown): null {\n if (!(error instanceof UnkeyableValueError)) {\n console.error(\n '[timber] cache key canonicalization threw — treating input as unkeyable:',\n error\n );\n }\n return null;\n}\n\n/**\n * Split a props record into data props (participate in the cache key) and\n * slot values (React-element holes, excluded from the key) per the\n * component's declared `slots` option (TIM-1173).\n *\n * Every DECLARED slot lands in `slotValues` — present or not — because the\n * capture render always injects a SlotOutlet placeholder for each declared\n * slot: the cached shell is identical whether the caller passed the slot\n * or omitted it, so slot presence must not vary the key. `dataProps` is\n * everything else and is what gets hashed.\n *\n * Returns null when the props OBJECT itself is outside the identity\n * contract at the top level — accessors, symbol-keyed or non-enumerable\n * properties, or a non-`Object.prototype` prototype. Splitting such an\n * object would normalize away observable state (and reading an accessor\n * would invoke user code, which this walk must never do) BEFORE\n * `computeComponentCacheKey` gets the chance to reject it — a cached\n * shell could then be served for inputs a live render distinguishes.\n * Null means unkeyable: the caller renders live with the original props.\n * The walk is descriptor-reads only; getters are never invoked. Nested\n * data-prop values still face the full allowlist when hashed.\n */\n/** Create an own enumerable data property — safe for keys like `__proto__`. */\nfunction defineOwn(target: Record<string, unknown>, key: string, value: unknown): void {\n Object.defineProperty(target, key, {\n value,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n}\n\nexport function splitSlotProps(\n props: Record<string, unknown>,\n slots: readonly string[]\n): { dataProps: Record<string, unknown>; slotValues: Record<string, unknown> } | null {\n // TOTAL, like tryCanonicalize: the reflection ops below run against a\n // user-controlled object, and a Proxy trap (getPrototypeOf, ownKeys,\n // getOwnPropertyDescriptor) can throw arbitrarily — that must degrade\n // to unkeyable (live render), not abort the request. toUnkeyable logs\n // the unexpected throw for visibility. Codex P2 on PR #890.\n try {\n if (Object.getPrototypeOf(props) !== Object.prototype) return null;\n if (Object.getOwnPropertySymbols(props).length > 0) return null;\n const slotSet = new Set(slots);\n const dataProps: Record<string, unknown> = {};\n const slotValues: Record<string, unknown> = {};\n // Own-property defines + Object.hasOwn, never assignment or `in`: a\n // prop/slot legitimately named `__proto__` must land as an own data\n // property (assignment would mutate the map's prototype), and an absent\n // slot named `toString`/`constructor` must not read as present through\n // the prototype chain (the provider would then expose the inherited\n // function instead of undefined). Codex P2 on PR #890.\n for (const key of Object.getOwnPropertyNames(props)) {\n const desc = Object.getOwnPropertyDescriptor(props, key);\n if (\n desc === undefined ||\n desc.get !== undefined ||\n desc.set !== undefined ||\n !desc.enumerable\n ) {\n return null;\n }\n defineOwn(slotSet.has(key) ? slotValues : dataProps, key, desc.value);\n }\n for (const slot of slotSet) {\n if (!Object.hasOwn(slotValues, slot)) defineOwn(slotValues, slot, undefined);\n }\n return { dataProps, slotValues };\n } catch (error) {\n return toUnkeyable(error);\n }\n}\n\n/**\n * Compute the cache-entry hash for a component render:\n * `sha256({props, params}).slice(0, 16)` over canonical JSON.\n *\n * Returns null when props (or params) contain unkeyable values — the\n * caller must fall back to dynamic rendering.\n */\nexport function computeComponentCacheKey(\n props: Record<string, unknown>,\n params: CoercedParams\n): string | null {\n let canonical: string;\n try {\n // One shared `seen` set: an object aliased between params and props is\n // just as observable as one aliased within either.\n const seen = new Set<object>();\n // The params RECORD is framework-produced: coerceSegmentParams builds\n // it with Object.create(null) as a prototype-pollution defense\n // (design/13 checklist #36b), uniformly on every request — its\n // prototype is an implementation detail, not user-observable input\n // variation, so the record is normalized to a plain object before the\n // walk (codex P1 on PR #835: rejecting it made every real request\n // unkeyable). Nested VALUES still face the full allowlist, and user\n // props stay strict — a null-prototype prop object remains unkeyable.\n canonical =\n '{\"params\":' +\n canonicalize({ ...params }, seen) +\n ',\"props\":' +\n canonicalize(props, seen) +\n '}';\n } catch (error) {\n return toUnkeyable(error);\n }\n // NOTE(hash choice — DECIDED, TIM-1119): 64 bits of truncated sha256 is\n // the SHIPPED artifact format; the capture pass writes .flight files and\n // manifest entries named by this hash, so changing the width is now a\n // build-artifact format break. The width is adequate: entries are\n // namespaced per component AND per deploy, so birthday odds need ~2^32\n // entries under ONE component to matter, and design/13 #24 already\n // accepts 64-bit non-crypto FNV-1a for data-cache keys on the same\n // namespacing argument. Only revisit (with a format migration) if the\n // phase-3 runtime tier ever stores attacker-influenced keys more\n // aggressively.\n return createHash('sha256').update(canonical).digest('hex').slice(0, 16);\n}\n","/**\n * SlotContext — delivers live slot content to SlotOutlet holes inside\n * cached component shells (TIM-1173).\n *\n * A `cache.component(Fn, { slots: [...] })` shell is captured with a\n * stable <SlotOutlet slot={name} /> client reference in place of each\n * declared slot prop. At request time the revived shell is wrapped in a\n * SlotsProvider carrying the live slot values; each outlet reads its\n * value from this context by name.\n *\n * Providers MERGE per-key with their parent: an inner SlotsProvider\n * inherits the outer's values and overrides only the keys it declares.\n * Two sibling instances each have their own provider and resolve\n * independently. Layouts use a reserved slot name (LAYOUT_CHILDREN_SLOT)\n * that cannot collide with user-declared slot names (TIM-1191).\n *\n * Generalizes the original layout children pattern (TIM-1181) from a\n * single implicit `children` hole on layouts to explicitly declared,\n * named slot props on any cached component. Layouts use this same\n * context with the reserved LAYOUT_CHILDREN_SLOT key (TIM-1191).\n *\n * SINGLETON GUARANTEE: globalThis + Symbol.for — the RSC client bundler\n * can duplicate this module across chunks; globalThis guarantees a single\n * context instance.\n *\n * See design/45-cache-lifetimes.md §Slot Components.\n */\n\n'use client';\n\nimport React, { type ReactNode } from 'react';\n\nexport type SlotValues = Record<string, ReactNode>;\n\nconst CTX_KEY = Symbol.for('__timber_slot_ctx');\n\nfunction getOrCreateContext(): React.Context<SlotValues | null> {\n const existing = (globalThis as Record<symbol, unknown>)[CTX_KEY] as\n | React.Context<SlotValues | null>\n | undefined;\n if (existing !== undefined) return existing;\n if (typeof React.createContext === 'function') {\n const ctx = React.createContext<SlotValues | null>(null);\n (globalThis as Record<symbol, unknown>)[CTX_KEY] = ctx;\n return ctx;\n }\n return undefined as unknown as React.Context<SlotValues | null>;\n}\n\nexport const SlotContext = getOrCreateContext();\n","/**\n * SlotOutlet — the hole in a cached component shell (TIM-1173).\n *\n * At capture time the prebuilt runtime renders the wrapped component with\n * <SlotOutlet slot={name} /> in place of each declared slot prop. Being a\n * client component, it serializes into the flight payload as a stable,\n * deterministic client reference — the same bytes regardless of what live\n * content will fill the hole. At request time the revived shell sits under\n * a SlotsProvider and each outlet reads its live value from SlotContext.\n *\n * See design/45-cache-lifetimes.md §Slot Components.\n */\n\n'use client';\n\nimport { useContext } from 'react';\nimport { SlotContext } from './slot-context.ts';\n\nexport function SlotOutlet({ slot }: { slot: string }) {\n const values = useContext(SlotContext);\n return values ? (values[slot] ?? null) : null;\n}\n","/**\n * SlotsProvider — wraps a revived cached shell to supply live slot content\n * to the SlotOutlet holes inside it (TIM-1173).\n *\n * Values MERGE with the nearest parent provider so that nesting a\n * cache.component SlotsProvider inside a layout SlotsProvider preserves\n * the layout's `children` slot while adding the component's own slots.\n * Inner values override outer ones with the same name (spread order).\n *\n * Tree structure per cached-component instance:\n * SlotsProvider(values={children: <Live />})\n * └── revived shell\n * └── SlotOutlet(slot=\"children\") → reads context → <Live />\n *\n * See design/45-cache-lifetimes.md §Slot Components.\n */\n\n'use client';\n\nimport { createElement, useContext, type ReactNode } from 'react';\nimport { SlotContext, type SlotValues } from './slot-context.ts';\n\ninterface SlotsProviderProps {\n values: SlotValues;\n children: ReactNode;\n}\n\nexport function SlotsProvider({ values, children }: SlotsProviderProps) {\n const parent = useContext(SlotContext);\n const merged = parent ? { ...parent, ...values } : values;\n return createElement(SlotContext.Provider, { value: merged }, children);\n}\n","/**\n * Lifetime declarations of a `cache.component` — `prerender`, `ttl`,\n * `tags` (design/45-cache-lifetimes.md) — and the nesting clamp between\n * two of them (§Nesting Semantics, TIM-1136).\n *\n * The clamp rule lives here once, for both places a capture can embed one\n * wrapped component in another: the post-build capture pass\n * (server/prebuilt-builder.ts) and request-time re-renders\n * (`captureComponentPayload()` in server/prebuilt-runtime.ts, TIM-1545).\n */\n\nimport { splitSlotProps } from './cache-key.ts';\nimport type { NestedWrapperRender } from './capture-state.ts';\nimport type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';\n\n/** Whether the component has a runtime lifetime (ttl or tags). */\nexport function hasRuntimeLifetime(options: PrebuiltComponentOptions): boolean {\n return options.ttl !== undefined || options.tags != null;\n}\n\n/**\n * Resolve tags from options (may be static array or function of props).\n * Function-form tags receive DATA props only — slot props are excluded so\n * the tags fn never sees SlotOutlet placeholders (capture paths pass\n * placeholder-substituted props) and tags stay deterministic per key.\n */\nexport function resolveTags(\n options: PrebuiltComponentOptions,\n props: Record<string, unknown>\n): string[] {\n if (!options.tags) return [];\n if (Array.isArray(options.tags)) return options.tags;\n const slots = options.slots;\n // The split cannot fail here — capture paths pass framework-built shell\n // props — but stay total: fall back to the props as given.\n const fnProps =\n slots && slots.length > 0 ? (splitSlotProps(props, slots)?.dataProps ?? props) : props;\n return options.tags(fnProps);\n}\n\n// ─── Nesting clamp (design/45 §Nesting Semantics) ────────────────────────\n\n/** The entry a capture is producing: its declaration and resolved tags. */\nexport interface CapturedLifetime {\n id: string;\n options: PrebuiltComponentOptions;\n tags: readonly string[];\n}\n\n/**\n * Why an embedded copy of `inner` goes stale inside `outer`, or null when\n * the outer's refreshes cover every refresh channel the inner declares:\n *\n * - `shorterTtl`: the inner's ttl is shorter than the outer's effective\n * lifetime (its ttl, or deploy-long without one).\n * - `missingTags`: tags the inner resolved to that the outer lacks —\n * `revalidateTag` on them refreshes the inner's own entries, never the\n * copy. `null` inner tags (a tags function threw) cannot be proven a\n * subset, so they count as missing.\n *\n * Declaring the inner's tags on the outer is the documented fix, and it\n * silences the tag half by construction.\n */\nfunction clampReasons(\n outer: CapturedLifetime,\n inner: NestedWrapperRender\n): { shorterTtl: boolean; missingTags: string[] | null } | null {\n const outerTtl = outer.options.ttl ?? Infinity;\n const shorterTtl = inner.options.ttl !== undefined && inner.options.ttl < outerTtl;\n const missingTags =\n inner.tags === null ? null : inner.tags.filter((t) => !outer.tags.includes(t));\n if (!shorterTtl && missingTags !== null && missingTags.length === 0) return null;\n return { shorterTtl, missingTags };\n}\n\n/** Render a lifetime declaration for the clamp warning. */\nfunction describeLifetime(\n options: PrebuiltComponentOptions,\n tags: readonly string[] | null\n): string {\n const parts: string[] = [];\n if (options.prerender) parts.push('prerender');\n if (options.ttl !== undefined) parts.push(`ttl: ${options.ttl}`);\n if (tags === null) parts.push('tags: fn');\n else if (tags.length > 0) parts.push(`tags: ${JSON.stringify(tags)}`);\n return parts.join(', ') || 'no lifetime';\n}\n\n/** When the outer entry — and so every copy embedded in it — refreshes. */\nfunction describeRefresh(outer: CapturedLifetime): string {\n const parts: string[] = [];\n if (outer.options.ttl !== undefined) parts.push(`every ${outer.options.ttl}s`);\n if (outer.tags.length > 0) parts.push(`on revalidateTag of its own tags`);\n // Component keys are per-deploy, so every entry refreshes on redeploy.\n parts.push('on redeploy');\n return parts.join(', or ');\n}\n\n/**\n * Warn for each wrapped component embedded in `outer`'s captured payload\n * whose refresh channels the outer cannot honor. Once per (outer, inner)\n * pair for the lifetime of `warnedPairs` — the builder passes one per\n * build, the runtime one per process, since re-renders repeat. The key is\n * the pair alone, not the reason: resolved tags vary with props, and a key\n * that included them would grow with the data. So the first clamp found\n * for a pair is the one reported. Returns the number of warnings emitted.\n */\nexport function warnNestingClamps(\n outer: CapturedLifetime,\n nested: readonly NestedWrapperRender[],\n warnedPairs: Set<string>,\n log: (message: string) => void\n): number {\n let count = 0;\n for (const inner of nested) {\n const reasons = clampReasons(outer, inner);\n if (reasons === null) continue;\n const pairKey = `${outer.id}\\0${inner.innerId}`;\n if (warnedPairs.has(pairKey)) continue;\n warnedPairs.add(pairKey);\n count++;\n const outerLifetime = describeLifetime(outer.options, outer.tags);\n const innerLifetime = describeLifetime(inner.options, inner.tags);\n const consequences: string[] = [];\n if (reasons.missingTags === null) {\n consequences.push(\n `${inner.innerId}'s tags could not be resolved during the capture (its tags function ` +\n `threw or needed request context), so revalidating them may NOT update the embedded copy.`\n );\n } else if (reasons.missingTags.length > 0) {\n const calls = reasons.missingTags.map((t) => `revalidateTag(${JSON.stringify(t)})`);\n consequences.push(\n `${calls.join(', ')} will NOT update the embedded copy; tag ${outer.id} itself if you ` +\n `need that.`\n );\n }\n if (reasons.shorterTtl) {\n consequences.push(\n `${inner.innerId}'s ttl: ${inner.options.ttl} does not apply to the embedded copy.`\n );\n }\n log(\n `[timber] ${inner.innerId} (${innerLifetime}) is embedded in ` +\n `${outer.options.prerender ? 'prerendered' : 'cached'} ${outer.id} — the embedded ` +\n `copy refreshes only when ${outer.id} does (${describeRefresh(outer)}). ` +\n `${consequences.join(' ')} Chain: ${outer.id} (${outerLifetime}) → ${inner.innerId} ` +\n `(${innerLifetime})`\n );\n }\n return count;\n}\n","/**\n * Slot-component helpers for cache.component (TIM-1173).\n *\n * A `slots: ['children', ...]` declaration caches the component's output\n * as a shell with a stable <SlotOutlet slot={name} /> client-reference\n * hole per declared slot prop; live slot content composes in per instance\n * at request time via SlotsProvider/SlotContext. This generalizes the\n * TIM-1181 layout mechanism to explicitly declared, named slots on any\n * cached component. Layouts use the same mechanism with a `children` slot.\n *\n * Both the production wrapper (cache path) and the dev wrapper (no cache,\n * same tree shape for dev/prod parity) build their render from these\n * helpers. See design/45-cache-lifetimes.md §Slot Components.\n */\n\nimport { createElement } from 'react';\n\nimport type { SlotValues } from '../../client/slot-context.ts';\nimport { SlotOutlet } from '../../client/slot-outlet.tsx';\nimport { SlotsProvider } from '../../client/slot-provider.tsx';\nimport { splitSlotProps } from './cache-key.ts';\nimport { hasRuntimeLifetime } from './lifetime.ts';\nimport type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';\n\n/**\n * Framework-internal slot name for layout children. Uses a prefix that\n * cannot collide with user-declared slot names (which are React prop\n * names). Layout children flow through SlotsProvider/SlotOutlet with\n * this key instead of the bare \"children\" key, so a cached component\n * with `slots: ['children']` inside a layout never shadows the layout's\n * own children delivery.\n *\n * Defined here (a server module) rather than in `client/slot-context.ts`\n * (`'use client'`) because RSC's client-reference proxying would replace\n * the string value with a proxy object in the server environment. The\n * client-side SlotOutlet receives this value via props, so it doesn't\n * need the constant. See TIM-1191.\n */\nexport const LAYOUT_CHILDREN_SLOT = '\\0timber:children';\n\n/**\n * Is this value the framework-injected layout children slot outlet\n * (`<SlotOutlet slot={LAYOUT_CHILDREN_SLOT} />`)? Layout components\n * receive this as their `children` prop — a stable client reference\n * whose cache key is stripped so layout `cache.component` hits work\n * (design/45 §Layout Propagation).\n *\n * Uses a framework-reserved slot name (LAYOUT_CHILDREN_SLOT) that\n * cannot collide with user-declared slot names, preventing context\n * shadowing when a cached component with its own SlotsProvider is\n * nested inside a layout. See TIM-1191.\n *\n * Total: the probes run against a user-controlled value, and a Proxy\n * trap can throw — that must classify as \"not the outlet\" (the\n * canonicalizer then rejects the value as unkeyable → live render), not\n * abort the request (codex P2 on PR #890).\n */\nexport function isChildrenSlotOutletElement(value: unknown): boolean {\n try {\n if (value == null || typeof value !== 'object') return false;\n if (!('type' in value)) return false;\n const el = value as { type: unknown; props?: { slot?: unknown } };\n return el.type === SlotOutlet && el.props?.slot === LAYOUT_CHILDREN_SLOT;\n } catch {\n return false;\n }\n}\n\n/**\n * `props` without the framework-injected children outlet — the key props\n * of a render. The outlet is the same client reference on every request,\n * so it never varies the cache key; user-provided children stay (and\n * leave the props unkeyable). See design/45 §Layout Propagation, TIM-1181.\n */\nexport function withoutChildrenOutlet(props: Record<string, unknown>): Record<string, unknown> {\n if (!isChildrenSlotOutletElement(props.children)) return props;\n const { children: _children, ...rest } = props;\n return rest;\n}\n\n/**\n * Outcome of validating a `slots` declaration at registration time.\n *\n * - `none` — not declared (or an empty array): plain non-slot component.\n * - `disabled` — declared but unusable (malformed shape, or missing the\n * required runtime lifetime): warned once here (module load); the\n * component falls back WHOLESALE to non-slot semantics — the caller\n * strips `slots` from the options and every other option (including\n * `prerender`) keeps its normal meaning. Safe by construction:\n * element-valued props are unkeyable on the non-slot path, so renders\n * with slot content go live. Slower, never wrong.\n * - `active` — usable slot names.\n */\nexport type SlotResolution = { kind: 'none' | 'disabled' } | { kind: 'active'; slots: string[] };\n\n/**\n * Dense array of non-empty strings — no holes, no non-string entries.\n * Total: the reads run against a user-controlled value at module load,\n * and a throwing Proxy trap must classify as invalid, not crash startup.\n */\nfunction isDenseStringArray(value: unknown): value is string[] {\n try {\n if (!Array.isArray(value)) return false;\n for (let i = 0; i < value.length; i++) {\n if (!Object.hasOwn(value, i)) return false; // sparse hole\n const entry: unknown = value[i];\n if (typeof entry !== 'string' || entry.length === 0) return false;\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Validate the `slots` option. Both the production and dev wrappers gate\n * on this — slot substitution is active in dev exactly when it would be\n * active in production, so the tree shape a component sees never\n * diverges between the two.\n */\nexport function resolveSlotNames(id: string, options: PrebuiltComponentOptions): SlotResolution {\n const slots = options.slots;\n if (slots === undefined) return { kind: 'none' };\n // Shape first — a non-array (null, object, …) must not reach a .length\n // or iteration and crash module load over an option typo. Explicit\n // index walk with Object.hasOwn: Array.prototype.every skips sparse\n // holes, which would let `slots[1] = 'children'` on an empty array pass\n // as active and flow an undefined slot into the shell (codex P2 on\n // PR #890).\n if (!isDenseStringArray(slots)) {\n console.warn(\n `[timber] cache.component \"${id}\": invalid slots declaration — expected ` +\n `an array of non-empty prop-name strings. Slot caching is disabled.`\n );\n return { kind: 'disabled' };\n }\n if (slots.length === 0) return { kind: 'none' };\n if (!hasRuntimeLifetime(options)) {\n console.warn(\n `[timber] cache.component \"${id}\": slots require a runtime lifetime ` +\n `(ttl and/or tags). Slot caching is disabled.`\n );\n return { kind: 'disabled' };\n }\n return { kind: 'active', slots };\n}\n\nexport interface SlotRender {\n /** Props the shell renders with: data props + a SlotOutlet per slot. */\n shellProps: Record<string, unknown>;\n /** Non-slot props — the only props that participate in the cache key. */\n dataProps: Record<string, unknown>;\n /** Live slot content, keyed by slot name, for the SlotsProvider. */\n slotValues: Record<string, unknown>;\n}\n\n/**\n * Split the live props into the cacheable shell render (data props plus a\n * deterministic SlotOutlet placeholder per declared slot — identical\n * whether or not the caller passed the slot) and the per-instance live\n * slot values.\n *\n * Null when the props object itself is unkeyable at the top level\n * (accessors, hidden properties, exotic prototype — see splitSlotProps):\n * the caller must render live with the original props.\n */\nexport function prepareSlotRender(\n props: Record<string, unknown>,\n slots: readonly string[]\n): SlotRender | null {\n const split = splitSlotProps(props ?? {}, slots);\n if (split === null) return null;\n const { dataProps, slotValues } = split;\n // Spread + defineProperty, not assignment: a slot named `__proto__`\n // must become an own property, not mutate the shell props' prototype\n // (spread uses CreateDataProperty, so it is already safe).\n const shellProps: Record<string, unknown> = { ...dataProps };\n for (const slot of slots) {\n Object.defineProperty(shellProps, slot, {\n value: createElement(SlotOutlet, { slot }),\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n return { shellProps, dataProps, slotValues };\n}\n\n/**\n * Wrap a rendered shell (revived payload or live element) in a\n * per-instance SlotsProvider feeding the live values to its outlets.\n */\nexport function wrapInSlotsProvider(\n shell: unknown,\n slotValues: Record<string, unknown>\n): React.ReactElement {\n // children passed as a prop, not a JSX child — the shell is `unknown`\n // to the type system. Same pattern as route-element-builder's `h` alias\n // for SlotsProvider.\n const h = createElement as (...args: unknown[]) => React.ReactElement;\n return h(SlotsProvider, { values: slotValues as SlotValues, children: shell });\n}\n","/**\n * Key-discipline diagnostic for cache.component (design/45 §Enforcement).\n *\n * Runtime-tier cached components MAY read request context, but the cache\n * key is computed from props and segment params only — request-derived\n * values in cached output are the data-leak danger zone (design/06\n * security note). During a capture render the ALS store is wrapped in a\n * transparent observing proxy; any request-context read produces a\n * structured, rate-limited production diagnostic.\n *\n * The diagnostic fires per offending component, rate-limited to once per\n * interval (default 60 s) — not once per process. This ensures the\n * signal stays visible in log aggregators across restarts and deploys.\n *\n * When `strictKeyDiscipline` is enabled (via timber.config.ts\n * `cache.strictKeyDiscipline: true`), the diagnostic is promoted to a\n * thrown error that prevents the tainted payload from being cached.\n */\n\nimport type { RequestContextStore } from '../als-registry.ts';\nimport { getLogger } from '../logger.ts';\n\nconst REQUEST_CONTEXT_FIELDS: Record<string, string> = {\n headers: 'headers()',\n parsedCookies: 'cookies()',\n searchParams: 'searchParams',\n};\n\n/** Rate-limit interval: one diagnostic per component per 60 seconds. */\nconst RATE_LIMIT_MS = 60_000;\n\n/** Last emission timestamp per component ID. */\nconst lastEmitted = new Map<string, number>();\n\nlet strict = false;\n\n/**\n * Configure strict key-discipline mode. When true, a violation throws\n * instead of logging — the tainted payload is never cached.\n * Called at boot from the RSC entry with the resolved config value.\n */\nexport function setKeyDisciplineStrict(enabled: boolean): void {\n strict = enabled;\n}\n\n/**\n * Whether the proxy should be created for this component on this render.\n * Returns true when strict mode is on (always check) or enough time has\n * elapsed since the last diagnostic for this component.\n */\nexport function shouldCheckKeyDiscipline(id: string): boolean {\n if (strict) return true;\n const last = lastEmitted.get(id);\n if (last === undefined) return true;\n return Date.now() - last >= RATE_LIMIT_MS;\n}\n\n/**\n * Wrap a store with a proxy that records per-request field access.\n * The proxy forwards all reads/writes transparently — it only observes.\n */\nexport function createKeyDisciplineProxy(store: RequestContextStore): {\n proxy: RequestContextStore;\n accessedApis: Set<string>;\n} {\n const accessedApis = new Set<string>();\n const proxy = new Proxy(store, {\n get(target, prop, receiver) {\n const api = REQUEST_CONTEXT_FIELDS[prop as string];\n if (api) accessedApis.add(api);\n return Reflect.get(target, prop, receiver);\n },\n });\n return { proxy, accessedApis };\n}\n\n/**\n * Emit the key-discipline diagnostic or throw in strict mode.\n *\n * In strict mode: throws an error so the tainted payload is never cached.\n * In default mode: emits a structured error-level diagnostic through the\n * logger (same path as render errors), rate-limited per component.\n */\nexport function emitKeyDisciplineWarning(id: string, apis: Set<string>): void {\n const apiList = Array.from(apis).join(', ');\n\n if (strict) {\n throw new Error(\n `[timber] cache.component key-discipline violation: \"${id}\" reads ${apiList} ` +\n `during a cache capture render. The cache key does not include ` +\n `request-derived values — caching this output would serve one ` +\n `user's data to another. Either pass request-derived values as ` +\n `props (included in the cache key) or remove the ${apiList} call. ` +\n `To downgrade this to a warning, set cache.strictKeyDiscipline: false ` +\n `in timber.config.ts.`\n );\n }\n\n const now = Date.now();\n const last = lastEmitted.get(id);\n if (last !== undefined && now - last < RATE_LIMIT_MS) return;\n lastEmitted.set(id, now);\n\n getLogger().error('cache.component cross-user data leak risk', {\n component: id,\n accessedApis: Array.from(apis),\n message:\n `cache.component \"${id}\" reads ${apiList} but the cache key is ` +\n `computed from props and segment params only. If the output varies ` +\n `by ${apiList}, different users may see each other's cached content. ` +\n `Either pass request-derived values as props (included in the cache ` +\n `key) or remove the ${apiList} call.`,\n });\n}\n\n/**\n * Reset all diagnostic state. Exported for tests only.\n */\nexport function resetKeyDisciplineState(): void {\n lastEmitted.clear();\n strict = false;\n}\n","/**\n * Capture state — the channel between a payload capture and the\n * `__prebuilt` wrappers that render inside it (server/prebuilt-runtime.ts).\n *\n * Two callers capture a wrapped component's flight payload:\n *\n * - **Build time**: the post-build capture pass (server/prebuilt-builder.ts)\n * renders each registry entry in turn.\n * - **Request time**: `captureComponentPayload()` in prebuilt-runtime.ts\n * renders a component in isolation for an inline re-render (full miss,\n * stale entry, tombstone) or an SWR background re-render. These run\n * concurrently with other requests' renders — and with each other.\n *\n * During a capture, the component's subtree may render OTHER wrapped\n * components. Those inner wrappers render live and their output is baked\n * flat into the outer entry — the nesting clamp of\n * design/45-cache-lifetimes.md §Nesting Semantics (TIM-1136). The wrapper\n * reports every render that happens inside a capture:\n *\n * - **Cycle**: the inner render IS the entry being captured — same\n * component id AND same props key (TIM-1547). Left alone this recurses\n * until the render times out; instead the wrapper throws\n * `PrebuiltCaptureCycleError`, failing that entry with an error naming\n * the cycle (build continues per doc 44 skip-and-report policy; at\n * request time the re-render fails and is not cached, and the wrapper\n * falls back as for any failed re-render). A component that renders\n * itself with different props (a comment thread, a tree) is legitimate\n * recursion with a base case and bakes flat like any other nesting.\n * - **Nesting**: any other wrapper render is recorded per inner component\n * with the tags it resolved to. Both capture callers run the clamp rule\n * over those records when the entry completes (prebuilt/lifetime.ts).\n *\n * Identity is the capture ROOT only. A wrapper cannot see the wrappers\n * between it and the root: Flight renders a component's children after\n * the wrapper has returned, in Flight's own async context, not in a frame\n * the wrapper could enter. So a same-key cycle that closes below the root\n * (`A(p1) → A(p2) → A(p2) → …`) is not detected here; it is also an\n * infinite recursion without caching, and the capture's render timeout\n * fails it.\n *\n * The props key is the props half of the cache key (data props only,\n * framework children outlet stripped — the same inputs the cache key\n * hashes). The params half is left out: every render inside one capture\n * reads the same segment params, so props decide identity. Unkeyable props\n * (live React elements, …) cannot be proven identical and are never a\n * cycle.\n *\n * Each capture's state lives in an AsyncLocalStorage store entered by\n * `CaptureScope.run()`, so it is visible only to renders started inside\n * that capture — including work Flight resumes after an await, which runs\n * in the context the awaited promise was created in. A concurrent request\n * rendering the same component is not a cycle, and a concurrent request\n * rendering a different cached component still revives it from cache\n * instead of baking it live (TIM-1536). Outside any capture\n * `noteWrapperRender` is a single store lookup.\n */\n\nimport {\n prebuiltCaptureAls,\n requestContextAls,\n type PrebuiltCaptureStore,\n} from '../als-registry.ts';\nimport type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';\nimport { computeComponentCacheKey, splitSlotProps } from './cache-key.ts';\nimport { resolveTags } from './lifetime.ts';\nimport { withoutChildrenOutlet } from './slots.ts';\n\n/** A wrapped component that rendered inside an active capture. */\nexport interface NestedWrapperRender {\n innerId: string;\n options: PrebuiltComponentOptions;\n /**\n * Every tag the inner resolved to across its renders in this capture;\n * null when its tags function threw (the tags are unknown).\n */\n tags: string[] | null;\n}\n\n/** Per-inner record kept while the capture runs. */\nexport interface NestedRecord {\n options: PrebuiltComponentOptions;\n tags: Set<string> | null;\n}\n\n/** Thrown by the wrapper when a capture renders its own entry. */\nexport class PrebuiltCaptureCycleError extends Error {\n constructor(componentId: string) {\n super(\n `[timber] cache.component \"${componentId}\" renders itself with the same props ` +\n `(directly or through other components) — capturing its payload would recurse ` +\n `forever. Remove the cycle or stop caching this component with cache.component.`\n );\n this.name = 'PrebuiltCaptureCycleError';\n }\n}\n\n/** One capture's state, entered for the duration of its render. */\nexport interface CaptureScope {\n /**\n * Run `fn` inside this capture. Flight renders in the async context it\n * was started (and pinged) from, so the render must be CREATED inside\n * `run`; every wrapper it renders then sees this capture.\n */\n run<T>(fn: () => T): T;\n /** Wrapped components that rendered inside this capture so far. */\n nestedRenders(): NestedWrapperRender[];\n}\n\n/**\n * The props half of a render's cache key, or null when unkeyable. Same\n * inputs `tryRevivePayload` hashes: data props only for slot components,\n * the framework-injected children outlet stripped.\n */\nfunction propsKey(\n options: PrebuiltComponentOptions,\n props: Record<string, unknown>\n): string | null {\n let keyProps = props;\n if (options.slots && options.slots.length > 0) {\n const split = splitSlotProps(props, options.slots);\n if (split === null) return null;\n keyProps = split.dataProps;\n }\n return computeComponentCacheKey(withoutChildrenOutlet(keyProps), {});\n}\n\n/**\n * Open a capture of component `outerId` rendered with `props`. Its state\n * ends with the scope object.\n */\nexport function createCaptureScope(\n outerId: string,\n options: PrebuiltComponentOptions,\n props: Record<string, unknown>\n): CaptureScope {\n const store: PrebuiltCaptureStore = {\n outerId,\n outerPropsKey: propsKey(options, props),\n nested: new Map(),\n };\n return {\n run: (fn) => prebuiltCaptureAls.run(store, fn),\n nestedRenders: () =>\n Array.from(store.nested, ([innerId, record]) => ({\n innerId,\n options: record.options,\n tags: record.tags && Array.from(record.tags),\n })),\n };\n}\n\n/** Whether the current render is inside a capture. */\nexport function isCaptureActive(): boolean {\n return prebuiltCaptureAls.getStore() !== undefined;\n}\n\n/**\n * Called by the `__prebuilt` wrapper on every render. No-op outside a\n * capture. Throws `PrebuiltCaptureCycleError` when the render is the\n * entry the enclosing capture is producing.\n */\nexport function noteWrapperRender(\n innerId: string,\n options: PrebuiltComponentOptions,\n props: Record<string, unknown>\n): void {\n const capture = prebuiltCaptureAls.getStore();\n if (capture === undefined) return;\n if (innerId === capture.outerId && capture.outerPropsKey !== null) {\n if (propsKey(options, props) === capture.outerPropsKey) {\n throw new PrebuiltCaptureCycleError(innerId);\n }\n }\n let record = capture.nested.get(innerId);\n if (record === undefined) {\n record = { options, tags: new Set() };\n capture.nested.set(innerId, record);\n }\n if (record.tags !== null && options.tags) {\n // A diagnostic must not change the capture. The tags function is user\n // code, so it runs with the request context exited: a read of\n // segment params, headers, or cookies inside it must not be charged\n // to the OUTER entry (a build-time context violation, a lost\n // param-independence proof, a key-discipline report). A tags function\n // that throws — including because it needed that context — leaves the\n // inner's tags unknown, which the clamp rule treats as not covered by\n // the outer; the warning says so. The throw itself is not reported\n // here: it belongs to the inner, which may never be cached on its own.\n const tags = record.tags;\n try {\n for (const tag of requestContextAls.exit(() => resolveTags(options, props))) tags.add(tag);\n } catch {\n record.tags = null;\n }\n }\n}\n","/**\n * Prebuilt component runtime — registration target for the timber-prebuilt\n * transform (plugins/prebuilt.ts) and the request-time half of\n * cache.component (TIM-1140).\n *\n * `cache.component(fn, opts)` call sites are rewritten at build time to\n * `__prebuilt(stableId, fn, opts)` (production) or `__prebuiltDev(name, fn)`\n * (dev). Both are exported via #server-internal — they are framework\n * plumbing, never called by user code directly.\n *\n * Cache hits are served by FLIGHT REVIVAL: the cached `.flight` payload is\n * decoded back into React elements inside the RSC environment with\n * `createFromReadableStream` (the flight client running in the flight\n * server — plugin-rsc wires the server-decode manifest so client\n * references revive as re-serializable reference proxies). The revived\n * element is returned from the wrapper and the outer render re-serializes\n * it like any other subtree. This is the same mechanism as Next.js\n * `\"use cache\"` (next/src/server/use-cache/use-cache-wrapper.ts).\n *\n * What a hit skips: all user work — data fetching, MDX compilation, the\n * component function itself never runs. What it re-pays: React\n * re-serializes the already-resolved tree (cost proportional to payload\n * size, not to data latency). The alternative — splicing raw payload bytes\n * into the outer stream — avoids re-serialization but requires byte-level\n * coupling to the flight wire format (row framing, ID rebasing, marker\n * detection); it was implemented and reviewed on PR #835 and deliberately\n * replaced by revival. See design/44-render-at-build-time.md\n * §Request-Time Injection.\n *\n * Misses render the original component live via the wrapper's own closure,\n * inside the React pass — segment params from ALS, deny()/redirect()\n * signals, Suspense, and error boundaries behave exactly as an unwrapped\n * component. `fallbackOnMissingSegmentParams: false` throws instead.\n */\n\nimport { createElement } from 'react';\n\nimport { requestContextAls, type RequestContextStore } from './als-registry.ts';\nimport type { CoercedParams } from '../shared/param-value.ts';\nimport type { SlotParamsRecord } from '../shared/slot-params.ts';\nimport { computeComponentCacheKey, tryCanonicalize } from './prebuilt/cache-key.ts';\nimport {\n resolveSlotNames,\n prepareSlotRender,\n withoutChildrenOutlet,\n wrapInSlotsProvider,\n} from './prebuilt/slots.ts';\nimport {\n createKeyDisciplineProxy,\n emitKeyDisciplineWarning,\n shouldCheckKeyDiscipline,\n} from './prebuilt/key-discipline.ts';\nimport {\n createCaptureScope,\n isCaptureActive,\n noteWrapperRender,\n type NestedWrapperRender,\n} from './prebuilt/capture-state.ts';\nimport { hasRuntimeLifetime, resolveTags, warnNestingClamps } from './prebuilt/lifetime.ts';\nimport {\n hasPrebuiltPayloadSource,\n lookupPrebuiltPayload,\n getManifestEntry,\n isParamIndependent,\n} from './prebuilt/payload-source.ts';\nimport { lookupOverlay, storeOverlayEntry, overlayKey } from './prebuilt/overlay.ts';\nimport { getWaitUntil } from './waituntil-bridge.ts';\nimport { runBackgroundFlight } from './pipeline-helpers.ts';\nimport { runOutsideReactCacheScope } from './react-cache-scope.ts';\nimport { readAllBytesWithDeadline } from './stream-utils.ts';\nimport { DEFAULT_RENDER_TIMEOUT_MS } from './render-timeout.ts';\nimport { createSingleflight } from '../cache/singleflight.ts';\nimport {\n currentInvalidationEpoch,\n wasInvalidatedSince,\n lastInvalidationEpochFor,\n} from '../cache/invalidation-epoch.ts';\n\n/** Default timeout for component re-renders (overridden by renderTimeoutMs). */\nconst DEFAULT_COMPONENT_TIMEOUT_MS = DEFAULT_RENDER_TIMEOUT_MS;\n\n/** Singleflight for component re-renders (inline and background). */\nlet componentSingleflight = createSingleflight({\n timeoutMs: DEFAULT_COMPONENT_TIMEOUT_MS,\n});\nlet componentTimeoutMs = DEFAULT_COMPONENT_TIMEOUT_MS;\n\n/**\n * Set the timeout for component re-render captures. Called at boot from\n * the RSC entry with renderTimeoutMs from timber.config.ts.\n */\nexport function setComponentRefreshTimeout(timeoutMs: number): void {\n componentTimeoutMs = timeoutMs;\n componentSingleflight = createSingleflight({ timeoutMs });\n}\n\nlet warnedNoWaitUntil = false;\n\n/**\n * (outer, inner) pairs already warned about by request-time captures.\n * Process-wide: re-renders of a hot component repeat, and the warning is\n * about the code, not the request. Bounded by the number of wrapped\n * components in the app.\n */\nconst warnedNestingPairs = new Set<string>();\n\n/**\n * Options captured from the `cache.component(fn, opts)` call site.\n *\n * `prerender`/`ttl`/`tags` (design/45) are carried through untouched — the\n * build phase (TIM-1119) and runtime overlay (design/45 phase 3) consume\n * them.\n */\nexport interface PrebuiltComponentOptions {\n /** Populate the cache at build time via generateStaticSegmentParams. */\n prerender?: boolean;\n /** Runtime freshness window, seconds (design/45 runtime tier). */\n ttl?: number;\n /** Runtime invalidation tags (design/45 runtime tier). */\n tags?: string[] | ((props: Record<string, unknown>) => string[]);\n /** Serve stale while a background re-render refreshes (design/45 §SWR). */\n staleWhileRevalidate?: boolean;\n /**\n * Slot props (TIM-1173): prop names whose values are live React\n * elements composed into the cached shell at request time instead of\n * participating in the cache. Each declared slot renders as a stable\n * SlotOutlet client reference at capture time; the live value flows in\n * through SlotContext per instance. Slot props are excluded from the\n * cache key — only the remaining data props (+ segment params) hash.\n * Runtime tier only: `prerender` is ignored (with a warning) because\n * the build cannot enumerate children variants.\n */\n slots?: string[];\n /**\n * On a cache miss, render the component live (default: true). When false,\n * a miss throws instead — for sites that must never render unknown params\n * dynamically. See design/44 §fallbackOnMissingSegmentParams.\n */\n fallbackOnMissingSegmentParams?: boolean;\n}\n\n/** An async server component: props in, renderable out. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ServerComponent = (props: any) => unknown;\n\n/**\n * View of a ServerComponent that satisfies createElement's overloads.\n * Server components legitimately return `unknown` from the framework's\n * perspective (promises, elements, strings, …) — React renders whatever\n * comes back; the narrowing exists only to cross createElement's\n * ReactNode-typed signature.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype RenderableComponent = (props: any) => React.ReactNode;\n\nexport interface PrebuiltRegistration {\n id: string;\n component: ServerComponent;\n options: PrebuiltComponentOptions;\n}\n\n/**\n * Server-side component registry, keyed by stable component ID. Populated at\n * module load time by `__prebuilt` calls; consumed by the post-build capture\n * pass (TIM-1119). Never serialized — component functions are not\n * Flight-serializable.\n */\nconst registry = new Map<string, PrebuiltRegistration>();\n\n/**\n * Resolve the params the cache key may faithfully hash, or null if this\n * render is unkeyable.\n *\n * A wrapper rendered inside a parallel slot reads params merged with that\n * slot's overrides (`getSegmentParams`: `{...segmentParams, ...slotParams}`)\n * — but the cache key hashes only the route-level params, and the wrapper\n * cannot know which slot it renders under. The route params are usable\n * only when every slot's merged view canonicalizes identically to them;\n * otherwise two renders with the same key could see different effective\n * inputs and a hit could serve the WRONG cached subtree — so the render\n * goes live: slower, never wrong. (Build-time capture doesn't model slot\n * params either, so a divergent request could never have a faithful\n * entry. Codex review on PR #835; revisit with segment-path-scoped keys\n * if slot-scoped prebuilt is ever needed.)\n *\n * Comparison happens through `tryCanonicalize` — the same single\n * definition of value equality the cache key uses — so anything it\n * cannot represent faithfully (bigint-coerced codec params, accessors,\n * aliases, …) is unkeyable here too, and this guard can never throw.\n */\nfunction resolveKeyParams(store: {\n segmentParams?: CoercedParams;\n slotParams?: SlotParamsRecord;\n}): CoercedParams | null {\n const main = store.segmentParams ?? {};\n const slots = store.slotParams;\n if (!slots || Object.keys(slots).length === 0) return main;\n // Spread before canonicalizing: param records are framework-produced\n // Object.create(null) objects (prototype-pollution defense) — normalize\n // the records themselves, let nested values face the full allowlist.\n const mainCanonical = tryCanonicalize({ ...main });\n if (mainCanonical === null) return null;\n for (const slotParams of Object.values(slots)) {\n const merged = tryCanonicalize({ ...main, ...slotParams });\n if (merged === null || merged !== mainCanonical) return null;\n }\n return main;\n}\n\n/**\n * Mirror the production cache-key decision for a slot render, with no\n * cache IO — used by the dev wrapper so slot substitution happens in dev\n * exactly when production would serve the cache path rather than the\n * live fallback (dev/prod parity, codex P2 on PR #890): requires an ALS\n * store, keyable params (slot-param divergence unkeys), and keyable data\n * props (after the children slot outlet strip).\n */\nfunction isSlotRenderKeyable(dataProps: Record<string, unknown>): boolean {\n const store = requestContextAls.getStore();\n if (!store) return false;\n const keyParams = resolveKeyParams(store);\n if (keyParams === null) return false;\n return computeComponentCacheKey(withoutChildrenOutlet(dataProps), keyParams) !== null;\n}\n\n/** Wrap payload bytes as a single-chunk ReadableStream for the decoder. */\nfunction bytesToStream(bytes: Uint8Array): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes);\n controller.close();\n },\n });\n}\n\n// ─── Slot components (TIM-1173) ──────────────────────────────────────────\n\n/**\n * Serve a slot component from the cache: split live slot values out of the\n * props, look up / capture the shell (data props + a deterministic\n * SlotOutlet placeholder per slot), and wrap the revived shell in a\n * per-instance SlotsProvider that feeds the live values to the outlets.\n *\n * Null on any miss — the caller renders live with the original props.\n */\nasync function tryReviveSlotShell(\n id: string,\n options: PrebuiltComponentOptions,\n slots: readonly string[],\n props: Record<string, unknown>\n): Promise<{ element: unknown } | null> {\n const render = prepareSlotRender(props, slots);\n if (render === null) return null; // top-level props unkeyable → live render\n const { shellProps, dataProps, slotValues } = render;\n const revived = await tryRevivePayload(id, options, shellProps, dataProps);\n if (revived === null) return null;\n return { element: wrapInSlotsProvider(revived.element, slotValues) };\n}\n\n// ─── RSC function injection ─────────────────────────────────────────────\n// The flight client/server is only resolvable in the RSC environment\n// (react-server condition). The RSC entry wires these at boot via\n// setRscFunctions(); tests inject mocks directly. Same pattern as\n// setCacheHandler / setPrebuiltPayloadSource.\n\ninterface RscFunctions {\n createFromReadableStream: (stream: ReadableStream<Uint8Array>) => Promise<unknown>;\n renderToReadableStream: (\n element: unknown,\n options?: { onError?: (error: unknown) => string }\n ) => ReadableStream<Uint8Array>;\n}\n\nlet rscFns: RscFunctions | null = null;\n\n/**\n * Wire the RSC flight client/server functions. Called once at server\n * startup from the RSC entry module.\n */\nexport function setRscFunctions(fns: RscFunctions): void {\n rscFns = fns;\n}\n\nfunction requireRscFunctions(): RscFunctions {\n if (!rscFns) {\n throw new Error('[timber] RSC functions not wired — setRscFunctions() must be called at boot');\n }\n return rscFns;\n}\n\n/**\n * Revive flight payload bytes into a React element.\n * Returns null on any failure (corrupt payload, missing decoder).\n */\nasync function revivePayload(\n id: string,\n payload: Uint8Array,\n outcome: string\n): Promise<{ element: unknown } | null> {\n try {\n const { createFromReadableStream } = requireRscFunctions();\n const element: unknown = await createFromReadableStream(bytesToStream(payload));\n return { element };\n } catch (error) {\n console.error(`[timber] failed to revive prebuilt payload for \"${id}\" — ${outcome}:`, error);\n return null;\n }\n}\n\n/** Ceiling on component re-render capture (design/13 A2). Uses configured renderTimeoutMs. */\nfunction getCaptureTimeoutMs(): number {\n return componentTimeoutMs;\n}\n\n/** A request-time capture: the payload and the wrappers baked into it. */\ninterface CapturedPayload {\n bytes: Uint8Array;\n nested: NestedWrapperRender[];\n}\n\n/**\n * Render a component in isolation and capture its flight payload bytes.\n * Used for inline re-renders (tombstone/miss) and SWR background re-renders.\n *\n * The stream read is timeout-guarded and the reader is cancelled on\n * expiry (design/13 A2, A3).\n */\nasync function captureComponentPayload(\n id: string,\n component: ServerComponent,\n props: Record<string, unknown>,\n options: PrebuiltComponentOptions\n): Promise<CapturedPayload> {\n const { renderToReadableStream } = requireRscFunctions();\n const element = createElement(component as RenderableComponent, props);\n // Render inside a capture scope so nested cache.component wrappers render\n // live (bake flat into this entry) per design/45 §Nesting Semantics. The\n // scope is this capture's async context only — concurrent requests\n // rendering the same or other wrapped components never see it (TIM-1536).\n const capture = createCaptureScope(id, options, props);\n // The first error the capture render hit, kept so a failed capture\n // reports the component's own error rather than a stand-in.\n let renderError: { error: unknown } | undefined;\n\n // Key-discipline diagnostic (design/45 §Enforcement): proxy the ALS\n // store to detect request-context reads during the capture render.\n // The proxy is transparent — it never blocks or throws; it only observes.\n const store = requestContextAls.getStore();\n const discipline = store && shouldCheckKeyDiscipline(id) ? createKeyDisciplineProxy(store) : null;\n\n const doCapture = (): Promise<Uint8Array> =>\n capture.run(async () => {\n // Outside the request's React.cache scope: this payload is stored\n // cross-request (and the capture is singleflight-coalesced across\n // requests), so it must not bake in values memoized for the request\n // that happened to trigger it. Flight gives the capture its own\n // per-render cache instead (TIM-1529).\n const stream: ReadableStream<Uint8Array> = runOutsideReactCacheScope(() =>\n renderToReadableStream(element, {\n onError(error: unknown) {\n renderError ??= { error };\n return '';\n },\n })\n );\n const bytes = await readAllBytesWithDeadline(\n stream,\n getCaptureTimeoutMs(),\n '[timber] component re-render capture'\n );\n // Error rows are never cached. The component's own error is what\n // failed, so it is what the caller logs and reports.\n if (renderError) throw renderError.error;\n return bytes;\n });\n\n const bytes = discipline\n ? await requestContextAls.run(discipline.proxy, doCapture)\n : await doCapture();\n\n if (discipline && discipline.accessedApis.size > 0) {\n emitKeyDisciplineWarning(id, discipline.accessedApis);\n }\n\n return { bytes, nested: capture.nestedRenders() };\n}\n\n/**\n * Store a captured entry in the overlay, then say which embedded\n * components it clamps (design/45 §Nesting Semantics, TIM-1545). The\n * warning follows the store: a capture that is discarded (aborted,\n * invalidated mid-render, failed store) holds no clamped copy, and must\n * not spend the pair's one warning.\n */\nasync function storeCapturedEntry(\n id: string,\n cacheKey: string,\n captured: CapturedPayload,\n options: PrebuiltComponentOptions,\n tags: string[],\n hasSeed: boolean\n): Promise<void> {\n await storeOverlayEntry(id, cacheKey, captured.bytes, { ttl: options.ttl, tags, hasSeed });\n warnNestingClamps({ id, options, tags }, captured.nested, warnedNestingPairs, (m) =>\n console.warn(m)\n );\n}\n\n/**\n * Inline re-render: capture flight bytes, store in overlay, revive for\n * the current request. Singleflight-coalesced by overlay key.\n */\nasync function inlineRerender(\n id: string,\n component: ServerComponent,\n props: Record<string, unknown>,\n cacheKey: string,\n options: PrebuiltComponentOptions,\n hasSeed: boolean,\n outcome: string\n): Promise<{ element: unknown } | null> {\n const tags = resolveTags(options, props);\n const oKey = overlayKey(id, cacheKey);\n const sfKey = `prebuilt:${id}:${cacheKey}\\0${lastInvalidationEpochFor(oKey, tags)}`;\n\n try {\n const payload = await componentSingleflight.do(sfKey, async (signal) => {\n const startEpoch = currentInvalidationEpoch();\n const captured = await captureComponentPayload(id, component, props, options);\n // Skip the store if aborted (singleflight timeout) or if the\n // key/tags were invalidated while rendering (TIM-1028 guard).\n if (\n !signal.aborted &&\n hasRuntimeLifetime(options) &&\n !wasInvalidatedSince(startEpoch, oKey, tags)\n ) {\n await storeCapturedEntry(id, cacheKey, captured, options, tags, hasSeed);\n }\n return captured.bytes;\n });\n return await revivePayload(id, payload, outcome);\n } catch (error) {\n console.error(`[timber] cache.component re-render failed for \"${id}\" — ${outcome}:`, error);\n return null;\n }\n}\n\n/**\n * Snapshot the request context values needed for a background re-render.\n * Creates a FRESH store with copied values — the original ALS store is\n * not referenced after capture. The `Request` itself is shared, not\n * copied: the re-render reports its failure against it.\n */\nfunction snapshotRequestContext(store: RequestContextStore): RequestContextStore {\n return {\n request: store.request,\n headers: new Headers(store.headers),\n originalHeaders: new Headers(store.originalHeaders),\n cookieHeader: store.cookieHeader,\n parsedCookies: store.parsedCookies ? new Map(store.parsedCookies) : undefined,\n searchParams: new URLSearchParams(store.searchParams),\n searchString: store.searchString,\n segmentParams: store.segmentParams ? { ...store.segmentParams } : undefined,\n cookieJar: new Map(),\n flushed: false,\n mutableContext: false,\n };\n}\n\n/**\n * Kick off a background re-render via waitUntil. The re-render runs inside\n * a fresh ALS scope with snapshotted request context.\n */\nfunction backgroundRerender(\n id: string,\n component: ServerComponent,\n props: Record<string, unknown>,\n cacheKey: string,\n options: PrebuiltComponentOptions,\n hasSeed: boolean,\n snapshot: RequestContextStore\n): void {\n const waitUntil = getWaitUntil();\n const tags = resolveTags(options, props);\n const oKey = overlayKey(id, cacheKey);\n const startEpoch = currentInvalidationEpoch();\n const sfKey = `prebuilt-bg:${id}:${cacheKey}\\0${lastInvalidationEpochFor(oKey, tags)}`;\n\n const work = requestContextAls.run(snapshot, () =>\n componentSingleflight\n // The stale payload already answered the request, so nothing else sees\n // a failure here: logged and reported once per flight. Inline re-render\n // and revive failures are only logged: a live render answers instead.\n .do(sfKey, (signal) =>\n runBackgroundFlight(\n signal,\n async () => {\n const captured = await captureComponentPayload(id, component, props, options);\n if (!signal.aborted && !wasInvalidatedSince(startEpoch, oKey, tags)) {\n await storeCapturedEntry(id, cacheKey, captured, options, tags, hasSeed);\n }\n },\n (error) =>\n console.error(\n `[timber] cache.component background re-render failed for \"${id}\":`,\n error\n )\n )\n )\n // runBackgroundFlight never rejects; only the singleflight timeout,\n // which it already reported, can reject the flight.\n .catch(() => {})\n );\n\n if (waitUntil) {\n waitUntil(work);\n } else if (!warnedNoWaitUntil) {\n warnedNoWaitUntil = true;\n console.warn(\n '[timber] cache.component SWR background re-render has no waitUntil — ' +\n 'the re-render may be killed when the handler returns on serverless platforms. ' +\n 'Ensure the adapter wires runWithWaitUntil().'\n );\n }\n}\n\n/**\n * Try to serve this render from the prebuilt cache: overlay → artifact →\n * live render. Handles ISR (SWR, tombstones, re-renders) per design/45.\n *\n * Null on any miss — the caller renders live.\n */\nasync function tryRevivePayload(\n id: string,\n options: PrebuiltComponentOptions,\n props: Record<string, unknown>,\n keyPropsOverride?: Record<string, unknown>\n): Promise<{ element: unknown } | null> {\n const hasSource = hasPrebuiltPayloadSource();\n const hasRuntime = hasRuntimeLifetime(options);\n if (!hasSource && !hasRuntime) return null;\n\n const store = requestContextAls.getStore();\n if (!store) return null;\n const paramIndep = options.prerender ? await isParamIndependent(id) : false;\n const keyParams = paramIndep ? {} : resolveKeyParams(store);\n if (keyParams === null) return null;\n\n // Strip `children` from the cache key ONLY when it is the framework-\n // injected children slot outlet (<SlotOutlet slot=\"children\" />).\n // Layout components receive this as children — a deterministic client\n // reference that is the same on every request, so it should not vary\n // the key. User-provided React element children are NOT stripped —\n // they remain unkeyable so the component renders live, which is\n // correct: the cache cannot distinguish <A> from <B>.\n // See design/45-cache-lifetimes.md §Layout Propagation, TIM-1181.\n // keyPropsOverride = slot component (TIM-1173): the wrapper already\n // split out slot props; only data props participate in the key. The\n // children outlet strip applies to EITHER source — a cached layout\n // declaring only named slots (slots: ['modal']) still receives the\n // framework-injected children outlet in its data props, and it must not\n // unkey the render there any more than on the non-slot path (codex P2\n // on PR #890).\n const allProps = (props ?? {}) as Record<string, unknown>;\n const cacheKey = computeComponentCacheKey(\n withoutChildrenOutlet(keyPropsOverride ?? allProps),\n keyParams\n );\n if (cacheKey === null) return null;\n\n const outcome =\n options.fallbackOnMissingSegmentParams === false\n ? 'failing the render (fallbackOnMissingSegmentParams: false)'\n : 'rendering dynamically';\n\n const registration = registry.get(id);\n const component = registration?.component;\n\n // ─── Step 1: Check overlay (CacheHandler) ─────────────────────────\n if (hasRuntime) {\n const overlayResult = await lookupOverlay(id, cacheKey);\n if (overlayResult) {\n const overlayHasSeed = overlayResult.record?.s ?? false;\n if (overlayResult.kind === 'tombstone') {\n if (component) {\n return await inlineRerender(id, component, props, cacheKey, options, true, outcome);\n }\n return null;\n }\n if (overlayResult.kind === 'fresh' && overlayResult.payload) {\n return await revivePayload(id, overlayResult.payload, outcome);\n }\n if (overlayResult.kind === 'stale' && overlayResult.payload) {\n if (options.staleWhileRevalidate && component) {\n backgroundRerender(\n id,\n component,\n props,\n cacheKey,\n options,\n overlayHasSeed,\n snapshotRequestContext(store)\n );\n return await revivePayload(id, overlayResult.payload, outcome);\n }\n if (component) {\n return await inlineRerender(\n id,\n component,\n props,\n cacheKey,\n options,\n overlayHasSeed,\n outcome\n );\n }\n return null;\n }\n }\n }\n\n // ─── Step 2: Check build artifact ─────────────────────────────────\n if (hasSource) {\n const artifactPayload = await lookupPrebuiltPayload(id, cacheKey);\n if (artifactPayload !== null) {\n // Check seed freshness when the component has a TTL.\n if (options.ttl !== undefined) {\n const entry = await getManifestEntry(id, cacheKey);\n const buildTs = entry?.buildTimestamp ?? 0;\n const seedAge = (Date.now() - buildTs) / 1000;\n if (seedAge > options.ttl) {\n // Stale seed\n if (options.staleWhileRevalidate && component) {\n backgroundRerender(\n id,\n component,\n props,\n cacheKey,\n options,\n true,\n snapshotRequestContext(store)\n );\n return await revivePayload(id, artifactPayload, outcome);\n }\n if (component) {\n return await inlineRerender(id, component, props, cacheKey, options, true, outcome);\n }\n // No component in registry — can't re-render; fall through to\n // live render via the wrapper (design/45 step 3).\n return null;\n }\n }\n // Fresh seed (or no TTL — immutable until redeploy)\n return await revivePayload(id, artifactPayload, outcome);\n }\n\n // Manifest miss\n if (options.prerender) {\n console.warn(\n `[timber] cache.component cache miss: \"${id}\" with params ${JSON.stringify(\n store.segmentParams ?? {}\n )} — ${outcome}`\n );\n }\n }\n\n // ─── Step 3: Full miss with runtime lifetime — inline re-render ───\n // Skip when fallbackOnMissingSegmentParams is false — that option means\n // \"only prebuilt content\", so an unenumerated miss must throw (the\n // wrapper handles the throw after we return null).\n if (hasRuntime && component && options.fallbackOnMissingSegmentParams !== false) {\n return await inlineRerender(id, component, props, cacheKey, options, false, outcome);\n }\n\n return null;\n}\n\n/**\n * Production wrapper injected by the timber-prebuilt transform. Registers\n * the component under its stable ID and returns a wrapper component that\n * either revives the cached payload (hit) or renders the original\n * component live (miss).\n */\nexport function __prebuilt<C extends ServerComponent>(\n id: string,\n component: C,\n options: PrebuiltComponentOptions = {}\n): C {\n // Slot resolution first, then option normalization in its terms\n // (TIM-1173). ACTIVE slots are runtime-tier only — the build cannot\n // enumerate slot content — so `prerender` is stripped (loudly); the\n // capture pass reads the registry's normalized options, so stripping\n // here also keeps the build from capturing slot components. DISABLED\n // declarations (malformed shape, missing lifetime — warned inside\n // resolveSlotNames) fall back wholesale to non-slot semantics: `slots`\n // is stripped so no downstream consumer (resolveTags' slot filtering,\n // the registry, the capture pass) ever sees the raw value, and every\n // other option — including `prerender` — keeps its normal meaning\n // (codex P2s on PR #890).\n const resolution = resolveSlotNames(id, options);\n const slots = resolution.kind === 'active' ? resolution.slots : null;\n if (resolution.kind === 'active' && options.prerender) {\n console.warn(\n `[timber] cache.component \"${id}\": slots are runtime-tier only — ` +\n `prerender is ignored (the build cannot enumerate slot content). ` +\n `Use ttl/tags for the cache lifetime.`\n );\n options = { ...options, prerender: undefined };\n }\n if (resolution.kind === 'disabled') {\n options = { ...options, slots: undefined };\n }\n registry.set(id, { id, component, options });\n\n const wrapper = async (props: Parameters<C>[0]) => {\n // Report this render to the enclosing capture, if any — cycle\n // detection (throws) and nesting-clamp warnings (design/45 §Nesting\n // Semantics). Outside a capture this is a single store lookup.\n noteWrapperRender(id, options, props as Record<string, unknown>);\n if (isCaptureActive()) {\n // Nested wrapper inside a capture: render live so the subtree\n // bakes flat into the enclosing entry (design/45 §Nesting).\n // This deliberately bypasses fallbackOnMissingSegmentParams: false —\n // that option means \"never serve non-prebuilt content\", and a\n // capture render IS the cached content; throwing here would\n // spuriously fail the outer entry (codex P2 on PR #836).\n return createElement(component as RenderableComponent, props as Record<string, unknown>);\n }\n\n const revived = slots\n ? await tryReviveSlotShell(id, options, slots, props as Record<string, unknown>)\n : await tryRevivePayload(id, options, props as Record<string, unknown>);\n if (revived !== null) {\n return revived.element;\n }\n if (options.fallbackOnMissingSegmentParams === false) {\n throw new Error(\n `[timber] cache.component \"${id}\": no prebuilt payload for the current params and fallbackOnMissingSegmentParams is false`\n );\n }\n // Return an ELEMENT — React invokes the component itself, with its\n // render dispatcher active. Calling component(props) here would run\n // it after this wrapper's await, outside a dispatcher frame, breaking\n // sync server components that call use() (codex review on PR #835).\n return createElement(component as RenderableComponent, props as Record<string, unknown>);\n };\n Object.defineProperty(wrapper, 'name', { value: `Prebuilt(${id})` });\n // Double cast, deliberately: C's return type may be narrower than the\n // wrapper's (a sync component wrapped by an async function, or a revived\n // subtree in place of C's exact JSX type). Callers only ever *render*\n // the result — React treats any component returning ReactNode-compatible\n // values identically — so widening through `unknown` is safe here and a\n // direct cast would be rejected by the compiler for exactly the\n // difference we intend.\n return wrapper as unknown as C;\n}\n\n/** Look up a registration by stable component ID. */\nexport function getPrebuiltRegistration(id: string): PrebuiltRegistration | undefined {\n return registry.get(id);\n}\n\n/** All registrations, for the post-build capture pass (TIM-1119). */\nexport function getPrebuiltRegistry(): ReadonlyMap<string, PrebuiltRegistration> {\n return registry;\n}\n\n/**\n * Dev-mode wrapper injected by the timber-prebuilt transform: a no-op that\n * renders the component dynamically on every request, logging once per\n * component on first render so the production behavior difference is visible.\n * See design/44 §Dev Mode.\n */\nexport function __prebuiltDev<C extends ServerComponent>(\n name: string,\n component: C,\n options: PrebuiltComponentOptions = {}\n): C {\n // Dev/prod parity for slot components: in production a slot component\n // ALWAYS receives a SlotOutlet element for each declared slot (never the\n // live children), so a component that introspects a slot prop would\n // behave differently between dev and prod if dev passed children\n // through. Dev renders the same tree shape — outlets in the props,\n // live values via SlotsProvider — just without any caching. The same\n // validation applies (including the lifetime requirement): slots are\n // active in dev exactly when they would be active in production.\n const resolution = resolveSlotNames(name, options);\n const slots = resolution.kind === 'active' ? resolution.slots : null;\n let logged = false;\n const wrapper = (props: Parameters<C>[0]) => {\n if (!logged) {\n logged = true;\n console.log(`[timber] cache.component: \"${name}\" — rendering dynamically (dev mode)`);\n }\n if (slots) {\n const render = prepareSlotRender(props as Record<string, unknown>, slots);\n // Substitute outlets only when PRODUCTION would: top-level props\n // splittable AND the data props keyable. Unkeyable inputs render\n // live with the original props there, so dev must too (parity —\n // codex P2 on PR #890).\n if (render !== null && isSlotRenderKeyable(render.dataProps)) {\n return wrapInSlotsProvider(\n createElement(component as RenderableComponent, render.shellProps),\n render.slotValues\n );\n }\n }\n // Element, not a direct call — same dispatcher reasoning as the\n // production wrapper's live fallback.\n return createElement(component as RenderableComponent, props as Record<string, unknown>);\n };\n return wrapper as C;\n}\n"],"mappings":"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"}
|