@timber-js/app 0.2.0-alpha.1 → 0.2.0-alpha.100
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-CQ8Z8VGL.js +1061 -0
- package/dist/_chunks/actions-CQ8Z8VGL.js.map +1 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js +61 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js.map +1 -0
- package/dist/_chunks/chunk-BYIpzuS7.js +39 -0
- package/dist/_chunks/define-B-Q_UMOD.js +195 -0
- package/dist/_chunks/define-B-Q_UMOD.js.map +1 -0
- package/dist/_chunks/define-CfBPoJb0.js +123 -0
- package/dist/_chunks/define-CfBPoJb0.js.map +1 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js +194 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js.map +1 -0
- package/dist/_chunks/format-Bcn-Iv1x.js +14 -0
- package/dist/_chunks/format-Bcn-Iv1x.js.map +1 -0
- package/dist/_chunks/handler-store-B-lqaGyh.js +54 -0
- package/dist/_chunks/handler-store-B-lqaGyh.js.map +1 -0
- package/dist/_chunks/logger-0m8MsKdc.js +291 -0
- package/dist/_chunks/logger-0m8MsKdc.js.map +1 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js +122 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js.map +1 -0
- package/dist/_chunks/{metadata-routes-CQCnF4VK.js → metadata-routes-BU684ls2.js} +1 -1
- package/dist/_chunks/{metadata-routes-CQCnF4VK.js.map → metadata-routes-BU684ls2.js.map} +1 -1
- package/dist/_chunks/navigation-root-BCYczjml.js +96 -0
- package/dist/_chunks/navigation-root-BCYczjml.js.map +1 -0
- package/dist/_chunks/registry-I2ss-lvy.js +20 -0
- package/dist/_chunks/registry-I2ss-lvy.js.map +1 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js +28 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js.map +1 -0
- package/dist/_chunks/schema-bridge-Cxu4l-7p.js +86 -0
- package/dist/_chunks/schema-bridge-Cxu4l-7p.js.map +1 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js +137 -0
- package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -0
- package/dist/_chunks/segment-context-Dx_OizxD.js +34 -0
- package/dist/_chunks/segment-context-Dx_OizxD.js.map +1 -0
- package/dist/_chunks/{ssr-data-DLnbYpj1.js → ssr-data-B4CdH7rE.js} +1 -1
- package/dist/_chunks/ssr-data-B4CdH7rE.js.map +1 -0
- package/dist/_chunks/stale-reload-Bab885FO.js +64 -0
- package/dist/_chunks/stale-reload-Bab885FO.js.map +1 -0
- package/dist/_chunks/tracing-C8V-YGsP.js +329 -0
- package/dist/_chunks/tracing-C8V-YGsP.js.map +1 -0
- package/dist/_chunks/{use-query-states-DAhgj8Gx.js → use-query-states-B2XTqxDR.js} +7 -20
- package/dist/_chunks/use-query-states-B2XTqxDR.js.map +1 -0
- package/dist/_chunks/use-segment-params-BkpKAQ7D.js +185 -0
- package/dist/_chunks/use-segment-params-BkpKAQ7D.js.map +1 -0
- package/dist/_chunks/walkers-Tg0Alwcg.js +850 -0
- package/dist/_chunks/walkers-Tg0Alwcg.js.map +1 -0
- package/dist/_chunks/{format-DNt20Kt8.js → warnings-Cg47l5sk.js} +7 -45
- package/dist/_chunks/warnings-Cg47l5sk.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +28 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.d.ts +109 -0
- package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +73 -0
- package/dist/adapters/cloudflare-dev.js.map +1 -0
- package/dist/adapters/cloudflare-kv-cache.d.ts +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 +142 -38
- 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 +143 -45
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +16 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/fast-hash.d.ts +22 -0
- package/dist/cache/fast-hash.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 +195 -84
- 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 +34 -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 +26 -5
- 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 +16 -27
- 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 +9 -24
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +312 -1109
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +19 -0
- package/dist/client/internal.d.ts.map +1 -0
- package/dist/client/internal.js +964 -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 +73 -63
- 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 +22 -5
- 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-context.d.ts +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-merger.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/state.d.ts +1 -1
- package/dist/client/top-loader.d.ts +5 -5
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/use-cookie.d.ts +8 -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-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/client/{use-params.d.ts → use-segment-params.d.ts} +7 -5
- package/dist/client/use-segment-params.d.ts.map +1 -0
- 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 +294 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-validation.d.ts +51 -0
- package/dist/config-validation.d.ts.map +1 -0
- package/dist/content/index.d.ts +1 -10
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +0 -2
- package/dist/cookies/define-cookie.d.ts +98 -25
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +2 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +36 -72
- 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 +46 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/dev-tools/404-page.d.ts +46 -0
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/dev-tools/browser-logs.d.ts +84 -0
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/dev-tools/error-page.d.ts +58 -0
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/dev-tools/holding-server.d.ts +54 -0
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
- 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} +2 -2
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/dev-tools/overlay.d.ts +91 -0
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/dev-tools/terminal.d.ts +28 -0
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +2 -22
- package/dist/dev-tools/warnings.d.ts.map +1 -0
- package/dist/fonts/bundle.d.ts +48 -0
- package/dist/fonts/bundle.d.ts.map +1 -0
- package/dist/fonts/css.d.ts +1 -0
- package/dist/fonts/css.d.ts.map +1 -1
- package/dist/fonts/dev-middleware.d.ts +22 -0
- package/dist/fonts/dev-middleware.d.ts.map +1 -0
- package/dist/fonts/local.d.ts +4 -2
- package/dist/fonts/local.d.ts.map +1 -1
- package/dist/fonts/pipeline.d.ts +167 -0
- package/dist/fonts/pipeline.d.ts.map +1 -0
- package/dist/fonts/transform.d.ts +64 -0
- package/dist/fonts/transform.d.ts.map +1 -0
- package/dist/fonts/types.d.ts +45 -1
- package/dist/fonts/types.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts +103 -0
- package/dist/fonts/virtual-modules.d.ts.map +1 -0
- package/dist/index.d.ts +46 -152
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14702 -12350
- 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 +16 -4
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/chunks.d.ts +9 -1
- package/dist/plugins/chunks.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-server.d.ts +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +8 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +17 -65
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts +7 -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-shared.d.ts +55 -0
- package/dist/routing/codegen-shared.d.ts.map +1 -0
- package/dist/routing/codegen-types.d.ts +52 -0
- package/dist/routing/codegen-types.d.ts.map +1 -0
- package/dist/routing/codegen.d.ts +2 -2
- package/dist/routing/codegen.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts +41 -0
- package/dist/routing/convention-lint.d.ts.map +1 -0
- package/dist/routing/index.d.ts +5 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -2
- package/dist/routing/link-codegen.d.ts +90 -0
- package/dist/routing/link-codegen.d.ts.map +1 -0
- package/dist/routing/scanner.d.ts +1 -10
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +75 -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 +77 -25
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/routing/walkers.d.ts +51 -0
- package/dist/routing/walkers.d.ts.map +1 -0
- package/dist/rsc-runtime/rsc.d.ts +1 -1
- package/dist/rsc-runtime/rsc.d.ts.map +1 -1
- package/dist/rsc-runtime/ssr.d.ts +12 -0
- package/dist/rsc-runtime/ssr.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts +76 -0
- package/dist/schema-bridge.d.ts.map +1 -0
- package/dist/search-params/define.d.ts +157 -0
- package/dist/search-params/define.d.ts.map +1 -0
- package/dist/search-params/index.d.ts +4 -7
- package/dist/search-params/index.d.ts.map +1 -1
- package/dist/search-params/index.js +34 -441
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/registry.d.ts +2 -2
- package/dist/search-params/registry.d.ts.map +1 -1
- package/dist/search-params/wrappers.d.ts +53 -0
- package/dist/search-params/wrappers.d.ts.map +1 -0
- package/dist/segment-params/define.d.ts +95 -0
- package/dist/segment-params/define.d.ts.map +1 -0
- package/dist/segment-params/index.d.ts +3 -0
- package/dist/segment-params/index.d.ts.map +1 -0
- package/dist/segment-params/index.js +2 -0
- package/dist/server/access-gate.d.ts +8 -3
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-client.d.ts +41 -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 +35 -1
- 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 +33 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +1 -15
- package/dist/server/asset-headers.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/cookie-context.d.ts +170 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +51 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/debug.d.ts +82 -0
- package/dist/server/debug.d.ts.map +1 -0
- package/dist/server/default-logger.d.ts +22 -0
- package/dist/server/default-logger.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +90 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/dev-source-map.d.ts +22 -0
- package/dist/server/dev-source-map.d.ts.map +1 -0
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/early-hints.d.ts +13 -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 +12 -7
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/flight-injection-state.d.ts +66 -0
- package/dist/server/flight-injection-state.d.ts.map +1 -0
- package/dist/server/flight-scripts.d.ts +42 -0
- package/dist/server/flight-scripts.d.ts.map +1 -0
- package/dist/server/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-injector-core.d.ts +212 -0
- package/dist/server/html-injector-core.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts +81 -41
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +9 -46
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +158 -2899
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +48 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +2900 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/logger.d.ts +39 -7
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +36 -4
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +110 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -0
- package/dist/server/param-coercion.d.ts +26 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +95 -0
- package/dist/server/pipeline-helpers.d.ts.map +1 -0
- package/dist/server/pipeline-interception.d.ts +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-metadata.d.ts +6 -0
- package/dist/server/pipeline-metadata.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +52 -0
- package/dist/server/pipeline-phases.d.ts.map +1 -0
- package/dist/server/pipeline.d.ts +93 -23
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/port-resolution.d.ts +117 -0
- package/dist/server/port-resolution.d.ts.map +1 -0
- package/dist/server/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 +41 -109
- 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 +21 -34
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/api-handler.d.ts +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 +49 -6
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +20 -3
- 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/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 +20 -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/rsc-entry/wrap-action-dispatch.d.ts +119 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
- package/dist/server/rsc-prop-warnings.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/sensitive-fields.d.ts +74 -0
- package/dist/server/sensitive-fields.d.ts.map +1 -0
- package/dist/server/sitemap-generator.d.ts +129 -0
- package/dist/server/sitemap-generator.d.ts.map +1 -0
- package/dist/server/sitemap-handler.d.ts +22 -0
- package/dist/server/sitemap-handler.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +23 -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/state-tree-diff.d.ts.map +1 -1
- package/dist/server/status-code-resolver.d.ts +16 -11
- 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 +15 -5
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +62 -30
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +49 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/server/version-skew.d.ts +61 -0
- package/dist/server/version-skew.d.ts.map +1 -0
- package/dist/server/waituntil-bridge.d.ts.map +1 -1
- 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 +3 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +11 -5
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/utils/directive-parser.d.ts +1 -43
- 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/build-output-helper.ts +77 -0
- package/src/adapters/cloudflare-dev.ts +177 -0
- package/src/adapters/cloudflare-kv-cache.ts +142 -0
- package/src/adapters/cloudflare.ts +350 -76
- package/src/adapters/compress-module.ts +24 -4
- package/src/adapters/nitro.ts +148 -60
- package/src/adapters/shared.ts +40 -0
- package/src/adapters/wrangler.d.ts +7 -0
- package/src/cache/cache-api.ts +38 -0
- package/src/cache/fast-hash.ts +34 -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 +41 -29
- package/src/cli.ts +16 -6
- package/src/client/browser-dev.ts +153 -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 +143 -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 +97 -20
- package/src/client/error-reconstituter.tsx +65 -0
- package/src/client/form.tsx +31 -32
- package/src/client/history.ts +26 -4
- package/src/client/index.ts +77 -43
- package/src/client/internal.ts +58 -0
- package/src/client/link-pending-store.ts +111 -0
- package/src/client/link.tsx +432 -140
- 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 +83 -18
- 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 +303 -78
- package/src/client/rsc-fetch.ts +112 -8
- package/src/client/segment-cache.ts +1 -1
- package/src/client/segment-context.ts +6 -1
- package/src/client/segment-merger.ts +2 -8
- package/src/client/segment-outlet.tsx +86 -0
- package/src/client/ssr-data.ts +13 -5
- package/src/client/stale-reload.ts +74 -7
- package/src/client/state.ts +2 -2
- package/src/client/top-loader.tsx +41 -25
- package/src/client/use-cookie.ts +29 -0
- package/src/client/use-link-status.ts +7 -7
- package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
- package/src/client/use-query-states.ts +9 -3
- package/src/client/use-router.ts +1 -1
- package/src/client/{use-params.ts → use-segment-params.ts} +7 -5
- package/src/codec.ts +45 -0
- package/src/config-types.ts +292 -0
- package/src/config-validation.ts +303 -0
- package/src/content/index.ts +5 -13
- package/src/cookies/define-cookie.ts +301 -55
- package/src/cookies/index.ts +12 -1
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +134 -0
- package/src/dev-tools/404-page.ts +387 -0
- package/src/dev-tools/browser-logs.ts +288 -0
- package/src/dev-tools/error-page.ts +509 -0
- package/src/dev-tools/holding-server.ts +187 -0
- package/src/dev-tools/index.ts +90 -0
- package/src/dev-tools/instrumentation.ts +176 -0
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +3 -3
- package/src/dev-tools/overlay.ts +456 -0
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/dev-tools/terminal.ts +183 -0
- package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +6 -50
- package/src/fonts/bundle.ts +142 -0
- package/src/fonts/css.ts +2 -1
- package/src/fonts/dev-middleware.ts +74 -0
- package/src/fonts/local.ts +7 -3
- package/src/fonts/pipeline.ts +314 -0
- package/src/fonts/transform.ts +406 -0
- package/src/fonts/types.ts +50 -1
- package/src/fonts/virtual-modules.ts +227 -0
- package/src/index.ts +376 -315
- package/src/plugin-context.ts +240 -0
- package/src/plugins/adapter-build.ts +12 -4
- package/src/plugins/build-manifest.ts +13 -2
- package/src/plugins/build-report.ts +32 -21
- package/src/plugins/chunks.ts +9 -1
- package/src/plugins/client-chunks.ts +65 -0
- package/src/plugins/content.ts +1 -1
- package/src/plugins/dev-server.ts +154 -21
- package/src/plugins/entries.ts +119 -12
- package/src/plugins/fonts.ts +177 -524
- package/src/plugins/mdx.ts +52 -15
- package/src/plugins/routing.ts +225 -41
- package/src/plugins/server-action-exports.ts +1 -1
- package/src/plugins/server-bundle.ts +36 -1
- package/src/plugins/shims.ts +136 -35
- package/src/plugins/static-build.ts +17 -11
- package/src/routing/codegen-shared.ts +98 -0
- package/src/routing/codegen-types.ts +53 -0
- package/src/routing/codegen.ts +143 -176
- package/src/routing/convention-lint.ts +357 -0
- package/src/routing/index.ts +5 -1
- package/src/routing/interception.ts +1 -1
- package/src/routing/link-codegen.ts +294 -0
- package/src/routing/scanner.ts +107 -110
- package/src/routing/segment-classify.ts +188 -0
- package/src/routing/status-file-lint.ts +10 -7
- package/src/routing/types.ts +78 -25
- package/src/routing/walkers.ts +90 -0
- 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 +538 -0
- package/src/search-params/index.ts +14 -20
- package/src/search-params/registry.ts +2 -2
- package/src/search-params/wrappers.ts +92 -0
- package/src/segment-params/define.ts +332 -0
- package/src/segment-params/index.ts +9 -0
- package/src/server/access-gate.tsx +79 -36
- package/src/server/action-client.ts +103 -20
- package/src/server/action-encryption.ts +144 -0
- package/src/server/action-handler.ts +112 -14
- package/src/server/actions.ts +10 -9
- package/src/server/als-registry.ts +35 -7
- package/src/server/asset-headers.ts +8 -34
- package/src/server/build-manifest.ts +10 -4
- package/src/server/compress.ts +25 -7
- package/src/server/cookie-context.ts +468 -0
- package/src/server/cookie-parsing.ts +135 -0
- package/src/server/debug.ts +137 -0
- package/src/server/default-logger.ts +99 -0
- package/src/server/deny-boundary.ts +218 -0
- package/src/server/deny-renderer.ts +33 -51
- package/src/server/dev-source-map.ts +31 -0
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/early-hints.ts +36 -15
- package/src/server/error-boundary-wrapper.ts +74 -22
- package/src/server/fallback-error.ts +74 -102
- 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-injector-core.ts +403 -0
- package/src/server/html-injectors.ts +244 -223
- package/src/server/index.ts +31 -184
- package/src/server/internal.ts +176 -0
- package/src/server/logger.ts +67 -35
- package/src/server/middleware-runner.ts +75 -4
- package/src/server/node-stream-transforms.ts +369 -0
- package/src/server/param-coercion.ts +76 -0
- package/src/server/pipeline-helpers.ts +204 -0
- package/src/server/pipeline-interception.ts +17 -16
- package/src/server/pipeline-metadata.ts +13 -0
- package/src/server/pipeline-outcome.ts +167 -0
- package/src/server/pipeline-phases.ts +409 -0
- package/src/server/pipeline.ts +128 -387
- package/src/server/port-resolution.ts +215 -0
- package/src/server/primitives.ts +113 -29
- package/src/server/render-timeout.ts +108 -0
- package/src/server/request-context.ts +94 -337
- package/src/server/route-element-builder.ts +289 -198
- package/src/server/route-handler.ts +24 -4
- package/src/server/route-matcher.ts +44 -65
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/api-handler.ts +16 -17
- package/src/server/rsc-entry/error-renderer.ts +305 -89
- package/src/server/rsc-entry/helpers.ts +136 -12
- package/src/server/rsc-entry/index.ts +330 -312
- package/src/server/rsc-entry/render-route.ts +304 -0
- package/src/server/rsc-entry/rsc-payload.ts +100 -18
- package/src/server/rsc-entry/rsc-stream.ts +90 -17
- package/src/server/rsc-entry/ssr-bridge.ts +14 -5
- package/src/server/rsc-entry/ssr-renderer.ts +177 -37
- package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -0
- package/src/server/rsc-prop-warnings.ts +3 -1
- package/src/server/safe-load.ts +60 -0
- package/src/server/sensitive-fields.ts +230 -0
- package/src/server/sitemap-generator.ts +338 -0
- package/src/server/sitemap-handler.ts +126 -0
- package/src/server/slot-resolver.ts +245 -230
- package/src/server/ssr-entry.ts +215 -32
- package/src/server/ssr-render.ts +289 -67
- package/src/server/ssr-wrappers.tsx +139 -0
- package/src/server/state-tree-diff.ts +4 -1
- package/src/server/status-code-resolver.ts +112 -128
- package/src/server/stream-utils.ts +213 -0
- package/src/server/tracing.ts +44 -10
- package/src/server/tree-builder.ts +202 -90
- package/src/server/types.ts +55 -6
- package/src/server/utils/escape-html.ts +20 -0
- package/src/server/version-skew.ts +104 -0
- package/src/server/waituntil-bridge.ts +4 -1
- 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 +4 -3
- package/src/shims/navigation.ts +14 -7
- package/src/utils/directive-parser.ts +1 -390
- package/src/utils/state-machine.ts +111 -0
- package/dist/_chunks/als-registry-k-AtAQ9R.js +0 -41
- package/dist/_chunks/als-registry-k-AtAQ9R.js.map +0 -1
- package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
- package/dist/_chunks/interception-DGDIjDbR.js +0 -676
- package/dist/_chunks/interception-DGDIjDbR.js.map +0 -1
- package/dist/_chunks/request-context-CRj2Zh1E.js +0 -329
- package/dist/_chunks/request-context-CRj2Zh1E.js.map +0 -1
- package/dist/_chunks/ssr-data-DLnbYpj1.js.map +0 -1
- package/dist/_chunks/tracing-DF0G3FB7.js +0 -173
- package/dist/_chunks/tracing-DF0G3FB7.js.map +0 -1
- package/dist/_chunks/use-cookie-dDbpCTx-.js +0 -91
- package/dist/_chunks/use-cookie-dDbpCTx-.js.map +0 -1
- package/dist/_chunks/use-query-states-DAhgj8Gx.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 -22
- package/dist/client/browser-entry.d.ts.map +0 -1
- package/dist/client/browser-links.d.ts +0 -32
- package/dist/client/browser-links.d.ts.map +0 -1
- package/dist/client/link-navigate-interceptor.d.ts +0 -28
- package/dist/client/link-navigate-interceptor.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/client/use-params.d.ts.map +0 -1
- package/dist/plugins/cache-transform.d.ts +0 -36
- package/dist/plugins/cache-transform.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts +0 -60
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dynamic-transform.d.ts +0 -72
- package/dist/plugins/dynamic-transform.d.ts.map +0 -1
- package/dist/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/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.map +0 -1
- package/dist/server/dev-warnings.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/src/cache/register-cached-function.ts +0 -99
- package/src/client/browser-entry.ts +0 -686
- package/src/client/browser-links.ts +0 -90
- package/src/client/link-navigate-interceptor.tsx +0 -62
- package/src/client/link-status-provider.tsx +0 -30
- package/src/client/transition-root.tsx +0 -160
- package/src/plugins/cache-transform.ts +0 -199
- package/src/plugins/dev-error-overlay.ts +0 -230
- package/src/plugins/dynamic-transform.ts +0 -161
- package/src/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/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/manifest-status-resolver.ts +0 -215
- package/src/server/prerender.ts +0 -139
- /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie parsing and serialization helpers — pure string ↔ structure
|
|
3
|
+
* functions with no ALS dependency. Split out of `cookie-context.ts`
|
|
4
|
+
* (TIM-853) so the API surface and the wire-format codecs can each be
|
|
5
|
+
* read on their own.
|
|
6
|
+
*
|
|
7
|
+
* The functions in this module are total over arbitrary input. They
|
|
8
|
+
* never throw and never call `assertValid*` (the security validators
|
|
9
|
+
* live in the API surface — `cookie-context.ts` invokes them at every
|
|
10
|
+
* jar entry point so the smuggling-primitive invariant from TIM-868
|
|
11
|
+
* is enforced regardless of which path produced the bytes).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { CookieEntry } from './als-registry.js';
|
|
15
|
+
import type { CookieOptions } from './cookie-context.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse a Cookie header string into a Map of name → value pairs.
|
|
19
|
+
* Follows RFC 6265 §4.2.1: cookies are semicolon-separated key=value pairs.
|
|
20
|
+
*
|
|
21
|
+
* Values are auto-decoded with `decodeURIComponent` so they round-trip
|
|
22
|
+
* losslessly with `getCookies().set()` (which auto-encodes). Malformed
|
|
23
|
+
* `%`-escapes from third-party cookies fall back to the raw byte sequence
|
|
24
|
+
* — the parser must be total over arbitrary inbound headers, including
|
|
25
|
+
* non-conforming values from other servers, browser extensions, etc.
|
|
26
|
+
*/
|
|
27
|
+
export function parseCookieHeader(header: string): Map<string, string> {
|
|
28
|
+
const map = new Map<string, string>();
|
|
29
|
+
if (!header) return map;
|
|
30
|
+
|
|
31
|
+
for (const pair of header.split(';')) {
|
|
32
|
+
const eqIndex = pair.indexOf('=');
|
|
33
|
+
if (eqIndex === -1) continue;
|
|
34
|
+
const name = pair.slice(0, eqIndex).trim();
|
|
35
|
+
const value = pair.slice(eqIndex + 1).trim();
|
|
36
|
+
if (name) {
|
|
37
|
+
map.set(name, safeDecodeCookieValue(value));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return map;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Decode a single cookie value with `decodeURIComponent`, falling back to
|
|
46
|
+
* the raw byte sequence if the input contains a malformed `%`-escape.
|
|
47
|
+
*
|
|
48
|
+
* Used by both `parseCookieHeader` (incoming Cookie: header) and the
|
|
49
|
+
* `setRaw` forwarding path (outgoing Set-Cookie from upstream services).
|
|
50
|
+
* Total — never throws.
|
|
51
|
+
*/
|
|
52
|
+
export function safeDecodeCookieValue(raw: string): string {
|
|
53
|
+
try {
|
|
54
|
+
return decodeURIComponent(raw);
|
|
55
|
+
} catch {
|
|
56
|
+
return raw;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Serialize a CookieEntry into a Set-Cookie header value. */
|
|
61
|
+
export function serializeCookieEntry(entry: CookieEntry): string {
|
|
62
|
+
const parts = [`${entry.name}=${entry.value}`];
|
|
63
|
+
const opts = entry.options;
|
|
64
|
+
|
|
65
|
+
if (opts.domain) parts.push(`Domain=${opts.domain}`);
|
|
66
|
+
if (opts.path) parts.push(`Path=${opts.path}`);
|
|
67
|
+
if (opts.expires) parts.push(`Expires=${opts.expires.toUTCString()}`);
|
|
68
|
+
if (opts.maxAge !== undefined) parts.push(`Max-Age=${opts.maxAge}`);
|
|
69
|
+
if (opts.httpOnly) parts.push('HttpOnly');
|
|
70
|
+
if (opts.secure) parts.push('Secure');
|
|
71
|
+
if (opts.sameSite) {
|
|
72
|
+
parts.push(`SameSite=${opts.sameSite.charAt(0).toUpperCase()}${opts.sameSite.slice(1)}`);
|
|
73
|
+
}
|
|
74
|
+
if (opts.partitioned) parts.push('Partitioned');
|
|
75
|
+
|
|
76
|
+
return parts.join('; ');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Parse a raw `Set-Cookie` header string into name, value, and options.
|
|
81
|
+
* Handles all standard attributes: Path, Domain, Max-Age, Expires,
|
|
82
|
+
* SameSite, Secure, HttpOnly, Partitioned.
|
|
83
|
+
*
|
|
84
|
+
* Does NOT apply DEFAULT_COOKIE_OPTIONS — the caller decides whether
|
|
85
|
+
* to merge defaults (e.g. `set()` does, but `setRaw()` should preserve
|
|
86
|
+
* the original header's intent).
|
|
87
|
+
*/
|
|
88
|
+
export function parseSetCookie(
|
|
89
|
+
header: string
|
|
90
|
+
): { name: string; value: string; options: CookieOptions } | null {
|
|
91
|
+
const segments = header.split(';');
|
|
92
|
+
const nameValue = segments[0];
|
|
93
|
+
const eqIdx = nameValue.indexOf('=');
|
|
94
|
+
if (eqIdx <= 0) return null;
|
|
95
|
+
|
|
96
|
+
const name = nameValue.slice(0, eqIdx).trim();
|
|
97
|
+
const value = nameValue.slice(eqIdx + 1).trim();
|
|
98
|
+
const options: CookieOptions = {};
|
|
99
|
+
|
|
100
|
+
for (let i = 1; i < segments.length; i++) {
|
|
101
|
+
const seg = segments[i].trim();
|
|
102
|
+
if (!seg) continue;
|
|
103
|
+
const [attrName, ...rest] = seg.split('=');
|
|
104
|
+
const key = attrName.trim().toLowerCase();
|
|
105
|
+
const val = rest.join('=').trim();
|
|
106
|
+
switch (key) {
|
|
107
|
+
case 'path':
|
|
108
|
+
options.path = val || '/';
|
|
109
|
+
break;
|
|
110
|
+
case 'domain':
|
|
111
|
+
options.domain = val;
|
|
112
|
+
break;
|
|
113
|
+
case 'max-age':
|
|
114
|
+
options.maxAge = Number(val);
|
|
115
|
+
break;
|
|
116
|
+
case 'expires':
|
|
117
|
+
options.expires = new Date(val);
|
|
118
|
+
break;
|
|
119
|
+
case 'samesite':
|
|
120
|
+
options.sameSite = val.toLowerCase() as 'strict' | 'lax' | 'none';
|
|
121
|
+
break;
|
|
122
|
+
case 'secure':
|
|
123
|
+
options.secure = true;
|
|
124
|
+
break;
|
|
125
|
+
case 'httponly':
|
|
126
|
+
options.httpOnly = true;
|
|
127
|
+
break;
|
|
128
|
+
case 'partitioned':
|
|
129
|
+
options.partitioned = true;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { name, value, options };
|
|
135
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime debug flag for timber.js.
|
|
3
|
+
*
|
|
4
|
+
* Two distinct functions for two distinct security levels:
|
|
5
|
+
*
|
|
6
|
+
* ## `isDebug()` — server-side logging only
|
|
7
|
+
*
|
|
8
|
+
* Returns true when timber's debug/warning messages should be written to
|
|
9
|
+
* stderr / the server console. This NEVER affects what is sent to the
|
|
10
|
+
* client (no error details, no timing headers, no stack traces).
|
|
11
|
+
*
|
|
12
|
+
* Active when any of:
|
|
13
|
+
* - `NODE_ENV !== 'production'` (standard dev mode)
|
|
14
|
+
* - `TIMBER_DEBUG` env var is set to a truthy value at runtime
|
|
15
|
+
* - `timber.config.ts` has `debug: true`
|
|
16
|
+
*
|
|
17
|
+
* ## `isDevMode()` — client-visible dev behavior
|
|
18
|
+
*
|
|
19
|
+
* Returns true ONLY when `NODE_ENV !== 'production'`. This gates anything
|
|
20
|
+
* that changes what clients can observe:
|
|
21
|
+
* - Dev error pages with stack traces (fallback-error.ts)
|
|
22
|
+
* - Detailed Server-Timing headers (pipeline.ts)
|
|
23
|
+
* - Error messages in action INTERNAL_ERROR payloads (action-client.ts)
|
|
24
|
+
* - Pipeline error handler wiring (Vite overlay)
|
|
25
|
+
*
|
|
26
|
+
* `isDevMode()` is statically replaced in production builds → the guarded
|
|
27
|
+
* code is tree-shaken to zero bytes. TIMBER_DEBUG cannot enable it.
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* In Cloudflare Workers wrangler.toml:
|
|
31
|
+
* [vars]
|
|
32
|
+
* TIMBER_DEBUG = "1"
|
|
33
|
+
*
|
|
34
|
+
* In Node.js:
|
|
35
|
+
* TIMBER_DEBUG=1 node server.js
|
|
36
|
+
*
|
|
37
|
+
* In timber.config.ts:
|
|
38
|
+
* export default { debug: true }
|
|
39
|
+
*
|
|
40
|
+
* See design/13-security.md for the security taxonomy.
|
|
41
|
+
* See design/18-build-system.md for build pipeline details.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
// ─── Dev Mode (client-visible) ──────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if the application is running in development mode.
|
|
48
|
+
*
|
|
49
|
+
* This is the ONLY function that should gate client-visible dev behavior:
|
|
50
|
+
* - Dev error pages with stack traces
|
|
51
|
+
* - Server-Timing mode default (`'detailed'` in dev, `'total'` in prod)
|
|
52
|
+
* - Error messages in action `INTERNAL_ERROR` payloads
|
|
53
|
+
* - Pipeline error handler wiring (Vite overlay)
|
|
54
|
+
*
|
|
55
|
+
* Returns `process.env.NODE_ENV !== 'production'`, which is statically
|
|
56
|
+
* replaced by the bundler in production builds. Code guarded by this
|
|
57
|
+
* function is tree-shaken to zero bytes in production.
|
|
58
|
+
*
|
|
59
|
+
* TIMBER_DEBUG does NOT enable this — that would leak server internals
|
|
60
|
+
* to clients. Use `isDebug()` for server-side-only logging.
|
|
61
|
+
*/
|
|
62
|
+
export function isDevMode(): boolean {
|
|
63
|
+
return process.env.NODE_ENV !== 'production';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Debug Flag (server-side logging only) ──────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Config-level debug override. Set via `setDebugFromConfig()` during
|
|
70
|
+
* initialization when timber.config.ts has `debug: true`.
|
|
71
|
+
*/
|
|
72
|
+
let _configDebug = false;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Set the debug flag from timber.config.ts.
|
|
76
|
+
* Called during handler initialization.
|
|
77
|
+
*/
|
|
78
|
+
export function setDebugFromConfig(debug: boolean): void {
|
|
79
|
+
_configDebug = debug;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if timber debug logging is active (server-side only).
|
|
84
|
+
*
|
|
85
|
+
* Returns true if ANY of these conditions hold:
|
|
86
|
+
* - NODE_ENV is not 'production' (standard dev mode)
|
|
87
|
+
* - TIMBER_DEBUG environment variable is set to a truthy value at runtime
|
|
88
|
+
* - timber.config.ts has `debug: true`
|
|
89
|
+
*
|
|
90
|
+
* This function controls ONLY server-side logging — messages written to
|
|
91
|
+
* stderr or the server console. It NEVER affects client-visible behavior
|
|
92
|
+
* (error pages, response headers, action payloads). For client-visible
|
|
93
|
+
* behavior, use `isDevMode()`.
|
|
94
|
+
*
|
|
95
|
+
* The TIMBER_DEBUG check is deliberately written as a dynamic property
|
|
96
|
+
* access so bundlers cannot statically replace it.
|
|
97
|
+
*/
|
|
98
|
+
export function isDebug(): boolean {
|
|
99
|
+
// Fast path: dev mode (statically replaced to `true` in dev, `false` in prod)
|
|
100
|
+
if (process.env.NODE_ENV !== 'production') return true;
|
|
101
|
+
|
|
102
|
+
// Config override
|
|
103
|
+
if (_configDebug) return true;
|
|
104
|
+
|
|
105
|
+
// Runtime env var check — uses dynamic access to prevent static replacement.
|
|
106
|
+
// In production builds, process.env.NODE_ENV is statically replaced, but
|
|
107
|
+
// TIMBER_DEBUG must survive as a runtime check. The dynamic key access
|
|
108
|
+
// pattern ensures the bundler treats this as opaque.
|
|
109
|
+
return _readTimberDebugEnv();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Read TIMBER_DEBUG from the environment at runtime.
|
|
114
|
+
*
|
|
115
|
+
* Extracted to a separate function to:
|
|
116
|
+
* 1. Prevent bundler inlining (cross-module function calls are not inlined)
|
|
117
|
+
* 2. Handle platforms where `process` may not exist (Cloudflare Workers)
|
|
118
|
+
* 3. Support globalThis.__TIMBER_DEBUG for programmatic control
|
|
119
|
+
*/
|
|
120
|
+
function _readTimberDebugEnv(): boolean {
|
|
121
|
+
// globalThis override — useful for programmatic control and testing
|
|
122
|
+
if ((globalThis as Record<string, unknown>).__TIMBER_DEBUG) return true;
|
|
123
|
+
|
|
124
|
+
// process.env — works in Node.js and platforms that polyfill process
|
|
125
|
+
try {
|
|
126
|
+
const key = 'TIMBER_DEBUG';
|
|
127
|
+
const val =
|
|
128
|
+
typeof process !== 'undefined' && process.env
|
|
129
|
+
? (process.env as Record<string, string | undefined>)[key]
|
|
130
|
+
: undefined;
|
|
131
|
+
if (val && val !== '0' && val !== 'false') return true;
|
|
132
|
+
} catch {
|
|
133
|
+
// process may not exist or env may throw — safe to ignore
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DefaultLogger — human-readable stderr logging when no custom logger is configured.
|
|
3
|
+
*
|
|
4
|
+
* Ships as the fallback so production deployments always have error visibility,
|
|
5
|
+
* even without an `instrumentation.ts` logger export. Output is one line per
|
|
6
|
+
* event, designed for `fly logs`, `kubectl logs`, Cloudflare dashboard tails, etc.
|
|
7
|
+
*
|
|
8
|
+
* Format:
|
|
9
|
+
* [timber] ERROR message key=value key=value trace_id=4bf92f35
|
|
10
|
+
* [timber] WARN message key=value key=value trace_id=4bf92f35
|
|
11
|
+
* [timber] INFO message method=GET path=/dashboard status=200 durationMs=43 trace_id=4bf92f35
|
|
12
|
+
*
|
|
13
|
+
* Behavior:
|
|
14
|
+
* - Suppressed entirely in dev mode (dev logging handles all output)
|
|
15
|
+
* - `debug` suppressed unless TIMBER_DEBUG is set
|
|
16
|
+
* - Replaced entirely when a custom logger is set via `setLogger()`
|
|
17
|
+
*
|
|
18
|
+
* See design/17-logging.md §"DefaultLogger"
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { isDevMode, isDebug } from './debug.js';
|
|
22
|
+
import { formatSsrError } from './error-formatter.js';
|
|
23
|
+
import type { TimberLogger } from './logger.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Format data fields as `key=value` pairs for human-readable output.
|
|
27
|
+
* - `error` key is serialized via formatSsrError for stack trace cleanup
|
|
28
|
+
* - `trace_id` is truncated to 8 chars for readability (full ID in OTEL)
|
|
29
|
+
* - Other values are stringified inline
|
|
30
|
+
*/
|
|
31
|
+
function formatDataFields(data?: Record<string, unknown>): string {
|
|
32
|
+
if (!data) return '';
|
|
33
|
+
|
|
34
|
+
const parts: string[] = [];
|
|
35
|
+
let traceId: string | undefined;
|
|
36
|
+
|
|
37
|
+
for (const [key, value] of Object.entries(data)) {
|
|
38
|
+
if (key === 'trace_id') {
|
|
39
|
+
// Defer trace_id to the end
|
|
40
|
+
traceId = typeof value === 'string' ? value : String(value);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (key === 'error') {
|
|
44
|
+
// Serialize errors with formatSsrError for clean output
|
|
45
|
+
parts.push(`error=${formatSsrError(value)}`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (value === undefined || value === null) continue;
|
|
49
|
+
parts.push(`${key}=${value}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// trace_id always last, truncated to 8 chars for readability
|
|
53
|
+
if (traceId) {
|
|
54
|
+
parts.push(`trace_id=${traceId.slice(0, 8)}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return parts.length > 0 ? ' ' + parts.join(' ') : '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Pad level string to fixed width for alignment. */
|
|
61
|
+
function padLevel(level: string): string {
|
|
62
|
+
return level.padEnd(5);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createDefaultLogger(): TimberLogger {
|
|
66
|
+
return {
|
|
67
|
+
error(msg: string, data?: Record<string, unknown>): void {
|
|
68
|
+
// Errors are ALWAYS logged, including dev mode. Suppressing errors
|
|
69
|
+
// in dev causes silent 500s with no stack trace, making route.ts
|
|
70
|
+
// and render errors impossible to debug. See TIM-555.
|
|
71
|
+
const fields = formatDataFields(data);
|
|
72
|
+
process.stderr.write(`[timber] ${padLevel('ERROR')} ${msg}${fields}\n`);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
warn(msg: string, data?: Record<string, unknown>): void {
|
|
76
|
+
// Warnings are always logged — same rationale as errors.
|
|
77
|
+
const fields = formatDataFields(data);
|
|
78
|
+
process.stderr.write(`[timber] ${padLevel('WARN')} ${msg}${fields}\n`);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
info(msg: string, data?: Record<string, unknown>): void {
|
|
82
|
+
// info is suppressed by default — per-request lines are too noisy
|
|
83
|
+
// without a custom logger. Enable with TIMBER_DEBUG.
|
|
84
|
+
if (isDevMode()) return;
|
|
85
|
+
if (!isDebug()) return;
|
|
86
|
+
const fields = formatDataFields(data);
|
|
87
|
+
process.stderr.write(`[timber] ${padLevel('INFO')} ${msg}${fields}\n`);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
debug(msg: string, data?: Record<string, unknown>): void {
|
|
91
|
+
// debug is suppressed in dev (dev logger handles it) and in
|
|
92
|
+
// production unless TIMBER_DEBUG is explicitly set.
|
|
93
|
+
if (isDevMode()) return;
|
|
94
|
+
if (!isDebug()) return;
|
|
95
|
+
const fields = formatDataFields(data);
|
|
96
|
+
process.stderr.write(`[timber] ${padLevel('DEBUG')} ${msg}${fields}\n`);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deny boundary subsystem — the in-tree DenySignal flow.
|
|
3
|
+
*
|
|
4
|
+
* Three things live together here because they form a single flow:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Chain construction** (`buildDenyPageChain`) — walks the matched
|
|
7
|
+
* segment chain at element-tree build time and produces a list of
|
|
8
|
+
* `DenyPageEntry` records ordered by specificity (specific status →
|
|
9
|
+
* category catch-all → `error.tsx`).
|
|
10
|
+
*
|
|
11
|
+
* 2. **Runtime matching** (`renderMatchingDenyPage`) — picks the first
|
|
12
|
+
* chain entry whose status filter matches the thrown DenySignal and
|
|
13
|
+
* returns a React element for the matching component. Used by
|
|
14
|
+
* `AccessGate` and `PageDenyBoundary` when they catch a deny.
|
|
15
|
+
*
|
|
16
|
+
* 3. **The page boundary itself** (`PageDenyBoundary`) — the async server
|
|
17
|
+
* component that wraps a server-component page, calls it, and catches
|
|
18
|
+
* `DenySignal` so the deny page renders in-tree (no throw reaches
|
|
19
|
+
* React Flight, single render pass).
|
|
20
|
+
*
|
|
21
|
+
* Plus the ALS helpers (`setDenyStatus` / `getDenyStatus`) the boundary
|
|
22
|
+
* uses to thread the matched status code back to the pipeline so the
|
|
23
|
+
* HTTP status reflects the deny.
|
|
24
|
+
*
|
|
25
|
+
* Folded into one module from the former `deny-page-resolver.ts` and
|
|
26
|
+
* `page-deny-boundary.tsx` (TIM-853) — the names were misleading and the
|
|
27
|
+
* three pieces only made sense together.
|
|
28
|
+
*
|
|
29
|
+
* See design/04-authorization.md, design/10-error-handling.md, TIM-666.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { createElement } from 'react';
|
|
33
|
+
|
|
34
|
+
import { requestContextAls } from './als-registry.js';
|
|
35
|
+
import { DenySignal } from './primitives.js';
|
|
36
|
+
import { loadModule } from './safe-load.js';
|
|
37
|
+
import { withSpan } from './tracing.js';
|
|
38
|
+
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
39
|
+
|
|
40
|
+
// ─── Types ────────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
/** A single entry in the deny page fallback chain. */
|
|
43
|
+
export interface DenyPageEntry {
|
|
44
|
+
/** Status code filter: specific (403), category (400 = any 4xx), or null (catch-all). */
|
|
45
|
+
status: number | null;
|
|
46
|
+
/** The component to render (server or client — both work). */
|
|
47
|
+
component: (...args: unknown[]) => unknown;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ─── Chain Construction ──────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build the deny page fallback chain from the segment chain.
|
|
54
|
+
*
|
|
55
|
+
* Walks segments from `startIndex` outward (toward root) and collects
|
|
56
|
+
* status-code file components in fallback order:
|
|
57
|
+
* 1. Specific status files (403.tsx, 404.tsx) — exact match
|
|
58
|
+
* 2. Category catch-alls (4xx.tsx) — matches any 4xx
|
|
59
|
+
* 3. error.tsx — catches everything
|
|
60
|
+
*
|
|
61
|
+
* Each segment is checked in this order. The chain is ordered so the
|
|
62
|
+
* FIRST match wins at catch time.
|
|
63
|
+
*/
|
|
64
|
+
export async function buildDenyPageChain(
|
|
65
|
+
segments: ManifestSegmentNode[],
|
|
66
|
+
startIndex: number
|
|
67
|
+
): Promise<DenyPageEntry[]> {
|
|
68
|
+
const chain: DenyPageEntry[] = [];
|
|
69
|
+
|
|
70
|
+
// Pass 1: Status files (specific + category) across ALL segments.
|
|
71
|
+
// These have higher priority than error.tsx — a root 4xx.tsx should
|
|
72
|
+
// match before a leaf error.tsx. Walking inner → outer ensures the
|
|
73
|
+
// nearest match wins within each priority tier.
|
|
74
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
75
|
+
const segment = segments[i];
|
|
76
|
+
if (!segment.statusFiles) continue;
|
|
77
|
+
|
|
78
|
+
// Specific status files (403.tsx, 404.tsx, etc.)
|
|
79
|
+
for (const [key, file] of Object.entries(segment.statusFiles)) {
|
|
80
|
+
if (key !== '4xx' && key !== '5xx') {
|
|
81
|
+
const status = parseInt(key, 10);
|
|
82
|
+
if (!isNaN(status)) {
|
|
83
|
+
const mod = await loadModule(file).catch(() => null);
|
|
84
|
+
if (mod?.default) {
|
|
85
|
+
chain.push({ status, component: mod.default as (...args: unknown[]) => unknown });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Category catch-alls (4xx.tsx, 5xx.tsx)
|
|
92
|
+
for (const [key, file] of Object.entries(segment.statusFiles)) {
|
|
93
|
+
if (key === '4xx' || key === '5xx') {
|
|
94
|
+
const mod = await loadModule(file).catch(() => null);
|
|
95
|
+
if (mod?.default) {
|
|
96
|
+
const categoryStatus = key === '4xx' ? 400 : 500;
|
|
97
|
+
chain.push({
|
|
98
|
+
status: categoryStatus,
|
|
99
|
+
component: mod.default as (...args: unknown[]) => unknown,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Pass 2: error.tsx files — lowest priority catch-all.
|
|
107
|
+
// Only added AFTER all status files so they never shadow a specific
|
|
108
|
+
// or category status file from an ancestor segment.
|
|
109
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
110
|
+
const segment = segments[i];
|
|
111
|
+
if (segment.error) {
|
|
112
|
+
const mod = await loadModule(segment.error).catch(() => null);
|
|
113
|
+
if (mod?.default) {
|
|
114
|
+
chain.push({ status: null, component: mod.default as (...args: unknown[]) => unknown });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return chain;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── Runtime Matcher ──────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Find the first deny page in the chain that matches the given status code.
|
|
126
|
+
* Returns a React element for the matching component, or null if no match.
|
|
127
|
+
*/
|
|
128
|
+
export function renderMatchingDenyPage(
|
|
129
|
+
chain: DenyPageEntry[],
|
|
130
|
+
status: number,
|
|
131
|
+
data: unknown
|
|
132
|
+
): React.ReactElement | null {
|
|
133
|
+
const h = createElement as (...args: unknown[]) => React.ReactElement;
|
|
134
|
+
|
|
135
|
+
for (const entry of chain) {
|
|
136
|
+
if (entry.status === status) {
|
|
137
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
138
|
+
}
|
|
139
|
+
if (entry.status === 400 && status >= 400 && status <= 499) {
|
|
140
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
141
|
+
}
|
|
142
|
+
if (entry.status === 500 && status >= 500 && status <= 599) {
|
|
143
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
144
|
+
}
|
|
145
|
+
if (entry.status === null) {
|
|
146
|
+
return h(entry.component, { status, dangerouslyPassData: data });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ─── Page Boundary ────────────────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Async server component that wraps a page call with DenySignal catching.
|
|
156
|
+
*
|
|
157
|
+
* Calls the page component as an async function (the same thing React
|
|
158
|
+
* Flight does internally), awaits it, and catches DenySignal. On catch,
|
|
159
|
+
* renders the matching deny page in-tree. On success, returns the page's
|
|
160
|
+
* rendered output normally.
|
|
161
|
+
*
|
|
162
|
+
* Client component pages ('use client') are NOT wrapped — they can't call
|
|
163
|
+
* deny() (server-only API) and must go through createElement normally.
|
|
164
|
+
*
|
|
165
|
+
* No error reaches React Flight — the Flight stream is clean, SSR succeeds,
|
|
166
|
+
* and the entire request uses a single renderToReadableStream call.
|
|
167
|
+
*/
|
|
168
|
+
export async function PageDenyBoundary({
|
|
169
|
+
Page,
|
|
170
|
+
route,
|
|
171
|
+
denyPages,
|
|
172
|
+
}: {
|
|
173
|
+
/** The page server component function. */
|
|
174
|
+
Page: (...args: unknown[]) => unknown;
|
|
175
|
+
/** Route path for OTEL tracing. */
|
|
176
|
+
route: string;
|
|
177
|
+
/** Deny page fallback chain from the segment chain. */
|
|
178
|
+
denyPages: DenyPageEntry[];
|
|
179
|
+
}): Promise<React.ReactElement> {
|
|
180
|
+
try {
|
|
181
|
+
// Call the page as an async function — same as React Flight does.
|
|
182
|
+
// Wrap in OTEL span for tracing (replaces the TracedPage wrapper).
|
|
183
|
+
const result = await withSpan('timber.page', { 'timber.route': route }, () => Page({}));
|
|
184
|
+
return result as React.ReactElement;
|
|
185
|
+
} catch (error: unknown) {
|
|
186
|
+
if (error instanceof DenySignal) {
|
|
187
|
+
const denyElement = renderMatchingDenyPage(denyPages, error.status, error.data);
|
|
188
|
+
if (denyElement) {
|
|
189
|
+
setDenyStatus(error.status);
|
|
190
|
+
return denyElement;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Non-deny errors (RedirectSignal, runtime errors) propagate normally.
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ─── ALS Helpers ──────────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Set the deny status in the request context ALS.
|
|
202
|
+
* Called from AccessGate / PageDenyBoundary when a DenySignal is caught.
|
|
203
|
+
* The pipeline reads this after render to set the HTTP status code.
|
|
204
|
+
*/
|
|
205
|
+
export function setDenyStatus(status: number): void {
|
|
206
|
+
const store = requestContextAls.getStore();
|
|
207
|
+
if (store) {
|
|
208
|
+
store.denyStatus = status;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Read the deny status from the request context ALS.
|
|
214
|
+
* Returns undefined if no deny was caught during render.
|
|
215
|
+
*/
|
|
216
|
+
export function getDenyStatus(): number | undefined {
|
|
217
|
+
return requestContextAls.getStore()?.denyStatus;
|
|
218
|
+
}
|