@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
|
@@ -20,12 +20,13 @@ import {
|
|
|
20
20
|
renderToReadableStream,
|
|
21
21
|
} from '../rsc-runtime/rsc.ts';
|
|
22
22
|
|
|
23
|
-
import { validateCsrf, type CsrfConfig } from './csrf.ts';
|
|
24
|
-
import { isDenySignal, isRedirectSignal } from './
|
|
23
|
+
import { validateCsrf, csrfRejectionResponse, type CsrfConfig } from './csrf.ts';
|
|
24
|
+
import { isDenySignal, isRedirectSignal } from './signal-identity.ts';
|
|
25
25
|
import { executeAction, type RevalidateRenderer } from './actions.ts';
|
|
26
26
|
import { runWithRequestContext, setMutableCookieContext } from './request-context.ts';
|
|
27
|
+
import { runOutsideReactCacheScope, runWithReactCacheScope } from './react-cache-scope.ts';
|
|
27
28
|
import { getSetCookieHeaders, getCookiesForSsr } from './cookie-context.ts';
|
|
28
|
-
import { handleActionError } from './action-client.ts';
|
|
29
|
+
import { ActionError, handleActionError } from './action-client.ts';
|
|
29
30
|
import { enforceBodyLimits, enforceFieldLimit, type BodyLimitsConfig } from './body-limits.ts';
|
|
30
31
|
import { parseFormData } from './form-data.ts';
|
|
31
32
|
import {
|
|
@@ -36,8 +37,9 @@ import {
|
|
|
36
37
|
} from './sensitive-fields.ts';
|
|
37
38
|
import type { FormFlashData } from './form-flash.ts';
|
|
38
39
|
import { checkVersionSkew, applyReloadHeaders } from './version-skew.ts';
|
|
39
|
-
import { logActionError } from './logger.ts';
|
|
40
|
-
import {
|
|
40
|
+
import { logActionError, swallow } from './logger.ts';
|
|
41
|
+
import { fireOnRequestError } from './pipeline-helpers.ts';
|
|
42
|
+
import { withTimeout, RenderTimeoutError, DEFAULT_RENDER_TIMEOUT_MS } from './render-timeout.ts';
|
|
41
43
|
import { canonicalize } from './canonicalize.ts';
|
|
42
44
|
import { RSC_CONTENT_TYPE } from '../shared/rsc-media-type.ts';
|
|
43
45
|
|
|
@@ -105,10 +107,11 @@ export function isActionRequest(req: Request): boolean {
|
|
|
105
107
|
*
|
|
106
108
|
* - `cookies`: the post-action read-your-own-writes view of the cookie
|
|
107
109
|
* jar, as the same `Map<string, string>` shape used by the request
|
|
108
|
-
* context's `parsedCookies`. The rerender dispatcher
|
|
109
|
-
*
|
|
110
|
-
* bypassing any string round-trip through a
|
|
111
|
-
*
|
|
110
|
+
* context's `parsedCookies`. The rerender dispatcher passes this map to
|
|
111
|
+
* the pipeline's re-entry, which makes it the rerender request
|
|
112
|
+
* context's cookies, bypassing any string round-trip through a
|
|
113
|
+
* `Cookie:` header. The
|
|
114
|
+
* direct Map eliminates the value-smuggling primitive that the
|
|
112
115
|
* previous `cookieHeader: string` shape carried — see
|
|
113
116
|
* ONGOING_SECURITY.md H-3 (TIM-868) and TIM-837.
|
|
114
117
|
*/
|
|
@@ -152,7 +155,7 @@ export async function handleActionRequest(
|
|
|
152
155
|
// future entry point that bypasses the wrapper. See LOCAL-773.
|
|
153
156
|
const csrfResult = validateCsrf(req, config.csrf);
|
|
154
157
|
if (!csrfResult.ok) {
|
|
155
|
-
return
|
|
158
|
+
return csrfRejectionResponse(req, csrfResult);
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
// Body size limits — reject oversized requests before parsing.
|
|
@@ -167,47 +170,174 @@ export async function handleActionRequest(
|
|
|
167
170
|
|
|
168
171
|
// Run inside request context so getHeaders(), getCookies() work in actions.
|
|
169
172
|
// Actions are a mutable context — they can set cookies (design/29-cookies.md).
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
173
|
+
//
|
|
174
|
+
// ...and outside any React.cache scope: dispatch runs inside the pipeline's
|
|
175
|
+
// request scope (after proxy.ts), and runWithRequestContext would open
|
|
176
|
+
// another. An action reads, writes cookies, and mutates, so a memoized read
|
|
177
|
+
// would go stale mid-action — React.cache in an action does not dedupe,
|
|
178
|
+
// same as stock React and Next.js (TIM-1529 D2). The revalidation render
|
|
179
|
+
// below re-enters its own fresh scope explicitly.
|
|
180
|
+
return runWithRequestContext(req, () =>
|
|
181
|
+
runOutsideReactCacheScope(async () => {
|
|
182
|
+
setMutableCookieContext(true);
|
|
183
|
+
const actionId = req.headers.get('x-rsc-action');
|
|
184
|
+
|
|
185
|
+
let result: Response | FormRerender | null;
|
|
186
|
+
if (actionId) {
|
|
187
|
+
// With-JS path: client sent action ID in header, args in body
|
|
188
|
+
result = await handleRscAction(req, actionId, config);
|
|
189
|
+
} else {
|
|
190
|
+
// No-JS path: form POST with React's hidden action fields
|
|
191
|
+
result = await handleFormAction(req, config);
|
|
192
|
+
}
|
|
182
193
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
// Apply cookie jar to action responses.
|
|
195
|
+
//
|
|
196
|
+
// For Response results we append Set-Cookie directly. For FormRerender
|
|
197
|
+
// signals we snapshot the headers here, before this ALS scope exits, so
|
|
198
|
+
// the caller can apply them to the rerender pipeline's response (which
|
|
199
|
+
// runs in its own request-context scope with a fresh cookie jar).
|
|
200
|
+
// See LOCAL-740 — without this snapshot, cookies set inside a no-JS
|
|
201
|
+
// form action that returns validation errors are silently dropped.
|
|
202
|
+
if (result instanceof Response) {
|
|
203
|
+
for (const value of getSetCookieHeaders()) {
|
|
204
|
+
result.headers.append('Set-Cookie', value);
|
|
205
|
+
}
|
|
206
|
+
} else if (result && 'rerender' in result) {
|
|
207
|
+
result.setCookieHeaders = getSetCookieHeaders();
|
|
208
|
+
// Snapshot the post-action RYW cookie state as a Map so the rerender
|
|
209
|
+
// dispatcher can hand it to the rerender request context directly,
|
|
210
|
+
// with no string round-trip. See TIM-837
|
|
211
|
+
// and ONGOING_SECURITY.md H-3 (TIM-868). `getCookiesForSsr` already
|
|
212
|
+
// returns a defensive copy, so the rerender scope cannot mutate the
|
|
213
|
+
// snapshot through this reference.
|
|
214
|
+
result.cookies = getCookiesForSsr();
|
|
194
215
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// dispatcher can seed it directly into the rerender request context
|
|
199
|
-
// via `seedRequestCookies`, with no string round-trip. See TIM-837
|
|
200
|
-
// and ONGOING_SECURITY.md H-3 (TIM-868). `getCookiesForSsr` already
|
|
201
|
-
// returns a defensive copy, so the rerender scope cannot mutate the
|
|
202
|
-
// snapshot through this reference.
|
|
203
|
-
result.cookies = getCookiesForSsr();
|
|
204
|
-
}
|
|
205
|
-
return result;
|
|
206
|
-
});
|
|
216
|
+
return result;
|
|
217
|
+
})
|
|
218
|
+
);
|
|
207
219
|
}
|
|
208
220
|
|
|
209
221
|
// ─── With-JS Action ───────────────────────────────────────────────────────
|
|
210
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Log an action error and report it to `onRequestError` as phase
|
|
225
|
+
* `'action'`. An `ActionError` is not reported: it is an outcome the
|
|
226
|
+
* action chose to return, not an unhandled error.
|
|
227
|
+
*/
|
|
228
|
+
async function reportActionError(req: Request, error: unknown): Promise<void> {
|
|
229
|
+
logActionError({ method: req.method, path: new URL(req.url).pathname, error });
|
|
230
|
+
if (error instanceof ActionError) return;
|
|
231
|
+
await fireOnRequestError(error, req, 'action');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Report errors the action survived after its body returned — from
|
|
236
|
+
* `executeAction`'s revalidation, or from serializing the revalidated tree.
|
|
237
|
+
* Each is logged where it was caught; this is its one `onRequestError`
|
|
238
|
+
* report, as phase `'action'`. Errors that are not reportable (a
|
|
239
|
+
* signal a revalidated page threw, an abort) and anything
|
|
240
|
+
* after the request aborted are skipped by the same rule as a page render.
|
|
241
|
+
*/
|
|
242
|
+
async function reportRevalidationErrors(req: Request, errors: readonly unknown[]): Promise<void> {
|
|
243
|
+
for (const error of errors) {
|
|
244
|
+
await fireOnRequestError(error, req, 'action').catch((hookError: unknown) =>
|
|
245
|
+
swallow(hookError, 'onRequestError could not be called')
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Answer an action request that failed before the action ran with a bare
|
|
252
|
+
* status, never a 200 action-error payload: a fabricated action id must not
|
|
253
|
+
* look like an action that ran (tests/e2e/security.test.ts). Either way it
|
|
254
|
+
* is logged and reported to `onRequestError` as phase `'action'` (TIM-1537).
|
|
255
|
+
*
|
|
256
|
+
* The status is chosen by what failed, not by matching error messages:
|
|
257
|
+
* - **400**: the request is wrong in a way the handler can see for itself.
|
|
258
|
+
* The body will not parse or decode, or the reference resolves to
|
|
259
|
+
* something that is not a function.
|
|
260
|
+
* - **500**: loading the action module failed. plugin-rsc rejects the same
|
|
261
|
+
* way for an unknown reference and for a real module that fails to import
|
|
262
|
+
* or evaluate, and the second is a server fault, so the load failure keeps
|
|
263
|
+
* the 5xx it had before this change. The no-JS path cannot make this
|
|
264
|
+
* split (`decodeAction` decodes and loads in one call) and answers 400;
|
|
265
|
+
* see `handleFormAction`.
|
|
266
|
+
*/
|
|
267
|
+
async function rejectActionRequest(
|
|
268
|
+
req: Request,
|
|
269
|
+
error: unknown,
|
|
270
|
+
status: 400 | 500
|
|
271
|
+
): Promise<Response> {
|
|
272
|
+
await reportActionError(req, error);
|
|
273
|
+
return new Response(null, { status });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The no-JS answer to an action error: re-render the page with the error as
|
|
278
|
+
* flash data. `handleActionError` produces `{ serverError }` for an
|
|
279
|
+
* ActionError and `{ serverError: { code: 'INTERNAL_ERROR' } }` otherwise.
|
|
280
|
+
*/
|
|
281
|
+
function errorRerender(error: unknown, submittedValues: Record<string, unknown>): FormRerender {
|
|
282
|
+
return {
|
|
283
|
+
rerender: { ...handleActionError(error), submittedValues },
|
|
284
|
+
// Filled in by handleActionRequest before the ALS scope exits.
|
|
285
|
+
setCookieHeaders: [],
|
|
286
|
+
cookies: new Map(),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Load the action by reference ID and decode its args from the request body
|
|
292
|
+
* (RSC wire format). Returns a Response for a request that fails before the
|
|
293
|
+
* action can run: see `rejectActionRequest` for the status, and the field
|
|
294
|
+
* limit for its own.
|
|
295
|
+
*/
|
|
296
|
+
async function decodeRscActionCall(
|
|
297
|
+
req: Request,
|
|
298
|
+
actionId: string,
|
|
299
|
+
config: ActionDispatchConfig
|
|
300
|
+
): Promise<{ actionFn: (...args: unknown[]) => Promise<unknown>; args: unknown[] } | Response> {
|
|
301
|
+
let loaded: unknown;
|
|
302
|
+
try {
|
|
303
|
+
loaded = await loadServerAction(actionId);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
return rejectActionRequest(req, error, 500);
|
|
306
|
+
}
|
|
307
|
+
if (typeof loaded !== 'function') {
|
|
308
|
+
// The module loaded but has no such export: a reference the client made up.
|
|
309
|
+
return rejectActionRequest(req, new Error(`Unknown server action "${actionId}"`), 400);
|
|
310
|
+
}
|
|
311
|
+
const actionFn = loaded as (...args: unknown[]) => Promise<unknown>;
|
|
312
|
+
|
|
313
|
+
let decoded: unknown;
|
|
314
|
+
try {
|
|
315
|
+
const contentType = req.headers.get('Content-Type') ?? '';
|
|
316
|
+
if (contentType.includes('multipart/form-data')) {
|
|
317
|
+
// FormData-based args (file uploads, etc.)
|
|
318
|
+
const formData = await req.formData();
|
|
319
|
+
// Enforce field count limit after parsing FormData.
|
|
320
|
+
const fieldResult = enforceFieldLimit(formData, config.bodyLimits ?? {});
|
|
321
|
+
if (!fieldResult.ok) {
|
|
322
|
+
return new Response(null, { status: fieldResult.status });
|
|
323
|
+
}
|
|
324
|
+
decoded = await decodeReply(formData);
|
|
325
|
+
} else {
|
|
326
|
+
// Text-based args
|
|
327
|
+
decoded = await decodeReply(await req.text());
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
return rejectActionRequest(req, error, 400);
|
|
331
|
+
}
|
|
332
|
+
// The client always encodes an argument list. Anything else would fail
|
|
333
|
+
// when `executeAction` spreads it, inside the action's own catch, and
|
|
334
|
+
// come back as a 200 INTERNAL_ERROR for what is the caller's mistake.
|
|
335
|
+
if (!Array.isArray(decoded)) {
|
|
336
|
+
return rejectActionRequest(req, new Error('Server action body is not an argument list'), 400);
|
|
337
|
+
}
|
|
338
|
+
return { actionFn, args: decoded };
|
|
339
|
+
}
|
|
340
|
+
|
|
211
341
|
/**
|
|
212
342
|
* Handle an RSC action request (JavaScript enabled).
|
|
213
343
|
*
|
|
@@ -219,27 +349,10 @@ async function handleRscAction(
|
|
|
219
349
|
actionId: string,
|
|
220
350
|
config: ActionDispatchConfig
|
|
221
351
|
): Promise<Response> {
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const contentType = req.headers.get('Content-Type') ?? '';
|
|
227
|
-
let args: unknown[];
|
|
228
|
-
|
|
229
|
-
if (contentType.includes('multipart/form-data')) {
|
|
230
|
-
// FormData-based args (file uploads, etc.)
|
|
231
|
-
const formData = await req.formData();
|
|
232
|
-
// Enforce field count limit after parsing FormData.
|
|
233
|
-
const fieldResult = enforceFieldLimit(formData, config.bodyLimits ?? {});
|
|
234
|
-
if (!fieldResult.ok) {
|
|
235
|
-
return new Response(null, { status: fieldResult.status });
|
|
236
|
-
}
|
|
237
|
-
args = (await decodeReply(formData)) as unknown[];
|
|
238
|
-
} else {
|
|
239
|
-
// Text-based args
|
|
240
|
-
const body = await req.text();
|
|
241
|
-
args = (await decodeReply(body)) as unknown[];
|
|
242
|
-
}
|
|
352
|
+
// A request that fails before the action runs is answered here, not a
|
|
353
|
+
// rejection that escapes into the pipeline (TIM-1537).
|
|
354
|
+
const call = await decodeRscActionCall(req, actionId, config);
|
|
355
|
+
if (call instanceof Response) return call;
|
|
243
356
|
|
|
244
357
|
// Execute the action with revalidation tracking.
|
|
245
358
|
// Errors are caught here so raw 'use server' functions (not using
|
|
@@ -251,14 +364,13 @@ async function handleRscAction(
|
|
|
251
364
|
// Canonicalize the request pathname so it matches the decoded form
|
|
252
365
|
// that revalidationPathMatches uses on the target side.
|
|
253
366
|
const canonical = canonicalize(requestUrl.pathname, true);
|
|
254
|
-
result = await executeAction(actionFn, args, {
|
|
367
|
+
result = await executeAction(call.actionFn, call.args, {
|
|
255
368
|
renderer: config.revalidateRenderer,
|
|
256
369
|
requestPathname: canonical.ok ? canonical.pathname : requestUrl.pathname,
|
|
257
370
|
requestSearch: requestUrl.search,
|
|
258
371
|
});
|
|
259
372
|
} catch (error) {
|
|
260
|
-
|
|
261
|
-
logActionError({ method: req.method, path: new URL(req.url).pathname, error });
|
|
373
|
+
await reportActionError(req, error);
|
|
262
374
|
|
|
263
375
|
// Return structured error response — ActionError gets its code/data,
|
|
264
376
|
// unexpected errors get sanitized { code: 'INTERNAL_ERROR' }
|
|
@@ -269,6 +381,9 @@ async function handleRscAction(
|
|
|
269
381
|
headers: { 'Content-Type': RSC_CONTENT_TYPE },
|
|
270
382
|
});
|
|
271
383
|
}
|
|
384
|
+
// Outside the try: the action succeeded, and a failure to report its
|
|
385
|
+
// revalidation must not turn it into an action error.
|
|
386
|
+
await reportRevalidationErrors(req, result.revalidationErrors);
|
|
272
387
|
|
|
273
388
|
// Handle redirect — encode in RSC stream for client-side SPA navigation.
|
|
274
389
|
// The client detects X-Timber-Redirect and calls router.navigate() instead
|
|
@@ -322,31 +437,46 @@ async function handleRscAction(
|
|
|
322
437
|
| { kind: 'redirect'; location: string; status: number }
|
|
323
438
|
| { kind: 'error' }
|
|
324
439
|
| undefined;
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
440
|
+
const serializationErrors: unknown[] = [];
|
|
441
|
+
//
|
|
442
|
+
// Rendered in the scope the revalidation middleware ran in, not this
|
|
443
|
+
// request context's: the action body read through that one before it
|
|
444
|
+
// mutated, and the revalidated tree must see post-mutation values
|
|
445
|
+
// (TIM-1529).
|
|
446
|
+
const rscStream = runWithReactCacheScope(
|
|
447
|
+
() =>
|
|
448
|
+
renderToReadableStream(revalidationPayload, {
|
|
449
|
+
signal: req.signal,
|
|
450
|
+
onError(error: unknown) {
|
|
451
|
+
// ??= keeps the first signal (shallowest AccessGate in top-down render).
|
|
452
|
+
if (isDenySignal(error)) {
|
|
453
|
+
serializationSignal ??= { kind: 'deny', status: error.status };
|
|
454
|
+
} else if (isRedirectSignal(error)) {
|
|
455
|
+
serializationSignal ??= {
|
|
456
|
+
kind: 'redirect',
|
|
457
|
+
location: error.location,
|
|
458
|
+
status: error.status,
|
|
459
|
+
};
|
|
460
|
+
} else {
|
|
461
|
+
console.error('[timber] revalidation serialization error:', error);
|
|
462
|
+
serializationErrors.push(error);
|
|
463
|
+
serializationSignal ??= { kind: 'error' };
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
}),
|
|
467
|
+
result.revalidation.reactCacheScope
|
|
468
|
+
);
|
|
343
469
|
|
|
344
470
|
// Drain the stream to detect any signals before committing the response.
|
|
345
471
|
// Timeout-guarded: the element tree may contain async server components
|
|
346
472
|
// with stalled fetches. 30s matches the default renderTimeoutMs.
|
|
473
|
+
// Not readAllBytesWithDeadline: this timeout is per read, not one
|
|
474
|
+
// overall deadline; the loop stops at the first chunk after onError
|
|
475
|
+
// records a signal (the payload is dropped then); and the catch below
|
|
476
|
+
// branches on RenderTimeoutError, which the helper does not throw.
|
|
347
477
|
const reader = rscStream.getReader();
|
|
348
478
|
const chunks: Uint8Array[] = [];
|
|
349
|
-
const drainTimeoutMs =
|
|
479
|
+
const drainTimeoutMs = DEFAULT_RENDER_TIMEOUT_MS;
|
|
350
480
|
try {
|
|
351
481
|
for (;;) {
|
|
352
482
|
const { done, value } = await withTimeout(
|
|
@@ -365,12 +495,17 @@ async function handleRscAction(
|
|
|
365
495
|
reader.cancel().catch(() => {});
|
|
366
496
|
if (drainError instanceof RenderTimeoutError) {
|
|
367
497
|
console.error('[timber] revalidatePath dropped — stream drain timed out');
|
|
498
|
+
// A revalidated tree that never finished rendering is a failure,
|
|
499
|
+
// even though the action result still ships.
|
|
500
|
+
await reportRevalidationErrors(req, [...serializationErrors, drainError]);
|
|
368
501
|
const fallbackStream = renderToReadableStream(result.actionResult);
|
|
369
502
|
return new Response(fallbackStream, { status: 200, headers });
|
|
370
503
|
}
|
|
504
|
+
await reportRevalidationErrors(req, serializationErrors);
|
|
371
505
|
throw drainError;
|
|
372
506
|
}
|
|
373
507
|
|
|
508
|
+
await reportRevalidationErrors(req, serializationErrors);
|
|
374
509
|
if (serializationSignal) {
|
|
375
510
|
if (serializationSignal.kind === 'redirect') {
|
|
376
511
|
const redirectPayload = {
|
|
@@ -399,7 +534,10 @@ async function handleRscAction(
|
|
|
399
534
|
// Clean serialization — return the buffered bytes with revalidation header.
|
|
400
535
|
headers['X-Timber-Revalidation'] = '1';
|
|
401
536
|
const buffered = concatUint8Arrays(chunks);
|
|
402
|
-
return new Response(buffered.buffer as ArrayBuffer, {
|
|
537
|
+
return new Response(buffered.buffer as ArrayBuffer, {
|
|
538
|
+
status: 200,
|
|
539
|
+
headers,
|
|
540
|
+
});
|
|
403
541
|
}
|
|
404
542
|
|
|
405
543
|
const rscStream = renderToReadableStream(result.actionResult);
|
|
@@ -440,7 +578,13 @@ async function handleFormAction(
|
|
|
440
578
|
// Clone before consuming — if this turns out not to be a server action form,
|
|
441
579
|
// we return null and the original request body must remain readable for
|
|
442
580
|
// downstream route handlers. Clone is cheap (shares the body buffer until read).
|
|
443
|
-
|
|
581
|
+
// A body that will not parse is a bad request (TIM-1537).
|
|
582
|
+
let formData: FormData;
|
|
583
|
+
try {
|
|
584
|
+
formData = await req.clone().formData();
|
|
585
|
+
} catch (error) {
|
|
586
|
+
return rejectActionRequest(req, error, 400);
|
|
587
|
+
}
|
|
444
588
|
|
|
445
589
|
// Enforce field count limit after parsing FormData.
|
|
446
590
|
const fieldResult = enforceFieldLimit(formData, config.bodyLimits ?? {});
|
|
@@ -461,37 +605,36 @@ async function handleFormAction(
|
|
|
461
605
|
// decodeAction resolves the action function from the form data's hidden fields.
|
|
462
606
|
// Returns null when no $ACTION_REF_/$ACTION_ID_ fields are present — meaning
|
|
463
607
|
// this is a regular form POST, not a React server action.
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
608
|
+
// Execute the action — no additional args needed (form data is already bound).
|
|
609
|
+
// Errors are caught to prevent stack traces from leaking in the response.
|
|
610
|
+
let actionFn: ((...args: unknown[]) => Promise<unknown>) | null;
|
|
611
|
+
try {
|
|
612
|
+
actionFn = (await decodeAction(formData)) as ((...args: unknown[]) => Promise<unknown>) | null;
|
|
613
|
+
} catch (error) {
|
|
614
|
+
// decodeAction both decodes the form's `$ACTION_REF_` metadata and loads
|
|
615
|
+
// the module, and React does not say which failed. On a no-JS POST that
|
|
616
|
+
// metadata is written by React into the form, so a failure is almost
|
|
617
|
+
// always a forged or truncated request: 400. A module that genuinely
|
|
618
|
+
// fails to import also breaks the RSC render of the page holding the
|
|
619
|
+
// form, which surfaces it as a 500 there.
|
|
620
|
+
return rejectActionRequest(req, error, 400);
|
|
621
|
+
}
|
|
467
622
|
if (!actionFn) {
|
|
468
623
|
return null;
|
|
469
624
|
}
|
|
470
625
|
|
|
471
|
-
// Execute the action — no additional args needed (form data is already bound).
|
|
472
|
-
// Errors are caught to prevent stack traces from leaking in the response.
|
|
473
626
|
let result;
|
|
474
627
|
try {
|
|
475
628
|
result = await executeAction(actionFn, [], {
|
|
476
629
|
renderer: config.revalidateRenderer,
|
|
477
630
|
});
|
|
478
631
|
} catch (error) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
// Return the error as flash data for re-render.
|
|
482
|
-
// handleActionError produces { serverError } for ActionErrors
|
|
483
|
-
// and { serverError: { code: 'INTERNAL_ERROR' } } for unexpected errors.
|
|
484
|
-
const errorResult = handleActionError(error);
|
|
485
|
-
return {
|
|
486
|
-
rerender: {
|
|
487
|
-
...errorResult,
|
|
488
|
-
submittedValues,
|
|
489
|
-
},
|
|
490
|
-
// Filled in by handleActionRequest before the ALS scope exits.
|
|
491
|
-
setCookieHeaders: [],
|
|
492
|
-
cookies: new Map(),
|
|
493
|
-
};
|
|
632
|
+
await reportActionError(req, error);
|
|
633
|
+
return errorRerender(error, submittedValues);
|
|
494
634
|
}
|
|
635
|
+
// Outside the try: the action succeeded, and a failure to report its
|
|
636
|
+
// revalidation must not turn it into an action error.
|
|
637
|
+
await reportRevalidationErrors(req, result.revalidationErrors);
|
|
495
638
|
|
|
496
639
|
// Handle redirect from the action (e.g. redirect() called in the action body)
|
|
497
640
|
if (result.redirectTo) {
|