@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
|
@@ -14,29 +14,30 @@
|
|
|
14
14
|
|
|
15
15
|
import type { ClientBootstrapConfig } from '../html-injectors.ts';
|
|
16
16
|
import { flightInitScript } from '../flight-scripts.ts';
|
|
17
|
-
import { getCspNonce
|
|
17
|
+
import { getCspNonce } from '../csp-nonce.ts';
|
|
18
|
+
import { nonceAttr } from '../render-utils.ts';
|
|
18
19
|
import { appVisibleSearch } from '../../shared/rsc-cache-key.ts';
|
|
19
|
-
import { getSlotParamsForClient } from '../request-context.ts';
|
|
20
20
|
import type { LayoutEntry } from '../deny-renderer.ts';
|
|
21
|
-
import { renderDenyPage } from '../deny-renderer.ts';
|
|
22
21
|
import type { RouteMatch } from '../pipeline.ts';
|
|
23
|
-
import { isSsrStreamError } from '../
|
|
22
|
+
import { isSsrStreamError } from '../signal-identity.ts';
|
|
24
23
|
import type { LayoutComponentEntry } from '../route-element-builder.ts';
|
|
25
24
|
import type { ManifestSegmentNode } from '../route-matcher.ts';
|
|
26
25
|
import type { SlotSkipEntry } from '../slot-resolver.ts';
|
|
27
|
-
import type { NavContext } from '../ssr-bridge-types.ts';
|
|
26
|
+
import type { NavContext, SsrRenderResult } from '../ssr-bridge-types.ts';
|
|
28
27
|
|
|
29
28
|
import { htmlEscapeJsonString } from '../flight-scripts.ts';
|
|
30
|
-
import {
|
|
29
|
+
import { buildSegmentInfo, isAbortError } from './helpers.ts';
|
|
31
30
|
import { getCookiesForSsr } from '../cookie-context.ts';
|
|
32
31
|
import { getDenyStatus, getFirstDeniedSegmentIndex } from '../deny-boundary.ts';
|
|
33
32
|
import { renderErrorPage, type GlobalErrorFile } from './error-renderer.ts';
|
|
34
33
|
import { callSsr } from './ssr-bridge.ts';
|
|
35
|
-
import type { RenderSignals } from './
|
|
34
|
+
import type { RenderSignals } from './render-signals.ts';
|
|
35
|
+
import type { DenySignal, RedirectSignal } from '../primitives.ts';
|
|
36
36
|
import { recordTiming } from '../server-timing.ts';
|
|
37
37
|
import { teeWithErrorPropagation } from '../stream-utils.ts';
|
|
38
38
|
import { addSpanEventSync } from '../tracing.ts';
|
|
39
39
|
import { isDevMode } from '../debug.ts';
|
|
40
|
+
import { swallow } from '../logger.ts';
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Maximum number of queueMicrotask yields during signal promotion.
|
|
@@ -75,7 +76,7 @@ export const __test_only_signalPromotionDepth: { value: number } = { value: 0 };
|
|
|
75
76
|
* Test-only observable: true when the promotion loop hit the cap without
|
|
76
77
|
* capturing a signal (the silent-miss path — state 3 in TIM-970). False
|
|
77
78
|
* when the loop captured a signal at any depth, when it was skipped via
|
|
78
|
-
* `
|
|
79
|
+
* `fizzAllReadyResolved`, or when no signal was ever expected at a depth
|
|
79
80
|
* shallower than the cap.
|
|
80
81
|
*
|
|
81
82
|
* Pairs with `__test_only_signalPromotionDepth`: depth alone cannot
|
|
@@ -112,13 +113,18 @@ interface SsrRenderOptions {
|
|
|
112
113
|
* SSR will attempt to render the element tree progressively. Two outcomes:
|
|
113
114
|
*
|
|
114
115
|
* 1. deny() outside Suspense: the error appears in the RSC shell. SSR's
|
|
115
|
-
* renderToReadableStream fails (rejects). We catch the failure,
|
|
116
|
-
* denySignal, and
|
|
116
|
+
* renderToReadableStream fails (rejects). We catch the failure, find
|
|
117
|
+
* the captured denySignal, and rethrow it to the pipeline.
|
|
117
118
|
*
|
|
118
119
|
* 2. deny() inside Suspense: the SSR shell succeeds (200 committed). The
|
|
119
120
|
* error streams into the connection as a React error boundary. The
|
|
120
121
|
* status is already committed — per design/05-streaming.md this is the
|
|
121
122
|
* expected degraded behavior for deny inside Suspense.
|
|
123
|
+
*
|
|
124
|
+
* @throws the captured `DenySignal` or `RedirectSignal` when one decides the
|
|
125
|
+
* response. `runRenderPhase()` turns it into a `deny` / `redirect` outcome,
|
|
126
|
+
* and the pipeline renders the deny page or builds the redirect, exactly as
|
|
127
|
+
* for a signal thrown out of render (design/49 §"C").
|
|
122
128
|
*/
|
|
123
129
|
export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Response> {
|
|
124
130
|
const {
|
|
@@ -154,27 +160,12 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
154
160
|
[ssrStream, inlineStream] = teeWithErrorPropagation(rscStream);
|
|
155
161
|
}
|
|
156
162
|
|
|
157
|
-
// Wire an AbortController so the Flight injector stops writing <script>
|
|
158
|
-
// tags when an unhandled RSC error is detected. Without this, React's
|
|
159
|
-
// Flight encoder may write model data for a chunk that already received
|
|
160
|
-
// an error row, causing the client's Flight decoder to crash with
|
|
161
|
-
// "enqueueModel is not a function". See TIM-938.
|
|
162
|
-
const errorAbort = new AbortController();
|
|
163
|
-
signals.onUnhandledError = () => errorAbort.abort();
|
|
164
|
-
|
|
165
163
|
// Segment metadata for initial hydration: deferred to shell-flush time.
|
|
166
164
|
// The SSR entry invokes this thunk AFTER renderSsrNodeStream /
|
|
167
165
|
// renderSsrStream returns (shell ready ⇒ AccessGates settled), so
|
|
168
166
|
// getFirstDeniedSegmentIndex() returns the authoritative ALS value
|
|
169
167
|
// rather than the pre-render Infinity. See TIM-1365, TIM-1359.
|
|
170
168
|
|
|
171
|
-
// Params reach the browser inside the payload — a field on the root row of
|
|
172
|
-
// the same Flight stream that is inlined for hydration. SSR itself renders
|
|
173
|
-
// only the tree, and the client components it renders read params from the
|
|
174
|
-
// ALS context seeded below, which is also where server components answer
|
|
175
|
-
// `getSegmentParams(slotPath)` from.
|
|
176
|
-
const slotParams = getSlotParamsForClient();
|
|
177
|
-
|
|
178
169
|
// Middleware has already run; if it read `ctx.nonce` for its CSP header,
|
|
179
170
|
// that is the value every inline script must wear.
|
|
180
171
|
const nonce = getCspNonce();
|
|
@@ -183,8 +174,6 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
183
174
|
const navContext: NavContext = {
|
|
184
175
|
pathname: reqUrl.pathname,
|
|
185
176
|
search: appVisibleSearch(reqUrl).search,
|
|
186
|
-
segmentParams: match.segmentParams,
|
|
187
|
-
slotParams,
|
|
188
177
|
statusCode: 200,
|
|
189
178
|
responseHeaders,
|
|
190
179
|
headHtml:
|
|
@@ -204,256 +193,71 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
204
193
|
deferSuspenseFor: deferSuspenseFor > 0 ? deferSuspenseFor : undefined,
|
|
205
194
|
signal: req.signal,
|
|
206
195
|
cookies: getCookiesForSsr(),
|
|
207
|
-
|
|
196
|
+
// Stops the Flight injector writing <script> tags once an unhandled RSC
|
|
197
|
+
// error is captured. Without this, React's Flight encoder may write model
|
|
198
|
+
// data for a chunk that already received an error row, causing the
|
|
199
|
+
// client's Flight decoder to crash with "enqueueModel is not a
|
|
200
|
+
// function". See TIM-938.
|
|
201
|
+
_errorSignal: signals.unhandledError,
|
|
208
202
|
};
|
|
209
203
|
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
204
|
+
// The signal a render captured, if any. Used after both successful SSR
|
|
205
|
+
// (signal promotion from Suspense) and failed SSR (signal outside Suspense).
|
|
206
|
+
// A captured deny or redirect is reported, not rendered: callers cancel the
|
|
207
|
+
// streams this render holds and rethrow it, and runRenderPhase() turns it
|
|
208
|
+
// into the same `deny` / `redirect` outcome a thrown signal becomes, so
|
|
209
|
+
// the pipeline's deny fallback and redirect builder answer it (design/49
|
|
210
|
+
// §"C"). Redirect wins over deny, as it always has.
|
|
213
211
|
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
function resolvedDeniedIndex(): number {
|
|
222
|
-
return getFirstDeniedSegmentIndex();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function checkCapturedSignals(skipHandledDeny = false): Response | Promise<Response> | null {
|
|
226
|
-
if (signals.redirectSignal) {
|
|
227
|
-
return buildRedirectResponse(signals.redirectSignal, req, responseHeaders);
|
|
228
|
-
}
|
|
229
|
-
if (signals.denySignal && !(skipHandledDeny && navContext._denyHandledByBoundary)) {
|
|
230
|
-
// Deny was not handled by an in-tree error boundary.
|
|
231
|
-
// Fall back to renderDenyPage (separate React.cache scope).
|
|
232
|
-
// For single-render behavior, add a 'use client' status-code file
|
|
233
|
-
// (e.g., 4xx.tsx) — the error boundary handles it in-tree.
|
|
234
|
-
return renderDenyPage(
|
|
235
|
-
signals.denySignal,
|
|
236
|
-
segments,
|
|
237
|
-
layoutComponents as LayoutEntry[],
|
|
238
|
-
req,
|
|
239
|
-
match,
|
|
240
|
-
responseHeaders,
|
|
241
|
-
clientBootstrap,
|
|
242
|
-
callSsr,
|
|
243
|
-
undefined,
|
|
244
|
-
resolvedDeniedIndex()
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
if (signals.renderError) {
|
|
248
|
-
return renderErrorPage(
|
|
249
|
-
signals.renderError.error,
|
|
250
|
-
signals.renderError.status,
|
|
251
|
-
segments,
|
|
252
|
-
layoutComponents as LayoutEntry[],
|
|
253
|
-
req,
|
|
254
|
-
match,
|
|
255
|
-
responseHeaders,
|
|
256
|
-
clientBootstrap,
|
|
257
|
-
globalError,
|
|
258
|
-
resolvedDeniedIndex()
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
return null;
|
|
212
|
+
// A signal the detection phase below saw arrive past the promotion cap is
|
|
213
|
+
// discarded rather than promoted; this flag records that without writing
|
|
214
|
+
// into the producer's signals.
|
|
215
|
+
let detectionConfirmedLateSignal = false;
|
|
216
|
+
function capturedSignal(): RedirectSignal | DenySignal | null {
|
|
217
|
+
if (detectionConfirmedLateSignal) return null;
|
|
218
|
+
return signals.redirectSignal ?? signals.denySignal;
|
|
262
219
|
}
|
|
263
220
|
|
|
221
|
+
// Only the SSR call is guarded: everything after it runs on a document
|
|
222
|
+
// SSR produced, and a captured signal rethrown there must reach
|
|
223
|
+
// runRenderPhase() rather than this renderer's own failure handling.
|
|
224
|
+
let ssr: SsrRenderResult;
|
|
264
225
|
try {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
// Record SSR sub-phase timings for Server-Timing header (detailed mode).
|
|
268
|
-
// These are populated by handleSsr() in the SSR environment and passed
|
|
269
|
-
// back via navContext._ssrTimings across the RSC→SSR boundary.
|
|
270
|
-
if (navContext._ssrTimings) {
|
|
271
|
-
const t = navContext._ssrTimings;
|
|
272
|
-
recordTiming({ name: 'ssr-decode', dur: t.decodeMs, desc: 'RSC Flight decode' });
|
|
273
|
-
recordTiming({ name: 'ssr-shell', dur: t.shellMs, desc: 'Fizz onShellReady' });
|
|
274
|
-
recordTiming({ name: 'ssr-pipeline', dur: t.pipelineMs, desc: 'stream transforms' });
|
|
275
|
-
recordTiming({
|
|
276
|
-
name: 'ssr-total',
|
|
277
|
-
dur: t.totalMs,
|
|
278
|
-
desc: t.nodeStreams ? 'SSR (Node streams)' : 'SSR (Web Streams)',
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Signal promotion: check if any signals were captured during rendering
|
|
283
|
-
// inside Suspense boundaries. If no signals are present yet, we may
|
|
284
|
-
// need to yield microtasks so async component rejections propagate
|
|
285
|
-
// through the full rejection chain to the RSC onError callback before
|
|
286
|
-
// we commit the response.
|
|
287
|
-
//
|
|
288
|
-
// Option 1 short-circuit: when Fizz's `stream.allReady` settled before
|
|
289
|
-
// the `deferSuspenseFor` hold ended (navContext._fizzAllReadyResolved),
|
|
290
|
-
// Flight has closed its stream, every `onError` already fired, and the
|
|
291
|
-
// signals object is fully populated. The retry loop would be a no-op.
|
|
292
|
-
// See design/spike-signal-promotion-protocol.md §"Option 1".
|
|
293
|
-
//
|
|
294
|
-
// Fallback path (hold timed out, no hold window, or shell-only return):
|
|
295
|
-
// the known rejection chain depth for a withSpan-wrapped page is 3+
|
|
296
|
-
// microtasks —
|
|
297
|
-
// 1. PageComponent throws DenySignal/RedirectSignal
|
|
298
|
-
// 2. withSpan catches and re-throws (microtask 1)
|
|
299
|
-
// 3. TracedPage promise rejects (microtask 2)
|
|
300
|
-
// 4. React Flight rejection handler → onError (microtask 3+)
|
|
301
|
-
// so a bounded retry loop (max 5) is required to catch signals whose
|
|
302
|
-
// propagation is still in-flight when callSsr returns. The loop exits
|
|
303
|
-
// early as soon as a signal is detected. Uses queueMicrotask instead
|
|
304
|
-
// of setTimeout(0) to avoid yielding to the full event loop.
|
|
305
|
-
// See design/05-streaming.md §"deferSuspenseFor and the Hold Window"
|
|
306
|
-
if (!signals.redirectSignal && !signals.denySignal && !signals.renderError) {
|
|
307
|
-
let yieldsConsumed = 0;
|
|
308
|
-
let detectionConfirmedLateSignal = false;
|
|
309
|
-
if (!navContext._fizzAllReadyResolved) {
|
|
310
|
-
// Promotion phase: bounded cap of SIGNAL_PROMOTION_MAX_YIELDS.
|
|
311
|
-
// Signals captured here are honored by checkCapturedSignals and
|
|
312
|
-
// become the response (redirect/deny/error page).
|
|
313
|
-
for (let i = 0; i < SIGNAL_PROMOTION_MAX_YIELDS; i++) {
|
|
314
|
-
await new Promise<void>((r) => queueMicrotask(r));
|
|
315
|
-
yieldsConsumed++;
|
|
316
|
-
if (signals.redirectSignal || signals.denySignal || signals.renderError) break;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Detection phase (TIM-970): if the promotion cap was hit without
|
|
320
|
-
// capturing a signal, yield a few more times to disambiguate state 2
|
|
321
|
-
// ("no signal was ever coming" — the common legitimate-200 case) from
|
|
322
|
-
// state 3 ("signal arrived one microtask past the cap" — the silent
|
|
323
|
-
// miss). Telemetry-only: if a late signal is observed it triggers
|
|
324
|
-
// the warning and span event but is NOT promoted. Promoting it would
|
|
325
|
-
// effectively raise the cap to MAX_YIELDS + DETECTION_EXTRA_YIELDS,
|
|
326
|
-
// which the ticket defers to the E.2 investigation. The signals are
|
|
327
|
-
// cleared so checkCapturedSignals does not pick them up.
|
|
328
|
-
if (
|
|
329
|
-
yieldsConsumed === SIGNAL_PROMOTION_MAX_YIELDS &&
|
|
330
|
-
!signals.redirectSignal &&
|
|
331
|
-
!signals.denySignal &&
|
|
332
|
-
!signals.renderError
|
|
333
|
-
) {
|
|
334
|
-
for (let i = 0; i < SIGNAL_PROMOTION_DETECTION_EXTRA_YIELDS; i++) {
|
|
335
|
-
await new Promise<void>((r) => queueMicrotask(r));
|
|
336
|
-
if (signals.redirectSignal || signals.denySignal || signals.renderError) {
|
|
337
|
-
detectionConfirmedLateSignal = true;
|
|
338
|
-
signals.redirectSignal = null;
|
|
339
|
-
signals.denySignal = null;
|
|
340
|
-
signals.renderError = null;
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
__test_only_signalPromotionDepth.value = yieldsConsumed;
|
|
347
|
-
__test_only_signalPromotionCapHit.value = detectionConfirmedLateSignal;
|
|
348
|
-
|
|
349
|
-
if (detectionConfirmedLateSignal) {
|
|
350
|
-
if (isDevMode()) {
|
|
351
|
-
console.warn(
|
|
352
|
-
`[timber] Signal promotion cap reached (${SIGNAL_PROMOTION_MAX_YIELDS} microtask yields) — a deny()/redirect()/renderError signal arrived just past the cap and was discarded. ` +
|
|
353
|
-
`Likely cause: a page using deny()/redirect() inside a deeply-wrapped async component (custom withSpan, decorators, etc.). ` +
|
|
354
|
-
`Simplify the async chain or reduce withSpan/wrapper depth. ` +
|
|
355
|
-
`See design/05-streaming.md §"Signal Promotion".`
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
|
-
addSpanEventSync('timber.ssr.signal_promotion_cap_reached', {
|
|
359
|
-
depth: SIGNAL_PROMOTION_MAX_YIELDS,
|
|
360
|
-
signal_types_checked: 'redirect,deny,renderError',
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const promoted = checkCapturedSignals(/* skipHandledDeny */ true);
|
|
366
|
-
if (promoted) {
|
|
367
|
-
ssrResponse.body?.cancel();
|
|
368
|
-
return promoted;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// Check if a DenySignal was caught in-tree by AccessGate or
|
|
372
|
-
// PageDenyBoundary. The deny page was rendered as a normal element
|
|
373
|
-
// (no error in the Flight stream), so SSR succeeded with status 200.
|
|
374
|
-
// Override the status code from the ALS-stored deny status. See TIM-666.
|
|
375
|
-
const denyStatus = getDenyStatus();
|
|
376
|
-
if (denyStatus) {
|
|
377
|
-
return new Response(ssrResponse.body, {
|
|
378
|
-
status: denyStatus,
|
|
379
|
-
headers: ssrResponse.headers,
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return ssrResponse;
|
|
226
|
+
ssr = await callSsr(ssrStream, navContext);
|
|
384
227
|
} catch (ssrError) {
|
|
228
|
+
// SSR failed, so nothing will read the teed inline stream: every answer
|
|
229
|
+
// below renders its own streams or none. Without explicit cancellation
|
|
230
|
+
// the orphaned tee branch keeps the RSC source stream alive, preventing
|
|
231
|
+
// garbage collection — so release it before anything returns or throws.
|
|
232
|
+
inlineStream
|
|
233
|
+
?.cancel()
|
|
234
|
+
.catch((err: unknown) => swallow(err, 'orphaned RSC inline stream did not cancel'));
|
|
235
|
+
|
|
385
236
|
// Connection abort — the client disconnected (page refresh, navigation
|
|
386
237
|
// away). No response needed; return empty 499 (client closed request).
|
|
387
238
|
if (isAbortError(ssrError) || req.signal?.aborted) {
|
|
388
|
-
inlineStream?.cancel().catch(() => {});
|
|
389
239
|
return new Response(null, { status: 499 });
|
|
390
240
|
}
|
|
391
241
|
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
//
|
|
242
|
+
// A captured signal explains the failure, whichever shape it took: the
|
|
243
|
+
// signal was in the shell, outside any Suspense boundary.
|
|
244
|
+
const signal = capturedSignal();
|
|
245
|
+
if (signal) throw signal;
|
|
246
|
+
|
|
247
|
+
// SsrStreamError with no captured signal: SSR's renderToReadableStream
|
|
248
|
+
// failed because the RSC stream contained an uncontained error (e.g., a
|
|
249
|
+
// slot without an error boundary).
|
|
398
250
|
//
|
|
399
|
-
// Deny pages still go through RSC → SSR (plain props), so they pass empty
|
|
400
|
-
// layouts to avoid re-executing server components in the RSC environment's
|
|
401
|
-
// stale ALS scope. See LOCAL-293.
|
|
402
251
|
// SsrStreamError is thrown in the SSR environment but caught here in
|
|
403
252
|
// RSC — separate Vite module graphs, so `instanceof` can never match.
|
|
404
253
|
// isSsrStreamError() checks the Symbol.for brand instead. See
|
|
405
254
|
// design/18-build-system.md §"Dev Mode: Signal Identity Across Program Reloads".
|
|
406
255
|
if (isSsrStreamError(ssrError)) {
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
// RSC source stream alive, preventing garbage collection.
|
|
411
|
-
inlineStream?.cancel().catch(() => {});
|
|
412
|
-
|
|
413
|
-
if (signals.redirectSignal) {
|
|
414
|
-
return buildRedirectResponse(signals.redirectSignal, req, responseHeaders);
|
|
415
|
-
}
|
|
416
|
-
if (signals.denySignal) {
|
|
417
|
-
// SSR failed (SsrStreamError) — the deny was in the shell and
|
|
418
|
-
// the error boundary didn't catch it during Fizz rendering.
|
|
419
|
-
// Fall back to renderDenyPage (separate render). See TIM-664.
|
|
420
|
-
return renderDenyPage(
|
|
421
|
-
signals.denySignal,
|
|
422
|
-
segments,
|
|
423
|
-
layoutComponents as LayoutEntry[],
|
|
424
|
-
req,
|
|
425
|
-
match,
|
|
426
|
-
responseHeaders,
|
|
427
|
-
clientBootstrap,
|
|
428
|
-
callSsr,
|
|
429
|
-
undefined,
|
|
430
|
-
resolvedDeniedIndex()
|
|
431
|
-
);
|
|
432
|
-
}
|
|
433
|
-
if (signals.renderError) {
|
|
434
|
-
// RenderError: TSX error pages use SSR-only path (layouts OK),
|
|
435
|
-
// MDX error pages use RSC path (plain props, no Error object).
|
|
436
|
-
return renderErrorPage(
|
|
437
|
-
signals.renderError.error,
|
|
438
|
-
signals.renderError.status,
|
|
439
|
-
segments,
|
|
440
|
-
layoutComponents as LayoutEntry[],
|
|
441
|
-
req,
|
|
442
|
-
match,
|
|
443
|
-
responseHeaders,
|
|
444
|
-
clientBootstrap,
|
|
445
|
-
globalError,
|
|
446
|
-
resolvedDeniedIndex()
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
// No captured signal — unhandled error in the RSC stream.
|
|
450
|
-
// Use the lastUnhandledError from RSC onError if available (more
|
|
451
|
-
// reliable than extracting SsrStreamError.cause). Falls back to
|
|
452
|
-
// cause extraction for backward compatibility.
|
|
453
|
-
const originalError =
|
|
454
|
-
signals.lastUnhandledError ?? (ssrError as { cause?: unknown }).cause ?? ssrError;
|
|
256
|
+
// The cause is the error Flight relayed for the row that failed the
|
|
257
|
+
// shell — not the last error the RSC render reported, which may be one
|
|
258
|
+
// a Suspense boundary contained (TIM-1552).
|
|
455
259
|
return renderErrorPage(
|
|
456
|
-
|
|
260
|
+
ssrError.cause ?? ssrError,
|
|
457
261
|
500,
|
|
458
262
|
segments,
|
|
459
263
|
layoutComponents as LayoutEntry[],
|
|
@@ -462,16 +266,131 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
462
266
|
responseHeaders,
|
|
463
267
|
clientBootstrap,
|
|
464
268
|
globalError,
|
|
465
|
-
|
|
269
|
+
getFirstDeniedSegmentIndex()
|
|
466
270
|
);
|
|
467
271
|
}
|
|
468
272
|
|
|
469
|
-
// SSR shell rendering failed — the error was outside Suspense.
|
|
470
|
-
// Check captured signals (redirect, deny, render error).
|
|
471
|
-
const signalResponse = checkCapturedSignals();
|
|
472
|
-
if (signalResponse) return signalResponse;
|
|
473
|
-
|
|
474
273
|
// No tracked error — rethrow (infrastructure failure)
|
|
475
274
|
throw ssrError;
|
|
476
275
|
}
|
|
276
|
+
|
|
277
|
+
const { response: ssrResponse, timings: t, fizzAllReadyResolved } = ssr;
|
|
278
|
+
|
|
279
|
+
// Record SSR sub-phase timings for the Server-Timing header. recordTiming
|
|
280
|
+
// is a no-op outside a detailed-mode timing collector.
|
|
281
|
+
recordTiming({ name: 'ssr-decode', dur: t.decodeMs, desc: 'RSC Flight decode' });
|
|
282
|
+
recordTiming({ name: 'ssr-shell', dur: t.shellMs, desc: 'Fizz onShellReady' });
|
|
283
|
+
recordTiming({ name: 'ssr-pipeline', dur: t.pipelineMs, desc: 'stream transforms' });
|
|
284
|
+
recordTiming({
|
|
285
|
+
name: 'ssr-total',
|
|
286
|
+
dur: t.totalMs,
|
|
287
|
+
desc: t.nodeStreams ? 'SSR (Node streams)' : 'SSR (Web Streams)',
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Signal promotion: check if any signals were captured during rendering
|
|
291
|
+
// inside Suspense boundaries. If no signals are present yet, we may
|
|
292
|
+
// need to yield microtasks so async component rejections propagate
|
|
293
|
+
// through the full rejection chain to the RSC onError callback before
|
|
294
|
+
// we commit the response.
|
|
295
|
+
//
|
|
296
|
+
// Option 1 short-circuit: when Fizz's `stream.allReady` settled before
|
|
297
|
+
// the `deferSuspenseFor` hold ended (`fizzAllReadyResolved`),
|
|
298
|
+
// Flight has closed its stream, every `onError` already fired, and the
|
|
299
|
+
// signals object is fully populated. The retry loop would be a no-op.
|
|
300
|
+
// See design/spike-signal-promotion-protocol.md §"Option 1".
|
|
301
|
+
//
|
|
302
|
+
// Fallback path (hold timed out, no hold window, or shell-only return):
|
|
303
|
+
// the known rejection chain depth for a withSpan-wrapped page is 3+
|
|
304
|
+
// microtasks —
|
|
305
|
+
// 1. PageComponent throws DenySignal/RedirectSignal
|
|
306
|
+
// 2. withSpan catches and re-throws (microtask 1)
|
|
307
|
+
// 3. TracedPage promise rejects (microtask 2)
|
|
308
|
+
// 4. React Flight rejection handler → onError (microtask 3+)
|
|
309
|
+
// so a bounded retry loop (max 5) is required to catch signals whose
|
|
310
|
+
// propagation is still in-flight when callSsr returns. The loop exits
|
|
311
|
+
// early as soon as a signal is detected. Uses queueMicrotask instead
|
|
312
|
+
// of setTimeout(0) to avoid yielding to the full event loop.
|
|
313
|
+
// See design/05-streaming.md §"deferSuspenseFor and the Hold Window"
|
|
314
|
+
if (!capturedSignal()) {
|
|
315
|
+
let yieldsConsumed = 0;
|
|
316
|
+
if (!fizzAllReadyResolved) {
|
|
317
|
+
// Promotion phase: bounded cap of SIGNAL_PROMOTION_MAX_YIELDS.
|
|
318
|
+
// A signal captured here is rethrown below and becomes the
|
|
319
|
+
// response (redirect or deny page).
|
|
320
|
+
for (let i = 0; i < SIGNAL_PROMOTION_MAX_YIELDS; i++) {
|
|
321
|
+
await new Promise<void>((r) => queueMicrotask(r));
|
|
322
|
+
yieldsConsumed++;
|
|
323
|
+
if (capturedSignal()) break;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Detection phase (TIM-970): if the promotion cap was hit without
|
|
327
|
+
// capturing a signal, yield a few more times to disambiguate state 2
|
|
328
|
+
// ("no signal was ever coming" — the common legitimate-200 case) from
|
|
329
|
+
// state 3 ("signal arrived one microtask past the cap" — the silent
|
|
330
|
+
// miss). Telemetry-only: if a late signal is observed it triggers
|
|
331
|
+
// the warning and span event but is NOT promoted. Promoting it would
|
|
332
|
+
// effectively raise the cap to MAX_YIELDS + DETECTION_EXTRA_YIELDS,
|
|
333
|
+
// which the ticket defers to the E.2 investigation. Setting
|
|
334
|
+
// detectionConfirmedLateSignal keeps capturedSignal() from picking
|
|
335
|
+
// them up.
|
|
336
|
+
//
|
|
337
|
+
// The signal is discarded, but a late deny's status still applies: an
|
|
338
|
+
// in-tree catch site that hoisted it recorded the status before
|
|
339
|
+
// rethrowing (handleCaughtDeny), so the getDenyStatus() override below
|
|
340
|
+
// serves this document with the deny's 4xx. A late deny that no status
|
|
341
|
+
// file matched recorded nothing and stays a 200, as does any deny that
|
|
342
|
+
// lands after this window — the override is read once, below.
|
|
343
|
+
if (yieldsConsumed === SIGNAL_PROMOTION_MAX_YIELDS && !capturedSignal()) {
|
|
344
|
+
for (let i = 0; i < SIGNAL_PROMOTION_DETECTION_EXTRA_YIELDS; i++) {
|
|
345
|
+
await new Promise<void>((r) => queueMicrotask(r));
|
|
346
|
+
if (capturedSignal()) {
|
|
347
|
+
detectionConfirmedLateSignal = true;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
__test_only_signalPromotionDepth.value = yieldsConsumed;
|
|
354
|
+
__test_only_signalPromotionCapHit.value = detectionConfirmedLateSignal;
|
|
355
|
+
|
|
356
|
+
if (detectionConfirmedLateSignal) {
|
|
357
|
+
if (isDevMode()) {
|
|
358
|
+
console.warn(
|
|
359
|
+
`[timber] Signal promotion cap reached (${SIGNAL_PROMOTION_MAX_YIELDS} microtask yields) — a deny()/redirect() signal arrived just past the cap and was discarded. ` +
|
|
360
|
+
`Likely cause: a page using deny()/redirect() inside a deeply-wrapped async component (custom withSpan, decorators, etc.). ` +
|
|
361
|
+
`Simplify the async chain or reduce withSpan/wrapper depth. ` +
|
|
362
|
+
`See design/05-streaming.md §"Signal Promotion".`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
addSpanEventSync('timber.ssr.signal_promotion_cap_reached', {
|
|
366
|
+
depth: SIGNAL_PROMOTION_MAX_YIELDS,
|
|
367
|
+
signal_types_checked: 'redirect,deny',
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// A captured signal replaces this document, so its body is never read.
|
|
373
|
+
const promoted = capturedSignal();
|
|
374
|
+
if (promoted) {
|
|
375
|
+
ssrResponse.body
|
|
376
|
+
?.cancel()
|
|
377
|
+
.catch((err: unknown) => swallow(err, 'discarded SSR document body did not cancel'));
|
|
378
|
+
throw promoted;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Check if a DenySignal was caught in-tree by AccessGate or
|
|
382
|
+
// PageDenyBoundary. The deny page was rendered as a normal element
|
|
383
|
+
// (no error in the Flight stream), so SSR succeeded with status 200.
|
|
384
|
+
// Override the status code from the ALS-stored deny status. See TIM-666.
|
|
385
|
+
// A hoisted deny whose signal arrived past the promotion cap lands here
|
|
386
|
+
// too, with the status its catch site recorded (see the detection phase).
|
|
387
|
+
const denyStatus = getDenyStatus();
|
|
388
|
+
if (denyStatus) {
|
|
389
|
+
return new Response(ssrResponse.body, {
|
|
390
|
+
status: denyStatus,
|
|
391
|
+
headers: ssrResponse.headers,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return ssrResponse;
|
|
477
396
|
}
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
import type { FormRerender } from '../action-handler.ts';
|
|
31
31
|
import { handleActionRequest, isActionRequest } from '../action-handler.ts';
|
|
32
32
|
import type { BodyLimitsConfig } from '../body-limits.ts';
|
|
33
|
-
import { validateCsrf, type CsrfConfig } from '../csrf.ts';
|
|
33
|
+
import { validateCsrf, csrfRejectionResponse, type CsrfConfig } from '../csrf.ts';
|
|
34
34
|
import { runWithFormFlash } from '../form-flash.ts';
|
|
35
|
-
import { seedRequestCookies } from '../cookie-context.ts';
|
|
36
35
|
import type { RouteMatcher } from '../pipeline.ts';
|
|
36
|
+
import { isApiRouteChain } from '../route-matcher.ts';
|
|
37
37
|
import type { SensitiveFieldsOption } from '../sensitive-fields.ts';
|
|
38
38
|
import type { RevalidateRenderer } from '../actions.ts';
|
|
39
39
|
|
|
@@ -95,7 +95,7 @@ export function wrapPipelineWithActionDispatch(
|
|
|
95
95
|
// Runs on EVERY unsafe-method request, before any dispatch decision.
|
|
96
96
|
const csrfResult = validateCsrf(req, deps.csrfConfig);
|
|
97
97
|
if (!csrfResult.ok) {
|
|
98
|
-
return
|
|
98
|
+
return csrfRejectionResponse(req, csrfResult);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
return pipeline(req);
|
|
@@ -120,12 +120,12 @@ export function buildActionDispatcher(
|
|
|
120
120
|
): (
|
|
121
121
|
req: Request,
|
|
122
122
|
canonicalPath: string,
|
|
123
|
-
reenter: (req: Request) => Promise<Response>
|
|
123
|
+
reenter: (req: Request, cookies: Map<string, string>) => Promise<Response>
|
|
124
124
|
) => Promise<Response | null> {
|
|
125
125
|
return async (
|
|
126
126
|
req: Request,
|
|
127
127
|
canonicalPath: string,
|
|
128
|
-
reenter: (req: Request) => Promise<Response>
|
|
128
|
+
reenter: (req: Request, cookies: Map<string, string>) => Promise<Response>
|
|
129
129
|
): Promise<Response | null> => {
|
|
130
130
|
if (!isActionRequest(req)) return null;
|
|
131
131
|
|
|
@@ -138,11 +138,8 @@ export function buildActionDispatcher(
|
|
|
138
138
|
// which re-encodes the path. The matcher expects the decoded canonical form.
|
|
139
139
|
if (deps.matchRoute) {
|
|
140
140
|
const match = deps.matchRoute(canonicalPath);
|
|
141
|
-
if (match) {
|
|
142
|
-
|
|
143
|
-
if (leaf?.route) {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
141
|
+
if (match && isApiRouteChain(match.segments)) {
|
|
142
|
+
return null;
|
|
146
143
|
}
|
|
147
144
|
}
|
|
148
145
|
|
|
@@ -161,8 +158,8 @@ export function buildActionDispatcher(
|
|
|
161
158
|
// Build a synthetic GET request for the rerender pipeline:
|
|
162
159
|
// - Same URL (so route matching lands on the same page)
|
|
163
160
|
// - Cookie header DROPPED entirely. The post-action RYW state
|
|
164
|
-
// is
|
|
165
|
-
//
|
|
161
|
+
// is handed to `reenter` as a parsed `Map<string, string>`,
|
|
162
|
+
// which becomes the rerender request context's cookies.
|
|
166
163
|
// - Method GET because the rerender is conceptually a page render.
|
|
167
164
|
const rerenderHeaders = new Headers(req.headers);
|
|
168
165
|
rerenderHeaders.delete('cookie');
|
|
@@ -170,8 +167,9 @@ export function buildActionDispatcher(
|
|
|
170
167
|
method: 'GET',
|
|
171
168
|
headers: rerenderHeaders,
|
|
172
169
|
});
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
const response = await runWithFormFlash(formRerender.rerender, () =>
|
|
171
|
+
reenter(rerenderReq, formRerender.cookies)
|
|
172
|
+
);
|
|
175
173
|
// Apply Set-Cookie headers snapshotted from the action's ALS scope.
|
|
176
174
|
for (const value of formRerender.setCookieHeaders) {
|
|
177
175
|
response.headers.append('Set-Cookie', value);
|