@timber-js/app 0.2.0-alpha.207 → 0.2.0-alpha.209
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/dist/_chunks/{primitives-DLAnvsrk.js → actions-BerlqoXA.js} +640 -410
- package/dist/_chunks/actions-BerlqoXA.js.map +1 -0
- package/dist/_chunks/{als-registry-C6kcfprT.js → als-registry-DaxkVjt5.js} +6 -2
- package/dist/_chunks/als-registry-DaxkVjt5.js.map +1 -0
- package/dist/_chunks/{build-manifest-DTmSGLRz.js → build-manifest-DWppEdLB.js} +2 -51
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/{build-output-helper-9dqCv1pZ.js → build-output-helper-RV_BRcF1.js} +50 -53
- package/dist/_chunks/build-output-helper-RV_BRcF1.js.map +1 -0
- package/dist/_chunks/{cache-api-CUD9Ezaq.js → cache-api-CR23J_NC.js} +64 -32
- package/dist/_chunks/cache-api-CR23J_NC.js.map +1 -0
- package/dist/_chunks/{chains-B4bgOl2g.js → chains-CpFg56UB.js} +2 -2
- package/dist/_chunks/{chains-B4bgOl2g.js.map → chains-CpFg56UB.js.map} +1 -1
- package/dist/_chunks/{cli-check-G8o30ldg.js → cli-check-C6Ev6wBO.js} +11 -52
- package/dist/_chunks/cli-check-C6Ev6wBO.js.map +1 -0
- package/dist/_chunks/cli-context-By7k2xVo.js +70 -0
- package/dist/_chunks/cli-context-By7k2xVo.js.map +1 -0
- package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js → cli-schema-sync-CbT2AUUI.js} +3 -3
- package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js.map → cli-schema-sync-CbT2AUUI.js.map} +1 -1
- package/dist/_chunks/{cloudflare-BFb__LYG.js → cloudflare-Byxl8FWP.js} +96 -53
- package/dist/_chunks/{cloudflare-BFb__LYG.js.map → cloudflare-Byxl8FWP.js.map} +1 -1
- package/dist/_chunks/{convention-lint-5KzoMg_A.js → convention-lint-jKTwKwPe.js} +21 -6
- package/dist/_chunks/convention-lint-jKTwKwPe.js.map +1 -0
- package/dist/_chunks/{dev-server-BzBxgYAV.js → dev-server-C4WZdB7L.js} +15 -167
- package/dist/_chunks/dev-server-C4WZdB7L.js.map +1 -0
- package/dist/_chunks/{error-boundary-BndF-3Td.js → error-boundary-tA7kVfs4.js} +84 -104
- package/dist/_chunks/error-boundary-tA7kVfs4.js.map +1 -0
- package/dist/_chunks/{fs-identity-D7vb6GdI.js → fs-identity-BRKuL215.js} +3 -4
- package/dist/_chunks/fs-identity-BRKuL215.js.map +1 -0
- package/dist/_chunks/{graph-cache-CP4GEmf9.js → graph-cache-CYiUS2aS.js} +4 -5
- package/dist/_chunks/graph-cache-CYiUS2aS.js.map +1 -0
- package/dist/_chunks/{json-lossy-check-ClNvBM_3.js → json-lossy-check-ip0Qi0MT.js} +6 -3
- package/dist/_chunks/json-lossy-check-ip0Qi0MT.js.map +1 -0
- package/dist/_chunks/{live-graph-Bm5WTvcr.js → live-graph-Dv-JJCZw.js} +3 -3
- package/dist/_chunks/{live-graph-Bm5WTvcr.js.map → live-graph-Dv-JJCZw.js.map} +1 -1
- package/dist/_chunks/{logger-k2DQ4EUf.js → logger-DiDt5ppH.js} +192 -51
- package/dist/_chunks/logger-DiDt5ppH.js.map +1 -0
- package/dist/_chunks/{navigation-root-mHSK9psY.js → navigation-root-BQfo1-kG.js} +2 -2
- package/dist/_chunks/{navigation-root-mHSK9psY.js.map → navigation-root-BQfo1-kG.js.map} +1 -1
- package/dist/_chunks/{plugin-context-8idfR3UZ.js → plugin-context-BPBPc3lL.js} +28 -4
- package/dist/_chunks/plugin-context-BPBPc3lL.js.map +1 -0
- package/dist/_chunks/{poison-scan-DG5eI2_z.js → poison-scan-CpeT6_OJ.js} +2 -2
- package/dist/_chunks/{poison-scan-DG5eI2_z.js.map → poison-scan-CpeT6_OJ.js.map} +1 -1
- package/dist/_chunks/render-timeout-DOf_BBcO.js +46 -0
- package/dist/_chunks/render-timeout-DOf_BBcO.js.map +1 -0
- package/dist/_chunks/{rsc-payload-path-B_LBodc2.js → rsc-payload-path-dffcs4jp.js} +9 -3
- package/dist/_chunks/{rsc-payload-path-B_LBodc2.js.map → rsc-payload-path-dffcs4jp.js.map} +1 -1
- package/dist/_chunks/{scanner-BQ5sPIJ7.js → scanner-Bw0oq1HB.js} +2 -2
- package/dist/_chunks/{scanner-BQ5sPIJ7.js.map → scanner-Bw0oq1HB.js.map} +1 -1
- package/dist/_chunks/{navigation-context-D0TU0Jog.js → segment-context-xtPUGfdq.js} +36 -34
- package/dist/_chunks/segment-context-xtPUGfdq.js.map +1 -0
- package/dist/_chunks/{singleflight-2lUWfcAk.js → singleflight-BeVMMKi0.js} +4 -3
- package/dist/_chunks/{singleflight-2lUWfcAk.js.map → singleflight-BeVMMKi0.js.map} +1 -1
- package/dist/_chunks/{sizeof-lXffQ1Vr.js → sizeof-UwzwB1uM.js} +3 -2
- package/dist/_chunks/sizeof-UwzwB1uM.js.map +1 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js +49 -0
- package/dist/_chunks/ssr-data-nA3I70_n.js.map +1 -0
- package/dist/_chunks/{state-FippDgxN.js → state-BhNGPsdi.js} +6 -8
- package/dist/_chunks/state-BhNGPsdi.js.map +1 -0
- package/dist/_chunks/{status-page-marker-DwQBrLBz.js → status-page-marker-gaihi0KZ.js} +140 -28
- package/dist/_chunks/status-page-marker-gaihi0KZ.js.map +1 -0
- package/dist/_chunks/{walkers-CN2N_bA-.js → walkers-BXExhzzk.js} +2 -2
- package/dist/_chunks/{walkers-CN2N_bA-.js.map → walkers-BXExhzzk.js.map} +1 -1
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js +32 -0
- package/dist/_chunks/write-file-atomic-D1qWqHb4.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +7 -7
- package/dist/adapters/build-output-helper.d.ts.map +1 -1
- package/dist/adapters/canonicalize-module.d.ts +8 -0
- package/dist/adapters/canonicalize-module.d.ts.map +1 -0
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +2 -2
- package/dist/adapters/cloudflare.d.ts +30 -8
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +2 -2
- package/dist/adapters/compress-module.d.ts +8 -0
- package/dist/adapters/compress-module.d.ts.map +1 -1
- package/dist/adapters/fs-identity.d.ts +2 -3
- package/dist/adapters/fs-identity.d.ts.map +1 -1
- package/dist/adapters/nitro-presets.d.ts +0 -6
- package/dist/adapters/nitro-presets.d.ts.map +1 -1
- package/dist/adapters/nitro-preview.d.ts +43 -11
- package/dist/adapters/nitro-preview.d.ts.map +1 -1
- package/dist/adapters/nitro.d.ts +1 -13
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +291 -176
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +7 -2
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +105 -21
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js +0 -0
- package/dist/analyze/crawl-entry.js +3 -3
- package/dist/analyze/graph-cache.d.ts.map +1 -1
- package/dist/analyze/graph-command.js +4 -4
- package/dist/cache/index.js +2 -2
- package/dist/cache/json-lossy-check.d.ts.map +1 -1
- package/dist/cache/singleflight.d.ts.map +1 -1
- package/dist/cache/sizeof.d.ts.map +1 -1
- package/dist/cache/stores/memory.js +1 -1
- package/dist/cache/tag-aware-handler.d.ts.map +1 -1
- package/dist/cdn/workers-cache-purge.js +1 -1
- package/dist/cli-check.d.ts +7 -37
- package/dist/cli-check.d.ts.map +1 -1
- package/dist/cli-context.d.ts +54 -0
- package/dist/cli-context.d.ts.map +1 -0
- package/dist/cli.d.ts +9 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -24
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-dev.d.ts +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/hydrate.d.ts +19 -29
- package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
- package/dist/client/browser-entry/index.d.ts +7 -7
- package/dist/client/browser-entry/post-hydration.d.ts +6 -9
- package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
- package/dist/client/browser-entry/router-init.d.ts +6 -11
- package/dist/client/browser-entry/router-init.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +4 -3
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/error-reconstituter.d.ts +3 -9
- package/dist/client/error-reconstituter.d.ts.map +1 -1
- package/dist/client/history.d.ts +20 -11
- package/dist/client/history.d.ts.map +1 -1
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +5 -6
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +3 -3
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +95 -108
- package/dist/client/internal.js.map +1 -1
- package/dist/client/navigation-commit.d.ts +20 -7
- package/dist/client/navigation-commit.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts +3 -5
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/react-root.d.ts +3 -2
- package/dist/client/react-root.d.ts.map +1 -1
- package/dist/client/router-pipeline.d.ts +3 -8
- package/dist/client/router-pipeline.d.ts.map +1 -1
- package/dist/client/router-types.d.ts +45 -39
- package/dist/client/router-types.d.ts.map +1 -1
- package/dist/client/router-url.d.ts +24 -0
- package/dist/client/router-url.d.ts.map +1 -0
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts +8 -4
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/segment-cache.d.ts +44 -4
- package/dist/client/segment-cache.d.ts.map +1 -1
- package/dist/client/ssr-data.d.ts +18 -64
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/state.d.ts +2 -5
- package/dist/client/state.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts +1 -1
- package/dist/config-types.d.ts +2 -1
- package/dist/config-types.d.ts.map +1 -1
- package/dist/config-validation.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/dev-tools/dev-page-shell.d.ts +17 -0
- package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
- package/dist/dev-tools/index.d.ts +1 -1
- package/dist/dev-tools/index.d.ts.map +1 -1
- package/dist/dev-tools/instrumentation.d.ts +17 -2
- package/dist/dev-tools/instrumentation.d.ts.map +1 -1
- package/dist/dev-tools/overlay.d.ts +6 -27
- package/dist/dev-tools/overlay.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -373
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +26 -40
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/build-manifest.d.ts.map +1 -1
- package/dist/plugins/build-report.d.ts +15 -2
- package/dist/plugins/build-report.d.ts.map +1 -1
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +19 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/plugins/post-build.d.ts +110 -0
- package/dist/plugins/post-build.d.ts.map +1 -0
- package/dist/plugins/prebuilt-capture.d.ts +11 -4
- package/dist/plugins/prebuilt-capture.d.ts.map +1 -1
- package/dist/plugins/prebuilt.d.ts +17 -1
- package/dist/plugins/prebuilt.d.ts.map +1 -1
- package/dist/plugins/prerender-sugar.d.ts.map +1 -1
- package/dist/plugins/react-resolve.d.ts +49 -0
- package/dist/plugins/react-resolve.d.ts.map +1 -0
- package/dist/plugins/rsc-assets-manifest.d.ts +33 -0
- package/dist/plugins/rsc-assets-manifest.d.ts.map +1 -0
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/plugins/static-build.d.ts +32 -9
- package/dist/plugins/static-build.d.ts.map +1 -1
- package/dist/routing/codegen-write.d.ts +0 -9
- package/dist/routing/codegen-write.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/routing/segment-codegen.d.ts.map +1 -1
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts +5 -4
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/actions.d.ts +46 -7
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +58 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/children-interception.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +2 -23
- package/dist/server/cookie-context.d.ts.map +1 -1
- package/dist/server/csp-nonce.d.ts +0 -9
- package/dist/server/csp-nonce.d.ts.map +1 -1
- package/dist/server/csrf.d.ts +27 -4
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/debug.d.ts +0 -1
- package/dist/server/debug.d.ts.map +1 -1
- package/dist/server/default-logger.d.ts +2 -1
- package/dist/server/default-logger.d.ts.map +1 -1
- package/dist/server/deny-boundary.d.ts +12 -6
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +2 -2
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +7 -3
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts +9 -2
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/head-response.d.ts +4 -4
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts +10 -3
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/internal.d.ts +1 -4
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +961 -581
- package/dist/server/internal.js.map +1 -1
- package/dist/server/json-status-response.d.ts +34 -0
- package/dist/server/json-status-response.d.ts.map +1 -0
- package/dist/server/logger.d.ts +26 -0
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +11 -6
- package/dist/server/param-coercion.d.ts.map +1 -1
- package/dist/server/pipeline-helpers.d.ts +95 -7
- package/dist/server/pipeline-helpers.d.ts.map +1 -1
- package/dist/server/pipeline-interception.d.ts +11 -0
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +11 -1
- package/dist/server/pipeline-outcome.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts +2 -2
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +23 -35
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/prebuilt/capture-render.d.ts +25 -0
- package/dist/server/prebuilt/capture-render.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-routes.d.ts +37 -0
- package/dist/server/prebuilt/capture-routes.d.ts.map +1 -0
- package/dist/server/prebuilt/capture-state.d.ts +79 -35
- package/dist/server/prebuilt/capture-state.d.ts.map +1 -1
- package/dist/server/prebuilt/lifetime.d.ts +38 -0
- package/dist/server/prebuilt/lifetime.d.ts.map +1 -0
- package/dist/server/prebuilt/slots.d.ts +7 -0
- package/dist/server/prebuilt/slots.d.ts.map +1 -1
- package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -1
- package/dist/server/prebuilt-builder.d.ts.map +1 -1
- package/dist/server/prebuilt-runtime.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +6 -81
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/react-cache-bridge.d.ts +59 -0
- package/dist/server/react-cache-bridge.d.ts.map +1 -0
- package/dist/server/react-cache-scope.d.ts +49 -0
- package/dist/server/react-cache-scope.d.ts.map +1 -0
- package/dist/server/render-timeout.d.ts +15 -0
- package/dist/server/render-timeout.d.ts.map +1 -1
- package/dist/server/render-utils.d.ts +9 -0
- package/dist/server/render-utils.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +26 -5
- package/dist/server/request-context.d.ts.map +1 -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 +7 -0
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +22 -22
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts +7 -0
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/deny-fallback.d.ts +32 -6
- package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +11 -18
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +0 -1
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +5 -15
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +5 -6
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-signals.d.ts +65 -0
- package/dist/server/rsc-entry/render-signals.d.ts.map +1 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +6 -16
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts +7 -3
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +8 -53
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +2 -2
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +9 -4
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +1 -1
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -1
- package/dist/server/signal-identity.d.ts +43 -0
- package/dist/server/signal-identity.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts +4 -3
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/slot-subtree-contain.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +91 -53
- package/dist/server/ssr-bridge-types.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +8 -5
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +26 -40
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +1 -1
- package/dist/server/static-generator.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts +12 -0
- package/dist/server/stream-utils.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +12 -16
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -1
- package/dist/server/version-skew.d.ts +3 -3
- package/dist/shared/csrf-reject.d.ts +16 -0
- package/dist/shared/csrf-reject.d.ts.map +1 -0
- package/dist/shared/error-digest.d.ts +28 -0
- package/dist/shared/error-digest.d.ts.map +1 -0
- package/dist/shared/payload-root.d.ts +11 -10
- package/dist/shared/payload-root.d.ts.map +1 -1
- package/dist/shared/rsc-payload-path.d.ts +6 -0
- package/dist/shared/rsc-payload-path.d.ts.map +1 -1
- package/dist/utils/write-file-atomic.d.ts +17 -0
- package/dist/utils/write-file-atomic.d.ts.map +1 -0
- package/docs/api/30-api-server.mdx +17 -14
- package/docs/api/32-api-cache.mdx +51 -23
- package/docs/api/34-api-config.mdx +34 -6
- package/docs/api/36-cli.mdx +11 -1
- package/docs/learn/03-fetching-data.mdx +17 -1
- package/docs/learn/04-access-control.mdx +1 -1
- package/docs/learn/10-caching.mdx +29 -11
- package/docs/learn/11-middleware.mdx +8 -2
- package/docs/learn/12-error-handling.mdx +6 -1
- package/package.json +7 -3
- package/src/adapters/build-output-helper.ts +55 -53
- package/src/adapters/canonicalize-module.ts +29 -0
- package/src/adapters/cloudflare.ts +105 -63
- package/src/adapters/compress-module.ts +16 -5
- package/src/adapters/fs-identity.ts +2 -3
- package/src/adapters/nitro-presets.ts +0 -15
- package/src/adapters/nitro-preview.ts +272 -136
- package/src/adapters/nitro.ts +119 -82
- package/src/adapters/shared.ts +23 -14
- package/src/adapters/types.ts +110 -21
- package/src/analyze/graph-cache.ts +3 -4
- package/src/cache/json-lossy-check.ts +3 -9
- package/src/cache/singleflight.ts +5 -2
- package/src/cache/sizeof.ts +3 -1
- package/src/cache/tag-aware-handler.ts +43 -26
- package/src/cli-check.ts +8 -98
- package/src/cli-context.ts +119 -0
- package/src/cli.ts +19 -28
- package/src/client/browser-dev.ts +1 -1
- package/src/client/browser-entry/action-dispatch.ts +26 -4
- package/src/client/browser-entry/hydrate.ts +53 -58
- package/src/client/browser-entry/index.ts +16 -27
- package/src/client/browser-entry/post-hydration.ts +6 -40
- package/src/client/browser-entry/router-init.ts +66 -84
- package/src/client/error-boundary.tsx +9 -41
- package/src/client/error-reconstituter.tsx +10 -5
- package/src/client/history.ts +35 -21
- package/src/client/index.ts +0 -1
- package/src/client/internal.ts +2 -7
- package/src/client/navigation-commit.ts +41 -18
- package/src/client/navigation-context.ts +3 -39
- package/src/client/react-root.ts +3 -2
- package/src/client/router-pipeline.ts +96 -132
- package/src/client/router-types.ts +46 -44
- package/src/client/router-url.ts +32 -0
- package/src/client/router.ts +62 -21
- package/src/client/rsc-fetch.ts +117 -155
- package/src/client/segment-cache.ts +110 -11
- package/src/client/ssr-data.ts +19 -80
- package/src/client/state.ts +2 -9
- package/src/client/use-pathname.ts +1 -1
- package/src/config-types.ts +2 -1
- package/src/config-validation.ts +2 -1
- package/src/dev-tools/dev-page-shell.ts +18 -0
- package/src/dev-tools/index.ts +0 -2
- package/src/dev-tools/instrumentation.ts +50 -2
- package/src/dev-tools/overlay.ts +8 -238
- package/src/index.ts +26 -14
- package/src/plugin-context.ts +39 -40
- package/src/plugins/build-manifest.ts +4 -11
- package/src/plugins/build-report.ts +70 -70
- package/src/plugins/dev-server.ts +24 -44
- package/src/plugins/entries.ts +2 -1
- package/src/plugins/fonts.ts +35 -7
- package/src/plugins/post-build.ts +327 -0
- package/src/plugins/prebuilt-capture.ts +28 -32
- package/src/plugins/prebuilt.ts +54 -39
- package/src/plugins/prerender-sugar.ts +0 -4
- package/src/plugins/react-resolve.ts +149 -0
- package/src/plugins/{adapter-build.ts → rsc-assets-manifest.ts} +20 -109
- package/src/plugins/shims.ts +1 -0
- package/src/plugins/static-build.ts +42 -74
- package/src/routing/codegen-write.ts +25 -3
- package/src/routing/segment-codegen.ts +3 -2
- package/src/rsc-runtime/vendor-types.d.ts +8 -0
- package/src/server/access-gate.tsx +2 -1
- package/src/server/action-client.ts +1 -1
- package/src/server/action-handler.ts +253 -110
- package/src/server/actions.ts +73 -25
- package/src/server/als-registry.ts +73 -5
- package/src/server/chain-url-parts.ts +1 -1
- package/src/server/children-interception.ts +2 -1
- package/src/server/cookie-context.ts +18 -48
- package/src/server/csp-nonce.ts +0 -12
- package/src/server/csrf.ts +140 -8
- package/src/server/debug.ts +0 -1
- package/src/server/default-logger.ts +2 -1
- package/src/server/deny-boundary.ts +25 -13
- package/src/server/deny-renderer.ts +30 -97
- package/src/server/error-boundary-wrapper.ts +7 -3
- package/src/server/fallback-error.ts +26 -11
- package/src/server/flight-scripts.ts +1 -1
- package/src/server/head-response.ts +4 -4
- package/src/server/html-injector-core.ts +2 -2
- package/src/server/html-injectors.ts +2 -4
- package/src/server/index.ts +0 -4
- package/src/server/instrumentation.ts +10 -3
- package/src/server/internal.ts +1 -6
- package/src/server/json-status-response.ts +105 -0
- package/src/server/logger.ts +39 -3
- package/src/server/param-coercion.ts +15 -12
- package/src/server/pipeline-helpers.ts +257 -12
- package/src/server/pipeline-interception.ts +133 -0
- package/src/server/pipeline-outcome.ts +103 -31
- package/src/server/pipeline-phases.ts +127 -237
- package/src/server/pipeline.ts +204 -207
- package/src/server/prebuilt/capture-render.ts +118 -0
- package/src/server/prebuilt/capture-routes.ts +104 -0
- package/src/server/prebuilt/capture-state.ts +155 -48
- package/src/server/prebuilt/lifetime.ts +151 -0
- package/src/server/prebuilt/slots.ts +14 -2
- package/src/server/prebuilt/synthetic-store.ts +3 -0
- package/src/server/prebuilt-builder.ts +30 -320
- package/src/server/prebuilt-runtime.ts +125 -129
- package/src/server/primitives.ts +8 -168
- package/src/server/react-cache-bridge.ts +124 -0
- package/src/server/react-cache-scope.ts +104 -0
- package/src/server/render-timeout.ts +20 -0
- package/src/server/render-utils.ts +11 -1
- package/src/server/request-context.ts +36 -9
- package/src/server/route-element-builder.ts +11 -6
- package/src/server/route-handler.ts +36 -23
- package/src/server/route-matcher.ts +15 -1
- package/src/server/rsc-entry/action-middleware-runner.ts +79 -123
- package/src/server/rsc-entry/api-handler.ts +27 -103
- package/src/server/rsc-entry/deny-fallback.ts +93 -26
- package/src/server/rsc-entry/error-renderer.ts +39 -91
- package/src/server/rsc-entry/helpers.ts +2 -4
- package/src/server/rsc-entry/index.ts +64 -58
- package/src/server/rsc-entry/render-route.ts +15 -80
- package/src/server/rsc-entry/render-signals.ts +108 -0
- package/src/server/rsc-entry/revalidate-renderer.ts +56 -57
- package/src/server/rsc-entry/rsc-payload.ts +28 -61
- package/src/server/rsc-entry/rsc-stream.ts +113 -213
- package/src/server/rsc-entry/ssr-bridge.ts +2 -2
- package/src/server/rsc-entry/ssr-renderer.ts +182 -263
- package/src/server/rsc-entry/wrap-action-dispatch.ts +12 -14
- package/src/server/signal-identity.ts +112 -0
- package/src/server/slot-resolver.ts +18 -18
- package/src/server/slot-subtree-contain.ts +2 -1
- package/src/server/ssr-bridge-types.ts +92 -56
- package/src/server/ssr-entry.ts +87 -111
- package/src/server/ssr-render.ts +55 -64
- package/src/server/ssr-wrappers.tsx +2 -2
- package/src/server/static-generator.ts +7 -42
- package/src/server/static-not-found.ts +3 -3
- package/src/server/stream-utils.ts +51 -0
- package/src/server/tracing.ts +58 -75
- package/src/server/types.ts +1 -1
- package/src/server/version-skew.ts +5 -5
- package/src/shared/csrf-reject.ts +15 -0
- package/src/shared/error-digest.ts +46 -0
- package/src/shared/payload-root.ts +11 -10
- package/src/shared/rsc-payload-path.ts +8 -1
- package/src/utils/write-file-atomic.ts +32 -0
- package/dist/_chunks/actions-jNrXdzgs.js +0 -346
- package/dist/_chunks/actions-jNrXdzgs.js.map +0 -1
- package/dist/_chunks/als-registry-C6kcfprT.js.map +0 -1
- package/dist/_chunks/build-manifest-DTmSGLRz.js.map +0 -1
- package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +0 -1
- package/dist/_chunks/cache-api-CUD9Ezaq.js.map +0 -1
- package/dist/_chunks/cli-check-G8o30ldg.js.map +0 -1
- package/dist/_chunks/convention-lint-5KzoMg_A.js.map +0 -1
- package/dist/_chunks/dev-server-BzBxgYAV.js.map +0 -1
- package/dist/_chunks/error-boundary-BndF-3Td.js.map +0 -1
- package/dist/_chunks/fs-identity-D7vb6GdI.js.map +0 -1
- package/dist/_chunks/graph-cache-CP4GEmf9.js.map +0 -1
- package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +0 -1
- package/dist/_chunks/logger-k2DQ4EUf.js.map +0 -1
- package/dist/_chunks/navigation-context-D0TU0Jog.js.map +0 -1
- package/dist/_chunks/plugin-context-8idfR3UZ.js.map +0 -1
- package/dist/_chunks/primitives-DLAnvsrk.js.map +0 -1
- package/dist/_chunks/segment-context-D9_89u34.js +0 -34
- package/dist/_chunks/segment-context-D9_89u34.js.map +0 -1
- package/dist/_chunks/sizeof-lXffQ1Vr.js.map +0 -1
- package/dist/_chunks/ssr-data-D6T6Y3ef.js +0 -60
- package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +0 -1
- package/dist/_chunks/state-FippDgxN.js.map +0 -1
- package/dist/_chunks/status-page-marker-DwQBrLBz.js.map +0 -1
- package/dist/client/types.d.ts +0 -14
- package/dist/client/types.d.ts.map +0 -1
- package/dist/plugins/adapter-build.d.ts +0 -38
- package/dist/plugins/adapter-build.d.ts.map +0 -1
- package/dist/server/asset-headers.d.ts +0 -32
- package/dist/server/asset-headers.d.ts.map +0 -1
- package/dist/server/dev-source-map.d.ts +0 -22
- package/dist/server/dev-source-map.d.ts.map +0 -1
- package/src/client/types.ts +0 -21
- package/src/server/asset-headers.ts +0 -59
- package/src/server/dev-source-map.ts +0 -31
package/src/server/pipeline.ts
CHANGED
|
@@ -55,15 +55,19 @@ import { isDebug } from './debug.ts';
|
|
|
55
55
|
export interface RouteMatch {
|
|
56
56
|
/** The matched segment chain from root to leaf. */
|
|
57
57
|
segments: ManifestSegmentNode[];
|
|
58
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Segment params as the page sees them. The matcher sets them to the raw
|
|
60
|
+
* values; whoever runs `coerceSegmentParams()` replaces them with its
|
|
61
|
+
* result, whose values may be non-string (TIM-1347).
|
|
62
|
+
*/
|
|
59
63
|
segmentParams: CoercedParams;
|
|
60
64
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
+
* Segment params as the URL carried them (catch-all segments produce
|
|
66
|
+
* string[]). Set by the matcher, which owns them, and never replaced.
|
|
67
|
+
* Slot resolution and URL-part reconstruction read these: coerced values
|
|
68
|
+
* need not round-trip to the URL (`"007"` → `7`).
|
|
65
69
|
*/
|
|
66
|
-
rawSegmentParams
|
|
70
|
+
rawSegmentParams: Record<string, string | string[]>;
|
|
67
71
|
/** Middleware chain from the segment tree, ordered root-to-leaf. */
|
|
68
72
|
middlewareChain: MiddlewareFn[];
|
|
69
73
|
}
|
|
@@ -87,7 +91,6 @@ export type RouteRenderer = (
|
|
|
87
91
|
req: Request,
|
|
88
92
|
match: RouteMatch,
|
|
89
93
|
responseHeaders: Headers,
|
|
90
|
-
requestHeaderOverlay: Headers,
|
|
91
94
|
interception?: InterceptionContext
|
|
92
95
|
) => Response | Promise<Response>;
|
|
93
96
|
|
|
@@ -184,33 +187,6 @@ export interface PipelineConfig {
|
|
|
184
187
|
*/
|
|
185
188
|
onPipelineError?: (error: Error, phase: string) => void;
|
|
186
189
|
|
|
187
|
-
/**
|
|
188
|
-
* Dev error handler with RSC debug context — set by the dev server after
|
|
189
|
-
* the RSC entry module is imported. `onPipelineError` resolves debug
|
|
190
|
-
* components from ALS and delegates to this handler.
|
|
191
|
-
*
|
|
192
|
-
* This is a mutable property (not a constructor argument) because the dev
|
|
193
|
-
* server imports the RSC entry module first (which constructs the config),
|
|
194
|
-
* then wires in the overlay handler. Moving the state here (from a
|
|
195
|
-
* module-level `let`) keeps it co-located with the config it belongs to
|
|
196
|
-
* and makes it visible in tests without module-level mutation.
|
|
197
|
-
*
|
|
198
|
-
* Undefined in production — zero overhead.
|
|
199
|
-
*/
|
|
200
|
-
devPipelineErrorHandler?: (error: Error, phase: string) => void;
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* HMR connection options for dev-only HTML pages (dev 404 page, fallback
|
|
204
|
-
* error page) — set by the dev server after the RSC entry module is
|
|
205
|
-
* imported, like `devPipelineErrorHandler`. The RSC environment can't
|
|
206
|
-
* read the Vite server config (separate module graph), so the dev server
|
|
207
|
-
* plumbs the resolved HMR endpoint (protocol/host/port/path/token) here
|
|
208
|
-
* for the pages' auto-reload WebSocket. See TIM-1067.
|
|
209
|
-
*
|
|
210
|
-
* Undefined in production — zero overhead.
|
|
211
|
-
*/
|
|
212
|
-
devHmrOptions?: import('../dev-tools/dev-page-shell.ts').DevErrorHmrOptions;
|
|
213
|
-
|
|
214
190
|
/**
|
|
215
191
|
* Fallback error renderer — called when a catastrophic error escapes the
|
|
216
192
|
* render phase. Produces an HTML Response instead of a bare empty 500.
|
|
@@ -225,7 +201,13 @@ export interface PipelineConfig {
|
|
|
225
201
|
renderFallbackError?: (
|
|
226
202
|
error: unknown,
|
|
227
203
|
req: Request,
|
|
228
|
-
responseHeaders: Headers
|
|
204
|
+
responseHeaders: Headers,
|
|
205
|
+
/**
|
|
206
|
+
* The matched route, when the error came after matching. A route.ts
|
|
207
|
+
* match is answered in the API route's JSON format, never a page
|
|
208
|
+
* (design/10-error-handling.md §"JSON Error Pages").
|
|
209
|
+
*/
|
|
210
|
+
match?: RouteMatch
|
|
229
211
|
) => Response | Promise<Response>;
|
|
230
212
|
/**
|
|
231
213
|
* Fallback deny page renderer — called when a DenySignal escapes from
|
|
@@ -261,7 +243,10 @@ export interface PipelineConfig {
|
|
|
261
243
|
*
|
|
262
244
|
* The `reenter` parameter is the full pipeline function (including proxy,
|
|
263
245
|
* ALS, tracing) for the no-JS validation rerender path — the synthetic
|
|
264
|
-
* GET flows through the complete pipeline.
|
|
246
|
+
* GET flows through the complete pipeline. Its `cookies` argument becomes
|
|
247
|
+
* that request's parsed cookies (`runWithRequestContext`'s `cookies`
|
|
248
|
+
* option), so the rerender reads the action's post-mutation state without
|
|
249
|
+
* the pipeline needing the same `Request` object to reach it.
|
|
265
250
|
*
|
|
266
251
|
* Moved into the pipeline (TIM-1213) so proxy.ts runs on action POSTs,
|
|
267
252
|
* matching the design doc contract: "proxy.ts runs on every request,
|
|
@@ -270,7 +255,7 @@ export interface PipelineConfig {
|
|
|
270
255
|
dispatchAction?: (
|
|
271
256
|
req: Request,
|
|
272
257
|
canonicalPath: string,
|
|
273
|
-
reenter: (req: Request) => Promise<Response>
|
|
258
|
+
reenter: (req: Request, cookies: Map<string, string>) => Promise<Response>
|
|
274
259
|
) => Promise<Response | null>;
|
|
275
260
|
}
|
|
276
261
|
|
|
@@ -303,12 +288,11 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
303
288
|
// passes a synthetic GET back through the full pipeline (including
|
|
304
289
|
// proxy, ALS, tracing). The inner closure captures `pipelineFn` by
|
|
305
290
|
// name; by the time it's invoked, the const binding is initialized.
|
|
306
|
-
const pipelineFn = async (req: Request): Promise<Response> => {
|
|
291
|
+
const pipelineFn = async (req: Request, cookies?: Map<string, string>): Promise<Response> => {
|
|
307
292
|
const url = new URL(req.url);
|
|
308
293
|
const method = req.method;
|
|
309
294
|
const path = url.pathname;
|
|
310
295
|
const startTime = performance.now();
|
|
311
|
-
activeRequests++;
|
|
312
296
|
|
|
313
297
|
// Establish per-request trace ID scope (design/17-logging.md §"trace_id is Always Set").
|
|
314
298
|
// This runs before runWithRequestContext so traceId() is available from the
|
|
@@ -316,194 +300,206 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
316
300
|
const traceIdValue = generateTraceId();
|
|
317
301
|
|
|
318
302
|
return runWithTraceId(traceIdValue, async () => {
|
|
319
|
-
//
|
|
320
|
-
// throughout the entire request lifecycle (proxy, middleware, render).
|
|
321
|
-
|
|
303
|
+
// Runs in the request context ALS scope, so getHeaders() and getCookies()
|
|
304
|
+
// work throughout the entire request lifecycle (proxy, middleware, render).
|
|
305
|
+
const inRequestContext = async () => {
|
|
322
306
|
// In dev mode, wrap with timing collector for Server-Timing header.
|
|
323
307
|
// The collector uses ALS so timing entries are per-request.
|
|
324
308
|
const runRequest = async () => {
|
|
325
309
|
logRequestReceived({ method, path });
|
|
326
310
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
311
|
+
// Incremented and decremented in one scope, the decrement in
|
|
312
|
+
// `finally`: a rejection that escaped the span used to skip it and
|
|
313
|
+
// leave the request counted as in flight for the life of the
|
|
314
|
+
// process (TIM-1537).
|
|
315
|
+
activeRequests++;
|
|
316
|
+
let concurrency = activeRequests;
|
|
317
|
+
let response: Response;
|
|
318
|
+
try {
|
|
319
|
+
response = await withSpan(
|
|
320
|
+
'http.server.request',
|
|
321
|
+
{ 'http.request.method': method, 'url.path': path },
|
|
322
|
+
async () => {
|
|
323
|
+
// If OTEL is active, the root span now exists — replace the UUID
|
|
324
|
+
// fallback with the real OTEL trace ID for log–trace correlation.
|
|
325
|
+
const otelTraceId = await getOtelTraceId();
|
|
326
|
+
if (otelTraceId) {
|
|
327
|
+
replaceTraceId(otelTraceId);
|
|
328
|
+
}
|
|
337
329
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
330
|
+
// Stage 0: Canonicalize URL at the outer boundary — before
|
|
331
|
+
// proxy.ts sees the request. Every layer (proxy, middleware,
|
|
332
|
+
// access, render) must see the same canonical path.
|
|
333
|
+
// See design/07-routing.md §"URL Canonicalization & Security".
|
|
334
|
+
const stripTrailingSlash = config.stripTrailingSlash ?? true;
|
|
335
|
+
const canonResult = canonicalize(url.pathname, stripTrailingSlash);
|
|
336
|
+
if (!canonResult.ok) {
|
|
337
|
+
if (isDebug()) {
|
|
338
|
+
console.warn(
|
|
339
|
+
`[timber] URL canonicalization rejected ${method} ${url.pathname} — responding with ${canonResult.status}\n` +
|
|
340
|
+
` This usually means the URL contains encoded separators (%2f, %5c),\n` +
|
|
341
|
+
` null bytes (%00), path traversal (..), or malformed percent-encoding.`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return new Response(null, { status: canonResult.status });
|
|
345
|
+
}
|
|
346
|
+
const canonicalPath = canonResult.pathname;
|
|
347
|
+
|
|
348
|
+
// Construct a Request with the canonical URL so proxy.ts sees
|
|
349
|
+
// the same path that route matching will use. This prevents
|
|
350
|
+
// auth bypass via /admin/, /%61dmin, etc.
|
|
351
|
+
let canonicalReq = req;
|
|
352
|
+
if (url.pathname !== canonicalPath) {
|
|
353
|
+
const canonicalUrl = new URL(req.url);
|
|
354
|
+
canonicalUrl.pathname = canonicalPath;
|
|
355
|
+
canonicalReq = new Request(canonicalUrl.toString(), req);
|
|
351
356
|
}
|
|
352
|
-
return new Response(null, { status: canonResult.status });
|
|
353
|
-
}
|
|
354
|
-
const canonicalPath = canonResult.pathname;
|
|
355
|
-
|
|
356
|
-
// Construct a Request with the canonical URL so proxy.ts sees
|
|
357
|
-
// the same path that route matching will use. This prevents
|
|
358
|
-
// auth bypass via /admin/, /%61dmin, etc.
|
|
359
|
-
let canonicalReq = req;
|
|
360
|
-
if (url.pathname !== canonicalPath) {
|
|
361
|
-
const canonicalUrl = new URL(req.url);
|
|
362
|
-
canonicalUrl.pathname = canonicalPath;
|
|
363
|
-
canonicalReq = new Request(canonicalUrl.toString(), req);
|
|
364
|
-
}
|
|
365
357
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
358
|
+
// Build the inner handler — runs after proxy, before route
|
|
359
|
+
// matching. Checks for server action POSTs and dispatches them
|
|
360
|
+
// without entering the route match → middleware → render chain.
|
|
361
|
+
// Falls through to handleRequest for normal route handling.
|
|
362
|
+
// TIM-1213: action dispatch is now INSIDE the pipeline so
|
|
363
|
+
// proxy.ts runs on every request, including action POSTs.
|
|
364
|
+
const innerHandler = async (): Promise<Response> => {
|
|
365
|
+
if (config.dispatchAction) {
|
|
366
|
+
const actionResult = await config.dispatchAction(
|
|
367
|
+
canonicalReq,
|
|
368
|
+
canonicalPath,
|
|
369
|
+
pipelineFn
|
|
370
|
+
);
|
|
371
|
+
if (actionResult) return actionResult;
|
|
372
|
+
}
|
|
373
|
+
return handleRequest(config, canonicalReq, method, canonicalPath, true);
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
let result: Response;
|
|
377
|
+
if (proxyResolver) {
|
|
378
|
+
const outcome = await runProxyPhase(
|
|
379
|
+
config,
|
|
380
|
+
proxyResolver,
|
|
375
381
|
canonicalReq,
|
|
382
|
+
method,
|
|
376
383
|
canonicalPath,
|
|
377
|
-
|
|
384
|
+
innerHandler
|
|
378
385
|
);
|
|
379
|
-
|
|
386
|
+
result = await outcomeToResponse(config, outcome, {
|
|
387
|
+
req: canonicalReq,
|
|
388
|
+
method,
|
|
389
|
+
path: canonicalPath,
|
|
390
|
+
});
|
|
391
|
+
} else {
|
|
392
|
+
result = await innerHandler();
|
|
380
393
|
}
|
|
381
|
-
return handleRequest(config, canonicalReq, method, canonicalPath, true);
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
let result: Response;
|
|
385
|
-
if (proxyResolver) {
|
|
386
|
-
const outcome = await runProxyPhase(
|
|
387
|
-
config,
|
|
388
|
-
proxyResolver,
|
|
389
|
-
canonicalReq,
|
|
390
|
-
method,
|
|
391
|
-
canonicalPath,
|
|
392
|
-
innerHandler
|
|
393
|
-
);
|
|
394
|
-
result = await outcomeToResponse(config, outcome, {
|
|
395
|
-
req: canonicalReq,
|
|
396
|
-
method,
|
|
397
|
-
path: canonicalPath,
|
|
398
|
-
});
|
|
399
|
-
} else {
|
|
400
|
-
result = await innerHandler();
|
|
401
|
-
}
|
|
402
394
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
result.headers.set(
|
|
441
|
-
'Vary',
|
|
442
|
-
existingVary ? `${existingVary}, ${newTokens.join(', ')}` : newTokens.join(', ')
|
|
395
|
+
// Set response status on the root span before it ends —
|
|
396
|
+
// DevSpanProcessor reads this for tree/summary output.
|
|
397
|
+
await setSpanAttribute('http.response.status_code', result.status);
|
|
398
|
+
|
|
399
|
+
// Vary on exactly the headers the `_rsc` cache key hashes.
|
|
400
|
+
//
|
|
401
|
+
// Those two mechanisms answer the same question — which request
|
|
402
|
+
// headers change this response — so they are the same list, not
|
|
403
|
+
// two lists that happen to agree. A separate hand-written list
|
|
404
|
+
// here drifted from `RSC_KEY_HEADERS` the moment the key set
|
|
405
|
+
// grew, and the drift is invisible: `Vary` is the *fallback*
|
|
406
|
+
// layer, used only when a cache omits the query from its key,
|
|
407
|
+
// which is precisely when nobody is watching (TIM-1268).
|
|
408
|
+
//
|
|
409
|
+
// Why any of it: without `Vary: Accept` a shared cache may serve
|
|
410
|
+
// an RSC Flight payload to a browser expecting HTML, or the
|
|
411
|
+
// reverse (GHSA-wfc6-r584-vfw7, design/13-security.md). The
|
|
412
|
+
// `_rsc` param puts that distinction in the URL, so correctness
|
|
413
|
+
// no longer *depends* on `Vary` — which is opt-in configuration
|
|
414
|
+
// on Cloudflare and CloudFront. `Vary` covers the requests that
|
|
415
|
+
// arrive without the param: a stripped query, a hand-rolled
|
|
416
|
+
// client.
|
|
417
|
+
//
|
|
418
|
+
// It costs no hit rate. Document requests send no `X-Timber-*`
|
|
419
|
+
// header at all, so they collapse to a single cache key; payload
|
|
420
|
+
// requests are already fragmented by these same values via the
|
|
421
|
+
// URL.
|
|
422
|
+
const varyTokens = [...RSC_KEY_HEADERS];
|
|
423
|
+
const existingVary = result.headers.get('Vary');
|
|
424
|
+
const existingTokens = existingVary
|
|
425
|
+
? existingVary
|
|
426
|
+
.toLowerCase()
|
|
427
|
+
.split(',')
|
|
428
|
+
.map((t) => t.trim())
|
|
429
|
+
: [];
|
|
430
|
+
const newTokens = varyTokens.filter(
|
|
431
|
+
(t) => !existingTokens.includes(t.toLowerCase())
|
|
443
432
|
);
|
|
444
|
-
|
|
433
|
+
if (newTokens.length > 0) {
|
|
434
|
+
result.headers.set(
|
|
435
|
+
'Vary',
|
|
436
|
+
existingVary ? `${existingVary}, ${newTokens.join(', ')}` : newTokens.join(', ')
|
|
437
|
+
);
|
|
438
|
+
}
|
|
445
439
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
440
|
+
// A request may only claim an `_rsc` cache key that matches its
|
|
441
|
+
// own headers. The key is predictable by design, so without this
|
|
442
|
+
// a caller could render its own variant under another client's
|
|
443
|
+
// key and have a shared cache store it there (TIM-1268).
|
|
444
|
+
await enforceRscCacheKey(canonicalReq, result);
|
|
445
|
+
|
|
446
|
+
// Flight payloads must never be sniffable into a renderable
|
|
447
|
+
// type — applied at this single exit so every producer is
|
|
448
|
+
// covered, not just the success path (TIM-1268).
|
|
449
|
+
hardenRscPayloadResponse(result);
|
|
450
|
+
|
|
451
|
+
// A HEAD response carries the headers its GET would produce and
|
|
452
|
+
// no content (RFC 9110 §9.3.2). Applied at this single exit so
|
|
453
|
+
// every response shape is covered — page render, API route,
|
|
454
|
+
// metadata route, deny page, error page, proxy short-circuit —
|
|
455
|
+
// rather than per-renderer, where it was missing for page
|
|
456
|
+
// renders entirely (TIM-1324). The render still runs: the
|
|
457
|
+
// headers have to be the ones a GET would have sent.
|
|
458
|
+
result = stripHeadBody(result, method);
|
|
459
|
+
|
|
460
|
+
// Append Server-Timing header based on configured mode.
|
|
461
|
+
// Header mutability is guaranteed by the producer-side clone
|
|
462
|
+
// in `outcomeToResponse` and the metadata-route / auto-sitemap
|
|
463
|
+
// user-handler clones in `handleRequest`, so we can write
|
|
464
|
+
// directly without a runtime probe. See TIM-866.
|
|
465
|
+
if (serverTiming === 'detailed') {
|
|
466
|
+
// Detailed: per-phase breakdown (proxy, middleware, render).
|
|
467
|
+
const timingHeader = getServerTimingHeader();
|
|
468
|
+
if (timingHeader) {
|
|
469
|
+
result.headers.set('Server-Timing', timingHeader);
|
|
470
|
+
}
|
|
471
|
+
} else if (serverTiming === 'total') {
|
|
472
|
+
// Total only: single `total;dur=N` — no phase names.
|
|
473
|
+
// Prevents information disclosure while giving browser
|
|
474
|
+
// DevTools useful timing data.
|
|
475
|
+
const totalMs = Math.round(performance.now() - startTime);
|
|
476
|
+
result.headers.set('Server-Timing', `total;dur=${totalMs}`);
|
|
477
|
+
}
|
|
478
|
+
// serverTiming === false: no header at all
|
|
479
|
+
|
|
480
|
+
// Wrap the response body with stream-lifecycle timing when
|
|
481
|
+
// detailed mode is on. Logs firstChunk/lastChunk/maxGap/close
|
|
482
|
+
// on stream close — measures the post-flush stream tail that
|
|
483
|
+
// the Server-Timing header can't capture (TIM-1106).
|
|
484
|
+
if (serverTiming === 'detailed' && result.body) {
|
|
485
|
+
result = new Response(wrapResponseWithStreamTiming(result.body, startTime), {
|
|
486
|
+
status: result.status,
|
|
487
|
+
statusText: result.statusText,
|
|
488
|
+
headers: result.headers,
|
|
489
|
+
});
|
|
476
490
|
}
|
|
477
|
-
} else if (serverTiming === 'total') {
|
|
478
|
-
// Total only: single `total;dur=N` — no phase names.
|
|
479
|
-
// Prevents information disclosure while giving browser
|
|
480
|
-
// DevTools useful timing data.
|
|
481
|
-
const totalMs = Math.round(performance.now() - startTime);
|
|
482
|
-
result.headers.set('Server-Timing', `total;dur=${totalMs}`);
|
|
483
|
-
}
|
|
484
|
-
// serverTiming === false: no header at all
|
|
485
|
-
|
|
486
|
-
// Wrap the response body with stream-lifecycle timing when
|
|
487
|
-
// detailed mode is on. Logs firstChunk/lastChunk/maxGap/close
|
|
488
|
-
// on stream close — measures the post-flush stream tail that
|
|
489
|
-
// the Server-Timing header can't capture (TIM-1106).
|
|
490
|
-
if (serverTiming === 'detailed' && result.body) {
|
|
491
|
-
result = new Response(wrapResponseWithStreamTiming(result.body, startTime), {
|
|
492
|
-
status: result.status,
|
|
493
|
-
statusText: result.statusText,
|
|
494
|
-
headers: result.headers,
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
491
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
492
|
+
return result;
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
} finally {
|
|
496
|
+
concurrency = activeRequests;
|
|
497
|
+
activeRequests--;
|
|
498
|
+
}
|
|
501
499
|
|
|
502
500
|
// Post-span: structured production logging
|
|
503
501
|
const durationMs = Math.round(performance.now() - startTime);
|
|
504
502
|
const status = response.status;
|
|
505
|
-
const concurrency = activeRequests;
|
|
506
|
-
activeRequests--;
|
|
507
503
|
logRequestCompleted({ method, path, status, durationMs, concurrency });
|
|
508
504
|
|
|
509
505
|
if (slowRequestMs > 0 && durationMs > slowRequestMs) {
|
|
@@ -514,7 +510,8 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
514
510
|
};
|
|
515
511
|
|
|
516
512
|
return serverTiming === 'detailed' ? runWithTimingCollector(runRequest) : runRequest();
|
|
517
|
-
}
|
|
513
|
+
};
|
|
514
|
+
return runWithRequestContext(req, inRequestContext, { cookies });
|
|
518
515
|
});
|
|
519
516
|
};
|
|
520
517
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One build-time capture entry (server/prebuilt-builder.ts): render a
|
|
3
|
+
* registered component in isolation under the synthetic build store and
|
|
4
|
+
* drain its flight payload under a deadline.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createElement } from 'react';
|
|
8
|
+
|
|
9
|
+
import { SlotOutlet } from '../../client/slot-outlet.tsx';
|
|
10
|
+
import type { CoercedParams } from '../../shared/param-value.ts';
|
|
11
|
+
import { renderToReadableStream } from '../../rsc-runtime/rsc.ts';
|
|
12
|
+
import { requestContextAls } from '../als-registry.ts';
|
|
13
|
+
import { readAllBytesWithDeadline } from '../stream-utils.ts';
|
|
14
|
+
import type { PrebuiltRegistration } from '../prebuilt-runtime.ts';
|
|
15
|
+
import { createCaptureScope, type NestedWrapperRender } from './capture-state.ts';
|
|
16
|
+
import { resolveTags } from './lifetime.ts';
|
|
17
|
+
import { LAYOUT_CHILDREN_SLOT } from './slots.ts';
|
|
18
|
+
import { createBuildTimeStore } from './synthetic-store.ts';
|
|
19
|
+
|
|
20
|
+
/** Wrap payload bytes as a single-chunk stream for the smoke revival. */
|
|
21
|
+
export function bytesToStream(bytes: Uint8Array): ReadableStream<Uint8Array> {
|
|
22
|
+
return new ReadableStream({
|
|
23
|
+
start(c) {
|
|
24
|
+
c.enqueue(bytes);
|
|
25
|
+
c.close();
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* View of a registered component that satisfies createElement — same
|
|
32
|
+
* narrowing rationale as prebuilt-runtime.ts.
|
|
33
|
+
*/
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
type RenderableComponent = (props: any) => React.ReactNode;
|
|
36
|
+
|
|
37
|
+
export interface EntryOutcome {
|
|
38
|
+
bytes: Uint8Array | null;
|
|
39
|
+
failure: unknown;
|
|
40
|
+
nested: NestedWrapperRender[];
|
|
41
|
+
resolvedTags: string[] | undefined;
|
|
42
|
+
segmentParamsRead: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Render one (component, props, coerced-params) entry in isolation and drain
|
|
47
|
+
* its flight payload. Any `onError` during serialization fails the entry —
|
|
48
|
+
* a payload with an embedded error row would replay that error on every
|
|
49
|
+
* future request, so only fully clean renders are captured.
|
|
50
|
+
*/
|
|
51
|
+
export async function renderEntry(
|
|
52
|
+
registration: PrebuiltRegistration,
|
|
53
|
+
props: Record<string, unknown>,
|
|
54
|
+
coercedParams: CoercedParams,
|
|
55
|
+
timeoutMs: number,
|
|
56
|
+
isLayout: boolean
|
|
57
|
+
): Promise<EntryOutcome> {
|
|
58
|
+
const storeHandle = createBuildTimeStore(registration.id, coercedParams);
|
|
59
|
+
const { store, violations } = storeHandle;
|
|
60
|
+
let failure: unknown = null;
|
|
61
|
+
|
|
62
|
+
const capture = createCaptureScope(registration.id, registration.options, props);
|
|
63
|
+
let bytes: Uint8Array | null = null;
|
|
64
|
+
let resolvedTags: string[] | undefined;
|
|
65
|
+
try {
|
|
66
|
+
// Render AND drain inside one ALS scope. Flight renders in the context
|
|
67
|
+
// it was started from (and pinged from), not the one that pulls the
|
|
68
|
+
// stream, so the render itself only needs the scope at creation; the
|
|
69
|
+
// drain sits inside it too so everything in this capture reads the
|
|
70
|
+
// synthetic store (segmentParams.get() inside the component).
|
|
71
|
+
// Tag resolution also runs inside this scope so function-form tags
|
|
72
|
+
// that read segment params see the synthetic store (codex P2 on PR #858).
|
|
73
|
+
// Layout captures get <SlotOutlet slot="children" /> as children so
|
|
74
|
+
// the cached payload has a context-driven hole (design/45, TIM-1181).
|
|
75
|
+
const renderProps =
|
|
76
|
+
isLayout && !('children' in props)
|
|
77
|
+
? { ...props, children: createElement(SlotOutlet, { slot: LAYOUT_CHILDREN_SLOT }) }
|
|
78
|
+
: props;
|
|
79
|
+
// The capture scope wraps the render the same way, so every wrapper
|
|
80
|
+
// inside it reports to this entry (cycle + nesting clamp).
|
|
81
|
+
bytes = await capture.run(() =>
|
|
82
|
+
requestContextAls.run(store, async () => {
|
|
83
|
+
const stream = renderToReadableStream(
|
|
84
|
+
createElement(registration.component as RenderableComponent, renderProps),
|
|
85
|
+
{
|
|
86
|
+
onError(error: unknown) {
|
|
87
|
+
failure ??= error ?? new Error('unknown render error');
|
|
88
|
+
// Digest string keeps flight from warning about a missing
|
|
89
|
+
// digest; the payload is discarded because `failure` is set.
|
|
90
|
+
return 'timber-prebuilt-capture-error';
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
// On timeout the reader is cancelled, never abandoned mid-read
|
|
95
|
+
// (design/13 A2/A3), and the entry fails.
|
|
96
|
+
const drained = await readAllBytesWithDeadline(stream, timeoutMs, 'render');
|
|
97
|
+
const tags = resolveTags(registration.options, props);
|
|
98
|
+
resolvedTags = tags.length > 0 ? tags : undefined;
|
|
99
|
+
return drained;
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// Sync component throw (renderToReadableStream creation), drain
|
|
104
|
+
// timeout, or stream error.
|
|
105
|
+
failure ??= error;
|
|
106
|
+
}
|
|
107
|
+
const nested = capture.nestedRenders();
|
|
108
|
+
|
|
109
|
+
// Side-channel check FIRST: a component that touched per-request context
|
|
110
|
+
// is a hard error even when it caught the throw and rendered a fallback —
|
|
111
|
+
// accepting that payload would bake the request-dependent branch for
|
|
112
|
+
// every future request (codex P1 on PR #836).
|
|
113
|
+
const { segmentParamsRead } = storeHandle;
|
|
114
|
+
if (violations.length > 0)
|
|
115
|
+
return { bytes: null, failure: violations[0], nested, resolvedTags, segmentParamsRead };
|
|
116
|
+
if (failure !== null) return { bytes: null, failure, nested, resolvedTags, segmentParamsRead };
|
|
117
|
+
return { bytes, failure: null, nested, resolvedTags, segmentParamsRead };
|
|
118
|
+
}
|