@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":"logger-BP0LN6vP.js","names":[],"sources":["../../src/server/tracing.ts","../../src/server/debug.ts","../../src/server/error-formatter.ts","../../src/server/default-logger.ts","../../src/server/signal-identity.ts","../../src/server/logger.ts"],"sourcesContent":["/**\n * Tracing — per-request trace ID via AsyncLocalStorage, OTEL span helpers.\n *\n * getTraceId() is always available in server code (middleware, access, components, actions).\n * Returns a 32-char lowercase hex string — the OTEL trace ID when an SDK is active,\n * or a crypto.randomUUID()-derived fallback otherwise.\n *\n * See design/17-logging.md §\"trace_id is Always Set\"\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { traceAls, type TraceStore } from './als-registry.ts';\n\n// Re-export the TraceStore type for public API consumers.\nexport type { TraceStore } from './als-registry.ts';\n\n// ─── Public API ───────────────────────────────────────────────────────────\n\n/**\n * Returns the current request's trace ID — always a 32-char lowercase hex string.\n *\n * With OTEL: the real OTEL trace ID (matches Jaeger/Honeycomb/Datadog).\n * Without OTEL: crypto.randomUUID() with hyphens stripped.\n *\n * Throws if called outside a request context (no ALS store).\n */\nexport function getTraceId(): string {\n const store = traceAls.getStore();\n if (!store) {\n throw new Error(\n '[timber] getTraceId() called outside of a request context. ' +\n 'It can only be used in middleware, access checks, server components, and server actions.'\n );\n }\n return store.request.traceId;\n}\n\n/**\n * Returns the current OTEL span ID if available, undefined otherwise.\n */\nexport function getSpanId(): string | undefined {\n return traceAls.getStore()?.spanId;\n}\n\n// ─── Framework-Internal Helpers ───────────────────────────────────────────\n\n/**\n * Generate a 32-char lowercase hex ID from crypto.randomUUID().\n * Same format as OTEL trace IDs — zero-friction upgrade path.\n */\nexport function generateTraceId(): string {\n return randomUUID().replace(/-/g, '');\n}\n\n/**\n * Run a callback within a trace context. Used by the pipeline to establish\n * per-request ALS scope.\n */\nexport function runWithTraceId<T>(id: string, fn: () => T): T {\n return traceAls.run({ request: { traceId: id } }, fn);\n}\n\n/**\n * Replace the request's trace ID. Used when OTEL creates the root span and\n * we want to switch from the UUID fallback to the real OTEL trace ID. Writes\n * the request's shared trace, so every scope in the request sees it —\n * including the ones outside the span this runs in.\n */\nexport function replaceTraceId(newTraceId: string): void {\n const store = traceAls.getStore();\n if (store) {\n store.request.traceId = newTraceId;\n }\n}\n\n/**\n * Run `fn` in a new trace scope for one span: the enclosing scope's request\n * trace, with this span's pointers. A scope per span, not a save/restore on\n * a shared store — spans overlap (MetadataCollector does not await\n * `timber.metadata`), and a restore that runs after a sibling's would\n * leave the sibling's pointer behind (TIM-1538).\n */\nfunction runInSpanScope<T>(\n pointers: Pick<TraceStore, 'spanId'> | Pick<TraceStore, 'platformSpan'>,\n fn: () => T\n): T {\n const store = traceAls.getStore();\n return store ? traceAls.run({ ...store, ...pointers }, fn) : fn();\n}\n\n/**\n * Get the current trace store, or undefined if outside a request context.\n * Framework-internal — use getTraceId()/getSpanId() in user code.\n */\nexport function getTraceStore(): TraceStore | undefined {\n return traceAls.getStore();\n}\n\n// ─── Dev-Mode OTEL Auto-Init ─────────────────────────────────────────────\n\n/**\n * Well-known key marking dev tracing as initialized.\n *\n * The RSC entry module re-evaluates on every HMR invalidation and calls\n * initDevTracing() again — without this guard, each call would register a\n * fresh provider/processor and duplicate every span's output. Symbol.for()\n * survives module re-evaluation. See TIM-1067, B49.\n */\nconst DEV_TRACING_INIT_KEY = Symbol.for('timber.dev.tracing-initialized');\n\n/**\n * Initialize a minimal OTEL SDK in dev mode so spans are recorded and\n * fed to the DevSpanProcessor for dev log output.\n *\n * If the user already configured an OTEL SDK in register(), we add\n * our DevSpanProcessor alongside theirs. If no SDK is configured,\n * we create a BasicTracerProvider with our processor.\n *\n * Idempotent across module re-evaluations (HMR) — only the first call\n * registers. Called in dev, and in production only when TIMBER_DEBUG is\n * set — otherwise production never loads the OTEL SDK.\n */\nexport async function initDevTracing(\n config: import('../dev-tools/logger.ts').DevLoggerConfig\n): Promise<void> {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[DEV_TRACING_INIT_KEY]) return;\n\n const api = await getOtelApi();\n if (!api) return;\n\n // Tracing is a diagnostic: any failure to load or construct the SDK\n // disables it with a warning and never fails the server's boot (TIM-1554).\n try {\n const { registerDevTracing } = await import('../dev-tools/instrumentation.ts');\n registerDevTracing(config);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[timber] Dev tracing disabled — failed to set up OTEL:\\n ${msg}`);\n return;\n }\n\n // Reset cached tracer so next getTracer() picks up the new provider\n _tracer = undefined;\n\n globals[DEV_TRACING_INIT_KEY] = true;\n}\n\n// ─── Platform Tracer ─────────────────────────────────────────────────────\n\n/**\n * A native platform span. Mirrors the subset of the Cloudflare Workers\n * `Span` API that timber uses. See design/17-logging.md §\"Cloudflare Native\n * Spans\" and TIM-1135.\n */\nexport interface PlatformSpan {\n setAttribute(key: string, value: string | number | boolean): void;\n}\n\n/**\n * Adapter-provided native tracer. Callback-scoped like Cloudflare's\n * `tracing.enterSpan()` — the span starts when the callback is invoked and\n * ends when it returns or its promise settles. Nesting follows the\n * platform's async context.\n *\n * When registered, withSpan() wraps every framework span in a native span\n * *in addition to* the OTEL emission — dual emission, so external OTEL\n * collectors keep working alongside the platform's native trace view.\n *\n * Register via setPlatformTracer(), or by writing the\n * Symbol.for('timber:platform-tracer') key on globalThis from\n * adapter-generated entry code (what the Cloudflare _worker.js does).\n */\nexport interface PlatformTracer {\n enterSpan<T>(name: string, fn: (span: PlatformSpan) => T): T;\n}\n\n// globalThis + Symbol.for so a tracer registered by adapter-generated entry\n// code (a separate module instance) is visible in both the RSC and SSR\n// environments — same pattern as the cf-bindings ALS.\nconst PLATFORM_TRACER_KEY = Symbol.for('timber:platform-tracer');\n\n/** Register (or clear) the native platform tracer for this runtime. */\nexport function setPlatformTracer(tracer: PlatformTracer | undefined): void {\n (globalThis as Record<symbol, unknown>)[PLATFORM_TRACER_KEY] = tracer;\n}\n\n/** The registered native platform tracer, if any. */\nexport function getPlatformTracer(): PlatformTracer | undefined {\n return (globalThis as Record<symbol, unknown>)[PLATFORM_TRACER_KEY] as PlatformTracer | undefined;\n}\n\n// ─── OTEL Span Helpers ───────────────────────────────────────────────────\n\n/**\n * Attempt to get the @opentelemetry/api tracer. Returns undefined if the\n * package is not installed or no SDK is registered.\n *\n * timber.js depends on @opentelemetry/api as the vendor-neutral interface.\n * The API is a no-op by default — spans are only emitted when the developer\n * initializes an SDK in register().\n */\nlet _otelApi: typeof import('@opentelemetry/api') | null | undefined;\n\nasync function getOtelApi(): Promise<typeof import('@opentelemetry/api') | null> {\n if (_otelApi === undefined) {\n try {\n _otelApi = await import('@opentelemetry/api');\n } catch {\n _otelApi = null;\n }\n }\n return _otelApi;\n}\n\n/** OTEL tracer instance, lazily created. */\nlet _tracer: import('@opentelemetry/api').Tracer | null | undefined;\n\n/**\n * Get the timber.js OTEL tracer. Returns null if @opentelemetry/api is not available.\n */\nexport async function getTracer(): Promise<import('@opentelemetry/api').Tracer | null> {\n if (_tracer === undefined) {\n const api = await getOtelApi();\n if (api) {\n _tracer = api.trace.getTracer('timber.js');\n } else {\n _tracer = null;\n }\n }\n return _tracer;\n}\n\n/**\n * Run a function within a framework span. Composes two emission channels:\n *\n * - **Native platform span** — when an adapter registered a PlatformTracer\n * (Cloudflare Workers), the fn is wrapped in platformTracer.enterSpan()\n * so it appears in the platform's native trace view.\n * - **OTEL span** — when an OTEL SDK is active, the fn also runs inside an\n * OTEL span (dual emission). No SDK and no platform tracer = zero overhead.\n *\n * Automatically:\n * - Creates the span as a child of the current context\n * - Runs fn in its own trace scope carrying the span's IDs, for log–trace\n * correlation and setSpanAttribute()\n * - Ends the span when the function completes\n * - Records exceptions on error (OTEL channel)\n */\nexport async function withSpan<T>(\n name: string,\n attributes: Record<string, string | number | boolean>,\n fn: () => T | Promise<T>\n): Promise<T> {\n const platformTracer = getPlatformTracer();\n if (!platformTracer) {\n return runOtelSpan(name, attributes, fn);\n }\n\n // Native platform span wraps the OTEL emission (dual emission). The\n // span is tracked on its own trace scope so setSpanAttribute() can reach\n // it after creation — the platform API has no getActiveSpan() equivalent.\n return platformTracer.enterSpan(name, (span) => {\n for (const key of Object.keys(attributes)) {\n span.setAttribute(key, attributes[key]);\n }\n return runInSpanScope({ platformSpan: span }, () => runOtelSpan(name, attributes, fn));\n });\n}\n\n/** The OTEL half of withSpan() — no-op passthrough when no SDK is active. */\nasync function runOtelSpan<T>(\n name: string,\n attributes: Record<string, string | number | boolean>,\n fn: () => T | Promise<T>\n): Promise<T> {\n const tracer = await getTracer();\n if (!tracer) {\n return fn();\n }\n\n const api = (await getOtelApi())!;\n return tracer.startActiveSpan(name, { attributes }, (span) =>\n runInSpanScope({ spanId: span.spanContext().spanId }, () => settleOtelSpan(api, span, fn))\n );\n}\n\n/** Run `fn` and end `span` with its outcome. */\nasync function settleOtelSpan<T>(\n api: typeof import('@opentelemetry/api'),\n span: import('@opentelemetry/api').Span,\n fn: () => T | Promise<T>\n): Promise<T> {\n try {\n const result = await fn();\n span.setStatus({ code: api.SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({ code: api.SpanStatusCode.ERROR });\n if (error instanceof Error) {\n span.recordException(error);\n }\n throw error;\n } finally {\n span.end();\n }\n}\n\n/**\n * Set an attribute on the current active span (if any).\n * Used for setting span attributes after span creation (e.g. timber.result on access spans).\n */\nexport async function setSpanAttribute(\n key: string,\n value: string | number | boolean\n): Promise<void> {\n // Forward to the innermost active native platform span, if any.\n const platformSpan = traceAls.getStore()?.platformSpan;\n if (platformSpan) {\n platformSpan.setAttribute(key, value);\n }\n\n const api = await getOtelApi();\n if (!api) return;\n\n const activeSpan = api.trace.getActiveSpan();\n if (activeSpan) {\n activeSpan.setAttribute(key, value);\n }\n}\n\n/**\n * Add a span event to the current active span (if any).\n * Used for timber.cache HIT/MISS events — recorded as span events, not child spans.\n */\nexport async function addSpanEvent(\n name: string,\n attributes?: Record<string, string | number | boolean>\n): Promise<void> {\n const api = await getOtelApi();\n if (!api) return;\n\n const activeSpan = api.trace.getActiveSpan();\n if (activeSpan) {\n activeSpan.addEvent(name, attributes);\n }\n}\n\n/**\n * Fire-and-forget span event — no await, no microtask overhead.\n *\n * Used on the cache hot path where awaiting addSpanEvent creates an\n * unnecessary microtask per cache operation. If OTEL is not loaded yet,\n * the event is silently dropped (acceptable for diagnostics).\n *\n * See TIM-370 for perf motivation.\n */\nexport function addSpanEventSync(\n name: string,\n attributes?: Record<string, string | number | boolean>\n): void {\n // Fast path: if OTEL API hasn't been loaded yet, skip entirely.\n // _otelApi is undefined (not yet loaded), null (failed to load), or the module.\n if (!_otelApi) return;\n\n const activeSpan = _otelApi.trace.getActiveSpan();\n if (activeSpan) {\n activeSpan.addEvent(name, attributes);\n }\n}\n\n/**\n * Try to extract the OTEL trace ID from the current active span context.\n * Returns undefined if OTEL is not active or no span exists. (The span ID\n * reaches logs through the span's own trace scope, not from here.)\n */\nexport async function getOtelTraceId(): Promise<string | undefined> {\n const api = await getOtelApi();\n if (!api) return undefined;\n\n const activeSpan = api.trace.getActiveSpan();\n if (!activeSpan) return undefined;\n\n const ctx = activeSpan.spanContext();\n // OTEL uses \"0000000000000000\" as invalid trace IDs\n if (!ctx.traceId || ctx.traceId === '00000000000000000000000000000000') {\n return undefined;\n }\n\n return ctx.traceId;\n}\n","/**\n * Runtime debug flag for timber.js.\n *\n * Two distinct functions for two distinct security levels:\n *\n * ## `isDebug()` — server-side logging only\n *\n * Returns true when timber's debug/warning messages should be written to\n * stderr / the server console. This NEVER affects what is sent to the\n * client (no error details, no timing headers, no stack traces).\n *\n * Active when any of:\n * - `NODE_ENV !== 'production'` (standard dev mode)\n * - `TIMBER_DEBUG` env var is set to a truthy value at runtime\n * - `timber.config.ts` has `debug: true`\n *\n * ## `isDevMode()` — client-visible dev behavior\n *\n * Returns true ONLY when `NODE_ENV !== 'production'`. This gates anything\n * that changes what clients can observe:\n * - Dev error pages with stack traces (fallback-error.ts)\n * - Detailed Server-Timing headers (pipeline.ts)\n * - Error messages in action INTERNAL_ERROR payloads (action-client.ts)\n * - Pipeline error handler wiring (Vite overlay)\n *\n * `isDevMode()` is statically replaced in production builds → the guarded\n * code is tree-shaken to zero bytes. TIMBER_DEBUG cannot enable it.\n *\n * Usage:\n * In Cloudflare Workers wrangler.toml:\n * [vars]\n * TIMBER_DEBUG = \"1\"\n *\n * In Node.js:\n * TIMBER_DEBUG=1 node server.js\n *\n * In timber.config.ts:\n * export default { debug: true }\n *\n * See design/13-security.md for the security taxonomy.\n * See design/18-build-system.md for build pipeline details.\n */\n\n// ─── Dev Mode (client-visible) ──────────────────────────────────────────────\n\n/**\n * Check if the application is running in development mode.\n *\n * This is the ONLY function that should gate client-visible dev behavior:\n * - Dev error pages with stack traces\n * - Error messages in action `INTERNAL_ERROR` payloads\n * - Pipeline error handler wiring (Vite overlay)\n *\n * Returns `process.env.NODE_ENV !== 'production'`, which is statically\n * replaced by the bundler in production builds. Code guarded by this\n * function is tree-shaken to zero bytes in production.\n *\n * TIMBER_DEBUG does NOT enable this — that would leak server internals\n * to clients. Use `isDebug()` for server-side-only logging.\n */\nexport function isDevMode(): boolean {\n return process.env.NODE_ENV !== 'production';\n}\n\n// ─── Debug Flag (server-side logging only) ──────────────────────────────────\n\n/**\n * Config-level debug override. Set via `setDebugFromConfig()` during\n * initialization when timber.config.ts has `debug: true`.\n */\nlet _configDebug = false;\n\n/**\n * Set the debug flag from timber.config.ts.\n * Called during handler initialization.\n */\nexport function setDebugFromConfig(debug: boolean): void {\n _configDebug = debug;\n}\n\n/**\n * Check if timber debug logging is active (server-side only).\n *\n * Returns true if ANY of these conditions hold:\n * - NODE_ENV is not 'production' (standard dev mode)\n * - TIMBER_DEBUG environment variable is set to a truthy value at runtime\n * - timber.config.ts has `debug: true`\n *\n * This function controls ONLY server-side logging — messages written to\n * stderr or the server console. It NEVER affects client-visible behavior\n * (error pages, response headers, action payloads). For client-visible\n * behavior, use `isDevMode()`.\n *\n * The TIMBER_DEBUG check is deliberately written as a dynamic property\n * access so bundlers cannot statically replace it.\n */\nexport function isDebug(): boolean {\n // Fast path: dev mode (statically replaced to `true` in dev, `false` in prod)\n if (process.env.NODE_ENV !== 'production') return true;\n\n // Config override\n if (_configDebug) return true;\n\n // Runtime env var check — uses dynamic access to prevent static replacement.\n // In production builds, process.env.NODE_ENV is statically replaced, but\n // TIMBER_DEBUG must survive as a runtime check. The dynamic key access\n // pattern ensures the bundler treats this as opaque.\n return _readTimberDebugEnv();\n}\n\n/**\n * Read TIMBER_DEBUG from the environment at runtime.\n *\n * Extracted to a separate function to:\n * 1. Prevent bundler inlining (cross-module function calls are not inlined)\n * 2. Handle platforms where `process` may not exist (Cloudflare Workers)\n * 3. Support globalThis.__TIMBER_DEBUG for programmatic control\n */\nfunction _readTimberDebugEnv(): boolean {\n // globalThis override — useful for programmatic control and testing\n if ((globalThis as Record<string, unknown>).__TIMBER_DEBUG) return true;\n\n // process.env — works in Node.js and platforms that polyfill process\n try {\n const key = 'TIMBER_DEBUG';\n const val =\n typeof process !== 'undefined' && process.env\n ? (process.env as Record<string, string | undefined>)[key]\n : undefined;\n if (val && val !== '0' && val !== 'false') return true;\n } catch {\n // process may not exist or env may throw — safe to ignore\n }\n\n return false;\n}\n","/**\n * Error Formatter — rewrites SSR/RSC error messages to surface user code.\n *\n * When React or Vite throw errors during SSR, stack traces reference\n * vendored dependency paths (e.g. `.vite/deps_ssr/@vitejs_plugin-rsc_vendor_...`)\n * and mangled export names (`__vite_ssr_export_default__`). This module\n * rewrites error messages and stack traces to point at user code instead.\n *\n * Dev-only — in production, errors go through the structured logger\n * without formatting.\n */\n\n// ─── Stack Trace Rewriting ──────────────────────────────────────────────────\n\n/**\n * Patterns that identify internal Vite/RSC vendor paths in stack traces.\n * These are replaced with human-readable labels.\n */\nconst VENDOR_PATH_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n {\n pattern: /node_modules\\/\\.vite\\/deps_ssr\\/@vitejs_plugin-rsc_vendor_react-server-dom[^\\s)]+/g,\n replacement: '<react-server-dom>',\n },\n {\n pattern: /node_modules\\/\\.vite\\/deps_ssr\\/@vitejs_plugin-rsc_vendor[^\\s)]+/g,\n replacement: '<rsc-vendor>',\n },\n {\n pattern: /node_modules\\/\\.vite\\/deps_ssr\\/[^\\s)]+/g,\n replacement: '<vite-dep>',\n },\n {\n pattern: /node_modules\\/\\.vite\\/deps\\/[^\\s)]+/g,\n replacement: '<vite-dep>',\n },\n];\n\n/**\n * Patterns that identify Vite-mangled export names in error messages.\n */\nconst MANGLED_NAME_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n {\n pattern: /__vite_ssr_export_default__/g,\n replacement: '<default export>',\n },\n {\n pattern: /__vite_ssr_export_(\\w+)__/g,\n replacement: '<export $1>',\n },\n];\n\n/**\n * Rewrite an error's message and stack to replace internal Vite paths\n * and mangled names with human-readable labels.\n */\nexport function formatSsrError(error: unknown): string {\n if (!(error instanceof Error)) {\n return String(error);\n }\n\n let message = error.message;\n let stack = error.stack ?? '';\n\n // Rewrite mangled names in the message\n for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) {\n message = message.replace(pattern, replacement);\n }\n\n // Rewrite vendor paths in the stack\n for (const { pattern, replacement } of VENDOR_PATH_PATTERNS) {\n stack = stack.replace(pattern, replacement);\n }\n\n // Rewrite mangled names in the stack too\n for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) {\n stack = stack.replace(pattern, replacement);\n }\n\n // Extract hints from React-specific error patterns\n const hint = extractErrorHint(error.message);\n\n // Build formatted output: cleaned message, hint (if any), then cleaned stack\n const parts: string[] = [];\n parts.push(message);\n if (hint) {\n parts.push(` → ${hint}`);\n }\n\n // Include only the user-code frames from the stack (skip the first line\n // which is the message itself, and filter out vendor-only frames)\n const userFrames = extractUserFrames(stack);\n if (userFrames.length > 0) {\n parts.push('');\n parts.push(' User code in stack:');\n for (const frame of userFrames) {\n parts.push(` ${frame}`);\n }\n }\n\n return parts.join('\\n');\n}\n\n// ─── Error Hint Extraction ──────────────────────────────────────────────────\n\n/**\n * Extract a human-readable hint from common React/RSC error messages.\n *\n * React error messages contain useful information but the surrounding\n * context (vendor paths, mangled names) obscures it. This extracts the\n * actionable part as a one-line hint.\n */\nfunction extractErrorHint(message: string): string | null {\n // \"Functions cannot be passed directly to Client Components\"\n // Extract the component and prop name from the JSX-like syntax in the message\n const fnPassedMatch = message.match(/Functions cannot be passed directly to Client Components/);\n if (fnPassedMatch) {\n // Try to extract the prop name from the message\n // React formats: <... propName={function ...} ...>\n const propMatch = message.match(/<[^>]*?\\s(\\w+)=\\{function/);\n if (propMatch) {\n return `Prop \"${propMatch[1]}\" is a function — mark it \"use server\" or call it before passing`;\n }\n return 'A function prop was passed to a Client Component — mark it \"use server\" or call it before passing';\n }\n\n // \"Objects are not valid as a React child\"\n if (message.includes('Objects are not valid as a React child')) {\n return 'An object was rendered as JSX children — convert to string or extract the value';\n }\n\n // \"Cannot read properties of undefined/null\"\n const nullRefMatch = message.match(\n /Cannot read propert(?:y|ies) of (undefined|null) \\(reading '(\\w+)'\\)/\n );\n if (nullRefMatch) {\n return `Accessed .${nullRefMatch[2]} on ${nullRefMatch[1]} — check that the value exists`;\n }\n\n // \"X is not a function\"\n const notFnMatch = message.match(/(\\w+) is not a function/);\n if (notFnMatch) {\n return `\"${notFnMatch[1]}\" is not a function — check imports and exports`;\n }\n\n // \"Element type is invalid\"\n if (message.includes('Element type is invalid')) {\n return 'A component resolved to undefined/null — check default exports and import paths';\n }\n\n // \"Invalid hook call\" — hooks called outside React's render context.\n // In RSC, this typically means a 'use client' component was executed as a\n // server component instead of being serialized as a client reference.\n if (message.includes('Invalid hook call')) {\n return (\n 'A hook was called outside of a React component render. ' +\n \"If this is a 'use client' component, ensure the directive is at the very top of the file \" +\n '(before any imports) and that @vitejs/plugin-rsc is loaded correctly. ' +\n \"Barrel re-exports from non-'use client' files do not propagate the directive.\"\n );\n }\n\n return null;\n}\n\n// ─── Stack Frame Filtering ──────────────────────────────────────────────────\n\n/**\n * Extract stack frames that reference user code (not node_modules,\n * not framework internals).\n *\n * Returns at most 5 frames to keep output concise.\n */\nfunction extractUserFrames(stack: string): string[] {\n const lines = stack.split('\\n');\n const userFrames: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Skip non-frame lines\n if (!trimmed.startsWith('at ')) continue;\n // Skip node_modules, vendor, and internal frames\n if (\n trimmed.includes('node_modules') ||\n trimmed.includes('<react-server-dom>') ||\n trimmed.includes('<rsc-vendor>') ||\n trimmed.includes('<vite-dep>') ||\n trimmed.includes('node:internal')\n ) {\n continue;\n }\n userFrames.push(trimmed);\n if (userFrames.length >= 5) break;\n }\n\n return userFrames;\n}\n","/**\n * DefaultLogger — human-readable stderr logging when no custom logger is configured.\n *\n * Ships as the fallback so production deployments always have error visibility,\n * even without an `instrumentation.ts` logger export. Output is one line per\n * event, designed for `fly logs`, `kubectl logs`, Cloudflare dashboard tails, etc.\n *\n * Format:\n * [timber] ERROR message key=value key=value trace_id=4bf92f35\n * [timber] WARN message key=value key=value trace_id=4bf92f35\n * [timber] INFO message method=GET path=/dashboard status=200 durationMs=43 trace_id=4bf92f35\n *\n * Behavior:\n * - `info` and `debug` suppressed in dev mode (dev logging handles them);\n * `warn` and `error` are always written (TIM-555)\n * - `debug` suppressed unless TIMBER_DEBUG is set\n * - Replaced entirely when a custom logger is set via `setLogger()`\n *\n * See design/17-logging.md §\"DefaultLogger\"\n */\n\nimport { isDevMode, isDebug } from './debug.ts';\nimport { formatSsrError } from './error-formatter.ts';\nimport type { TimberLogger } from './logger.ts';\n\n/**\n * Format data fields as `key=value` pairs for human-readable output.\n * - `error` key is serialized via formatSsrError for stack trace cleanup\n * - `trace_id` is truncated to 8 chars for readability (full ID in OTEL)\n * - Other values are stringified inline\n */\nfunction formatDataFields(data?: Record<string, unknown>): string {\n if (!data) return '';\n\n const parts: string[] = [];\n let traceId: string | undefined;\n\n for (const [key, value] of Object.entries(data)) {\n if (key === 'trace_id') {\n // Defer trace_id to the end\n traceId = typeof value === 'string' ? value : String(value);\n continue;\n }\n if (key === 'error') {\n // Serialize errors with formatSsrError for clean output\n parts.push(`error=${formatSsrError(value)}`);\n continue;\n }\n if (value === undefined || value === null) continue;\n parts.push(`${key}=${value}`);\n }\n\n // trace_id always last, truncated to 8 chars for readability\n if (traceId) {\n parts.push(`trace_id=${traceId.slice(0, 8)}`);\n }\n\n return parts.length > 0 ? ' ' + parts.join(' ') : '';\n}\n\n/** Pad level string to fixed width for alignment. */\nfunction padLevel(level: string): string {\n return level.padEnd(5);\n}\n\nexport function createDefaultLogger(): TimberLogger {\n return {\n error(msg: string, data?: Record<string, unknown>): void {\n // Errors are ALWAYS logged, including dev mode. Suppressing errors\n // in dev causes silent 500s with no stack trace, making route.ts\n // and render errors impossible to debug. See TIM-555.\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('ERROR')} ${msg}${fields}\\n`);\n },\n\n warn(msg: string, data?: Record<string, unknown>): void {\n // Warnings are always logged — same rationale as errors.\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('WARN')} ${msg}${fields}\\n`);\n },\n\n info(msg: string, data?: Record<string, unknown>): void {\n // info is suppressed by default — per-request lines are too noisy\n // without a custom logger. Enable with TIMBER_DEBUG.\n if (isDevMode()) return;\n if (!isDebug()) return;\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('INFO')} ${msg}${fields}\\n`);\n },\n\n debug(msg: string, data?: Record<string, unknown>): void {\n // debug is suppressed in dev (dev logger handles it) and in\n // production unless TIMBER_DEBUG is explicitly set.\n if (isDevMode()) return;\n if (!isDebug()) return;\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('DEBUG')} ${msg}${fields}\\n`);\n },\n };\n}\n","// Signal identity — the brands framework signals carry, the predicates that\n// recognise them, and SsrStreamError.\n//\n// No runtime imports (the one import is type-only), so any environment can\n// load it. The SSR entry's import graph\n// must not reach RSC request state (`request-context.ts` and friends, held\n// to that by `tests/ssr-import-boundary.test.ts`), and the signal classes\n// in primitives.ts sit beside `deny()` and `redirect()`, which read it. SSR\n// code that has to recognise a signal (the logger skips them) imports the\n// predicates from here; the classes stamp the brands exported here.\n\nimport type { DenySignal, RedirectSignal } from './primitives.ts';\n\n// ─── Signal branding ────────────────────────────────────────────────────────\n//\n// Catch sites must NOT use `instanceof` on these classes. In dev, an HMR\n// program reload clears the RSC module cache; a request that is mid-render\n// still holds the catch sites from the old evaluation of primitives.ts while\n// user code loaded after the reload throws from the new one. The two\n// evaluations are distinct classes, so `instanceof` fails and a correct\n// deny() falls through every catch site as an unhandled 500 (TIM-1499).\n//\n// Each class stamps a `Symbol.for` brand on its instances in the constructor.\n// `Symbol.for` keys live in the realm-wide symbol registry, so every\n// evaluation of these modules — and every module graph in the same process —\n// agrees on the key. The `is*` predicates below check the brand and are the\n// only supported way to detect a signal. The classes themselves are NOT\n// anchored on globalThis: a re-evaluated module must hand out its own\n// (possibly updated) class, not a stale one.\n//\n// See design/18-build-system.md §\"Dev Mode: Signal Identity Across Program Reloads\".\n\nexport const DENY_BRAND: unique symbol = Symbol.for('timber:signal.deny');\nexport const REDIRECT_BRAND: unique symbol = Symbol.for('timber:signal.redirect');\nconst SSR_STREAM_ERROR_BRAND: unique symbol = Symbol.for('timber:signal.ssr-stream-error');\n\nfunction hasBrand(value: unknown, brand: symbol): boolean {\n return typeof value === 'object' && value !== null && brand in value;\n}\n\n/** True for any `DenySignal`, regardless of which module evaluation created it. */\nexport function isDenySignal(error: unknown): error is DenySignal {\n return hasBrand(error, DENY_BRAND);\n}\n\n/** True for any `RedirectSignal`, regardless of which module evaluation created it. */\nexport function isRedirectSignal(error: unknown): error is RedirectSignal {\n return hasBrand(error, REDIRECT_BRAND);\n}\n\n/**\n * True for any `SsrStreamError`. This one also crosses Vite environments:\n * it is thrown in SSR and caught in RSC, which are separate module graphs in\n * the same process — the brand is the only identity the two share.\n */\nexport function isSsrStreamError(error: unknown): error is SsrStreamError {\n return hasBrand(error, SSR_STREAM_ERROR_BRAND);\n}\n\n/**\n * Returns true if the error is a framework control-flow signal (RedirectSignal\n * or DenySignal) rather than a genuine application error. Works both for direct\n * instances (RSC-side) and deserialized digest errors (SSR cross-boundary).\n *\n * See also: isFrameworkSignalError() in client/browser-dev.ts (client-only).\n */\nexport function isControlFlowSignal(error: unknown): boolean {\n if (isDenySignal(error) || isRedirectSignal(error)) {\n return true;\n }\n if (error && typeof error === 'object') {\n const digest = (error as { digest?: unknown }).digest;\n if (typeof digest === 'string') {\n try {\n const parsed = JSON.parse(digest) as { type?: unknown } | null;\n if (parsed && typeof parsed === 'object') {\n return parsed.type === 'redirect' || parsed.type === 'deny';\n }\n } catch {\n // Not valid digest JSON\n }\n }\n }\n return false;\n}\n\n// ─── SsrStreamError ─────────────────────────────────────────────────────────\n\n/**\n * Error thrown when SSR's renderToReadableStream fails due to an error\n * in the decoded RSC stream (e.g., uncontained slot errors).\n *\n * The RSC entry checks for this error type in its catch block. A captured\n * deny or redirect is rethrown to the pipeline first; with no captured\n * signal, it renders the error page for the uncontained error.\n *\n * Not defined in ssr-entry.ts because ssr-entry.ts imports react-dom/server,\n * which cannot be loaded in the RSC environment.\n *\n * Detect with `isSsrStreamError()` — it is thrown in the SSR environment and\n * caught in RSC, so `instanceof` never matches. See \"Signal branding\" above.\n */\nexport class SsrStreamError extends Error {\n readonly [SSR_STREAM_ERROR_BRAND] = true;\n override readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = 'SsrStreamError';\n this.cause = cause;\n }\n}\n","/**\n * Logger — structured logging with environment-aware formatting.\n *\n * timber.js ships a DefaultLogger that writes human-readable lines to stderr\n * in production. Users can export a custom logger from instrumentation.ts to\n * replace it with pino, winston, or any TimberLogger-compatible object.\n *\n * See design/17-logging.md §\"Production Logging\"\n */\n\nimport { generateTraceId, getTraceStore } from './tracing.ts';\nimport { createDefaultLogger } from './default-logger.ts';\nimport { isDevMode } from './debug.ts';\nimport { isControlFlowSignal } from './signal-identity.ts';\nimport type { CsrfRejectReason } from './csrf.ts';\n\n// ─── Logger Interface ─────────────────────────────────────────────────────\n\n/** Any object with standard log methods satisfies this — pino, winston, consola, console. */\nexport interface TimberLogger {\n info(msg: string, data?: Record<string, unknown>): void;\n warn(msg: string, data?: Record<string, unknown>): void;\n error(msg: string, data?: Record<string, unknown>): void;\n debug(msg: string, data?: Record<string, unknown>): void;\n}\n\n// ─── Logger Registry ──────────────────────────────────────────────────────\n\n// Initialize with DefaultLogger so production errors are never silent.\n// Replaced when setLogger() is called from instrumentation.ts.\nlet _logger: TimberLogger = createDefaultLogger();\n\n/**\n * Set the user-provided logger. Called by the instrumentation loader\n * when it finds a `logger` export in instrumentation.ts. Replaces\n * the DefaultLogger entirely.\n */\nexport function setLogger(logger: TimberLogger): void {\n _logger = logger;\n}\n\n/**\n * Get the current logger. Always non-null — returns DefaultLogger when\n * no custom logger is configured.\n */\nexport function getLogger(): TimberLogger {\n return _logger;\n}\n\n// ─── Framework Log Helpers ────────────────────────────────────────────────\n\n/**\n * Inject trace_id and span_id into log data for log–trace correlation.\n * Always injects trace_id (never undefined). Injects span_id only when OTEL is active.\n */\nfunction withTraceContext(data?: Record<string, unknown>): Record<string, unknown> {\n const store = getTraceStore();\n const enriched: Record<string, unknown> = { ...data };\n if (store) {\n enriched.trace_id = store.request.traceId;\n if (store.spanId) {\n enriched.span_id = store.spanId;\n }\n }\n return enriched;\n}\n\n// ─── Framework Event Emitters ─────────────────────────────────────────────\n\n/**\n * Log a CSRF rejection. Level: warn — the 403 body is deliberately terse,\n * so this line is the only place the rejected origin is visible (TIM-1459).\n * `detail` names the observed origin and, where one exists, the expected one.\n *\n * The gate runs inside the pipeline's trace scope, so the line carries the\n * request's `trace_id`. A caller outside any scope still gets one minted\n * here — the field is always present (design/17-logging.md §\"trace_id is\n * Always Set\").\n */\nexport function logCsrfRejected(\n detail: string,\n data: { method: string; path: string; reason: CsrfRejectReason }\n): void {\n const fields = withTraceContext(data);\n fields.trace_id ??= generateTraceId();\n _logger.warn(`CSRF origin check failed: ${detail}`, fields);\n}\n\n/** Log a completed request. Level: info. */\nexport function logRequestCompleted(data: {\n method: string;\n path: string;\n status: number;\n durationMs: number;\n /** Number of concurrent in-flight requests (including this one) at completion time. */\n concurrency?: number;\n}): void {\n _logger.info('request completed', withTraceContext(data));\n}\n\n/** Log request received. Level: debug. */\nexport function logRequestReceived(data: { method: string; path: string }): void {\n _logger.debug('request received', withTraceContext(data));\n}\n\n/** Log a slow request warning. Level: warn. */\nexport function logSlowRequest(data: {\n method: string;\n path: string;\n durationMs: number;\n threshold: number;\n /** Number of concurrent in-flight requests at the time the slow request completed. */\n concurrency?: number;\n}): void {\n _logger.warn('slow request exceeded threshold', withTraceContext(data));\n}\n\n/** Log middleware short-circuit. Level: debug. */\nexport function logMiddlewareShortCircuit(data: {\n method: string;\n path: string;\n status: number;\n}): void {\n _logger.debug('middleware short-circuited', withTraceContext(data));\n}\n\n/** Log unhandled error in middleware phase. Level: error. */\nexport function logMiddlewareError(data: { method: string; path: string; error: unknown }): void {\n if (isControlFlowSignal(data.error)) return;\n _logger.error('unhandled error in middleware phase', withTraceContext(data));\n}\n\n/** Log unhandled error in route setup (matching, param coercion). Level: error. */\nexport function logRouteSetupError(data: { method: string; path: string; error: unknown }): void {\n if (isControlFlowSignal(data.error)) return;\n _logger.error('unhandled error in route setup', withTraceContext(data));\n}\n\n/** Log unhandled render-phase error. Level: error. */\nexport function logRenderError(data: {\n method: string;\n path: string;\n error: unknown;\n errorId?: string;\n}): void {\n if (isControlFlowSignal(data.error)) return;\n _logger.error('unhandled render-phase error', withTraceContext(data));\n}\n\n/**\n * Log a status page, error page, `global-error.tsx` or fallback layout that\n * failed to load and was skipped: the next fallback tier answers in its place.\n * Level: error — a boundary that vanished is a bug in the app, even though the\n * request still gets a page. The caller writes it once per file and failure.\n */\nexport function logSkippedModule(data: {\n method: string;\n path: string;\n file: string;\n error: unknown;\n}): void {\n _logger.error('route file failed to load and was skipped', withTraceContext(data));\n}\n\n/** Log proxy.ts uncaught error. Level: error. */\nexport function logProxyError(data: { error: unknown }): void {\n _logger.error('proxy.ts threw uncaught error', withTraceContext(data));\n}\n\n/** Log unhandled error in server action. Level: error. */\nexport function logActionError(data: { method: string; path: string; error: unknown }): void {\n if (isControlFlowSignal(data.error)) return;\n _logger.error('unhandled server action error', withTraceContext(data));\n}\n\n/** Log unhandled error in route handler. Level: error. */\nexport function logRouteError(data: { method: string; path: string; error: unknown }): void {\n if (isControlFlowSignal(data.error)) return;\n _logger.error('unhandled route handler error', withTraceContext(data));\n}\n\n/** Log SSR streaming error (post-shell). Level: error. */\nexport function logStreamingError(data: { error: unknown }): void {\n _logger.error('SSR streaming error (post-shell)', withTraceContext(data));\n}\n\n/** Log waitUntil() adapter missing (once at startup). Level: warn. */\nexport function logWaitUntilUnsupported(): void {\n _logger.warn('adapter does not support waitUntil()');\n}\n\n/** Log waitUntil() promise rejection. Level: warn. */\nexport function logWaitUntilRejected(data: { error: unknown }): void {\n _logger.warn('waitUntil() promise rejected', withTraceContext(data));\n}\n\n/** Log staleWhileRevalidate refetch failure. Level: warn. */\nexport function logSwrRefetchFailed(data: { cacheKey: string; error: unknown }): void {\n _logger.warn('staleWhileRevalidate refetch failed', withTraceContext(data));\n}\n\n/** Log a cache value that loses fidelity through JSON serialization. Level: warn. */\nexport function logLossyCacheValue(data: { cacheKey: string; types: string }): void {\n _logger.warn(\n 'cache value contains types that lose fidelity through JSON serialization in ' +\n 'Redis/KV cache handlers: Date becomes an ISO string, Map/Set become {}, BigInt throws. ' +\n 'The MemoryCacheHandler preserves them. Transform values to JSON-safe types before ' +\n 'caching, or use MemoryCacheHandler for values that require type preservation.',\n withTraceContext(data)\n );\n}\n\n/** Log cache miss. Level: debug. */\nexport function logCacheMiss(data: { cacheKey: string }): void {\n _logger.debug('timber.cache MISS', withTraceContext(data));\n}\n\n// ─── Swallow Helper ───────────────────────────────────────────────────────\n\n/**\n * Log an intentionally swallowed error. Provides observability into catch\n * blocks that are deliberately empty — the error is consumed, never rethrown.\n *\n * Default level: `warn` in dev (so the overlay surfaces patterns), `debug`\n * in production (low noise unless TIMBER_DEBUG is set). Pass `opts.level`\n * to override.\n *\n * **Infallible** — swallow() itself never throws, even if the logger is\n * broken. A thrown swallow would turn a benign catch into a crash.\n */\nexport function swallow(err: unknown, reason: string, opts?: { level?: 'debug' | 'warn' }): void {\n try {\n const level = opts?.level ?? (isDevMode() ? 'warn' : 'debug');\n _logger[level](`swallowed: ${reason}`, withTraceContext({ error: err }));\n } catch {\n // swallow() must never throw.\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "node:crypto";
|
|
1
2
|
//#region src/server/metadata-routes.ts
|
|
2
3
|
/**
|
|
3
4
|
* All recognized metadata route file conventions.
|
|
@@ -38,7 +39,7 @@ var METADATA_ROUTE_CONVENTIONS = {
|
|
|
38
39
|
contentType: "image/x-icon",
|
|
39
40
|
nestable: false,
|
|
40
41
|
staticExtensions: ["ico"],
|
|
41
|
-
dynamicExtensions: [],
|
|
42
|
+
dynamicExtensions: ["ts", "tsx"],
|
|
42
43
|
servePath: "favicon.ico"
|
|
43
44
|
},
|
|
44
45
|
"icon": {
|
|
@@ -51,7 +52,8 @@ var METADATA_ROUTE_CONVENTIONS = {
|
|
|
51
52
|
"svg"
|
|
52
53
|
],
|
|
53
54
|
dynamicExtensions: ["ts", "tsx"],
|
|
54
|
-
servePath: "icon"
|
|
55
|
+
servePath: "icon",
|
|
56
|
+
serveExtension: "png"
|
|
55
57
|
},
|
|
56
58
|
"opengraph-image": {
|
|
57
59
|
type: "opengraph-image",
|
|
@@ -59,15 +61,8 @@ var METADATA_ROUTE_CONVENTIONS = {
|
|
|
59
61
|
nestable: true,
|
|
60
62
|
staticExtensions: ["png", "jpg"],
|
|
61
63
|
dynamicExtensions: ["ts", "tsx"],
|
|
62
|
-
servePath: "opengraph-image"
|
|
63
|
-
|
|
64
|
-
"twitter-image": {
|
|
65
|
-
type: "twitter-image",
|
|
66
|
-
contentType: "image/*",
|
|
67
|
-
nestable: true,
|
|
68
|
-
staticExtensions: ["png", "jpg"],
|
|
69
|
-
dynamicExtensions: ["ts", "tsx"],
|
|
70
|
-
servePath: "twitter-image"
|
|
64
|
+
servePath: "opengraph-image",
|
|
65
|
+
serveExtension: "png"
|
|
71
66
|
},
|
|
72
67
|
"apple-icon": {
|
|
73
68
|
type: "apple-icon",
|
|
@@ -75,10 +70,23 @@ var METADATA_ROUTE_CONVENTIONS = {
|
|
|
75
70
|
nestable: true,
|
|
76
71
|
staticExtensions: ["png"],
|
|
77
72
|
dynamicExtensions: ["ts", "tsx"],
|
|
78
|
-
servePath: "apple-icon"
|
|
73
|
+
servePath: "apple-icon",
|
|
74
|
+
serveExtension: "png"
|
|
79
75
|
}
|
|
80
76
|
};
|
|
81
77
|
/**
|
|
78
|
+
* Check if a file extension represents a static (non-code) metadata route file.
|
|
79
|
+
*
|
|
80
|
+
* @param baseName - The base file name without extension (e.g. "sitemap", "icon")
|
|
81
|
+
* @param extension - The file extension without leading dot (e.g. "xml", "png", "ts")
|
|
82
|
+
* @returns true if this is a static file, false if dynamic or unrecognized
|
|
83
|
+
*/
|
|
84
|
+
function isStaticMetadataExtension(baseName, extension) {
|
|
85
|
+
const convention = METADATA_ROUTE_CONVENTIONS[baseName];
|
|
86
|
+
if (!convention) return false;
|
|
87
|
+
return convention.staticExtensions.includes(extension);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
82
90
|
* Check if a file extension represents a dynamic (code) metadata route file.
|
|
83
91
|
*
|
|
84
92
|
* @param baseName - The base file name without extension (e.g. "sitemap", "icon")
|
|
@@ -113,41 +121,77 @@ function classifyMetadataRoute(fileName) {
|
|
|
113
121
|
};
|
|
114
122
|
}
|
|
115
123
|
/**
|
|
116
|
-
* Get the serve path for a metadata route type
|
|
117
|
-
*
|
|
118
|
-
* @param type - The metadata route type
|
|
119
|
-
* @returns The URL path fragment this route serves at
|
|
124
|
+
* Get the default serve path for a metadata route type (using default extension
|
|
125
|
+
* for image routes). Used for auto-link generation when only the type is known.
|
|
120
126
|
*/
|
|
121
127
|
function getMetadataRouteServePath(type) {
|
|
122
|
-
for (const convention of Object.values(METADATA_ROUTE_CONVENTIONS)) if (convention.type === type)
|
|
128
|
+
for (const convention of Object.values(METADATA_ROUTE_CONVENTIONS)) if (convention.type === type) {
|
|
129
|
+
if (convention.serveExtension) return `${convention.servePath}.${convention.serveExtension}`;
|
|
130
|
+
return convention.servePath;
|
|
131
|
+
}
|
|
123
132
|
throw new Error(`[timber] Unknown metadata route type: ${type}`);
|
|
124
133
|
}
|
|
125
134
|
/**
|
|
135
|
+
* All possible serve path segments for metadata routes (includes extension
|
|
136
|
+
* variants for image routes).
|
|
137
|
+
*/
|
|
138
|
+
var METADATA_SERVE_PATHS = /* @__PURE__ */ new Set();
|
|
139
|
+
for (const convention of Object.values(METADATA_ROUTE_CONVENTIONS)) if (convention.serveExtension) for (const ext of [...convention.staticExtensions, convention.serveExtension]) METADATA_SERVE_PATHS.add(`${convention.servePath}.${ext}`);
|
|
140
|
+
else METADATA_SERVE_PATHS.add(convention.servePath);
|
|
141
|
+
function isMetadataRouteServePath(pathname) {
|
|
142
|
+
let lastSegment = pathname.slice(pathname.lastIndexOf("/") + 1);
|
|
143
|
+
const qIdx = lastSegment.indexOf("?");
|
|
144
|
+
let query = "";
|
|
145
|
+
if (qIdx !== -1) {
|
|
146
|
+
query = lastSegment.slice(qIdx + 1);
|
|
147
|
+
lastSegment = lastSegment.slice(0, qIdx);
|
|
148
|
+
}
|
|
149
|
+
if (!METADATA_SERVE_PATHS.has(lastSegment)) return false;
|
|
150
|
+
if (/(?:^|&)(?:import|url|raw|worker|inline)(?:&|$)/.test(query)) return false;
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
126
154
|
* Get the auto-link tags to inject into <head> for metadata route files
|
|
127
155
|
* discovered in a segment.
|
|
128
156
|
*
|
|
157
|
+
* Returns link tags for icon/apple-icon/manifest, and meta tags for
|
|
158
|
+
* opengraph-image (emits both og:image and twitter:image). Returns null
|
|
159
|
+
* for types that don't auto-link (favicon, sitemap, robots).
|
|
160
|
+
*
|
|
129
161
|
* @param type - The metadata route type
|
|
130
162
|
* @param href - The resolved URL path to the metadata route
|
|
131
|
-
* @returns
|
|
163
|
+
* @returns Tag descriptor(s) for the <head>, or null if no auto-link
|
|
132
164
|
*/
|
|
133
165
|
function getMetadataRouteAutoLink(type, href) {
|
|
134
166
|
switch (type) {
|
|
135
|
-
case "icon": return {
|
|
167
|
+
case "icon": return [{
|
|
168
|
+
tag: "link",
|
|
136
169
|
rel: "icon",
|
|
137
170
|
href
|
|
138
|
-
};
|
|
139
|
-
case "apple-icon": return {
|
|
171
|
+
}];
|
|
172
|
+
case "apple-icon": return [{
|
|
173
|
+
tag: "link",
|
|
140
174
|
rel: "apple-touch-icon",
|
|
141
175
|
href
|
|
142
|
-
};
|
|
143
|
-
case "manifest": return {
|
|
176
|
+
}];
|
|
177
|
+
case "manifest": return [{
|
|
178
|
+
tag: "link",
|
|
144
179
|
rel: "manifest",
|
|
145
180
|
href
|
|
146
|
-
};
|
|
147
|
-
|
|
181
|
+
}];
|
|
182
|
+
case "opengraph-image": return [{
|
|
183
|
+
tag: "meta",
|
|
184
|
+
property: "og:image",
|
|
185
|
+
content: href
|
|
186
|
+
}, {
|
|
187
|
+
tag: "meta",
|
|
188
|
+
name: "twitter:image",
|
|
189
|
+
content: href
|
|
190
|
+
}];
|
|
191
|
+
default: return [];
|
|
148
192
|
}
|
|
149
193
|
}
|
|
150
194
|
//#endregion
|
|
151
|
-
export { isDynamicMetadataExtension as a, getMetadataRouteServePath as i, classifyMetadataRoute as n, getMetadataRouteAutoLink as r, METADATA_ROUTE_CONVENTIONS as t };
|
|
195
|
+
export { isDynamicMetadataExtension as a, getMetadataRouteServePath as i, classifyMetadataRoute as n, isMetadataRouteServePath as o, getMetadataRouteAutoLink as r, isStaticMetadataExtension as s, METADATA_ROUTE_CONVENTIONS as t };
|
|
152
196
|
|
|
153
|
-
//# sourceMappingURL=metadata-routes-
|
|
197
|
+
//# sourceMappingURL=metadata-routes-DSDjM_hJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-routes-DSDjM_hJ.js","names":[],"sources":["../../src/server/metadata-routes.ts"],"sourcesContent":["/**\n * Metadata route classification for timber.js.\n *\n * Metadata routes are file-based endpoints that generate well-known URLs for\n * crawlers and browsers (sitemap.xml, robots.txt, OG images, etc.).\n *\n * These routes run through proxy.ts but NOT through middleware.ts or access.ts —\n * they are public endpoints by nature.\n *\n * See design/16-metadata.md §\"Metadata Routes\"\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { HeadElement } from './metadata.ts';\nimport type { Metadata } from './types.ts';\nimport type { ManifestSegmentNode } from './route-matcher.ts';\nimport { extractUrlParts } from './chain-url-parts.ts';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Classification of a metadata route file. */\nexport interface MetadataRouteInfo {\n /** The metadata route type. */\n type: MetadataRouteType;\n /** The content type to serve this route with. */\n contentType: string;\n /** Whether this route can appear in nested segments (not just app root). */\n nestable: boolean;\n}\n\nexport type MetadataRouteType =\n | 'sitemap'\n | 'robots'\n | 'manifest'\n | 'favicon'\n | 'icon'\n | 'opengraph-image'\n | 'apple-icon';\n\n// ─── Convention Table ────────────────────────────────────────────────────────\n\n/**\n * All recognized metadata route file conventions.\n *\n * Each entry maps a base file name (without extension) to its route info.\n * The extensions determine whether the file is static or dynamic.\n *\n * Static extensions: .xml, .txt, .json, .png, .jpg, .ico, .svg\n * Dynamic extensions: .ts, .tsx\n */\nexport const METADATA_ROUTE_CONVENTIONS: Record<\n string,\n {\n type: MetadataRouteType;\n contentType: string;\n nestable: boolean;\n staticExtensions: string[];\n dynamicExtensions: string[];\n /**\n * The URL path basename this file serves at (relative to segment).\n * For image routes, the full serve path includes an extension via\n * `resolveServePathForFile()`.\n */\n servePath: string;\n /**\n * When set, image routes append `.{serveExtension}` to the serve path.\n * Dynamic handlers (`.ts`/`.tsx`) use this as the default. Static files\n * use their own extension instead. Non-image routes leave this undefined.\n */\n serveExtension?: string;\n }\n> = {\n 'sitemap': {\n type: 'sitemap',\n contentType: 'application/xml',\n nestable: true,\n staticExtensions: ['xml'],\n dynamicExtensions: ['ts'],\n servePath: 'sitemap.xml',\n },\n 'robots': {\n type: 'robots',\n contentType: 'text/plain',\n nestable: false,\n staticExtensions: ['txt'],\n dynamicExtensions: ['ts'],\n servePath: 'robots.txt',\n },\n 'manifest': {\n type: 'manifest',\n contentType: 'application/manifest+json',\n nestable: false,\n staticExtensions: ['json'],\n dynamicExtensions: ['ts'],\n servePath: 'manifest.webmanifest',\n },\n 'favicon': {\n type: 'favicon',\n contentType: 'image/x-icon',\n nestable: false,\n staticExtensions: ['ico'],\n dynamicExtensions: ['ts', 'tsx'],\n servePath: 'favicon.ico',\n },\n 'icon': {\n type: 'icon',\n contentType: 'image/*',\n nestable: true,\n staticExtensions: ['png', 'jpg', 'svg'],\n dynamicExtensions: ['ts', 'tsx'],\n servePath: 'icon',\n serveExtension: 'png',\n },\n 'opengraph-image': {\n type: 'opengraph-image',\n contentType: 'image/*',\n nestable: true,\n staticExtensions: ['png', 'jpg'],\n dynamicExtensions: ['ts', 'tsx'],\n servePath: 'opengraph-image',\n serveExtension: 'png',\n },\n\n 'apple-icon': {\n type: 'apple-icon',\n contentType: 'image/*',\n nestable: true,\n staticExtensions: ['png'],\n dynamicExtensions: ['ts', 'tsx'],\n servePath: 'apple-icon',\n serveExtension: 'png',\n },\n};\n\n// ─── MIME Type Resolution ─────────────────────────────────────────────────────\n\n/**\n * Map of file extensions to MIME types for static metadata route files.\n * Used to resolve the generic `image/*` content type for static image files.\n */\nconst EXTENSION_MIME_TYPES: Record<string, string> = {\n xml: 'application/xml',\n txt: 'text/plain',\n json: 'application/json',\n ico: 'image/x-icon',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n};\n\n/**\n * Resolve the concrete MIME type for a static metadata route file.\n *\n * For generic content types like `image/*`, this resolves to the actual\n * MIME type based on the file extension (e.g. `image/png` for `.png`).\n *\n * @param conventionContentType - The content type from the convention table (may be generic like `image/*`)\n * @param extension - The file extension without leading dot (e.g. \"png\", \"xml\")\n * @returns The resolved MIME type\n */\nexport function resolveStaticContentType(conventionContentType: string, extension: string): string {\n if (conventionContentType.includes('*')) {\n return EXTENSION_MIME_TYPES[extension] ?? 'application/octet-stream';\n }\n return conventionContentType;\n}\n\n/**\n * Check if a file extension represents a static (non-code) metadata route file.\n *\n * @param baseName - The base file name without extension (e.g. \"sitemap\", \"icon\")\n * @param extension - The file extension without leading dot (e.g. \"xml\", \"png\", \"ts\")\n * @returns true if this is a static file, false if dynamic or unrecognized\n */\nexport function isStaticMetadataExtension(baseName: string, extension: string): boolean {\n const convention = METADATA_ROUTE_CONVENTIONS[baseName];\n if (!convention) return false;\n return convention.staticExtensions.includes(extension);\n}\n\n/**\n * Check if a file extension represents a dynamic (code) metadata route file.\n *\n * @param baseName - The base file name without extension (e.g. \"sitemap\", \"icon\")\n * @param extension - The file extension without leading dot (e.g. \"ts\", \"tsx\")\n * @returns true if this is a dynamic file, false if static or unrecognized\n */\nexport function isDynamicMetadataExtension(baseName: string, extension: string): boolean {\n const convention = METADATA_ROUTE_CONVENTIONS[baseName];\n if (!convention) return false;\n return convention.dynamicExtensions.includes(extension);\n}\n\n// ─── Classification ──────────────────────────────────────────────────────────\n\n/**\n * Classify a file name as a metadata route, or return null if it's not one.\n *\n * @param fileName - The full file name including extension (e.g. \"sitemap.xml\", \"icon.tsx\")\n * @returns Classification info, or null if not a metadata route\n */\nexport function classifyMetadataRoute(fileName: string): MetadataRouteInfo | null {\n const dotIndex = fileName.lastIndexOf('.');\n if (dotIndex === -1) return null;\n\n const baseName = fileName.slice(0, dotIndex);\n const ext = fileName.slice(dotIndex + 1);\n\n const convention = METADATA_ROUTE_CONVENTIONS[baseName];\n if (!convention) return null;\n\n const isStatic = convention.staticExtensions.includes(ext);\n const isDynamic = convention.dynamicExtensions.includes(ext);\n\n if (!isStatic && !isDynamic) return null;\n\n return {\n type: convention.type,\n contentType: convention.contentType,\n nestable: convention.nestable,\n };\n}\n\n/**\n * Resolve the serve path for a metadata route file.\n *\n * For image routes (icon, opengraph-image, apple-icon), the serve path includes\n * a file extension so CDNs cache correctly:\n * - Dynamic handlers (.ts/.tsx) use the convention's `serveExtension` (default: .png)\n * - Static files use their own extension (e.g., icon.svg → icon.svg)\n *\n * Non-image routes return the convention's `servePath` as-is (already includes\n * extension: sitemap.xml, robots.txt, etc.).\n */\nexport function resolveServePathForFile(baseName: string, filePath: string): string {\n const convention = METADATA_ROUTE_CONVENTIONS[baseName];\n if (!convention) return baseName;\n\n if (!convention.serveExtension) return convention.servePath;\n\n const ext = filePath.slice(filePath.lastIndexOf('.') + 1);\n if (convention.staticExtensions.includes(ext)) {\n return `${convention.servePath}.${ext}`;\n }\n return `${convention.servePath}.${convention.serveExtension}`;\n}\n\n/**\n * Get the default serve path for a metadata route type (using default extension\n * for image routes). Used for auto-link generation when only the type is known.\n */\nexport function getMetadataRouteServePath(type: MetadataRouteType): string {\n for (const convention of Object.values(METADATA_ROUTE_CONVENTIONS)) {\n if (convention.type === type) {\n if (convention.serveExtension) {\n return `${convention.servePath}.${convention.serveExtension}`;\n }\n return convention.servePath;\n }\n }\n throw new Error(`[timber] Unknown metadata route type: ${type}`);\n}\n\n/**\n * All possible serve path segments for metadata routes (includes extension\n * variants for image routes).\n */\nconst METADATA_SERVE_PATHS = new Set<string>();\nfor (const convention of Object.values(METADATA_ROUTE_CONVENTIONS)) {\n if (convention.serveExtension) {\n for (const ext of [...convention.staticExtensions, convention.serveExtension]) {\n METADATA_SERVE_PATHS.add(`${convention.servePath}.${ext}`);\n }\n } else {\n METADATA_SERVE_PATHS.add(convention.servePath);\n }\n}\n\nexport function isMetadataRouteServePath(pathname: string): boolean {\n let lastSegment = pathname.slice(pathname.lastIndexOf('/') + 1);\n const qIdx = lastSegment.indexOf('?');\n let query = '';\n if (qIdx !== -1) {\n query = lastSegment.slice(qIdx + 1);\n lastSegment = lastSegment.slice(0, qIdx);\n }\n if (!METADATA_SERVE_PATHS.has(lastSegment)) return false;\n // Vite module requests (e.g., /src/icon.svg?import) use special query params.\n // These are source assets, not metadata routes.\n if (/(?:^|&)(?:import|url|raw|worker|inline)(?:&|$)/.test(query)) return false;\n return true;\n}\n\n/** A <link> auto-link tag. */\nexport interface AutoLinkLink {\n tag: 'link';\n rel: string;\n href: string;\n type?: string;\n}\n\n/** A <meta> auto-link tag. */\nexport interface AutoLinkMeta {\n tag: 'meta';\n property?: string;\n name?: string;\n content: string;\n}\n\nexport type AutoLinkTag = AutoLinkLink | AutoLinkMeta;\n\n/**\n * Get the auto-link tags to inject into <head> for metadata route files\n * discovered in a segment.\n *\n * Returns link tags for icon/apple-icon/manifest, and meta tags for\n * opengraph-image (emits both og:image and twitter:image). Returns null\n * for types that don't auto-link (favicon, sitemap, robots).\n *\n * @param type - The metadata route type\n * @param href - The resolved URL path to the metadata route\n * @returns Tag descriptor(s) for the <head>, or null if no auto-link\n */\nexport function getMetadataRouteAutoLink(type: MetadataRouteType, href: string): AutoLinkTag[] {\n switch (type) {\n case 'icon':\n return [{ tag: 'link', rel: 'icon', href }];\n case 'apple-icon':\n return [{ tag: 'link', rel: 'apple-touch-icon', href }];\n case 'manifest':\n return [{ tag: 'link', rel: 'manifest', href }];\n case 'opengraph-image':\n return [\n { tag: 'meta', property: 'og:image', content: href },\n { tag: 'meta', name: 'twitter:image', content: href },\n ];\n default:\n return [];\n }\n}\n\n// ─── Auto-Linking ──────────────────────────────────────────────────────────\n\n// In dev mode, use a per-startup nonce for metadata route cache busting\n// instead of per-file content hashes (avoids rehashing on every request).\nlet _devNonce: string | undefined;\nfunction getDevNonce(): string {\n _devNonce ??= randomUUID().slice(0, 8);\n return _devNonce;\n}\n\n/**\n * Collect auto-linked head elements from metadata route files in the segment chain.\n *\n * Walks each segment's metadataRoutes, resolves serve paths and URLs, and\n * emits HeadElement descriptors for <link> and <meta> tags that React Float\n * hoists into <head>.\n *\n * A metadata file is served under the URL of the segment that owns it, not\n * under every descendant URL: a root `app/icon.tsx` rendered on `/map` links\n * `/icon.png`, and `app/posts/[id]/opengraph-image.tsx` on `/posts/42/comments`\n * links `/posts/42/opengraph-image.png`. The owner's prefix is the URL parts\n * the chain has consumed through that segment (`extractUrlParts`, the same\n * walk slot matching uses), filled with the request's raw param values — the\n * parts the metadata route matcher walks back to the same owner.\n *\n * Segments at or below an intercepting segment are skipped: the metadata\n * matcher only walks the canonical tree, so nothing serves their files.\n *\n * See design/16-metadata.md §\"Auto-Linking\"\n */\nexport function collectMetadataRouteHeadElements(\n segments: ManifestSegmentNode[],\n firstDeniedIndex: number,\n resolvedMetadata: Metadata,\n requestUrl: URL,\n rawSegmentParams: Record<string, string | string[]>,\n metadataRouteHashes?: Record<string, string>\n): HeadElement[] {\n const elements: HeadElement[] = [];\n const hasUserOgImage = Boolean(resolvedMetadata.openGraph?.images);\n const hasUserTwitterImage = Boolean(resolvedMetadata.twitter?.images);\n // In dev mode, use the request origin so OG URLs resolve to localhost.\n // In production, use metadataBase (the canonical domain).\n const ogBase =\n process.env.NODE_ENV !== 'production'\n ? new URL(requestUrl.origin)\n : resolvedMetadata.metadataBase;\n\n const interceptingIndex = segments.findIndex((s) => s.segmentType === 'intercepting');\n const servedDepth = interceptingIndex === -1 ? segments.length : interceptingIndex;\n\n for (let si = 0; si < servedDepth; si++) {\n const segment = segments[si];\n if (!segment.metadataRoutes) continue;\n if (si >= firstDeniedIndex) continue;\n // Params are canonical (decoded) values; encode each part so the href\n // canonicalizes back to the pathname the matcher resolves to this owner.\n const segmentPrefix = extractUrlParts(segments.slice(0, si + 1), rawSegmentParams)\n .map((part) => `/${encodeURIComponent(part)}`)\n .join('');\n for (const baseName of Object.keys(segment.metadataRoutes)) {\n const convention = METADATA_ROUTE_CONVENTIONS[baseName];\n if (!convention) continue;\n if (!convention.nestable && segment.urlPath !== '/') continue;\n if (convention.type === 'opengraph-image' && hasUserOgImage) continue;\n const metaFile = segment.metadataRoutes[baseName];\n const fileServePath = metaFile?.filePath\n ? resolveServePathForFile(baseName, metaFile.filePath)\n : convention.serveExtension\n ? `${convention.servePath}.${convention.serveExtension}`\n : convention.servePath;\n let href = `${segmentPrefix}/${fileServePath}`;\n if (convention.type === 'opengraph-image') {\n const fileHash = metaFile?.filePath ? metadataRouteHashes?.[metaFile.filePath] : undefined;\n const cacheBust = fileHash ?? getDevNonce();\n href = `${href}?${cacheBust}`;\n }\n if (ogBase && convention.type === 'opengraph-image') {\n href = new URL(href, ogBase).toString();\n }\n for (const autoLink of getMetadataRouteAutoLink(convention.type, href)) {\n if (\n hasUserTwitterImage &&\n autoLink.tag === 'meta' &&\n 'name' in autoLink &&\n autoLink.name === 'twitter:image'\n )\n continue;\n if (autoLink.tag === 'link') {\n const attrs: Record<string, string> = { rel: autoLink.rel, href: autoLink.href };\n if (autoLink.type) attrs.type = autoLink.type;\n elements.push({ tag: 'link', attrs });\n } else {\n const attrs: Record<string, string> = { content: autoLink.content };\n if (autoLink.property) attrs.property = autoLink.property;\n if (autoLink.name) attrs.name = autoLink.name;\n elements.push({ tag: 'meta', attrs });\n }\n }\n }\n }\n return elements;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { l as globalRouter, n as _setGlobalRouter } from "./state-BhNGPsdi.js";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
//#region src/client/router-ref.ts
|
|
4
|
+
/**
|
|
5
|
+
* Set the global router instance. Called once during bootstrap.
|
|
6
|
+
*/
|
|
7
|
+
function setGlobalRouter(router) {
|
|
8
|
+
_setGlobalRouter(router);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the global router instance. Throws if called before bootstrap.
|
|
12
|
+
* Used by client-side hooks (usePendingNavigation, etc.)
|
|
13
|
+
*/
|
|
14
|
+
function getRouter() {
|
|
15
|
+
if (!globalRouter) throw new Error("[timber] Router not initialized. getRouter() was called before bootstrap().");
|
|
16
|
+
return globalRouter;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the global router instance or null if not yet initialized.
|
|
20
|
+
* Used by useRouter() methods to avoid silent failures — callers
|
|
21
|
+
* can log a meaningful warning instead of silently no-oping.
|
|
22
|
+
*/
|
|
23
|
+
function getRouterOrNull() {
|
|
24
|
+
return globalRouter;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/client/use-pending-navigation.ts
|
|
28
|
+
function subscribe(onStoreChange) {
|
|
29
|
+
const router = getRouterOrNull();
|
|
30
|
+
if (!router) return () => {};
|
|
31
|
+
return router.onPendingChange(onStoreChange);
|
|
32
|
+
}
|
|
33
|
+
function getSnapshot() {
|
|
34
|
+
const router = getRouterOrNull();
|
|
35
|
+
return router ? router.isPending() : false;
|
|
36
|
+
}
|
|
37
|
+
var getServerSnapshot = getSnapshot;
|
|
38
|
+
/**
|
|
39
|
+
* Returns true while an RSC navigation is in flight.
|
|
40
|
+
*
|
|
41
|
+
* Reads from the router's external pending store via useSyncExternalStore.
|
|
42
|
+
* Only components that call this hook re-render when pending state
|
|
43
|
+
* changes — no full-tree re-render.
|
|
44
|
+
*
|
|
45
|
+
* ```tsx
|
|
46
|
+
* 'use client'
|
|
47
|
+
* import { usePendingNavigation } from '@timber-js/app/client'
|
|
48
|
+
*
|
|
49
|
+
* export function NavBar() {
|
|
50
|
+
* const isPending = usePendingNavigation()
|
|
51
|
+
* return (
|
|
52
|
+
* <nav className={isPending ? 'opacity-50' : ''}>
|
|
53
|
+
* <Link href="/dashboard">Dashboard</Link>
|
|
54
|
+
* </nav>
|
|
55
|
+
* )
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
function usePendingNavigation() {
|
|
60
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/client/top-loader.tsx
|
|
64
|
+
/**
|
|
65
|
+
* TopLoader — Built-in progress bar for client navigations.
|
|
66
|
+
*
|
|
67
|
+
* Shows an animated progress bar at the top of the viewport while an RSC
|
|
68
|
+
* navigation is in flight. Injected automatically by the framework into
|
|
69
|
+
* NavigationRoot — users never render this component directly.
|
|
70
|
+
*
|
|
71
|
+
* Configuration is via timber.config.ts `topLoader` key. Enabled by default.
|
|
72
|
+
* Users who want a fully custom progress indicator disable the built-in one
|
|
73
|
+
* (`topLoader: { enabled: false }`) and use `usePendingNavigation()` directly.
|
|
74
|
+
*
|
|
75
|
+
* Animation approach: pure CSS @keyframes. The bar crawls from 0% to ~90%
|
|
76
|
+
* width over ~30s using ease-out timing. When navigation completes, the bar
|
|
77
|
+
* snaps to 100% and fades out over 200ms. No JS animation loops (RAF, setInterval).
|
|
78
|
+
*
|
|
79
|
+
* Phase transitions are derived synchronously during render (React's
|
|
80
|
+
* getDerivedStateFromProps pattern) — no useEffect needed for state tracking.
|
|
81
|
+
* The finishing → hidden cleanup uses onTransitionEnd from the CSS transition.
|
|
82
|
+
*
|
|
83
|
+
* When delay > 0, CSS animation-delay + a visibility keyframe ensure the bar
|
|
84
|
+
* stays invisible during the delay period. If navigation finishes before the
|
|
85
|
+
* delay, the bar was never visible so the finish transition is also invisible.
|
|
86
|
+
*
|
|
87
|
+
* See design/19-client-navigation.md §"usePendingNavigation()"
|
|
88
|
+
* See LOCAL-336 for design decisions.
|
|
89
|
+
*/
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/client/navigation-root.tsx
|
|
92
|
+
/**
|
|
93
|
+
* Module-level flag indicating a hard (MPA) navigation is in progress.
|
|
94
|
+
*
|
|
95
|
+
* When true:
|
|
96
|
+
* - NavigationRoot throws an unresolved thenable to suspend forever,
|
|
97
|
+
* preventing React from rendering children during page teardown
|
|
98
|
+
* (avoids "Rendered more hooks" crashes).
|
|
99
|
+
* - The Navigation API handler skips interception, letting the browser
|
|
100
|
+
* perform a full page load (prevents infinite loops where
|
|
101
|
+
* window.location.href → navigate event → router.navigate → 500 →
|
|
102
|
+
* window.location.href → ...).
|
|
103
|
+
*
|
|
104
|
+
* Uses globalThis for singleton guarantee across chunks (same pattern
|
|
105
|
+
* as NavigationContext). See design/19-client-navigation.md §"Singleton
|
|
106
|
+
* Guarantee via globalThis".
|
|
107
|
+
*/
|
|
108
|
+
var HARD_NAV_KEY = Symbol.for("__timber_hard_navigating");
|
|
109
|
+
function getHardNavStore() {
|
|
110
|
+
const g = globalThis;
|
|
111
|
+
if (!g[HARD_NAV_KEY]) g[HARD_NAV_KEY] = { value: false };
|
|
112
|
+
return g[HARD_NAV_KEY];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Set the hard-navigating flag. Call this BEFORE setting
|
|
116
|
+
* window.location.href or window.location.reload() to prevent:
|
|
117
|
+
* 1. React from rendering children during page teardown
|
|
118
|
+
* 2. Navigation API from intercepting the hard navigation
|
|
119
|
+
*/
|
|
120
|
+
function setHardNavigating(value) {
|
|
121
|
+
getHardNavStore().value = value;
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { setGlobalRouter as a, getRouterOrNull as i, usePendingNavigation as n, getRouter as r, setHardNavigating as t };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=navigation-root-BQfo1-kG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-root-BQfo1-kG.js","names":[],"sources":["../../src/client/router-ref.ts","../../src/client/use-pending-navigation.ts","../../src/client/top-loader.tsx","../../src/client/navigation-root.tsx"],"sourcesContent":["// Global router reference — shared between browser-entry and client hooks.\n//\n// Delegates to client/state.ts for the actual module-level variable.\n// This ensures singleton semantics regardless of import path — all\n// callers converge on the same state.ts instance via the barrel.\n//\n// See design/18-build-system.md §\"Module Singleton Strategy\"\n\nimport type { RouterInstance } from './router-types.ts';\nimport { globalRouter, _setGlobalRouter } from './state.ts';\n\n/**\n * Set the global router instance. Called once during bootstrap.\n */\nexport function setGlobalRouter(router: RouterInstance): void {\n _setGlobalRouter(router);\n}\n\n/**\n * Get the global router instance. Throws if called before bootstrap.\n * Used by client-side hooks (usePendingNavigation, etc.)\n */\nexport function getRouter(): RouterInstance {\n if (!globalRouter) {\n throw new Error('[timber] Router not initialized. getRouter() was called before bootstrap().');\n }\n return globalRouter;\n}\n\n/**\n * Get the global router instance or null if not yet initialized.\n * Used by useRouter() methods to avoid silent failures — callers\n * can log a meaningful warning instead of silently no-oping.\n */\nexport function getRouterOrNull(): RouterInstance | null {\n return globalRouter;\n}\n\n/**\n * Reset the global router to null. Used only in tests to isolate\n * module-level state between test cases.\n * @internal\n */\nexport function resetGlobalRouter(): void {\n _setGlobalRouter(null);\n}\n","import { useSyncExternalStore } from 'react';\nimport { getRouterOrNull } from './router-ref.ts';\n\nfunction subscribe(onStoreChange: () => void): () => void {\n const router = getRouterOrNull();\n if (!router) return () => {};\n return router.onPendingChange(onStoreChange);\n}\n\nfunction getSnapshot(): boolean {\n const router = getRouterOrNull();\n return router ? router.isPending() : false;\n}\n\nconst getServerSnapshot = getSnapshot;\n\n/**\n * Returns true while an RSC navigation is in flight.\n *\n * Reads from the router's external pending store via useSyncExternalStore.\n * Only components that call this hook re-render when pending state\n * changes — no full-tree re-render.\n *\n * ```tsx\n * 'use client'\n * import { usePendingNavigation } from '@timber-js/app/client'\n *\n * export function NavBar() {\n * const isPending = usePendingNavigation()\n * return (\n * <nav className={isPending ? 'opacity-50' : ''}>\n * <Link href=\"/dashboard\">Dashboard</Link>\n * </nav>\n * )\n * }\n * ```\n */\nexport function usePendingNavigation(): boolean {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","/**\n * TopLoader — Built-in progress bar for client navigations.\n *\n * Shows an animated progress bar at the top of the viewport while an RSC\n * navigation is in flight. Injected automatically by the framework into\n * NavigationRoot — users never render this component directly.\n *\n * Configuration is via timber.config.ts `topLoader` key. Enabled by default.\n * Users who want a fully custom progress indicator disable the built-in one\n * (`topLoader: { enabled: false }`) and use `usePendingNavigation()` directly.\n *\n * Animation approach: pure CSS @keyframes. The bar crawls from 0% to ~90%\n * width over ~30s using ease-out timing. When navigation completes, the bar\n * snaps to 100% and fades out over 200ms. No JS animation loops (RAF, setInterval).\n *\n * Phase transitions are derived synchronously during render (React's\n * getDerivedStateFromProps pattern) — no useEffect needed for state tracking.\n * The finishing → hidden cleanup uses onTransitionEnd from the CSS transition.\n *\n * When delay > 0, CSS animation-delay + a visibility keyframe ensure the bar\n * stays invisible during the delay period. If navigation finishes before the\n * delay, the bar was never visible so the finish transition is also invisible.\n *\n * See design/19-client-navigation.md §\"usePendingNavigation()\"\n * See LOCAL-336 for design decisions.\n */\n\n'use client';\n\nimport { useState, createElement } from 'react';\nimport { usePendingNavigation } from './use-pending-navigation.ts';\n\n// ─── Types ───────────────────────────────────────────────────────\n\nexport interface TopLoaderConfig {\n /** Whether the top-loader is enabled. Default: true. */\n enabled?: boolean;\n /** Bar color. Default: '#2299DD'. */\n color?: string;\n /** Bar height in pixels. Default: 3. */\n height?: number;\n /** Show subtle glow/shadow effect. Default: false. */\n shadow?: boolean;\n /** Delay in ms before showing the bar. Default: 0. */\n delay?: number;\n /** CSS z-index. Default: 1600. */\n zIndex?: number;\n}\n\n// ─── Defaults ────────────────────────────────────────────────────\n\nconst DEFAULT_COLOR = '#2299DD';\nconst DEFAULT_HEIGHT = 3;\nconst DEFAULT_SHADOW = false;\nconst DEFAULT_DELAY = 0;\nconst DEFAULT_Z_INDEX = 1600;\n\n// ─── Keyframes ───────────────────────────────────────────────────\n\n// Unique keyframes name to avoid collisions with user styles.\nconst CRAWL_KEYFRAMES = '__timber_top_loader_crawl';\nconst APPEAR_KEYFRAMES = '__timber_top_loader_appear';\nconst FINISH_KEYFRAMES = '__timber_top_loader_finish';\n\n// Track whether the @keyframes rules have been injected into the document.\nlet keyframesInjected = false;\n\n/**\n * Inject the @keyframes rules into the document head once.\n * Called during render (idempotent). Uses a <style> tag so the\n * animations are available for inline-styled elements.\n */\nfunction ensureKeyframes(): void {\n if (keyframesInjected) return;\n if (typeof document === 'undefined') return;\n\n const style = document.createElement('style');\n style.textContent = `\n@keyframes ${CRAWL_KEYFRAMES} {\n 0% { width: 0%; }\n 100% { width: 90%; }\n}\n@keyframes ${APPEAR_KEYFRAMES} {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n@keyframes ${FINISH_KEYFRAMES} {\n 0% { width: 90%; opacity: 1; }\n 50% { width: 100%; opacity: 1; }\n 100% { width: 100%; opacity: 0; }\n}\n`;\n document.head.appendChild(style);\n keyframesInjected = true;\n}\n\n// ─── Component ───────────────────────────────────────────────────\n\n/**\n * Internal top-loader component. Injected by NavigationRoot.\n *\n * Reads pending navigation state from the router's external store, via\n * usePendingNavigation() — the one pending representation (TIM-1307).\n * Phase transitions are derived synchronously during render:\n *\n * hidden → crawling: when isPending becomes true\n * crawling → finishing: when isPending becomes false\n * finishing → hidden: when CSS transition ends (onTransitionEnd)\n * finishing → crawling: when isPending becomes true again\n *\n * No useEffect — all state changes are either derived during render\n * (getDerivedStateFromProps pattern) or triggered by DOM events.\n */\nexport function TopLoader({ config }: { config?: TopLoaderConfig }): React.ReactElement | null {\n // Read pending state from the router's external store via\n // useSyncExternalStore (inside usePendingNavigation). Only this\n // component re-renders when pending changes — no full-tree re-render.\n const isPending = usePendingNavigation();\n\n const color = config?.color ?? DEFAULT_COLOR;\n const height = config?.height ?? DEFAULT_HEIGHT;\n const shadow = config?.shadow ?? DEFAULT_SHADOW;\n const delay = config?.delay ?? DEFAULT_DELAY;\n const zIndex = config?.zIndex ?? DEFAULT_Z_INDEX;\n\n const [phase, setPhase] = useState<'hidden' | 'crawling' | 'finishing'>('hidden');\n\n // ─── Synchronous phase derivation (getDerivedStateFromProps) ──\n // React allows setState during render if the value changes — it\n // immediately re-renders with the updated state before committing.\n\n if (isPending && (phase === 'hidden' || phase === 'finishing')) {\n setPhase('crawling');\n }\n if (!isPending && phase === 'crawling') {\n setPhase('finishing');\n }\n\n // Inject keyframes on first visible render (idempotent)\n if (phase !== 'hidden') {\n ensureKeyframes();\n }\n\n if (phase === 'hidden') return null;\n\n // ─── Styles ──────────────────────────────────────────────────\n\n const containerStyle: React.CSSProperties = {\n position: 'fixed',\n top: 0,\n left: 0,\n width: '100%',\n height: `${height}px`,\n zIndex,\n pointerEvents: 'none',\n };\n\n const barStyle: React.CSSProperties = {\n height: '100%',\n backgroundColor: color,\n ...(phase === 'crawling'\n ? {\n // Crawl from 0% to 90% over 30s. When delay > 0, both the crawl\n // and a visibility animation are delayed — the bar stays at width 0%\n // and opacity 0 during the delay, then appears and starts crawling.\n // With delay 0, the appear animation is instant (0s duration, no delay).\n animation: [\n `${CRAWL_KEYFRAMES} 30s ease-out ${delay}ms forwards`,\n `${APPEAR_KEYFRAMES} 0s ${delay}ms both`,\n ].join(', '),\n }\n : {\n // Finishing: fill to 100% then fade out via a keyframe animation.\n // We use a keyframe instead of a CSS transition because the\n // animation-to-transition handoff is unreliable — the browser\n // may not capture the animated width as the transition's \"from\"\n // value when both the animation removal and transition are\n // applied in the same render frame.\n animation: `${FINISH_KEYFRAMES} 400ms ease forwards`,\n }),\n ...(shadow\n ? {\n boxShadow: `0 0 10px ${color}, 0 0 5px ${color}`,\n }\n : {}),\n };\n\n // Clean up the finishing phase when the finish animation completes.\n const handleAnimationEnd =\n phase === 'finishing'\n ? (e: React.AnimationEvent) => {\n if (e.animationName === FINISH_KEYFRAMES) {\n setPhase('hidden');\n }\n }\n : undefined;\n\n return createElement(\n 'div',\n {\n 'style': containerStyle,\n 'aria-hidden': 'true',\n 'data-timber-top-loader': '',\n },\n createElement('div', { style: barStyle, onAnimationEnd: handleAnimationEnd })\n );\n}\n","/**\n * NavigationRoot — the component the router renders the page through.\n *\n * It is stateless. The router owns the displayed tree and drives React with\n * `root.render(<NavigationRoot rendered={{ element, publish }} />)` inside a\n * synchronous `startTransition` (see `client/react-root.ts`). A transition\n * update keeps the committed tree on screen while the incoming one resolves,\n * instead of replacing it with a Suspense fallback — the reason this\n * component exists (TIM-1306).\n *\n * It used to hold the tree in `useState` and register `setState` closures\n * into module globals during render so the router could reach into it, with a\n * second set of stand-in closures for the window before a root existed\n * (TIM-600). Inverting that — router calls React, not the reverse — deleted\n * all of it (TIM-1431). Next.js's `use-action-queue.ts` says it wants this\n * shape and cannot have it because it must decode Flight during render;\n * timber decodes in `router-pipeline.ts`, so nothing stands in the way.\n *\n * What this component does own is **the commit-time publish**: a navigation's\n * state (segment cache, address bar, history stack, pathname) is published\n * from a layout effect keyed on the tree object, so the event that puts a\n * route on screen is the event that makes it current (TIM-1301). Props work\n * for that exactly as state did.\n *\n * This component holds no pending state. The `TopLoader` it renders and the\n * public `usePendingNavigation()` both subscribe to the router's external\n * pending store; NavigationRoot's own `pendingUrl` was a second, unread\n * representation of the same fact and is gone (TIM-1307).\n *\n * Hard navigation guard: When a hard navigation is triggered (500 error,\n * version skew), the component throws an unresolved thenable AFTER all\n * hooks to suspend forever — preventing React from rendering children\n * during page teardown. The throw must come after hooks to satisfy\n * React's rules (same hook count every render) while still preventing\n * child renders that could hit hook count mismatches in components\n * whose positions shift during teardown. This pattern is borrowed from\n * Next.js (app-router.tsx pushRef.mpaNavigation — also after hooks).\n *\n * See design/05-streaming.md §\"deferSuspenseFor\"\n * See design/19-client-navigation.md §\"NavigationContext\"\n */\n\nimport { createElement, Fragment, useLayoutEffect, useRef, type ReactNode } from 'react';\nimport { TopLoader, type TopLoaderConfig } from './top-loader.tsx';\n\n// ─── Rendered Tree ──────────────────────────────────────────────\n\n/**\n * The tree the router has handed to React, and the state publish that belongs\n * to it. They travel as one object so React's commit of the tree is the event\n * that publishes — see the effect in NavigationRoot. Every `render` builds a\n * fresh one, which is what keys that effect: a tree is published once, however\n * many times React re-runs the effect for it.\n */\nexport interface RenderedTree {\n element: ReactNode;\n /**\n * Publishes the navigation's state — segment cache, pathname, address bar,\n * history stack, and the client's record of the mounted tree — and\n * announces it to listeners outside React. Runs when React commits\n * `element`, never before (TIM-1301). Null for a render that has nothing to\n * publish on commit (hydration, the shallow search re-wrap).\n */\n publish: (() => void) | null;\n}\n\n/**\n * Hand a tree to React in a transition. `publish` runs when React commits it.\n *\n * Every path that puts a page on screen goes through one of these — a\n * navigation, a revalidation, a popstate replay, a shallow search re-wrap —\n * and it is always a synchronous `startTransition` around `root.render`.\n * The production one is `createReactRoot().render`.\n *\n * `types` are the view transition types this render animates as\n * (design/37-navigation-api.md §\"Transition types\"). They are added with\n * `addTransitionType` inside that same `startTransition`, and nowhere else:\n * React queues types per root and hands them to the next transition-only\n * commit, so a type added in any other scope describes whichever tree commits\n * next rather than this one (TIM-1463, TIM-1471). Empty for the shallow search\n * re-wrap, which re-renders the displayed page rather than changing it.\n */\nexport type NavigationRender = (\n element: ReactNode,\n publish: (() => void) | null,\n types: readonly string[]\n) => void;\n\n// ─── Hard Navigation Guard ──────────────────────────────────────\n\n/**\n * Module-level flag indicating a hard (MPA) navigation is in progress.\n *\n * When true:\n * - NavigationRoot throws an unresolved thenable to suspend forever,\n * preventing React from rendering children during page teardown\n * (avoids \"Rendered more hooks\" crashes).\n * - The Navigation API handler skips interception, letting the browser\n * perform a full page load (prevents infinite loops where\n * window.location.href → navigate event → router.navigate → 500 →\n * window.location.href → ...).\n *\n * Uses globalThis for singleton guarantee across chunks (same pattern\n * as NavigationContext). See design/19-client-navigation.md §\"Singleton\n * Guarantee via globalThis\".\n */\nconst HARD_NAV_KEY = Symbol.for('__timber_hard_navigating');\n\nfunction getHardNavStore(): { value: boolean } {\n const g = globalThis as Record<symbol, unknown>;\n if (!g[HARD_NAV_KEY]) {\n g[HARD_NAV_KEY] = { value: false };\n }\n return g[HARD_NAV_KEY] as { value: boolean };\n}\n\n/**\n * Set the hard-navigating flag. Call this BEFORE setting\n * window.location.href or window.location.reload() to prevent:\n * 1. React from rendering children during page teardown\n * 2. Navigation API from intercepting the hard navigation\n */\nexport function setHardNavigating(value: boolean): void {\n getHardNavStore().value = value;\n}\n\n/**\n * Check if a hard navigation is in progress.\n * Used by NavigationRoot (throw unresolvedThenable) and by the\n * Navigation API handler (skip interception).\n */\nexport function isHardNavigating(): boolean {\n return getHardNavStore().value;\n}\n\n/**\n * A thenable that never resolves. When thrown during React render,\n * it causes the component to suspend forever — React keeps the\n * old committed tree visible and never attempts to render children.\n *\n * This is the same pattern Next.js uses in app-router.tsx for MPA\n * navigations (pushRef.mpaNavigation → throw unresolvedThenable).\n */\n// for React's Suspense mechanism. Same pattern as Next.js's unresolvedThenable.\n// eslint-disable-next-line unicorn/no-thenable -- Intentionally a never-resolving thenable\nconst unresolvedThenable = { then() {} } as PromiseLike<never>;\n\n// ─── Component ───────────────────────────────────────────────────\n\n/**\n * Root component the router renders the page through.\n *\n * Renders the TopLoader alongside the tree it is given. Neither adds a DOM\n * element on the hydration path, so the tree matches the server HTML.\n *\n * Rendered only by `createReactRoot` (client/react-root.ts): hydration passes\n * `{ element, publish: null }`, and every later render is a synchronous\n * `startTransition(() => root.render(...))` with a fresh `rendered` object.\n */\nexport function NavigationRoot({\n rendered,\n topLoaderConfig,\n}: {\n rendered: RenderedTree;\n topLoaderConfig?: TopLoaderConfig;\n}): ReactNode {\n // Publish the navigation's state when React commits its tree — not when the\n // tree is handed over. A tree React is still waiting on, or one a later\n // navigation replaces before React renders it, has been *given* to React\n // without being on screen; publishing then describes a route the user never\n // saw, which is the defect this ordering exists to prevent (TIM-1301).\n //\n // A **layout** effect, so the publish lands before the browser paints and,\n // more importantly, before every descendant's passive effect. A destination\n // component that navigates from a mount effect — a redirect guard, a\n // `refresh()` on mount — would otherwise start its navigation while the\n // segment cache, address bar and pathname still described the departing\n // route, and send an X-Timber-State-Tree for a tree that is no longer\n // mounted (codex on #998).\n //\n // Descendant *layout* effects still run first: React runs layout effects\n // child-before-parent, and the only way to precede them would be a fiber\n // rendered as an earlier sibling of the payload. That is not free here —\n // `server/ssr-wrappers.tsx` mirrors this component's fiber shape so `useId`\n // agrees across hydration, and an extra sibling shifts every id in the\n // payload subtree. A layout effect that navigates on mount is the price.\n //\n // Keyed on the tree object rather than on the effect run. A publish moves\n // the address bar, which is not idempotent, so any second invocation for the\n // same tree — an effect re-run React is entitled to perform, StrictMode's\n // double-invoke — must be a no-op rather than a second history entry.\n const publishedRef = useRef<RenderedTree | null>(null);\n useLayoutEffect(() => {\n if (publishedRef.current === rendered) return;\n publishedRef.current = rendered;\n rendered.publish?.();\n }, [rendered]);\n\n // ─── Hard navigation guard ─────────────────────────────────\n // When a hard navigation is in progress (500 error, version skew),\n // suspend forever to prevent React from rendering children during\n // page teardown. This avoids \"Rendered more hooks\" crashes in\n // CHILD components whose hook counts may shift during teardown.\n //\n // CRITICAL: This throw MUST come AFTER all hooks (the useRef and\n // useLayoutEffect above). React requires the same hooks to run on every\n // render. If we threw before hooks, React would see 0 hooks on the\n // re-render vs 2 on the initial render — triggering the exact \"Rendered\n // more hooks\" error we're trying to prevent.\n //\n // By placing it after hooks but before the return, all hooks\n // satisfy React's rules, but the thrown thenable prevents any\n // children from rendering. Same pattern as Next.js app-router.tsx\n // (pushRef.mpaNavigation — also placed after all hooks).\n if (isHardNavigating()) {\n throw unresolvedThenable;\n }\n\n // Inject TopLoader alongside the element tree. It subscribes to the router's\n // pending store itself, so it takes no props from here beyond its config,\n // and only it re-renders when a navigation starts or ends. Rendered only\n // when not explicitly disabled via config.\n //\n // This Fragment is a FORK — two children — so it advances React's tree\n // context and shifts every `useId` below it. `server/ssr-wrappers.tsx`\n // mirrors it for exactly that reason; a single-child wrapper would not need\n // a mirror. See tests/ssr-wrapper-parity.test.ts.\n const showTopLoader = topLoaderConfig?.enabled !== false;\n if (!showTopLoader) return rendered.element;\n return createElement(\n Fragment,\n null,\n createElement(TopLoader, { config: topLoaderConfig }),\n rendered.element\n );\n}\n"],"mappings":";;;;;;AAcA,SAAgB,gBAAgB,QAA8B;CAC5D,iBAAiB,MAAM;AACzB;;;;;AAMA,SAAgB,YAA4B;CAC1C,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,6EAA6E;CAE/F,OAAO;AACT;;;;;;AAOA,SAAgB,kBAAyC;CACvD,OAAO;AACT;;;ACjCA,SAAS,UAAU,eAAuC;CACxD,MAAM,SAAS,gBAAgB;CAC/B,IAAI,CAAC,QAAQ,aAAa,CAAC;CAC3B,OAAO,OAAO,gBAAgB,aAAa;AAC7C;AAEA,SAAS,cAAuB;CAC9B,MAAM,SAAS,gBAAgB;CAC/B,OAAO,SAAS,OAAO,UAAU,IAAI;AACvC;AAEA,IAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;AAuB1B,SAAgB,uBAAgC;CAC9C,OAAO,qBAAqB,WAAW,aAAa,iBAAiB;AACvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AEmEA,IAAM,eAAe,OAAO,IAAI,0BAA0B;AAE1D,SAAS,kBAAsC;CAC7C,MAAM,IAAI;CACV,IAAI,CAAC,EAAE,eACL,EAAE,gBAAgB,EAAE,OAAO,MAAM;CAEnC,OAAO,EAAE;AACX;;;;;;;AAQA,SAAgB,kBAAkB,OAAsB;CACtD,gBAAgB,CAAC,CAAC,QAAQ;AAC5B"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/shared/param-value.ts
|
|
2
|
+
/** The domain, for error messages. Derived, never a second hand-written list. */
|
|
3
|
+
var DOMAIN = `a string, number, boolean, bigint, null, undefined, a plain object, an array, or ${[
|
|
4
|
+
"Date",
|
|
5
|
+
"Map",
|
|
6
|
+
"Set"
|
|
7
|
+
].join("/")}`;
|
|
8
|
+
function reject(path, was, hint) {
|
|
9
|
+
throw new Error(`[timber] Segment param "${path || "(root)"}" was coerced to ${was}, which cannot cross to the client. A param value may be ${DOMAIN}.\n ${hint}\n See design/41-global-params.md §"Transport".`);
|
|
10
|
+
}
|
|
11
|
+
function describe(value) {
|
|
12
|
+
return value.constructor?.name ?? "an object";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Deep-clone a codec's output into the canonical form, or throw.
|
|
16
|
+
*
|
|
17
|
+
* `seen` accumulates every object the walk has entered, and a second encounter
|
|
18
|
+
* is rejected. That is one rule for two things — a shared reference and a cycle
|
|
19
|
+
* are both "this object again" — and it is what keeps the result a tree.
|
|
20
|
+
*/
|
|
21
|
+
function normalizeParamValue(value, path = "") {
|
|
22
|
+
return normalize(value, path, /* @__PURE__ */ new Set());
|
|
23
|
+
}
|
|
24
|
+
function normalize(value, path, seen) {
|
|
25
|
+
if (value === null) return null;
|
|
26
|
+
const kind = typeof value;
|
|
27
|
+
if (kind === "string" || kind === "number" || kind === "boolean" || kind === "bigint") return value;
|
|
28
|
+
if (kind === "undefined") return void 0;
|
|
29
|
+
if (kind === "function") reject(path, "a function", "Return the data it would produce, not the function.");
|
|
30
|
+
if (kind === "symbol") reject(path, "a symbol", "Return a string instead — a symbol has no wire representation.");
|
|
31
|
+
const object = value;
|
|
32
|
+
if (seen.has(object)) throw new Error(`[timber] Segment param "${path || "(root)"}" is a value that already appears elsewhere in the same param — a shared reference or a cycle. A param value is a tree: React Flight carries a repeated \`Date\` by value and a repeated object by reference, so sharing would survive for some types and not others.\n Return separate values, or move the shared part outside the params.\n See design/41-global-params.md §"Transport".`);
|
|
33
|
+
seen.add(object);
|
|
34
|
+
if (Array.isArray(object)) {
|
|
35
|
+
const out = [];
|
|
36
|
+
for (let index = 0; index < object.length; index++) out.push(normalize(object[index], `${path}[${index}]`, seen));
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
if (object instanceof Date) return new Date(object.getTime());
|
|
40
|
+
if (object instanceof Map) {
|
|
41
|
+
const out = /* @__PURE__ */ new Map();
|
|
42
|
+
for (const [key, entry] of object) out.set(normalize(key, `${path}<key>`, seen), normalize(entry, `${path}.get(${keyLabel(key)})`, seen));
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
if (object instanceof Set) {
|
|
46
|
+
const out = /* @__PURE__ */ new Set();
|
|
47
|
+
let index = 0;
|
|
48
|
+
for (const entry of object) out.add(normalize(entry, `${path}[${index++}]`, seen));
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
const prototype = Object.getPrototypeOf(object);
|
|
52
|
+
if (prototype !== null && prototype !== Object.prototype) reject(path, `a ${describe(object)} instance`, "Return a plain object with the fields you need.");
|
|
53
|
+
const out = Object.create(null);
|
|
54
|
+
for (const key of Object.keys(object)) {
|
|
55
|
+
if (key === "__proto__") continue;
|
|
56
|
+
out[key] = normalize(object[key], path ? `${path}.${key}` : key, seen);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function keyLabel(key) {
|
|
61
|
+
return typeof key === "string" ? JSON.stringify(key) : String(key);
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { normalizeParamValue as t };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=param-value-C8TNYchQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"param-value-C8TNYchQ.js","names":[],"sources":["../../src/shared/param-value.ts"],"sourcesContent":["/**\n * The canonical form of a segment param value.\n *\n * `getSegmentParams()` on the server and `useSegmentParams()` on the client\n * must return the same value — same prototype, same own properties. This\n * module is how that is guaranteed, and the mechanism matters:\n *\n * **Both sides are images of one normalizer.** A codec's output is deep-cloned\n * into a closed canonical domain at coercion time, and *that clone* is what the\n * server returns and what goes on the wire. Server and client agree by\n * construction, because neither holds the codec's original.\n *\n * That replaces predicting what React Flight would do to an arbitrary value.\n * Prediction is what the previous design attempted and it cannot be finished:\n * the question \"will Flight's decode output be observably identical to this\n * input?\" ranges over every way a JS object can carry state that is not in its\n * serialization — own keys, enumerability, symbols, holes, accessors,\n * subclassing, exotic objects — and a `Proxy` defeats it outright, since a\n * lying `getPrototypeOf` trap makes any static check unsound. Twelve review\n * findings on PR #992 were each one more case of that set, and the set does\n * not close.\n *\n * Normalizing closes it. The only remaining question is whether Flight\n * round-trips the normalizer's *output range* — a finite domain we defined,\n * covered by `tests/e2e/segment-params.test.ts` against the real serializer.\n *\n * ## The domain\n *\n * - `undefined`, `null`, `string`, `number`, `boolean`, `bigint`\n * - null-prototype objects, own enumerable string keys only\n * - dense arrays\n * - `Date`, `Map`, `Set` — rebuilt, never the codec's instance\n *\n * ...and it is a **tree**: no value appears twice, and nothing is cyclic.\n * That is not a simplification, it is the last prediction being removed.\n * Flight encodes a `Date` by value at each occurrence but tracks plain objects\n * for reference dedup, so preserving aliasing would carry it across for some\n * types and drop it for others — and knowing which is exactly the kind of\n * guess this design exists to stop making (codex, PR #992). A tree has no\n * sharing to preserve or lose, so what Flight does about it is unobservable.\n *\n * Anything else throws, naming the param and what it was. Note what is *not*\n * a rejection: a `Date` subclass normalizes to a `Date`, a decorated array to\n * a plain one, a sparse array to a dense one, a getter to the value it\n * returned. Those used to be twelve separate checks. They are not divergences\n * any more, because the normalization happens once and both sides see its\n * result — so they need no checks at all.\n *\n * Own properties that Flight would drop (non-enumerable, symbol-keyed) are\n * dropped here instead, symmetrically. Prototype pollution is handled by the\n * same pass: `__proto__` is never copied, and every object is\n * `Object.create(null)` (design/13-security.md #36b/#36c, TIM-873).\n *\n * ## The prototype flip\n *\n * Flight refuses to serialize a null-prototype object, so the canonical form\n * cannot go on the wire as-is. `toPlainRecord` and `toNullProtoRecord` flip\n * the prototype on the way out and back. They are exact inverses and both\n * total, because they only ever see canonical values — there is nothing to\n * validate and no shape to special-case.\n *\n * See design/41-global-params.md §\"Transport\".\n */\n\n// ─── Post-coercion param types ──────────────────────────────────────────\n\n/**\n * A single segment param value after codec coercion and normalization.\n *\n * Before coercion, every param is `string | string[]` (the raw URL part).\n * After `app/schema.ts` codecs run, a param can be any value in the\n * `normalizeParamValue` domain below. This type replaces the previous\n * `string | string[]` declaration, which was a lie whenever a codec\n * produced a non-string value (TIM-1347).\n *\n * The typed accessor `getSegmentParams(SEGMENT_PATH)` resolves through\n * the schema and returns the exact type the codec declares. This type\n * covers the untyped/no-argument form and internal plumbing.\n */\nexport type CoercedParamValue =\n | string\n | number\n | boolean\n | bigint\n | null\n | undefined\n | Date\n | Map<CoercedParamValue, CoercedParamValue>\n | Set<CoercedParamValue>\n | CoercedParamValue[]\n | { [key: string]: CoercedParamValue };\n\n/**\n * A record of coerced segment params, keyed by param name.\n *\n * This is the post-coercion type for `segmentParams` throughout the\n * framework. Before coercion (route matcher output, `rawSegmentParams`),\n * the type is `Record<string, string | string[]>`.\n */\nexport type CoercedParams = Record<string, CoercedParamValue>;\n\n/** Types the canonical form rebuilds rather than rejects. */\nconst REBUILT = ['Date', 'Map', 'Set'] as const;\n\n/** The domain, for error messages. Derived, never a second hand-written list. */\nconst DOMAIN = `a string, number, boolean, bigint, null, undefined, a plain object, an array, or ${REBUILT.join('/')}`;\n\nfunction reject(path: string, was: string, hint: string): never {\n throw new Error(\n `[timber] Segment param \"${path || '(root)'}\" was coerced to ${was}, which cannot ` +\n `cross to the client. A param value may be ${DOMAIN}.\\n` +\n ` ${hint}\\n` +\n ` See design/41-global-params.md §\"Transport\".`\n );\n}\n\nfunction describe(value: object): string {\n return (value as { constructor?: { name?: string } }).constructor?.name ?? 'an object';\n}\n\n/**\n * Deep-clone a codec's output into the canonical form, or throw.\n *\n * `seen` accumulates every object the walk has entered, and a second encounter\n * is rejected. That is one rule for two things — a shared reference and a cycle\n * are both \"this object again\" — and it is what keeps the result a tree.\n */\nexport function normalizeParamValue(value: unknown, path = ''): CoercedParamValue {\n return normalize(value, path, new Set());\n}\n\nfunction normalize(value: unknown, path: string, seen: Set<object>): CoercedParamValue {\n if (value === null) return null;\n\n const kind = typeof value;\n if (kind === 'string' || kind === 'number' || kind === 'boolean' || kind === 'bigint') {\n return value as string | number | boolean | bigint;\n }\n if (kind === 'undefined') return undefined;\n if (kind === 'function') {\n reject(path, 'a function', 'Return the data it would produce, not the function.');\n }\n if (kind === 'symbol') {\n reject(path, 'a symbol', 'Return a string instead — a symbol has no wire representation.');\n }\n\n const object = value as object;\n if (seen.has(object)) {\n throw new Error(\n `[timber] Segment param \"${path || '(root)'}\" is a value that already appears ` +\n `elsewhere in the same param — a shared reference or a cycle. A param value is a ` +\n `tree: React Flight carries a repeated \\`Date\\` by value and a repeated object by ` +\n `reference, so sharing would survive for some types and not others.\\n` +\n ` Return separate values, or move the shared part outside the params.\\n` +\n ` See design/41-global-params.md §\"Transport\".`\n );\n }\n seen.add(object);\n\n if (Array.isArray(object)) {\n // Read by index, so holes become `undefined` — on both sides, which is\n // the point. A subclass and any own properties are left behind for the\n // same reason: the clone is a plain, dense array either way.\n const out: CoercedParamValue[] = [];\n for (let index = 0; index < object.length; index++) {\n out.push(normalize((object as unknown[])[index], `${path}[${index}]`, seen));\n }\n return out;\n }\n\n if (object instanceof Date) {\n // A fresh Date, so a subclass or an attached property cannot travel half\n // way and be dropped by the wire.\n return new Date(object.getTime());\n }\n\n if (object instanceof Map) {\n const out = new Map<CoercedParamValue, CoercedParamValue>();\n for (const [key, entry] of object) {\n out.set(\n normalize(key, `${path}<key>`, seen),\n normalize(entry, `${path}.get(${keyLabel(key)})`, seen)\n );\n }\n return out;\n }\n\n if (object instanceof Set) {\n const out = new Set<CoercedParamValue>();\n let index = 0;\n for (const entry of object) out.add(normalize(entry, `${path}[${index++}]`, seen));\n return out;\n }\n\n // Everything else is judged by its prototype. A `Proxy` can lie here, and\n // that is fine: whatever it answers, the clone below reads through it once\n // and both sides see the same snapshot.\n const prototype = Object.getPrototypeOf(object);\n if (prototype !== null && prototype !== Object.prototype) {\n reject(\n path,\n `a ${describe(object)} instance`,\n 'Return a plain object with the fields you need.'\n );\n }\n\n // Own *enumerable string* keys only — the rest is what Flight would drop,\n // so dropping it here keeps the two sides identical. `__proto__` is skipped\n // rather than copied: it has a language-level setter that would change the\n // prototype chain of the copy (TIM-655, TIM-855, TIM-873).\n const out: Record<string, CoercedParamValue> = Object.create(null);\n for (const key of Object.keys(object)) {\n if (key === '__proto__') continue;\n out[key] = normalize(\n (object as Record<string, unknown>)[key],\n path ? `${path}.${key}` : key,\n seen\n );\n }\n return out;\n}\n\nfunction keyLabel(key: unknown): string {\n return typeof key === 'string' ? JSON.stringify(key) : String(key);\n}\n\n// ─── Prototype flip ──────────────────────────────────────────────\n\n/**\n * Canonical form → wire form. React Flight rejects a null prototype\n * (\"Classes or null prototypes are not supported\"), so objects cross as plain\n * ones and are restored on arrival.\n */\nexport function toPlainRecord<T>(value: T): T {\n return reproto(value, {}) as T;\n}\n\n/** Wire form → canonical form. The exact inverse of `toPlainRecord`. */\nexport function toNullProtoRecord<T>(value: T): T {\n return reproto(value, null) as T;\n}\n\n/**\n * Rebuild a canonical value with objects on `proto`.\n *\n * Total by construction: its input is always canonical, so the cases are the\n * domain and nothing else. No validation, no shape it might not have seen, and\n * no cycle to guard — a canonical value is a tree. That is what moving the\n * checking to `normalizeParamValue` bought.\n */\nfunction reproto(value: unknown, proto: object | null): unknown {\n if (value === null || typeof value !== 'object') return value;\n\n const object = value as object;\n\n // A Date carries no nested values, so it crosses as itself.\n if (object instanceof Date) return object;\n\n if (Array.isArray(object)) {\n return (object as unknown[]).map((item) => reproto(item, proto));\n }\n\n if (object instanceof Map) {\n const out = new Map<unknown, unknown>();\n for (const [key, entry] of object) out.set(reproto(key, proto), reproto(entry, proto));\n return out;\n }\n\n if (object instanceof Set) {\n const out = new Set<unknown>();\n for (const entry of object) out.add(reproto(entry, proto));\n return out;\n }\n\n const out: Record<string, unknown> = proto === null ? Object.create(null) : {};\n for (const key of Object.keys(object)) {\n if (key === '__proto__') continue;\n out[key] = reproto((object as Record<string, unknown>)[key], proto);\n }\n return out;\n}\n"],"mappings":";;AAyGA,IAAM,SAAS,oFAAoF;CAHlF;CAAQ;CAAO;AAGmE,CAAA,CAAQ,KAAK,GAAG;AAEnH,SAAS,OAAO,MAAc,KAAa,MAAqB;CAC9D,MAAM,IAAI,MACR,2BAA2B,QAAQ,SAAS,mBAAmB,IAAI,2DACpB,OAAO,OAC/C,KAAK,iDAEd;AACF;AAEA,SAAS,SAAS,OAAuB;CACvC,OAAQ,MAA8C,aAAa,QAAQ;AAC7E;;;;;;;;AASA,SAAgB,oBAAoB,OAAgB,OAAO,IAAuB;CAChF,OAAO,UAAU,OAAO,sBAAM,IAAI,IAAI,CAAC;AACzC;AAEA,SAAS,UAAU,OAAgB,MAAc,MAAsC;CACrF,IAAI,UAAU,MAAM,OAAO;CAE3B,MAAM,OAAO,OAAO;CACpB,IAAI,SAAS,YAAY,SAAS,YAAY,SAAS,aAAa,SAAS,UAC3E,OAAO;CAET,IAAI,SAAS,aAAa,OAAO,KAAA;CACjC,IAAI,SAAS,YACX,OAAO,MAAM,cAAc,qDAAqD;CAElF,IAAI,SAAS,UACX,OAAO,MAAM,YAAY,gEAAgE;CAG3F,MAAM,SAAS;CACf,IAAI,KAAK,IAAI,MAAM,GACjB,MAAM,IAAI,MACR,2BAA2B,QAAQ,SAAS,6XAM9C;CAEF,KAAK,IAAI,MAAM;CAEf,IAAI,MAAM,QAAQ,MAAM,GAAG;EAIzB,MAAM,MAA2B,CAAC;EAClC,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SACzC,IAAI,KAAK,UAAW,OAAqB,QAAQ,GAAG,KAAK,GAAG,MAAM,IAAI,IAAI,CAAC;EAE7E,OAAO;CACT;CAEA,IAAI,kBAAkB,MAGpB,OAAO,IAAI,KAAK,OAAO,QAAQ,CAAC;CAGlC,IAAI,kBAAkB,KAAK;EACzB,MAAM,sBAAM,IAAI,IAA0C;EAC1D,KAAK,MAAM,CAAC,KAAK,UAAU,QACzB,IAAI,IACF,UAAU,KAAK,GAAG,KAAK,QAAQ,IAAI,GACnC,UAAU,OAAO,GAAG,KAAK,OAAO,SAAS,GAAG,EAAE,IAAI,IAAI,CACxD;EAEF,OAAO;CACT;CAEA,IAAI,kBAAkB,KAAK;EACzB,MAAM,sBAAM,IAAI,IAAuB;EACvC,IAAI,QAAQ;EACZ,KAAK,MAAM,SAAS,QAAQ,IAAI,IAAI,UAAU,OAAO,GAAG,KAAK,GAAG,QAAQ,IAAI,IAAI,CAAC;EACjF,OAAO;CACT;CAKA,MAAM,YAAY,OAAO,eAAe,MAAM;CAC9C,IAAI,cAAc,QAAQ,cAAc,OAAO,WAC7C,OACE,MACA,KAAK,SAAS,MAAM,EAAE,YACtB,iDACF;CAOF,MAAM,MAAyC,OAAO,OAAO,IAAI;CACjE,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;EACrC,IAAI,QAAQ,aAAa;EACzB,IAAI,OAAO,UACR,OAAmC,MACpC,OAAO,GAAG,KAAK,GAAG,QAAQ,KAC1B,IACF;CACF;CACA,OAAO;AACT;AAEA,SAAS,SAAS,KAAsB;CACtC,OAAO,OAAO,QAAQ,WAAW,KAAK,UAAU,GAAG,IAAI,OAAO,GAAG;AACnE"}
|