@timber-js/app 0.2.0-alpha.8 → 0.2.0-alpha.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/dist/_chunks/actions-Dg-ANYHb.js +421 -0
- package/dist/_chunks/actions-Dg-ANYHb.js.map +1 -0
- package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
- package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
- package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
- package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
- package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
- package/dist/_chunks/define-C77ScO0m.js +106 -0
- package/dist/_chunks/define-C77ScO0m.js.map +1 -0
- package/dist/_chunks/define-CZqDwhSu.js +199 -0
- package/dist/_chunks/define-CZqDwhSu.js.map +1 -0
- package/dist/_chunks/define-cookie-C2IkoFGN.js +94 -0
- package/dist/_chunks/define-cookie-C2IkoFGN.js.map +1 -0
- package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
- package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
- package/dist/_chunks/format-CYBGxKtc.js +14 -0
- package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
- package/dist/_chunks/{interception-BOoWmLUA.js → interception-Dpn_UfAD.js} +171 -97
- package/dist/_chunks/interception-Dpn_UfAD.js.map +1 -0
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
- package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
- package/dist/_chunks/request-context-qMsWgy9C.js +478 -0
- package/dist/_chunks/request-context-qMsWgy9C.js.map +1 -0
- package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
- package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
- package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
- package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
- package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
- package/dist/_chunks/stale-reload-BX5gL1r-.js +64 -0
- package/dist/_chunks/stale-reload-BX5gL1r-.js.map +1 -0
- package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
- package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
- package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
- package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
- package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-Lo_s_pw2.js} +4 -4
- package/dist/_chunks/use-query-states-Lo_s_pw2.js.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +73 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.js +95 -0
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +148 -12
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +135 -11
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +17 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +56 -13
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/handler-store.d.ts +31 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +23 -7
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +142 -80
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/singleflight.d.ts +18 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts +22 -0
- package/dist/cache/sizeof.d.ts.map +1 -0
- package/dist/cache/timber-cache.d.ts +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +27 -1
- package/dist/client/browser-dev.d.ts.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
- package/dist/client/browser-entry/hmr.d.ts +21 -0
- package/dist/client/browser-entry/hmr.d.ts.map +1 -0
- package/dist/client/browser-entry/hydrate.d.ts +46 -0
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
- package/dist/client/browser-entry/index.d.ts +30 -0
- package/dist/client/browser-entry/index.d.ts.map +1 -0
- package/dist/client/browser-entry/post-hydration.d.ts +26 -0
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
- package/dist/client/browser-entry/router-init.d.ts +23 -0
- package/dist/client/browser-entry/router-init.d.ts.map +1 -0
- package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
- package/dist/client/browser-entry/scroll.d.ts +19 -0
- package/dist/client/browser-entry/scroll.d.ts.map +1 -0
- package/dist/client/error-boundary.d.ts +12 -5
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +10 -4
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/error-reconstituter.d.ts +54 -0
- package/dist/client/error-reconstituter.d.ts.map +1 -0
- package/dist/client/form.d.ts +3 -3
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/history.d.ts +19 -4
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +7 -21
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +210 -1017
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +18 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +890 -0
- package/dist/client/internal.js.map +1 -0
- package/dist/client/link-pending-store.d.ts +63 -0
- package/dist/client/link-pending-store.d.ts.map +1 -0
- package/dist/client/link.d.ts +90 -32
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/nav-link-store.d.ts +36 -0
- package/dist/client/nav-link-store.d.ts.map +1 -0
- package/dist/client/navigation-api-types.d.ts +90 -0
- package/dist/client/navigation-api-types.d.ts.map +1 -0
- package/dist/client/navigation-api.d.ts +115 -0
- package/dist/client/navigation-api.d.ts.map +1 -0
- package/dist/client/navigation-context.d.ts +13 -2
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/nuqs-adapter.d.ts.map +1 -1
- package/dist/client/router-ref.d.ts +1 -1
- package/dist/client/router.d.ts +70 -4
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +38 -3
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +1 -1
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/segment-outlet.d.ts +63 -0
- package/dist/client/segment-outlet.d.ts.map +1 -0
- package/dist/client/ssr-data.d.ts +13 -4
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts +15 -0
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +5 -5
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/use-link-status.d.ts +5 -5
- package/dist/client/use-link-status.d.ts.map +1 -1
- package/dist/client/use-params.d.ts +6 -4
- package/dist/client/use-params.d.ts.map +1 -1
- package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
- package/dist/client/use-pending-navigation.d.ts.map +1 -0
- package/dist/client/use-query-states.d.ts +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts +1 -1
- package/dist/codec.d.ts +33 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +2 -0
- package/dist/config-types.d.ts +227 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts +35 -14
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -83
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/index.d.ts +45 -192
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12357 -11925
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +107 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugins/adapter-build.d.ts +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts +2 -2
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +3 -3
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/client-chunks.d.ts +32 -0
- package/dist/plugins/client-chunks.d.ts.map +1 -0
- package/dist/plugins/content.d.ts +1 -1
- package/dist/plugins/content.d.ts.map +1 -1
- package/dist/plugins/dev-browser-logs.d.ts +84 -0
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
- package/dist/plugins/dev-error-overlay.d.ts +26 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
- package/dist/plugins/dev-logs.d.ts +1 -1
- package/dist/plugins/dev-logs.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +19 -5
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +1 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts +6 -5
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +4 -4
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/index.d.ts +2 -0
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -2
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +46 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/routing/status-file-lint.d.ts +2 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/routing/types.d.ts +16 -4
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +76 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +139 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +32 -441
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/registry.d.ts +2 -2
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/segment-params/define.d.ts +78 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +3 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +2 -0
- package/dist/server/access-gate.d.ts +4 -0
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +25 -6
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/action-encryption.d.ts +76 -0
- package/dist/server/action-encryption.d.ts.map +1 -0
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +3 -6
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +32 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/build-manifest.d.ts +2 -2
- package/dist/server/build-manifest.d.ts.map +1 -1
- package/dist/server/debug.d.ts +1 -1
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-page-resolver.d.ts +52 -0
- package/dist/server/deny-page-resolver.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-holding-server.d.ts +52 -0
- package/dist/server/dev-holding-server.d.ts.map +1 -0
- package/dist/server/dev-warnings.d.ts +1 -21
- package/dist/server/dev-warnings.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -5
- package/dist/server/early-hints.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +4 -3
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/flush.d.ts.map +1 -1
- package/dist/server/form-data.d.ts +29 -0
- package/dist/server/form-data.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +51 -11
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +5 -43
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +37 -2798
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +46 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +2883 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +25 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +19 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +113 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/page-deny-boundary.d.ts +31 -0
- package/dist/server/page-deny-boundary.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +6 -0
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +42 -10
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +69 -18
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/render-timeout.d.ts +51 -0
- package/dist/server/render-timeout.d.ts.map +1 -0
- package/dist/server/request-context.d.ts +112 -43
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts +27 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-handler.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts +9 -2
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +2 -2
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +48 -5
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +8 -3
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +4 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +129 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +22 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +39 -21
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +50 -0
- package/dist/server/ssr-wrappers.d.ts.map +1 -0
- package/dist/server/status-code-resolver.d.ts +1 -1
- package/dist/server/status-code-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +36 -0
- package/dist/server/stream-utils.d.ts.map +1 -0
- package/dist/server/tracing.d.ts +4 -4
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +22 -19
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/shared/merge-search-params.d.ts +22 -0
- package/dist/shared/merge-search-params.d.ts.map +1 -0
- package/dist/shims/font-google.d.ts +1 -1
- package/dist/shims/font-google.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.d.ts +26 -0
- package/dist/shims/font-local.d.ts.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +1 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +3 -2
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/directive-parser.d.ts +5 -2
- package/dist/utils/directive-parser.d.ts.map +1 -1
- package/dist/utils/state-machine.d.ts +80 -0
- package/dist/utils/state-machine.d.ts.map +1 -0
- package/package.json +56 -22
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/adapters/cloudflare.ts +342 -28
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +52 -8
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +38 -0
- package/src/cache/handler-store.ts +68 -0
- package/src/cache/index.ts +81 -18
- package/src/cache/singleflight.ts +62 -4
- package/src/cache/sizeof.ts +31 -0
- package/src/cache/timber-cache.ts +24 -20
- package/src/cli.ts +16 -6
- package/src/client/browser-dev.ts +128 -1
- package/src/client/browser-entry/action-dispatch.ts +116 -0
- package/src/client/browser-entry/hmr.ts +81 -0
- package/src/client/browser-entry/hydrate.ts +145 -0
- package/src/client/browser-entry/index.ts +138 -0
- package/src/client/browser-entry/post-hydration.ts +119 -0
- package/src/client/browser-entry/router-init.ts +193 -0
- package/src/client/browser-entry/rsc-stream.ts +157 -0
- package/src/client/browser-entry/scroll.ts +27 -0
- package/src/client/error-boundary.tsx +48 -16
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +9 -7
- package/src/client/history.ts +26 -4
- package/src/client/index.ts +19 -38
- package/src/client/internal.ts +57 -0
- package/src/client/link-pending-store.ts +111 -0
- package/src/client/link.tsx +329 -97
- package/src/client/nav-link-store.ts +47 -0
- package/src/client/navigation-api-types.ts +112 -0
- package/src/client/navigation-api.ts +332 -0
- package/src/client/navigation-context.ts +31 -6
- package/src/client/navigation-root.tsx +342 -0
- package/src/client/nuqs-adapter.tsx +16 -3
- package/src/client/router-ref.ts +1 -1
- package/src/client/router.ts +299 -72
- package/src/client/rsc-fetch.ts +97 -8
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/stale-reload.ts +72 -3
- package/src/client/top-loader.tsx +16 -8
- package/src/client/use-link-status.ts +7 -7
- package/src/client/use-params.ts +7 -5
- package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
- package/src/client/use-query-states.ts +3 -3
- package/src/client/use-router.ts +1 -1
- package/src/codec.ts +49 -0
- package/src/config-types.ts +225 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +78 -25
- package/src/cookies/index.ts +8 -0
- package/src/fonts/css.ts +2 -1
- package/src/index.ts +295 -354
- package/src/plugin-context.ts +240 -0
- package/src/plugins/adapter-build.ts +9 -3
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +3 -3
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-browser-logs.ts +288 -0
- package/src/plugins/dev-error-overlay.ts +70 -1
- package/src/plugins/dev-logs.ts +1 -1
- package/src/plugins/dev-server.ts +70 -9
- package/src/plugins/entries.ts +71 -10
- package/src/plugins/fonts.ts +168 -61
- package/src/plugins/mdx.ts +1 -1
- package/src/plugins/routing.ts +57 -17
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +32 -1
- package/src/plugins/shims.ts +135 -35
- package/src/plugins/static-build.ts +17 -11
- package/src/routing/codegen.ts +165 -105
- package/src/routing/index.ts +2 -0
- package/src/routing/scanner.ts +93 -23
- package/src/routing/segment-classify.ts +89 -0
- package/src/routing/status-file-lint.ts +3 -2
- package/src/routing/types.ts +17 -4
- package/src/rsc-runtime/rsc.ts +2 -0
- package/src/rsc-runtime/ssr.ts +50 -0
- package/src/rsc-runtime/vendor-types.d.ts +7 -0
- package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
- package/src/search-params/define.ts +482 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +85 -0
- package/src/segment-params/define.ts +279 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +70 -29
- package/src/server/action-client.ts +46 -11
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +21 -4
- package/src/server/actions.ts +10 -9
- package/src/server/als-registry.ts +34 -6
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/debug.ts +1 -1
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-page-resolver.ts +154 -0
- package/src/server/deny-renderer.ts +24 -38
- package/src/server/dev-holding-server.ts +185 -0
- package/src/server/dev-warnings.ts +4 -49
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +74 -22
- package/src/server/fallback-error.ts +31 -15
- package/src/server/flight-injection-state.ts +113 -0
- package/src/server/flight-scripts.ts +62 -0
- package/src/server/flush.ts +2 -1
- package/src/server/form-data.ts +76 -0
- package/src/server/html-injectors.ts +280 -120
- package/src/server/index.ts +25 -177
- package/src/server/internal.ts +169 -0
- package/src/server/logger.ts +44 -36
- package/src/server/middleware-runner.ts +31 -4
- package/src/server/node-stream-transforms.ts +509 -0
- package/src/server/page-deny-boundary.tsx +56 -0
- package/src/server/pipeline-interception.ts +17 -16
- package/src/server/pipeline-metadata.ts +13 -0
- package/src/server/pipeline.ts +227 -62
- package/src/server/primitives.ts +111 -28
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +293 -132
- package/src/server/route-element-builder.ts +283 -191
- package/src/server/route-handler.ts +24 -4
- package/src/server/route-matcher.ts +24 -20
- package/src/server/rsc-entry/api-handler.ts +15 -16
- package/src/server/rsc-entry/error-renderer.ts +300 -89
- package/src/server/rsc-entry/helpers.ts +134 -5
- package/src/server/rsc-entry/index.ts +200 -112
- package/src/server/rsc-entry/rsc-payload.ts +65 -18
- package/src/server/rsc-entry/rsc-stream.ts +65 -13
- package/src/server/rsc-entry/ssr-bridge.ts +14 -5
- package/src/server/rsc-entry/ssr-renderer.ts +168 -38
- package/src/server/safe-load.ts +60 -0
- package/src/server/sitemap-generator.ts +338 -0
- package/src/server/sitemap-handler.ts +126 -0
- package/src/server/slot-resolver.ts +244 -229
- package/src/server/ssr-entry.ts +211 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/status-code-resolver.ts +1 -1
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +20 -9
- package/src/server/tree-builder.ts +92 -58
- package/src/server/types.ts +3 -6
- package/src/server/version-skew.ts +104 -0
- package/src/shared/merge-search-params.ts +55 -0
- package/src/shims/font-google.ts +1 -1
- package/src/shims/font-local.ts +34 -0
- package/src/shims/headers.ts +5 -1
- package/src/shims/navigation-client.ts +1 -1
- package/src/shims/navigation.ts +7 -2
- package/src/utils/directive-parser.ts +5 -2
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
- package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
- package/dist/_chunks/format-DviM89f0.js.map +0 -1
- package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
- package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
- package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
- package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
- package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
- package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
- package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
- package/dist/cache/register-cached-function.d.ts +0 -17
- package/dist/cache/register-cached-function.d.ts.map +0 -1
- package/dist/client/browser-entry.d.ts +0 -21
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/link-status-provider.d.ts +0 -11
- package/dist/client/link-status-provider.d.ts.map +0 -1
- package/dist/client/transition-root.d.ts.map +0 -1
- package/dist/client/use-navigation-pending.d.ts.map +0 -1
- package/dist/cookies/index.js.map +0 -1
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/search-params/analyze.d.ts +0 -54
- package/dist/search-params/analyze.d.ts.map +0 -1
- package/dist/search-params/builtin-codecs.d.ts +0 -105
- package/dist/search-params/builtin-codecs.d.ts.map +0 -1
- package/dist/search-params/codecs.d.ts +0 -53
- package/dist/search-params/codecs.d.ts.map +0 -1
- package/dist/search-params/create.d.ts +0 -106
- package/dist/search-params/create.d.ts.map +0 -1
- package/dist/server/prerender.d.ts +0 -77
- package/dist/server/prerender.d.ts.map +0 -1
- package/dist/server/response-cache.d.ts +0 -54
- package/dist/server/response-cache.d.ts.map +0 -1
- package/src/cache/register-cached-function.ts +0 -103
- package/src/client/browser-entry.ts +0 -678
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/transition-root.tsx +0 -166
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/search-params/analyze.ts +0 -192
- package/src/search-params/builtin-codecs.ts +0 -228
- package/src/search-params/create.ts +0 -321
- package/src/server/prerender.ts +0 -139
- package/src/server/response-cache.ts +0 -410
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Request Context — per-request ALS store for
|
|
2
|
+
* Request Context — per-request ALS store for getHeaders() and getCookies().
|
|
3
3
|
*
|
|
4
4
|
* Follows the same pattern as tracing.ts: a module-level AsyncLocalStorage
|
|
5
5
|
* instance, public accessor functions that throw outside request scope,
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* See design/29-cookies.md for cookie mutation semantics.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
14
|
-
import type { Routes } from '#/index.js';
|
|
15
13
|
import { requestContextAls, type RequestContextStore, type CookieEntry } from './als-registry.js';
|
|
16
14
|
import { isDebug } from './debug.js';
|
|
15
|
+
import { _setGetSearchParamsFn } from '../search-params/define.js';
|
|
16
|
+
import { _setGetSegmentParamsFn } from '../segment-params/define.js';
|
|
17
17
|
|
|
18
18
|
// Re-export the ALS for framework-internal consumers that need direct access.
|
|
19
19
|
export { requestContextAls };
|
|
@@ -22,30 +22,6 @@ export { requestContextAls };
|
|
|
22
22
|
// the ALS context persists for the entire request lifecycle including
|
|
23
23
|
// async stream consumption by React's renderToReadableStream.
|
|
24
24
|
|
|
25
|
-
// ─── Cookie Signing Secrets ──────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Module-level cookie signing secrets. Index 0 is the newest (used for signing).
|
|
29
|
-
* All entries are tried for verification (key rotation support).
|
|
30
|
-
*
|
|
31
|
-
* Set by the framework at startup via `setCookieSecrets()`.
|
|
32
|
-
* See design/29-cookies.md §"Signed Cookies"
|
|
33
|
-
*/
|
|
34
|
-
let _cookieSecrets: string[] = [];
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Configure the cookie signing secrets.
|
|
38
|
-
*
|
|
39
|
-
* Called by the framework during server initialization with values from
|
|
40
|
-
* `cookies.secret` or `cookies.secrets` in timber.config.ts.
|
|
41
|
-
*
|
|
42
|
-
* The first secret (index 0) is used for signing new cookies.
|
|
43
|
-
* All secrets are tried for verification (supports key rotation).
|
|
44
|
-
*/
|
|
45
|
-
export function setCookieSecrets(secrets: string[]): void {
|
|
46
|
-
_cookieSecrets = secrets.filter(Boolean);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
25
|
// ─── Public API ───────────────────────────────────────────────────────────
|
|
50
26
|
|
|
51
27
|
/**
|
|
@@ -54,15 +30,34 @@ export function setCookieSecrets(secrets: string[]): void {
|
|
|
54
30
|
* Available in middleware, access checks, server components, and server actions.
|
|
55
31
|
* Throws if called outside a request context (security principle #2: no global fallback).
|
|
56
32
|
*/
|
|
57
|
-
export function
|
|
33
|
+
export function getHeaders(): Promise<ReadonlyHeaders> {
|
|
58
34
|
const store = requestContextAls.getStore();
|
|
59
35
|
if (!store) {
|
|
60
36
|
throw new Error(
|
|
61
|
-
'[timber]
|
|
37
|
+
'[timber] getHeaders() called outside of a request context. ' +
|
|
62
38
|
'It can only be used in middleware, access checks, server components, and server actions.'
|
|
63
39
|
);
|
|
64
40
|
}
|
|
65
|
-
return store.headers;
|
|
41
|
+
return Promise.resolve(store.headers);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns the value of a single request header, or undefined if absent.
|
|
46
|
+
*
|
|
47
|
+
* Thin wrapper over `(await getHeaders()).get(name)` for the common
|
|
48
|
+
* case where you need exactly one header.
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { getHeader } from '@timber-js/app/server'
|
|
52
|
+
*
|
|
53
|
+
* export default async function Page() {
|
|
54
|
+
* const auth = await getHeader('authorization');
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export async function getHeader(name: string): Promise<string | undefined> {
|
|
59
|
+
const headers = await getHeaders();
|
|
60
|
+
return headers.get(name) ?? undefined;
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
/**
|
|
@@ -80,11 +75,11 @@ export function headers(): ReadonlyHeaders {
|
|
|
80
75
|
*
|
|
81
76
|
* See design/29-cookies.md
|
|
82
77
|
*/
|
|
83
|
-
export function
|
|
78
|
+
export function getCookies(): Promise<RequestCookies> {
|
|
84
79
|
const store = requestContextAls.getStore();
|
|
85
80
|
if (!store) {
|
|
86
81
|
throw new Error(
|
|
87
|
-
'[timber]
|
|
82
|
+
'[timber] getCookies() called outside of a request context. ' +
|
|
88
83
|
'It can only be used in middleware, access checks, server components, and server actions.'
|
|
89
84
|
);
|
|
90
85
|
}
|
|
@@ -95,7 +90,7 @@ export function cookies(): RequestCookies {
|
|
|
95
90
|
}
|
|
96
91
|
|
|
97
92
|
const map = store.parsedCookies;
|
|
98
|
-
return {
|
|
93
|
+
return Promise.resolve({
|
|
99
94
|
get(name: string): string | undefined {
|
|
100
95
|
return map.get(name);
|
|
101
96
|
},
|
|
@@ -109,39 +104,45 @@ export function cookies(): RequestCookies {
|
|
|
109
104
|
return map.size;
|
|
110
105
|
},
|
|
111
106
|
|
|
112
|
-
getSigned(name: string): string | undefined {
|
|
113
|
-
const raw = map.get(name);
|
|
114
|
-
if (!raw || _cookieSecrets.length === 0) return undefined;
|
|
115
|
-
return verifySignedCookie(raw, _cookieSecrets);
|
|
116
|
-
},
|
|
117
|
-
|
|
118
107
|
set(name: string, value: string, options?: CookieOptions): void {
|
|
119
108
|
assertMutable(store, 'set');
|
|
120
109
|
if (store.flushed) {
|
|
121
110
|
if (isDebug()) {
|
|
122
111
|
console.warn(
|
|
123
|
-
`[timber] warn:
|
|
112
|
+
`[timber] warn: getCookies().set('${name}') called after response headers were committed.\n` +
|
|
124
113
|
` The cookie will NOT be sent. Move cookie mutations to middleware.ts, a server action,\n` +
|
|
125
114
|
` or a route.ts handler.`
|
|
126
115
|
);
|
|
127
116
|
}
|
|
128
117
|
return;
|
|
129
118
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
119
|
+
const opts = { ...DEFAULT_COOKIE_OPTIONS, ...options };
|
|
120
|
+
store.cookieJar.set(name, { name, value, options: opts });
|
|
121
|
+
// Read-your-own-writes: update the parsed cookies map
|
|
122
|
+
map.set(name, value);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
setFromHeaders(headers: Headers): void {
|
|
126
|
+
assertMutable(store, 'setFromHeaders');
|
|
127
|
+
if (store.flushed) {
|
|
128
|
+
console.warn(
|
|
129
|
+
`[timber] warn: getCookies().setFromHeaders() called after response headers were committed.\n` +
|
|
130
|
+
` The cookies will NOT be sent. Move cookie mutations to middleware.ts, a server action,\n` +
|
|
131
|
+
` or a route.ts handler.`
|
|
132
|
+
);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Headers.getSetCookie() returns individual Set-Cookie strings,
|
|
136
|
+
// avoiding the fragile comma-splitting that raw .get() requires.
|
|
137
|
+
for (const raw of headers.getSetCookie()) {
|
|
138
|
+
const parsed = parseSetCookie(raw);
|
|
139
|
+
if (parsed) {
|
|
140
|
+
// Use setRaw to preserve the original header's attributes without
|
|
141
|
+
// merging DEFAULT_COOKIE_OPTIONS (parseSetCookie intentionally
|
|
142
|
+
// does not apply defaults — see its doc comment).
|
|
143
|
+
setRaw(store, map, parsed.name, parsed.value, parsed.options);
|
|
137
144
|
}
|
|
138
|
-
storedValue = signCookieValue(value, _cookieSecrets[0]);
|
|
139
145
|
}
|
|
140
|
-
const opts = { ...DEFAULT_COOKIE_OPTIONS, ...options };
|
|
141
|
-
store.cookieJar.set(name, { name, value: storedValue, options: opts });
|
|
142
|
-
// Read-your-own-writes: update the parsed cookies map with the signed value
|
|
143
|
-
// so getSigned() can verify it in the same request
|
|
144
|
-
map.set(name, storedValue);
|
|
145
146
|
},
|
|
146
147
|
|
|
147
148
|
delete(name: string, options?: Pick<CookieOptions, 'path' | 'domain'>): void {
|
|
@@ -149,7 +150,7 @@ export function cookies(): RequestCookies {
|
|
|
149
150
|
if (store.flushed) {
|
|
150
151
|
if (isDebug()) {
|
|
151
152
|
console.warn(
|
|
152
|
-
`[timber] warn:
|
|
153
|
+
`[timber] warn: getCookies().delete('${name}') called after response headers were committed.\n` +
|
|
153
154
|
` The cookie will NOT be deleted. Move cookie mutations to middleware.ts, a server action,\n` +
|
|
154
155
|
` or a route.ts handler.`
|
|
155
156
|
);
|
|
@@ -186,45 +187,135 @@ export function cookies(): RequestCookies {
|
|
|
186
187
|
.map(([name, value]) => `${name}=${value}`)
|
|
187
188
|
.join('; ');
|
|
188
189
|
},
|
|
189
|
-
};
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Returns the value of a single cookie, or undefined if absent.
|
|
195
|
+
*
|
|
196
|
+
* Thin wrapper over `(await getCookies()).get(name)` for the common
|
|
197
|
+
* case where you need exactly one cookie.
|
|
198
|
+
*
|
|
199
|
+
* ```ts
|
|
200
|
+
* import { getCookie } from '@timber-js/app/server'
|
|
201
|
+
*
|
|
202
|
+
* export default async function Page() {
|
|
203
|
+
* const session = await getCookie('session_id');
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
export async function getCookie(name: string): Promise<string | undefined> {
|
|
208
|
+
const cookies = await getCookies();
|
|
209
|
+
return cookies.get(name);
|
|
190
210
|
}
|
|
191
211
|
|
|
192
212
|
/**
|
|
193
|
-
* Returns a Promise resolving to the current request's
|
|
213
|
+
* Returns a Promise resolving to the current request's raw URLSearchParams.
|
|
194
214
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* object. In all other server component contexts it resolves to raw
|
|
198
|
-
* `URLSearchParams`.
|
|
215
|
+
* For typed, parsed search params, import the definition from params.ts
|
|
216
|
+
* and call `.load()` or `.parse()`:
|
|
199
217
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
218
|
+
* ```ts
|
|
219
|
+
* import { searchParams } from './params'
|
|
220
|
+
* const parsed = await searchParams.get()
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* Or explicitly:
|
|
224
|
+
*
|
|
225
|
+
* ```ts
|
|
226
|
+
* import { getSearchParams } from '@timber-js/app/server'
|
|
227
|
+
* import { searchParams } from './params'
|
|
228
|
+
* const parsed = searchParams.parse(await getSearchParams())
|
|
229
|
+
* ```
|
|
202
230
|
*
|
|
203
231
|
* Throws if called outside a request context.
|
|
204
232
|
*/
|
|
205
|
-
export function
|
|
206
|
-
export function searchParams(): Promise<URLSearchParams | Record<string, unknown>>;
|
|
207
|
-
export function searchParams(): Promise<URLSearchParams | Record<string, unknown>> {
|
|
233
|
+
export function getSearchParams(): Promise<URLSearchParams> {
|
|
208
234
|
const store = requestContextAls.getStore();
|
|
209
235
|
if (!store) {
|
|
210
236
|
throw new Error(
|
|
211
|
-
'[timber]
|
|
237
|
+
'[timber] getSearchParams() called outside of a request context. ' +
|
|
212
238
|
'It can only be used in middleware, access checks, server components, and server actions.'
|
|
213
239
|
);
|
|
214
240
|
}
|
|
215
241
|
return store.searchParamsPromise;
|
|
216
242
|
}
|
|
217
243
|
|
|
244
|
+
// Eagerly register getSearchParams with the search-params module so
|
|
245
|
+
// searchParams.get() can call it synchronously without a dynamic import.
|
|
246
|
+
// Dynamic imports lose ALS context in React's RSC Flight renderer,
|
|
247
|
+
// breaking getSearchParams() in parallel slot pages. See TIM-523.
|
|
248
|
+
_setGetSearchParamsFn(getSearchParams);
|
|
249
|
+
|
|
250
|
+
// Eagerly register getSegmentParams with the segment-params module so
|
|
251
|
+
// segmentParams.get() can call it synchronously without a dynamic import.
|
|
252
|
+
// Same pattern as search params — dynamic imports lose ALS context. See TIM-523.
|
|
253
|
+
_setGetSegmentParamsFn(getSegmentParams);
|
|
254
|
+
|
|
218
255
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
256
|
+
* Returns a Promise resolving to the current request's coerced segment params.
|
|
257
|
+
*
|
|
258
|
+
* Segment params are set by the pipeline after route matching and param
|
|
259
|
+
* coercion (via params.ts codecs). When no params.ts exists, values are
|
|
260
|
+
* raw strings. When codecs are defined, values are already coerced
|
|
261
|
+
* (e.g., `id` is a `number` if `defineSegmentParams({ id: z.coerce.number() })`).
|
|
262
|
+
*
|
|
263
|
+
* This is the primary way page and layout components access route params:
|
|
264
|
+
*
|
|
265
|
+
* ```ts
|
|
266
|
+
* import { getSegmentParams } from '@timber-js/app/server'
|
|
267
|
+
*
|
|
268
|
+
* export default async function Page() {
|
|
269
|
+
* const { slug } = await getSegmentParams()
|
|
270
|
+
* // ...
|
|
271
|
+
* }
|
|
272
|
+
* ```
|
|
273
|
+
*
|
|
274
|
+
* Throws if called outside a request context.
|
|
222
275
|
*/
|
|
223
|
-
export function
|
|
276
|
+
export function getSegmentParams(): Promise<Record<string, string | string[]>> {
|
|
224
277
|
const store = requestContextAls.getStore();
|
|
225
|
-
if (store) {
|
|
226
|
-
|
|
278
|
+
if (!store) {
|
|
279
|
+
throw new Error(
|
|
280
|
+
'[timber] getSegmentParams() called outside of a request context. ' +
|
|
281
|
+
'It can only be used in middleware, access checks, server components, and server actions.'
|
|
282
|
+
);
|
|
227
283
|
}
|
|
284
|
+
if (!store.segmentParamsPromise) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
'[timber] getSegmentParams() called before route matching completed. ' +
|
|
287
|
+
'Segment params are not available until after the route is matched.'
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return store.segmentParamsPromise;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Set the segment params promise on the current request context.
|
|
295
|
+
* Called by the pipeline after route matching and param coercion.
|
|
296
|
+
*
|
|
297
|
+
* @internal — framework use only
|
|
298
|
+
*/
|
|
299
|
+
export function setSegmentParams(params: Record<string, string | string[]>): void {
|
|
300
|
+
const store = requestContextAls.getStore();
|
|
301
|
+
if (!store) {
|
|
302
|
+
throw new Error('[timber] setSegmentParams() called outside of a request context.');
|
|
303
|
+
}
|
|
304
|
+
store.segmentParamsPromise = Promise.resolve(params);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Returns the raw search string from the current request URL (e.g. "?foo=bar").
|
|
309
|
+
* Synchronous — safe for use in `redirect()` which throws synchronously.
|
|
310
|
+
*
|
|
311
|
+
* Returns empty string if called outside a request context (non-throwing for
|
|
312
|
+
* use in redirect's optional preserveSearchParams path).
|
|
313
|
+
*
|
|
314
|
+
* @internal — used by redirect() for preserveSearchParams support.
|
|
315
|
+
*/
|
|
316
|
+
export function getRequestSearchString(): string {
|
|
317
|
+
const store = requestContextAls.getStore();
|
|
318
|
+
return store?.searchString ?? '';
|
|
228
319
|
}
|
|
229
320
|
|
|
230
321
|
// ─── Types ────────────────────────────────────────────────────────────────
|
|
@@ -257,12 +348,6 @@ export interface CookieOptions {
|
|
|
257
348
|
sameSite?: 'strict' | 'lax' | 'none';
|
|
258
349
|
/** Partitioned (CHIPS) — isolate cookie per top-level site. Default: false. */
|
|
259
350
|
partitioned?: boolean;
|
|
260
|
-
/**
|
|
261
|
-
* Sign the cookie value with HMAC-SHA256 for integrity verification.
|
|
262
|
-
* Requires `cookies.secret` or `cookies.secrets` in timber.config.ts.
|
|
263
|
-
* See design/29-cookies.md §"Signed Cookies".
|
|
264
|
-
*/
|
|
265
|
-
signed?: boolean;
|
|
266
351
|
}
|
|
267
352
|
|
|
268
353
|
const DEFAULT_COOKIE_OPTIONS: CookieOptions = {
|
|
@@ -273,7 +358,89 @@ const DEFAULT_COOKIE_OPTIONS: CookieOptions = {
|
|
|
273
358
|
};
|
|
274
359
|
|
|
275
360
|
/**
|
|
276
|
-
*
|
|
361
|
+
* Write a cookie to the jar WITHOUT merging DEFAULT_COOKIE_OPTIONS.
|
|
362
|
+
* Used by setFromHeaders to preserve the original header's attributes exactly.
|
|
363
|
+
*
|
|
364
|
+
* For deletion cookies (maxAge=0), the jar entry is still created so the
|
|
365
|
+
* Set-Cookie header is emitted, but the cookie is NOT added to the read map
|
|
366
|
+
* (it would be misleading — the cookie is being deleted).
|
|
367
|
+
*/
|
|
368
|
+
function setRaw(
|
|
369
|
+
store: RequestContextStore,
|
|
370
|
+
readMap: Map<string, string>,
|
|
371
|
+
name: string,
|
|
372
|
+
value: string,
|
|
373
|
+
options: CookieOptions
|
|
374
|
+
): void {
|
|
375
|
+
store.cookieJar.set(name, { name, value, options });
|
|
376
|
+
// Deletion cookies (Max-Age=0) should not appear in the read map
|
|
377
|
+
if (options.maxAge === 0) {
|
|
378
|
+
readMap.delete(name);
|
|
379
|
+
} else {
|
|
380
|
+
readMap.set(name, value);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Parse a raw `Set-Cookie` header string into name, value, and options.
|
|
386
|
+
* Handles all standard attributes: Path, Domain, Max-Age, Expires,
|
|
387
|
+
* SameSite, Secure, HttpOnly, Partitioned.
|
|
388
|
+
*
|
|
389
|
+
* Does NOT apply DEFAULT_COOKIE_OPTIONS — the caller decides whether
|
|
390
|
+
* to merge defaults (e.g. `set()` does, but `setRaw()` should preserve
|
|
391
|
+
* the original header's intent).
|
|
392
|
+
*/
|
|
393
|
+
function parseSetCookie(
|
|
394
|
+
header: string
|
|
395
|
+
): { name: string; value: string; options: CookieOptions } | null {
|
|
396
|
+
const segments = header.split(';');
|
|
397
|
+
const nameValue = segments[0];
|
|
398
|
+
const eqIdx = nameValue.indexOf('=');
|
|
399
|
+
if (eqIdx <= 0) return null;
|
|
400
|
+
|
|
401
|
+
const name = nameValue.slice(0, eqIdx).trim();
|
|
402
|
+
const value = nameValue.slice(eqIdx + 1).trim();
|
|
403
|
+
const options: CookieOptions = {};
|
|
404
|
+
|
|
405
|
+
for (let i = 1; i < segments.length; i++) {
|
|
406
|
+
const seg = segments[i].trim();
|
|
407
|
+
if (!seg) continue;
|
|
408
|
+
const [attrName, ...rest] = seg.split('=');
|
|
409
|
+
const key = attrName.trim().toLowerCase();
|
|
410
|
+
const val = rest.join('=').trim();
|
|
411
|
+
switch (key) {
|
|
412
|
+
case 'path':
|
|
413
|
+
options.path = val || '/';
|
|
414
|
+
break;
|
|
415
|
+
case 'domain':
|
|
416
|
+
options.domain = val;
|
|
417
|
+
break;
|
|
418
|
+
case 'max-age':
|
|
419
|
+
options.maxAge = Number(val);
|
|
420
|
+
break;
|
|
421
|
+
case 'expires':
|
|
422
|
+
options.expires = new Date(val);
|
|
423
|
+
break;
|
|
424
|
+
case 'samesite':
|
|
425
|
+
options.sameSite = val.toLowerCase() as 'strict' | 'lax' | 'none';
|
|
426
|
+
break;
|
|
427
|
+
case 'secure':
|
|
428
|
+
options.secure = true;
|
|
429
|
+
break;
|
|
430
|
+
case 'httponly':
|
|
431
|
+
options.httpOnly = true;
|
|
432
|
+
break;
|
|
433
|
+
case 'partitioned':
|
|
434
|
+
options.partitioned = true;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return { name, value, options };
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Cookie accessor returned by `getCookies()`.
|
|
277
444
|
*
|
|
278
445
|
* Read methods are always available. Mutation methods throw in read-only
|
|
279
446
|
* contexts (access.ts, server components).
|
|
@@ -287,16 +454,20 @@ export interface RequestCookies {
|
|
|
287
454
|
getAll(): Array<{ name: string; value: string }>;
|
|
288
455
|
/** Number of cookies. */
|
|
289
456
|
readonly size: number;
|
|
457
|
+
/** Set a cookie. Only available in mutable contexts (middleware, actions, route handlers). */
|
|
458
|
+
set(name: string, value: string, options?: CookieOptions): void;
|
|
290
459
|
/**
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
460
|
+
* Copy all `Set-Cookie` headers from a `Headers` object.
|
|
461
|
+
* Parses each header and forwards name, value, and all attributes
|
|
462
|
+
* (path, domain, max-age, expires, sameSite, secure, httpOnly, partitioned).
|
|
294
463
|
*
|
|
295
|
-
*
|
|
464
|
+
* Useful when forwarding cookies from an internal `fetch()` or auth handler:
|
|
465
|
+
* ```ts
|
|
466
|
+
* const response = await auth.handler(req);
|
|
467
|
+
* getCookies().then(c => c.setFromHeaders(response.headers));
|
|
468
|
+
* ```
|
|
296
469
|
*/
|
|
297
|
-
|
|
298
|
-
/** Set a cookie. Only available in mutable contexts (middleware, actions, route handlers). */
|
|
299
|
-
set(name: string, value: string, options?: CookieOptions): void;
|
|
470
|
+
setFromHeaders(headers: Headers): void;
|
|
300
471
|
/** Delete a cookie. Only available in mutable contexts. */
|
|
301
472
|
delete(name: string, options?: Pick<CookieOptions, 'path' | 'domain'>): void;
|
|
302
473
|
/** Delete all cookies. Only available in mutable contexts. */
|
|
@@ -309,18 +480,20 @@ export interface RequestCookies {
|
|
|
309
480
|
|
|
310
481
|
/**
|
|
311
482
|
* Run a callback within a request context. Used by the pipeline to establish
|
|
312
|
-
* per-request ALS scope so that `
|
|
483
|
+
* per-request ALS scope so that `getHeaders()` and `getCookies()` work.
|
|
313
484
|
*
|
|
314
485
|
* @param req - The incoming Request object.
|
|
315
486
|
* @param fn - The function to run within the request context.
|
|
316
487
|
*/
|
|
317
488
|
export function runWithRequestContext<T>(req: Request, fn: () => T): T {
|
|
318
489
|
const originalCopy = new Headers(req.headers);
|
|
490
|
+
const parsedUrl = new URL(req.url);
|
|
319
491
|
const store: RequestContextStore = {
|
|
320
492
|
headers: freezeHeaders(req.headers),
|
|
321
493
|
originalHeaders: originalCopy,
|
|
322
494
|
cookieHeader: req.headers.get('cookie') ?? '',
|
|
323
|
-
searchParamsPromise: Promise.resolve(
|
|
495
|
+
searchParamsPromise: Promise.resolve(parsedUrl.searchParams),
|
|
496
|
+
searchString: parsedUrl.search,
|
|
324
497
|
cookieJar: new Map(),
|
|
325
498
|
flushed: false,
|
|
326
499
|
mutableContext: false,
|
|
@@ -354,6 +527,35 @@ export function markResponseFlushed(): void {
|
|
|
354
527
|
}
|
|
355
528
|
}
|
|
356
529
|
|
|
530
|
+
/**
|
|
531
|
+
* Build a Map of cookie name → value reflecting the current request's
|
|
532
|
+
* read-your-own-writes state. Includes incoming cookies plus any
|
|
533
|
+
* mutations from getCookies().set() / getCookies().delete() in the same request.
|
|
534
|
+
*
|
|
535
|
+
* Used by SSR renderers to populate NavContext.cookies so that
|
|
536
|
+
* useCookie()'s server snapshot matches the actual response state.
|
|
537
|
+
*
|
|
538
|
+
* See design/29-cookies.md §"Read-Your-Own-Writes"
|
|
539
|
+
* See design/triage/TIM-441-cookie-api-triage.md §4
|
|
540
|
+
*/
|
|
541
|
+
export function getCookiesForSsr(): Map<string, string> {
|
|
542
|
+
const store = requestContextAls.getStore();
|
|
543
|
+
if (!store) {
|
|
544
|
+
throw new Error('[timber] getCookiesForSsr() called outside of a request context.');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Trigger lazy parsing if not yet done
|
|
548
|
+
if (!store.parsedCookies) {
|
|
549
|
+
store.parsedCookies = parseCookieHeader(store.cookieHeader);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// The parsedCookies map already reflects read-your-own-writes:
|
|
553
|
+
// - getCookies().set() updates the map via map.set(name, value)
|
|
554
|
+
// - getCookies().delete() removes from the map via map.delete(name)
|
|
555
|
+
// Return a copy so callers can't mutate the internal map.
|
|
556
|
+
return new Map(store.parsedCookies);
|
|
557
|
+
}
|
|
558
|
+
|
|
357
559
|
/**
|
|
358
560
|
* Collect all Set-Cookie headers from the cookie jar.
|
|
359
561
|
* Called by the framework at flush time to apply cookies to the response.
|
|
@@ -371,7 +573,7 @@ export function getSetCookieHeaders(): string[] {
|
|
|
371
573
|
*
|
|
372
574
|
* Called by the pipeline after middleware.ts runs. Merges overlay headers
|
|
373
575
|
* on top of the original request headers so downstream code (access.ts,
|
|
374
|
-
* server components, server actions) sees them via `
|
|
576
|
+
* server components, server actions) sees them via `getHeaders()`.
|
|
375
577
|
*
|
|
376
578
|
* The original request headers are never mutated — a new frozen Headers
|
|
377
579
|
* object is created with the overlay applied on top.
|
|
@@ -418,7 +620,7 @@ function freezeHeaders(source: Headers): Headers {
|
|
|
418
620
|
if (typeof prop === 'string' && MUTATING_METHODS.has(prop)) {
|
|
419
621
|
return () => {
|
|
420
622
|
throw new Error(
|
|
421
|
-
`[timber]
|
|
623
|
+
`[timber] getHeaders() returns a read-only Headers object. ` +
|
|
422
624
|
`Calling .${prop}() is not allowed. ` +
|
|
423
625
|
`Use ctx.requestHeaders in middleware to inject headers for downstream components.`
|
|
424
626
|
);
|
|
@@ -440,7 +642,7 @@ function freezeHeaders(source: Headers): Headers {
|
|
|
440
642
|
function assertMutable(store: RequestContextStore, method: string): void {
|
|
441
643
|
if (!store.mutableContext) {
|
|
442
644
|
throw new Error(
|
|
443
|
-
`
|
|
645
|
+
`(timber] getCookies().${method}() cannot be called in this context.\n` +
|
|
444
646
|
` Set cookies in middleware.ts, server actions, or route.ts handlers.`
|
|
445
647
|
);
|
|
446
648
|
}
|
|
@@ -467,47 +669,6 @@ function parseCookieHeader(header: string): Map<string, string> {
|
|
|
467
669
|
return map;
|
|
468
670
|
}
|
|
469
671
|
|
|
470
|
-
// ─── Cookie Signing ──────────────────────────────────────────────────────
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Sign a cookie value with HMAC-SHA256.
|
|
474
|
-
* Returns `value.hex_signature`.
|
|
475
|
-
*/
|
|
476
|
-
function signCookieValue(value: string, secret: string): string {
|
|
477
|
-
const signature = createHmac('sha256', secret).update(value).digest('hex');
|
|
478
|
-
return `${value}.${signature}`;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Verify a signed cookie value against an array of secrets.
|
|
483
|
-
* Returns the original value if any secret produces a matching signature,
|
|
484
|
-
* or undefined if none match. Uses timing-safe comparison.
|
|
485
|
-
*
|
|
486
|
-
* The signed format is `value.hex_signature` — split at the last `.`.
|
|
487
|
-
*/
|
|
488
|
-
function verifySignedCookie(raw: string, secrets: string[]): string | undefined {
|
|
489
|
-
const lastDot = raw.lastIndexOf('.');
|
|
490
|
-
if (lastDot <= 0 || lastDot === raw.length - 1) return undefined;
|
|
491
|
-
|
|
492
|
-
const value = raw.slice(0, lastDot);
|
|
493
|
-
const signature = raw.slice(lastDot + 1);
|
|
494
|
-
|
|
495
|
-
// Hex-encoded SHA-256 is always 64 chars
|
|
496
|
-
if (signature.length !== 64) return undefined;
|
|
497
|
-
|
|
498
|
-
const signatureBuffer = Buffer.from(signature, 'hex');
|
|
499
|
-
// If the hex decode produced fewer bytes, the signature was not valid hex
|
|
500
|
-
if (signatureBuffer.length !== 32) return undefined;
|
|
501
|
-
|
|
502
|
-
for (const secret of secrets) {
|
|
503
|
-
const expected = createHmac('sha256', secret).update(value).digest();
|
|
504
|
-
if (timingSafeEqual(expected, signatureBuffer)) {
|
|
505
|
-
return value;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return undefined;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
672
|
/** Serialize a CookieEntry into a Set-Cookie header value. */
|
|
512
673
|
function serializeCookieEntry(entry: CookieEntry): string {
|
|
513
674
|
const parts = [`${entry.name}=${entry.value}`];
|