@timber-js/app 0.2.0-alpha.208 → 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-BrHmG-2X.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-CNbpUOPB.js → status-page-marker-gaihi0KZ.js} +53 -20
- 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 +12 -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 +68 -104
- package/dist/client/internal.js.map +1 -1
- package/dist/client/navigation-commit.d.ts +16 -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 +1 -6
- 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/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 +531 -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/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 +5 -1
- 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 +18 -21
- package/src/client/index.ts +0 -1
- package/src/client/internal.ts +2 -7
- package/src/client/navigation-commit.ts +35 -18
- package/src/client/navigation-context.ts +3 -39
- package/src/client/react-root.ts +3 -2
- package/src/client/router-pipeline.ts +65 -128
- package/src/client/router-types.ts +46 -44
- package/src/client/router-url.ts +32 -0
- package/src/client/router.ts +43 -22
- package/src/client/rsc-fetch.ts +117 -155
- 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 +24 -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/{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-BrHmG-2X.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-CNbpUOPB.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/actions.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Server action primitives: revalidatePath, revalidateTag, and the action handler.
|
|
3
3
|
*
|
|
4
4
|
* - revalidatePath(path) re-renders the route at that path and returns the RSC
|
|
5
|
-
* flight payload for inline reconciliation.
|
|
6
|
-
* - revalidateTag(tag) invalidates timber.cache entries by tag.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* flight payload for inline reconciliation. Server actions only.
|
|
6
|
+
* - revalidateTag(tag) invalidates timber.cache entries by tag. Callable from
|
|
7
|
+
* any server code: deferred to the end of the action inside one, immediate
|
|
8
|
+
* anywhere else.
|
|
9
9
|
*
|
|
10
10
|
* The action handler processes incoming action requests, validates CSRF,
|
|
11
11
|
* enforces body limits, executes the action, and returns the response
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { cache } from '../cache/cache-api.ts';
|
|
18
18
|
import { canonicalize } from './canonicalize.ts';
|
|
19
|
-
import { isDenySignal, isRedirectSignal } from './
|
|
19
|
+
import { isDenySignal, isRedirectSignal } from './signal-identity.ts';
|
|
20
20
|
import { withSpan } from './tracing.ts';
|
|
21
21
|
import { revalidationAls, type RevalidationState } from './als-registry.ts';
|
|
22
|
+
import type { ReactCacheScope } from './react-cache-scope.ts';
|
|
22
23
|
// ─── Types ───────────────────────────────────────────────────────────────
|
|
23
24
|
|
|
24
25
|
/** Result of rendering a revalidation — payload root before RSC serialization. */
|
|
@@ -28,11 +29,33 @@ export interface RevalidationResult {
|
|
|
28
29
|
* ordinary route payload. The client splits it in `applyActionResult`.
|
|
29
30
|
*/
|
|
30
31
|
payload: unknown;
|
|
32
|
+
/**
|
|
33
|
+
* The `React.cache` scope the target route's middleware ran in. The
|
|
34
|
+
* revalidated tree renders in it, so middleware, access.ts and components
|
|
35
|
+
* share one scope — fresh, never the action body's (TIM-1529).
|
|
36
|
+
*/
|
|
37
|
+
reactCacheScope: ReactCacheScope;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
/** Renderer function that builds a React element tree for a given path. */
|
|
34
41
|
export type RevalidateRenderer = (path: string) => Promise<RevalidationResult>;
|
|
35
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Thrown by a `RevalidateRenderer` that decided not to render: the path
|
|
45
|
+
* was rejected, its params failed coercion, or its middleware answered
|
|
46
|
+
* with a `Response` that cannot become an element tree. `executeAction`
|
|
47
|
+
* drops the revalidation — the action result is still delivered, with no
|
|
48
|
+
* `_tree` piggybacked — and, because the drop was a decision, does not
|
|
49
|
+
* return it as an error to report. Identified by `instanceof`, so the
|
|
50
|
+
* message text never reaches clients.
|
|
51
|
+
*/
|
|
52
|
+
export class RevalidationDropped extends Error {
|
|
53
|
+
constructor(message: string) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = 'RevalidationDropped';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
36
59
|
// Re-export the type from the registry for public API consumers.
|
|
37
60
|
export type { RevalidationState } from './als-registry.ts';
|
|
38
61
|
|
|
@@ -67,6 +90,14 @@ export interface ActionHandlerResult {
|
|
|
67
90
|
redirectTo?: string;
|
|
68
91
|
/** Redirect status code. */
|
|
69
92
|
redirectStatus?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Errors the action survived after its body returned: a `revalidateTag`
|
|
95
|
+
* invalidation that rejected, or a `revalidatePath` render that threw.
|
|
96
|
+
* Each is already logged. They are returned rather than reported here
|
|
97
|
+
* because reporting needs the request, which the caller owns; the caller
|
|
98
|
+
* passes each to `onRequestError` once.
|
|
99
|
+
*/
|
|
100
|
+
revalidationErrors: unknown[];
|
|
70
101
|
}
|
|
71
102
|
|
|
72
103
|
// ─── Revalidation State ──────────────────────────────────────────────────
|
|
@@ -83,49 +114,56 @@ export function _runWithRevalidationState<T>(state: RevalidationState, fn: () =>
|
|
|
83
114
|
return revalidationAls.run(state, fn);
|
|
84
115
|
}
|
|
85
116
|
|
|
86
|
-
/**
|
|
87
|
-
* Get the current revalidation state. Throws if called outside an action context.
|
|
88
|
-
* @internal
|
|
89
|
-
*/
|
|
90
|
-
function getRevalidationState(): RevalidationState {
|
|
91
|
-
const state = revalidationAls.getStore();
|
|
92
|
-
if (!state) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
'revalidatePath/revalidateTag called outside of a server action context. ' +
|
|
95
|
-
'These functions can only be called during action execution.'
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
return state;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
117
|
// ─── Public API ──────────────────────────────────────────────────────────
|
|
102
118
|
|
|
103
119
|
/**
|
|
104
120
|
* Re-render the route at `path` and include the RSC flight payload in the
|
|
105
121
|
* action response. The client reconciles inline — no separate fetch needed.
|
|
106
122
|
*
|
|
107
|
-
*
|
|
123
|
+
* Only callable inside a server action: it attaches a render to the action
|
|
124
|
+
* response, and nothing else has one. To refresh cached data from a
|
|
125
|
+
* `route.ts` handler, a webhook, or a job, use `revalidateTag()` or
|
|
126
|
+
* `cache.invalidate()`.
|
|
108
127
|
*
|
|
109
128
|
* @param path - The path to re-render (e.g. '/dashboard', '/todos').
|
|
110
129
|
*/
|
|
111
130
|
export function revalidatePath(path: string): void {
|
|
112
|
-
const state =
|
|
131
|
+
const state = revalidationAls.getStore();
|
|
132
|
+
if (!state || state.closed) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
'revalidatePath() can only be called inside a server action: it re-renders ' +
|
|
135
|
+
'the route into the action response, and there is no action response here. ' +
|
|
136
|
+
'To refresh cached data from a route handler or other server code, call ' +
|
|
137
|
+
'revalidateTag() or cache.invalidate() for the tags the route reads.'
|
|
138
|
+
);
|
|
139
|
+
}
|
|
113
140
|
if (!state.paths.includes(path)) {
|
|
114
141
|
state.paths.push(path);
|
|
115
142
|
}
|
|
116
143
|
}
|
|
117
144
|
|
|
118
145
|
/**
|
|
119
|
-
* Invalidate all timber.cache entries tagged with `tag
|
|
146
|
+
* Invalidate all timber.cache entries tagged with `tag`, and tombstone the
|
|
147
|
+
* pre-rendered component seeds that carry it.
|
|
120
148
|
* Does not return a payload — the next request for an invalidated entry re-executes.
|
|
121
149
|
*
|
|
150
|
+
* Callable from any server code. Inside a server action the invalidation is
|
|
151
|
+
* deferred until the action body returns, so a `revalidatePath()` render in
|
|
152
|
+
* the same action reads fresh data; the returned promise resolves at once.
|
|
153
|
+
* Anywhere else — a `route.ts` webhook, a job, or background work an action
|
|
154
|
+
* started that runs after the action body returned — it is
|
|
155
|
+
* `cache.invalidate({ tag })`, and the promise settles when the invalidation
|
|
156
|
+
* has. Await it before responding.
|
|
157
|
+
*
|
|
122
158
|
* @param tag - The cache tag to invalidate (e.g. 'products', 'user:123').
|
|
123
159
|
*/
|
|
124
|
-
export function revalidateTag(tag: string): void {
|
|
125
|
-
const state =
|
|
160
|
+
export function revalidateTag(tag: string): Promise<void> {
|
|
161
|
+
const state = revalidationAls.getStore();
|
|
162
|
+
if (!state || state.closed) return cache.invalidate({ tag });
|
|
126
163
|
if (!state.tags.includes(tag)) {
|
|
127
164
|
state.tags.push(tag);
|
|
128
165
|
}
|
|
166
|
+
return Promise.resolve();
|
|
129
167
|
}
|
|
130
168
|
|
|
131
169
|
// ─── Helpers ────────────────────────────────────────────────────────────
|
|
@@ -157,6 +195,7 @@ export async function executeAction(
|
|
|
157
195
|
spanMeta?: { actionFile?: string; actionName?: string }
|
|
158
196
|
): Promise<ActionHandlerResult> {
|
|
159
197
|
const state: RevalidationState = { paths: [], tags: [] };
|
|
198
|
+
const revalidationErrors: unknown[] = [];
|
|
160
199
|
let actionResult: unknown;
|
|
161
200
|
let redirectTo: string | undefined;
|
|
162
201
|
let redirectStatus: number | undefined;
|
|
@@ -180,6 +219,10 @@ export async function executeAction(
|
|
|
180
219
|
} else {
|
|
181
220
|
throw error;
|
|
182
221
|
}
|
|
222
|
+
} finally {
|
|
223
|
+
// From here `paths` and `tags` are snapshotted below (or abandoned on
|
|
224
|
+
// a throw); later calls from un-awaited work must not queue into them.
|
|
225
|
+
state.closed = true;
|
|
183
226
|
}
|
|
184
227
|
});
|
|
185
228
|
|
|
@@ -201,6 +244,7 @@ export async function executeAction(
|
|
|
201
244
|
for (const r of results) {
|
|
202
245
|
if (r.status === 'rejected') {
|
|
203
246
|
console.error('[timber] revalidateTag invalidation failed:', r.reason);
|
|
247
|
+
revalidationErrors.push(r.reason);
|
|
204
248
|
}
|
|
205
249
|
}
|
|
206
250
|
}
|
|
@@ -232,8 +276,11 @@ export async function executeAction(
|
|
|
232
276
|
console.error(
|
|
233
277
|
`[timber] revalidatePath dropped — target middleware denied (status ${renderError.status})`
|
|
234
278
|
);
|
|
279
|
+
} else if (renderError instanceof RevalidationDropped) {
|
|
280
|
+
console.error(`[timber] ${renderError.message}`);
|
|
235
281
|
} else {
|
|
236
282
|
console.error('[timber] revalidatePath render failed:', renderError);
|
|
283
|
+
revalidationErrors.push(renderError);
|
|
237
284
|
}
|
|
238
285
|
}
|
|
239
286
|
}
|
|
@@ -243,6 +290,7 @@ export async function executeAction(
|
|
|
243
290
|
actionResult,
|
|
244
291
|
revalidation,
|
|
245
292
|
invalidatedPaths,
|
|
293
|
+
revalidationErrors,
|
|
246
294
|
...(redirectTo ? { redirectTo, redirectStatus } : {}),
|
|
247
295
|
};
|
|
248
296
|
}
|
|
@@ -66,6 +66,14 @@ export const requestContextAls = getOrCreateAls<RequestContextStore>(
|
|
|
66
66
|
);
|
|
67
67
|
|
|
68
68
|
export interface RequestContextStore {
|
|
69
|
+
/**
|
|
70
|
+
* The request this context was opened for, or `null` in the build-time
|
|
71
|
+
* capture store, where there is none. Read only to report a failed
|
|
72
|
+
* `cache.component` background re-render, which outlives the code that had the request
|
|
73
|
+
* in hand (design/17 §"Which errors reach it"). Everything a page may read
|
|
74
|
+
* has its own field below.
|
|
75
|
+
*/
|
|
76
|
+
request: Request | null;
|
|
69
77
|
/** Incoming request headers (read-only view). */
|
|
70
78
|
headers: Headers;
|
|
71
79
|
/** Raw cookie header string, parsed lazily into a Map on first access. */
|
|
@@ -167,16 +175,26 @@ export interface CookieEntry {
|
|
|
167
175
|
// Used by: tracing.ts (getTraceId(), getSpanId())
|
|
168
176
|
// Design doc: design/17-logging.md
|
|
169
177
|
|
|
178
|
+
/**
|
|
179
|
+
* One trace scope. The pipeline opens the request's scope; withSpan() opens a
|
|
180
|
+
* copy per span, so the span pointers below always name the span the code is
|
|
181
|
+
* running in, however sibling spans interleave (TIM-1538).
|
|
182
|
+
*/
|
|
170
183
|
export interface TraceStore {
|
|
171
|
-
/**
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
/**
|
|
185
|
+
* The request's trace, shared by reference by every span scope in it.
|
|
186
|
+
* `traceId` is the 32-char lowercase hex trace ID (OTEL or UUID fallback);
|
|
187
|
+
* replaceTraceId() swaps it from inside the first span, and code outside
|
|
188
|
+
* that span (the request's completion log) sees the swap.
|
|
189
|
+
*/
|
|
190
|
+
request: { traceId: string };
|
|
191
|
+
/** The enclosing OTEL span's ID if an SDK is active, undefined otherwise. */
|
|
174
192
|
spanId?: string;
|
|
175
193
|
/**
|
|
176
|
-
*
|
|
194
|
+
* The enclosing native platform span (e.g. Cloudflare's `Span` from
|
|
177
195
|
* tracing.enterSpan()). Tracked so setSpanAttribute() can set attributes
|
|
178
196
|
* after span creation — the platform API has no getActiveSpan() equivalent.
|
|
179
|
-
*
|
|
197
|
+
* See TIM-1135.
|
|
180
198
|
*/
|
|
181
199
|
platformSpan?: import('./tracing.ts').PlatformSpan;
|
|
182
200
|
}
|
|
@@ -204,6 +222,13 @@ export interface RevalidationState {
|
|
|
204
222
|
paths: string[];
|
|
205
223
|
/** Tags to invalidate (populated by revalidateTag calls). */
|
|
206
224
|
tags: string[];
|
|
225
|
+
/**
|
|
226
|
+
* Set once the action body has settled. ALS still hands this state to
|
|
227
|
+
* work the action started and did not await (a `waitUntil()` job), but
|
|
228
|
+
* `paths` and `tags` are no longer read, so a late `revalidateTag` must
|
|
229
|
+
* invalidate immediately instead of queueing into a list nobody drains.
|
|
230
|
+
*/
|
|
231
|
+
closed?: boolean;
|
|
207
232
|
}
|
|
208
233
|
|
|
209
234
|
/** @internal — import via actions.ts public API */
|
|
@@ -255,3 +280,46 @@ export interface WorkersCachePurgeCtx {
|
|
|
255
280
|
export const workersCachePurgeAls = getOrCreateAls<WorkersCachePurgeCtx>(
|
|
256
281
|
Symbol.for('timber:workers-cache-purge-als')
|
|
257
282
|
);
|
|
283
|
+
|
|
284
|
+
// ─── React.cache Scope ───────────────────────────────────────────────────
|
|
285
|
+
// Used by: react-cache-bridge.ts (runWithReactCacheScope(), the patched
|
|
286
|
+
// getCacheForType on Flight's dispatcher)
|
|
287
|
+
// Design doc: design/02-rendering-pipeline.md §"Cache Scoping Model"
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* One request's `React.cache` storage — the Map React's `cache()` hands to
|
|
291
|
+
* `getCacheForType`, owned by timber instead of by a Flight `Request` so
|
|
292
|
+
* `middleware.ts`, `proxy.ts`, and route handlers share it with the render.
|
|
293
|
+
*/
|
|
294
|
+
export type ReactCacheScope = Map<() => unknown, unknown>;
|
|
295
|
+
|
|
296
|
+
/** @internal — import via react-cache-bridge.ts public API */
|
|
297
|
+
export const reactCacheScopeAls = getOrCreateAls<ReactCacheScope>(
|
|
298
|
+
Symbol.for('timber:react-cache-scope-als')
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
// ─── Prebuilt Capture ────────────────────────────────────────────────────
|
|
302
|
+
// Used by: prebuilt/capture-state.ts (createCaptureScope(), noteWrapperRender())
|
|
303
|
+
// Design doc: design/45-cache-lifetimes.md §Nesting Semantics
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* One in-flight `cache.component` payload capture — a build-time entry or
|
|
307
|
+
* a request-time re-render. Scoped to the capture's async context so a
|
|
308
|
+
* concurrent request's render does not observe it.
|
|
309
|
+
*/
|
|
310
|
+
export interface PrebuiltCaptureStore {
|
|
311
|
+
/** The component being captured. */
|
|
312
|
+
outerId: string;
|
|
313
|
+
/**
|
|
314
|
+
* Props half of the captured entry's cache key (null when unkeyable).
|
|
315
|
+
* Rendering `outerId` again with this key is a cycle (TIM-1547).
|
|
316
|
+
*/
|
|
317
|
+
outerPropsKey: string | null;
|
|
318
|
+
/** Wrapped components that rendered inside this capture, by component id. */
|
|
319
|
+
nested: Map<string, import('./prebuilt/capture-state.ts').NestedRecord>;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** @internal — import via prebuilt/capture-state.ts */
|
|
323
|
+
export const prebuiltCaptureAls = getOrCreateAls<PrebuiltCaptureStore>(
|
|
324
|
+
Symbol.for('timber:prebuilt-capture-als')
|
|
325
|
+
);
|
|
@@ -129,7 +129,7 @@ export function consumedUrlParts(
|
|
|
129
129
|
index: number,
|
|
130
130
|
match: RouteMatch
|
|
131
131
|
): string[] {
|
|
132
|
-
const rawParams = match.rawSegmentParams
|
|
132
|
+
const rawParams = match.rawSegmentParams;
|
|
133
133
|
const partsThrough = (from: number, to: number) =>
|
|
134
134
|
extractUrlParts(segments.slice(from, to + 1), rawParams);
|
|
135
135
|
|
|
@@ -77,7 +77,8 @@ export function createInterceptedRouteMatcher(root: ManifestSegmentNode): Interc
|
|
|
77
77
|
// `validateInterceptionPlacement` rejects a dynamic one at build time,
|
|
78
78
|
// precisely because the intercepted URL carries no value to bind it
|
|
79
79
|
// with. So the intercepting subtree's params are the whole record.
|
|
80
|
-
|
|
80
|
+
rawSegmentParams: result.slotParams,
|
|
81
|
+
segmentParams: { ...result.slotParams },
|
|
81
82
|
middlewareChain: collectMiddlewareChain(segments),
|
|
82
83
|
};
|
|
83
84
|
};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Cookie Context — per-request cookie API and on-the-wire helpers.
|
|
3
3
|
*
|
|
4
4
|
* Split out of `request-context.ts` (TIM-853) so the cookie subsystem
|
|
5
|
-
* — encoding contract, options grammar, parser, serializer, RYW map
|
|
6
|
-
*
|
|
5
|
+
* — encoding contract, options grammar, parser, serializer, and RYW map
|
|
6
|
+
* — lives in one file. The headers/scope/params APIs
|
|
7
7
|
* stay in `request-context.ts` and call into this module via the
|
|
8
8
|
* exported helpers.
|
|
9
9
|
*
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
import { requestContextAls, type RequestContextStore } from './als-registry.ts';
|
|
16
16
|
import { isDebug } from './debug.ts';
|
|
17
|
+
import {
|
|
18
|
+
ANY_COOKIE,
|
|
19
|
+
noteCookieReadForReactCache,
|
|
20
|
+
warnIfCachedCookieIsWritten,
|
|
21
|
+
} from './react-cache-scope.ts';
|
|
17
22
|
import {
|
|
18
23
|
assertValidCookieName,
|
|
19
24
|
assertValidCookieValue,
|
|
@@ -69,16 +74,22 @@ export function getCookieJar(): RequestCookies {
|
|
|
69
74
|
|
|
70
75
|
const map = store.parsedCookies;
|
|
71
76
|
return {
|
|
77
|
+
// Reads are noted (dev only) so a later write of the same cookie can
|
|
78
|
+
// warn if React.cache may have memoized the old value (TIM-1529 D3).
|
|
72
79
|
get(name: string): string | undefined {
|
|
80
|
+
noteCookieReadForReactCache(name);
|
|
73
81
|
return map.get(name);
|
|
74
82
|
},
|
|
75
83
|
has(name: string): boolean {
|
|
84
|
+
noteCookieReadForReactCache(name);
|
|
76
85
|
return map.has(name);
|
|
77
86
|
},
|
|
78
87
|
getAll(): Array<{ name: string; value: string }> {
|
|
88
|
+
noteCookieReadForReactCache(ANY_COOKIE);
|
|
79
89
|
return Array.from(map.entries()).map(([name, value]) => ({ name, value }));
|
|
80
90
|
},
|
|
81
91
|
get size(): number {
|
|
92
|
+
noteCookieReadForReactCache(ANY_COOKIE);
|
|
82
93
|
return map.size;
|
|
83
94
|
},
|
|
84
95
|
|
|
@@ -148,6 +159,7 @@ export function getCookieJar(): RequestCookies {
|
|
|
148
159
|
// exactly what the developer wrote — never the encoded form.
|
|
149
160
|
// For `{ raw: true }`, the wire form IS the logical form.
|
|
150
161
|
map.set(name, raw ? wireValue : value);
|
|
162
|
+
warnIfCachedCookieIsWritten(name);
|
|
151
163
|
},
|
|
152
164
|
|
|
153
165
|
setFromHeaders(headers: Headers): void {
|
|
@@ -203,6 +215,7 @@ export function getCookieJar(): RequestCookies {
|
|
|
203
215
|
store.cookieJar.set(name, { name, value: '', options: opts });
|
|
204
216
|
// Remove from read view
|
|
205
217
|
map.delete(name);
|
|
218
|
+
warnIfCachedCookieIsWritten(name);
|
|
206
219
|
},
|
|
207
220
|
|
|
208
221
|
clear(): void {
|
|
@@ -217,9 +230,11 @@ export function getCookieJar(): RequestCookies {
|
|
|
217
230
|
});
|
|
218
231
|
}
|
|
219
232
|
map.clear();
|
|
233
|
+
warnIfCachedCookieIsWritten(ANY_COOKIE);
|
|
220
234
|
},
|
|
221
235
|
|
|
222
236
|
toString(): string {
|
|
237
|
+
noteCookieReadForReactCache(ANY_COOKIE);
|
|
223
238
|
// Re-encode values when serializing as a Cookie header — the
|
|
224
239
|
// RYW map holds decoded logical values, but a Cookie header has
|
|
225
240
|
// to satisfy `cookie-octet`. Mirror the auto-encode contract on
|
|
@@ -341,52 +356,6 @@ const DEFAULT_COOKIE_OPTIONS: CookieOptions = {
|
|
|
341
356
|
|
|
342
357
|
// ─── Framework-Internal Helpers ───────────────────────────────────────────
|
|
343
358
|
|
|
344
|
-
/**
|
|
345
|
-
* Per-request seed map of cookie name → value, registered out-of-band so the
|
|
346
|
-
* pipeline's `runWithRequestContext` call can pick it up without changing
|
|
347
|
-
* the function's calling convention. Stored in a WeakMap keyed by the
|
|
348
|
-
* synthetic Request object built for the rerender path, so the seed lives
|
|
349
|
-
* exactly as long as the request and is collected with it.
|
|
350
|
-
*
|
|
351
|
-
* The seed exists to eliminate the parse/serialize round-trip on the no-JS
|
|
352
|
-
* form-rerender path — see ONGOING_SECURITY.md H-3 (TIM-868). The action's
|
|
353
|
-
* post-mutation RYW snapshot is threaded directly into the rerender scope's
|
|
354
|
-
* `parsedCookies` map, bypassing `parseCookieHeader` entirely.
|
|
355
|
-
*/
|
|
356
|
-
const seededRequestCookies = new WeakMap<Request, Map<string, string>>();
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Register a pre-parsed cookie map to use as the request context seed for
|
|
360
|
-
* the next `runWithRequestContext(req, …)` call with this exact `req`.
|
|
361
|
-
*
|
|
362
|
-
* Used by the no-JS form-rerender dispatcher in
|
|
363
|
-
* `rsc-entry/wrap-action-dispatch.ts` to thread the action's post-mutation
|
|
364
|
-
* cookie state into the rerender scope without serializing back through a
|
|
365
|
-
* `Cookie:` header. See TIM-868 / TIM-837.
|
|
366
|
-
*
|
|
367
|
-
* @internal — framework use only.
|
|
368
|
-
*/
|
|
369
|
-
export function seedRequestCookies(req: Request, cookies: Map<string, string>): void {
|
|
370
|
-
// Defensive copy: callers must not be able to mutate the rerender scope's
|
|
371
|
-
// map after seeding, and the rerender scope must not mutate the snapshot
|
|
372
|
-
// we hand back to other observers.
|
|
373
|
-
seededRequestCookies.set(req, new Map(cookies));
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Pop the seed (if any) for `req` and return it. Called from
|
|
378
|
-
* `runWithRequestContext` exactly once per request — the seed is consumed
|
|
379
|
-
* eagerly so it cannot leak into a hypothetical future re-use of the same
|
|
380
|
-
* Request reference.
|
|
381
|
-
*
|
|
382
|
-
* @internal — framework use only.
|
|
383
|
-
*/
|
|
384
|
-
export function consumeSeededCookies(req: Request): Map<string, string> | undefined {
|
|
385
|
-
const seed = seededRequestCookies.get(req);
|
|
386
|
-
if (seed) seededRequestCookies.delete(req);
|
|
387
|
-
return seed;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
359
|
/**
|
|
391
360
|
* Build a Map of cookie name → value reflecting the current request's
|
|
392
361
|
* read-your-own-writes state. Includes incoming cookies plus any
|
|
@@ -472,6 +441,7 @@ function setRaw(
|
|
|
472
441
|
// the caller. See design/29-cookies.md §"Cookie Attribute Validation".
|
|
473
442
|
assertValidCookieOptions(options);
|
|
474
443
|
store.cookieJar.set(name, { name, value, options });
|
|
444
|
+
warnIfCachedCookieIsWritten(name);
|
|
475
445
|
// Deletion cookies (Max-Age=0) should not appear in the read map.
|
|
476
446
|
if (options.maxAge === 0) {
|
|
477
447
|
readMap.delete(name);
|
package/src/server/csp-nonce.ts
CHANGED
|
@@ -56,15 +56,3 @@ export function requestCspNonce(): string {
|
|
|
56
56
|
export function getCspNonce(): string | undefined {
|
|
57
57
|
return requestContextAls.getStore()?.cspNonce;
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The ` nonce="…"` attribute fragment for a timber-generated `<script>` tag,
|
|
62
|
-
* or `''` when the request has no nonce. Callers interpolate it directly
|
|
63
|
-
* after the tag name: `` `<script${nonceAttr(nonce)}>` ``.
|
|
64
|
-
*
|
|
65
|
-
* The value comes from `generateNonce` and is base64, so no attribute
|
|
66
|
-
* escaping is required.
|
|
67
|
-
*/
|
|
68
|
-
export function nonceAttr(nonce: string | undefined): string {
|
|
69
|
-
return nonce ? ` nonce="${nonce}"` : '';
|
|
70
|
-
}
|
package/src/server/csrf.ts
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* See design/13-security.md §"Security Testing Checklist" #6
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { logCsrfRejected } from './logger.ts';
|
|
13
|
+
import { CSRF_REJECT_HEADER, CSRF_REJECT_VALUE } from '../shared/csrf-reject.ts';
|
|
14
|
+
|
|
12
15
|
// ─── Types ────────────────────────────────────────────────────────────────
|
|
13
16
|
|
|
14
17
|
export interface CsrfConfig {
|
|
@@ -18,7 +21,31 @@ export interface CsrfConfig {
|
|
|
18
21
|
csrf?: boolean;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
/** Why a request failed the Origin check — one value per rejection path. */
|
|
25
|
+
export type CsrfRejectReason =
|
|
26
|
+
| 'missing-origin'
|
|
27
|
+
| 'origin-not-allowed'
|
|
28
|
+
| 'missing-host'
|
|
29
|
+
| 'invalid-host'
|
|
30
|
+
| 'invalid-origin'
|
|
31
|
+
| 'origin-mismatch';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A failed Origin check. `origin` is the request's Origin header (null when
|
|
35
|
+
* absent); `expected` is the origin(s) it was compared against — the
|
|
36
|
+
* `allowedOrigins` list, or the one origin derived from the Host header.
|
|
37
|
+
* `expected` is empty when the check failed before an expected origin could
|
|
38
|
+
* be determined. Both are for the server log only — never the response.
|
|
39
|
+
*/
|
|
40
|
+
export interface CsrfRejection {
|
|
41
|
+
ok: false;
|
|
42
|
+
status: 403;
|
|
43
|
+
reason: CsrfRejectReason;
|
|
44
|
+
origin: string | null;
|
|
45
|
+
expected: readonly string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type CsrfResult = { ok: true } | CsrfRejection;
|
|
22
49
|
|
|
23
50
|
// ─── Constants ────────────────────────────────────────────────────────────
|
|
24
51
|
|
|
@@ -76,19 +103,20 @@ export function validateCsrf(req: Request, config: CsrfConfig): CsrfResult {
|
|
|
76
103
|
|
|
77
104
|
// No Origin header on a mutation → reject
|
|
78
105
|
if (!origin) {
|
|
79
|
-
return
|
|
106
|
+
return reject('missing-origin', null, []);
|
|
80
107
|
}
|
|
81
108
|
|
|
82
109
|
// If allowedOrigins is configured, use that instead of Host-based derivation
|
|
83
110
|
if (config.allowedOrigins) {
|
|
84
|
-
|
|
85
|
-
|
|
111
|
+
return config.allowedOrigins.includes(origin)
|
|
112
|
+
? { ok: true }
|
|
113
|
+
: reject('origin-not-allowed', origin, config.allowedOrigins);
|
|
86
114
|
}
|
|
87
115
|
|
|
88
116
|
// Auto-derive from Host header
|
|
89
117
|
const host = req.headers.get('Host');
|
|
90
118
|
if (!host) {
|
|
91
|
-
return
|
|
119
|
+
return reject('missing-host', origin, []);
|
|
92
120
|
}
|
|
93
121
|
|
|
94
122
|
// Compare full origins (scheme + host + port) using URL.origin for
|
|
@@ -97,7 +125,7 @@ export function validateCsrf(req: Request, config: CsrfConfig): CsrfResult {
|
|
|
97
125
|
try {
|
|
98
126
|
originOrigin = new URL(origin).origin;
|
|
99
127
|
} catch {
|
|
100
|
-
return
|
|
128
|
+
return reject('invalid-origin', origin, []);
|
|
101
129
|
}
|
|
102
130
|
|
|
103
131
|
const scheme = deriveRequestScheme(req);
|
|
@@ -105,8 +133,112 @@ export function validateCsrf(req: Request, config: CsrfConfig): CsrfResult {
|
|
|
105
133
|
try {
|
|
106
134
|
expectedOrigin = new URL(`${scheme}://${host}`).origin;
|
|
107
135
|
} catch {
|
|
108
|
-
return
|
|
136
|
+
return reject('invalid-host', origin, []);
|
|
109
137
|
}
|
|
110
138
|
|
|
111
|
-
return originOrigin === expectedOrigin
|
|
139
|
+
return originOrigin === expectedOrigin
|
|
140
|
+
? { ok: true }
|
|
141
|
+
: reject('origin-mismatch', origin, [expectedOrigin]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function reject(
|
|
145
|
+
reason: CsrfRejectReason,
|
|
146
|
+
origin: string | null,
|
|
147
|
+
expected: readonly string[]
|
|
148
|
+
): CsrfRejection {
|
|
149
|
+
return { ok: false, status: 403, reason, origin, expected };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ─── Rejection Response// ─── Rejection Response ───────────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Longest request-derived value echoed into the server log. Origin, Host,
|
|
156
|
+
* and the path are attacker-controlled; a request can carry kilobytes in
|
|
157
|
+
* each, and every rejection writes a log line. Real values are far shorter.
|
|
158
|
+
*/
|
|
159
|
+
const MAX_LOGGED_VALUE = 200;
|
|
160
|
+
|
|
161
|
+
function clip(value: string): string {
|
|
162
|
+
return value.length > MAX_LOGGED_VALUE ? `${value.slice(0, MAX_LOGGED_VALUE)}…` : value;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Clip and quote a request-derived value for the log. JSON quoting escapes
|
|
167
|
+
* quotes and control characters, so a crafted header cannot close the quote
|
|
168
|
+
* and forge `key=value` fields or a second line.
|
|
169
|
+
*/
|
|
170
|
+
function quote(value: string): string {
|
|
171
|
+
return JSON.stringify(clip(value));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const PROXY_HINT =
|
|
175
|
+
'If the app runs behind a proxy that rewrites Host or terminates TLS, forward the ' +
|
|
176
|
+
'original Host and X-Forwarded-Proto, or list the public origin in allowedOrigins ' +
|
|
177
|
+
'in timber.config.ts.';
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Browsers send `Origin: null` from opaque contexts: sandboxed iframes, a POST
|
|
181
|
+
* redirected across origins, file: pages. Every such context shares the one
|
|
182
|
+
* value — an attacker's `<iframe sandbox>` included — so the hint must never
|
|
183
|
+
* suggest allowlisting it.
|
|
184
|
+
*/
|
|
185
|
+
const OPAQUE_ORIGIN_DETAIL =
|
|
186
|
+
'origin "null" is an opaque origin (sandboxed iframe, a POST redirected across ' +
|
|
187
|
+
'origins, or a file: page). Do not add "null" to allowedOrigins: every opaque ' +
|
|
188
|
+
"context sends it, including an attacker's sandboxed iframe.";
|
|
189
|
+
|
|
190
|
+
/** One sentence per rejection path: what was observed, and what to change. */
|
|
191
|
+
function describeRejection(r: CsrfRejection, host: string | null): string {
|
|
192
|
+
const opaque = r.origin === 'null';
|
|
193
|
+
const origin = quote(r.origin ?? '');
|
|
194
|
+
const expected = r.expected.map(quote).join(', ');
|
|
195
|
+
switch (r.reason) {
|
|
196
|
+
case 'missing-origin':
|
|
197
|
+
return (
|
|
198
|
+
'request has no Origin header. Browsers send Origin on fetch and form POSTs; ' +
|
|
199
|
+
'non-browser clients calling an unsafe method must set it.'
|
|
200
|
+
);
|
|
201
|
+
// The opaque-origin note replaces only the reasons where the origin
|
|
202
|
+
// itself is the fault. A null-origin request that fails for another
|
|
203
|
+
// reason (no Host, a bad Host) keeps that reason's diagnosis and hint.
|
|
204
|
+
case 'origin-not-allowed':
|
|
205
|
+
if (opaque) return OPAQUE_ORIGIN_DETAIL;
|
|
206
|
+
return (
|
|
207
|
+
`origin ${origin} is not in allowedOrigins [${expected}]. ` +
|
|
208
|
+
'If this origin is legitimate, add it to allowedOrigins in timber.config.ts.'
|
|
209
|
+
);
|
|
210
|
+
case 'missing-host':
|
|
211
|
+
return `origin ${origin} could not be checked: request has no Host header. ${PROXY_HINT}`;
|
|
212
|
+
case 'invalid-host':
|
|
213
|
+
return `origin ${origin} could not be checked: Host header ${quote(host ?? '')} is not a valid host. ${PROXY_HINT}`;
|
|
214
|
+
case 'invalid-origin':
|
|
215
|
+
if (opaque) return OPAQUE_ORIGIN_DETAIL;
|
|
216
|
+
return `Origin header ${origin} is not a valid origin.`;
|
|
217
|
+
case 'origin-mismatch':
|
|
218
|
+
return `origin ${origin} does not match the request origin ${expected}. ${PROXY_HINT}`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Turn a failed check into the response the client sees, and log why.
|
|
224
|
+
*
|
|
225
|
+
* The response is a 403 marked as a CSRF rejection (header + plain-text
|
|
226
|
+
* body) so it cannot be mistaken for an access-control 403. It never
|
|
227
|
+
* carries the observed or expected origins — `allowedOrigins` is server
|
|
228
|
+
* configuration, and a Host-derived origin can be an internal hostname
|
|
229
|
+
* behind a proxy. The server log gets the full diagnosis.
|
|
230
|
+
*/
|
|
231
|
+
export function csrfRejectionResponse(req: Request, rejection: CsrfRejection): Response {
|
|
232
|
+
logCsrfRejected(describeRejection(rejection, req.headers.get('Host')), {
|
|
233
|
+
method: req.method,
|
|
234
|
+
path: clip(new URL(req.url).pathname),
|
|
235
|
+
reason: rejection.reason,
|
|
236
|
+
});
|
|
237
|
+
return new Response('Forbidden: CSRF origin check failed\n', {
|
|
238
|
+
status: rejection.status,
|
|
239
|
+
headers: {
|
|
240
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
241
|
+
[CSRF_REJECT_HEADER]: CSRF_REJECT_VALUE,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
112
244
|
}
|
package/src/server/debug.ts
CHANGED
|
@@ -48,7 +48,6 @@
|
|
|
48
48
|
*
|
|
49
49
|
* This is the ONLY function that should gate client-visible dev behavior:
|
|
50
50
|
* - Dev error pages with stack traces
|
|
51
|
-
* - Server-Timing mode default (`'detailed'` in dev, `'total'` in prod)
|
|
52
51
|
* - Error messages in action `INTERNAL_ERROR` payloads
|
|
53
52
|
* - Pipeline error handler wiring (Vite overlay)
|
|
54
53
|
*
|